User prompt
Copy LaneDivider and put the LineDividers you copied on both sides of the LaneDivider
User prompt
Copy the lanes of the road passing through the middle and put them on the right and left side of the strip you copied, do not put an extra line
User prompt
Delete the line in the middle
User prompt
Make the middle strip 3
User prompt
Delete the line in the middle
User prompt
LaneDivider assets Copy and settle on the right and left
User prompt
Delete what you did last time, put the same strip in the middle on both sides
User prompt
Put the same strip to the left and right of the strip in the middle.
User prompt
Add 2 stripes on the sides of the assets olarak
User prompt
Bring text right at the top of the ribbon
User prompt
Center the numbers that indicate the score, high score, and shield duration
User prompt
While the shield is active, let's not destroy enemies, cars or barriers, let's pass through them
User prompt
After 50 points, let the magic bottle come out more
User prompt
Let the magic bottle disappear when it collides with an enemy car
User prompt
Let the bottle of magic move
User prompt
Let the magic bottle stay stationary in a random lane, and as the car goes, the magic bottle will be erased when it leaves the screen
User prompt
Don't let the magic bottle be born too much
User prompt
Let the shield second provided by the magic bottle be written somewhere on the screen
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'intersects')' in or related to this line: 'if (!playerCar.shieldActive && spellBottle.intersects(playerCar)) {' Line Number: 304
User prompt
The magic bottle doesn't move again, let it move
User prompt
Put the magic bottle in random places along the path
User prompt
When you call the magic bottle a car, the car gets a 3-second shield. Don't let the magic bottle move
User prompt
Let the magic bottle spawn in random place on the way
User prompt
Add assets to the spell bottle
User prompt
High Score write ↪💡 Consider importing and using the following plugins: @upit/storage.v1
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Enemy Car Class
var EnemyCar = Container.expand(function () {
var self = Container.call(this);
var car = self.attachAsset('enemyCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = 1;
self.speed = 18;
self.update = function () {
self.y += self.speed * gameSpeed;
};
return self;
});
// Lane Divider Class
var LaneDivider = Container.expand(function () {
var self = Container.call(this);
var div = self.attachAsset('laneDivider', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 18;
self.update = function () {
self.y += self.speed * gameSpeed;
};
return self;
});
// Obstacle Class
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obs = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = 1;
self.speed = 18;
self.update = function () {
self.y += self.speed * gameSpeed;
};
return self;
});
// Player Car Class
var PlayerCar = Container.expand(function () {
var self = Container.call(this);
var car = self.attachAsset('playerCar', {
anchorX: 0.5,
anchorY: 0.5
});
self.lane = 1; // 0: left, 1: center, 2: right
self.setLane = function (laneIdx) {
self.lane = laneIdx;
// Animate to new lane position
var targetX = lanes[self.lane];
tween(self, {
x: targetX
}, {
duration: 120,
easing: tween.cubicOut
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Spell bottle asset (example: blue bottle, 120x180)
// Lane positions (3 lanes)
// Car (player)
// Enemy car
// Obstacle (barrier)
// Road lane divider
// Sound for crash
// Sound for lane change
// Music (background)
var laneCount = 3;
var laneWidth = 410;
var lanes = [2048 / 2 - laneWidth,
// left
2048 / 2,
// center
2048 / 2 + laneWidth // right
];
// Game variables
var playerCar;
var enemyCars = [];
var obstacles = [];
var laneDividers = [];
var score = 0;
var highScore = storage.highScore || 0;
var scoreTxt;
var highScoreTxt;
var gameSpeed = 1;
var ticksSinceStart = 0;
var swipeStartX = null;
var swipeStartY = null;
var swipeActive = false;
var lastLane = 1;
var spawnTick = 0;
var dividerSpacing = 320;
var dragNode = null;
// Score display
scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0.5);
LK.gui.top.addChild(scoreTxt);
// Shield timer display
var shieldTxt = new Text2('', {
size: 80,
fill: 0x2BD5E6
});
shieldTxt.anchor.set(0.5, 0.5);
LK.gui.top.addChild(shieldTxt);
// High Score display
highScoreTxt = new Text2('HI: ' + highScore, {
size: 60,
fill: 0xFFFF00
});
highScoreTxt.anchor.set(0.5, 0.5);
LK.gui.top.addChild(highScoreTxt);
// Start music
LK.playMusic('bgmusic');
// Create player car
playerCar = new PlayerCar();
playerCar.x = lanes[1];
playerCar.y = 2732 - 500;
playerCar.setLane(1);
// Shield properties
playerCar.shieldActive = false;
playerCar.shieldTicks = 0;
game.addChild(playerCar);
// Create lane dividers (vertical lines for each lane)
// Draw a divider for each lane boundary (between lanes)
for (var l = 0; l < laneCount + 1; l++) {
// For 3 lanes, this will draw 4 lines: left edge, between lanes, right edge
// But we want only the lines between lanes, so skip the first and last
if (l === 0 || l === laneCount) continue;
for (var i = 0; i < 10; i++) {
var divider = new LaneDivider();
// Place the divider at the correct X for the lane line
divider.x = (lanes[l - 1] + lanes[l]) / 2;
divider.y = i * dividerSpacing;
laneDividers.push(divider);
game.addChild(divider);
}
}
// Prepare for dynamic spell bottle spawning
var spellBottle = null;
var spellBottleActive = false;
var spellBottleLane = 1;
// Add: track last spell bottle spawn tick to limit spawn rate
var lastSpellBottleSpawnTick = -1000;
// Helper: spawn enemy car or obstacle
function spawnObstacleOrEnemy() {
// Randomly decide: 70% enemy car, 30% obstacle
var isEnemy = Math.random() < 0.7;
var laneIdx = Math.floor(Math.random() * laneCount);
var y = -300;
if (isEnemy) {
var enemy = new EnemyCar();
enemy.lane = laneIdx;
enemy.x = lanes[laneIdx];
enemy.y = y;
enemyCars.push(enemy);
game.addChild(enemy);
} else {
var obs = new Obstacle();
obs.lane = laneIdx;
obs.x = lanes[laneIdx];
obs.y = y;
obstacles.push(obs);
game.addChild(obs);
}
}
// Helper: update score
function updateScore(val) {
score = val;
scoreTxt.setText(score);
if (score > highScore) {
highScore = score;
highScoreTxt.setText('HI: ' + highScore);
storage.highScore = highScore;
}
}
// Touch/drag/swipe handling
game.down = function (x, y, obj) {
swipeStartX = x;
swipeStartY = y;
swipeActive = true;
dragNode = playerCar;
};
game.move = function (x, y, obj) {
// Only handle swipe if active
if (!swipeActive) return;
if (!dragNode) return;
var dx = x - swipeStartX;
var dy = y - swipeStartY;
// Only consider horizontal swipes, ignore vertical
if (Math.abs(dx) > 80 && Math.abs(dx) > Math.abs(dy)) {
var newLane = playerCar.lane;
if (dx < 0 && playerCar.lane > 0) {
newLane = playerCar.lane - 1;
} else if (dx > 0 && playerCar.lane < laneCount - 1) {
newLane = playerCar.lane + 1;
}
if (newLane !== playerCar.lane) {
playerCar.setLane(newLane);
LK.getSound('swipe').play();
swipeActive = false;
dragNode = null;
}
}
};
game.up = function (x, y, obj) {
swipeActive = false;
dragNode = null;
};
// Main game update loop
game.update = function () {
ticksSinceStart++;
// Only increase game speed after score reaches 50
if (score >= 50) {
if (ticksSinceStart % 60 === 0 && gameSpeed < 4) {
// Increase speed every second, and allow it to go higher
if (gameSpeed < 2) {
gameSpeed += 0.08;
} else if (gameSpeed < 3) {
gameSpeed += 0.12;
} else {
gameSpeed += 0.18;
}
if (gameSpeed > 4) gameSpeed = 4;
}
} else {
gameSpeed = 1;
}
// Move lane dividers, loop to top
for (var i = 0; i < laneDividers.length; i++) {
var div = laneDividers[i];
div.update();
if (div.y > 2732 + 60) {
div.y -= dividerSpacing * 10;
}
}
// Spawn or move spell bottle
if (!spellBottleActive) {
// Determine spawn cooldown and chance based on score
var bottleCooldown = score >= 50 ? 300 : 600; // 5s if score>=50, else 10s
var bottleChance = score >= 50 ? 1 / 60 : 1 / 120; // 1/60 per frame if score>=50, else 1/120
// Only allow spawn if enough time has passed since last spawn
if (ticksSinceStart - lastSpellBottleSpawnTick > bottleCooldown) {
// Try to spawn with the appropriate chance
if (Math.random() < bottleChance) {
spellBottleLane = Math.floor(Math.random() * laneCount);
var bottleX = lanes[spellBottleLane];
// Place the bottle at a fixed Y position (e.g., 900px from the top)
var bottleY = 900;
spellBottle = LK.getAsset('spellBottle', {
anchorX: 0.5,
anchorY: 1.0,
x: bottleX,
y: bottleY
});
game.addChild(spellBottle);
spellBottleActive = true;
lastSpellBottleSpawnTick = ticksSinceStart;
}
}
} else if (spellBottle) {
// Move the spell bottle down the screen
spellBottle.y += 18 * gameSpeed;
// Off screen? Remove (if it has scrolled above the visible area)
if (spellBottle.y < -200 || spellBottle.y > 2732 + 200) {
spellBottle.destroy();
spellBottle = null;
spellBottleActive = false;
}
// Check collision with playerCar for shield pickup
if (spellBottle && !playerCar.shieldActive && spellBottle.intersects(playerCar)) {
// Grant shield for 3 seconds
playerCar.shieldActive = true;
playerCar.shieldTicks = 180; // 3 seconds at 60fps
// Optionally, you could add a visual effect here (not required)
spellBottle.destroy();
spellBottle = null;
spellBottleActive = false;
}
}
// Spawn enemies/obstacles every 40-60 ticks, randomize
spawnTick++;
var spawnInterval = 40 + Math.floor(Math.random() * 20);
if (spawnTick > spawnInterval) {
spawnObstacleOrEnemy();
spawnTick = 0;
}
// Update enemy cars
for (var i = enemyCars.length - 1; i >= 0; i--) {
var enemy = enemyCars[i];
enemy.update();
// Off screen
if (enemy.y > 2732 + 300) {
enemy.destroy();
enemyCars.splice(i, 1);
updateScore(score + 1);
continue;
}
// Collision with spell bottle
if (spellBottle && enemy.intersects(spellBottle)) {
spellBottle.destroy();
spellBottle = null;
spellBottleActive = false;
}
// Collision with player
if (enemy.intersects(playerCar)) {
if (playerCar.shieldActive) {
// Ignore collision, let player pass through enemy car while shield is active
continue;
} else {
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
}
// Update obstacles
for (var j = obstacles.length - 1; j >= 0; j--) {
var obs = obstacles[j];
obs.update();
// Off screen
if (obs.y > 2732 + 200) {
obs.destroy();
obstacles.splice(j, 1);
updateScore(score + 1);
continue;
}
// Collision with player
if (obs.intersects(playerCar)) {
if (playerCar.shieldActive) {
// Ignore collision, let player pass through obstacle while shield is active
continue;
} else {
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
}
;
// Shield timer logic
if (playerCar.shieldActive) {
playerCar.shieldTicks--;
// Show shield seconds left (rounded up)
var shieldSeconds = Math.ceil(playerCar.shieldTicks / 60);
shieldTxt.setText("Shield: " + shieldSeconds + "s");
if (playerCar.shieldTicks <= 0) {
playerCar.shieldActive = false;
playerCar.shieldTicks = 0;
shieldTxt.setText('');
}
} else {
shieldTxt.setText('');
}
};
// Center score text at top, avoid top left 100x100
scoreTxt.x = LK.gui.top.width / 2;
scoreTxt.y = 100;
// Position shield timer text below score
shieldTxt.x = LK.gui.top.width / 2;
shieldTxt.y = scoreTxt.y + scoreTxt.height / 2 + shieldTxt.height / 2 + 10;
// Position high score text below shield timer
highScoreTxt.x = LK.gui.top.width / 2;
highScoreTxt.y = shieldTxt.y + shieldTxt.height / 2 + highScoreTxt.height / 2 + 10; ===================================================================
--- original.js
+++ change.js
@@ -119,23 +119,23 @@
scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
-scoreTxt.anchor.set(0.5, 0);
+scoreTxt.anchor.set(0.5, 0.5);
LK.gui.top.addChild(scoreTxt);
// Shield timer display
var shieldTxt = new Text2('', {
size: 80,
fill: 0x2BD5E6
});
-shieldTxt.anchor.set(0.5, 0);
+shieldTxt.anchor.set(0.5, 0.5);
LK.gui.top.addChild(shieldTxt);
// High Score display
highScoreTxt = new Text2('HI: ' + highScore, {
size: 60,
fill: 0xFFFF00
});
-highScoreTxt.anchor.set(0.5, 0);
+highScoreTxt.anchor.set(0.5, 0.5);
LK.gui.top.addChild(highScoreTxt);
// Start music
LK.playMusic('bgmusic');
// Create player car
@@ -382,11 +382,11 @@
}
};
// Center score text at top, avoid top left 100x100
scoreTxt.x = LK.gui.top.width / 2;
-scoreTxt.y = 40;
+scoreTxt.y = 100;
// Position shield timer text below score
shieldTxt.x = LK.gui.top.width / 2;
-shieldTxt.y = scoreTxt.y + scoreTxt.height + 5;
+shieldTxt.y = scoreTxt.y + scoreTxt.height / 2 + shieldTxt.height / 2 + 10;
// Position high score text below shield timer
highScoreTxt.x = LK.gui.top.width / 2;
-highScoreTxt.y = shieldTxt.y + shieldTxt.height + 10;
\ No newline at end of file
+highScoreTxt.y = shieldTxt.y + shieldTxt.height / 2 + highScoreTxt.height / 2 + 10;
\ No newline at end of file