/****
* 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