User prompt
reserve özelliğinden sonra maruz kalan araçlar ve engeller patlasın patlama efekti olsun
User prompt
reserve özelliğinden sonra araçlar en son patlasın
User prompt
bonus da aldığı özelliği oyuncuya belli et
User prompt
bonusu oyuncuya belli et
User prompt
reverse bonus kullanıldığında araçlar geriye doğru gittikten sonra patlasın
User prompt
bonus da çıkan yazıya emoji ekle
User prompt
dahada büyük yaz skorun boyutunda olsun
User prompt
yazıyı daha büyük yaz
User prompt
bonus yazısını biraz daha kalın yaz ve emoji kullan
User prompt
bütün ses dosyalarını sıfırla ve yeni sesler ekle oyunda olması gereken her sesi ekle
User prompt
oyuna arkaplan müziği ekle
User prompt
bonus çıkma olasılığını arttır oyuncunun çoğunlukla alabileceği yerlerde çıksın
User prompt
✅ Add new fun bonus types with unique effects (slow motion, shrink, invincibility, random teleport, etc) ✅ Implement new bonus effects in collision logic (slowmo, shrink, invincible, teleport, clear, magnet, reverse) ✅ Handle new bonus timers and effects in main update loop (slowmo, shrink, invincible, magnet, reverse) ✅ Make player invincible to crash if invincible bonus is active ✅ Make player invincible to crash with obstacles if invincible bonus is active ✅ Reset all new bonus effects on game start bu ekledğin bonusları test et çalışıyorsa kalsın çalışmıyorsa sil
User prompt
başka daha eğlenceli bonuslar ekle
User prompt
50 tane bonus ekle basit bonuslar olsun
User prompt
mousela birlikte haraket etsin
User prompt
kontroller kullanıcı dostu olsun çok kolay kontrol edilebilsin
User prompt
yazıyı biraz daha aşağıya yaz ve görünür bir renkte olsun
User prompt
bonus dan ne çıktığını ekrana yaz
User prompt
tamam oyuna ekleyebildiğini ekle ekleyemediğini sil
User prompt
oyun ilk başta orta hızda olsun sonradan zorluğa göre hızlansın
User prompt
oyun ilk başta yavaş olsun
User prompt
playercar biraz daha küçüly
User prompt
enemycar assetlerini çoğalt
User prompt
oyunu çok kolaydan ortaya sonra zora al
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bonus Item Class
var Bonus = Container.expand(function () {
var self = Container.call(this);
// 50 simple bonus types, all using the same asset but different type strings
var types = [];
for (var i = 1; i <= 40; i++) {
types.push({
id: 'bonus',
type: 'score' + i
});
}
// Add new fun bonus types!
types.push({
id: 'bonus',
type: 'shield'
});
types.push({
id: 'bonus',
type: 'double'
});
types.push({
id: 'bonus',
type: 'slowmo'
}); // Slow motion for a short time
types.push({
id: 'bonus',
type: 'shrink'
}); // Shrink player for a short time
types.push({
id: 'bonus',
type: 'invincible'
}); // Invincible for a short time
types.push({
id: 'bonus',
type: 'teleport'
}); // Teleport player to random lane
types.push({
id: 'bonus',
type: 'clear'
}); // Clear all obstacles/enemies
types.push({
id: 'bonus',
type: 'magnet'
}); // Attract bonuses for a short time
types.push({
id: 'bonus',
type: 'reverse'
}); // Reverse enemy direction for a short time
types.push({
id: 'bonus',
type: 'score'
}); // fallback classic
var chosen = types[Math.floor(Math.random() * types.length)];
self.type = chosen.type;
// Use different tints for power-ups
var tint = 0xffffff;
if (self.type === 'shield') tint = 0x42a5f5;else if (self.type === 'double') tint = 0xffd600;else {
// Give each score bonus a different color for fun
// Cycle through a palette
var palette = [0xffffff, 0xffe082, 0x80cbc4, 0xffab91, 0xb39ddb, 0xa5d6a7, 0xffccbc, 0x90caf9, 0xf48fb1, 0xc5e1a5, 0xffecb3, 0xb0bec5, 0xd7ccc8, 0xffb74d, 0x81d4fa, 0xe1bee7, 0xc8e6c9, 0xff8a65, 0x9575cd, 0x4db6ac, 0x7986cb, 0x64b5f6, 0xffd54f, 0x4fc3f7, 0x81c784, 0xba68c8, 0x4dd0e1, 0xf06292, 0xa1887f, 0x90a4ae, 0x388e3c, 0xdce775, 0x00bcd4, 0x8d6e63, 0x43a047, 0x00acc1, 0x689f38, 0x039be5, 0x7e57c2, 0x0288d1, 0x0097a7, 0x388e3c, 0x1976d2, 0x0288d1, 0x009688, 0x43a047, 0x689f38];
// Extract number from type string, e.g. "score17" -> 17
var idx = 0;
if (self.type.indexOf('score') === 0 && self.type.length > 5) {
idx = parseInt(self.type.substring(5), 10) - 1;
if (isNaN(idx) || idx < 0) idx = 0;
}
tint = palette[idx % palette.length];
}
var b = self.attachAsset(chosen.id, {
anchorX: 0.5,
anchorY: 0.5
});
b.tint = tint;
self.width = b.width;
self.height = b.height;
self.speed = 18 + Math.random() * 8; // Will be set by game
self.lane = 0;
self.update = function () {
self.y += self.speed;
};
self.getBounds = function () {
// Shrink hitbox for better gameplay feel
var w = b.width * 0.7;
var h = b.height * 0.7;
return {
x: self.x - w / 2,
y: self.y - h / 2,
width: w,
height: h
};
};
return self;
});
// Enemy Car Class
var EnemyCar = Container.expand(function () {
var self = Container.call(this);
// Randomly select one of the enemy car asset ids
var enemyCarIds = ['enemyCar', 'enemyCar2', 'enemyCar3', 'enemyCar4'];
var chosenId = enemyCarIds[Math.floor(Math.random() * enemyCarIds.length)];
var car = self.attachAsset(chosenId, {
anchorX: 0.5,
anchorY: 0.5
});
self.width = car.width;
self.height = car.height;
self.speed = 18 + Math.random() * 8; // Will be set by game
self.lane = 0;
self.update = function () {
self.y += self.speed;
};
self.getBounds = function () {
// Shrink hitbox for better gameplay feel
var w = car.width * 0.7;
var h = car.height * 0.7;
return {
x: self.x - w / 2,
y: self.y - h / 2,
width: w,
height: h
};
};
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.width = obs.width;
self.height = obs.height;
self.speed = 18 + Math.random() * 8; // Will be set by game
self.lane = 0;
self.update = function () {
self.y += self.speed;
};
self.getBounds = function () {
// Shrink hitbox for better gameplay feel
var w = obs.width * 0.7;
var h = obs.height * 0.7;
return {
x: self.x - w / 2,
y: self.y - h / 2,
width: w,
height: h
};
};
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,
scaleX: 0.55,
scaleY: 0.55
});
self._carAsset = car; // Store reference for shrink/restore
self.width = car.width * 0.55;
self.height = car.height * 0.55;
// For touch drag offset
self.dragOffsetX = 0;
self.dragOffsetY = 0;
// For collision
self.getBounds = function () {
// Shrink hitbox for better gameplay feel
var w = car.width * 0.55;
var h = car.height * 0.55;
return {
x: self.x - w / 2,
y: self.y - h / 2,
width: w,
height: h
};
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222222
});
/****
* Game Code
****/
// Intense mode music (for hard stage, optional)
// Main background music (looped)
// --- MUSIC ---
// Win
// Game over
// Button tap (UI)
// Lane change (player moves to another lane)
// Reverse pickup
// Magnet pickup
// Clear pickup
// Teleport pickup
// Invincible pickup
// Shrink pickup
// Slowmo pickup
// Double score pickup
// Shield pickup
// Bonus pickup
// Car crash
// Car engine accelerate (short burst)
// Car engine idle (looped quietly in background)
// --- SOUND EFFECTS ---
// Tree and plant assets for background
// Road and lane setup
// Car (player)
// Enemy car
// Obstacle (barrier)
// Road lane
// Bonus item
var roadWidth = 900;
var roadLeft = (2048 - roadWidth) / 2;
var roadRight = roadLeft + roadWidth;
var laneCount = 4;
var laneWidth = roadWidth / laneCount;
var laneCenters = [];
for (var i = 0; i < laneCount; i++) {
laneCenters.push(roadLeft + laneWidth / 2 + i * laneWidth);
}
// --- Add colorful trees and plants to left and right sides of the road as background ---
var bgDecor = [];
var decorTypes = [{
id: 'tree1',
yOffset: 0
}, {
id: 'tree2',
yOffset: 40
}, {
id: 'plant1',
yOffset: 120
}, {
id: 'plant2',
yOffset: 180
}, {
id: 'plant3',
yOffset: 240
}, {
id: 'plant3',
yOffset: 240
}, {
id: 'plant3',
yOffset: 240
}, {
id: 'plant3',
yOffset: 240
}, {
// extra plant3 for higher probability
id: 'plant3',
yOffset: 240
}, {
id: 'plant3',
yOffset: 240
}, {
id: 'plant3',
yOffset: 240
}];
// Place decorations in a staggered, repeating pattern, but less frequently
for (var side = 0; side < 2; side++) {
// 0: left, 1: right
for (var i = 0; i < 4; i++) {
// Reduced from 8 to 4 for lower frequency
var typeIdx = i % decorTypes.length;
var decor = LK.getAsset(decorTypes[typeIdx].id, {
anchorX: 0.5,
anchorY: 0.5
});
// X position: left or right of road, with some random offset for natural look
if (side === 0) {
decor.x = roadLeft - 90 + Math.random() * 30;
} else {
decor.x = roadRight + 90 - Math.random() * 30;
}
// Y position: staggered vertically, with some random offset, spacing increased for less density
decor.y = 300 + i * 640 + decorTypes[typeIdx].yOffset + Math.random() * 40;
// Store for scrolling
decor._baseY = decor.y;
decor._side = side;
decor._typeIdx = typeIdx;
game.addChild(decor);
bgDecor.push(decor);
}
}
// Draw lane markers (scrolling effect)
var laneMarkers = [];
for (var i = 1; i < laneCount; i++) {
for (var j = 0; j < 6; j++) {
var marker = LK.getAsset('lane', {
anchorX: 0.5,
anchorY: 0.5,
x: roadLeft + i * laneWidth,
y: j * 400
});
marker.laneIdx = i;
marker.offsetIdx = j;
game.addChild(marker);
laneMarkers.push(marker);
}
}
// Player car
var player = new PlayerCar();
player.x = laneCenters[1];
player.y = 2732 - 500;
game.addChild(player);
// Score
var score = 0;
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Bonus score
var bonusScore = 0;
var bonusTxt = new Text2('', {
size: 80,
fill: 0xFFFA00,
// Bright yellow for high visibility
font: "bold 900 80px Arial, 'GillSans-Bold', Impact, 'Arial Black', Tahoma" // Extra bold
});
bonusTxt.anchor.set(0.5, 0);
// Move the bonus text further down (e.g. 180px from the top)
bonusTxt.y = 180;
LK.gui.top.addChild(bonusTxt);
// Game state
var enemyCars = [];
var obstacles = [];
var bonuses = [];
var gameSpeed = 18;
var ticksSinceStart = 0;
var lastSpawnTick = 0;
var lastBonusTick = 0;
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
var playerStartX = 0;
var playerStartY = 0;
var lastCrash = false;
// Mouse/touch drag to move player car directly with finger/mouse
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
var playerStartX = 0;
var playerStartY = 0;
game.down = function (x, y, obj) {
// Only start drag if touch/click is on the player car
// Use a generous hitbox for mobile
var bounds = player.getBounds();
if (x >= bounds.x - 60 && x <= bounds.x + bounds.width + 60 && y >= bounds.y - 60 && y <= bounds.y + bounds.height + 60) {
isDragging = true;
dragStartX = x;
dragStartY = y;
playerStartX = player.x;
playerStartY = player.y;
// Cancel any lane tween if present
if (typeof playerMoveTween !== "undefined" && playerMoveTween && playerMoveTween.cancel) playerMoveTween.cancel();
}
};
game.move = function (x, y, obj) {
if (isDragging) {
// Move player car with finger/mouse, but clamp to road
var dx = x - dragStartX;
var dy = y - dragStartY;
var newX = playerStartX + dx;
var newY = playerStartY + dy;
// Clamp X to road
var minX = roadLeft + player.width / 2;
var maxX = roadRight - player.width / 2;
if (newX < minX) newX = minX;
if (newX > maxX) newX = maxX;
// Clamp Y to visible area (bottom 2/3 of screen)
var minY = 600 + player.height / 2;
var maxY = 2732 - player.height / 2;
if (newY < minY) newY = minY;
if (newY > maxY) newY = maxY;
// Play lane change sound if player changed lane (by X)
if (Math.abs(player.x - newX) > laneWidth * 0.8) {
LK.getSound('lane_change').play();
}
player.x = newX;
player.y = newY;
}
};
game.up = function (x, y, obj) {
isDragging = false;
};
// Helper: collision check (AABB)
function intersects(a, b) {
var ab = a.getBounds();
var bb = b.getBounds();
return ab.x < bb.x + bb.width && ab.x + ab.width > bb.x && ab.y < bb.y + bb.height && ab.y + ab.height > bb.y;
}
// Main game loop
game.update = function () {
ticksSinceStart++;
// 3-stage difficulty progression: very easy, then medium, then hard
// Very Easy: 0-3000 ticks (~50s), Medium: 3000-6000 ticks (~100s), Hard: 6000+ ticks
if (!game._spawnInterval) game._spawnInterval = 40;
if (ticksSinceStart < 3000) {
// Very Easy: very slow ramp up
if (ticksSinceStart % 600 == 0 && gameSpeed < 20) {
gameSpeed += 1;
}
if (ticksSinceStart % 600 == 0 && game._spawnInterval > 32) {
game._spawnInterval -= 1;
}
} else if (ticksSinceStart < 6000) {
// Medium: moderate ramp up
if (ticksSinceStart % 300 == 0 && gameSpeed < 28) {
gameSpeed += 1;
}
if (ticksSinceStart % 300 == 0 && game._spawnInterval > 20) {
game._spawnInterval -= 1;
}
} else {
// Hard: faster ramp up, but cap
if (ticksSinceStart % 120 == 0 && gameSpeed < 38) {
gameSpeed += 1;
}
if (ticksSinceStart % 120 == 0 && game._spawnInterval > 14) {
game._spawnInterval -= 1;
}
}
// Move background trees and plants for scrolling effect
for (var i = 0; i < bgDecor.length; i++) {
var decor = bgDecor[i];
decor.y += gameSpeed;
// If decor goes off bottom, loop to top with new random offset for variety
if (decor.y > 2732 + 120) {
decor.y -= 8 * 320;
decor.y += Math.random() * 40 - 20;
// Optionally randomize X a bit for more natural look
if (decor._side === 0) {
decor.x = roadLeft - 90 + Math.random() * 30;
} else {
decor.x = roadRight + 90 - Math.random() * 30;
}
}
}
// Move lane markers for scrolling effect
for (var i = 0; i < laneMarkers.length; i++) {
var marker = laneMarkers[i];
marker.y += gameSpeed;
if (marker.y > 2732) {
marker.y -= 2400;
}
}
// Spawn enemy cars and obstacles, ensuring no overlap with any existing object
if (ticksSinceStart - lastSpawnTick > (game._spawnInterval || 36)) {
lastSpawnTick = ticksSinceStart;
// Randomly pick lanes to spawn cars/obstacles, but never all 4 at once
var spawnLanes = [];
for (var i = 0; i < laneCount; i++) {
if (Math.random() < 0.5) spawnLanes.push(i);
}
// Never allow all 4 lanes to be filled at once
if (spawnLanes.length > 3) {
// Randomly remove one lane to ensure max 3
var idxToRemove = Math.floor(Math.random() * spawnLanes.length);
spawnLanes.splice(idxToRemove, 1);
}
if (spawnLanes.length == 0) spawnLanes.push(Math.floor(Math.random() * laneCount));
// Limit to max 3 obstacles per spawn
var obstacleCountThisSpawn = 0;
// Track which lanes will have obstacles this spawn
var obstacleLanesThisSpawn = [];
// Track which lanes are used (to prevent both enemy and obstacle in same lane)
var usedLanes = {};
// Track all new objects to check for overlap
var newObjects = [];
for (var i = 0; i < spawnLanes.length; i++) {
var laneIdx = spawnLanes[i];
// If already 3 obstacles, force enemy car for the rest
var forceEnemy = obstacleCountThisSpawn >= 3;
// Only allow one object per lane (no overlap of enemy/obstacle)
if (usedLanes[laneIdx]) continue;
// Determine spawn Y and type
var spawnY,
obj,
isObstacle = false;
if (!forceEnemy && Math.random() >= 0.7) {
// Obstacle
obj = new Obstacle();
obj.x = laneCenters[laneIdx];
obj.y = -100;
obj.speed = gameSpeed;
obj.lane = laneIdx;
spawnY = obj.y;
isObstacle = true;
} else {
// Enemy car
obj = new EnemyCar();
obj.x = laneCenters[laneIdx];
obj.y = -200;
obj.speed = gameSpeed;
obj.lane = laneIdx;
spawnY = obj.y;
}
// Check for overlap with all existing objects (enemyCars, obstacles, bonuses) and newObjects
var overlap = false;
var objBounds = obj.getBounds();
// Check with existing enemy cars
for (var j = 0; j < enemyCars.length; j++) {
if (enemyCars[j].lane === laneIdx) {
var other = enemyCars[j];
var otherBounds = other.getBounds();
if (!(objBounds.x + objBounds.width < otherBounds.x || objBounds.x > otherBounds.x + otherBounds.width || objBounds.y + objBounds.height < otherBounds.y || objBounds.y > otherBounds.y + otherBounds.height)) {
overlap = true;
break;
}
}
}
// Check with existing obstacles
if (!overlap) {
for (var j = 0; j < obstacles.length; j++) {
if (obstacles[j].lane === laneIdx) {
var other = obstacles[j];
var otherBounds = other.getBounds();
if (!(objBounds.x + objBounds.width < otherBounds.x || objBounds.x > otherBounds.x + otherBounds.width || objBounds.y + objBounds.height < otherBounds.y || objBounds.y > otherBounds.y + otherBounds.height)) {
overlap = true;
break;
}
}
}
}
// Check with existing bonuses
if (!overlap) {
for (var j = 0; j < bonuses.length; j++) {
if (bonuses[j].lane === laneIdx) {
var other = bonuses[j];
var otherBounds = other.getBounds();
if (!(objBounds.x + objBounds.width < otherBounds.x || objBounds.x > otherBounds.x + otherBounds.width || objBounds.y + objBounds.height < otherBounds.y || objBounds.y > otherBounds.y + otherBounds.height)) {
overlap = true;
break;
}
}
}
}
// Check with new objects in this spawn
if (!overlap) {
for (var j = 0; j < newObjects.length; j++) {
if (newObjects[j].lane === laneIdx) {
var other = newObjects[j];
var otherBounds = other.getBounds();
if (!(objBounds.x + objBounds.width < otherBounds.x || objBounds.x > otherBounds.x + otherBounds.width || objBounds.y + objBounds.height < otherBounds.y || objBounds.y > otherBounds.y + otherBounds.height)) {
overlap = true;
break;
}
}
}
}
if (overlap) {
// Don't spawn this object
if (obj && obj.destroy) obj.destroy();
continue;
}
// No overlap, spawn
if (isObstacle) {
obstacles.push(obj);
game.addChild(obj);
obstacleCountThisSpawn++;
obstacleLanesThisSpawn.push(laneIdx);
usedLanes[laneIdx] = true;
} else {
enemyCars.push(obj);
game.addChild(obj);
usedLanes[laneIdx] = true;
}
newObjects.push(obj);
}
// Store obstacle lanes for this tick for bonus spawn logic
game._obstacleLanesThisSpawn = obstacleLanesThisSpawn;
} else {
// If not spawning this tick, clear obstacle lanes
game._obstacleLanesThisSpawn = [];
}
// Spawn bonus, ensuring no overlap with any object
// Increased spawn frequency: every 90 ticks (was 180), and higher probability (was 0.5, now 0.85)
if (ticksSinceStart - lastBonusTick > 90 && Math.random() < 0.85) {
lastBonusTick = ticksSinceStart;
// Prevent bonus from spawning in a lane with an obstacle this tick
var availableBonusLanes = [];
// Only consider the two center lanes as "most accessible" for the player
var preferredLanes = [1, 2];
for (var i = 0; i < laneCount; i++) {
var blocked = false;
if (game._obstacleLanesThisSpawn) {
for (var j = 0; j < game._obstacleLanesThisSpawn.length; j++) {
if (game._obstacleLanesThisSpawn[j] === i) {
blocked = true;
break;
}
}
}
// Check for overlap with any object in this lane at spawn Y
if (!blocked) {
var testBonus = new Bonus();
testBonus.x = laneCenters[i];
testBonus.y = -100;
testBonus.lane = i;
var testBounds = testBonus.getBounds();
// Check with enemy cars
for (var j = 0; j < enemyCars.length; j++) {
if (enemyCars[j].lane === i) {
var other = enemyCars[j];
var otherBounds = other.getBounds();
if (!(testBounds.x + testBounds.width < otherBounds.x || testBounds.x > otherBounds.x + otherBounds.width || testBounds.y + testBounds.height < otherBounds.y || testBounds.y > otherBounds.y + otherBounds.height)) {
blocked = true;
break;
}
}
}
// Check with obstacles
if (!blocked) {
for (var j = 0; j < obstacles.length; j++) {
if (obstacles[j].lane === i) {
var other = obstacles[j];
var otherBounds = other.getBounds();
if (!(testBounds.x + testBounds.width < otherBounds.x || testBounds.x > otherBounds.x + otherBounds.width || testBounds.y + testBounds.height < otherBounds.y || testBounds.y > otherBounds.y + otherBounds.height)) {
blocked = true;
break;
}
}
}
}
// Check with bonuses
if (!blocked) {
for (var j = 0; j < bonuses.length; j++) {
if (bonuses[j].lane === i) {
var other = bonuses[j];
var otherBounds = other.getBounds();
if (!(testBounds.x + testBounds.width < otherBounds.x || testBounds.x > otherBounds.x + otherBounds.width || testBounds.y + testBounds.height < otherBounds.y || testBounds.y > otherBounds.y + otherBounds.height)) {
blocked = true;
break;
}
}
}
}
if (!blocked) availableBonusLanes.push(i);
if (testBonus && testBonus.destroy) testBonus.destroy();
}
}
// Prefer to spawn in center lanes if available, else fallback to any available
var spawnLanes = [];
for (var i = 0; i < availableBonusLanes.length; i++) {
if (preferredLanes.indexOf(availableBonusLanes[i]) !== -1) {
spawnLanes.push(availableBonusLanes[i]);
}
}
if (spawnLanes.length === 0) spawnLanes = availableBonusLanes;
if (spawnLanes.length > 0) {
var laneIdx = spawnLanes[Math.floor(Math.random() * spawnLanes.length)];
var b = new Bonus();
b.x = laneCenters[laneIdx];
b.y = -100;
b.speed = gameSpeed;
b.lane = laneIdx;
bonuses.push(b);
game.addChild(b);
}
}
// Move enemy cars
for (var i = enemyCars.length - 1; i >= 0; i--) {
var e = enemyCars[i];
e.update();
if (e.y > 2732 + 200) {
e.destroy();
enemyCars.splice(i, 1);
continue;
}
// Collision with player
if (intersects(player, e)) {
if (!lastCrash) {
if (player._invincible) {
// Invincible: just destroy enemy, no crash
LK.effects.flashObject(player, 0xFFD700, 400);
enemyCars.splice(i, 1);
e.destroy();
continue;
}
if (player._shield) {
player._shield = 0;
LK.effects.flashObject(player, 0x42a5f5, 600);
enemyCars.splice(i, 1);
e.destroy();
continue;
}
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 800);
lastCrash = true;
LK.getSound('gameover').play();
LK.showGameOver();
return;
}
}
}
// Move obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var o = obstacles[i];
o.update();
if (o.y > 2732 + 100) {
o.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision with player
if (intersects(player, o)) {
if (!lastCrash) {
if (player._invincible) {
// Invincible: just destroy obstacle, no crash
LK.effects.flashObject(player, 0xFFD700, 400);
obstacles.splice(i, 1);
o.destroy();
continue;
}
if (player._shield) {
player._shield = 0;
LK.effects.flashObject(player, 0x42a5f5, 600);
obstacles.splice(i, 1);
o.destroy();
continue;
}
LK.getSound('crash').play();
LK.effects.flashScreen(0xff0000, 800);
lastCrash = true;
LK.getSound('gameover').play();
LK.showGameOver();
return;
}
}
}
// Move bonuses
for (var i = bonuses.length - 1; i >= 0; i--) {
var b = bonuses[i];
b.update();
if (b.y > 2732 + 100) {
b.destroy();
bonuses.splice(i, 1);
continue;
}
// Collision with player
if (intersects(player, b)) {
if (b.type === 'shield') {
player._shield = 1;
LK.getSound('shield').play();
LK.effects.flashObject(player, 0x42a5f5, 600);
bonusTxt.setText("🛡️ <b>SHIELD!</b> (Shield Bonus)");
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
alpha: 0
}, {
duration: 900,
easing: tween.linear,
onFinish: function onFinish() {
t.setText('');
}
});
})();
} else if (b.type === 'double') {
player._doubleScore = 1;
player._doubleScoreTicks = 600; // 10 seconds at 60fps
LK.getSound('double').play();
LK.effects.flashObject(player, 0xffd600, 600);
bonusTxt.setText("✨ <b>x2 SCORE!</b> (Double Score Bonus)");
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
alpha: 0
}, {
duration: 900,
easing: tween.linear,
onFinish: function onFinish() {
t.setText('');
}
});
})();
} else if (b.type === 'slowmo') {
// Slow motion: halve gameSpeed for 6 seconds
if (!game._slowmoTicks || game._slowmoTicks <= 0) {
game._origGameSpeed = gameSpeed;
gameSpeed = Math.max(8, Math.floor(gameSpeed / 2));
game._slowmoTicks = 360;
LK.getSound('slowmo').play();
bonusTxt.setText("🐢 <b>SLOW-MO!</b> (Everything slows down)");
LK.effects.flashObject(player, 0x80cbc4, 600);
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
alpha: 0
}, {
duration: 1200,
easing: tween.linear,
onFinish: function onFinish() {
t.setText('');
}
});
})();
}
} else if (b.type === 'shrink') {
// Shrink player for 8 seconds
if (!player._shrinkTicks || player._shrinkTicks <= 0) {
player._shrinkTicks = 480;
player.scaleX = player.scaleY = 0.35;
player.width = player._carAsset.width * 0.35;
player.height = player._carAsset.height * 0.35;
LK.getSound('shrink').play();
bonusTxt.setText("🔎 <b>SHRINK!</b> (Tiny car!)");
LK.effects.flashObject(player, 0xf48fb1, 600);
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
alpha: 0
}, {
duration: 1200,
easing: tween.linear,
onFinish: function onFinish() {
t.setText('');
}
});
})();
}
} else if (b.type === 'invincible') {
// Invincible for 7 seconds
player._invincible = 1;
player._invincibleTicks = 420;
LK.getSound('invincible').play();
bonusTxt.setText("💥 <b>INVINCIBLE!</b> (Can't crash!)");
LK.effects.flashObject(player, 0xFFD700, 600);
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
alpha: 0
}, {
duration: 1200,
easing: tween.linear,
onFinish: function onFinish() {
t.setText('');
}
});
})();
} else if (b.type === 'teleport') {
// Teleport player to random lane
var oldLane = -1;
for (var li = 0; li < laneCenters.length; li++) {
if (Math.abs(player.x - laneCenters[li]) < laneWidth / 2) oldLane = li;
}
var newLane = oldLane;
while (newLane === oldLane) {
newLane = Math.floor(Math.random() * laneCenters.length);
}
player.x = laneCenters[newLane];
LK.getSound('teleport').play();
bonusTxt.setText("🌀 <b>TELEPORT!</b> (Random lane)");
LK.effects.flashObject(player, 0x4fc3f7, 600);
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
alpha: 0
}, {
duration: 1200,
easing: tween.linear,
onFinish: function onFinish() {
t.setText('');
}
});
})();
} else if (b.type === 'clear') {
// Clear all obstacles and enemy cars
for (var ci = enemyCars.length - 1; ci >= 0; ci--) {
enemyCars[ci].destroy();
enemyCars.splice(ci, 1);
}
for (var oi = obstacles.length - 1; oi >= 0; oi--) {
obstacles[oi].destroy();
obstacles.splice(oi, 1);
}
LK.getSound('clear').play();
bonusTxt.setText("🧹 <b>CLEAR!</b> (All obstacles gone)");
LK.effects.flashObject(player, 0x81d4fa, 600);
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
alpha: 0
}, {
duration: 1200,
easing: tween.linear,
onFinish: function onFinish() {
t.setText('');
}
});
})();
} else if (b.type === 'magnet') {
// Magnet: attract bonuses for 8 seconds
player._magnetTicks = 480;
LK.getSound('magnet').play();
bonusTxt.setText("🧲 <b>MAGNET!</b> (Bonuses come to you)");
LK.effects.flashObject(player, 0xff8a65, 600);
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
alpha: 0
}, {
duration: 1200,
easing: tween.linear,
onFinish: function onFinish() {
t.setText('');
}
});
})();
} else if (b.type === 'reverse') {
// Reverse: enemies move up for 5 seconds
game._reverseTicks = 300;
LK.getSound('reverse').play();
bonusTxt.setText("🔄 <b>REVERSE!</b> (Enemies go up!)");
LK.effects.flashObject(player, 0xba68c8, 600);
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
alpha: 0
}, {
duration: 1200,
easing: tween.linear,
onFinish: function onFinish() {
t.setText('');
}
});
})();
} else if (b.type.indexOf('score') === 0) {
// All score bonuses
var addScore = 100;
// Optionally, make higher-numbered bonuses worth more
var idx = 0;
if (b.type.length > 5) {
idx = parseInt(b.type.substring(5), 10) - 1;
if (isNaN(idx) || idx < 0) idx = 0;
}
addScore += idx * 10; // e.g. score17 gives 100+16*10=260
if (player._doubleScore) addScore *= 2;
bonusScore += addScore;
score += addScore;
LK.getSound('bonus').play();
LK.effects.flashObject(player, 0x43a047, 400);
bonusTxt.setText("🎁 <b>+" + addScore + "!</b> (Bonus " + b.type.replace('score', '') + ")");
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
alpha: 0
}, {
duration: 900,
easing: tween.linear,
onFinish: function onFinish() {
t.setText('');
}
});
})();
} else {
// fallback
var addScore = 100;
if (player._doubleScore) addScore *= 2;
bonusScore += addScore;
score += addScore;
LK.getSound('bonus').play();
LK.effects.flashObject(player, 0x43a047, 400);
bonusTxt.setText("🎁 <b>+" + addScore + "!</b> (Score Bonus)");
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
alpha: 0
}, {
duration: 900,
easing: tween.linear,
onFinish: function onFinish() {
t.setText('');
}
});
})();
}
b.destroy();
bonuses.splice(i, 1);
}
}
// Score increases with distance
if (!lastCrash) {
var addScore = Math.floor(gameSpeed / 2);
if (player._doubleScore) addScore *= 2;
score += addScore;
scoreTxt.setText(score + "");
// Handle double score timer
if (player._doubleScore) {
player._doubleScoreTicks--;
if (player._doubleScoreTicks <= 0) {
player._doubleScore = 0;
player._doubleScoreTicks = 0;
}
}
// Handle slowmo timer
if (game._slowmoTicks && game._slowmoTicks > 0) {
game._slowmoTicks--;
if (game._slowmoTicks === 0 && typeof game._origGameSpeed !== "undefined") {
gameSpeed = game._origGameSpeed;
game._origGameSpeed = undefined;
}
}
// Handle shrink timer
if (player._shrinkTicks && player._shrinkTicks > 0) {
player._shrinkTicks--;
if (player._shrinkTicks === 0) {
player.scaleX = player.scaleY = 0.55;
// Restore width/height to original (not cumulative shrink)
player.width = player._carAsset.width * 0.55;
player.height = player._carAsset.height * 0.55;
}
}
// Handle invincible timer
if (player._invincible && player._invincibleTicks > 0) {
player._invincibleTicks--;
if (player._invincibleTicks === 0) {
player._invincible = 0;
}
}
// Handle magnet timer
if (player._magnetTicks && player._magnetTicks > 0) {
player._magnetTicks--;
// Attract bonuses
for (var mi = 0; mi < bonuses.length; mi++) {
var bonusObj = bonuses[mi];
var dx = player.x - bonusObj.x;
var dy = player.y - bonusObj.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 600) {
// Move bonus towards player
bonusObj.x += dx * 0.08;
bonusObj.y += dy * 0.08;
}
}
if (player._magnetTicks === 0) {
// End magnet
}
}
// Handle reverse timer
if (game._reverseTicks && game._reverseTicks > 0) {
game._reverseTicks--;
// Reverse enemy and obstacle movement
for (var ri = 0; ri < enemyCars.length; ri++) {
enemyCars[ri].y -= gameSpeed * 2;
}
for (var ro = 0; ro < obstacles.length; ro++) {
obstacles[ro].y -= gameSpeed * 2;
}
if (game._reverseTicks === 0) {
// End reverse
}
}
// Play win sound if score threshold reached (example: 10000)
if (score >= 10000 && !game._winSoundPlayed) {
LK.getSound('win').play();
game._winSoundPlayed = true;
}
}
};
// Reset crash state on new game
LK.on('gameStart', function () {
lastCrash = false;
score = 0;
bonusScore = 0;
scoreTxt.setText('0');
bonusTxt.setText('');
// Remove all cars, obstacles, bonuses
for (var i = enemyCars.length - 1; i >= 0; i--) {
enemyCars[i].destroy();
enemyCars.splice(i, 1);
}
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
obstacles.splice(i, 1);
}
for (var i = bonuses.length - 1; i >= 0; i--) {
bonuses[i].destroy();
bonuses.splice(i, 1);
}
playerTargetLane = 1;
player.x = laneCenters[1];
player.y = 2732 - 500;
if (playerMoveTween && playerMoveTween.cancel) playerMoveTween.cancel();
player._shield = 0;
player._doubleScore = 0;
player._doubleScoreTicks = 0;
player._shrinkTicks = 0;
player._invincible = 0;
player._invincibleTicks = 0;
player._magnetTicks = 0;
player.scaleX = player.scaleY = 0.55;
player.width = player._carAsset.width * 0.55;
player.height = player._carAsset.height * 0.55;
game._slowmoTicks = 0;
game._reverseTicks = 0;
gameSpeed = 18;
ticksSinceStart = 0;
lastSpawnTick = 0;
lastBonusTick = 0;
game._spawnInterval = 36; // Easy stage spawn interval
});
// Prevent player from moving into top left menu area
// (handled by roadLeft, but double check)
if (roadLeft < 100) {
roadLeft = 100;
roadWidth = roadRight - roadLeft;
laneWidth = roadWidth / laneCount;
for (var i = 0; i < laneCount; i++) {
laneCenters[i] = roadLeft + laneWidth / 2 + i * laneWidth;
}
}
// Play background music and engine idle at game start
LK.on('gameStart', function () {
LK.playMusic('bgmusic');
LK.getSound('engine_idle').play();
}); ===================================================================
--- original.js
+++ change.js
@@ -327,10 +327,12 @@
LK.gui.top.addChild(scoreTxt);
// Bonus score
var bonusScore = 0;
var bonusTxt = new Text2('', {
- size: 70,
- fill: 0xFFFA00 // Bright yellow for high visibility
+ size: 80,
+ fill: 0xFFFA00,
+ // Bright yellow for high visibility
+ font: "bold 900 80px Arial, 'GillSans-Bold', Impact, 'Arial Black', Tahoma" // Extra bold
});
bonusTxt.anchor.set(0.5, 0);
// Move the bonus text further down (e.g. 180px from the top)
bonusTxt.y = 180;
@@ -756,9 +758,9 @@
if (b.type === 'shield') {
player._shield = 1;
LK.getSound('shield').play();
LK.effects.flashObject(player, 0x42a5f5, 600);
- bonusTxt.setText("SHIELD! (Shield Bonus)");
+ bonusTxt.setText("🛡️ <b>SHIELD!</b> (Shield Bonus)");
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
@@ -775,9 +777,9 @@
player._doubleScore = 1;
player._doubleScoreTicks = 600; // 10 seconds at 60fps
LK.getSound('double').play();
LK.effects.flashObject(player, 0xffd600, 600);
- bonusTxt.setText("x2 SCORE! (Double Score Bonus)");
+ bonusTxt.setText("✨ <b>x2 SCORE!</b> (Double Score Bonus)");
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
@@ -796,9 +798,9 @@
game._origGameSpeed = gameSpeed;
gameSpeed = Math.max(8, Math.floor(gameSpeed / 2));
game._slowmoTicks = 360;
LK.getSound('slowmo').play();
- bonusTxt.setText("SLOW-MO! (Everything slows down)");
+ bonusTxt.setText("🐢 <b>SLOW-MO!</b> (Everything slows down)");
LK.effects.flashObject(player, 0x80cbc4, 600);
(function () {
var t = bonusTxt;
t.alpha = 1;
@@ -820,9 +822,9 @@
player.scaleX = player.scaleY = 0.35;
player.width = player._carAsset.width * 0.35;
player.height = player._carAsset.height * 0.35;
LK.getSound('shrink').play();
- bonusTxt.setText("SHRINK! (Tiny car!)");
+ bonusTxt.setText("🔎 <b>SHRINK!</b> (Tiny car!)");
LK.effects.flashObject(player, 0xf48fb1, 600);
(function () {
var t = bonusTxt;
t.alpha = 1;
@@ -841,9 +843,9 @@
// Invincible for 7 seconds
player._invincible = 1;
player._invincibleTicks = 420;
LK.getSound('invincible').play();
- bonusTxt.setText("INVINCIBLE! (Can't crash!)");
+ bonusTxt.setText("💥 <b>INVINCIBLE!</b> (Can't crash!)");
LK.effects.flashObject(player, 0xFFD700, 600);
(function () {
var t = bonusTxt;
t.alpha = 1;
@@ -868,9 +870,9 @@
newLane = Math.floor(Math.random() * laneCenters.length);
}
player.x = laneCenters[newLane];
LK.getSound('teleport').play();
- bonusTxt.setText("TELEPORT! (Random lane)");
+ bonusTxt.setText("🌀 <b>TELEPORT!</b> (Random lane)");
LK.effects.flashObject(player, 0x4fc3f7, 600);
(function () {
var t = bonusTxt;
t.alpha = 1;
@@ -894,9 +896,9 @@
obstacles[oi].destroy();
obstacles.splice(oi, 1);
}
LK.getSound('clear').play();
- bonusTxt.setText("CLEAR! (All obstacles gone)");
+ bonusTxt.setText("🧹 <b>CLEAR!</b> (All obstacles gone)");
LK.effects.flashObject(player, 0x81d4fa, 600);
(function () {
var t = bonusTxt;
t.alpha = 1;
@@ -913,9 +915,9 @@
} else if (b.type === 'magnet') {
// Magnet: attract bonuses for 8 seconds
player._magnetTicks = 480;
LK.getSound('magnet').play();
- bonusTxt.setText("MAGNET! (Bonuses come to you)");
+ bonusTxt.setText("🧲 <b>MAGNET!</b> (Bonuses come to you)");
LK.effects.flashObject(player, 0xff8a65, 600);
(function () {
var t = bonusTxt;
t.alpha = 1;
@@ -932,9 +934,9 @@
} else if (b.type === 'reverse') {
// Reverse: enemies move up for 5 seconds
game._reverseTicks = 300;
LK.getSound('reverse').play();
- bonusTxt.setText("REVERSE! (Enemies go up!)");
+ bonusTxt.setText("🔄 <b>REVERSE!</b> (Enemies go up!)");
LK.effects.flashObject(player, 0xba68c8, 600);
(function () {
var t = bonusTxt;
t.alpha = 1;
@@ -962,9 +964,9 @@
bonusScore += addScore;
score += addScore;
LK.getSound('bonus').play();
LK.effects.flashObject(player, 0x43a047, 400);
- bonusTxt.setText("+" + addScore + "! (Bonus " + b.type.replace('score', '') + ")");
+ bonusTxt.setText("🎁 <b>+" + addScore + "!</b> (Bonus " + b.type.replace('score', '') + ")");
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
@@ -984,9 +986,9 @@
bonusScore += addScore;
score += addScore;
LK.getSound('bonus').play();
LK.effects.flashObject(player, 0x43a047, 400);
- bonusTxt.setText("+" + addScore + "! (Score Bonus)");
+ bonusTxt.setText("🎁 <b>+" + addScore + "!</b> (Score Bonus)");
(function () {
var t = bonusTxt;
t.alpha = 1;
tween(t, {
bonus. In-Game asset. 2d. High contrast. No shadows
obstackle. In-Game asset. 2d. High contrast. No shadows
Rear and top view of cool luxury sports car looking upwards. In-Game asset. 2d. High contrast. No shadows
top view of plant looking upwards. In-Game asset. 2d. High contrast. No shadows
Top view of colorful yellow plant looking upwards. In-Game asset. 2d. High contrast. No shadows
Top view of colorful pink plant looking upwards. In-Game asset. 2d. High contrast. No shadows
Top view of colorful pink tree looking upwards. In-Game asset. 2d. High contrast. No shadows
Top view of colorful tree looking upwards. In-Game asset. 2d. High contrast. No shadows
hearth red. In-Game asset. 2d. High contrast. No shadows
cool luxury sports car bumper view looking up. In-Game asset. 2d. High contrast. No shadows