User prompt
add a new type of obstacle that the player can destroy, its a hole, if the player dont avoid it, he will take damage
User prompt
adjust the hit effect for, just make the player sprite turn red for 0.2 seconds and turn back to normal. and only when the player dies you can blink the screen with the red effect ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
define the updateHealthDisplay before calling it
User prompt
create an function that updates the health display for when the player hit an obstacle or get hit by an enemy bullet
User prompt
Please fix the bug: 'ReferenceError: updateHealthDisplay is not defined' in or related to this line: 'updateHealthDisplay();' Line Number: 243
User prompt
Please fix the bug: 'ReferenceError: updateHealthDisplay is not defined' in or related to this line: 'updateHealthDisplay();' Line Number: 243
User prompt
Please fix the bug: 'ReferenceError: updateHealthDisplay is not defined' in or related to this line: 'updateHealthDisplay();' Line Number: 243
User prompt
make an updatehealth funtion tu subtract the health by one when a player hit a obstacle or get hit by an enemy bullet
User prompt
Please fix the bug: 'ReferenceError: updateHealthDisplay is not defined' in or related to this line: 'updateHealthDisplay();' Line Number: 746
User prompt
Please fix the bug: 'ReferenceError: updateHealthDisplay is not defined' in or related to this line: 'updateHealthDisplay();' Line Number: 746
User prompt
Please fix the bug: 'ReferenceError: updateHealthDisplay is not defined' in or related to this line: 'updateHealthDisplay();' Line Number: 746
User prompt
make the scale of the heart image bigger ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
add a new image for the player health
User prompt
Please fix the bug: 'ReferenceError: updateHealthDisplay is not defined' in or related to this line: 'updateHealthDisplay();' Line Number: 746
User prompt
add player health, and an image for each health point the player has as UI, and at initialize it should always set the ammount of images to the ammount of maxHealth
Code edit (4 edits merged)
Please save this source code
User prompt
make the whole game locked at 60 fps
User prompt
make the shootRate be frame independent, make it be per 60fps
Code edit (1 edits merged)
Please save this source code
User prompt
the basic shooter is still not shooting, why is that? all the enemies must share the same shootRate and shoot the same amount of bullets per second
User prompt
so just eliminate the cooldown entirely
User prompt
make all enemies shoot the same rate except the tank
User prompt
the enemies are not shooting, call the enemy shoot function in each enemy
Code edit (3 edits merged)
Please save this source code
User prompt
remake the enemy shooting function to work like the players shooting function, through a shootRate variable and frame independent
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Background elements that scrolls to create movement illusion var BackgroundTile = Container.expand(function () { var self = Container.call(this); var tileGraphics = self.attachAsset('backgroundTile', { anchorX: 0.5, anchorY: 0 }); self.speed = 2; //{6} // Start with slower speed self.update = function () { self.y += self.speed; // Reset position when it goes out of view if (self.y >= 2732) { // Calculate the exact position needed for seamless tiling // Find the tile that's highest up (lowest y value) var highestTile = self; var highestY = self.y; for (var i = 0; i < backgroundTiles.length; i++) { var tile = backgroundTiles[i]; if (tile !== self && tile.y < highestY) { highestTile = tile; highestY = tile.y; } } // Position this tile directly above the highest tile self.y = highestY - tileGraphics.height; } }; return self; }); // Game variables // Barrier obstacle var Barrier = Container.expand(function () { var self = Container.call(this); var barrierGraphics = self.attachAsset('barrier', { anchorX: 0.5, anchorY: 0.5 }); // Barrier properties self.health = 5; self.speed = 2; //{i} // Start with slower speed // Last position tracking for collision detection self.lastX = 0; self.lastY = 0; self.lastWasIntersecting = false; // Take damage self.takeDamage = function () { self.health--; if (self.health <= 0) { LK.getSound('explosion').play(); LK.setScore(LK.getScore() + 2); return true; // Barrier destroyed } return false; // Barrier still intact }; // Update called every frame self.update = function () { self.lastX = self.x; self.lastY = self.y; // Move downward self.y += self.speed; }; return self; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); var enemyGraphics; // Enemy properties self.health = 1; self.speed = 5; self.shootChance = 1; // 1% chance per frame self.lane = 0; self.type = 'basic'; // basic, shooter, tank // Last position tracking for collision detection self.lastX = 0; self.lastY = 0; self.lastWasIntersecting = false; // Initialize enemy with type self.init = function (type, lane) { self.type = type; self.lane = lane; // Remove previous graphics if exists if (enemyGraphics) { self.removeChild(enemyGraphics); } if (type === 'basic') { enemyGraphics = self.attachAsset('enemyBasic', { anchorX: 0.5, anchorY: 0.5 }); self.health = 1; self.speed = 3; //{P} // Slower starting speed self.shootRate = 0.5; // Shots per second } else if (type === 'shooter') { enemyGraphics = self.attachAsset('enemyShooter', { anchorX: 0.5, anchorY: 0.5 }); self.health = 1; self.speed = 2.5; // Slower starting speed self.shootRate = 2; // Moderate fire rate } else if (type === 'tank') { enemyGraphics = self.attachAsset('enemyTank', { anchorX: 0.5, anchorY: 0.5 }); self.health = 3; self.speed = 2; // Slower starting speed self.shootRate = 1; // Slow fire rate } }; // Shoot method for enemies self.shootRate = 5; // Base shoot rate (bullets per second) self.shootCooldown = 0; self.tryShoot = function () { // Use cooldown-based shooting like player if (self.shootCooldown <= 0) { var bullet = new EnemyBullet(); bullet.x = self.x; bullet.y = self.y + 60; game.addChild(bullet); enemyBullets.push(bullet); // Set cooldown based on shoot rate self.shootCooldown = self.shootRate * LK.deltaTime; } }; // Take damage self.takeDamage = function () { self.health--; if (self.health <= 0) { LK.getSound('explosion').play(); LK.setScore(LK.getScore() + 1); return true; // Enemy destroyed } return false; // Enemy still alive }; // Update called every frame self.update = function () { self.lastX = self.x; self.lastY = self.y; // Move downward self.y += self.speed; // Update shooting cooldown if (self.shootCooldown > 0) { self.shootCooldown -= LK.deltaTime; } // Try to shoot if we're a shooting type if ((self.type === 'shooter' || self.type === 'tank') && self.y > 0) { self.tryShoot(); } }; return self; }); // Enemy bullet var EnemyBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('enemyBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; // Last position tracking for collision detection self.lastX = 0; self.lastY = 0; self.lastWasIntersecting = false; self.update = function () { self.lastX = self.x; self.lastY = self.y; // Move bullet downward using delta time var frameRate = 60; // Base frame rate var speedMultiplier = LK.deltaTime * frameRate; // Adjust speed based on actual frame time self.y += self.speed * speedMultiplier; }; return self; }); // Lane definitions for positioning var Lane = Container.expand(function () { var self = Container.call(this); var laneGraphics = self.attachAsset('lane', { anchorX: 0.5, anchorY: 0 }); return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // Player properties self.currentLane = 1; // 0=left, 1=center, 2=right self.shootCooldown = 0; self.shootRate = 50; // Configurable shoot rate (bullets per second) self.bulletType = 'normal'; // normal, double, triple self.powerUpTimer = 0; self.isAlive = true; // Last position tracking for collision detection self.lastX = 0; self.lastY = 0; self.lastWasIntersecting = false; // Movement handling self.moveTo = function (laneIndex) { if (laneIndex >= 0 && laneIndex <= 2) { self.currentLane = laneIndex; } }; // Shoot method self.shoot = function () { // Use the configurable shootRate variable instead of hard-coded value if (self.shootCooldown <= 0) { LK.getSound('shoot').play(); if (self.bulletType === 'normal') { // Create a single bullet var bullet = new PlayerBullet(); bullet.x = self.x; bullet.y = self.y - 60; game.addChild(bullet); playerBullets.push(bullet); } else if (self.bulletType === 'double') { // Create two side-by-side bullets var bullet1 = new PlayerBullet(); bullet1.x = self.x - 30; bullet1.y = self.y - 60; game.addChild(bullet1); playerBullets.push(bullet1); var bullet2 = new PlayerBullet(); bullet2.x = self.x + 30; bullet2.y = self.y - 60; game.addChild(bullet2); playerBullets.push(bullet2); } else if (self.bulletType === 'triple') { // Create three bullets - one forward and two diagonal var bulletCenter = new PlayerBullet(); bulletCenter.x = self.x; bulletCenter.y = self.y - 60; game.addChild(bulletCenter); playerBullets.push(bulletCenter); var bulletLeft = new PlayerBullet(); bulletLeft.x = self.x - 30; bulletLeft.y = self.y - 60; bulletLeft.angle = -15; // Diagonal left game.addChild(bulletLeft); playerBullets.push(bulletLeft); var bulletRight = new PlayerBullet(); bulletRight.x = self.x + 30; bulletRight.y = self.y - 60; bulletRight.angle = 15; // Diagonal right game.addChild(bulletRight); playerBullets.push(bulletRight); } // Set cooldown based on the configurable shootRate variable self.shootCooldown = self.shootRate * LK.deltaTime; } }; // Power-up activation self.activatePowerUp = function (type) { LK.getSound('powerUp').play(); if (type === 'fastShoot') { self.setShootRate(25); // Set faster shooting rate self.bulletType = 'normal'; // Keep normal bullet type } else { self.bulletType = type; self.setShootRate(50); // Reset to default rate } self.powerUpTimer = 300; // 5 seconds at 60fps }; // Method to change the shoot rate self.setShootRate = function (rate) { if (rate > 0) { self.shootRate = rate; } }; // Update called every frame self.update = function () { self.lastX = self.x; self.lastY = self.y; // Handle cooldowns directly (not converting from frames) if (self.shootCooldown > 0) { self.shootCooldown -= LK.deltaTime; } // Power-up timer using delta time if (self.powerUpTimer > 0) { self.powerUpTimer -= LK.deltaTime / (1 / 60); if (self.powerUpTimer <= 0) { self.bulletType = 'normal'; self.setShootRate(50); // Reset shooting rate to default } } // Auto-shoot self.shoot(); }; return self; }); // Player bullet var PlayerBullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('playerBullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 20; self.angle = 0; // 0 = straight, positive/negative for diagonal // Last position tracking for collision detection self.lastX = 0; self.lastY = 0; self.lastWasIntersecting = false; self.update = function () { self.lastX = self.x; self.lastY = self.y; // Move bullet based on angle using delta time var radians = self.angle * (Math.PI / 180); var frameRate = 60; // Base frame rate var speedMultiplier = LK.deltaTime * frameRate; // Adjust speed based on actual frame time self.x += Math.sin(radians) * self.speed * speedMultiplier; self.y -= Math.cos(radians) * self.speed * speedMultiplier; }; return self; }); // Power-up class var PowerUp = Container.expand(function () { var self = Container.call(this); // Start with a placeholder that will be replaced in init() var powerUpGraphics = self.attachAsset('doublePowerUp', { anchorX: 0.5, anchorY: 0.5 }); // Power-up properties self.type = 'double'; // double, triple self.speed = 2; //{2h} // Start with slower speed // Last position tracking for collision detection self.lastX = 0; self.lastY = 0; self.lastWasIntersecting = false; // Initialize power-up with type self.init = function (type) { self.type = type; // Remove existing graphics self.removeChild(powerUpGraphics); // Use appropriate image based on power-up type if (type === 'double') { powerUpGraphics = self.attachAsset('doublePowerUp', { anchorX: 0.5, anchorY: 0.5 }); } else if (type === 'triple') { powerUpGraphics = self.attachAsset('triplePowerUp', { anchorX: 0.5, anchorY: 0.5 }); } else if (type === 'fastShoot') { powerUpGraphics = self.attachAsset('fastShootPowerUp', { anchorX: 0.5, anchorY: 0.5 }); } // Add pulsating animation to the power-up function startPulseAnimation() { // Grow slightly tween(powerUpGraphics, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { // Shrink back tween(powerUpGraphics, { scaleX: 0.9, scaleY: 0.9 }, { duration: 800, easing: tween.easeInOut, onFinish: startPulseAnimation }); } }); } // Start the animation startPulseAnimation(); }; // Update called every frame self.update = function () { self.lastX = self.x; self.lastY = self.y; // Move downward self.y += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Import tween plugin // Player, enemies and bullets // Environment and obstacles // Power-ups // Sounds // Background // Game variables // Add deltaTime calculation if it's not provided by LK engine if (typeof LK.deltaTime === 'undefined') { LK.lastTime = Date.now(); LK.deltaTime = 1 / 60; // Default to 60fps // Update deltaTime before each frame LK.on('tick', function () { var now = Date.now(); LK.deltaTime = Math.min(0.1, (now - LK.lastTime) / 1000); // Cap at 0.1s to prevent huge jumps LK.lastTime = now; }); } var player; var lanes = []; var lanePositions = [512, 1024, 1536]; // The three lanes X positions var playerBullets = []; var enemies = []; var enemyBullets = []; var barriers = []; var powerUps = []; var backgroundTiles = []; var gameSpeed = 2; // Start with slower speed var difficulty = 0.5; // Start with lower difficulty var spawnTimer = 0; var barrierTimer = 0; var powerUpTimer = 0; var difficultyIncreaseRate = 0.05; // How fast difficulty increases var maxDifficulty = 6; // Cap on maximum difficulty // Touch tracking for swipe detection var touchStartX = null; var touchStartY = null; // Initialize the game elements function initGame() { // Play background music with loop LK.playMusic('bgMusic', { fade: { start: 0, end: 0.7, duration: 1000 } }); // Set up background var bgTileHeight = LK.getAsset('backgroundTile', {}).height; var numTilesNeeded = Math.ceil(2732 / bgTileHeight) + 1; // One extra for seamless scrolling for (var i = 0; i < numTilesNeeded; i++) { var bgTile = new BackgroundTile(); bgTile.x = 1024; // Center of screen bgTile.y = i * bgTileHeight; // Position tiles exactly adjacent to each other backgroundTiles.push(bgTile); game.addChild(bgTile); } // Create the lane markers for (var i = 0; i < 2; i++) { var lane = new Lane(); lane.x = lanePositions[i] + (lanePositions[1] - lanePositions[0]) / 2; // Position between lanes lane.y = 0; lane.alpha = 0.3; lanes.push(lane); game.addChild(lane); } // Create the player player = new Player(); player.x = lanePositions[1]; // Start in center lane player.y = 2732 - 300; // Near bottom of screen game.addChild(player); // Initialize score display var scoreBackground = game.addChild(LK.getAsset('scoreBackground', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 80, alpha: 0.7 })); var scoreTxt = new Text2('0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0.5); scoreTxt.x = 1024; scoreTxt.y = 80; game.addChild(scoreTxt); // Update score display every second LK.setInterval(function () { scoreTxt.setText("SCORE: " + LK.getScore()); }, 1000); } // Spawn a new enemy function spawnEnemy() { var laneIndex = Math.floor(Math.random() * 3); var enemyType = 'basic'; // Determine enemy type based on difficulty var typeRoll = Math.random(); if (difficulty >= 2) { if (typeRoll < 0.3) { enemyType = 'shooter'; } else if (typeRoll < 0.4 && difficulty >= 3) { enemyType = 'tank'; } } var enemy = new Enemy(); enemy.init(enemyType, laneIndex); enemy.x = lanePositions[laneIndex]; enemy.y = -100; game.addChild(enemy); enemies.push(enemy); } // Spawn a barrier across all lanes function spawnBarrier() { var barrier = new Barrier(); barrier.x = 1024; // Center of screen barrier.y = -100; game.addChild(barrier); barriers.push(barrier); } // Spawn a power-up function spawnPowerUp() { var laneIndex = Math.floor(Math.random() * 3); var randomValue = Math.random(); var powerUpType; if (randomValue < 0.33) { powerUpType = 'double'; } else if (randomValue < 0.66) { powerUpType = 'triple'; } else { powerUpType = 'fastShoot'; // Add fast shoot power-up type } var powerUp = new PowerUp(); powerUp.init(powerUpType); powerUp.x = lanePositions[laneIndex]; powerUp.y = -100; game.addChild(powerUp); powerUps.push(powerUp); } // Increase difficulty over time function updateDifficulty() { // More gradual difficulty increase based on score var targetDifficulty = Math.min(maxDifficulty, 0.5 + LK.getScore() / 20); // Smooth difficulty transition instead of sudden jumps difficulty += (targetDifficulty - difficulty) * difficultyIncreaseRate; // Calculate game speed based on smoothed difficulty var targetSpeed = 2 + Math.min(difficulty, 4); gameSpeed += (targetSpeed - gameSpeed) * 0.05; // Update game elements with new speed for (var i = 0; i < backgroundTiles.length; i++) { backgroundTiles[i].speed = gameSpeed; } for (var i = 0; i < enemies.length; i++) { var speedModifier = enemies[i].type === 'basic' ? 1 : 0; var targetEnemySpeed = gameSpeed + speedModifier; enemies[i].speed = targetEnemySpeed; } for (var i = 0; i < barriers.length; i++) { barriers[i].speed = gameSpeed; } for (var i = 0; i < powerUps.length; i++) { powerUps[i].speed = gameSpeed; } } // Handle touch input for lane changing game.down = function (x, y, obj) { // Store touch start position for swipe detection game.touchStartX = x; game.touchStartY = y; }; // Handle touch move events for swipe detection game.move = function (x, y, obj) { // Skip if no touch start position is recorded if (!game.touchStartX) { return; } }; // Handle touch up events for swipe detection game.up = function (x, y, obj) { // Skip if no touch start position is recorded if (!game.touchStartX) { return; } // Calculate horizontal distance moved var deltaX = x - game.touchStartX; var deltaY = y - game.touchStartY; // Only process horizontal swipes (ignore vertical) if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 50) { if (deltaX < 0 && player.currentLane > 0) { // Swipe left - move to left lane player.moveTo(player.currentLane - 1); } else if (deltaX > 0 && player.currentLane < 2) { // Swipe right - move to right lane player.moveTo(player.currentLane + 1); } } // Reset touch start position game.touchStartX = null; game.touchStartY = null; }; // Main update function game.update = function () { // Initialize game on first update if (!player) { initGame(); return; } // Update player position based on current lane var targetX = lanePositions[player.currentLane]; player.x += (targetX - player.x) * 0.2; // Smooth movement // Update all game elements player.update(); // Update background tiles for (var i = 0; i < backgroundTiles.length; i++) { backgroundTiles[i].update(); } // Update and check player bullets for (var i = playerBullets.length - 1; i >= 0; i--) { var bullet = playerBullets[i]; bullet.update(); // Remove bullets that go off screen if (bullet.y < -50) { bullet.destroy(); playerBullets.splice(i, 1); continue; } // Check for collisions with enemies var hitEnemy = false; for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (!bullet.lastWasIntersecting && bullet.intersects(enemy)) { bullet.lastWasIntersecting = true; if (enemy.takeDamage()) { enemy.destroy(); enemies.splice(j, 1); } hitEnemy = true; break; } } // Check for collisions with barriers if (!hitEnemy) { for (var j = barriers.length - 1; j >= 0; j--) { var barrier = barriers[j]; if (!bullet.lastWasIntersecting && bullet.intersects(barrier)) { bullet.lastWasIntersecting = true; if (barrier.takeDamage()) { barrier.destroy(); barriers.splice(j, 1); } hitEnemy = true; break; } } } // Remove bullet if it hit something if (hitEnemy) { bullet.destroy(); playerBullets.splice(i, 1); } } // Update and check enemy bullets for (var i = enemyBullets.length - 1; i >= 0; i--) { var bullet = enemyBullets[i]; bullet.update(); // Remove bullets that go off screen if (bullet.y > 2732 + 50) { bullet.destroy(); enemyBullets.splice(i, 1); continue; } // Check for collision with player if (!bullet.lastWasIntersecting && bullet.intersects(player) && player.isAlive) { bullet.lastWasIntersecting = true; // Player hit by enemy bullet - game over player.isAlive = false; LK.effects.flashScreen(0xff0000, 1000); LK.setTimeout(function () { LK.showGameOver(); }, 1000); break; } } // Update and check enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; enemy.update(); // Remove enemies that go off screen if (enemy.y > 2732 + 100) { enemy.destroy(); enemies.splice(i, 1); continue; } // Check for collision with player if (!enemy.lastWasIntersecting && enemy.intersects(player) && player.isAlive) { enemy.lastWasIntersecting = true; // Player hit by enemy - game over player.isAlive = false; LK.effects.flashScreen(0xff0000, 1000); LK.setTimeout(function () { LK.showGameOver(); }, 1000); break; } } // Update and check barriers for (var i = barriers.length - 1; i >= 0; i--) { var barrier = barriers[i]; barrier.update(); // Remove barriers that go off screen if (barrier.y > 2732 + 100) { barrier.destroy(); barriers.splice(i, 1); continue; } // Check for collision with player if (!barrier.lastWasIntersecting && barrier.intersects(player) && player.isAlive) { barrier.lastWasIntersecting = true; // Player hit by barrier - game over player.isAlive = false; LK.effects.flashScreen(0xff0000, 1000); LK.setTimeout(function () { LK.showGameOver(); }, 1000); break; } } // Update and check power-ups for (var i = powerUps.length - 1; i >= 0; i--) { var powerUp = powerUps[i]; powerUp.update(); // Remove power-ups that go off screen if (powerUp.y > 2732 + 100) { powerUp.destroy(); powerUps.splice(i, 1); continue; } // Check for collision with player if (!powerUp.lastWasIntersecting && powerUp.intersects(player)) { powerUp.lastWasIntersecting = true; // Player got power-up player.activatePowerUp(powerUp.type); powerUp.destroy(); powerUps.splice(i, 1); } } // Spawn timers spawnTimer--; barrierTimer--; powerUpTimer--; // Spawn enemies if (spawnTimer <= 0) { spawnEnemy(); // Longer spawn intervals that decrease more slowly with difficulty spawnTimer = Math.max(60, 120 - difficulty * 8); // Slower spawn rate at the beginning } // Spawn barriers occasionally if (barrierTimer <= 0 && difficulty >= 1.5) { // Lower threshold for barriers spawnBarrier(); barrierTimer = 400; // Every ~6.6 seconds (longer than original) } // Spawn power-ups occasionally if (powerUpTimer <= 0) { spawnPowerUp(); powerUpTimer = 600 + Math.max(0, 300 - difficulty * 50); // Power-ups more frequent as game progresses } // Update difficulty based on score updateDifficulty(); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Background elements that scrolls to create movement illusion
var BackgroundTile = Container.expand(function () {
var self = Container.call(this);
var tileGraphics = self.attachAsset('backgroundTile', {
anchorX: 0.5,
anchorY: 0
});
self.speed = 2; //{6} // Start with slower speed
self.update = function () {
self.y += self.speed;
// Reset position when it goes out of view
if (self.y >= 2732) {
// Calculate the exact position needed for seamless tiling
// Find the tile that's highest up (lowest y value)
var highestTile = self;
var highestY = self.y;
for (var i = 0; i < backgroundTiles.length; i++) {
var tile = backgroundTiles[i];
if (tile !== self && tile.y < highestY) {
highestTile = tile;
highestY = tile.y;
}
}
// Position this tile directly above the highest tile
self.y = highestY - tileGraphics.height;
}
};
return self;
});
// Game variables
// Barrier obstacle
var Barrier = Container.expand(function () {
var self = Container.call(this);
var barrierGraphics = self.attachAsset('barrier', {
anchorX: 0.5,
anchorY: 0.5
});
// Barrier properties
self.health = 5;
self.speed = 2; //{i} // Start with slower speed
// Last position tracking for collision detection
self.lastX = 0;
self.lastY = 0;
self.lastWasIntersecting = false;
// Take damage
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
LK.getSound('explosion').play();
LK.setScore(LK.getScore() + 2);
return true; // Barrier destroyed
}
return false; // Barrier still intact
};
// Update called every frame
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Move downward
self.y += self.speed;
};
return self;
});
// Enemy class
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics;
// Enemy properties
self.health = 1;
self.speed = 5;
self.shootChance = 1; // 1% chance per frame
self.lane = 0;
self.type = 'basic'; // basic, shooter, tank
// Last position tracking for collision detection
self.lastX = 0;
self.lastY = 0;
self.lastWasIntersecting = false;
// Initialize enemy with type
self.init = function (type, lane) {
self.type = type;
self.lane = lane;
// Remove previous graphics if exists
if (enemyGraphics) {
self.removeChild(enemyGraphics);
}
if (type === 'basic') {
enemyGraphics = self.attachAsset('enemyBasic', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
self.speed = 3; //{P} // Slower starting speed
self.shootRate = 0.5; // Shots per second
} else if (type === 'shooter') {
enemyGraphics = self.attachAsset('enemyShooter', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 1;
self.speed = 2.5; // Slower starting speed
self.shootRate = 2; // Moderate fire rate
} else if (type === 'tank') {
enemyGraphics = self.attachAsset('enemyTank', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3;
self.speed = 2; // Slower starting speed
self.shootRate = 1; // Slow fire rate
}
};
// Shoot method for enemies
self.shootRate = 5; // Base shoot rate (bullets per second)
self.shootCooldown = 0;
self.tryShoot = function () {
// Use cooldown-based shooting like player
if (self.shootCooldown <= 0) {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y + 60;
game.addChild(bullet);
enemyBullets.push(bullet);
// Set cooldown based on shoot rate
self.shootCooldown = self.shootRate * LK.deltaTime;
}
};
// Take damage
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
LK.getSound('explosion').play();
LK.setScore(LK.getScore() + 1);
return true; // Enemy destroyed
}
return false; // Enemy still alive
};
// Update called every frame
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Move downward
self.y += self.speed;
// Update shooting cooldown
if (self.shootCooldown > 0) {
self.shootCooldown -= LK.deltaTime;
}
// Try to shoot if we're a shooting type
if ((self.type === 'shooter' || self.type === 'tank') && self.y > 0) {
self.tryShoot();
}
};
return self;
});
// Enemy bullet
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 10;
// Last position tracking for collision detection
self.lastX = 0;
self.lastY = 0;
self.lastWasIntersecting = false;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Move bullet downward using delta time
var frameRate = 60; // Base frame rate
var speedMultiplier = LK.deltaTime * frameRate; // Adjust speed based on actual frame time
self.y += self.speed * speedMultiplier;
};
return self;
});
// Lane definitions for positioning
var Lane = Container.expand(function () {
var self = Container.call(this);
var laneGraphics = self.attachAsset('lane', {
anchorX: 0.5,
anchorY: 0
});
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Player properties
self.currentLane = 1; // 0=left, 1=center, 2=right
self.shootCooldown = 0;
self.shootRate = 50; // Configurable shoot rate (bullets per second)
self.bulletType = 'normal'; // normal, double, triple
self.powerUpTimer = 0;
self.isAlive = true;
// Last position tracking for collision detection
self.lastX = 0;
self.lastY = 0;
self.lastWasIntersecting = false;
// Movement handling
self.moveTo = function (laneIndex) {
if (laneIndex >= 0 && laneIndex <= 2) {
self.currentLane = laneIndex;
}
};
// Shoot method
self.shoot = function () {
// Use the configurable shootRate variable instead of hard-coded value
if (self.shootCooldown <= 0) {
LK.getSound('shoot').play();
if (self.bulletType === 'normal') {
// Create a single bullet
var bullet = new PlayerBullet();
bullet.x = self.x;
bullet.y = self.y - 60;
game.addChild(bullet);
playerBullets.push(bullet);
} else if (self.bulletType === 'double') {
// Create two side-by-side bullets
var bullet1 = new PlayerBullet();
bullet1.x = self.x - 30;
bullet1.y = self.y - 60;
game.addChild(bullet1);
playerBullets.push(bullet1);
var bullet2 = new PlayerBullet();
bullet2.x = self.x + 30;
bullet2.y = self.y - 60;
game.addChild(bullet2);
playerBullets.push(bullet2);
} else if (self.bulletType === 'triple') {
// Create three bullets - one forward and two diagonal
var bulletCenter = new PlayerBullet();
bulletCenter.x = self.x;
bulletCenter.y = self.y - 60;
game.addChild(bulletCenter);
playerBullets.push(bulletCenter);
var bulletLeft = new PlayerBullet();
bulletLeft.x = self.x - 30;
bulletLeft.y = self.y - 60;
bulletLeft.angle = -15; // Diagonal left
game.addChild(bulletLeft);
playerBullets.push(bulletLeft);
var bulletRight = new PlayerBullet();
bulletRight.x = self.x + 30;
bulletRight.y = self.y - 60;
bulletRight.angle = 15; // Diagonal right
game.addChild(bulletRight);
playerBullets.push(bulletRight);
}
// Set cooldown based on the configurable shootRate variable
self.shootCooldown = self.shootRate * LK.deltaTime;
}
};
// Power-up activation
self.activatePowerUp = function (type) {
LK.getSound('powerUp').play();
if (type === 'fastShoot') {
self.setShootRate(25); // Set faster shooting rate
self.bulletType = 'normal'; // Keep normal bullet type
} else {
self.bulletType = type;
self.setShootRate(50); // Reset to default rate
}
self.powerUpTimer = 300; // 5 seconds at 60fps
};
// Method to change the shoot rate
self.setShootRate = function (rate) {
if (rate > 0) {
self.shootRate = rate;
}
};
// Update called every frame
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Handle cooldowns directly (not converting from frames)
if (self.shootCooldown > 0) {
self.shootCooldown -= LK.deltaTime;
}
// Power-up timer using delta time
if (self.powerUpTimer > 0) {
self.powerUpTimer -= LK.deltaTime / (1 / 60);
if (self.powerUpTimer <= 0) {
self.bulletType = 'normal';
self.setShootRate(50); // Reset shooting rate to default
}
}
// Auto-shoot
self.shoot();
};
return self;
});
// Player bullet
var PlayerBullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('playerBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 20;
self.angle = 0; // 0 = straight, positive/negative for diagonal
// Last position tracking for collision detection
self.lastX = 0;
self.lastY = 0;
self.lastWasIntersecting = false;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Move bullet based on angle using delta time
var radians = self.angle * (Math.PI / 180);
var frameRate = 60; // Base frame rate
var speedMultiplier = LK.deltaTime * frameRate; // Adjust speed based on actual frame time
self.x += Math.sin(radians) * self.speed * speedMultiplier;
self.y -= Math.cos(radians) * self.speed * speedMultiplier;
};
return self;
});
// Power-up class
var PowerUp = Container.expand(function () {
var self = Container.call(this);
// Start with a placeholder that will be replaced in init()
var powerUpGraphics = self.attachAsset('doublePowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
// Power-up properties
self.type = 'double'; // double, triple
self.speed = 2; //{2h} // Start with slower speed
// Last position tracking for collision detection
self.lastX = 0;
self.lastY = 0;
self.lastWasIntersecting = false;
// Initialize power-up with type
self.init = function (type) {
self.type = type;
// Remove existing graphics
self.removeChild(powerUpGraphics);
// Use appropriate image based on power-up type
if (type === 'double') {
powerUpGraphics = self.attachAsset('doublePowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (type === 'triple') {
powerUpGraphics = self.attachAsset('triplePowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (type === 'fastShoot') {
powerUpGraphics = self.attachAsset('fastShootPowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Add pulsating animation to the power-up
function startPulseAnimation() {
// Grow slightly
tween(powerUpGraphics, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Shrink back
tween(powerUpGraphics, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: startPulseAnimation
});
}
});
}
// Start the animation
startPulseAnimation();
};
// Update called every frame
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Move downward
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Import tween plugin
// Player, enemies and bullets
// Environment and obstacles
// Power-ups
// Sounds
// Background
// Game variables
// Add deltaTime calculation if it's not provided by LK engine
if (typeof LK.deltaTime === 'undefined') {
LK.lastTime = Date.now();
LK.deltaTime = 1 / 60; // Default to 60fps
// Update deltaTime before each frame
LK.on('tick', function () {
var now = Date.now();
LK.deltaTime = Math.min(0.1, (now - LK.lastTime) / 1000); // Cap at 0.1s to prevent huge jumps
LK.lastTime = now;
});
}
var player;
var lanes = [];
var lanePositions = [512, 1024, 1536]; // The three lanes X positions
var playerBullets = [];
var enemies = [];
var enemyBullets = [];
var barriers = [];
var powerUps = [];
var backgroundTiles = [];
var gameSpeed = 2; // Start with slower speed
var difficulty = 0.5; // Start with lower difficulty
var spawnTimer = 0;
var barrierTimer = 0;
var powerUpTimer = 0;
var difficultyIncreaseRate = 0.05; // How fast difficulty increases
var maxDifficulty = 6; // Cap on maximum difficulty
// Touch tracking for swipe detection
var touchStartX = null;
var touchStartY = null;
// Initialize the game elements
function initGame() {
// Play background music with loop
LK.playMusic('bgMusic', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
// Set up background
var bgTileHeight = LK.getAsset('backgroundTile', {}).height;
var numTilesNeeded = Math.ceil(2732 / bgTileHeight) + 1; // One extra for seamless scrolling
for (var i = 0; i < numTilesNeeded; i++) {
var bgTile = new BackgroundTile();
bgTile.x = 1024; // Center of screen
bgTile.y = i * bgTileHeight; // Position tiles exactly adjacent to each other
backgroundTiles.push(bgTile);
game.addChild(bgTile);
}
// Create the lane markers
for (var i = 0; i < 2; i++) {
var lane = new Lane();
lane.x = lanePositions[i] + (lanePositions[1] - lanePositions[0]) / 2; // Position between lanes
lane.y = 0;
lane.alpha = 0.3;
lanes.push(lane);
game.addChild(lane);
}
// Create the player
player = new Player();
player.x = lanePositions[1]; // Start in center lane
player.y = 2732 - 300; // Near bottom of screen
game.addChild(player);
// Initialize score display
var scoreBackground = game.addChild(LK.getAsset('scoreBackground', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 80,
alpha: 0.7
}));
var scoreTxt = new Text2('0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0.5);
scoreTxt.x = 1024;
scoreTxt.y = 80;
game.addChild(scoreTxt);
// Update score display every second
LK.setInterval(function () {
scoreTxt.setText("SCORE: " + LK.getScore());
}, 1000);
}
// Spawn a new enemy
function spawnEnemy() {
var laneIndex = Math.floor(Math.random() * 3);
var enemyType = 'basic';
// Determine enemy type based on difficulty
var typeRoll = Math.random();
if (difficulty >= 2) {
if (typeRoll < 0.3) {
enemyType = 'shooter';
} else if (typeRoll < 0.4 && difficulty >= 3) {
enemyType = 'tank';
}
}
var enemy = new Enemy();
enemy.init(enemyType, laneIndex);
enemy.x = lanePositions[laneIndex];
enemy.y = -100;
game.addChild(enemy);
enemies.push(enemy);
}
// Spawn a barrier across all lanes
function spawnBarrier() {
var barrier = new Barrier();
barrier.x = 1024; // Center of screen
barrier.y = -100;
game.addChild(barrier);
barriers.push(barrier);
}
// Spawn a power-up
function spawnPowerUp() {
var laneIndex = Math.floor(Math.random() * 3);
var randomValue = Math.random();
var powerUpType;
if (randomValue < 0.33) {
powerUpType = 'double';
} else if (randomValue < 0.66) {
powerUpType = 'triple';
} else {
powerUpType = 'fastShoot'; // Add fast shoot power-up type
}
var powerUp = new PowerUp();
powerUp.init(powerUpType);
powerUp.x = lanePositions[laneIndex];
powerUp.y = -100;
game.addChild(powerUp);
powerUps.push(powerUp);
}
// Increase difficulty over time
function updateDifficulty() {
// More gradual difficulty increase based on score
var targetDifficulty = Math.min(maxDifficulty, 0.5 + LK.getScore() / 20);
// Smooth difficulty transition instead of sudden jumps
difficulty += (targetDifficulty - difficulty) * difficultyIncreaseRate;
// Calculate game speed based on smoothed difficulty
var targetSpeed = 2 + Math.min(difficulty, 4);
gameSpeed += (targetSpeed - gameSpeed) * 0.05;
// Update game elements with new speed
for (var i = 0; i < backgroundTiles.length; i++) {
backgroundTiles[i].speed = gameSpeed;
}
for (var i = 0; i < enemies.length; i++) {
var speedModifier = enemies[i].type === 'basic' ? 1 : 0;
var targetEnemySpeed = gameSpeed + speedModifier;
enemies[i].speed = targetEnemySpeed;
}
for (var i = 0; i < barriers.length; i++) {
barriers[i].speed = gameSpeed;
}
for (var i = 0; i < powerUps.length; i++) {
powerUps[i].speed = gameSpeed;
}
}
// Handle touch input for lane changing
game.down = function (x, y, obj) {
// Store touch start position for swipe detection
game.touchStartX = x;
game.touchStartY = y;
};
// Handle touch move events for swipe detection
game.move = function (x, y, obj) {
// Skip if no touch start position is recorded
if (!game.touchStartX) {
return;
}
};
// Handle touch up events for swipe detection
game.up = function (x, y, obj) {
// Skip if no touch start position is recorded
if (!game.touchStartX) {
return;
}
// Calculate horizontal distance moved
var deltaX = x - game.touchStartX;
var deltaY = y - game.touchStartY;
// Only process horizontal swipes (ignore vertical)
if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 50) {
if (deltaX < 0 && player.currentLane > 0) {
// Swipe left - move to left lane
player.moveTo(player.currentLane - 1);
} else if (deltaX > 0 && player.currentLane < 2) {
// Swipe right - move to right lane
player.moveTo(player.currentLane + 1);
}
}
// Reset touch start position
game.touchStartX = null;
game.touchStartY = null;
};
// Main update function
game.update = function () {
// Initialize game on first update
if (!player) {
initGame();
return;
}
// Update player position based on current lane
var targetX = lanePositions[player.currentLane];
player.x += (targetX - player.x) * 0.2; // Smooth movement
// Update all game elements
player.update();
// Update background tiles
for (var i = 0; i < backgroundTiles.length; i++) {
backgroundTiles[i].update();
}
// Update and check player bullets
for (var i = playerBullets.length - 1; i >= 0; i--) {
var bullet = playerBullets[i];
bullet.update();
// Remove bullets that go off screen
if (bullet.y < -50) {
bullet.destroy();
playerBullets.splice(i, 1);
continue;
}
// Check for collisions with enemies
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (!bullet.lastWasIntersecting && bullet.intersects(enemy)) {
bullet.lastWasIntersecting = true;
if (enemy.takeDamage()) {
enemy.destroy();
enemies.splice(j, 1);
}
hitEnemy = true;
break;
}
}
// Check for collisions with barriers
if (!hitEnemy) {
for (var j = barriers.length - 1; j >= 0; j--) {
var barrier = barriers[j];
if (!bullet.lastWasIntersecting && bullet.intersects(barrier)) {
bullet.lastWasIntersecting = true;
if (barrier.takeDamage()) {
barrier.destroy();
barriers.splice(j, 1);
}
hitEnemy = true;
break;
}
}
}
// Remove bullet if it hit something
if (hitEnemy) {
bullet.destroy();
playerBullets.splice(i, 1);
}
}
// Update and check enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
bullet.update();
// Remove bullets that go off screen
if (bullet.y > 2732 + 50) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check for collision with player
if (!bullet.lastWasIntersecting && bullet.intersects(player) && player.isAlive) {
bullet.lastWasIntersecting = true;
// Player hit by enemy bullet - game over
player.isAlive = false;
LK.effects.flashScreen(0xff0000, 1000);
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
break;
}
}
// Update and check enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Remove enemies that go off screen
if (enemy.y > 2732 + 100) {
enemy.destroy();
enemies.splice(i, 1);
continue;
}
// Check for collision with player
if (!enemy.lastWasIntersecting && enemy.intersects(player) && player.isAlive) {
enemy.lastWasIntersecting = true;
// Player hit by enemy - game over
player.isAlive = false;
LK.effects.flashScreen(0xff0000, 1000);
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
break;
}
}
// Update and check barriers
for (var i = barriers.length - 1; i >= 0; i--) {
var barrier = barriers[i];
barrier.update();
// Remove barriers that go off screen
if (barrier.y > 2732 + 100) {
barrier.destroy();
barriers.splice(i, 1);
continue;
}
// Check for collision with player
if (!barrier.lastWasIntersecting && barrier.intersects(player) && player.isAlive) {
barrier.lastWasIntersecting = true;
// Player hit by barrier - game over
player.isAlive = false;
LK.effects.flashScreen(0xff0000, 1000);
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
break;
}
}
// Update and check power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
powerUp.update();
// Remove power-ups that go off screen
if (powerUp.y > 2732 + 100) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
// Check for collision with player
if (!powerUp.lastWasIntersecting && powerUp.intersects(player)) {
powerUp.lastWasIntersecting = true;
// Player got power-up
player.activatePowerUp(powerUp.type);
powerUp.destroy();
powerUps.splice(i, 1);
}
}
// Spawn timers
spawnTimer--;
barrierTimer--;
powerUpTimer--;
// Spawn enemies
if (spawnTimer <= 0) {
spawnEnemy();
// Longer spawn intervals that decrease more slowly with difficulty
spawnTimer = Math.max(60, 120 - difficulty * 8); // Slower spawn rate at the beginning
}
// Spawn barriers occasionally
if (barrierTimer <= 0 && difficulty >= 1.5) {
// Lower threshold for barriers
spawnBarrier();
barrierTimer = 400; // Every ~6.6 seconds (longer than original)
}
// Spawn power-ups occasionally
if (powerUpTimer <= 0) {
spawnPowerUp();
powerUpTimer = 600 + Math.max(0, 300 - difficulty * 50); // Power-ups more frequent as game progresses
}
// Update difficulty based on score
updateDifficulty();
};
an 16bit 20x40 yellow bullet. In-Game asset. 2d. High contrast. No shadows
a tank from a top down view in realistic 16bit 90s retro game style. the tank should have its bazooka point straight forward, it should be seen from above so no wheels should be seen. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
make it redish like a ruby
make it so there are 2 bullets side by side
make it so that there are 3 bullets, the one on the left inclined diagonally to the left, the one in the middle forward and the one on the right inclined diagonally to the right
make it so that there are two bullets one above the other like this 2 dots, :
an 16bit 20x40 red heart. In-Game asset. 2d. High contrast. No shadows
make it just an round hole with spikes in it seen from above
create an simple retangular play button image writen "play" in it, make it in a 16bit style. In-Game asset. 2d. High contrast. No shadows
Create an title image written "Bullet Rush" in it, add some elements of war like bulets and make it in a semirealistic 16bit style. In-Game asset. 2d. High contrast. No shadows
make soldier laying in with belly up dead