User prompt
menü arka planınıda mavi yap
User prompt
arka planıda mavi yap
User prompt
start yazısı beyaz olsun
User prompt
daha turuncu olsun
User prompt
tamam start butonunun renginide sarı ve turuncu karışımı yap
User prompt
tamam start butonunun arka planınıda startın yeni yerine taşı
User prompt
hint yazısı biraz daha aşağı gidebilir ayrıca menünün ortasında açık yeşil bir kare duruyor onuda fixle
User prompt
endless running adventure yazısını kaldır swipe left right yazan yeri startın altına al ve menüyü genel olarak tüm ekranı kaplayacak şekilde yap subway dashers logosu en üstte olsun start butonu ise biraz daha aşağı gidebilir
User prompt
üst ortaya koy ve menüyüde buna uygun olarak ayarla start butonu aşağı ortada olsun
User prompt
iki katına daha büyüt
User prompt
subway dashers logosunu biraz daha büyüt ve azıcık yukarı kaldır
User prompt
ortadaki yeşil kutuya oyunun logosunu koymak istiyorum subway dashers yazısınıda kaldır
User prompt
runner yazısı yerine subway dashers yaz
User prompt
modern runner yazısını kaldır ve menüyü polishle
User prompt
play kısmını start yap ve menüyü dahada güzelleştir estetik ve modern dursun
User prompt
Please fix the bug: 'storage.get is not a function' in or related to this line: 'var highScore = storage.get('highScore') || 0;' Line Number: 307 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
menüye high score ekle
User prompt
arkada oyun başlıyor hala ve karakter birşeye çarpıp ölüyor
User prompt
menüyü ingilizce yap birde hala başlatma tuşuna basmadan oyun başlıyor
User prompt
menüyü daha güzelleştir ve oyna butonuna basmadan oyun başlamasın
User prompt
oyuna menü ekle
User prompt
aynı zamanda özel güç yazısını kalan süresi ile birlikte aşağı ortaya taşı
User prompt
toplanan coin göstergesi ekranın dışında kalıyor onu sağ üste tam ayarla
User prompt
özel güçlerin kalan süresi yazsın altında
User prompt
engellerin üzerinden zıplamayı daha kolay hale getir ve animasyonunu daha güzel yap
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Coin class
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinAsset = self.attachAsset('coinCircle', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = 1;
self.speed = 0;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Obstacle class (trains, barriers)
var Obstacle = Container.expand(function () {
var self = Container.call(this);
// Attach asset for single obstacle
var obsSingle1 = self.attachAsset('obstacleBox', {
anchorX: 0.5,
anchorY: 0.5,
visible: true
});
// Attach asset for train obstacle
var obsTrain1 = self.attachAsset('obstacleTrain', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
self.lane = 1;
self.type = 'barrier'; // or 'train'
self.speed = 0; // set by game
// Animation state for obstacle
self.animFrame = 0;
self.animInterval = 18; // slightly slower than runner
self.animTick = 0;
self.setType = function (type) {
self.type = type;
// Set asset visibility
if (type === 'barrier') {
obsSingle1.visible = true;
obsTrain1.visible = false;
// Set size for single
self.width = obsSingle1.width;
self.height = obsSingle1.height;
} else {
obsSingle1.visible = false;
obsTrain1.visible = true;
// Set size for train
self.width = obsTrain1.width;
self.height = obsTrain1.height;
}
self.animFrame = 0;
self.animTick = 0;
};
self.update = function () {
self.y += self.speed;
// No animation for obstacles (only one asset per type)
};
return self;
});
// Powerup class
var Powerup = Container.expand(function () {
var self = Container.call(this);
var powerupAsset = self.attachAsset('powerupStar', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = 1;
self.speed = 0;
self.kind = 'invincible'; // or 'magnet'
self.update = function () {
self.y += self.speed;
};
return self;
});
// Player character class
var Runner = Container.expand(function () {
var self = Container.call(this);
// Attach two runner assets for animation
var runnerAsset1 = self.attachAsset('runnerBox', {
anchorX: 0.5,
anchorY: 0.5
});
var runnerAsset2 = self.attachAsset('runnerBox2', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
// Lane index: 0 (left), 1 (center), 2 (right)
self.lane = 1;
self.y = 0; // Will be set by game
self.isJumping = false;
self.jumpStartY = 0;
self.jumpTime = 0;
self.jumpDuration = 44; // frames (longer jump, about 0.73s)
self.jumpHeight = 420; // px (higher jump)
// Animation state
self.animFrame = 0;
self.animInterval = 16; // frames between switching (slower animation)
self.animTick = 0;
// Move to lane (with tween)
self.moveToLane = function (laneIdx) {
self.lane = laneIdx;
var targetX = laneX(laneIdx);
tween(self, {
x: targetX
}, {
duration: 120,
easing: tween.cubicOut
});
};
// Start jump
self.jump = function () {
if (self.isJumping) return;
self.isJumping = true;
self.jumpStartY = self.y;
self.jumpTime = 0;
};
// Update per frame
self.update = function () {
// Animation: alternate visible asset every animInterval frames
self.animTick++;
if (self.animTick >= self.animInterval) {
self.animTick = 0;
self.animFrame = 1 - self.animFrame;
runnerAsset1.visible = self.animFrame === 0;
runnerAsset2.visible = self.animFrame === 1;
}
if (self.isJumping) {
self.jumpTime++;
// Simple parabolic jump
var t = self.jumpTime / self.jumpDuration;
if (t > 1) t = 1;
var jumpOffset = -4 * self.jumpHeight * t * (t - 1);
self.y = runnerY() + jumpOffset;
// Squash and stretch effect
var scaleY, scaleX;
if (t < 0.15) {
// Squash at takeoff
scaleY = 0.7 + 0.3 * (t / 0.15);
scaleX = 1.2 - 0.2 * (t / 0.15);
} else if (t > 0.85) {
// Squash at landing
var t2 = (t - 0.85) / 0.15;
scaleY = 1.0 - 0.3 * t2;
scaleX = 1.0 + 0.2 * t2;
} else {
// Stretch in air
scaleY = 1.15 - 0.15 * ((t - 0.15) / 0.7);
scaleX = 0.85 + 0.15 * ((t - 0.15) / 0.7);
}
runnerAsset1.scale.y = scaleY;
runnerAsset1.scale.x = scaleX;
runnerAsset2.scale.y = scaleY;
runnerAsset2.scale.x = scaleX;
if (self.jumpTime >= self.jumpDuration) {
self.isJumping = false;
self.y = runnerY();
// Reset scale
runnerAsset1.scale.y = 1;
runnerAsset1.scale.x = 1;
runnerAsset2.scale.y = 1;
runnerAsset2.scale.x = 1;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x008080
});
/****
* Game Code
****/
// new train obstacle asset
// new train obstacle asset
// new single obstacle asset
// Rail images for 3 lanes (tiled vertically for better appearance)
var rails = [];
var railAssetNames = ['railLeft', 'railCenter', 'railRight'];
var railTileHeight = 400; // Use a reasonable tile height for the rail image
var railImageHeight = LK.getAsset(railAssetNames[0], {
anchorX: 0.5,
anchorY: 0
}).height;
var railImageWidth = LK.getAsset(railAssetNames[0], {
anchorX: 0.5,
anchorY: 0
}).width;
var railTilesCount = Math.ceil(2732 / railTileHeight) + 1;
for (var i = 0; i < 3; i++) {
rails[i] = [];
for (var t = 0; t < railTilesCount; t++) {
var rail = LK.getAsset(railAssetNames[i], {
anchorX: 0.5,
anchorY: 0,
x: laneX(i),
y: t * railTileHeight,
width: railImageWidth,
height: railTileHeight
});
rails[i].push(rail);
game.addChild(rail);
}
}
// --- Lane positions ---
function laneX(idx) {
// 3 lanes, centered, with 320px between centers
var center = 2048 / 2;
return center + (idx - 1) * 320;
}
function runnerY() {
// Place runner near bottom, but above bottom edge
return 2732 - 420;
}
// --- Game state ---
var runner;
var obstacles = [];
var coins = [];
var powerups = [];
var score = 0;
var coinScore = 0;
var speed = 10; // px per frame, much slower start, increases over time
var ticks = 0;
var invincibleTicks = 0;
var magnetTicks = 0;
var lastSwipeX = null;
var lastSwipeY = null;
var swipeStartX = null;
var swipeStartY = null;
var swipeStartTime = null;
var isGameOver = false;
// --- Score display ---
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// --- Coin display ---
var coinTxt = new Text2('0', {
size: 80,
fill: 0xF7D038
});
// Set anchor to right/top and add margin from the edge
coinTxt.anchor.set(1, 0);
coinTxt.x = -40; // 40px margin from right edge
coinTxt.y = 0; // flush with top
LK.gui.topRight.addChild(coinTxt);
// --- Powerup display (bottom center, with timer below) ---
var powerupTxt = new Text2('', {
size: 60,
fill: 0x83DE44
});
powerupTxt.anchor.set(0.5, 0); // center horizontally, top edge
powerupTxt.x = 0;
powerupTxt.y = 0;
var powerupTimerTxt = new Text2('', {
size: 48,
fill: 0xffffff
});
powerupTimerTxt.anchor.set(0.5, 0); // center horizontally, top edge
powerupTimerTxt.x = 0;
powerupTimerTxt.y = 70; // 70px below the main text
// Create a container for both texts
var powerupContainer = new Container();
powerupContainer.addChild(powerupTxt);
powerupContainer.addChild(powerupTimerTxt);
// Position container at bottom center, above the very bottom (e.g. 120px up)
powerupContainer.x = 0;
powerupContainer.y = -120;
LK.gui.bottom.addChild(powerupContainer);
// --- MENU OVERLAY ---
var menuOverlay = new Container();
menuOverlay.interactive = true;
menuOverlay.visible = true;
// Decorative background (larger, more rounded, colored)
var menuBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 22,
scaleY: 22,
tint: 0x222e3a,
alpha: 0.92
});
menuOverlay.addChild(menuBg);
// Decorative accent (smaller colored circle)
var menuAccent = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -340,
scaleX: 2.5,
scaleY: 2.5,
tint: 0x83de44,
alpha: 0.7
});
menuOverlay.addChild(menuAccent);
// Title with shadow
var menuTitleShadow = new Text2('RUNNER', {
size: 190,
fill: "#000",
alpha: 0.25
});
menuTitleShadow.anchor.set(0.5, 0.5);
menuTitleShadow.x = 0;
menuTitleShadow.y = -302;
menuOverlay.addChild(menuTitleShadow);
var menuTitle = new Text2('RUNNER', {
size: 180,
fill: "#fff",
font: "Impact, 'Arial Black', Tahoma"
});
menuTitle.anchor.set(0.5, 0.5);
menuTitle.x = 0;
menuTitle.y = -300;
menuOverlay.addChild(menuTitle);
// Subtitle
var menuSubtitle = new Text2('Endless Running Adventure', {
size: 64,
fill: 0xF7D038
});
menuSubtitle.anchor.set(0.5, 0.5);
menuSubtitle.x = 0;
menuSubtitle.y = -170;
menuOverlay.addChild(menuSubtitle);
// Play button with background
var playBtnBg = LK.getAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 160,
scaleX: 4.2,
scaleY: 2.1,
tint: 0x83de44,
alpha: 1
});
menuOverlay.addChild(playBtnBg);
var playBtn = new Text2('PLAY', {
size: 120,
fill: "#fff",
font: "Impact, 'Arial Black', Tahoma"
});
playBtn.anchor.set(0.5, 0.5);
playBtn.x = 0;
playBtn.y = 160;
menuOverlay.addChild(playBtn);
// Decorative hint text
var hintTxt = new Text2('Swipe to move, swipe up to jump!', {
size: 54,
fill: "#fff",
alpha: 0.7
});
hintTxt.anchor.set(0.5, 0.5);
hintTxt.x = 0;
hintTxt.y = 340;
menuOverlay.addChild(hintTxt);
// Center overlay
menuOverlay.x = 2048 / 2;
menuOverlay.y = 2732 / 2;
// Add to stage
game.addChild(menuOverlay);
// --- Initialize runner ---
runner = new Runner();
runner.x = laneX(1);
runner.y = runnerY();
game.addChild(runner);
// Hide runner and UI until game starts
runner.visible = false;
scoreTxt.visible = false;
coinTxt.visible = false;
powerupContainer.visible = false;
// --- Touch/Swipe controls ---
var gameStarted = false;
// Block all input until Play is pressed
game.down = function (x, y, obj) {
if (!gameStarted) return;
swipeStartX = x;
swipeStartY = y;
swipeStartTime = LK.ticks;
lastSwipeX = x;
lastSwipeY = y;
};
game.move = function (x, y, obj) {
if (!gameStarted) return;
if (swipeStartX === null) return;
var dx = x - swipeStartX;
var dy = y - swipeStartY;
var absDx = Math.abs(dx);
var absDy = Math.abs(dy);
var swipeThreshold = 120;
var swipeTime = LK.ticks - swipeStartTime;
if (swipeTime > 36) {
// Too slow, reset
swipeStartX = null;
swipeStartY = null;
return;
}
if (absDx > absDy && absDx > swipeThreshold) {
// Horizontal swipe
if (dx > 0 && runner.lane < 2) {
runner.moveToLane(runner.lane + 1);
} else if (dx < 0 && runner.lane > 0) {
runner.moveToLane(runner.lane - 1);
}
swipeStartX = null;
swipeStartY = null;
} else if (absDy > absDx && dy < -swipeThreshold) {
// Upward swipe (jump)
runner.jump();
swipeStartX = null;
swipeStartY = null;
}
};
game.up = function (x, y, obj) {
if (!gameStarted) return;
swipeStartX = null;
swipeStartY = null;
};
function startGame() {
if (gameStarted) return;
gameStarted = true;
menuOverlay.visible = false;
runner.visible = true;
scoreTxt.visible = true;
coinTxt.visible = true;
powerupContainer.visible = true;
// Reset state
isGameOver = false;
score = 0;
coinScore = 0;
speed = 10;
ticks = 0;
invincibleTicks = 0;
magnetTicks = 0;
scoreTxt.setText('0');
coinTxt.setText('0');
powerupTxt.setText('');
powerupTimerTxt.setText('');
}
// Play button interaction
playBtn.interactive = true;
playBtn.down = function (x, y, obj) {
startGame();
};
// Remove tap-anywhere-to-start: only play button starts the game
menuOverlay.down = function (x, y, obj) {
// Do nothing, only playBtn starts the game
};
game.down = function (x, y, obj) {
if (!gameStarted) return;
swipeStartX = x;
swipeStartY = y;
swipeStartTime = LK.ticks;
lastSwipeX = x;
lastSwipeY = y;
};
game.move = function (x, y, obj) {
if (!gameStarted) return;
if (swipeStartX === null) return;
var dx = x - swipeStartX;
var dy = y - swipeStartY;
var absDx = Math.abs(dx);
var absDy = Math.abs(dy);
var swipeThreshold = 120;
var swipeTime = LK.ticks - swipeStartTime;
if (swipeTime > 36) {
// Too slow, reset
swipeStartX = null;
swipeStartY = null;
return;
}
if (absDx > absDy && absDx > swipeThreshold) {
// Horizontal swipe
if (dx > 0 && runner.lane < 2) {
runner.moveToLane(runner.lane + 1);
} else if (dx < 0 && runner.lane > 0) {
runner.moveToLane(runner.lane - 1);
}
swipeStartX = null;
swipeStartY = null;
} else if (absDy > absDx && dy < -swipeThreshold) {
// Upward swipe (jump)
runner.jump();
swipeStartX = null;
swipeStartY = null;
}
};
game.up = function (x, y, obj) {
if (!gameStarted) return;
swipeStartX = null;
swipeStartY = null;
};
// Show menu again on game over
game.on('destroy', function () {
menuOverlay.visible = true;
runner.visible = false;
scoreTxt.visible = false;
coinTxt.visible = false;
powerupContainer.visible = false;
gameStarted = false;
});
// --- Helper: spawn obstacle ---
function spawnObstacle() {
var obs = new Obstacle();
obs.lane = Math.floor(Math.random() * 3);
obs.x = laneX(obs.lane);
obs.y = -120;
var type = Math.random() < 0.7 ? 'barrier' : 'train';
obs.setType(type);
obs.speed = speed;
obstacles.push(obs);
game.addChild(obs);
}
// --- Helper: spawn coin ---
function spawnCoin() {
var coin = new Coin();
coin.lane = Math.floor(Math.random() * 3);
coin.x = laneX(coin.lane);
coin.y = -80;
coin.speed = speed;
coins.push(coin);
game.addChild(coin);
}
// --- Helper: spawn powerup ---
function spawnPowerup() {
var powerup = new Powerup();
powerup.lane = Math.floor(Math.random() * 3);
powerup.x = laneX(powerup.lane);
powerup.y = -100;
powerup.speed = speed;
powerup.kind = Math.random() < 0.5 ? 'invincible' : 'magnet';
powerups.push(powerup);
game.addChild(powerup);
}
// --- Main update loop ---
game.update = function () {
if (isGameOver) return;
ticks++;
// Increase speed over time
// Old: every 180 ticks, +1.2, max 38
// New: every 180 ticks, +0.6, max 38 (so it takes twice as long to reach max speed)
if (ticks % 180 === 0 && speed < 38) {
speed += 0.6;
}
// Update runner
runner.update();
// Update powerup timers
if (invincibleTicks > 0) {
invincibleTicks--;
powerupTxt.setText("INVINCIBLE " + Math.ceil(invincibleTicks / 60).toString() + "s");
powerupTimerTxt.setText("");
} else if (magnetTicks > 0) {
magnetTicks--;
powerupTxt.setText("MAGNET " + Math.ceil(magnetTicks / 60).toString() + "s");
powerupTimerTxt.setText("");
} else {
powerupTxt.setText("");
powerupTimerTxt.setText("");
}
// Spawn obstacles
// 25% more obstacles: reduce interval by 25%
if (ticks % Math.max(36, Math.floor((120 - speed * 2) * 0.75)) === 0) {
spawnObstacle();
}
// Spawn coins
if (ticks % 36 === 0) {
spawnCoin();
}
// Spawn powerups
if (ticks % 420 === 0) {
spawnPowerup();
}
// --- Update obstacles ---
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.speed = speed;
obs.update();
// Remove if off screen
if (obs.y > 2732 + 200) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision with runner
var collides = false;
if (obs.lane === runner.lane) {
// If runner is jumping, only collide with trains (tall obstacles)
if (obs.type === 'train') {
// Trains are tall, can hit in air
if (Math.abs(obs.y - runner.y) < 180) {
collides = true;
}
} else {
// Barriers: only if runner is not jumping
if (!runner.isJumping && Math.abs(obs.y - runner.y) < 160) {
collides = true;
}
}
}
if (collides && invincibleTicks === 0) {
// Game over
LK.effects.flashScreen(0xff0000, 800);
isGameOver = true;
LK.setScore(score);
LK.showGameOver();
return;
}
}
// --- Update coins ---
for (var j = coins.length - 1; j >= 0; j--) {
var coin = coins[j];
coin.speed = speed;
coin.update();
// Remove if off screen
if (coin.y > 2732 + 100) {
coin.destroy();
coins.splice(j, 1);
continue;
}
// Collect coin
var collect = false;
if (magnetTicks > 0) {
// Magnet: collect if in any lane and close
if (Math.abs(coin.y - runner.y) < 220) {
collect = true;
}
} else {
if (coin.lane === runner.lane && Math.abs(coin.y - runner.y) < 120) {
collect = true;
}
}
if (collect) {
coinScore++;
score += 10;
coinTxt.setText(coinScore);
scoreTxt.setText(score);
coin.destroy();
coins.splice(j, 1);
}
}
// --- Update powerups ---
for (var k = powerups.length - 1; k >= 0; k--) {
var p = powerups[k];
p.speed = speed;
p.update();
// Remove if off screen
if (p.y > 2732 + 120) {
p.destroy();
powerups.splice(k, 1);
continue;
}
// Collect powerup
var collectP = false;
if (p.lane === runner.lane && Math.abs(p.y - runner.y) < 140) {
collectP = true;
}
if (collectP) {
if (p.kind === 'invincible') {
invincibleTicks = 180; // 3 seconds
LK.effects.flashObject(runner, 0x83de44, 800);
} else if (p.kind === 'magnet') {
magnetTicks = 240; // 4 seconds
LK.effects.flashObject(runner, 0xf7d038, 800);
}
p.destroy();
powerups.splice(k, 1);
}
}
// --- Score increases over time ---
if (ticks % 12 === 0) {
score++;
scoreTxt.setText(score);
}
};
// --- Reset state on game over ---
game.on('destroy', function () {
// Clean up arrays
for (var i = 0; i < obstacles.length; i++) obstacles[i].destroy();
for (var j = 0; j < coins.length; j++) coins[j].destroy();
for (var k = 0; k < powerups.length; k++) powerups[k].destroy();
obstacles = [];
coins = [];
powerups = [];
isGameOver = false;
score = 0;
coinScore = 0;
speed = 18;
ticks = 0;
invincibleTicks = 0;
magnetTicks = 0;
scoreTxt.setText('0');
coinTxt.setText('0');
powerupTxt.setText('');
}); ===================================================================
--- original.js
+++ change.js
@@ -312,18 +312,18 @@
alpha: 0.7
});
menuOverlay.addChild(menuAccent);
// Title with shadow
-var menuTitleShadow = new Text2('KOŞUCU', {
+var menuTitleShadow = new Text2('RUNNER', {
size: 190,
fill: "#000",
alpha: 0.25
});
menuTitleShadow.anchor.set(0.5, 0.5);
menuTitleShadow.x = 0;
menuTitleShadow.y = -302;
menuOverlay.addChild(menuTitleShadow);
-var menuTitle = new Text2('KOŞUCU', {
+var menuTitle = new Text2('RUNNER', {
size: 180,
fill: "#fff",
font: "Impact, 'Arial Black', Tahoma"
});
@@ -331,9 +331,9 @@
menuTitle.x = 0;
menuTitle.y = -300;
menuOverlay.addChild(menuTitle);
// Subtitle
-var menuSubtitle = new Text2('Sonsuz Koşu Macerası', {
+var menuSubtitle = new Text2('Endless Running Adventure', {
size: 64,
fill: 0xF7D038
});
menuSubtitle.anchor.set(0.5, 0.5);
@@ -351,9 +351,9 @@
tint: 0x83de44,
alpha: 1
});
menuOverlay.addChild(playBtnBg);
-var playBtn = new Text2('OYNA', {
+var playBtn = new Text2('PLAY', {
size: 120,
fill: "#fff",
font: "Impact, 'Arial Black', Tahoma"
});
@@ -361,9 +361,9 @@
playBtn.x = 0;
playBtn.y = 160;
menuOverlay.addChild(playBtn);
// Decorative hint text
-var hintTxt = new Text2('Kaydırarak hareket et, yukarı kaydır zıpla!', {
+var hintTxt = new Text2('Swipe to move, swipe up to jump!', {
size: 54,
fill: "#fff",
alpha: 0.7
});
@@ -387,8 +387,53 @@
coinTxt.visible = false;
powerupContainer.visible = false;
// --- Touch/Swipe controls ---
var gameStarted = false;
+// Block all input until Play is pressed
+game.down = function (x, y, obj) {
+ if (!gameStarted) return;
+ swipeStartX = x;
+ swipeStartY = y;
+ swipeStartTime = LK.ticks;
+ lastSwipeX = x;
+ lastSwipeY = y;
+};
+game.move = function (x, y, obj) {
+ if (!gameStarted) return;
+ if (swipeStartX === null) return;
+ var dx = x - swipeStartX;
+ var dy = y - swipeStartY;
+ var absDx = Math.abs(dx);
+ var absDy = Math.abs(dy);
+ var swipeThreshold = 120;
+ var swipeTime = LK.ticks - swipeStartTime;
+ if (swipeTime > 36) {
+ // Too slow, reset
+ swipeStartX = null;
+ swipeStartY = null;
+ return;
+ }
+ if (absDx > absDy && absDx > swipeThreshold) {
+ // Horizontal swipe
+ if (dx > 0 && runner.lane < 2) {
+ runner.moveToLane(runner.lane + 1);
+ } else if (dx < 0 && runner.lane > 0) {
+ runner.moveToLane(runner.lane - 1);
+ }
+ swipeStartX = null;
+ swipeStartY = null;
+ } else if (absDy > absDx && dy < -swipeThreshold) {
+ // Upward swipe (jump)
+ runner.jump();
+ swipeStartX = null;
+ swipeStartY = null;
+ }
+};
+game.up = function (x, y, obj) {
+ if (!gameStarted) return;
+ swipeStartX = null;
+ swipeStartY = null;
+};
function startGame() {
if (gameStarted) return;
gameStarted = true;
menuOverlay.visible = false;
2d coin pixel art. In-Game asset. 2d. High contrast. No shadows
2d star pixel art green. In-Game asset. 2d. High contrast. No shadows
2d rail upside view. In-Game asset. 2d. High contrast. No shadows
2d pixel art obstacle upview. In-Game asset. 2d. High contrast. No shadows
subway surfers style logo with text subway dashers. In-Game asset. 2d. High contrast. No shadows