Code edit (7 edits merged)
Please save this source code
User prompt
in Spaceship update use currentFighter instead of enemies array to serach for intersects
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (4 edits merged)
Please save this source code
User prompt
in handleGlobalMovement if(currentFighter) update current3DSpaceAngles.deltaH and current3DSpaceAngles.deltaV in order to aim to currentFighter
Code edit (7 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: reset is not defined' in or related to this line: 'reset();' Line Number: 261
User prompt
Please fix the bug: 'ReferenceError: fighter is not defined' in or related to this line: 'enemies[fighter.index] = getFighter();' Line Number: 742
Code edit (1 edits merged)
Please save this source code
Code edit (11 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: sizeRatio is not defined' in or related to this line: 'log("iniZ=" + initialFighterZ, "z=" + self.z.toFixed(0), "sizeRatio=" + sizeRatio, " => w=h=" + self.width);' Line Number: 130
Code edit (1 edits merged)
Please save this source code
Code edit (14 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: i is not defined' in or related to this line: 'log("Check collid " + i, currentFighter.x, currentFighter.y);' Line Number: 63
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: currentFighter is not defined' in or related to this line: 'if (!isChangingDirection && !currentFighter && enemies.length > 0) {' Line Number: 624
Code edit (1 edits merged)
Please save this source code
User prompt
in checkForCollision, use keys array for the loop
Code edit (5 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'log("Check collid " + i, enemies[i].x, enemies[i].y);' Line Number: 61
Code edit (11 edits merged)
Please save this source code
User prompt
in Bullet.undate show distanceToCenter in debugtext
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
/****
* Classes
****/
/***********************************************************************************/
/********************************** BULLET CLASS ***********************************/
/***********************************************************************************/
var Bullet = Container.expand(function (isLeft, isTop) {
var self = Container.call(this);
self.isTop = isTop;
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
width: 10,
height: 250,
tint: 0x00FF00,
alpha: 0.8
});
self.distanceToCenter = 1024;
self.isLeft = isLeft;
self.speed = 10;
self.update = function () {
self.x += self.isLeft ? self.speed : -self.speed;
self.y += self.isTop ? self.speed * 0.6 : -self.speed * 0.6;
// Calculate distance to center and adjust width accordingly
self.distanceToCenter = Math.abs(self.x - 1024);
var shrinkRatio = 0.1 + Math.pow(self.distanceToCenter, 1.2) * 5 / Math.pow(1024, 1.2);
self.width = Math.max(0.5, 6 * Math.pow(shrinkRatio, 1.1));
self.height = Math.max(10, 250 * Math.pow(shrinkRatio, 1.1));
self.speed = Math.max(40, Math.min(100, 100 * Math.exp(self.distanceToCenter / 1024 - 1)));
if (self.distanceToCenter <= 75) {
self.checkForCollision();
}
};
self.checkForCollision = function () {
if (!currentFighter) {
return;
}
log("Check collid", currentFighter.x, currentFighter.y);
var touched = (currentFighter.x < 1024 && self.isLeft || currentFighter.x >= 1024 && !self.isLeft) && self.intersects(currentFighter);
if (touched) {
if (isDebug) {
debugText.setText("Distance to Center: " + self.distanceToCenter.toFixed(0));
}
// Handle collision: destroy bullet and enemy, update score, etc.
self.destroy();
currentFighter.explode();
if (bullets.indexOf(self) !== -1) {
bullets.splice(bullets.indexOf(self), 1);
}
// Update score
LK.setScore(LK.getScore() + 1);
}
};
});
/***********************************************************************************/
/********************************** COCKPIT CLASS ***********************************/
/***********************************************************************************/
var CockpitDisplay = Container.expand(function () {
var self = Container.call(this);
self.cockpitButtonStand = self.attachAsset('fireButtonStand', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9,
y: 2732 + 300
});
self.cockpitButtonBase = self.attachAsset('fireButtonBase', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 1,
y: 2732
});
self.cockpitButton = self.attachAsset('fireButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 2732 - 570
});
self.cockpitButton.originalScaleX = self.cockpitButton.scale.x;
self.cockpitButton.originalScaleY = self.cockpitButton.scale.y;
self.cockpitButton.isAnimating = false;
});
/***********************************************************************************/
/********************************** FIGHTER CLASS **********************************/
/***********************************************************************************/
var Fighter = Container.expand(function (index) {
var self = Container.call(this);
self.baseSize = 512;
var outOffset = 512;
var fighterGraphics = self.attachAsset('fighter', {
anchorX: 0.5,
anchorY: 0.5,
width: self.baseSize,
height: self.baseSize
});
self.index = index;
self.isActive = false;
self.speedX = 1;
self.speedY = 1;
self.speedZ = 1;
self.sizeRatio = 1;
self.finalSpeedY = 0;
self.finalSpeedZ = 0;
self.isDestroyed = false;
self.update = function () {
if (!self.isActive) {
return;
}
self.sizeRatio = initialFighterZ / (Math.abs(self.z) * 20 + 0.1);
self.sizeRatio = Math.max(0.01, Math.min(2, self.sizeRatio));
self.width = self.baseSize * self.sizeRatio;
self.height = self.baseSize * self.sizeRatio;
//log("iniZ=" + initialFighterZ, "z=" + self.z.toFixed(0), "sizeRatio=" + self.sizeRatio, " baseSize" + self.baseSize, " => w=h=" + self.width);
if (self.sizeRatio <= 1) {
self.speedZ = self.speedZ + 0.02;
} else {
self.speedZ = self.speedZ * self.sizeRatio * 0.90;
}
if (self.isDestroyed) {
// Stop increase speed when destroyed
if (!self.finalSpeedY) {
self.finalSpeedY = self.speedY * 0.5;
self.finalSpeedZ = self.speedZ * 0.5;
}
self.speedY = self.finalSpeedY;
self.speedZ = self.finalSpeedZ;
}
var directionX = 0;
var directionY = Math.sign(self.y);
var length = Math.sqrt(directionX * directionX + directionY * directionY);
if (length === 0) {
length = 1;
}
directionX += current3DSpaceAngles.deltaH * 10;
directionY += current3DSpaceAngles.deltaV * 10;
directionX /= length;
directionY /= length;
self.x += directionX * self.speedX;
self.y += self.speedY * (self.sizeRatio > 0.3 ? 50 * Math.pow(self.sizeRatio, 2) : 0.5);
self.z -= self.speedZ;
// Remove when out of screen
if (!self.isDestroyed && (self.z <= 0 || self.x < -outOffset || self.y < -outOffset || self.x > 2048 + outOffset || self.y > 2732 + outOffset)) {
log(self.index + ") Fighter passed behind. cleaning currentFighter...");
//game.removeChild(self);
self.reset();
currentFighter = null;
}
};
self.reset = function () {
self.visible = false;
self.isActive = false;
self.speedX = 1;
self.speedY = 1;
self.speedZ = 1;
self.sizeRatio = 1;
self.width = self.baseSize * self.sizeRatio;
self.height = self.baseSize * self.sizeRatio;
log(self.index + ") Reseting width to :" + (self.baseSize * self.sizeRatio).toFixed(0), " => " + self.width);
self.finalSpeedY = 0;
self.finalSpeedZ = 0;
self.x = 1024; // TEMP DEBUG 512 + 1024 * Math.random();
self.z = initialFighterZ;
self.y = 1366 - 512 * Math.random();
self.isDestroyed = false;
};
self.activate = function () {
self.visible = true;
self.isActive = true;
};
self.shoot = function () {
var bullet = new Bullet(false);
bullet.x = self.x;
bullet.y = self.y + fighterGraphics.height / 2;
bullets.push(bullet);
game.addChildAt(bullet, 0);
};
self.explode = function (callback) {
if (self.isDestroyed) {
return;
}
self.isDestroyed = true;
log(self.index + ") Killed");
var explosion = self.attachAsset('explosion1', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
width: 256,
height: 256
});
var explosion2 = self.attachAsset('explosion2', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
width: 128,
height: 128
});
// Play explosion sound
LK.getSound('explosion').play();
var growInterval = LK.setInterval(function () {
explosion.width += 50;
explosion.height += 50;
if (explosion.width >= fighterGraphics.width) {
if (explosion.width >= 512) {
fighterGraphics.visible = false;
}
if (explosion.width >= 2048) {
explosion2.width += 50;
explosion2.height += 50;
explosion.alpha -= 0.05;
}
if (explosion.width >= 4096) {
LK.clearInterval(growInterval);
explosion.destroy();
explosion2.destroy();
//if (enemies[self.index]) {
//releaseFighter(self);
//delete enemies[self.index];
//var keys = Object.keys(enemies);
currentNbEnnemies--;
if (!currentNbEnnemies) {
log("All enemies cleared => Next level");
cleanPlayingState();
} else {
log(currentNbEnnemies + " Enemy to go");
}
// } else {
// log("Emeny " + self.index + " already removed");
// }
}
}
}, 16); // 60 FPS
};
});
/***********************************************************************************/
/******************************** SPACESHIP CLASS **********************************/
/***********************************************************************************/
var Spaceship = Container.expand(function () {
var self = Container.call(this);
var canonLeft = self.attachAsset('canon', {
anchorX: 0.5,
anchorY: 0.5,
x: -1100,
y: 650,
rotation: -Math.PI * 0.01
});
var canonRight = self.attachAsset('canon', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: -1,
x: 1100,
y: 650,
rotation: Math.PI * 0.01
});
self.centralHud = self.attachAsset('aimingCentralHud', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6,
y: -100,
tint: 0x00FF00
});
var spaceshipGraphics = self.attachAsset('spaceship', {
anchorX: 0.5,
anchorY: 0.5
});
self.coords = {
x: 0,
y: 0,
z: 0
};
self.speed = 0.01;
self.isShooting = false;
self.update = function () {
// Update space coordinates
spaceship.coords.x += Math.sin(current3DSpaceAngles.horizontalAngle) * spaceship.speed;
spaceship.coords.y += Math.cos(current3DSpaceAngles.verticalAngle) * spaceship.speed;
spaceship.coords.z += Math.sin(current3DSpaceAngles.verticalAngle) * Math.cos(current3DSpaceAngles.horizontalAngle) * spaceship.speed;
var targetLocked = false;
var keys = Object.keys(enemies);
for (var i = keys.length - 1; i >= 0; i--) {
if (self.centralHud.intersects(enemies[keys[i]])) {
targetLocked = true;
break;
}
}
self.centralHud.tint = targetLocked ? 0x00FF00 : 0xFFFFFF;
};
self.shoot = function () {
if (self.isShooting) {
return;
}
self.isShooting = true;
// Recoil effect for left canon
var originalLeftX = canonLeft.x;
var originalLeftY = canonLeft.y;
var recoilDistance = 40;
var recoilSpeed = 5;
var recoilLeftInterval = LK.setInterval(function () {
canonLeft.x -= recoilSpeed;
canonLeft.y += recoilSpeed;
if (canonLeft.x <= originalLeftX - recoilDistance) {
LK.clearInterval(recoilLeftInterval);
var returnLeftInterval = LK.setInterval(function () {
canonLeft.x += recoilSpeed;
canonLeft.y -= recoilSpeed;
if (canonLeft.x >= originalLeftX) {
canonLeft.x = originalLeftX;
canonLeft.y = originalLeftY;
LK.clearInterval(returnLeftInterval);
self.isShooting = false;
}
}, 16);
}
}, 16);
// Recoil effect for right canon
var originalRightX = canonRight.x;
var originalRightY = canonRight.y;
var recoilRightInterval = LK.setInterval(function () {
canonRight.x += recoilSpeed;
canonRight.y += recoilSpeed;
if (canonRight.x >= originalRightX + recoilDistance) {
LK.clearInterval(recoilRightInterval);
var returnRightInterval = LK.setInterval(function () {
canonRight.x -= recoilSpeed;
canonRight.y -= recoilSpeed;
if (canonRight.x <= originalRightX) {
canonRight.x = originalRightX;
canonRight.y = originalRightY;
LK.clearInterval(returnRightInterval);
}
}, 16);
}
}, 16);
// Play laserShot sound
LK.getSound('laserShot').play();
// Spawn bullets from side canons
var leftBullet = new Bullet(true);
leftBullet.x = 0; // Adjust for left canon position
leftBullet.y = self.y + 512; // Start the bullet just above the spaceship
leftBullet.rotation = Math.PI * 0.30;
game.addChildAt(leftBullet, 0);
bullets.push(leftBullet);
var rightBullet = new Bullet(false);
rightBullet.x = game.width; // Adjust for right canon position
rightBullet.y = self.y + 512; // Start the bullet just above the spaceship
rightBullet.rotation = -Math.PI * 0.30;
game.addChildAt(rightBullet, 0);
bullets.push(rightBullet);
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 // Initialize game with a black background
});
/****
* Game Code
****/
function animateCockpitButton() {
if (cockpitDisplay.cockpitButton.isAnimating) {
return;
}
cockpitDisplay.cockpitButton.isAnimating = true;
var moveDown = true;
var originalY = cockpitDisplay.cockpitButton.y;
var originalBaseY = cockpitDisplay.cockpitButtonBase.y;
var animationInterval = LK.setInterval(function () {
if (moveDown) {
cockpitDisplay.cockpitButton.y += 15;
cockpitDisplay.cockpitButtonBase.y += 1;
if (cockpitDisplay.cockpitButton.y >= originalY + 20) {
moveDown = false;
}
} else {
cockpitDisplay.cockpitButton.y -= 15;
cockpitDisplay.cockpitButtonBase.y -= 1;
if (cockpitDisplay.cockpitButton.y <= originalY) {
cockpitDisplay.cockpitButton.y = originalY;
cockpitDisplay.cockpitButtonBase.y = originalBaseY;
cockpitDisplay.cockpitButton.isAnimating = false;
LK.clearInterval(animationInterval);
}
}
}, 16); // 60 FPS
}
/*
# Space Strike
### Game Design and Planning
1. **Game Objectives**: Defeating all enemy fighters.
2. **Game Levels**: Random map with an increasing number of ennemy figthers per level.
3. **Game Assets**:
4. **Game Mechanics**:
1. **Player Interaction**: 1st person view. Tap to shoot.
4. **Game Loop and Events**: Objects updates occur in the game loop. Input events are handled in input functions.
5. **Scoring and Progression**: Player's score is updated when killing ennemies. When no more ennemies game switches to next level.
6. **Game Over and Reset**: The game is over when player's lives reaches zero.
*/
/****************************************************************************************** */
/************************************** GLOBAL VARIABLES ********************************** */
/****************************************************************************************** */
// Enumeration for game states
var GAME_STATE = {
INIT: 'INIT',
MENU: 'MENU',
HELP: 'HELP',
STARTING: 'STARTING',
NEW_ROUND: 'NEW_ROUND',
PLAYING: 'PLAYING',
SCORE: 'SCORE'
};
var gameState = GAME_STATE.INIT;
var currentLevel = 0;
var currentNbEnnemies = 0;
var player = {
lives: 3
};
var nbStars = 80;
var starsSpeed = 10;
var stars = [];
var current3DSpaceAngles = {
horizontalAngle: 0,
verticalAngle: 0,
deltaH: 0,
deltaV: 0
};
var initialFighterZ = 2048;
var spaceship;
var cockpitDisplay;
var bullets = []; // Player's bullets
var enemies = {}; // Ennemy fighters
var fighterPool = [];
var rotationSpeed = 0.25;
var isChangingDirection = false;
var currentFighter = null;
var lastAngleChangeTime = Date.now();
var nextAngleChangeDelay = 4000;
var isDebug = true;
var fpsText;
var lastTick;
var frameCount;
var debugText;
var bgMusic;
var currentIndex = 0;
/****************************************************************************************** */
/*********************************** UTILITY FUNCTIONS ************************************ */
/****************************************************************************************** */
function log() {
if (isDebug) {
var _console;
(_console = console).log.apply(_console, arguments);
}
}
function getNextIndex() {
currentIndex++;
return currentIndex;
}
/****************************************************************************************** */
/************************************** INPUT HANDLERS ************************************ */
/****************************************************************************************** */
game.on('down', function (x, y, obj) {
switch (gameState) {
case GAME_STATE.MENU:
gameMenuDown(x, y, obj);
break;
case GAME_STATE.STARTING:
gameStartingDown(x, y, obj);
break;
case GAME_STATE.PLAYING:
gamePlayingDown(x, y, obj);
break;
case GAME_STATE.SCORE:
// Handle score display logic here
break;
}
});
function gameMenuDown(x, y, obj) {
log("gameMenuDown...");
cleanMenuState();
initStartingState();
}
function gameStartingDown(x, y, obj) {
// TEMPORARY : Avoid multiple clicks
//cleanStartingState();
//initPlayingState();
}
function gamePlayingDown(x, y, obj) {
log("gamePlayingDown ...");
spaceship.shoot();
animateCockpitButton();
}
/****************************************************************************************** */
/************************************* GAME FUNCTIONS **************************************** */
/****************************************************************************************** */
function initStars() {
for (var i = 0; i < nbStars; i++) {
var star = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9,
x: Math.random() * 2048,
y: Math.random() * 2732
});
stars.push(star);
game.addChild(star);
}
// Farther stars
for (var i = 0; i < nbStars * 2; i++) {
var star = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5,
alpha: Math.random(),
x: Math.random() * 2048,
y: Math.random() * 2732,
slow: true
});
stars.push(star);
game.addChild(star);
}
}
function starFieldAnimation() {
stars.forEach(function (star) {
// Calculate direction vector from center to star
var directionX = star.x - 1024; // 1024 is half the width of the screen
var directionY = star.y - 1366; // 1366 is half the height of the screen
// Normalize direction
var length = Math.sqrt(directionX * directionX + directionY * directionY);
if (length === 0) {
// Prevent division by zero
length = 1;
}
directionX /= length;
directionY /= length;
// Add offset based on current3DSpaceAngles
directionX += current3DSpaceAngles.deltaH * 10; //.horizontalAngle;
directionY += current3DSpaceAngles.deltaV * 10; //.verticalAngle;
// Move star away from center
// Increase star size as it moves away to simulate faster movement
var sizeIncrease = Math.min(Math.abs(directionX * 2), Math.abs(directionY * 2));
star.width = Math.min(20, star.width + sizeIncrease * 0.05 * (star.slow ? 0 : 1)); // Limit width to 20
star.height = star.width;
star.x += directionX * starsSpeed * (star.slow ? 0.5 : 1); // Increase speed to 10 for faster star movement
star.y += directionY * starsSpeed * (star.slow ? 0.5 : 1);
if (star.alpha < 1) {
star.alpha = Math.min(1, star.alpha + 0.01);
}
// Reset star position if it moves off screen
if (star.x < 0 || star.x > 2048 || star.y < 0 || star.y > 2732) {
star.x = Math.random() * 2048;
star.y = Math.random() * 2732;
// Reset height to initial value
star.width = Math.random() * 10;
star.height = star.width;
star.alpha = Math.random() * (star.slow ? Math.random() * 0.5 : 1);
}
});
// Move nebulas images here .x-=0.1
}
function mapZtoScale(z) {
if (z <= 0) {
return 2; // Handle non-positive inputs (optional)
}
// Adjusted base function (linear decay)
var base = -z / 512 + 4; // Adjust coefficients for better fit
// Smoothing term (optional, remove for strictly increasing function)
var smoothTerm = Math.exp(-Math.pow(z - 2048, 2) / 10000);
// Combine base and smoothing term with an adjustable weight
var weight = 0.8; // Adjust weight between 0 (no smoothing) and 1 (full smoothing)
return weight * base + (1 - weight) * smoothTerm;
}
function loopBgMusic() {
if (bgMusic && Date.now() - bgMusic.lastPlayTime > 10000) {
bgMusic.lastPlayTime = Date.now();
bgMusic.play();
}
}
function handleGlobalMovement() {
if (Date.now() - lastAngleChangeTime < nextAngleChangeDelay) {
return;
}
var newDeltaH = 0;
var newDeltaV = 0;
isChangingDirection = false;
if (current3DSpaceAngles.deltaH == 0 & current3DSpaceAngles.deltaH == 0) {
var rH = Math.random();
var rV = Math.random();
var dirH = rH < 0.33 ? 1 : rH > 0.66 ? -1 : 0;
var dirV = rV < 0.33 ? 1 : rV > 0.66 ? -1 : 0;
newDeltaH = rH * 0.5 * dirH;
newDeltaV = rV * 0.8 * dirV;
isChangingDirection = true;
}
//current3DSpaceAngles.deltaH = newDeltaH; // TEMP DEBUG !!!
//current3DSpaceAngles.deltaV = newDeltaV; // TEMP DEBUG !!!
lastAngleChangeTime = Date.now();
nextAngleChangeDelay = 2000 + 2000 * Math.random();
}
function handleBulletsLifeCycle() {
for (var i = bullets.length - 1; i >= 0; i--) {
if (bullets[i].distanceToCenter <= 4) {
// Assuming a small threshold around the center for destruction
bullets[i].destroy();
bullets.splice(i, 1);
}
}
}
function getFighter() {
return new Fighter(getNextIndex()); // No pooling for now
/*
if (fighterPool.length > 0) {
log("Poping fighter...");
return fighterPool.pop();
} else {
log("Creating new fighter...");
return new Fighter(getNextIndex());
}
*/
}
function releaseFighter(fighter) {
log("releaseFighter ", fighter.index);
game.removeChild(fighter);
fighter.reset(); // Reset the fighter's properties
//fighterPool.push(fighter); // No pooling for now
}
function handleFightersLifeCycle() {
//!isChangingDirection && // TEMP DEBUG !!!!
if (currentFighter == null) {
log("Setting currentFighter...");
log("enemies:", enemies);
var keys = Object.keys(enemies);
// Select random inactive enemy
for (var i = 0; i < keys.length; i++) {
if (!enemies[keys[i]].isDestroyed && !enemies[keys[i]].isActive) {
log("selecting " + i + "/" + keys.length);
currentFighter = enemies[keys[i]];
break;
}
}
if (currentFighter) {
currentFighter.reset();
game.addChildAt(currentFighter, 0);
}
log("=> currentFighter=", currentFighter);
}
}
/****************************************************************************************** */
/************************************* GAME STATES **************************************** */
/****************************************************************************************** */
function gameInitialize() {
log("Game initialize...");
bgMusic = LK.getSound('bgMusic');
bgMusic.lastPlayTime = 0;
initStars();
spaceship = game.addChild(new Spaceship());
//enemies[0].z = 1024; // TEMP DEEBUG
spaceship.x = 2048 / 2; // Center spaceship horizontally
spaceship.y = 2732 - spaceship.height / 2; // Position spaceship near the bottom of the screen
cockpitDisplay = game.addChild(new CockpitDisplay());
cockpitDisplay.x = 2048 / 2; // Center cockpit display horizontally
if (isDebug) {
var debugMarker = LK.getAsset('debugMarker', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 * 0.5,
y: 2732
});
game.addChild(debugMarker);
fpsText = new Text2('FPS: 0', {
size: 50,
fill: "#ffffff"
});
// Position FPS text at the bottom-right corner
fpsText.anchor.set(1, 1); // Anchor to the bottom-right
LK.gui.bottomRight.addChild(fpsText);
// Update FPS display every second
lastTick = Date.now();
frameCount = 0;
// Debug text to display cube information
debugText = new Text2('Debug Info', {
size: 50,
fill: "#ffffff"
});
debugText.anchor.set(0.5, 0); // Anchor to the bottom-right
LK.gui.top.addChild(debugText);
}
initMenuState();
}
// GAME MENU
function initMenuState() {
log("initMenuState...");
gameState = GAME_STATE.MENU;
log("bgMusic volume", bgMusic.volume);
}
function handleMenuLoop() {
// Menu animations here
starFieldAnimation(); // Call the animation function within the game tick
}
function cleanMenuState() {
log("cleanMenuState...");
}
// STARTING
function initStartingState() {
log("initStartingState...");
gameState = GAME_STATE.STARTING;
// Round preparation logic here.
currentLevel++;
log("Level:" + currentLevel);
currentNbEnnemies = currentLevel;
for (var i = 0; i < currentNbEnnemies; i++) {
// Initialize first enemy fighter
var fighter = getFighter();
fighter.x = 1024; // TEMP DEBUG + (Math.random() > 0.5 ? -1 : 1) * 1024 * Math.random();
fighter.z = initialFighterZ;
fighter.y = 1024;
enemies[fighter.index] = fighter;
game.addChildAt(fighter, 0);
currentFighter = fighter;
currentFighter.activate();
}
// TEMPORARY.
cleanStartingState();
initPlayingState();
}
function handleStartingLoop() {
// Round Starting animations here
}
function cleanStartingState() {
log("cleanStartingState...");
}
// PLAYING
function initPlayingState() {
log("initPlayingState...");
gameState = GAME_STATE.PLAYING;
}
function handlePlayingLoop() {
loopBgMusic();
handleGlobalMovement();
starFieldAnimation();
handleBulletsLifeCycle();
handleFightersLifeCycle();
// Update angles at a lower rate using modulo on ticks
if (LK.ticks % 15 == 0) {
current3DSpaceAngles.horizontalAngle += current3DSpaceAngles.deltaH;
current3DSpaceAngles.verticalAngle += current3DSpaceAngles.deltaV;
}
// Rotate cockpitDisplay based on current3DSpaceAngles.horizontalAngle
if (cockpitDisplay.cockpitBase) {
cockpitDisplay.cockpitBase.rotation += -current3DSpaceAngles.deltaH - cockpitDisplay.cockpitBase.rotation >= 0.02 ? 0.1 : 0;
cockpitDisplay.cockpitBase.rotation += -current3DSpaceAngles.deltaH - cockpitDisplay.cockpitBase.rotation <= -0.02 ? -0.1 : 0;
cockpitDisplay.cockpitBase.rotation = Math.min(Math.PI * 0.3, Math.max(-Math.PI * 0.3, cockpitDisplay.cockpitBase.rotation));
cockpitDisplay.cockpitBase.scale.y = 1.5 + current3DSpaceAngles.deltaV * 0.5; // Illustrate vertical rotation by scaling the wheel
}
if (isDebug) {
//debugText.setText("lives: " + player.lives);
// FPS
var now = Date.now();
frameCount++;
if (now - lastTick >= 1000) {
// Update every second
fpsText.setText('FPS: ' + frameCount);
frameCount = 0;
lastTick = now;
}
}
}
function cleanPlayingState() {
log("cleanPlayingState...");
// TODO Remove elements
enemies = {};
// TEMPORAY next round
initStartingState();
}
// SCORE
function initScoreState() {
log("initScoreState...");
gameState = GAME_STATE.SCORE;
// TODO add score elements
// TEMPORARY : Avoid multiple clicks
cleanScoreState();
}
function handleScoreLoop() {
// Score display logic here
}
function cleanScoreState() {
log("cleanScoreState...");
LK.showGameOver();
}
/***********************************************************************************/
/******************************** MAIN GAME LOOP ***********************************/
/***********************************************************************************/
game.update = function () {
switch (gameState) {
case GAME_STATE.MENU:
handleMenuLoop();
break;
case GAME_STATE.STARTING:
handleStartingLoop();
break;
case GAME_STATE.PLAYING:
handlePlayingLoop();
break;
case GAME_STATE.SCORE:
handleScoreLoop();
break;
}
};
gameInitialize(); // Initialize the game ===================================================================
--- original.js
+++ change.js
@@ -84,26 +84,33 @@
/***********************************************************************************/
var Fighter = Container.expand(function (index) {
var self = Container.call(this);
self.baseSize = 512;
+ var outOffset = 512;
var fighterGraphics = self.attachAsset('fighter', {
anchorX: 0.5,
- anchorY: 0.5
+ anchorY: 0.5,
+ width: self.baseSize,
+ height: self.baseSize
});
self.index = index;
+ self.isActive = false;
self.speedX = 1;
self.speedY = 1;
self.speedZ = 1;
self.sizeRatio = 1;
self.finalSpeedY = 0;
self.finalSpeedZ = 0;
self.isDestroyed = false;
self.update = function () {
+ if (!self.isActive) {
+ return;
+ }
self.sizeRatio = initialFighterZ / (Math.abs(self.z) * 20 + 0.1);
self.sizeRatio = Math.max(0.01, Math.min(2, self.sizeRatio));
self.width = self.baseSize * self.sizeRatio;
self.height = self.baseSize * self.sizeRatio;
- log("iniZ=" + initialFighterZ, "z=" + self.z.toFixed(0), "sizeRatio=" + self.sizeRatio, " => w=h=" + self.width);
+ //log("iniZ=" + initialFighterZ, "z=" + self.z.toFixed(0), "sizeRatio=" + self.sizeRatio, " baseSize" + self.baseSize, " => w=h=" + self.width);
if (self.sizeRatio <= 1) {
self.speedZ = self.speedZ + 0.02;
} else {
self.speedZ = self.speedZ * self.sizeRatio * 0.90;
@@ -129,31 +136,37 @@
directionY /= length;
self.x += directionX * self.speedX;
self.y += self.speedY * (self.sizeRatio > 0.3 ? 50 * Math.pow(self.sizeRatio, 2) : 0.5);
self.z -= self.speedZ;
- var outOffset = 512;
// Remove when out of screen
if (!self.isDestroyed && (self.z <= 0 || self.x < -outOffset || self.y < -outOffset || self.x > 2048 + outOffset || self.y > 2732 + outOffset)) {
- log("Fighter out. cleaning currentFighter...");
- game.removeChild(self);
- currentFighter = null;
+ log(self.index + ") Fighter passed behind. cleaning currentFighter...");
+ //game.removeChild(self);
self.reset();
+ currentFighter = null;
}
};
self.reset = function () {
+ self.visible = false;
+ self.isActive = false;
self.speedX = 1;
self.speedY = 1;
self.speedZ = 1;
self.sizeRatio = 1;
self.width = self.baseSize * self.sizeRatio;
self.height = self.baseSize * self.sizeRatio;
+ log(self.index + ") Reseting width to :" + (self.baseSize * self.sizeRatio).toFixed(0), " => " + self.width);
self.finalSpeedY = 0;
self.finalSpeedZ = 0;
self.x = 1024; // TEMP DEBUG 512 + 1024 * Math.random();
self.z = initialFighterZ;
self.y = 1366 - 512 * Math.random();
self.isDestroyed = false;
};
+ self.activate = function () {
+ self.visible = true;
+ self.isActive = true;
+ };
self.shoot = function () {
var bullet = new Bullet(false);
bullet.x = self.x;
bullet.y = self.y + fighterGraphics.height / 2;
@@ -164,9 +177,9 @@
if (self.isDestroyed) {
return;
}
self.isDestroyed = true;
- log("Killed Emeny " + self.index);
+ log(self.index + ") Killed");
var explosion = self.attachAsset('explosion1', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
@@ -199,21 +212,22 @@
if (explosion.width >= 4096) {
LK.clearInterval(growInterval);
explosion.destroy();
explosion2.destroy();
- if (enemies[self.index]) {
- delete enemies[self.index];
- releaseFighter(self);
- var keys = Object.keys(enemies);
- if (!keys.length) {
- log("All enemies cleared => Next level");
- cleanPlayingState();
- } else {
- log(keys.length + " Enemy to go");
- }
+ //if (enemies[self.index]) {
+ //releaseFighter(self);
+ //delete enemies[self.index];
+ //var keys = Object.keys(enemies);
+ currentNbEnnemies--;
+ if (!currentNbEnnemies) {
+ log("All enemies cleared => Next level");
+ cleanPlayingState();
} else {
- log("Emeny " + self.index + " already removed");
+ log(currentNbEnnemies + " Enemy to go");
}
+ // } else {
+ // log("Emeny " + self.index + " already removed");
+ // }
}
}
}, 16); // 60 FPS
};
@@ -382,9 +396,9 @@
1. **Player Interaction**: 1st person view. Tap to shoot.
4. **Game Loop and Events**: Objects updates occur in the game loop. Input events are handled in input functions.
5. **Scoring and Progression**: Player's score is updated when killing ennemies. When no more ennemies game switches to next level.
6. **Game Over and Reset**: The game is over when player's lives reaches zero.
-*/
+*/
/****************************************************************************************** */
/************************************** GLOBAL VARIABLES ********************************** */
/****************************************************************************************** */
// Enumeration for game states
@@ -398,8 +412,9 @@
SCORE: 'SCORE'
};
var gameState = GAME_STATE.INIT;
var currentLevel = 0;
+var currentNbEnnemies = 0;
var player = {
lives: 3
};
var nbStars = 80;
@@ -591,31 +606,40 @@
}
}
}
function getFighter() {
+ return new Fighter(getNextIndex()); // No pooling for now
+ /*
if (fighterPool.length > 0) {
- log("Poping fighter...");
- return fighterPool.pop();
+ log("Poping fighter...");
+ return fighterPool.pop();
} else {
- log("Creating new fighter...");
- return new Fighter(getNextIndex());
+ log("Creating new fighter...");
+ return new Fighter(getNextIndex());
}
+ */
}
function releaseFighter(fighter) {
log("releaseFighter ", fighter.index);
game.removeChild(fighter);
fighter.reset(); // Reset the fighter's properties
- fighterPool.push(fighter);
+ //fighterPool.push(fighter); // No pooling for now
}
function handleFightersLifeCycle() {
//!isChangingDirection && // TEMP DEBUG !!!!
if (currentFighter == null) {
log("Setting currentFighter...");
log("enemies:", enemies);
var keys = Object.keys(enemies);
- if (keys.length) {
- log("key 0 =", keys[0]);
- currentFighter = enemies[keys[0]];
+ // Select random inactive enemy
+ for (var i = 0; i < keys.length; i++) {
+ if (!enemies[keys[i]].isDestroyed && !enemies[keys[i]].isActive) {
+ log("selecting " + i + "/" + keys.length);
+ currentFighter = enemies[keys[i]];
+ break;
+ }
+ }
+ if (currentFighter) {
currentFighter.reset();
game.addChildAt(currentFighter, 0);
}
log("=> currentFighter=", currentFighter);
@@ -682,17 +706,19 @@
gameState = GAME_STATE.STARTING;
// Round preparation logic here.
currentLevel++;
log("Level:" + currentLevel);
- for (var i = 0; i < currentLevel; i++) {
+ currentNbEnnemies = currentLevel;
+ for (var i = 0; i < currentNbEnnemies; i++) {
// Initialize first enemy fighter
var fighter = getFighter();
fighter.x = 1024; // TEMP DEBUG + (Math.random() > 0.5 ? -1 : 1) * 1024 * Math.random();
fighter.z = initialFighterZ;
fighter.y = 1024;
enemies[fighter.index] = fighter;
game.addChildAt(fighter, 0);
currentFighter = fighter;
+ currentFighter.activate();
}
// TEMPORARY.
cleanStartingState();
initPlayingState();
starfield.
remove
elongated futuristic laser canon gun green. top view
explosion from top. zenith view
white triangle.
black background ethereal blue gas.
black background ethereal centered galaxy.
black background ethereal centered galaxy.
black background ethereal centered planet.
close up of a giant red star. black background
planet with rings. black background. full, with margin.
metalic oval border with bevel. Black. Electronic style. empty inside. no background
futuristic space fighter.. full front view
Space scene with full earth (europe and africa side). High definition
elegant white rose in a long transparent futuristic glass tube.
laserShot
Sound effect
bgMusic
Sound effect
explosion
Sound effect
laserShot2
Sound effect
detectionBeep1
Sound effect
fighterPassing
Sound effect
targetFoundBeep
Sound effect
damage
Sound effect
warning
Sound effect
startSound
Sound effect
acceleration
Sound effect
teamKill
Sound effect
finalExplosion
Sound effect