Code edit (1 edits merged)
Please save this source code
Code edit (9 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'intersects')' in or related to this line: 'if (self.centralHud.intersects(enemies[i])) {' Line Number: 219
Code edit (5 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: distanceToCenter is not defined' in or related to this line: 'if (distanceToCenter <= 100) {' Line Number: 53
Code edit (3 edits merged)
Please save this source code
User prompt
Play explosion sound in explode()
Code edit (3 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: Cannot read properties of undefined (reading 'destroy')' in or related to this line: 'enemies[i].destroy();' Line Number: 58
Code edit (1 edits merged)
Please save this source code
User prompt
in checkForCollision, wait for the explode anim to end before destorying the enemy
User prompt
implement the explode function, use the explosion asset. make id grow then disapear.
Code edit (20 edits merged)
Please save this source code
User prompt
implement Bullet.checkForCollision()
Code edit (1 edits merged)
Please save this source code
Code edit (10 edits merged)
Please save this source code
User prompt
in handlePlayingLoop, randomly change current3DSpaceAngles.deltaH and deltaV every 5 sec
Code edit (1 edits merged)
Please save this source code
User prompt
try using width and height instead of scale in `self.scale.set((5000 - self.z) / 5000);`
Code edit (1 edits merged)
Please save this source code
Code edit (4 edits merged)
Please save this source code
User prompt
Fighter speed should grow exponnetially
Code edit (4 edits merged)
Please save this source code
User prompt
fighters should always apear behind spaceship (in term of z-index)
Code edit (3 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 <= 100) {
			self.checkForCollision();
		}
	};
	self.checkForCollision = function () {
		for (var i = enemies.length - 1; i >= 0; i--) {
			if (self.intersects(enemies[i])) {
				// Handle collision: destroy bullet and enemy, update score, etc.
				self.destroy();
				enemies[i].explode(function (index) {
					return function () {
						if (enemies[index]) {
							enemies[index].destroy();
							enemies.splice(index, 1);
						}
					};
				}(i));
				if (bullets.indexOf(self) !== -1) {
					bullets.splice(bullets.indexOf(self), 1);
				}
				// Update score
				LK.setScore(LK.getScore() + 1);
				break;
			}
		}
	};
});
/***********************************************************************************/ 
/********************************** 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 () {
	var self = Container.call(this);
	var fighterGraphics = self.attachAsset('fighter', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 1;
	self.update = function () {
		self.speed = Math.exp((5000 - self.z) * 0.002); // Increase speed exponentially as they come closer
		self.z -= self.speed;
		var sizeRatio = (5000 - self.z) / 5000;
		fighterGraphics.width = 1024 * sizeRatio;
		fighterGraphics.height = 1024 * sizeRatio;
		var directionX = 0; //self.x - 1024; // 1024 is half the width of the screen
		var directionY = self.y - 512; // 1366 is half the height of the screen
		var length = Math.sqrt(directionX * directionX + directionY * directionY);
		if (length === 0) {
			length = 1;
		}
		directionX += current3DSpaceAngles.deltaH * 4000;
		directionY += current3DSpaceAngles.deltaV * 10;
		directionX /= length;
		directionY /= length;
		self.x += directionX * self.speed;
		self.y += directionY * self.speed;
		if (self.z < -2000 || self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732) {
			self.destroy();
		}
	};
	self.shoot = function () {
		var bullet = new Bullet(false);
		bullet.x = self.x;
		bullet.y = self.y + fighterGraphics.height / 2;
		bullets.push(bullet);
		game.addChild(bullet);
	};
	self.explode = function (callback) {
		var explosion = self.attachAsset('explosion1', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 100,
			height: 100
		});
		// Play explosion sound
		LK.getSound('explosion').play();
		var growInterval = LK.setInterval(function () {
			explosion.width += 10;
			explosion.height += 10;
			if (explosion.width >= fighterGraphics.width) {
				{
					fighterGraphics.visible = false;
				}
				if (explosion.width >= 512) {
					LK.clearInterval(growInterval);
					explosion.destroy();
					if (callback) {
						callback();
					}
				}
			}
		}, 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
	});
	var 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;
		self.targetLocked = false;
		if (!self.centralHud) {
			self.centralHud = self.attachAsset('aimingCentralHud', {
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.6,
				y: -100,
				tint: 0x00FF00
			});
		}
		for (var i = enemies.length - 1; i >= 0; i--) {
			if (self.centralHud.intersects(enemies[i])) {
				self.targetLocked = true;
				break;
			}
		}
		elf.centralHud.tint = self.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 player = {
	lives: 3
};
var nbStars = 80;
var starsSpeed = 10;
var stars = [];
var current3DSpaceAngles = {
	horizontalAngle: 0,
	verticalAngle: 0,
	deltaH: 0,
	deltaV: 0
};
var spaceship;
var cockpitDisplay;
var bullets = []; // Player's bullets
var enemies = [];
var rotationSpeed = 0.25;
var lastAngleChangeTime = Date.now();
var nextAngleChangeDelay = 4000;
var isDebug = true;
var fpsText;
var lastTick;
var frameCount;
var debugText;
var bgMusic;
/****************************************************************************************** */ 
/*********************************** UTILITY FUNCTIONS ************************************ */
/****************************************************************************************** */ 
function log() {
	if (isDebug) {
		var _console;
		(_console = console).log.apply(_console, arguments);
	}
}
/****************************************************************************************** */ 
/************************************** 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 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;
	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;
	}
	current3DSpaceAngles.deltaH = newDeltaH;
	current3DSpaceAngles.deltaV = newDeltaV;
	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);
		}
	}
}
/****************************************************************************************** */ 
/************************************* GAME STATES **************************************** */
/****************************************************************************************** */ 
function gameInitialize() {
	log("Game initialize...");
	bgMusic = LK.getSound('bgMusic');
	bgMusic.lastPlayTime = 0;
	initStars();
	spaceship = game.addChild(new Spaceship());
	spaceship.centralHud = spaceship.attachAsset('aimingCentralHud', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.6,
		y: -100,
		tint: 0x00FF00
	});
	// Initialize enemy fighters
	for (var i = 0; i < 1; i++) {
		var fighter = new Fighter();
		fighter.x = 1024 + (Math.random() > 0.5 ? -1 : 1) * 1024 * Math.random();
		fighter.scale.set(0);
		fighter.z = 2732;
		fighter.y = 512;
		enemies.push(fighter);
		game.addChild(fighter);
	}
	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.
	// 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();
	// Update enemy fighters
	for (var i = enemies.length - 1; i >= 0; i--) {
		if (enemies[i].z < -500 || enemies[i].x < 0 || enemies[i].x > 2048 || enemies[i].y < 0 || enemies[i].y > 2732) {
			enemies.splice(i, 1);
			// Respawn a new fighter
			var newFighter = new Fighter();
			newFighter.x = 1024 + (Math.random() > 0.5 ? -1 : 1) * 512 * Math.random();
			newFighter.z = 5000;
			newFighter.y = 1024 - 512 * Math.random();
			enemies.push(newFighter);
			game.addChildAt(newFighter, 0);
		}
	}
	// 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
}
// 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
@@ -168,9 +168,12 @@
 		rotation: Math.PI * 0.01
 	});
 	var centralHud = self.attachAsset('aimingCentralHud', {
 		anchorX: 0.5,
-		anchorY: 0.5
+		anchorY: 0.5,
+		alpha: 0.6,
+		y: -100,
+		tint: 0x00FF00
 	});
 	var spaceshipGraphics = self.attachAsset('spaceship', {
 		anchorX: 0.5,
 		anchorY: 0.5
@@ -186,8 +189,25 @@
 		// 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;
+		self.targetLocked = false;
+		if (!self.centralHud) {
+			self.centralHud = self.attachAsset('aimingCentralHud', {
+				anchorX: 0.5,
+				anchorY: 0.5,
+				alpha: 0.6,
+				y: -100,
+				tint: 0x00FF00
+			});
+		}
+		for (var i = enemies.length - 1; i >= 0; i--) {
+			if (self.centralHud.intersects(enemies[i])) {
+				self.targetLocked = true;
+				break;
+			}
+		}
+		elf.centralHud.tint = self.targetLocked ? 0x00FF00 : 0xFFFFFF;
 	};
 	self.shoot = function () {
 		if (self.isShooting) {
 			return;
@@ -492,8 +512,15 @@
 	bgMusic = LK.getSound('bgMusic');
 	bgMusic.lastPlayTime = 0;
 	initStars();
 	spaceship = game.addChild(new Spaceship());
+	spaceship.centralHud = spaceship.attachAsset('aimingCentralHud', {
+		anchorX: 0.5,
+		anchorY: 0.5,
+		alpha: 0.6,
+		y: -100,
+		tint: 0x00FF00
+	});
 	// Initialize enemy fighters
 	for (var i = 0; i < 1; i++) {
 		var fighter = new Fighter();
 		fighter.x = 1024 + (Math.random() > 0.5 ? -1 : 1) * 1024 * Math.random();
@@ -511,9 +538,9 @@
 		var debugMarker = LK.getAsset('debugMarker', {
 			anchorX: 0.5,
 			anchorY: 0.5,
 			x: 2048 * 0.5,
-			y: 2732 / 2
+			y: 2732
 		});
 		game.addChild(debugMarker);
 		fpsText = new Text2('FPS: 0', {
 			size: 50,
:quality(85)/https://cdn.frvr.ai/6614ebd2581bcd5d64e47d3c.png%3F3) 
 starfield.
:quality(85)/https://cdn.frvr.ai/6614f0a0581bcd5d64e47d60.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6614f8fd581bcd5d64e47d88.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6615359b581bcd5d64e47e4d.png%3F3) 
 remove
:quality(85)/https://cdn.frvr.ai/6645c16554089513d80f043c.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6645e84f54089513d80f046d.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6645e89454089513d80f0472.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66466b946fe714601b1f1655.png%3F3) 
 elongated futuristic laser canon gun green. top view
:quality(85)/https://cdn.frvr.ai/66466ef46fe714601b1f16a2.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/664770c654089513d80f06d7.png%3F3) 
 explosion from top. zenith view
:quality(85)/https://cdn.frvr.ai/66479389faf492230520fe83.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/664a1c47b47838566a410257.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/664a7039b47838566a4102b8.png%3F3) 
 white triangle.
:quality(85)/https://cdn.frvr.ai/664ae067ad944aed30f74ea0.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/664ae29ead944aed30f74ebd.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/664ae2f1ad944aed30f74ec1.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/664d1b43b47838566a410e81.png%3F3) 
 black background ethereal blue gas.
:quality(85)/https://cdn.frvr.ai/664d766bb47838566a4112ac.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/664e2c9eb47838566a411549.png%3F3) 
 black background ethereal centered galaxy.
:quality(85)/https://cdn.frvr.ai/664e2d87b47838566a41155f.png%3F3) 
 black background ethereal centered galaxy.
:quality(85)/https://cdn.frvr.ai/664e2e12b47838566a41156d.png%3F3) 
 black background ethereal centered planet.
:quality(85)/https://cdn.frvr.ai/664e2f5db47838566a411592.png%3F3) 
 close up of a giant red star. black background
:quality(85)/https://cdn.frvr.ai/664e44ffb47838566a41164e.png%3F3) 
 planet with rings. black background. full, with margin.
:quality(85)/https://cdn.frvr.ai/664f4520b47838566a411ae8.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/664f843db47838566a411c2b.png%3F3) 
 metalic oval border with bevel. Black. Electronic style. empty inside. no background
:quality(85)/https://cdn.frvr.ai/664f8ec67ab47f73c319ab09.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/664fb0ae52d9f25470380f56.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66535fb98e9db13a9f968f8d.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6653625b8e9db13a9f968fb1.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6653a2468e9db13a9f96905d.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66555c2f348e66c1af08c714.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6655bf35348e66c1af08cb63.png%3F3) 
 futuristic space fighter.. full front view
:quality(85)/https://cdn.frvr.ai/66562d67348e66c1af08ce36.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66562ef0348e66c1af08ce58.png%3F3) 
 Space scene with full earth (europe and africa side). High definition
:quality(85)/https://cdn.frvr.ai/6656afed6ccb0fa48f945d42.png%3F3) 
 elegant white rose in a long transparent futuristic glass tube.
:quality(85)/https://cdn.frvr.ai/6656bb3e6ccb0fa48f945d85.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6656bccf6ccb0fa48f945d95.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6656bcef6ccb0fa48f945d99.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6656bd4b6ccb0fa48f945da1.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6656bd786ccb0fa48f945da5.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/665e02c7798d160653f6b431.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6669e63510c85596d3f26f2f.png%3F3) 
 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