diff --git a/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/Game.js b/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/Game.js
index 90a2ee0f..e3a42941 100644
--- a/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/Game.js
+++ b/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/Game.js
@@ -86,7 +86,6 @@ Game.onLoopStart = function(graphicSpritesSceneObject, CB_REM_dataObject, expect
//If the time to wait for the next wave has been reached, starts a new wave:
if (Game.data.levelEnemyWaveEndedTs !== null && CB_Device.getTiming() >= Game.data.levelEnemyWaveEndedTs + Game.Levels.data[Game.data.level].enemyWaves[Game.data.levelEnemyWave].timeFromLastEnemyToNextWave)
{
- logMessage("The time for next wave has been reached. Starting new wave #" + (Game.data.levelEnemyWave) + "...");
Game.data.levelEnemyWaveEndedTs = null;
Game.data.enemies = [];
@@ -95,6 +94,8 @@ Game.onLoopStart = function(graphicSpritesSceneObject, CB_REM_dataObject, expect
Game.data.levelEnemyWave++;
createNewEnemy = true;
+
+ logMessage("The time for next wave has been reached. Starting new wave #" + (Game.data.levelEnemyWave) + "...");
}
//...otherwise, the current wave has ended so we store the time (if not done yet):
else if (Game.data.levelEnemyWaveEndedTs === null)
@@ -132,7 +133,8 @@ Game.onLoopStart = function(graphicSpritesSceneObject, CB_REM_dataObject, expect
else if (levelPassed)
{
Game.data.levelSucceeded = true;
- Game.end("Congratulations! You survived successfully");
+ Game.data.score += Game.data.vitality >= 100 ? 1000 : 500;
+ Game.end("Congratulations! You survived successfully" + (Game.data.vitality >= 100 ? " (undamaged!!!)" : ""));
}
//Perform steps for each enemy:
@@ -217,7 +219,9 @@ Game.end = function(message)
message = CB_trim(message);
Game.data.gameStarted = false;
- CB_Elements.insertContentById("start_button", (message !== "" ? message + "
" : "") + (Game.data.levelSucceeded ? "Continue playing" : "Start game!"))
+ var buttonText = "Start game!";
+ if (Game.data.levelSucceeded) { buttonText = (Game.data.level >= Game.Levels.data.length - 1) ? "All levels passed!
Restart game" : "Continue playing"; }
+ CB_Elements.insertContentById("start_button", (message !== "" ? message + "
" : "") + buttonText)
CB_Elements.showById("start_button"); //Shows the start button again.
}
@@ -391,8 +395,8 @@ Game.Levels._loadData = function(level, avoidCache)
(
function (subSprite)
{
- subSprite.width = Visual._ELEMENTS_WIDTH;
- subSprite.height = Visual._ELEMENTS_HEIGHT;
+ subSprite.width = subSprite.id.indexOf("vitality") !== -1 && subSprite.data._enemyObject ? subSprite.data._enemyObject.vitality / subSprite.data._enemyObject.levelVitality[subSprite.data._enemyObject.level] * Visual._ELEMENTS_WIDTH : Visual._ELEMENTS_WIDTH;
+ subSprite.height = subSprite.id.indexOf("vitality") !== -1 ? Visual._ELEMENTS_HEIGHT / 15 : Visual._ELEMENTS_HEIGHT;
}
);
}
diff --git a/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/Visual.js b/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/Visual.js
index 5f7569db..7d57d825 100644
--- a/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/Visual.js
+++ b/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/Visual.js
@@ -24,6 +24,28 @@ Visual.getSpritesGroupsData = function()
};
//Sprites groups data:
+ Visual._spritesGroupsDataBeforeDrawingSprite =
+ function(element, canvasContext, canvasBufferContext, useBuffer, CB_GraphicSpritesSceneObject, drawingMap, x, y, mapElement) //Called before drawing the element.
+ {
+ if (!element.data._spriteDuration) { element.data._spriteDuration = 500 / (element.data._enemyObject.level + 1); }
+ if (element.data._beforeDrawingLastTS === null || CB_Device.getTiming() - element.data._beforeDrawingLastTS >= element.data._spriteDuration)
+ {
+ element.srcLeft += element.data._spriteWidth;
+ element.srcLeft %= element.data._spriteWidthTotal;
+ element.data._beforeDrawingLastTS = CB_Device.getTiming();
+ }
+
+ canvasContext.filter = "hue-rotate(" + (element.data._enemyObject.level * 60) + "deg)";
+
+ return element; //Same as 'element'. Must return the element to draw. Return null to skip drawing it.
+ };
+ Visual._spritesGroupsDataBeforeDrawingSpriteVitality =
+ function(element)
+ {
+ element.width = element.data._enemyObject.vitality / element.data._enemyObject.levelVitality[element.data._enemyObject.level] * Visual._ELEMENTS_WIDTH;
+ return element;
+ };
+
Visual._spritesGroupsData =
{
//'towers_defense_game_sprites_groups' ('CB_GraphicSpritesScene.SPRITES_GROUPS_OBJECT' object). Some missing or non-valid properties will get a default value:
@@ -40,13 +62,14 @@ Visual.getSpritesGroupsData = function()
id: "info",
srcType: CB_GraphicSprites.SRC_TYPES.TEXT,
top: 15,
- zIndex: 3,
+ zIndex: 4,
data:
{
fontSize: "16px",
fontFamily: "courier",
style: "#ffaa00",
- fontWeight: "bold"
+ fontWeight: "bold",
+ filter: "none"
},
sprites: [ { id: "info_sprite" } ]
},
@@ -95,7 +118,7 @@ Visual.getSpritesGroupsData = function()
{
id: "path_0",
src: "img/path_0.gif"
- }
+ }
]
},
@@ -172,7 +195,31 @@ Visual.getSpritesGroupsData = function()
{
id: "enemy_0_subsprites",
src: "img/enemy_0_sprites.gif",
- disabled: true
+ disabled: true,
+ data:
+ {
+ rotationUseDegrees: true,
+ rotation: 0,
+ _beforeDrawingLastTS: null,
+ _spriteWidth: 38,
+ _spriteWidthTotal: 152,
+ _spriteDuration: null, //It will change according to enemy level.
+ _enemyObject: null,
+ beforeDrawing: Visual._spritesGroupsDataBeforeDrawingSprite
+ }
+ },
+ {
+ id: "enemy_0_subsprites_vitality",
+ srcType: CB_GraphicSprites.SRC_TYPES.RECTANGLE,
+ disabled: true,
+ zIndex: 3,
+ data:
+ {
+ style: "#00aa00",
+ opacity: 0.6,
+ _enemyObject: null,
+ beforeDrawing: Visual._spritesGroupsDataBeforeDrawingSpriteVitality
+ }
}
]
}
@@ -194,7 +241,30 @@ Visual.getSpritesGroupsData = function()
{
id: "enemy_1_subsprites",
src: "img/enemy_1_sprites.gif",
- disabled: true
+ disabled: true,
+ data:
+ {
+ rotationUseDegrees: true,
+ rotation: 0,
+ _beforeDrawingLastTS: null,
+ _spriteWidth: 38,
+ _spriteWidthTotal: 152,
+ _spriteDuration: null, //It will change according to enemy level.
+ beforeDrawing: Visual._spritesGroupsDataBeforeDrawingSprite
+ }
+ },
+ {
+ id: "enemy_0_subsprites_vitality",
+ srcType: CB_GraphicSprites.SRC_TYPES.RECTANGLE,
+ disabled: true,
+ zIndex: 3,
+ data:
+ {
+ style: "#00aa00",
+ opacity: 0.6,
+ _enemyObject: null,
+ beforeDrawing: Visual._spritesGroupsDataBeforeDrawingSpriteVitality
+ }
}
]
}
@@ -374,8 +444,8 @@ Visual.updateInfo = function(graphicSpritesSceneObject)
graphicSpritesSceneObject.getById("info").get(0).src =
"Level: " + (Game.data.level + 1) + "\n" +
"Coins: " + Game.data.coins + "\n" +
- "Vitality: " + Game.data.vitality + "\n" +
"Score: " + Game.data.score + "\n" +
+ "Vitality: " + Game.data.vitality + "\n" +
"Wave: " + (Game.data.levelEnemyWave + 1) + "/" + Game.Levels.data[Game.data.level].enemyWaves.length + "\n" +
"* Enemies of this wave: " + Game.data.enemies.length + "/" + Game.Levels.data[Game.data.level].enemyWaves[Game.data.levelEnemyWave].enemies.length + " (" + Game.getEnemiesAlive().length + " alive)\n" +
(!CB_Screen.isLandscape() ? "\n\nLandscape screen recommended!" : "") +
@@ -493,17 +563,17 @@ Visual.resizeElements = function(graphicSpritesSceneObject, avoidFillingMap)
//NOTE: some browsers will fail to enable full screen mode if it is not requested through a user-driven event (as "onClick", "onTouchStart", etc.).
Visual.fullScreenToggle = function()
{
- showMessage("Toggling full screen mode...");
+ logMessage("Toggling full screen mode...");
//If it is using full screen mode already, disables it:
if (CB_Screen.isFullScreen())
{
- showMessage("Full screen mode detected. Trying to restore normal mode...");
+ logMessage("Full screen mode detected. Trying to restore normal mode...");
CB_Screen.setFullScreen(false); //Uses the Fullscreen API and fallbacks to other methods internally, including NW.js, Electron ones, when not available.
}
//...otherwise, requests full screen mode:
else
{
- showMessage("Normal mode detected. Trying to enable full screen mode...");
+ logMessage("Normal mode detected. Trying to enable full screen mode...");
CB_Screen.setFullScreen(true, undefined, true); //Allows reloading into another (bigger) window (for legacy clients).
}
}
\ No newline at end of file
diff --git a/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/enemies.js b/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/enemies.js
index d2f2b6b4..e9d3345f 100644
--- a/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/enemies.js
+++ b/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/enemies.js
@@ -15,11 +15,11 @@ Enemy.prototype.type = 0; //Enemy type (0 by default).
Enemy.prototype.level = 0; //Enemy level (0 is the first one).
Enemy.prototype.position = { x: 0, y: 0, xScreen: 0, yScreen: 0 }; //Enemy position.
Enemy.prototype.rotation = 0; //Enemy rotation (they rotate to follow their path).
-Enemy.prototype.levelVitality = [ 100, 150, 300, 600 ]; //Enemy vitality, separated by level.
-Enemy.prototype.levelSpeed = [ 1, 2, 4, 8 ]; //Enemy speed (1 is normal speed), separated by level.
-Enemy.prototype.levelDamage = [ 1, 2, 3, 5 ]; //Enemy damage to user's vitality when it reaches the objective, separated by level.
-Enemy.prototype._levelMax = null; //Maximum enemy leveal which can be reached. It will be re-calculated in the constructor automatically.
-Enemy.prototype.vitality = null; //Enemy vitality. It will be re-calculated in the constructor automatically.
+Enemy.prototype.levelVitality = [ 100, 150, 300, 600, 1200 ]; //Enemy vitality, separated by level.
+Enemy.prototype.levelSpeed = [ 1, 2, 4, 8, 16 ]; //Enemy speed (1 is normal speed), separated by level.
+Enemy.prototype.levelDamage = [ 1, 2, 3, 5, 8 ]; //Enemy damage to user's vitality when it reaches the objective, separated by level.
+Enemy.prototype._levelMax = null; //Maximum enemy leveal which can be reached. It will be calculated in the constructor automatically.
+Enemy.prototype.vitality = null; //Enemy vitality. It will be calculated in the constructor automatically.
Enemy.prototype.isWalking = false; //Determines whether the enemy is currently walking through its path.
Enemy.prototype.isRotating = false; //Determines whether the enemy is currently rotating to follow its path.
Enemy.prototype.isDead = false; //Determines whether the enemy is dead or not.
@@ -36,7 +36,7 @@ Enemy.prototype._init = function(type, level, x, y, map)
this.position.x = typeof(x) !== "undefined" && x !== null ? x : this.position.x || 0;
this.position.y = typeof(y) !== "undefined" && y !== null ? y : this.position.y || 0;
this.level = level || this.level;
- this._levelMax = this._levelMax || Math.min(this.levelVitality, this.levelSpeed.length, this.levelDamage.length) - 1;
+ this._levelMax = this._levelMax || Math.min(this.levelVitality.length, this.levelSpeed.length, this.levelDamage.length) - 1;
if (this._levelMax < 0)
{
logMessage("ERROR: Maximum level for the enemy is a negative number!");
@@ -100,14 +100,25 @@ Enemy.prototype._getSprites = function(returnOnFail)
subSprite = sprite.getSubSprites()[0]; //Default enemy subSprite.
}
}
+
+ subSpriteVitality = sprite.getById("enemy_" + this.type + "_subsprites_vitality_" + this.id, null);
+ if (subSpriteVitality === null)
+ {
+ subSpriteVitality = sprite.getById("enemy_" + this.type + "_subsprites_vitality", null);
+ if (subSpriteVitality === null)
+ {
+ subSpriteVitality = sprite.getSubSprites()[1]; //Default enemy vitality subSprite.
+ }
+ }
}
}
if (spritesGroup === null) { logMessage("No sprites object could be found!"); return returnOnFail; }
else if (sprite === null) { logMessage("No sprite object could be found!"); return returnOnFail; }
else if (subSprite === null) { logMessage("No subSprite object could be found!"); return returnOnFail; }
+ else if (subSpriteVitality === null) { logMessage("No vitality subSprite object could be found!"); return returnOnFail; }
- return { spritesGroup: spritesGroup, sprite: sprite, subSprite: subSprite };
+ return { spritesGroup: spritesGroup, sprite: sprite, subSprite: subSprite, subSpriteVitality: subSpriteVitality };
}
@@ -120,10 +131,16 @@ Enemy.prototype._spritesLoad = function(returnOnFail)
sprites.subSprite = CB_copyObject(sprites.subSprite);
sprites.subSprite.id += "_" + this.id;
sprites.subSprite.disabled = false;
+ sprites.subSprite.data._enemyObject = sprites.subSpriteVitality.data._enemyObject = this;
+
+ sprites.subSpriteVitality = CB_copyObject(sprites.subSpriteVitality);
+ sprites.subSpriteVitality.id += "_" + this.id;
+ sprites.subSpriteVitality.disabled = false;
this._spritesUpdateCoordinates(this.position.x, this.position.y, sprites, null);
sprites.sprite.insertSubSprite(sprites.subSprite); //It also updates the internal "subSpritesByZIndex" array.
+ sprites.sprite.insertSubSprite(sprites.subSpriteVitality); //It also updates the internal "subSpritesByZIndex" array.
return sprites;
}
@@ -135,11 +152,16 @@ Enemy.prototype._spritesDisable = function(returnOnFail)
var sprites = this._getSprites(null);
if (sprites === null) { return returnOnFail; }
- sprites.subSprite = CB_copyObject(sprites.subSprite);
+ //sprites.subSprite = CB_copyObject(sprites.subSprite);
sprites.subSprite.disabled = true;
sprites.sprite.insertSubSprite(sprites.subSprite); //It also updates the internal "subSpritesByZIndex" array.
+ //sprites.subSpriteVitality = CB_copyObject(sprites.subSpriteVitality);
+ sprites.subSpriteVitality.disabled = true;
+
+ sprites.sprite.insertSubSprite(sprites.subSpriteVitality); //It also updates the internal "subSpritesByZIndex" array.
+
return sprites;
}
@@ -152,13 +174,37 @@ Enemy.prototype._spritesUpdateCoordinates = function(x, y, sprites, returnOnFail
sprites = sprites || this._getSprites(null);
if (sprites === null) { return returnOnFail; }
- this.position.xScreen = sprites.subSprite.left = screenCoordinates ? x : Game.Levels.getRealScreenLeft(x);
+ this.position.xScreen = sprites.subSprite.left = sprites.subSpriteVitality.left = screenCoordinates ? x : Game.Levels.getRealScreenLeft(x);
this.position.yScreen = sprites.subSprite.top = screenCoordinates ? y : Game.Levels.getRealScreenTop(y);
+ sprites.subSpriteVitality.top = sprites.subSprite.top + sprites.subSpriteVitality.height;
return sprites;
}
+Enemy.prototype._spritesRotate = function(direction, sprites)
+{
+ sprites = sprites || this._getSprites(null);
+
+ if (direction === "up")
+ {
+ sprites.subSprite.data.rotation = 90;
+ }
+ else if (direction === "down")
+ {
+ sprites.subSprite.data.rotation = 270;
+ }
+ else if (direction === "left")
+ {
+ sprites.subSprite.data.rotation = 0;
+ }
+ else if (direction === "right")
+ {
+ sprites.subSprite.data.rotation = 180;
+ }
+}
+
+
//Finds a starting point for the enemy to appear on the map and start its way:
Enemy._findStartingPoint = function(map)
{
@@ -262,7 +308,8 @@ Enemy.prototype.loopStep = function()
if (this._isObjectiveReached())
{
logMessage("Enemy #" + this.id + " reached destiny!");
- Game.data.vitality -= this.levelDamage[this.level];
+ Game.data.vitality -= Game.data._godMode ? 0 : this.levelDamage[this.level];
+ if (Game.data.vitality < 0) { Game.data.vitality = 0; }
this.succeeded = true;
this.die();
}
@@ -304,15 +351,6 @@ Enemy.prototype._walk = function(pathX, pathY)
this.isWalking = true;
- if (this._needsRotateToFollow(pathX, pathY))
- {
- this._pointPath(pathX, pathY);
- }
- else
- {
- this.isRotating = false;
- }
-
if (this._pathCurrent.points[this._pathCurrent.pathPointer].direction === "up")
{
//this.position.y--;
@@ -343,39 +381,37 @@ Enemy.prototype._walk = function(pathX, pathY)
return;
}
- //Stores the time when it has moved:
- this._walkLastTime = CB_Device.getTiming();
-
//Updates the sprite with the new position:
//this._spritesUpdateCoordinates(this.position.x, this.position.y);
//this._spritesUpdateCoordinates(this.position.x, this.position.y, null, null, true);
//CB_console("Enemy #" + this.id + " walking to (" + this.position.xScreen + ", " + this.position.yScreen + ") (on map: " + this.position.x + ", " + this.position.y + ")");
- this._spritesUpdateCoordinates(this.position.xScreen, this.position.yScreen, null, null, true);
-
- return true;
-}
+ var sprites = this._spritesUpdateCoordinates(this.position.xScreen, this.position.yScreen, null, null, true);
-
-//Rotates the enemy to follow its way:
-Enemy.prototype._pointPath = function(pathX, pathY)
-{
- this.isRotating = true;
+ //Rotates the sprite if needed:
+ this._spritesRotate(this._pathCurrent.points[this._pathCurrent.pathPointer].direction, sprites);
- //TO DO: do stuff.
-}
-
-
-//Tells whether the enemy needs to rotate in order to folow their path or not:
-Enemy.prototype._needsRotateToFollow = function(pathX, pathY)
-{
+ //Stores the time when it has moved:
+ this._walkLastTime = CB_Device.getTiming();
+ return true;
}
//Makes the enemy to die:
Enemy.prototype.die = function()
{
- logMessage("Enemy #" + this.id + " died!" + (this.succeeded ? " (reached destiny)" : " (no destiny reached)"));
+ if (this.succeeded)
+ {
+ Game.data.coins += (this.type + 1) * ((this.level + 1) * this.vitality);
+ logMessage("Enemy #" + this.id + " died! (destiny reached)");
+ }
+ else
+ {
+ Game.data.score += 10 * ((this.level + 1) * this.vitality);
+ Game.data.coins += 10 * (this.type + 1) * ((this.level + 1) * this.vitality);
+ logMessage("Enemy #" + this.id + " died! (no destiny reached)");
+ }
+
this.isDead = true;
this._spritesDisable();
}
diff --git a/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/img/enemy_0_sprites.gif b/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/img/enemy_0_sprites.gif
index 1f7ea0b9..587caa8c 100644
Binary files a/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/img/enemy_0_sprites.gif and b/crossbrowdy.com/_html/_doc/examples/EN/advanced/tower_defense_game_files/img/enemy_0_sprites.gif differ
diff --git a/crossbrowdy.com/files/CrossBrowdy_0.99.96.36.zip b/crossbrowdy.com/files/CrossBrowdy_0.99.96.36.zip
index acf27407..dedf5d79 100644
Binary files a/crossbrowdy.com/files/CrossBrowdy_0.99.96.36.zip and b/crossbrowdy.com/files/CrossBrowdy_0.99.96.36.zip differ
diff --git a/crossbrowdy.com/files/CrossBrowdy_examples.zip b/crossbrowdy.com/files/CrossBrowdy_examples.zip
index 0c203336..68b91bc2 100644
Binary files a/crossbrowdy.com/files/CrossBrowdy_examples.zip and b/crossbrowdy.com/files/CrossBrowdy_examples.zip differ