/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Coin
var Coin = Container.expand(function () {
var self = Container.call(this);
self.lane = 1;
self.collected = false;
self.speed = 0;
self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.y += self.speed;
};
return self;
});
// Obstacle base class
var Obstacle = Container.expand(function () {
var self = Container.call(this);
self.type = 'barrier'; // default
self.lane = 1;
self.passed = false;
self.speed = 0;
self.update = function () {
self.y += self.speed;
};
return self;
});
// Train
var Train = Obstacle.expand(function () {
var self = Obstacle.call(this);
self.type = 'train';
self.attachAsset('train', {
anchorX: 0.5,
anchorY: 1
});
return self;
});
// Sign (slide under)
var Sign = Obstacle.expand(function () {
var self = Obstacle.call(this);
self.type = 'sign';
self.attachAsset('sign', {
anchorX: 0.5,
anchorY: 1
});
return self;
});
// Barrier
var Barrier = Obstacle.expand(function () {
var self = Obstacle.call(this);
self.type = 'barrier';
self.attachAsset('barrier', {
anchorX: 0.5,
anchorY: 1
});
return self;
});
// Runner class
var Runner = Container.expand(function () {
var self = Container.call(this);
var runnerSprite = self.attachAsset('runner', {
anchorX: 0.5,
anchorY: 1
});
self.lane = 1; // 0: left, 1: center, 2: right
self.isJumping = false;
self.isSliding = false;
self.jumpY = 0;
self.slideTimer = 0;
// Jump action
self.jump = function () {
if (self.isJumping || self.isSliding) return;
self.isJumping = true;
// Animate jump: up then down
tween(self, {
jumpY: -320
}, {
duration: 260,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(self, {
jumpY: 0
}, {
duration: 320,
easing: tween.cubicIn,
onFinish: function onFinish() {
self.isJumping = false;
}
});
}
});
};
// Slide action
self.slide = function () {
if (self.isSliding || self.isJumping) return;
self.isSliding = true;
self.slideTimer = 24; // ~0.4s at 60fps
tween(runnerSprite, {
height: 120
}, {
duration: 80,
easing: tween.linear
});
};
// Lane change
self.moveLane = function (dir) {
if (self.isJumping || self.isSliding) return;
var newLane = self.lane + dir;
if (newLane < 0 || newLane > 2) return;
self.lane = newLane;
var targetX = lanesX[self.lane];
tween(self, {
x: targetX
}, {
duration: 120,
easing: tween.cubicOut
});
};
// Update per frame
self.update = function () {
// Slide timer
if (self.isSliding) {
self.slideTimer--;
if (self.slideTimer <= 0) {
self.isSliding = false;
tween(runnerSprite, {
height: 240
}, {
duration: 80,
easing: tween.linear
});
}
}
// Apply jumpY offset
self.y = runnerBaseY + self.jumpY;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222831
});
/****
* Game Code
****/
// Coin
// Obstacle: Sign (slide under)
// Obstacle: Train
// Obstacle: Barrier
// Lane ground
// Character: The runner
// Lane positions (3 lanes)
var lanesX = [2048 / 2 - 320,
// left
2048 / 2,
// center
2048 / 2 + 320 // right
];
var runnerBaseY = 2732 - 420; // Y position for runner standing on ground
// Add lane backgrounds
for (var i = 0; i < 3; i++) {
var lane = LK.getAsset('lane', {
anchorX: 0.5,
anchorY: 1,
x: lanesX[i],
y: 2732
});
game.addChild(lane);
}
// Create runner
var runner = new Runner();
runner.x = lanesX[1];
runner.y = runnerBaseY;
game.addChild(runner);
// Score and coins
var score = 0;
var coins = 0;
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var coinTxt = new Text2('0', {
size: 80,
fill: 0xFFE066
});
coinTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(coinTxt);
// Game state
var obstacles = [];
var coinsArr = [];
var gameSpeed = 18; // pixels per frame
var spawnTimer = 0;
var coinSpawnTimer = 0;
var ticks = 0;
var lastTouch = {
x: 0,
y: 0
};
var swipeThreshold = 80; // px
var swipeTime = 18; // frames
// Touch/Swipe controls
var touchStartX = 0,
touchStartY = 0,
touchStartTick = 0;
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
touchStartTick = LK.ticks;
lastTouch.x = x;
lastTouch.y = y;
};
game.up = function (x, y, obj) {
var dx = x - touchStartX;
var dy = y - touchStartY;
var dt = LK.ticks - touchStartTick;
if (dt > swipeTime) return; // too slow
if (Math.abs(dx) > Math.abs(dy)) {
// Horizontal swipe
if (dx > swipeThreshold) {
runner.moveLane(1); // right
} else if (dx < -swipeThreshold) {
runner.moveLane(-1); // left
}
} else {
// Vertical swipe
if (dy < -swipeThreshold) {
runner.jump();
} else if (dy > swipeThreshold) {
runner.slide();
}
}
};
game.move = function (x, y, obj) {
lastTouch.x = x;
lastTouch.y = y;
};
// Main update loop
game.update = function () {
ticks++;
// Increase speed over time
if (ticks % 180 === 0 && gameSpeed < 38) {
gameSpeed += 1.2;
}
// Spawn obstacles
spawnTimer--;
if (spawnTimer <= 0) {
spawnTimer = 54 + Math.floor(Math.random() * 36); // 0.9-1.5s
var typeRand = Math.random();
var lane = Math.floor(Math.random() * 3);
var obs;
if (typeRand < 0.18) {
obs = new Train();
} else if (typeRand < 0.48) {
obs = new Barrier();
} else {
obs = new Sign();
}
obs.lane = lane;
obs.x = lanesX[lane];
obs.y = -40;
obs.speed = gameSpeed;
obstacles.push(obs);
game.addChild(obs);
}
// Spawn coins
coinSpawnTimer--;
if (coinSpawnTimer <= 0) {
coinSpawnTimer = 36 + Math.floor(Math.random() * 36); // 0.6-1.2s
var lane = Math.floor(Math.random() * 3);
var coin = new Coin();
coin.lane = lane;
coin.x = lanesX[lane];
coin.y = -60;
coin.speed = gameSpeed;
coinsArr.push(coin);
game.addChild(coin);
}
// Update runner
runner.update();
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.update();
// Remove if off screen
if (obs.y > 2732 + 200) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision detection
if (!obs.passed && Math.abs(obs.y - runner.y) < 120 && obs.lane === runner.lane) {
if (obs.type === 'barrier') {
if (!runner.isJumping) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
} else if (obs.type === 'sign') {
if (!runner.isSliding) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
} else if (obs.type === 'train') {
// Train: always game over
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
obs.passed = true;
score += 10;
scoreTxt.setText(score);
} else if (!obs.passed && obs.y > runner.y + 60) {
obs.passed = true;
score += 2;
scoreTxt.setText(score);
}
}
// Update coins
for (var i = coinsArr.length - 1; i >= 0; i--) {
var coin = coinsArr[i];
coin.update();
// Remove if off screen
if (coin.y > 2732 + 100) {
coin.destroy();
coinsArr.splice(i, 1);
continue;
}
// Collect coin
if (!coin.collected && Math.abs(coin.y - runner.y + 60) < 100 && coin.lane === runner.lane && !runner.isSliding) {
coin.collected = true;
coins++;
coinTxt.setText(coins);
coin.destroy();
coinsArr.splice(i, 1);
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,352 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// Coin
+var Coin = Container.expand(function () {
+ var self = Container.call(this);
+ self.lane = 1;
+ self.collected = false;
+ self.speed = 0;
+ self.attachAsset('coin', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.update = function () {
+ self.y += self.speed;
+ };
+ return self;
+});
+// Obstacle base class
+var Obstacle = Container.expand(function () {
+ var self = Container.call(this);
+ self.type = 'barrier'; // default
+ self.lane = 1;
+ self.passed = false;
+ self.speed = 0;
+ self.update = function () {
+ self.y += self.speed;
+ };
+ return self;
+});
+// Train
+var Train = Obstacle.expand(function () {
+ var self = Obstacle.call(this);
+ self.type = 'train';
+ self.attachAsset('train', {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ return self;
+});
+// Sign (slide under)
+var Sign = Obstacle.expand(function () {
+ var self = Obstacle.call(this);
+ self.type = 'sign';
+ self.attachAsset('sign', {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ return self;
+});
+// Barrier
+var Barrier = Obstacle.expand(function () {
+ var self = Obstacle.call(this);
+ self.type = 'barrier';
+ self.attachAsset('barrier', {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ return self;
+});
+// Runner class
+var Runner = Container.expand(function () {
+ var self = Container.call(this);
+ var runnerSprite = self.attachAsset('runner', {
+ anchorX: 0.5,
+ anchorY: 1
+ });
+ self.lane = 1; // 0: left, 1: center, 2: right
+ self.isJumping = false;
+ self.isSliding = false;
+ self.jumpY = 0;
+ self.slideTimer = 0;
+ // Jump action
+ self.jump = function () {
+ if (self.isJumping || self.isSliding) return;
+ self.isJumping = true;
+ // Animate jump: up then down
+ tween(self, {
+ jumpY: -320
+ }, {
+ duration: 260,
+ easing: tween.cubicOut,
+ onFinish: function onFinish() {
+ tween(self, {
+ jumpY: 0
+ }, {
+ duration: 320,
+ easing: tween.cubicIn,
+ onFinish: function onFinish() {
+ self.isJumping = false;
+ }
+ });
+ }
+ });
+ };
+ // Slide action
+ self.slide = function () {
+ if (self.isSliding || self.isJumping) return;
+ self.isSliding = true;
+ self.slideTimer = 24; // ~0.4s at 60fps
+ tween(runnerSprite, {
+ height: 120
+ }, {
+ duration: 80,
+ easing: tween.linear
+ });
+ };
+ // Lane change
+ self.moveLane = function (dir) {
+ if (self.isJumping || self.isSliding) return;
+ var newLane = self.lane + dir;
+ if (newLane < 0 || newLane > 2) return;
+ self.lane = newLane;
+ var targetX = lanesX[self.lane];
+ tween(self, {
+ x: targetX
+ }, {
+ duration: 120,
+ easing: tween.cubicOut
+ });
+ };
+ // Update per frame
+ self.update = function () {
+ // Slide timer
+ if (self.isSliding) {
+ self.slideTimer--;
+ if (self.slideTimer <= 0) {
+ self.isSliding = false;
+ tween(runnerSprite, {
+ height: 240
+ }, {
+ duration: 80,
+ easing: tween.linear
+ });
+ }
+ }
+ // Apply jumpY offset
+ self.y = runnerBaseY + self.jumpY;
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x222831
+});
+
+/****
+* Game Code
+****/
+// Coin
+// Obstacle: Sign (slide under)
+// Obstacle: Train
+// Obstacle: Barrier
+// Lane ground
+// Character: The runner
+// Lane positions (3 lanes)
+var lanesX = [2048 / 2 - 320,
+// left
+2048 / 2,
+// center
+2048 / 2 + 320 // right
+];
+var runnerBaseY = 2732 - 420; // Y position for runner standing on ground
+// Add lane backgrounds
+for (var i = 0; i < 3; i++) {
+ var lane = LK.getAsset('lane', {
+ anchorX: 0.5,
+ anchorY: 1,
+ x: lanesX[i],
+ y: 2732
+ });
+ game.addChild(lane);
+}
+// Create runner
+var runner = new Runner();
+runner.x = lanesX[1];
+runner.y = runnerBaseY;
+game.addChild(runner);
+// Score and coins
+var score = 0;
+var coins = 0;
+var scoreTxt = new Text2('0', {
+ size: 120,
+ fill: "#fff"
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+var coinTxt = new Text2('0', {
+ size: 80,
+ fill: 0xFFE066
+});
+coinTxt.anchor.set(1, 0);
+LK.gui.topRight.addChild(coinTxt);
+// Game state
+var obstacles = [];
+var coinsArr = [];
+var gameSpeed = 18; // pixels per frame
+var spawnTimer = 0;
+var coinSpawnTimer = 0;
+var ticks = 0;
+var lastTouch = {
+ x: 0,
+ y: 0
+};
+var swipeThreshold = 80; // px
+var swipeTime = 18; // frames
+// Touch/Swipe controls
+var touchStartX = 0,
+ touchStartY = 0,
+ touchStartTick = 0;
+game.down = function (x, y, obj) {
+ touchStartX = x;
+ touchStartY = y;
+ touchStartTick = LK.ticks;
+ lastTouch.x = x;
+ lastTouch.y = y;
+};
+game.up = function (x, y, obj) {
+ var dx = x - touchStartX;
+ var dy = y - touchStartY;
+ var dt = LK.ticks - touchStartTick;
+ if (dt > swipeTime) return; // too slow
+ if (Math.abs(dx) > Math.abs(dy)) {
+ // Horizontal swipe
+ if (dx > swipeThreshold) {
+ runner.moveLane(1); // right
+ } else if (dx < -swipeThreshold) {
+ runner.moveLane(-1); // left
+ }
+ } else {
+ // Vertical swipe
+ if (dy < -swipeThreshold) {
+ runner.jump();
+ } else if (dy > swipeThreshold) {
+ runner.slide();
+ }
+ }
+};
+game.move = function (x, y, obj) {
+ lastTouch.x = x;
+ lastTouch.y = y;
+};
+// Main update loop
+game.update = function () {
+ ticks++;
+ // Increase speed over time
+ if (ticks % 180 === 0 && gameSpeed < 38) {
+ gameSpeed += 1.2;
+ }
+ // Spawn obstacles
+ spawnTimer--;
+ if (spawnTimer <= 0) {
+ spawnTimer = 54 + Math.floor(Math.random() * 36); // 0.9-1.5s
+ var typeRand = Math.random();
+ var lane = Math.floor(Math.random() * 3);
+ var obs;
+ if (typeRand < 0.18) {
+ obs = new Train();
+ } else if (typeRand < 0.48) {
+ obs = new Barrier();
+ } else {
+ obs = new Sign();
+ }
+ obs.lane = lane;
+ obs.x = lanesX[lane];
+ obs.y = -40;
+ obs.speed = gameSpeed;
+ obstacles.push(obs);
+ game.addChild(obs);
+ }
+ // Spawn coins
+ coinSpawnTimer--;
+ if (coinSpawnTimer <= 0) {
+ coinSpawnTimer = 36 + Math.floor(Math.random() * 36); // 0.6-1.2s
+ var lane = Math.floor(Math.random() * 3);
+ var coin = new Coin();
+ coin.lane = lane;
+ coin.x = lanesX[lane];
+ coin.y = -60;
+ coin.speed = gameSpeed;
+ coinsArr.push(coin);
+ game.addChild(coin);
+ }
+ // Update runner
+ runner.update();
+ // Update obstacles
+ for (var i = obstacles.length - 1; i >= 0; i--) {
+ var obs = obstacles[i];
+ obs.update();
+ // Remove if off screen
+ if (obs.y > 2732 + 200) {
+ obs.destroy();
+ obstacles.splice(i, 1);
+ continue;
+ }
+ // Collision detection
+ if (!obs.passed && Math.abs(obs.y - runner.y) < 120 && obs.lane === runner.lane) {
+ if (obs.type === 'barrier') {
+ if (!runner.isJumping) {
+ LK.effects.flashScreen(0xff0000, 800);
+ LK.showGameOver();
+ return;
+ }
+ } else if (obs.type === 'sign') {
+ if (!runner.isSliding) {
+ LK.effects.flashScreen(0xff0000, 800);
+ LK.showGameOver();
+ return;
+ }
+ } else if (obs.type === 'train') {
+ // Train: always game over
+ LK.effects.flashScreen(0xff0000, 800);
+ LK.showGameOver();
+ return;
+ }
+ obs.passed = true;
+ score += 10;
+ scoreTxt.setText(score);
+ } else if (!obs.passed && obs.y > runner.y + 60) {
+ obs.passed = true;
+ score += 2;
+ scoreTxt.setText(score);
+ }
+ }
+ // Update coins
+ for (var i = coinsArr.length - 1; i >= 0; i--) {
+ var coin = coinsArr[i];
+ coin.update();
+ // Remove if off screen
+ if (coin.y > 2732 + 100) {
+ coin.destroy();
+ coinsArr.splice(i, 1);
+ continue;
+ }
+ // Collect coin
+ if (!coin.collected && Math.abs(coin.y - runner.y + 60) < 100 && coin.lane === runner.lane && !runner.isSliding) {
+ coin.collected = true;
+ coins++;
+ coinTxt.setText(coins);
+ coin.destroy();
+ coinsArr.splice(i, 1);
+ }
+ }
+};
\ No newline at end of file