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