User prompt
Make the speed boost red
User prompt
Locate the speed boost badge in the right side of the screen at the middle
User prompt
Add a badge when reach 500, make it a token the user can activate to slow the road for 30sec. Appear on screen โช๐ก Consider importing and using the following plugins: @upit/tween.v1
User prompt
Show the badge on the screen when reach 500 points and let the user activate it for slow mode for 30 seconds
User prompt
Add a badge when reach 500, make it a token the user can activate to slow the road for 30sec
User prompt
Remove the girl clapping
User prompt
Change the position of the gir at the end to center down
User prompt
Enhance winning animation and girl positioning
User prompt
Make a reflect in the front of the car that look like faded lights using a gradient
User prompt
Make te car lights yellow โช๐ก Consider importing and using the following plugins: @upit/tween.v1
User prompt
Relocate victory animation girl to the bottom right corner of the screen
User prompt
Relocate the girl at the end
User prompt
Relocate victory animation girl to the bottom right corner when winning
User prompt
Relocate victory animation girl to bottom right corner when winning
User prompt
Relocate girl clapping at the end
User prompt
Relocate girl clapping when winning
User prompt
Make the trees to be pink in japan and yellow in the beach
User prompt
Make the trees color PINK in japan environment โช๐ก Consider importing and using the following plugins: @upit/tween.v1
User prompt
Update japan environment and make trees pink
User prompt
In the beach level, please change the trees to palm trees, and in the japan just make them pink
User prompt
Enhance win animation and add effects also position the girl in the bottom right of the screen
User prompt
Enhance win animation add neon confetti and place girl in the bottom of the screen
User prompt
Change the position of the girl clapping to bottom right pf the screen when winning
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'self.message.style.fill = 0xFF00FF')' in or related to this line: 'self.message.style.fill = 0xFF00FF; // Pink' Line Number: 1066
User prompt
Please fix the bug: 'TypeError: undefined is not an object (evaluating 'self.message.style.fill = 0xFF00FF')' in or related to this line: 'self.message.style.fill = 0xFF00FF; // Pink' Line Number: 1065
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Badge = Container.expand(function () {
var self = Container.call(this);
// Create badge icon
var badgeGraphic = self.attachAsset('scoreEffect', {
anchorX: 0.5,
anchorY: 0.5,
width: 80,
height: 80,
tint: 0xFF0000 // Red color for badge
});
// Add a label to indicate what the badge does
var labelText = self.addChild(new Text2("SPEED BOOST", {
size: 20,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
}));
labelText.anchor.set(0.5, 0.5);
labelText.y = 60;
// Add a timer display
var timerText = self.addChild(new Text2("", {
size: 24,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3
}));
timerText.anchor.set(0.5, 0.5);
timerText.y = -60;
timerText.visible = false;
self.earned = false; // Whether badge has been earned
self.active = false;
self.timerSeconds = 30;
self.pulseDirection = 1;
self.originalScale = 1;
self.visible = false;
// Animation for when badge is first earned
self.showEarned = function () {
self.earned = true;
self.visible = true;
self.scale.set(0.1);
self.alpha = 0;
// Appear with a bounce effect
tween(self, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.elasticOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
};
// Activate the badge power
self.activate = function () {
if (self.earned && !self.active) {
self.active = true;
speedMultiplier = 0.5; // Slow down the road
timerText.visible = true;
// Visual feedback - flash effect
LK.effects.flashScreen(0xFFD700, 300);
// Start countdown
self.timerSeconds = 30;
timerText.setText(self.timerSeconds);
// Start timer to count down and update display
var timerInterval = LK.setInterval(function () {
self.timerSeconds--;
timerText.setText(self.timerSeconds);
if (self.timerSeconds <= 0) {
LK.clearInterval(timerInterval);
}
}, 1000);
// Reset after 30 seconds
LK.setTimeout(function () {
speedMultiplier = 1; // Reset speed after 30 seconds
self.active = false;
timerText.visible = false;
// Flash when effect ends
LK.effects.flashScreen(0x87CEEB, 300);
}, 30000);
}
};
// Update to pulse the badge when available
self.update = function () {
if (self.earned && !self.active) {
// Pulse effect when ready to use
if (self.pulseDirection > 0) {
self.scale.x += 0.005;
self.scale.y += 0.005;
if (self.scale.x >= 1.1) {
self.pulseDirection = -1;
}
} else {
self.scale.x -= 0.005;
self.scale.y -= 0.005;
if (self.scale.x <= 0.9) {
self.pulseDirection = 1;
}
}
} else if (self.active) {
// Rotate slightly when active
self.rotation += 0.01;
}
};
return self;
});
var Building = Container.expand(function () {
var self = Container.call(this);
var buildingGraphics = self.attachAsset('building', {
anchorX: 0.5,
anchorY: 0
});
// Randomize building properties
var shade = Math.floor(Math.random() * 40) + 40;
buildingGraphics.tint = shade << 16 | shade << 8 | shade;
buildingGraphics.height = Math.random() * 600 + 400;
buildingGraphics.width = Math.random() * 100 + 100;
// Add windows to buildings for a city look
var windowCount = Math.floor(buildingGraphics.height / 80);
var windowsPerRow = Math.floor(buildingGraphics.width / 40);
for (var i = 0; i < windowCount; i++) {
for (var j = 0; j < windowsPerRow; j++) {
var windowLight = self.addChild(new Container());
var windowAsset = windowLight.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
height: 30,
tint: 0xFFFF99
});
windowLight.x = j * 40 - buildingGraphics.width / 2 + 25;
windowLight.y = i * 80 + 50;
windowLight.alpha = Math.random() > 0.3 ? 0.8 : 0;
}
}
self.speed = 10; // Default speed
self.update = function () {
self.y += self.speed;
// Reset building when it goes off screen
if (self.y > 2732 + buildingGraphics.height) {
self.y = -buildingGraphics.height;
// Determine road boundaries to keep buildings off the road
var road = null;
for (var i = 0; i < game.children.length; i++) {
if (game.children[i].asset && game.children[i].asset.id === 'road') {
road = game.children[i];
break;
}
}
// Place building only on sidewalks
var roadLeftEdge = road ? (2048 - road.width) / 2 : 424;
var roadRightEdge = road ? 2048 - (2048 - road.width) / 2 : 1624;
// Determine which side to place the building on based on its current side
if (self.x < roadLeftEdge) {
// Keep on left side
self.x = Math.random() * (roadLeftEdge - buildingGraphics.width / 2);
} else {
// Keep on right side
self.x = roadRightEdge + Math.random() * (roadLeftEdge - buildingGraphics.width / 2);
}
// Check current environment for building appearance
if (environment && environment.current === environment.BEACH) {
// Beach resort buildings - lighter colors, more variation
var r = Math.floor(Math.random() * 40) + 215; // Bright beige/white
var g = Math.floor(Math.random() * 40) + 215;
var b = Math.floor(Math.random() * 40) + 190;
buildingGraphics.tint = r << 16 | g << 8 | b;
buildingGraphics.height = Math.random() * 400 + 300; // Beach buildings are shorter
buildingGraphics.width = Math.random() * 150 + 100; // But wider
} else if (environment && environment.current === environment.JAPAN) {
// Traditional Japanese buildings - pagoda style
var shade = Math.floor(Math.random() * 40) + 40; // Dark base
// Add red tint for some buildings to simulate temples/shrines
if (Math.random() > 0.5) {
buildingGraphics.tint = shade + 150 << 16 | shade << 8 | shade;
buildingGraphics.height = Math.random() * 500 + 300; // Slightly shorter
} else {
buildingGraphics.tint = shade << 16 | shade << 8 | shade;
buildingGraphics.height = Math.random() * 400 + 200; // Low traditional houses
}
buildingGraphics.width = Math.random() * 120 + 100;
} else {
// Default city buildings
var shade = Math.floor(Math.random() * 40) + 40;
buildingGraphics.tint = shade << 16 | shade << 8 | shade;
buildingGraphics.height = Math.random() * 600 + 400;
buildingGraphics.width = Math.random() * 100 + 100;
}
// Recreate windows when building resets
self.removeChildren(1); // Keep only the main building graphic
var windowCount = Math.floor(buildingGraphics.height / 80);
var windowsPerRow = Math.floor(buildingGraphics.width / 40);
for (var i = 0; i < windowCount; i++) {
for (var j = 0; j < windowsPerRow; j++) {
var windowLight = self.addChild(new Container());
var windowAsset = windowLight.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5,
width: 20,
height: 30,
tint: 0xFFFF99
});
windowLight.x = j * 40 - buildingGraphics.width / 2 + 25;
windowLight.y = i * 80 + 50;
// Randomly light windows
windowLight.alpha = Math.random() > 0.3 ? 0.8 : 0;
}
}
}
};
return self;
});
var Car = Container.expand(function () {
var self = Container.call(this);
// Create car body - using just the car asset without additional square
var carGraphics = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x3366CC // Blue car color
});
// Add headlights
var leftHeadlight = self.addChild(new Container());
var leftHeadlightAsset = leftHeadlight.attachAsset('scoreEffect', {
anchorX: 0.5,
anchorY: 0.5,
width: 40,
height: 40,
tint: 0xFFFF00
});
leftHeadlight.x = -60;
leftHeadlight.y = -140;
var rightHeadlight = self.addChild(new Container());
var rightHeadlightAsset = rightHeadlight.attachAsset('scoreEffect', {
anchorX: 0.5,
anchorY: 0.5,
width: 40,
height: 40,
tint: 0xFFFF00
});
rightHeadlight.x = 60;
rightHeadlight.y = -140;
// Add light reflection gradient in front of the car
// Left headlight reflection
var leftReflection = self.addChild(new Container());
for (var i = 0; i < 5; i++) {
var reflectionSegment = leftReflection.attachAsset('scoreEffect', {
anchorX: 0.5,
anchorY: 0.5,
width: 30 - i * 3,
height: 25 - i * 3,
tint: 0xFFFF00,
alpha: 0.4 - i * 0.07
});
reflectionSegment.y = -i * 15;
}
leftReflection.x = -60;
leftReflection.y = -170;
// Right headlight reflection
var rightReflection = self.addChild(new Container());
for (var i = 0; i < 5; i++) {
var reflectionSegment = rightReflection.attachAsset('scoreEffect', {
anchorX: 0.5,
anchorY: 0.5,
width: 30 - i * 3,
height: 25 - i * 3,
tint: 0xFFFF00,
alpha: 0.4 - i * 0.07
});
reflectionSegment.y = -i * 15;
}
rightReflection.x = 60;
rightReflection.y = -170;
self.jumping = false;
self.jumpHeight = 100;
self.originalY = 0;
self.lastY = 0; // Track last Y position for intersection detection
self.jump = function () {
if (self.jumping) {
return;
}
self.jumping = true;
self.originalY = self.y;
// Play jump sound
LK.getSound('jump').play();
// Enhanced neon effect during jump - random bright color
var randomNeonColor = Math.random() > 0.5 ? 0xFFFFFF : 0x00FFFF;
// Create a glowing neon effect
tween(carGraphics, {
tint: randomNeonColor,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 150,
onFinish: function onFinish() {
// Return to current neon color after the flash
tween(carGraphics, {
tint: self.neonColors[self.currentColorIndex],
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 450
});
}
});
// Jump animation using tween
tween(self, {
y: self.y - self.jumpHeight
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Fall back down
tween(self, {
y: self.originalY
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
self.jumping = false;
}
});
}
});
};
self.down = function () {
self.jump();
};
// Set up neon color cycling properties
self.neonColors = [0x3366CC,
// Blue
0xFF00FF,
// Magenta
0x00FFFF,
// Cyan
0x33CC33,
// Green
0xFF6600,
// Orange
0xFFFF00,
// Yellow
0xFF3366,
// Pink
0x9900FF // Purple
];
self.currentColorIndex = 0;
self.colorTransitionTime = 0;
self.colorTransitionDuration = 60; // About 1 second at 60fps - faster color cycling
self.update = function () {
self.lastY = self.y;
// Create headlight glow effect
if (LK.ticks % 5 === 0) {
leftHeadlightAsset.alpha = 0.7 + Math.random() * 0.3;
rightHeadlightAsset.alpha = 0.7 + Math.random() * 0.3;
// Animate reflection gradient
// Loop through each reflection segment container's children
for (var i = 0; i < 5; i++) {
if (leftReflection.children[i]) {
leftReflection.children[i].alpha = (0.4 - i * 0.07) * (0.7 + Math.random() * 0.3);
}
if (rightReflection.children[i]) {
rightReflection.children[i].alpha = (0.4 - i * 0.07) * (0.7 + Math.random() * 0.3);
}
}
}
// Update neon color effect
self.colorTransitionTime++;
if (self.colorTransitionTime >= self.colorTransitionDuration) {
self.colorTransitionTime = 0;
self.currentColorIndex = (self.currentColorIndex + 1) % self.neonColors.length;
// Start transition to the next color
tween(carGraphics, {
tint: self.neonColors[self.currentColorIndex]
}, {
duration: 1000,
easing: tween.easeInOut
});
}
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
// Create the coin graphic
var coinGraphic = self.attachAsset('scoreEffect', {
anchorX: 0.5,
anchorY: 0.5,
width: 40,
height: 40,
tint: 0xFFFF00 // Bright yellow color for coins
});
// Initialize properties
self.active = false;
// Animate coin from source to destination
self.animate = function (startX, startY, destX, destY) {
self.active = true;
self.visible = true;
self.x = startX + (Math.random() * 120 - 60);
self.y = startY + (Math.random() * 120 - 60);
self.alpha = 0;
self.rotation = Math.random() * Math.PI;
self.scale.set(1);
// Duration and timing variables
var duration = 500 + Math.random() * 200;
// First make the coin appear with a quick flash
tween(self, {
alpha: 1.0,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 60,
onFinish: function onFinish() {
// Add a spin to the coins as they move
self.rotation = Math.random() * Math.PI * 2;
// Small initial burst to create a more dynamic feel
tween(self, {
y: self.y - 50 - Math.random() * 70,
x: self.x + (Math.random() * 100 - 50),
alpha: 1.0,
rotation: self.rotation + Math.PI * (Math.random() > 0.5 ? 1 : -1)
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Now move directly to the score with arc path
tween(self, {
x: destX,
y: destY,
scaleX: 0.3,
scaleY: 0.3,
rotation: self.rotation + Math.PI * 2,
alpha: 0
}, {
duration: duration,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Flash the score text
tween(scoreText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(scoreText, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
}
});
// Reset coin
self.active = false;
self.visible = false;
}
});
}
});
}
});
};
return self;
});
var Environment = Container.expand(function () {
var self = Container.call(this);
// Environment types
self.CITY = 0;
self.BEACH = 1;
self.JAPAN = 2;
// Current environment
self.current = self.CITY;
// Assets for each environment
self.roadColors = [0x444444, 0xD2B48C, 0x8B4513]; // City, Beach, Japan
self.sidewalkColors = [0x999999, 0xF5DEB3, 0x7D8570]; // City, Beach, Japan
self.skyColors = [0x87CEEB, 0x87CEEB, 0xE0FFFF]; // City, Beach, Japan
// Change environment based on score
self.update = function (score) {
var newEnvironment = self.current;
// Determine environment based on score
if (score >= 700) {
newEnvironment = self.JAPAN;
} else if (score >= 350) {
newEnvironment = self.BEACH;
} else {
newEnvironment = self.CITY;
}
// Only update if environment changed
if (newEnvironment !== self.current) {
self.current = newEnvironment;
return true;
}
return false;
};
// Apply environment changes
self.apply = function (road, leftSidewalk, rightSidewalk, game) {
// Update colors based on current environment
road.tint = self.roadColors[self.current];
leftSidewalk.tint = self.sidewalkColors[self.current];
rightSidewalk.tint = self.sidewalkColors[self.current];
// Update sky color
game.setBackgroundColor(self.skyColors[self.current]);
// Apply special transition effect
LK.effects.flashScreen(0xFFFFFF, 500);
// Return message to display for level change
if (self.current === self.BEACH) {
return "BEACH LEVEL UNLOCKED!";
} else if (self.current === self.JAPAN) {
return "JAPAN LEVEL UNLOCKED!";
}
return "";
};
return self;
});
var Line = Container.expand(function () {
var self = Container.call(this);
// Create road line marking
var lineGraphics = self.attachAsset('line', {
anchorX: 0.5,
anchorY: 0.5
});
// Make line vertical
lineGraphics.rotation = Math.PI / 2; // Rotate 90 degrees
// Road lines have fixed width to better match car size
lineGraphics.width = 400; // Line length (now vertical)
lineGraphics.height = 60; // Line thickness (more visible)
self.lastY = 0; // Track last Y position for intersection detection
self.speed = 15; // Default speed
self.active = true; // Whether the line is active for scoring
self.scored = false; // Whether this line has been scored already
// Add visual effect to make lines more prominent
var glowEffect = self.addChild(new Container());
var glowAsset = glowEffect.attachAsset('line', {
anchorX: 0.5,
anchorY: 0.5,
width: lineGraphics.width + 20,
height: lineGraphics.height + 20,
tint: 0xFFFF00,
alpha: 0.3
});
glowAsset.rotation = Math.PI / 2;
self.update = function () {
self.lastY = self.y; // Store last position for collision detection
self.y += self.speed;
// Pulse glow effect
if (LK.ticks % 10 === 0) {
glowAsset.alpha = 0.2 + Math.random() * 0.2;
}
// Remove when off screen
if (self.y > 2732 + lineGraphics.width / 2) {
self.active = false;
}
};
return self;
});
var ScoreEffect = Container.expand(function () {
var self = Container.call(this);
var effectGraphics = self.attachAsset('scoreEffect', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.show = function (x, y, isPositive) {
self.x = x;
self.y = y;
if (!isPositive) {
effectGraphics.tint = 0xFF0000;
// Play penalty sound
LK.getSound('penalty').play();
} else {
effectGraphics.tint = 0x00FF00;
// Play point sound
LK.getSound('point').play();
}
// Animation for the effect
tween(self, {
alpha: 0,
y: y - 100
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
self.alpha = 1;
self.visible = false;
}
});
self.visible = true;
};
return self;
});
var Store = Container.expand(function () {
var self = Container.call(this);
// Create store building
var storeGraphics = self.attachAsset('building', {
anchorX: 0.5,
anchorY: 0,
width: 200,
height: 250,
tint: 0xFAE5D3 // Light beige for store
});
// Add store sign
var storeSign = self.addChild(new Container());
var storeSignAsset = storeSign.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5,
width: 180,
height: 60,
tint: 0x3498DB // Blue for store sign
});
storeSign.y = 40;
// Add store window
var storeWindow = self.addChild(new Container());
var storeWindowAsset = storeWindow.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5,
width: 120,
height: 100,
tint: 0xD6EAF8 // Light blue for window
});
storeWindow.y = 120;
// Add store door
var storeDoor = self.addChild(new Container());
var storeDoorAsset = storeDoor.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5,
width: 60,
height: 100,
tint: 0x784212 // Brown for door
});
storeDoor.y = 180;
self.speed = 10; // Default speed
self.update = function () {
self.y += self.speed;
// Reset store when it goes off screen
if (self.y > 2732 + storeGraphics.height) {
self.y = -storeGraphics.height;
// Store types based on environment
var storeTypes;
if (environment && environment.current === environment.BEACH) {
// Beach stores - surf shops, beach bars, cabanas
storeTypes = [{
building: 0xF0F8FF,
// AliceBlue
sign: 0x00BFFF,
// DeepSkyBlue
window: 0xE0FFFF // LightCyan
}, {
building: 0xFFEFD5,
// PapayaWhip
sign: 0xFF6347,
// Tomato
window: 0xFFDAB9 // PeachPuff
}, {
building: 0x40E0D0,
// Turquoise
sign: 0xFFFFFF,
// White
window: 0xAFEEEE // PaleTurquoise
}, {
building: 0xF5DEB3,
// Wheat
sign: 0x1E90FF,
// DodgerBlue
window: 0xFFF5EE // SeaShell
}];
} else if (environment && environment.current === environment.JAPAN) {
// Japanese stores - traditional shops, ramen stands, markets
storeTypes = [{
building: 0x8B4513,
// SaddleBrown (wood)
sign: 0xFF0000,
// Red
window: 0xFFD700 // Gold
}, {
building: 0xFFF5EE,
// SeaShell (white paper walls)
sign: 0x000000,
// Black
window: 0xFFF8DC // Cornsilk
}, {
building: 0x2F4F4F,
// DarkSlateGray
sign: 0xDC143C,
// Crimson
window: 0xF0FFF0 // Honeydew
}, {
building: 0xCD853F,
// Peru (wood)
sign: 0x4682B4,
// SteelBlue
window: 0xF5F5DC // Beige
}];
} else {
// Default city stores
storeTypes = [{
building: 0xFAE5D3,
sign: 0x3498DB,
window: 0xD6EAF8
},
// Blue store
{
building: 0xFCF3CF,
sign: 0xE74C3C,
window: 0xFADBD8
},
// Red store
{
building: 0xD5F5E3,
sign: 0x8E44AD,
window: 0xEBDEF0
},
// Purple store
{
building: 0xEAEDED,
sign: 0xF39C12,
window: 0xFAE5D3
} // Orange store
];
}
var type = storeTypes[Math.floor(Math.random() * storeTypes.length)];
storeGraphics.tint = type.building;
storeSignAsset.tint = type.sign;
storeWindowAsset.tint = type.window;
// Vary store size slightly
var sizeVar = 0.8 + Math.random() * 0.4;
storeGraphics.width = 200 * sizeVar;
storeGraphics.height = 250 * sizeVar;
storeSign.scale.set(sizeVar);
storeWindow.scale.set(sizeVar);
storeDoor.scale.set(sizeVar);
// Adjust positions based on new size
storeSign.y = 40 * sizeVar;
storeWindow.y = 120 * sizeVar;
storeDoor.y = 180 * sizeVar;
}
};
return self;
});
var StreetLight = Container.expand(function () {
var self = Container.call(this);
// Create pole
var pole = self.addChild(new Container());
var poleAsset = pole.attachAsset('building', {
anchorX: 0.5,
anchorY: 1.0,
width: 20,
height: 200,
tint: 0x555555 // Dark gray for pole
});
// Create light
var light = self.addChild(new Container());
var lightAsset = light.attachAsset('scoreEffect', {
anchorX: 0.5,
anchorY: 0.5,
width: 40,
height: 40,
tint: 0xFFFF99 // Yellow light
});
light.y = -200;
// Light arm
var arm = self.addChild(new Container());
var armAsset = arm.attachAsset('building', {
anchorX: 0,
anchorY: 0.5,
width: 40,
height: 10,
tint: 0x555555 // Dark gray for arm
});
arm.y = -190;
self.speed = 10; // Default speed
self.isLit = Math.random() > 0.2; // Most lights are on
self.update = function () {
self.y += self.speed;
// Make light flicker occasionally
if (self.isLit && LK.ticks % 20 === 0 && Math.random() > 0.7) {
lightAsset.alpha = 0.6 + Math.random() * 0.4;
}
// Reset light when it goes off screen
if (self.y > 2732 + 200) {
self.y = -200;
self.isLit = Math.random() > 0.2;
lightAsset.alpha = self.isLit ? 1 : 0.2;
}
};
return self;
});
var TapEffect = Container.expand(function () {
var self = Container.call(this);
var effectGraphics = self.attachAsset('scoreEffect', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 300,
alpha: 0.6
});
self.show = function (x, y, isPositive) {
self.x = x;
self.y = y;
// Set color based on whether it's a positive or negative tap
if (isPositive) {
effectGraphics.tint = 0x00FF00; // Green for good taps
// Play point sound with lower volume to avoid overwhelming
LK.getSound('point').play({
volume: 0.3
});
// Trigger coin effects separately - they're now handled in the game code
} else {
effectGraphics.tint = 0xFF0000; // Red for bad taps
// Play penalty sound with lower volume to avoid overwhelming
LK.getSound('penalty').play({
volume: 0.3
});
}
// Reset properties before animation
self.alpha = 1;
effectGraphics.alpha = 0.6;
effectGraphics.scale.x = 0.5;
effectGraphics.scale.y = 0.5;
self.visible = true;
// Animate the effect - expand and fade out for a nice ripple effect
tween(effectGraphics, {
alpha: 0,
scaleX: 2.5,
scaleY: 2.5
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
self.visible = false;
effectGraphics.scale.x = 0.5;
effectGraphics.scale.y = 0.5;
}
});
};
return self;
});
var Tree = Container.expand(function () {
var self = Container.call(this);
// Create tree trunk
var trunk = self.addChild(new Container());
var trunkAsset = trunk.attachAsset('building', {
anchorX: 0.5,
anchorY: 1.0,
width: 40,
height: 120,
tint: 0x8B4513 // Brown color for trunk
});
// Create tree foliage (multiple layers for depth)
var foliage1 = self.addChild(new Container());
var foliageAsset1 = foliage1.attachAsset('scoreEffect', {
anchorX: 0.5,
anchorY: 0.8,
width: 150,
height: 150,
tint: 0x228B22 // Forest green
});
foliage1.y = -80;
var foliage2 = self.addChild(new Container());
var foliageAsset2 = foliage2.attachAsset('scoreEffect', {
anchorX: 0.5,
anchorY: 0.7,
width: 120,
height: 120,
tint: 0x32CD32 // Lime green for highlight
});
foliage2.y = -100;
self.speed = 10; // Default speed
self.update = function () {
self.y += self.speed;
// Reset tree when it goes off screen
if (self.y > 2732 + 150) {
self.y = -150;
// Randomize tree appearance when resetting
trunkAsset.height = 80 + Math.random() * 80;
trunkAsset.width = 30 + Math.random() * 20;
var scale = 0.8 + Math.random() * 0.5;
foliage1.scale.set(scale);
foliage2.scale.set(scale * 0.9);
// Check current environment for tree appearance
if (environment && environment.current === environment.BEACH) {
// Palm trees for beach
trunkAsset.tint = 0xA0522D; // Brown trunk for palm trees
trunkAsset.height *= 1.5; // Make palm tree trunks much taller
trunkAsset.width *= 0.7; // Make palm tree trunks thinner
// Change foliage shape and color for palm trees
foliageAsset1.width = 200; // Wider palm fronds
foliageAsset1.height = 120; // Shorter palm fronds
foliageAsset1.tint = 0xFFFF00; // Yellow palm fronds
foliageAsset2.width = 220; // Even wider top fronds
foliageAsset2.height = 100; // Shorter top fronds
foliageAsset2.tint = 0xFFFF80; // Lighter yellow for highlights
// Position foliage to look like palm fronds
foliage1.y = -150; // Raise fronds higher for palm tree appearance
foliage2.y = -170; // Raise top fronds even higher
} else if (environment && environment.current === environment.JAPAN) {
// Cherry blossom trees (sakura)
trunkAsset.tint = 0x8B4513; // Brown trunk
// More vibrant pink cherry blossoms
foliageAsset1.width = 170; // Wider, fuller cherry blossom shape
foliageAsset1.height = 170; // Rounder for blossom shape
// Pure pink color for cherry blossoms
foliageAsset1.tint = 0xFF00FF; // Bright pink cherry blossoms
// Lighter pink for highlights
foliageAsset2.width = 140; // Slightly smaller top layer
foliageAsset2.height = 140; // Rounder for blossom shape
foliageAsset2.tint = 0xFF80FF; // Lighter pink highlights
// Position foliage to look more like cherry blossom
foliage1.y = -100; // Position for traditional cherry blossom tree shape
foliage2.y = -120; // Position for traditional cherry blossom tree shape
} else {
// Default city trees
var greenVariation = Math.floor(Math.random() * 40);
foliageAsset1.tint = 34 + greenVariation << 16 | 139 + greenVariation << 8 | 34;
foliageAsset2.tint = 50 + greenVariation << 16 | 205 + greenVariation << 8 | 50;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var car;
var lines = [];
var buildings = [];
var trees = [];
var stores = [];
var streetLights = [];
var score = 0;
var scoreText;
var speedMultiplier = 1;
var lineSpawnRate = 60; // Frames between line spawns
var difficulty = 1;
var isGameActive = true;
var scoreEffects = [];
var tapEffects = [];
var coins = []; // Pool of coin objects
var effectIndex = 0;
var tapEffectIndex = 0;
var coinIndex = 0;
var lastJumpScore = 0;
var badge;
var environment;
var levelText;
var levelTextTimer = 0;
// Create a sky background
game.setBackgroundColor(0x87CEEB); // Light blue sky
// Initialize the road
var road = game.addChild(LK.getAsset('road', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
width: 1200,
// Make the road narrower than the full width
tint: 0x444444 // Darker gray for asphalt
}));
// Add road edges/sidewalks
var leftSidewalk = game.addChild(LK.getAsset('building', {
anchorX: 0,
anchorY: 0.5,
width: (2048 - road.width) / 2,
height: 2732,
x: 0,
y: 2732 / 2,
tint: 0x999999 // Light gray for sidewalk
}));
var rightSidewalk = game.addChild(LK.getAsset('building', {
anchorX: 1,
anchorY: 0.5,
width: (2048 - road.width) / 2,
height: 2732,
x: 2048,
y: 2732 / 2,
tint: 0x999999 // Light gray for sidewalk
}));
// Initialize score display
scoreText = new Text2('SCORE: 0', {
size: 80,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 5
});
scoreText.anchor.set(0.5, 0);
scoreText.y = 50; // Move down slightly from top
LK.gui.top.addChild(scoreText);
// Initialize level transition text
levelText = new Text2('', {
size: 100,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 8,
fontWeight: 'bold'
});
levelText.anchor.set(0.5, 0.5);
levelText.visible = false;
LK.gui.center.addChild(levelText);
// Initialize environment
environment = new Environment();
// Add game instructions
var instructionsText = new Text2('Tap when no lines\nAvoid tapping on lines\nScore 1000 to win', {
size: 70,
fill: 0xFFFFFF,
stroke: 0x800080,
strokeThickness: 10,
fontWeight: 'bold',
align: 'center'
});
instructionsText.anchor.set(0.5, 0);
instructionsText.y = 150;
LK.gui.top.addChild(instructionsText);
// Create buildings for city skyline on both sides of the road (not on the road)
for (var i = 0; i < 20; i++) {
var building = new Building();
// Position buildings only on the sides, ensuring they stay off the road
var roadLeftEdge = (2048 - road.width) / 2;
var roadRightEdge = 2048 - roadLeftEdge;
if (i % 2 === 0) {
// Left side only - ensure buildings stay completely on sidewalk
var buildingWidth = building.children[0].width;
building.x = Math.random() * (roadLeftEdge - buildingWidth / 2); // Left side only, accounting for building width
} else {
// Right side only - ensure buildings stay completely on sidewalk
var buildingWidth = building.children[0].width;
building.x = roadRightEdge + Math.random() * (roadLeftEdge - buildingWidth / 2); // Right side only
}
building.y = Math.random() * 2732;
buildings.push(building);
game.addChild(building);
}
// Add trees along the road
var trees = [];
for (var i = 0; i < 15; i++) {
var tree = new Tree();
// Position trees on the sidewalks
if (i % 2 === 0) {
// Left side trees - further from road than buildings
tree.x = (2048 - road.width) / 2 - 250 - Math.random() * 60;
} else {
// Right side trees - further from road than buildings
tree.x = 2048 - (2048 - road.width) / 2 + 250 + Math.random() * 60;
}
// Distribute trees along the road
tree.y = -150 + i * 350 + Math.random() * 200;
trees.push(tree);
game.addChild(tree);
}
// Add stores on the sides
var stores = [];
for (var i = 0; i < 8; i++) {
var store = new Store();
// Position stores on the sidewalks, further from the road than trees
if (i % 2 === 0) {
// Left side stores
store.x = (2048 - road.width) / 4;
} else {
// Right side stores
store.x = 2048 - (2048 - road.width) / 4;
}
// Distribute stores along the road with some spacing
store.y = -300 + i * 650 + Math.random() * 300;
stores.push(store);
game.addChild(store);
}
// Add street lights
var streetLights = [];
for (var i = 0; i < 12; i++) {
var light = new StreetLight();
// Position lights on the edge of the road
if (i % 2 === 0) {
// Left side lights
light.x = (2048 - road.width) / 2 - 20;
} else {
// Right side lights
light.x = 2048 - (2048 - road.width) / 2 + 20;
}
// Distribute lights evenly
light.y = -200 + i * 400 + i % 2 * 200;
streetLights.push(light);
game.addChild(light);
}
// Create car
car = new Car();
car.x = 2048 / 2;
car.y = 2732 - 400;
game.addChild(car);
// Bring car to front to make sure it appears on top of lines
game.setChildIndex(car, game.children.length - 1);
// Create badge
badge = new Badge();
badge.x = 2048 - 150; // Position on the right side of screen
badge.y = 2732 / 2; // Position in the middle vertically
badge.visible = false; // Hidden until earned
badge.scale.set(0); // Start with zero scale
game.addChild(badge);
for (var i = 0; i < 5; i++) {
var effect = new ScoreEffect();
effect.visible = false;
scoreEffects.push(effect);
game.addChild(effect);
}
// Create tap effects pool - increased size to handle multiple effects
for (var i = 0; i < 10; i++) {
var tapEffect = new TapEffect();
tapEffect.visible = false;
tapEffects.push(tapEffect);
game.addChild(tapEffect);
}
// Create coin effects pool
for (var i = 0; i < 15; i++) {
var coin = new Coin();
coin.visible = false;
coin.active = false;
coins.push(coin);
game.addChild(coin);
}
// Game click handler
game.down = function (x, y, obj) {
if (!isGameActive) {
return;
}
// Check if we clicked on the badge
if (badge.earned && !badge.active && x >= badge.x - badge.width / 2 && x <= badge.x + badge.width / 2 && y >= badge.y - badge.height / 2 && y <= badge.y + badge.height / 2) {
badge.activate();
return;
}
// Check if car is already jumping
if (!car.jumping) {
car.jump();
// Check if car is over a road line
var overLine = false;
for (var i = 0; i < lines.length; i++) {
// Check if the car intersects with any vertical road line
if (lines[i].active && car.intersects(lines[i])) {
overLine = true;
break;
}
}
// Score or penalty based on jump
if (overLine) {
// Penalty for jumping over a line
score = Math.max(0, score - 10);
// Show penalty effect
var effect = scoreEffects[effectIndex];
effectIndex = (effectIndex + 1) % scoreEffects.length;
effect.show(car.x, car.y - 50, false);
// Show tap feedback effect (red for penalty)
var tapEffect = tapEffects[tapEffectIndex];
tapEffectIndex = (tapEffectIndex + 1) % tapEffects.length;
tapEffect.show(x, y, false);
// Add multiple red effects for stronger visual feedback
for (var j = 0; j < 2; j++) {
var extraEffect = tapEffects[tapEffectIndex];
tapEffectIndex = (tapEffectIndex + 1) % tapEffects.length;
extraEffect.show(x + (Math.random() * 100 - 50), y + (Math.random() * 100 - 50), false);
}
// Flash screen red for bad tap
LK.effects.flashScreen(0xff0000, 300);
} else {
// Points for jumping on empty road
var pointsGained = 20 * difficulty;
score += pointsGained;
lastJumpScore = pointsGained;
// Show score effect
var effect = scoreEffects[effectIndex];
effectIndex = (effectIndex + 1) % scoreEffects.length;
effect.show(car.x, car.y - 50, true);
// Show tap feedback effect (green for points)
var tapEffect = tapEffects[tapEffectIndex];
tapEffectIndex = (tapEffectIndex + 1) % tapEffects.length;
tapEffect.show(x, y, true);
// Add multiple green effects for stronger visual feedback
for (var j = 0; j < 2; j++) {
var extraEffect = tapEffects[tapEffectIndex];
tapEffectIndex = (tapEffectIndex + 1) % tapEffects.length;
extraEffect.show(x + (Math.random() * 100 - 50), y + (Math.random() * 100 - 50), true);
}
// Create coin animation effects
var coinCount = 3 + Math.floor(Math.random() * 3); // 3-5 coins
for (var i = 0; i < coinCount; i++) {
// Get a coin from the pool
var coin = coins[coinIndex];
coinIndex = (coinIndex + 1) % coins.length;
// Only animate if not currently active
if (!coin.active) {
// Set destination coordinates (score text position)
var destX = 2048 / 2; // Center of screen where the score is
var destY = 50; // Near the top where the score is
// Animate the coin
coin.animate(x, y, destX, destY);
}
}
}
// Update score display
scoreText.setText(Math.round(score));
LK.setScore(Math.round(score));
}
};
// Start background music
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 0.4,
duration: 1000
}
});
// Game update function
game.update = function () {
if (!isGameActive) {
return;
}
// Update badge
badge.update();
// Update car
car.update();
// Update all lines
for (var i = lines.length - 1; i >= 0; i--) {
lines[i].update();
// We don't penalize for just passing over a line anymore
// Only interactions happen when player taps
if (!lines[i].scored && lines[i].lastY < car.y && lines[i].y >= car.y) {
lines[i].scored = true; // Mark as scored
}
// Remove inactive lines
if (!lines[i].active) {
lines[i].destroy();
lines.splice(i, 1);
}
}
// Update all buildings
for (var i = 0; i < buildings.length; i++) {
buildings[i].speed = 5 * speedMultiplier;
buildings[i].update();
}
// Update all trees
for (var i = 0; i < trees.length; i++) {
trees[i].speed = 5 * speedMultiplier; // Changed from 7 to 5 to match building speed
trees[i].update();
}
// Update all stores
for (var i = 0; i < stores.length; i++) {
stores[i].speed = 5 * speedMultiplier;
stores[i].update();
}
// Update all street lights
for (var i = 0; i < streetLights.length; i++) {
streetLights[i].speed = 5 * speedMultiplier; // Changed from 7 to 5 to match building speed
streetLights[i].update();
}
// Create new lines at intervals - always come from center of the screen
if (LK.ticks % Math.floor(lineSpawnRate / speedMultiplier) === 0) {
var line = new Line();
// Position line at the center of the screen
line.x = 2048 / 2; // Center X coordinate
line.y = -50;
line.speed = 15 * speedMultiplier;
lines.push(line);
game.addChild(line);
// Ensure car is always rendered on top of lines
game.setChildIndex(car, game.children.length - 1);
}
// Increase difficulty over time
if (LK.ticks % 600 === 0) {
// Every 10 seconds
difficulty += 0.1;
// Speed up game after 500 points, but not too much, and slow down a bit after 800
if (score > 800) {
// Cap the speedMultiplier to prevent game from becoming too fast
speedMultiplier = Math.min(1.6, 1 + (difficulty - 1) * 0.6); // Further reduced speed cap
lineSpawnRate = Math.max(30, 45 - difficulty * 1.5); // More forgiving line spawn rate
} else if (score > 500) {
// Cap the speedMultiplier to prevent game from becoming too fast
speedMultiplier = Math.min(1.5, 1 + (difficulty - 1) * 0.7); // Lower speed cap
lineSpawnRate = Math.max(25, 40 - difficulty * 2); // More moderate increase in line spawn rate
} else {
speedMultiplier = 1 + (difficulty - 1) * 0.5;
lineSpawnRate = Math.max(15, 60 - difficulty * 5);
}
}
// Check if score has reached 500 to give badge
if (score >= 500 && !badge.earned) {
badge.showEarned();
// Create notification text
var badgeNotification = new Text2("SPEED BOOST UNLOCKED!", {
size: 80,
fill: 0xFFD700,
stroke: 0x000000,
strokeThickness: 6
});
badgeNotification.anchor.set(0.5, 0.5);
LK.gui.center.addChild(badgeNotification);
// Animate notification
tween(badgeNotification, {
alpha: 0,
y: badgeNotification.y - 100
}, {
duration: 2000,
onFinish: function onFinish() {
badgeNotification.destroy();
}
});
}
// Handle environment transitions based on score
if (environment.update(Math.round(score))) {
var message = environment.apply(road, leftSidewalk, rightSidewalk, game);
// Show level transition message
if (message) {
levelText.setText(message);
levelText.visible = true;
levelTextTimer = 120; // Show for 2 seconds (120 frames)
// Update car and environment elements based on the theme
if (environment.current === environment.BEACH) {
// Beach theme colors for buildings and objects
for (var i = 0; i < buildings.length; i++) {
var building = buildings[i];
if (building.children && building.children[0]) {
var shade = Math.floor(Math.random() * 30) + 220; // Lighter buildings for beach
building.children[0].tint = shade << 16 | shade << 8 | shade;
}
}
} else if (environment.current === environment.JAPAN) {
// Japan theme colors for buildings and objects
for (var i = 0; i < buildings.length; i++) {
var building = buildings[i];
if (building.children && building.children[0]) {
// Reddish pagoda style buildings
var red = Math.floor(Math.random() * 55) + 200;
var green = Math.floor(red * 0.5);
var blue = Math.floor(green * 0.5);
building.children[0].tint = red << 16 | green << 8 | blue;
}
}
}
}
}
// Update level transition text timer
if (levelTextTimer > 0) {
levelTextTimer--;
if (levelTextTimer === 0) {
levelText.visible = false;
}
}
// Check for game over condition
if (score < 0) {
isGameActive = false;
LK.showGameOver();
}
// Check for win condition (1000 points to win)
if (score >= 1000) {
// Only show win screen once
if (isGameActive) {
isGameActive = false;
// Flash screen with celebration colors
LK.effects.flashScreen(0xFFD700, 400); // Gold flash
// Create coin shower effect for winning celebration
LK.setTimeout(function () {
for (var i = 0; i < 40; i++) {
var coin = coins[Math.floor(Math.random() * coins.length)];
if (!coin.active) {
// Random positions for coins
var startX = Math.random() * 2048;
var startY = -100;
var destX = Math.random() * 2048;
var destY = Math.random() * 2732;
coin.animate(startX, startY, destX, destY);
}
}
// Show win screen immediately after coin effect starts
LK.showYouWin();
}, 300);
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -14,9 +14,9 @@
anchorX: 0.5,
anchorY: 0.5,
width: 80,
height: 80,
- tint: 0xFFD700 // Gold color for badge
+ tint: 0xFF0000 // Red color for badge
});
// Add a label to indicate what the badge does
var labelText = self.addChild(new Text2("SPEED BOOST", {
size: 20,