/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var CelebrationEffect = Container.expand(function () { var self = Container.call(this); var particles = []; for (var i = 0; i < 20; i++) { var particle = LK.getAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); particle.x = 1024 + (Math.random() - 0.5) * 1000; particle.y = 1366 + (Math.random() - 0.5) * 800; particle.vx = (Math.random() - 0.5) * 20; particle.vy = (Math.random() - 0.5) * 20; particles.push(particle); self.addChild(particle); } var celebText = new Text2('LEVEL COMPLETE!', { size: 120, fill: 0x00FF00 }); celebText.anchor.set(0.5, 0.5); celebText.x = 1024; celebText.y = 800; self.addChild(celebText); var continueText = new Text2('TAP TO CONTINUE', { size: 80, fill: 0xFFFFFF }); continueText.anchor.set(0.5, 0.5); continueText.x = 1024; continueText.y = 1000; self.addChild(continueText); self.timer = 0; self.update = function () { self.timer++; for (var i = 0; i < particles.length; i++) { var particle = particles[i]; particle.x += particle.vx; particle.y += particle.vy; particle.rotation += 0.1; particle.vy += 0.5; } celebText.alpha = 0.5 + 0.5 * Math.sin(self.timer * 0.1); }; self.down = function (x, y, obj) { gameState = 'menu'; self.visible = false; mainMenu.visible = true; mainMenu.maxUnlockedLevel = storage.maxUnlockedLevel || 1; mainMenu.currentLevel = storage.currentLevel || 1; mainMenu.updateDisplay(); }; return self; }); var Coin = Container.expand(function () { var self = Container.call(this); var coinGraphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.speed = gameSpeed; self.collected = false; self.update = function () { self.y += self.speed; coinGraphics.rotation += 0.1; }; return self; }); var MainMenu = Container.expand(function () { var self = Container.call(this); self.currentLevel = storage.currentLevel || 1; self.maxUnlockedLevel = storage.maxUnlockedLevel || 1; var titleText = new Text2('EMERALD RUNNER', { size: 120, fill: 0x00FF00 }); titleText.anchor.set(0.5, 0); titleText.x = 1024; titleText.y = 200; self.addChild(titleText); var levelText = new Text2('Level: ' + self.currentLevel + '/50', { size: 80, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0); levelText.x = 1024; levelText.y = 400; self.addChild(levelText); var emeraldsNeeded = 25 * self.currentLevel; var needText = new Text2('Collect ' + emeraldsNeeded + ' emeralds to win!', { size: 60, fill: 0xFFFF00 }); needText.anchor.set(0.5, 0); needText.x = 1024; needText.y = 500; self.addChild(needText); var playButton = new Text2('TAP TO PLAY', { size: 90, fill: 0x00FF00 }); playButton.anchor.set(0.5, 0); playButton.x = 1024; playButton.y = 800; self.addChild(playButton); var prevButton = new Text2('◀ PREV', { size: 60, fill: 0xCCCCCC }); prevButton.anchor.set(0.5, 0); prevButton.x = 512; prevButton.y = 1000; self.addChild(prevButton); var nextButton = new Text2('NEXT ▶', { size: 60, fill: 0xCCCCCC }); nextButton.anchor.set(0.5, 0); nextButton.x = 1536; nextButton.y = 1000; self.addChild(nextButton); var musicButton = new Text2('♪ MUSIC: ON', { size: 60, fill: 0x00FF00 }); musicButton.anchor.set(0.5, 0); musicButton.x = 1024; musicButton.y = 1200; self.addChild(musicButton); self.updateDisplay = function () { levelText.setText('Level: ' + self.currentLevel + '/50'); var emeraldsNeeded = 25 * self.currentLevel; needText.setText('Collect ' + emeraldsNeeded + ' emeralds to win!'); prevButton.tint = self.currentLevel > 1 ? 0xFFFFFF : 0x666666; nextButton.tint = self.currentLevel < self.maxUnlockedLevel ? 0xFFFFFF : 0x666666; playButton.tint = self.currentLevel <= self.maxUnlockedLevel ? 0x00FF00 : 0x666666; var musicEnabled = storage.musicEnabled !== false; musicButton.setText(musicEnabled ? '♪ MUSIC: ON' : '♪ MUSIC: OFF'); musicButton.tint = musicEnabled ? 0x00FF00 : 0xFF0000; }; self.down = function (x, y, obj) { // Use the x, y coordinates directly instead of trying to convert via obj.parent if (Math.abs(x - playButton.x) < 200 && Math.abs(y - playButton.y) < 50) { if (self.currentLevel <= self.maxUnlockedLevel) { gameState = 'playing'; currentLevel = self.currentLevel; self.visible = false; resetGame(); } } if (Math.abs(x - prevButton.x) < 100 && Math.abs(y - prevButton.y) < 40) { if (self.currentLevel > 1) { self.currentLevel--; self.updateDisplay(); } } if (Math.abs(x - nextButton.x) < 100 && Math.abs(y - nextButton.y) < 40) { if (self.currentLevel < self.maxUnlockedLevel) { self.currentLevel++; self.updateDisplay(); } } if (Math.abs(x - musicButton.x) < 150 && Math.abs(y - musicButton.y) < 40) { var musicEnabled = storage.musicEnabled !== false; storage.musicEnabled = !musicEnabled; if (storage.musicEnabled) { LK.playMusic('1', { loop: true }); } else { LK.stopMusic(); } self.updateDisplay(); } }; self.updateDisplay(); return self; }); var Obstacle = Container.expand(function () { var self = Container.call(this); var obstacleGraphics = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 1.0 }); self.speed = gameSpeed; self.update = function () { self.y += self.speed; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 1.0 }); self.lane = 1; // 0=left, 1=center, 2=right self.isJumping = false; self.isSliding = false; self.jumpStartY = 0; self.slideTimer = 0; self.update = function () { // Handle jumping if (self.isJumping) { var jumpProgress = (LK.ticks - self.jumpStartTick) / 45; // Slower jump duration for longer air time if (jumpProgress >= 1) { self.isJumping = false; self.y = self.jumpStartY; } else { var jumpHeight = Math.sin(jumpProgress * Math.PI) * 400; self.y = self.jumpStartY - jumpHeight; } } // Handle sliding if (self.isSliding) { self.slideTimer--; if (self.slideTimer <= 0) { self.isSliding = false; playerGraphics.scaleY = 1.0; } } // Update lane position var targetX = 512 + self.lane * 512; self.x += (targetX - self.x) * 0.2; }; self.jump = function () { if (!self.isJumping && !self.isSliding) { self.isJumping = true; self.jumpStartY = self.y; self.jumpStartTick = LK.ticks; LK.getSound('jump').play(); // Add tween for smoother jump animation tween(self, { scaleX: 1.2, scaleY: 0.8 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 600, easing: tween.easeOut // Slower landing for gravity effect }); } }); } }; self.slide = function () { if (!self.isJumping && !self.isSliding) { self.isSliding = true; self.slideTimer = 30; playerGraphics.scaleY = 0.5; } }; self.moveLeft = function () { if (self.lane > 0) { self.lane--; } }; self.moveRight = function () { if (self.lane < 2) { self.lane++; } }; self.isHighEnoughToClear = function () { if (!self.isJumping) return false; var jumpProgress = (LK.ticks - self.jumpStartTick) / 45; // Match slower gravity timing var jumpHeight = Math.sin(jumpProgress * Math.PI) * 400; return jumpHeight > 120; // Player needs to be at least 120 pixels high to clear obstacles }; return self; }); var Track = Container.expand(function () { var self = Container.call(this); var trackGraphics = self.attachAsset('track', { anchorX: 0.5, anchorY: 0.5 }); self.speed = gameSpeed; self.update = function () { self.y += self.speed; }; return self; }); var Train = Container.expand(function () { var self = Container.call(this); var trainGraphics = self.attachAsset('train', { anchorX: 0.5, anchorY: 1.0 }); self.speed = gameSpeed; self.update = function () { self.y += self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ var gameSpeed = 8; var difficulty = 'medium'; var obstacleSpawnRate = 120; var coinSpawnRate = 60; var distance = 0; var coins = 0; var currentLevel = 1; var gameState = 'menu'; var mainMenu; var celebrationEffect; var player; var obstacles = []; var trains = []; var coinsList = []; var tracks = []; var lastSwipeX = 0; var lastSwipeY = 0; var swipeStartX = 0; var swipeStartY = 0; var isSwipeStarted = false; // Initialize tracks for visual effect for (var i = 0; i < 5; i++) { var track = new Track(); track.x = 1024; track.y = i * 200 - 200; tracks.push(track); game.addChild(track); } // Initialize menu system mainMenu = new MainMenu(); game.addChild(mainMenu); // Initialize celebration effect celebrationEffect = new CelebrationEffect(); celebrationEffect.visible = false; game.addChild(celebrationEffect); // Initialize player player = new Player(); player.x = 1024; player.y = 2200; player.visible = false; game.addChild(player); // UI Elements var emeraldText = new Text2('Emerald: 0', { size: 80, fill: 0x00FF00 }); emeraldText.anchor.set(1, 0); LK.gui.topRight.addChild(emeraldText); // Set difficulty based on game design function setDifficulty(diff) { difficulty = diff; switch (diff) { case 'easy': gameSpeed = 6; obstacleSpawnRate = 150; coinSpawnRate = 45; break; case 'medium': gameSpeed = 8; obstacleSpawnRate = 120; coinSpawnRate = 60; break; case 'hard': gameSpeed = 12; obstacleSpawnRate = 90; coinSpawnRate = 80; break; } } // Set default difficulty setDifficulty('medium'); // Reset game for new level function resetGame() { // Clear all game objects for (var i = obstacles.length - 1; i >= 0; i--) { obstacles[i].destroy(); obstacles.splice(i, 1); } for (var i = trains.length - 1; i >= 0; i--) { trains[i].destroy(); trains.splice(i, 1); } for (var i = coinsList.length - 1; i >= 0; i--) { coinsList[i].destroy(); coinsList.splice(i, 1); } // Reset game variables coins = 0; distance = 0; LK.setScore(0); // Reset player position player.x = 1024; player.y = 2200; player.lane = 1; player.isJumping = false; player.isSliding = false; player.visible = true; // Update UI emeraldText.setText('Emerald: 0'); // Reset tracks for (var i = 0; i < tracks.length; i++) { tracks[i].y = i * 200 - 200; } } // Handle swipe controls game.down = function (x, y, obj) { if (gameState === 'playing') { swipeStartX = x; swipeStartY = y; isSwipeStarted = true; } }; game.up = function (x, y, obj) { if (gameState === 'playing') { if (!isSwipeStarted) return; var deltaX = x - swipeStartX; var deltaY = y - swipeStartY; var swipeThreshold = 50; if (Math.abs(deltaX) > Math.abs(deltaY)) { // Horizontal swipe if (Math.abs(deltaX) > swipeThreshold) { if (deltaX > 0) { player.moveRight(); } else { player.moveLeft(); } } } else { // Vertical swipe if (Math.abs(deltaY) > swipeThreshold) { if (deltaY < 0) { player.jump(); } else { player.slide(); } } } isSwipeStarted = false; } }; // Spawn obstacles function spawnObstacle() { var availableLanes = [0, 1, 2]; // Remove lanes that already have obstacles in extended spawn area for (var i = obstacles.length - 1; i >= 0; i--) { var obstacle = obstacles[i]; if (obstacle.y >= -800 && obstacle.y <= 600) { // Obstacle in extended spawn area with larger safety zone var obstacleLaneIndex = availableLanes.indexOf(obstacle.lane); if (obstacleLaneIndex > -1) { availableLanes.splice(obstacleLaneIndex, 1); } } } // Remove lanes that already have trains in extended spawn area for (var i = trains.length - 1; i >= 0; i--) { var train = trains[i]; if (train.y >= -800 && train.y <= 600) { // Train in extended spawn area with larger safety zone var trainLaneIndex = availableLanes.indexOf(train.lane); if (trainLaneIndex > -1) { availableLanes.splice(trainLaneIndex, 1); } } } // Remove lanes that have coins in spawn area to prevent overlap for (var i = coinsList.length - 1; i >= 0; i--) { var coin = coinsList[i]; if (coin.y >= -600 && coin.y <= 400) { // Coin in spawn area with larger safety zone var coinLaneIndex = availableLanes.indexOf(coin.lane); if (coinLaneIndex > -1) { availableLanes.splice(coinLaneIndex, 1); } } } // If no lanes available, don't spawn obstacle if (availableLanes.length === 0) { return; } var lane = availableLanes[Math.floor(Math.random() * availableLanes.length)]; var obstacleType = Math.random(); if (obstacleType < 0.6) { // Regular obstacle var obstacle = new Obstacle(); obstacle.x = 512 + lane * 512; obstacle.y = -200; obstacle.lane = lane; obstacles.push(obstacle); game.addChild(obstacle); } else { // Train var train = new Train(); train.x = 512 + lane * 512; train.y = -350; train.lane = lane; trains.push(train); game.addChild(train); } } // Spawn coins function spawnCoin() { var availableLanes = [0, 1, 2]; // Remove lanes that have trains in spawn area for (var i = trains.length - 1; i >= 0; i--) { var train = trains[i]; if (train.y >= -800 && train.y <= 400) { // Train in spawn area with larger safety zone var trainLaneIndex = availableLanes.indexOf(train.lane); if (trainLaneIndex > -1) { availableLanes.splice(trainLaneIndex, 1); } } } // Remove lanes that have obstacles in spawn area for (var i = obstacles.length - 1; i >= 0; i--) { var obstacle = obstacles[i]; if (obstacle.y >= -600 && obstacle.y <= 400) { // Obstacle in spawn area with larger safety zone var obstacleLaneIndex = availableLanes.indexOf(obstacle.lane); if (obstacleLaneIndex > -1) { availableLanes.splice(obstacleLaneIndex, 1); } } } // Remove lanes that already have coins in spawn area for (var i = coinsList.length - 1; i >= 0; i--) { var coin = coinsList[i]; if (coin.y >= -600 && coin.y <= 400) { // Coin in spawn area with larger safety zone var coinLaneIndex = availableLanes.indexOf(coin.lane); if (coinLaneIndex > -1) { availableLanes.splice(coinLaneIndex, 1); } } } // If no lanes available, don't spawn coin if (availableLanes.length === 0) { return; } var lane = availableLanes[Math.floor(Math.random() * availableLanes.length)]; var coin = new Coin(); coin.x = 512 + lane * 512; coin.y = -100; coin.lane = lane; coinsList.push(coin); game.addChild(coin); } // Check collisions function checkCollisions() { // Check obstacle collisions for (var i = obstacles.length - 1; i >= 0; i--) { var obstacle = obstacles[i]; if (obstacle.lane === player.lane) { // More precise collision detection with proper bounds var obstacleTop = obstacle.y - 80; var obstacleBottom = obstacle.y + 80; var playerTop = player.y - 97; var playerBottom = player.y; if (playerBottom > obstacleTop && playerTop < obstacleBottom) { // Check if player can clear obstacle by jumping if (!player.isJumping || !player.isHighEnoughToClear()) { // Collision detected LK.showGameOver(); return; } } } } // Check train collisions for (var i = trains.length - 1; i >= 0; i--) { var train = trains[i]; if (train.lane === player.lane) { // More precise collision detection with proper bounds var trainTop = train.y - 268; var trainBottom = train.y; var playerTop = player.y - 97; var playerBottom = player.y; if (playerBottom > trainTop && playerTop < trainBottom) { // Check if player can clear train by jumping if (!player.isJumping || !player.isHighEnoughToClear()) { // Collision detected LK.showGameOver(); return; } } } } // Check coin collection for (var i = coinsList.length - 1; i >= 0; i--) { var coin = coinsList[i]; if (!coin.collected && coin.lane === player.lane) { // More precise collection detection var coinTop = coin.y - 65; var coinBottom = coin.y + 65; var playerTop = player.y - 97; var playerBottom = player.y; if (playerBottom > coinTop && playerTop < coinBottom) { coin.collected = true; coins++; LK.setScore(LK.getScore() + 10); emeraldText.setText('Emerald: ' + coins); LK.getSound('collect').play(); coin.destroy(); coinsList.splice(i, 1); // Check level completion var emeraldsNeeded = 25 * currentLevel; if (coins >= emeraldsNeeded) { // Level completed! storage.currentLevel = currentLevel; if (currentLevel < 50) { storage.maxUnlockedLevel = Math.max(storage.maxUnlockedLevel || 1, currentLevel + 1); } // Show celebration gameState = 'celebration'; player.visible = false; celebrationEffect.visible = true; celebrationEffect.timer = 0; // Celebration tween effect tween(celebrationEffect, { scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { tween(celebrationEffect, { scaleX: 1.0, scaleY: 1.0 }, { duration: 500, easing: tween.easeIn }); } }); } } } } } // Clean up off-screen objects function cleanupObjects() { // Clean obstacles for (var i = obstacles.length - 1; i >= 0; i--) { if (obstacles[i].y > 2800) { obstacles[i].destroy(); obstacles.splice(i, 1); } } // Clean trains for (var i = trains.length - 1; i >= 0; i--) { if (trains[i].y > 2800) { trains[i].destroy(); trains.splice(i, 1); } } // Clean coins for (var i = coinsList.length - 1; i >= 0; i--) { if (coinsList[i].y > 2800) { coinsList[i].destroy(); coinsList.splice(i, 1); } } // Reset tracks for (var i = 0; i < tracks.length; i++) { if (tracks[i].y > 2800) { tracks[i].y = -200; } } } // Update UI function updateUI() { distance = Math.floor(LK.ticks / 6); } // Main game update game.update = function () { if (gameState === 'playing') { // Update speed over time gameSpeed = Math.min(15, 8 + LK.ticks / 1800); // Spawn obstacles if (LK.ticks % obstacleSpawnRate === 0) { spawnObstacle(); } // Spawn coins if (LK.ticks % coinSpawnRate === 0) { spawnCoin(); } // Update score based on distance if (LK.ticks % 6 === 0) { LK.setScore(LK.getScore() + 1); } // Check collisions checkCollisions(); // Clean up objects cleanupObjects(); // Update UI updateUI(); } }; // Start background music based on settings var musicEnabled = storage.musicEnabled !== false; if (musicEnabled) { LK.playMusic('1', { loop: true }); }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var CelebrationEffect = Container.expand(function () {
var self = Container.call(this);
var particles = [];
for (var i = 0; i < 20; i++) {
var particle = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
particle.x = 1024 + (Math.random() - 0.5) * 1000;
particle.y = 1366 + (Math.random() - 0.5) * 800;
particle.vx = (Math.random() - 0.5) * 20;
particle.vy = (Math.random() - 0.5) * 20;
particles.push(particle);
self.addChild(particle);
}
var celebText = new Text2('LEVEL COMPLETE!', {
size: 120,
fill: 0x00FF00
});
celebText.anchor.set(0.5, 0.5);
celebText.x = 1024;
celebText.y = 800;
self.addChild(celebText);
var continueText = new Text2('TAP TO CONTINUE', {
size: 80,
fill: 0xFFFFFF
});
continueText.anchor.set(0.5, 0.5);
continueText.x = 1024;
continueText.y = 1000;
self.addChild(continueText);
self.timer = 0;
self.update = function () {
self.timer++;
for (var i = 0; i < particles.length; i++) {
var particle = particles[i];
particle.x += particle.vx;
particle.y += particle.vy;
particle.rotation += 0.1;
particle.vy += 0.5;
}
celebText.alpha = 0.5 + 0.5 * Math.sin(self.timer * 0.1);
};
self.down = function (x, y, obj) {
gameState = 'menu';
self.visible = false;
mainMenu.visible = true;
mainMenu.maxUnlockedLevel = storage.maxUnlockedLevel || 1;
mainMenu.currentLevel = storage.currentLevel || 1;
mainMenu.updateDisplay();
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = gameSpeed;
self.collected = false;
self.update = function () {
self.y += self.speed;
coinGraphics.rotation += 0.1;
};
return self;
});
var MainMenu = Container.expand(function () {
var self = Container.call(this);
self.currentLevel = storage.currentLevel || 1;
self.maxUnlockedLevel = storage.maxUnlockedLevel || 1;
var titleText = new Text2('EMERALD RUNNER', {
size: 120,
fill: 0x00FF00
});
titleText.anchor.set(0.5, 0);
titleText.x = 1024;
titleText.y = 200;
self.addChild(titleText);
var levelText = new Text2('Level: ' + self.currentLevel + '/50', {
size: 80,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
levelText.x = 1024;
levelText.y = 400;
self.addChild(levelText);
var emeraldsNeeded = 25 * self.currentLevel;
var needText = new Text2('Collect ' + emeraldsNeeded + ' emeralds to win!', {
size: 60,
fill: 0xFFFF00
});
needText.anchor.set(0.5, 0);
needText.x = 1024;
needText.y = 500;
self.addChild(needText);
var playButton = new Text2('TAP TO PLAY', {
size: 90,
fill: 0x00FF00
});
playButton.anchor.set(0.5, 0);
playButton.x = 1024;
playButton.y = 800;
self.addChild(playButton);
var prevButton = new Text2('◀ PREV', {
size: 60,
fill: 0xCCCCCC
});
prevButton.anchor.set(0.5, 0);
prevButton.x = 512;
prevButton.y = 1000;
self.addChild(prevButton);
var nextButton = new Text2('NEXT ▶', {
size: 60,
fill: 0xCCCCCC
});
nextButton.anchor.set(0.5, 0);
nextButton.x = 1536;
nextButton.y = 1000;
self.addChild(nextButton);
var musicButton = new Text2('♪ MUSIC: ON', {
size: 60,
fill: 0x00FF00
});
musicButton.anchor.set(0.5, 0);
musicButton.x = 1024;
musicButton.y = 1200;
self.addChild(musicButton);
self.updateDisplay = function () {
levelText.setText('Level: ' + self.currentLevel + '/50');
var emeraldsNeeded = 25 * self.currentLevel;
needText.setText('Collect ' + emeraldsNeeded + ' emeralds to win!');
prevButton.tint = self.currentLevel > 1 ? 0xFFFFFF : 0x666666;
nextButton.tint = self.currentLevel < self.maxUnlockedLevel ? 0xFFFFFF : 0x666666;
playButton.tint = self.currentLevel <= self.maxUnlockedLevel ? 0x00FF00 : 0x666666;
var musicEnabled = storage.musicEnabled !== false;
musicButton.setText(musicEnabled ? '♪ MUSIC: ON' : '♪ MUSIC: OFF');
musicButton.tint = musicEnabled ? 0x00FF00 : 0xFF0000;
};
self.down = function (x, y, obj) {
// Use the x, y coordinates directly instead of trying to convert via obj.parent
if (Math.abs(x - playButton.x) < 200 && Math.abs(y - playButton.y) < 50) {
if (self.currentLevel <= self.maxUnlockedLevel) {
gameState = 'playing';
currentLevel = self.currentLevel;
self.visible = false;
resetGame();
}
}
if (Math.abs(x - prevButton.x) < 100 && Math.abs(y - prevButton.y) < 40) {
if (self.currentLevel > 1) {
self.currentLevel--;
self.updateDisplay();
}
}
if (Math.abs(x - nextButton.x) < 100 && Math.abs(y - nextButton.y) < 40) {
if (self.currentLevel < self.maxUnlockedLevel) {
self.currentLevel++;
self.updateDisplay();
}
}
if (Math.abs(x - musicButton.x) < 150 && Math.abs(y - musicButton.y) < 40) {
var musicEnabled = storage.musicEnabled !== false;
storage.musicEnabled = !musicEnabled;
if (storage.musicEnabled) {
LK.playMusic('1', {
loop: true
});
} else {
LK.stopMusic();
}
self.updateDisplay();
}
};
self.updateDisplay();
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 1.0
});
self.speed = gameSpeed;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1.0
});
self.lane = 1; // 0=left, 1=center, 2=right
self.isJumping = false;
self.isSliding = false;
self.jumpStartY = 0;
self.slideTimer = 0;
self.update = function () {
// Handle jumping
if (self.isJumping) {
var jumpProgress = (LK.ticks - self.jumpStartTick) / 45; // Slower jump duration for longer air time
if (jumpProgress >= 1) {
self.isJumping = false;
self.y = self.jumpStartY;
} else {
var jumpHeight = Math.sin(jumpProgress * Math.PI) * 400;
self.y = self.jumpStartY - jumpHeight;
}
}
// Handle sliding
if (self.isSliding) {
self.slideTimer--;
if (self.slideTimer <= 0) {
self.isSliding = false;
playerGraphics.scaleY = 1.0;
}
}
// Update lane position
var targetX = 512 + self.lane * 512;
self.x += (targetX - self.x) * 0.2;
};
self.jump = function () {
if (!self.isJumping && !self.isSliding) {
self.isJumping = true;
self.jumpStartY = self.y;
self.jumpStartTick = LK.ticks;
LK.getSound('jump').play();
// Add tween for smoother jump animation
tween(self, {
scaleX: 1.2,
scaleY: 0.8
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.easeOut // Slower landing for gravity effect
});
}
});
}
};
self.slide = function () {
if (!self.isJumping && !self.isSliding) {
self.isSliding = true;
self.slideTimer = 30;
playerGraphics.scaleY = 0.5;
}
};
self.moveLeft = function () {
if (self.lane > 0) {
self.lane--;
}
};
self.moveRight = function () {
if (self.lane < 2) {
self.lane++;
}
};
self.isHighEnoughToClear = function () {
if (!self.isJumping) return false;
var jumpProgress = (LK.ticks - self.jumpStartTick) / 45; // Match slower gravity timing
var jumpHeight = Math.sin(jumpProgress * Math.PI) * 400;
return jumpHeight > 120; // Player needs to be at least 120 pixels high to clear obstacles
};
return self;
});
var Track = Container.expand(function () {
var self = Container.call(this);
var trackGraphics = self.attachAsset('track', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = gameSpeed;
self.update = function () {
self.y += self.speed;
};
return self;
});
var Train = Container.expand(function () {
var self = Container.call(this);
var trainGraphics = self.attachAsset('train', {
anchorX: 0.5,
anchorY: 1.0
});
self.speed = gameSpeed;
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
var gameSpeed = 8;
var difficulty = 'medium';
var obstacleSpawnRate = 120;
var coinSpawnRate = 60;
var distance = 0;
var coins = 0;
var currentLevel = 1;
var gameState = 'menu';
var mainMenu;
var celebrationEffect;
var player;
var obstacles = [];
var trains = [];
var coinsList = [];
var tracks = [];
var lastSwipeX = 0;
var lastSwipeY = 0;
var swipeStartX = 0;
var swipeStartY = 0;
var isSwipeStarted = false;
// Initialize tracks for visual effect
for (var i = 0; i < 5; i++) {
var track = new Track();
track.x = 1024;
track.y = i * 200 - 200;
tracks.push(track);
game.addChild(track);
}
// Initialize menu system
mainMenu = new MainMenu();
game.addChild(mainMenu);
// Initialize celebration effect
celebrationEffect = new CelebrationEffect();
celebrationEffect.visible = false;
game.addChild(celebrationEffect);
// Initialize player
player = new Player();
player.x = 1024;
player.y = 2200;
player.visible = false;
game.addChild(player);
// UI Elements
var emeraldText = new Text2('Emerald: 0', {
size: 80,
fill: 0x00FF00
});
emeraldText.anchor.set(1, 0);
LK.gui.topRight.addChild(emeraldText);
// Set difficulty based on game design
function setDifficulty(diff) {
difficulty = diff;
switch (diff) {
case 'easy':
gameSpeed = 6;
obstacleSpawnRate = 150;
coinSpawnRate = 45;
break;
case 'medium':
gameSpeed = 8;
obstacleSpawnRate = 120;
coinSpawnRate = 60;
break;
case 'hard':
gameSpeed = 12;
obstacleSpawnRate = 90;
coinSpawnRate = 80;
break;
}
}
// Set default difficulty
setDifficulty('medium');
// Reset game for new level
function resetGame() {
// Clear all game objects
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
obstacles.splice(i, 1);
}
for (var i = trains.length - 1; i >= 0; i--) {
trains[i].destroy();
trains.splice(i, 1);
}
for (var i = coinsList.length - 1; i >= 0; i--) {
coinsList[i].destroy();
coinsList.splice(i, 1);
}
// Reset game variables
coins = 0;
distance = 0;
LK.setScore(0);
// Reset player position
player.x = 1024;
player.y = 2200;
player.lane = 1;
player.isJumping = false;
player.isSliding = false;
player.visible = true;
// Update UI
emeraldText.setText('Emerald: 0');
// Reset tracks
for (var i = 0; i < tracks.length; i++) {
tracks[i].y = i * 200 - 200;
}
}
// Handle swipe controls
game.down = function (x, y, obj) {
if (gameState === 'playing') {
swipeStartX = x;
swipeStartY = y;
isSwipeStarted = true;
}
};
game.up = function (x, y, obj) {
if (gameState === 'playing') {
if (!isSwipeStarted) return;
var deltaX = x - swipeStartX;
var deltaY = y - swipeStartY;
var swipeThreshold = 50;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// Horizontal swipe
if (Math.abs(deltaX) > swipeThreshold) {
if (deltaX > 0) {
player.moveRight();
} else {
player.moveLeft();
}
}
} else {
// Vertical swipe
if (Math.abs(deltaY) > swipeThreshold) {
if (deltaY < 0) {
player.jump();
} else {
player.slide();
}
}
}
isSwipeStarted = false;
}
};
// Spawn obstacles
function spawnObstacle() {
var availableLanes = [0, 1, 2];
// Remove lanes that already have obstacles in extended spawn area
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
if (obstacle.y >= -800 && obstacle.y <= 600) {
// Obstacle in extended spawn area with larger safety zone
var obstacleLaneIndex = availableLanes.indexOf(obstacle.lane);
if (obstacleLaneIndex > -1) {
availableLanes.splice(obstacleLaneIndex, 1);
}
}
}
// Remove lanes that already have trains in extended spawn area
for (var i = trains.length - 1; i >= 0; i--) {
var train = trains[i];
if (train.y >= -800 && train.y <= 600) {
// Train in extended spawn area with larger safety zone
var trainLaneIndex = availableLanes.indexOf(train.lane);
if (trainLaneIndex > -1) {
availableLanes.splice(trainLaneIndex, 1);
}
}
}
// Remove lanes that have coins in spawn area to prevent overlap
for (var i = coinsList.length - 1; i >= 0; i--) {
var coin = coinsList[i];
if (coin.y >= -600 && coin.y <= 400) {
// Coin in spawn area with larger safety zone
var coinLaneIndex = availableLanes.indexOf(coin.lane);
if (coinLaneIndex > -1) {
availableLanes.splice(coinLaneIndex, 1);
}
}
}
// If no lanes available, don't spawn obstacle
if (availableLanes.length === 0) {
return;
}
var lane = availableLanes[Math.floor(Math.random() * availableLanes.length)];
var obstacleType = Math.random();
if (obstacleType < 0.6) {
// Regular obstacle
var obstacle = new Obstacle();
obstacle.x = 512 + lane * 512;
obstacle.y = -200;
obstacle.lane = lane;
obstacles.push(obstacle);
game.addChild(obstacle);
} else {
// Train
var train = new Train();
train.x = 512 + lane * 512;
train.y = -350;
train.lane = lane;
trains.push(train);
game.addChild(train);
}
}
// Spawn coins
function spawnCoin() {
var availableLanes = [0, 1, 2];
// Remove lanes that have trains in spawn area
for (var i = trains.length - 1; i >= 0; i--) {
var train = trains[i];
if (train.y >= -800 && train.y <= 400) {
// Train in spawn area with larger safety zone
var trainLaneIndex = availableLanes.indexOf(train.lane);
if (trainLaneIndex > -1) {
availableLanes.splice(trainLaneIndex, 1);
}
}
}
// Remove lanes that have obstacles in spawn area
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
if (obstacle.y >= -600 && obstacle.y <= 400) {
// Obstacle in spawn area with larger safety zone
var obstacleLaneIndex = availableLanes.indexOf(obstacle.lane);
if (obstacleLaneIndex > -1) {
availableLanes.splice(obstacleLaneIndex, 1);
}
}
}
// Remove lanes that already have coins in spawn area
for (var i = coinsList.length - 1; i >= 0; i--) {
var coin = coinsList[i];
if (coin.y >= -600 && coin.y <= 400) {
// Coin in spawn area with larger safety zone
var coinLaneIndex = availableLanes.indexOf(coin.lane);
if (coinLaneIndex > -1) {
availableLanes.splice(coinLaneIndex, 1);
}
}
}
// If no lanes available, don't spawn coin
if (availableLanes.length === 0) {
return;
}
var lane = availableLanes[Math.floor(Math.random() * availableLanes.length)];
var coin = new Coin();
coin.x = 512 + lane * 512;
coin.y = -100;
coin.lane = lane;
coinsList.push(coin);
game.addChild(coin);
}
// Check collisions
function checkCollisions() {
// Check obstacle collisions
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
if (obstacle.lane === player.lane) {
// More precise collision detection with proper bounds
var obstacleTop = obstacle.y - 80;
var obstacleBottom = obstacle.y + 80;
var playerTop = player.y - 97;
var playerBottom = player.y;
if (playerBottom > obstacleTop && playerTop < obstacleBottom) {
// Check if player can clear obstacle by jumping
if (!player.isJumping || !player.isHighEnoughToClear()) {
// Collision detected
LK.showGameOver();
return;
}
}
}
}
// Check train collisions
for (var i = trains.length - 1; i >= 0; i--) {
var train = trains[i];
if (train.lane === player.lane) {
// More precise collision detection with proper bounds
var trainTop = train.y - 268;
var trainBottom = train.y;
var playerTop = player.y - 97;
var playerBottom = player.y;
if (playerBottom > trainTop && playerTop < trainBottom) {
// Check if player can clear train by jumping
if (!player.isJumping || !player.isHighEnoughToClear()) {
// Collision detected
LK.showGameOver();
return;
}
}
}
}
// Check coin collection
for (var i = coinsList.length - 1; i >= 0; i--) {
var coin = coinsList[i];
if (!coin.collected && coin.lane === player.lane) {
// More precise collection detection
var coinTop = coin.y - 65;
var coinBottom = coin.y + 65;
var playerTop = player.y - 97;
var playerBottom = player.y;
if (playerBottom > coinTop && playerTop < coinBottom) {
coin.collected = true;
coins++;
LK.setScore(LK.getScore() + 10);
emeraldText.setText('Emerald: ' + coins);
LK.getSound('collect').play();
coin.destroy();
coinsList.splice(i, 1);
// Check level completion
var emeraldsNeeded = 25 * currentLevel;
if (coins >= emeraldsNeeded) {
// Level completed!
storage.currentLevel = currentLevel;
if (currentLevel < 50) {
storage.maxUnlockedLevel = Math.max(storage.maxUnlockedLevel || 1, currentLevel + 1);
}
// Show celebration
gameState = 'celebration';
player.visible = false;
celebrationEffect.visible = true;
celebrationEffect.timer = 0;
// Celebration tween effect
tween(celebrationEffect, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(celebrationEffect, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 500,
easing: tween.easeIn
});
}
});
}
}
}
}
}
// Clean up off-screen objects
function cleanupObjects() {
// Clean obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
if (obstacles[i].y > 2800) {
obstacles[i].destroy();
obstacles.splice(i, 1);
}
}
// Clean trains
for (var i = trains.length - 1; i >= 0; i--) {
if (trains[i].y > 2800) {
trains[i].destroy();
trains.splice(i, 1);
}
}
// Clean coins
for (var i = coinsList.length - 1; i >= 0; i--) {
if (coinsList[i].y > 2800) {
coinsList[i].destroy();
coinsList.splice(i, 1);
}
}
// Reset tracks
for (var i = 0; i < tracks.length; i++) {
if (tracks[i].y > 2800) {
tracks[i].y = -200;
}
}
}
// Update UI
function updateUI() {
distance = Math.floor(LK.ticks / 6);
}
// Main game update
game.update = function () {
if (gameState === 'playing') {
// Update speed over time
gameSpeed = Math.min(15, 8 + LK.ticks / 1800);
// Spawn obstacles
if (LK.ticks % obstacleSpawnRate === 0) {
spawnObstacle();
}
// Spawn coins
if (LK.ticks % coinSpawnRate === 0) {
spawnCoin();
}
// Update score based on distance
if (LK.ticks % 6 === 0) {
LK.setScore(LK.getScore() + 1);
}
// Check collisions
checkCollisions();
// Clean up objects
cleanupObjects();
// Update UI
updateUI();
}
};
// Start background music based on settings
var musicEnabled = storage.musicEnabled !== false;
if (musicEnabled) {
LK.playMusic('1', {
loop: true
});
}
karizmatik ama aynı zamanda sevimli görünen koşucu subway surfers karakteri. In-Game asset. 2d. High contrast. No shadows
bariyer. In-Game asset. 2d. High contrast. No shadows
vagon. In-Game asset. 2d. High contrast. No shadows
zümrüt. In-Game asset. 2d. High contrast. No shadows
çakıl taşları. In-Game asset. 2d. High contrast. No shadows