/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Enemy = Container.expand(function () { var self = Container.call(this); // Enemy visual var cube = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, tint: 0xff0000 }); self.width = cube.width; self.height = cube.height; self.speed = 7; self.shootTimer = 0; self.shootInterval = 120; // Shoot every 120 frames (2 seconds) self.update = function () { self.x -= self.speed; self.shootTimer++; if (self.shootTimer >= self.shootInterval) { self.shoot(); self.shootTimer = 0; } // Remove if off screen if (self.x < -self.width) { self.destroy(); return true; // Signal to remove from the array } return false; }; self.shoot = function () { if (gameRunning && !player.isDead) { // Only create enemy cube if there are no enemy cubes currently in the game if (enemyCubes.length === 0) { createEnemyCube(self.x, self.y); } } }; return self; }); var EnemyCube = Container.expand(function () { var self = Container.call(this); // Cube visual var cube = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6, tint: 0xff6666 }); self.width = cube.width * 0.6; self.height = cube.height * 0.6; // Calculate direction towards player's position self.velocity = { x: 0, y: 0 }; self.update = function () { // Move the cube self.x += self.velocity.x; self.y += self.velocity.y; // Rotate the cube for visual effect cube.rotation += 0.05; // Remove if off screen if (self.y > 2732 || self.x < -self.width || self.x > 2048 + self.width) { self.destroy(); return true; } return false; }; return self; }); var Obstacle = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'spike'; self.speed = 10; if (self.type === 'spike') { var spikeGraphic = self.attachAsset('spike', { anchorX: 0.5, anchorY: 1.0 }); self.width = spikeGraphic.width; self.height = spikeGraphic.height; } else if (self.type === 'greenSpike') { var greenSpikeGraphic = self.attachAsset('greenSpike', { anchorX: 0.5, anchorY: 1.0 }); self.width = greenSpikeGraphic.width; self.height = greenSpikeGraphic.height; } else if (self.type === 'laser') { var laserGraphic = self.attachAsset('laser', { anchorX: 0.0, anchorY: 0.5, alpha: 0.7 }); self.width = laserGraphic.width; self.height = laserGraphic.height; // Laser activation self.active = false; self.warningTime = 30; self.activeTime = 60; self.timer = self.warningTime; // Warning effect self.flash = function () { if (self.timer % 5 === 0) { laserGraphic.alpha = laserGraphic.alpha === 0.3 ? 0.7 : 0.3; } }; } else if (self.type === 'searchlight') { var searchlightGraphic = self.attachAsset('searchlight', { anchorX: 0.5, anchorY: 0.0, alpha: 0.5 }); self.width = searchlightGraphic.width; self.height = searchlightGraphic.height; } self.update = function () { self.x -= self.speed; // Laser special behavior if (self.type === 'laser') { self.timer--; if (self.timer > 0 && !self.active) { // Warning phase self.flash(); } else if (!self.active) { // Activate self.active = true; laserGraphic.alpha = 1; self.timer = self.activeTime; // Play laser sound when activated LK.getSound('laser').play(); } else if (self.timer <= 0) { // Deactivate self.destroy(); return true; } } // Remove if off screen if (self.x < -self.width) { self.destroy(); return true; // Signal to remove from the array } return false; }; return self; }); var Platform = Container.expand(function () { var self = Container.call(this); var platformGraphic = self.attachAsset('platform', { anchorX: 0.5, anchorY: 0.0 }); self.width = platformGraphic.width; self.height = platformGraphic.height; self.speed = 10; self.update = function () { self.x -= self.speed; // Remove if off screen if (self.x < -self.width) { self.destroy(); return true; // Signal to remove from the array } return false; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); // Player states self.isJumping = false; self.isSliding = false; self.isHiding = false; self.isDead = false; self.health = 3; // Player starts with 3 health points self.invulnerable = false; // Invulnerability after getting hit self.invulnerableTime = 0; // Track invulnerability duration self.canDoubleJump = false; self.hasDoubleJumped = false; self.canTripleJump = false; self.lastJumpTime = 0; self.velocity = { x: 0, y: 0 }; self.gravity = 1.2; self.jumpForce = -30; // Increased from -25 to -30 for higher first jump self.groundY = 2200; // Visual components var cube = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // Set initial rotation and rotation speed self.rotationSpeed = 0.05; self.currentRotation = 0; // Particle system for the player's trail self.particles = []; // Player controls self.jump = function () { var currentTime = LK.ticks; if (!self.isDead && !self.isSliding) { if (!self.isJumping) { // First jump self.velocity.y = self.jumpForce; self.isJumping = true; self.canDoubleJump = true; self.hasDoubleJumped = false; self.canTripleJump = false; self.lastJumpTime = currentTime; // Increase rotation speed temporarily when jumping tween(self, { rotationSpeed: 0.15 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { rotationSpeed: 0.05 }, { duration: 500, easing: tween.easeIn }); } }); LK.getSound('jump').play(); } else if (self.canDoubleJump && !self.hasDoubleJumped && currentTime - self.lastJumpTime < 30) { // Double jump (only if tapped quickly after first jump) self.velocity.y = self.jumpForce * 1.2; // Higher second jump self.hasDoubleJumped = true; self.canDoubleJump = false; self.canTripleJump = true; // Enable triple jump after double jump self.lastJumpTime = currentTime; // Extra rotation boost for double jump tween(self, { rotationSpeed: 0.25 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { rotationSpeed: 0.05 }, { duration: 400, easing: tween.easeIn }); } }); LK.getSound('jump').play(); } else if (self.canTripleJump && self.hasDoubleJumped && currentTime - self.lastJumpTime < 30) { // Triple jump (only if tapped quickly after second jump) self.velocity.y = self.jumpForce * 1.3; // Even higher third jump self.canTripleJump = false; // Extreme rotation boost for triple jump tween(self, { rotationSpeed: 0.35 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { rotationSpeed: 0.05 }, { duration: 300, easing: tween.easeIn }); } }); LK.getSound('jump').play(); } } }; self.slide = function () { if (!self.isDead && !self.isSliding) { self.isSliding = true; // Set velocity directly instead of trying to tween it self.velocity.x = 10; // Increased from 5 to 10 for faster slide // Temporarily increase player speed and rotation tween(self, { rotationSpeed: 0.3 // Increased rotation speed for more visual impact }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Reset to normal speed after 300ms self.isSliding = false; self.velocity.x = 0; // Reset velocity directly // Store the current x position before slide ends var originalX = self.x; // Tween back to normal position tween(self, { x: originalX - 50 // Move back slightly from the slid position }, { duration: 150, easing: tween.easeOut }); tween(self, { rotationSpeed: 0.05 }, { duration: 200, easing: tween.easeIn }); } }); } }; self.hide = function (shadow) { if (!self.isDead && shadow) { self.isHiding = true; cube.alpha = 0.3; LK.getSound('hide').play(); } }; self.unhide = function () { self.isHiding = false; cube.alpha = 1; }; self.die = function () { if (self.invulnerable) { return; } // Don't take damage if invulnerable if (!self.isDead) { self.health--; if (self.health <= 0) { // Player is dead after losing all health self.isDead = true; // Stop rotation by tweening to zero tween(self, { rotationSpeed: 0 }, { duration: 100 }); LK.getSound('death').play(); LK.effects.flashScreen(0xff0000, 500); // Create death particles for (var i = 0; i < 20; i++) { var particle = LK.getAsset('particle', { anchorX: 0.5, anchorY: 0.5, x: self.x, y: self.y }); // Random velocity for each particle var angle = Math.random() * Math.PI * 2; var speed = 5 + Math.random() * 10; particle.vx = Math.cos(angle) * speed; particle.vy = Math.sin(angle) * speed; game.addChild(particle); deathParticles.push(particle); } LK.setTimeout(function () { LK.showGameOver(); }, 1000); } else { // Player still has health, make invulnerable temporarily self.invulnerable = true; self.invulnerableTime = 60; // 1 second invulnerability (60 frames) LK.effects.flashScreen(0xff0000, 200); // Play hit sound LK.getSound('hit').play(); // Flash the player to indicate damage var flashCount = 0; var flashInterval = LK.setInterval(function () { cube.alpha = cube.alpha === 1 ? 0.3 : 1; flashCount++; if (flashCount >= 6) { // Flash 3 times (6 state changes) LK.clearInterval(flashInterval); cube.alpha = 1; } }, 100); } } }; // Physics update self.updatePhysics = function () { if (self.isDead) { return; } // Update invulnerability timer if (self.invulnerable) { self.invulnerableTime--; if (self.invulnerableTime <= 0) { self.invulnerable = false; cube.alpha = 1; // Ensure player is fully visible } } // Apply gravity self.velocity.y += self.gravity; // Update position self.y += self.velocity.y; self.x += self.velocity.x; // Apply horizontal velocity for sliding // Check floor collision if (self.y >= self.groundY) { self.y = self.groundY; self.velocity.y = 0; self.isJumping = false; self.canDoubleJump = false; self.hasDoubleJumped = false; self.canTripleJump = false; } // Update cube rotation when moving if (gameRunning && !self.isDead) { self.currentRotation += self.rotationSpeed; cube.rotation = self.currentRotation; } // Create trail particles if (gameRunning && LK.ticks % 5 === 0) { var particle = LK.getAsset('particle', { anchorX: 0.5, anchorY: 0.5, x: self.x - 30, y: self.y + (self.isSliding ? 25 : 0) }); particle.alpha = 0.7; particle.life = 30; game.addChild(particle); self.particles.push(particle); } // Update particles for (var i = self.particles.length - 1; i >= 0; i--) { var p = self.particles[i]; p.alpha -= 0.02; p.scaleX -= 0.02; p.scaleY -= 0.02; p.life--; if (p.life <= 0 || p.alpha <= 0) { p.destroy(); self.particles.splice(i, 1); } } }; return self; }); var Shadow = Container.expand(function () { var self = Container.call(this); var shadowGraphic = self.attachAsset('shadow', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); self.width = shadowGraphic.width; self.height = shadowGraphic.height; self.speed = 10; self.update = function () { self.x -= self.speed; // Remove if off screen if (self.x < -self.width) { self.destroy(); return true; // Signal to remove from the array } return false; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x111111 }); /**** * Game Code ****/ // Game state var gameRunning = false; var speed = 10; var score = 0; var highScore = storage.highScore || 0; var platformY = 2200; var spawnDistance = 800; var nextSpawnX = 2048 + 200; var difficultyTimer = 0; var difficultyInterval = 1000; var lastTouchX = 0; var lastTouchY = 0; var touchStartTime = 0; // Game elements var player; var platforms = []; var obstacles = []; var shadows = []; var deathParticles = []; var enemies = []; var enemyCubes = []; // UI elements var scoreTxt; var highScoreTxt; var healthTxt; var tapToStartTxt; // Initialize the game function initGame() { gameRunning = false; speed = 10; score = 0; platformY = 2200; spawnDistance = 800; nextSpawnX = 2048 + 200; difficultyTimer = 0; // Clear existing elements while (platforms.length > 0) { platforms[0].destroy(); platforms.shift(); } while (obstacles.length > 0) { obstacles[0].destroy(); obstacles.shift(); } while (shadows.length > 0) { shadows[0].destroy(); shadows.shift(); } while (deathParticles.length > 0) { deathParticles[0].destroy(); deathParticles.shift(); } // Clear enemies and enemy cubes while (enemies.length > 0) { enemies[0].destroy(); enemies.shift(); } while (enemyCubes.length > 0) { enemyCubes[0].destroy(); enemyCubes.shift(); } // Add background var background = LK.getAsset('background', { anchorX: 0, anchorY: 0 }); game.addChildAt(background, 0); // Add at index 0 to ensure it's at the back // Create player player = new Player(); player.x = 400; player.y = platformY; // Position player on top edge of platform game.addChild(player); // Create initial platform createPlatform(0, platformY, 2048 + 500); // Create UI if (!scoreTxt) { scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(scoreTxt); scoreTxt.x = -250; scoreTxt.y = 50; } // Create health display healthTxt = new Text2('Health: 3', { size: 60, fill: 0xFF5555 }); healthTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(healthTxt); healthTxt.x = 120; // Keep away from top-left corner menu icon healthTxt.y = 50; if (!highScoreTxt) { highScoreTxt = new Text2('High Score: ' + highScore, { size: 40, fill: 0xAAAAAA }); highScoreTxt.anchor.set(0, 0); LK.gui.topRight.addChild(highScoreTxt); highScoreTxt.x = -250; highScoreTxt.y = 120; } // Create start instruction tapToStartTxt = new Text2('Tap to Start\nTap to Jump\nSwipe Right to Slide Faster', { size: 70, fill: 0xFFFFFF }); tapToStartTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(tapToStartTxt); // Start the background music LK.playMusic('gameBgm', { fade: { start: 0, end: 0.4, duration: 1000 } }); } // Create a platform at the specified position function createPlatform(x, y, width) { var platform = new Platform(); platform.x = x; platform.y = y; if (width) { platform.width = width; platform.getChildAt(0).width = width; } game.addChild(platform); platforms.push(platform); return platform; } // Create an obstacle function createObstacle(type, x, y) { var obstacle = new Obstacle(type); obstacle.x = x; obstacle.y = y; if (type === 'laser') { obstacle.y = Math.random() * 1500 + 500; } game.addChild(obstacle); obstacles.push(obstacle); return obstacle; } // Create a shadow area function createShadow(x, y) { var shadow = new Shadow(); shadow.x = x; shadow.y = y; game.addChild(shadow); shadows.push(shadow); return shadow; } // Create an enemy function createEnemy(x, y) { var enemy = new Enemy(); enemy.x = x; enemy.y = y; game.addChild(enemy); enemies.push(enemy); return enemy; } // Create an enemy cube function createEnemyCube(x, y) { var cube = new EnemyCube(); cube.x = x; cube.y = y; // Calculate direction vector towards player var dx = player.x - x; var dy = player.y - y; var distance = Math.sqrt(dx * dx + dy * dy); // Normalize and set speed cube.velocity.x = dx / distance * 12; cube.velocity.y = dy / distance * 12; game.addChild(cube); enemyCubes.push(cube); // Remove any spike obstacles that are at the bottom when enemy cubes are spawned for (var i = obstacles.length - 1; i >= 0; i--) { if (obstacles[i].type === 'spike' && obstacles[i].y === platformY) { obstacles[i].destroy(); obstacles.splice(i, 1); } } return cube; } // Spawn game elements function spawnElements() { if (nextSpawnX <= 2048 + 200) { // Decide what to spawn var rand = Math.random(); // Always spawn a platform var platform = createPlatform(nextSpawnX, platformY); // Maybe spawn an obstacle if (rand < 0.7) { // Only spawn spikes if there are no enemy cubes if (rand < 0.4 && enemyCubes.length === 0) { // Randomly decide between regular spike and green spike if (Math.random() < 0.5) { // Spawn regular spike createObstacle('spike', nextSpawnX, platformY); } else { // Spawn green spike createObstacle('greenSpike', nextSpawnX, platformY); } } else if (rand < 0.6) { // Spawn searchlight createObstacle('searchlight', nextSpawnX, 0); } else { // Spawn laser createObstacle('laser', 0, 0); } } // Maybe spawn a shadow if (Math.random() < 0.3) { createShadow(nextSpawnX, platformY - 40); } // Maybe spawn an enemy at the top if (Math.random() < 0.2) { var enemyX = nextSpawnX + Math.random() * 300; var enemyY = 200 + Math.random() * 300; createEnemy(enemyX, enemyY); } nextSpawnX += spawnDistance; } nextSpawnX -= speed; } // Check for collisions function checkCollisions() { if (player.isDead) { return; } // Check obstacle collisions for (var i = 0; i < obstacles.length; i++) { var obstacle = obstacles[i]; if (obstacle.type === 'laser' && !obstacle.active) { continue; // Skip inactive lasers } if (player.intersects(obstacle)) { // If in a shadow and it's a searchlight, you're safe if (obstacle.type === 'searchlight' && player.isHiding) { continue; } player.die(); break; } } // Check enemy cube collisions for (var i = enemyCubes.length - 1; i >= 0; i--) { if (player.intersects(enemyCubes[i])) { player.die(); // Remove the enemy cube that hit the player enemyCubes[i].destroy(); enemyCubes.splice(i, 1); // Update health display if (healthTxt) { healthTxt.setText('Health: ' + Math.max(0, player.health)); } break; } } // Check shadow interactions var inShadow = false; for (var j = 0; j < shadows.length; j++) { if (player.intersects(shadows[j])) { inShadow = true; break; } } if (inShadow) { player.hide(); } else { player.unhide(); } } // Update score function updateScore() { if (!gameRunning || player.isDead) { return; } score++; if (score > highScore) { highScore = score; storage.highScore = highScore; highScoreTxt.setText('High Score: ' + highScore); } if (score % 10 === 0) { scoreTxt.setText('Score: ' + score); } } // Increase difficulty over time function updateDifficulty() { difficultyTimer++; if (difficultyTimer >= difficultyInterval) { difficultyTimer = 0; // Increase speed speed += 0.5; for (var i = 0; i < platforms.length; i++) { platforms[i].speed = speed; } for (var j = 0; j < obstacles.length; j++) { obstacles[j].speed = speed; } for (var k = 0; k < shadows.length; k++) { shadows[k].speed = speed; } for (var e = 0; e < enemies.length; e++) { enemies[e].speed = speed * 0.7; // Enemies move a bit slower than obstacles } // Decrease spawn distance spawnDistance = Math.max(400, spawnDistance - 10); } } // Main update function game.update = function () { if (gameRunning) { // Update game elements player.updatePhysics(); // Spawn new elements spawnElements(); // Update existing elements for (var i = platforms.length - 1; i >= 0; i--) { if (platforms[i].update()) { platforms.splice(i, 1); } } for (var j = obstacles.length - 1; j >= 0; j--) { if (obstacles[j].update()) { obstacles.splice(j, 1); } } for (var k = shadows.length - 1; k >= 0; k--) { if (shadows[k].update()) { shadows.splice(k, 1); } } // Update enemies for (var m = enemies.length - 1; m >= 0; m--) { if (enemies[m].update()) { enemies.splice(m, 1); } } // Update enemy cubes for (var n = enemyCubes.length - 1; n >= 0; n--) { if (enemyCubes[n].update()) { enemyCubes.splice(n, 1); } } // Update death particles for (var l = deathParticles.length - 1; l >= 0; l--) { var p = deathParticles[l]; p.x += p.vx; p.y += p.vy; p.vx *= 0.95; p.vy *= 0.95; p.vy += 0.5; // gravity p.alpha -= 0.02; if (p.alpha <= 0) { p.destroy(); deathParticles.splice(l, 1); } } // Check for collisions checkCollisions(); // Update score (every 10 ticks) if (LK.ticks % 10 === 0) { updateScore(); } // Update difficulty updateDifficulty(); } }; // Event handlers game.down = function (x, y, obj) { // Track touch position and time for swipe detection lastTouchX = x; lastTouchY = y; touchStartTime = Date.now(); if (!gameRunning) { // Start the game gameRunning = true; tapToStartTxt.destroy(); scoreTxt.setText('Score: 0'); } else if (!player.isDead) { player.jump(); } }; // Sliding functionality has been removed game.up = function (x, y, obj) { if (gameRunning && !player.isDead) { var dx = x - lastTouchX; var dy = y - lastTouchY; var distance = Math.sqrt(dx * dx + dy * dy); var time = Date.now() - touchStartTime; // Add swipe property to event if this appears to be a swipe if (distance > 50 && time < 300) { // This is a swipe, create a custom property on the event object obj.event = obj.event || {}; obj.event.isSwipe = true; // If it's a right swipe (simplified check for better responsiveness) if (dx > 50) { player.slide(); } } } }; game.move = function (x, y, obj) { if (gameRunning && !player.isDead) { // We'll let the up handler manage all slide triggers // This prevents double-triggering slides } }; // Initialize the game initGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Enemy visual
var cube = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xff0000
});
self.width = cube.width;
self.height = cube.height;
self.speed = 7;
self.shootTimer = 0;
self.shootInterval = 120; // Shoot every 120 frames (2 seconds)
self.update = function () {
self.x -= self.speed;
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shoot();
self.shootTimer = 0;
}
// Remove if off screen
if (self.x < -self.width) {
self.destroy();
return true; // Signal to remove from the array
}
return false;
};
self.shoot = function () {
if (gameRunning && !player.isDead) {
// Only create enemy cube if there are no enemy cubes currently in the game
if (enemyCubes.length === 0) {
createEnemyCube(self.x, self.y);
}
}
};
return self;
});
var EnemyCube = Container.expand(function () {
var self = Container.call(this);
// Cube visual
var cube = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
tint: 0xff6666
});
self.width = cube.width * 0.6;
self.height = cube.height * 0.6;
// Calculate direction towards player's position
self.velocity = {
x: 0,
y: 0
};
self.update = function () {
// Move the cube
self.x += self.velocity.x;
self.y += self.velocity.y;
// Rotate the cube for visual effect
cube.rotation += 0.05;
// Remove if off screen
if (self.y > 2732 || self.x < -self.width || self.x > 2048 + self.width) {
self.destroy();
return true;
}
return false;
};
return self;
});
var Obstacle = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'spike';
self.speed = 10;
if (self.type === 'spike') {
var spikeGraphic = self.attachAsset('spike', {
anchorX: 0.5,
anchorY: 1.0
});
self.width = spikeGraphic.width;
self.height = spikeGraphic.height;
} else if (self.type === 'greenSpike') {
var greenSpikeGraphic = self.attachAsset('greenSpike', {
anchorX: 0.5,
anchorY: 1.0
});
self.width = greenSpikeGraphic.width;
self.height = greenSpikeGraphic.height;
} else if (self.type === 'laser') {
var laserGraphic = self.attachAsset('laser', {
anchorX: 0.0,
anchorY: 0.5,
alpha: 0.7
});
self.width = laserGraphic.width;
self.height = laserGraphic.height;
// Laser activation
self.active = false;
self.warningTime = 30;
self.activeTime = 60;
self.timer = self.warningTime;
// Warning effect
self.flash = function () {
if (self.timer % 5 === 0) {
laserGraphic.alpha = laserGraphic.alpha === 0.3 ? 0.7 : 0.3;
}
};
} else if (self.type === 'searchlight') {
var searchlightGraphic = self.attachAsset('searchlight', {
anchorX: 0.5,
anchorY: 0.0,
alpha: 0.5
});
self.width = searchlightGraphic.width;
self.height = searchlightGraphic.height;
}
self.update = function () {
self.x -= self.speed;
// Laser special behavior
if (self.type === 'laser') {
self.timer--;
if (self.timer > 0 && !self.active) {
// Warning phase
self.flash();
} else if (!self.active) {
// Activate
self.active = true;
laserGraphic.alpha = 1;
self.timer = self.activeTime;
// Play laser sound when activated
LK.getSound('laser').play();
} else if (self.timer <= 0) {
// Deactivate
self.destroy();
return true;
}
}
// Remove if off screen
if (self.x < -self.width) {
self.destroy();
return true; // Signal to remove from the array
}
return false;
};
return self;
});
var Platform = Container.expand(function () {
var self = Container.call(this);
var platformGraphic = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.0
});
self.width = platformGraphic.width;
self.height = platformGraphic.height;
self.speed = 10;
self.update = function () {
self.x -= self.speed;
// Remove if off screen
if (self.x < -self.width) {
self.destroy();
return true; // Signal to remove from the array
}
return false;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
// Player states
self.isJumping = false;
self.isSliding = false;
self.isHiding = false;
self.isDead = false;
self.health = 3; // Player starts with 3 health points
self.invulnerable = false; // Invulnerability after getting hit
self.invulnerableTime = 0; // Track invulnerability duration
self.canDoubleJump = false;
self.hasDoubleJumped = false;
self.canTripleJump = false;
self.lastJumpTime = 0;
self.velocity = {
x: 0,
y: 0
};
self.gravity = 1.2;
self.jumpForce = -30; // Increased from -25 to -30 for higher first jump
self.groundY = 2200;
// Visual components
var cube = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Set initial rotation and rotation speed
self.rotationSpeed = 0.05;
self.currentRotation = 0;
// Particle system for the player's trail
self.particles = [];
// Player controls
self.jump = function () {
var currentTime = LK.ticks;
if (!self.isDead && !self.isSliding) {
if (!self.isJumping) {
// First jump
self.velocity.y = self.jumpForce;
self.isJumping = true;
self.canDoubleJump = true;
self.hasDoubleJumped = false;
self.canTripleJump = false;
self.lastJumpTime = currentTime;
// Increase rotation speed temporarily when jumping
tween(self, {
rotationSpeed: 0.15
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
rotationSpeed: 0.05
}, {
duration: 500,
easing: tween.easeIn
});
}
});
LK.getSound('jump').play();
} else if (self.canDoubleJump && !self.hasDoubleJumped && currentTime - self.lastJumpTime < 30) {
// Double jump (only if tapped quickly after first jump)
self.velocity.y = self.jumpForce * 1.2; // Higher second jump
self.hasDoubleJumped = true;
self.canDoubleJump = false;
self.canTripleJump = true; // Enable triple jump after double jump
self.lastJumpTime = currentTime;
// Extra rotation boost for double jump
tween(self, {
rotationSpeed: 0.25
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
rotationSpeed: 0.05
}, {
duration: 400,
easing: tween.easeIn
});
}
});
LK.getSound('jump').play();
} else if (self.canTripleJump && self.hasDoubleJumped && currentTime - self.lastJumpTime < 30) {
// Triple jump (only if tapped quickly after second jump)
self.velocity.y = self.jumpForce * 1.3; // Even higher third jump
self.canTripleJump = false;
// Extreme rotation boost for triple jump
tween(self, {
rotationSpeed: 0.35
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
rotationSpeed: 0.05
}, {
duration: 300,
easing: tween.easeIn
});
}
});
LK.getSound('jump').play();
}
}
};
self.slide = function () {
if (!self.isDead && !self.isSliding) {
self.isSliding = true;
// Set velocity directly instead of trying to tween it
self.velocity.x = 10; // Increased from 5 to 10 for faster slide
// Temporarily increase player speed and rotation
tween(self, {
rotationSpeed: 0.3 // Increased rotation speed for more visual impact
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Reset to normal speed after 300ms
self.isSliding = false;
self.velocity.x = 0; // Reset velocity directly
// Store the current x position before slide ends
var originalX = self.x;
// Tween back to normal position
tween(self, {
x: originalX - 50 // Move back slightly from the slid position
}, {
duration: 150,
easing: tween.easeOut
});
tween(self, {
rotationSpeed: 0.05
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
};
self.hide = function (shadow) {
if (!self.isDead && shadow) {
self.isHiding = true;
cube.alpha = 0.3;
LK.getSound('hide').play();
}
};
self.unhide = function () {
self.isHiding = false;
cube.alpha = 1;
};
self.die = function () {
if (self.invulnerable) {
return;
} // Don't take damage if invulnerable
if (!self.isDead) {
self.health--;
if (self.health <= 0) {
// Player is dead after losing all health
self.isDead = true;
// Stop rotation by tweening to zero
tween(self, {
rotationSpeed: 0
}, {
duration: 100
});
LK.getSound('death').play();
LK.effects.flashScreen(0xff0000, 500);
// Create death particles
for (var i = 0; i < 20; i++) {
var particle = LK.getAsset('particle', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y
});
// Random velocity for each particle
var angle = Math.random() * Math.PI * 2;
var speed = 5 + Math.random() * 10;
particle.vx = Math.cos(angle) * speed;
particle.vy = Math.sin(angle) * speed;
game.addChild(particle);
deathParticles.push(particle);
}
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
} else {
// Player still has health, make invulnerable temporarily
self.invulnerable = true;
self.invulnerableTime = 60; // 1 second invulnerability (60 frames)
LK.effects.flashScreen(0xff0000, 200);
// Play hit sound
LK.getSound('hit').play();
// Flash the player to indicate damage
var flashCount = 0;
var flashInterval = LK.setInterval(function () {
cube.alpha = cube.alpha === 1 ? 0.3 : 1;
flashCount++;
if (flashCount >= 6) {
// Flash 3 times (6 state changes)
LK.clearInterval(flashInterval);
cube.alpha = 1;
}
}, 100);
}
}
};
// Physics update
self.updatePhysics = function () {
if (self.isDead) {
return;
}
// Update invulnerability timer
if (self.invulnerable) {
self.invulnerableTime--;
if (self.invulnerableTime <= 0) {
self.invulnerable = false;
cube.alpha = 1; // Ensure player is fully visible
}
}
// Apply gravity
self.velocity.y += self.gravity;
// Update position
self.y += self.velocity.y;
self.x += self.velocity.x; // Apply horizontal velocity for sliding
// Check floor collision
if (self.y >= self.groundY) {
self.y = self.groundY;
self.velocity.y = 0;
self.isJumping = false;
self.canDoubleJump = false;
self.hasDoubleJumped = false;
self.canTripleJump = false;
}
// Update cube rotation when moving
if (gameRunning && !self.isDead) {
self.currentRotation += self.rotationSpeed;
cube.rotation = self.currentRotation;
}
// Create trail particles
if (gameRunning && LK.ticks % 5 === 0) {
var particle = LK.getAsset('particle', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x - 30,
y: self.y + (self.isSliding ? 25 : 0)
});
particle.alpha = 0.7;
particle.life = 30;
game.addChild(particle);
self.particles.push(particle);
}
// Update particles
for (var i = self.particles.length - 1; i >= 0; i--) {
var p = self.particles[i];
p.alpha -= 0.02;
p.scaleX -= 0.02;
p.scaleY -= 0.02;
p.life--;
if (p.life <= 0 || p.alpha <= 0) {
p.destroy();
self.particles.splice(i, 1);
}
}
};
return self;
});
var Shadow = Container.expand(function () {
var self = Container.call(this);
var shadowGraphic = self.attachAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
self.width = shadowGraphic.width;
self.height = shadowGraphic.height;
self.speed = 10;
self.update = function () {
self.x -= self.speed;
// Remove if off screen
if (self.x < -self.width) {
self.destroy();
return true; // Signal to remove from the array
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x111111
});
/****
* Game Code
****/
// Game state
var gameRunning = false;
var speed = 10;
var score = 0;
var highScore = storage.highScore || 0;
var platformY = 2200;
var spawnDistance = 800;
var nextSpawnX = 2048 + 200;
var difficultyTimer = 0;
var difficultyInterval = 1000;
var lastTouchX = 0;
var lastTouchY = 0;
var touchStartTime = 0;
// Game elements
var player;
var platforms = [];
var obstacles = [];
var shadows = [];
var deathParticles = [];
var enemies = [];
var enemyCubes = [];
// UI elements
var scoreTxt;
var highScoreTxt;
var healthTxt;
var tapToStartTxt;
// Initialize the game
function initGame() {
gameRunning = false;
speed = 10;
score = 0;
platformY = 2200;
spawnDistance = 800;
nextSpawnX = 2048 + 200;
difficultyTimer = 0;
// Clear existing elements
while (platforms.length > 0) {
platforms[0].destroy();
platforms.shift();
}
while (obstacles.length > 0) {
obstacles[0].destroy();
obstacles.shift();
}
while (shadows.length > 0) {
shadows[0].destroy();
shadows.shift();
}
while (deathParticles.length > 0) {
deathParticles[0].destroy();
deathParticles.shift();
}
// Clear enemies and enemy cubes
while (enemies.length > 0) {
enemies[0].destroy();
enemies.shift();
}
while (enemyCubes.length > 0) {
enemyCubes[0].destroy();
enemyCubes.shift();
}
// Add background
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0
});
game.addChildAt(background, 0); // Add at index 0 to ensure it's at the back
// Create player
player = new Player();
player.x = 400;
player.y = platformY; // Position player on top edge of platform
game.addChild(player);
// Create initial platform
createPlatform(0, platformY, 2048 + 500);
// Create UI
if (!scoreTxt) {
scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreTxt);
scoreTxt.x = -250;
scoreTxt.y = 50;
}
// Create health display
healthTxt = new Text2('Health: 3', {
size: 60,
fill: 0xFF5555
});
healthTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(healthTxt);
healthTxt.x = 120; // Keep away from top-left corner menu icon
healthTxt.y = 50;
if (!highScoreTxt) {
highScoreTxt = new Text2('High Score: ' + highScore, {
size: 40,
fill: 0xAAAAAA
});
highScoreTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(highScoreTxt);
highScoreTxt.x = -250;
highScoreTxt.y = 120;
}
// Create start instruction
tapToStartTxt = new Text2('Tap to Start\nTap to Jump\nSwipe Right to Slide Faster', {
size: 70,
fill: 0xFFFFFF
});
tapToStartTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(tapToStartTxt);
// Start the background music
LK.playMusic('gameBgm', {
fade: {
start: 0,
end: 0.4,
duration: 1000
}
});
}
// Create a platform at the specified position
function createPlatform(x, y, width) {
var platform = new Platform();
platform.x = x;
platform.y = y;
if (width) {
platform.width = width;
platform.getChildAt(0).width = width;
}
game.addChild(platform);
platforms.push(platform);
return platform;
}
// Create an obstacle
function createObstacle(type, x, y) {
var obstacle = new Obstacle(type);
obstacle.x = x;
obstacle.y = y;
if (type === 'laser') {
obstacle.y = Math.random() * 1500 + 500;
}
game.addChild(obstacle);
obstacles.push(obstacle);
return obstacle;
}
// Create a shadow area
function createShadow(x, y) {
var shadow = new Shadow();
shadow.x = x;
shadow.y = y;
game.addChild(shadow);
shadows.push(shadow);
return shadow;
}
// Create an enemy
function createEnemy(x, y) {
var enemy = new Enemy();
enemy.x = x;
enemy.y = y;
game.addChild(enemy);
enemies.push(enemy);
return enemy;
}
// Create an enemy cube
function createEnemyCube(x, y) {
var cube = new EnemyCube();
cube.x = x;
cube.y = y;
// Calculate direction vector towards player
var dx = player.x - x;
var dy = player.y - y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Normalize and set speed
cube.velocity.x = dx / distance * 12;
cube.velocity.y = dy / distance * 12;
game.addChild(cube);
enemyCubes.push(cube);
// Remove any spike obstacles that are at the bottom when enemy cubes are spawned
for (var i = obstacles.length - 1; i >= 0; i--) {
if (obstacles[i].type === 'spike' && obstacles[i].y === platformY) {
obstacles[i].destroy();
obstacles.splice(i, 1);
}
}
return cube;
}
// Spawn game elements
function spawnElements() {
if (nextSpawnX <= 2048 + 200) {
// Decide what to spawn
var rand = Math.random();
// Always spawn a platform
var platform = createPlatform(nextSpawnX, platformY);
// Maybe spawn an obstacle
if (rand < 0.7) {
// Only spawn spikes if there are no enemy cubes
if (rand < 0.4 && enemyCubes.length === 0) {
// Randomly decide between regular spike and green spike
if (Math.random() < 0.5) {
// Spawn regular spike
createObstacle('spike', nextSpawnX, platformY);
} else {
// Spawn green spike
createObstacle('greenSpike', nextSpawnX, platformY);
}
} else if (rand < 0.6) {
// Spawn searchlight
createObstacle('searchlight', nextSpawnX, 0);
} else {
// Spawn laser
createObstacle('laser', 0, 0);
}
}
// Maybe spawn a shadow
if (Math.random() < 0.3) {
createShadow(nextSpawnX, platformY - 40);
}
// Maybe spawn an enemy at the top
if (Math.random() < 0.2) {
var enemyX = nextSpawnX + Math.random() * 300;
var enemyY = 200 + Math.random() * 300;
createEnemy(enemyX, enemyY);
}
nextSpawnX += spawnDistance;
}
nextSpawnX -= speed;
}
// Check for collisions
function checkCollisions() {
if (player.isDead) {
return;
}
// Check obstacle collisions
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (obstacle.type === 'laser' && !obstacle.active) {
continue; // Skip inactive lasers
}
if (player.intersects(obstacle)) {
// If in a shadow and it's a searchlight, you're safe
if (obstacle.type === 'searchlight' && player.isHiding) {
continue;
}
player.die();
break;
}
}
// Check enemy cube collisions
for (var i = enemyCubes.length - 1; i >= 0; i--) {
if (player.intersects(enemyCubes[i])) {
player.die();
// Remove the enemy cube that hit the player
enemyCubes[i].destroy();
enemyCubes.splice(i, 1);
// Update health display
if (healthTxt) {
healthTxt.setText('Health: ' + Math.max(0, player.health));
}
break;
}
}
// Check shadow interactions
var inShadow = false;
for (var j = 0; j < shadows.length; j++) {
if (player.intersects(shadows[j])) {
inShadow = true;
break;
}
}
if (inShadow) {
player.hide();
} else {
player.unhide();
}
}
// Update score
function updateScore() {
if (!gameRunning || player.isDead) {
return;
}
score++;
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreTxt.setText('High Score: ' + highScore);
}
if (score % 10 === 0) {
scoreTxt.setText('Score: ' + score);
}
}
// Increase difficulty over time
function updateDifficulty() {
difficultyTimer++;
if (difficultyTimer >= difficultyInterval) {
difficultyTimer = 0;
// Increase speed
speed += 0.5;
for (var i = 0; i < platforms.length; i++) {
platforms[i].speed = speed;
}
for (var j = 0; j < obstacles.length; j++) {
obstacles[j].speed = speed;
}
for (var k = 0; k < shadows.length; k++) {
shadows[k].speed = speed;
}
for (var e = 0; e < enemies.length; e++) {
enemies[e].speed = speed * 0.7; // Enemies move a bit slower than obstacles
}
// Decrease spawn distance
spawnDistance = Math.max(400, spawnDistance - 10);
}
}
// Main update function
game.update = function () {
if (gameRunning) {
// Update game elements
player.updatePhysics();
// Spawn new elements
spawnElements();
// Update existing elements
for (var i = platforms.length - 1; i >= 0; i--) {
if (platforms[i].update()) {
platforms.splice(i, 1);
}
}
for (var j = obstacles.length - 1; j >= 0; j--) {
if (obstacles[j].update()) {
obstacles.splice(j, 1);
}
}
for (var k = shadows.length - 1; k >= 0; k--) {
if (shadows[k].update()) {
shadows.splice(k, 1);
}
}
// Update enemies
for (var m = enemies.length - 1; m >= 0; m--) {
if (enemies[m].update()) {
enemies.splice(m, 1);
}
}
// Update enemy cubes
for (var n = enemyCubes.length - 1; n >= 0; n--) {
if (enemyCubes[n].update()) {
enemyCubes.splice(n, 1);
}
}
// Update death particles
for (var l = deathParticles.length - 1; l >= 0; l--) {
var p = deathParticles[l];
p.x += p.vx;
p.y += p.vy;
p.vx *= 0.95;
p.vy *= 0.95;
p.vy += 0.5; // gravity
p.alpha -= 0.02;
if (p.alpha <= 0) {
p.destroy();
deathParticles.splice(l, 1);
}
}
// Check for collisions
checkCollisions();
// Update score (every 10 ticks)
if (LK.ticks % 10 === 0) {
updateScore();
}
// Update difficulty
updateDifficulty();
}
};
// Event handlers
game.down = function (x, y, obj) {
// Track touch position and time for swipe detection
lastTouchX = x;
lastTouchY = y;
touchStartTime = Date.now();
if (!gameRunning) {
// Start the game
gameRunning = true;
tapToStartTxt.destroy();
scoreTxt.setText('Score: 0');
} else if (!player.isDead) {
player.jump();
}
};
// Sliding functionality has been removed
game.up = function (x, y, obj) {
if (gameRunning && !player.isDead) {
var dx = x - lastTouchX;
var dy = y - lastTouchY;
var distance = Math.sqrt(dx * dx + dy * dy);
var time = Date.now() - touchStartTime;
// Add swipe property to event if this appears to be a swipe
if (distance > 50 && time < 300) {
// This is a swipe, create a custom property on the event object
obj.event = obj.event || {};
obj.event.isSwipe = true;
// If it's a right swipe (simplified check for better responsiveness)
if (dx > 50) {
player.slide();
}
}
}
};
game.move = function (x, y, obj) {
if (gameRunning && !player.isDead) {
// We'll let the up handler manage all slide triggers
// This prevents double-triggering slides
}
};
// Initialize the game
initGame();
square re cube with 2 eyes and spike teeths inside In-Game asset. 2d. High contrast. No shadows
square white cube with 2 eyes and spike smily teeths inside In-Game asset. 2d. High contrast. No shadows
square yellowgreen cube with 2 eyes and smily face inside In-Game asset. 2d. High contrast. No shadows
background image for sqube darkness game. In-Game asset. 2d. High contrast. No shadows