User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return t;' Line Number: 347
User prompt
Fix the error: Uncaught TypeError caused by accessing index [0] of an undefined or null array inside KatanaSlash logic. Ensure all arrays are initialized properly before use.
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return t;' Line Number: 347
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return t;' Line Number: 338
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return t;' Line Number: 329
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return t;' Line Number: 320
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return t;' Line Number: 310
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return t;' Line Number: 288
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;' Line Number: 273
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;' Line Number: 272
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;' Line Number: 272
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;' Line Number: 271
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'if (self && typeof self.maxLife !== "undefined" && typeof self.life !== "undefined" && !isNaN(self.maxLife) && !isNaN(self.life) && self.life > self.maxLife) {' Line Number: 175
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'if (self && typeof self.maxLife !== "undefined" && self.life > self.maxLife) {' Line Number: 175
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'if (self.life > self.maxLife) {' Line Number: 175
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'if (self.life > self.maxLife) {' Line Number: 175
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'if (self.life > self.maxLife) {' Line Number: 175
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'if (self.life > self.maxLife) {' Line Number: 175
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'if (self.life > self.maxLife) {' Line Number: 175
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'if (self.life > self.maxLife) {' Line Number: 168
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'if (self.life > self.maxLife) {' Line Number: 161
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'if (self.life > self.maxLife) {' Line Number: 154
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'if (self.life > self.maxLife) {' Line Number: 155
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'if (self.life > self.maxLife) {' Line Number: 148
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'if (self.life > self.maxLife) {' Line Number: 141
/****
* Classes
****/
// EnemyBike class: faster enemy type
var EnemyBike = Container.expand(function () {
var self = Container.call(this);
// Attach enemyBike asset (image, facing upward)
var bike = self.attachAsset('enemyBike', {
anchorX: 0.5,
anchorY: 0.5
});
// Set vertical speed (will be set on spawn)
self.speedY = 24;
// Track lastY for event triggers
self.lastY = self.y;
self.update = function () {
self.lastY = self.y;
self.y += self.speedY;
// EnemyBike moves straight down in its lane
};
return self;
});
// KatanaSlash class: 360-degree melee attack with visible circular slash animation
var KatanaSlash = Container.expand(function () {
var self = Container.call(this);
// Visual: large transparent ellipse to represent slash area
var slashRadius = 260; // covers close range around player
var slashAsset = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
width: slashRadius * 2,
height: slashRadius * 2
});
slashAsset.alpha = 0.35; // semi-transparent
// Tint to blueish for katana effect
slashAsset.tint = 0x66ccff;
// Add a visible circular outline for the slash animation
var outline = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
width: slashRadius * 2 + 24,
height: slashRadius * 2 + 24
});
outline.alpha = 0.7;
outline.tint = 0xffffff;
outline.blendMode = "add"; // visually pop the outline if supported
// Animate the outline: scale up and fade out
outline.scaleX = 0.7;
outline.scaleY = 0.7;
// Track lifetime
self.life = 0;
self.maxLife = 18; // ~0.3s at 60fps
// Only trigger hit once per enemy per slash
if (typeof self.hitEnemies === "undefined" || !self.hitEnemies) self.hitEnemies = [];
if (typeof self.maxLife === "undefined") self.maxLife = 18;
self.update = function () {
// Defensive: ensure hitEnemies and maxLife are always defined
if (typeof self.hitEnemies === "undefined" || !self.hitEnemies) self.hitEnemies = [];
if (typeof self.maxLife === "undefined") self.maxLife = 18;
// Defensive: ensure hitEnemies and maxLife are always defined
if (typeof self.hitEnemies === "undefined" || !self.hitEnemies) self.hitEnemies = [];
if (typeof self.maxLife === "undefined") self.maxLife = 18;
// Defensive: ensure hitEnemies and maxLife are always defined at the top of update
if (typeof self.hitEnemies === "undefined" || !self.hitEnemies) self.hitEnemies = [];
if (typeof self.maxLife === "undefined") self.maxLife = 18;
// Defensive: ensure hitEnemies and maxLife are always defined at the top of update
if (typeof self.hitEnemies === "undefined" || !self.hitEnemies) self.hitEnemies = [];
if (typeof self.maxLife === "undefined") self.maxLife = 18;
// Defensive: ensure hitEnemies and maxLife are always defined at the top of update (for every call, every frame)
if (typeof self.hitEnemies === "undefined" || !self.hitEnemies) self.hitEnemies = [];
if (typeof self.maxLife === "undefined") self.maxLife = 18;
self.life++;
// Fade out as it ends
if (self.life > self.maxLife - 8) {
slashAsset.alpha = 0.35 * ((self.maxLife - self.life) / 8);
outline.alpha = 0.7 * ((self.maxLife - self.life) / 8);
} else {
outline.alpha = 0.7;
}
// Animate outline scale for a "slash" effect
if (self.life <= 8) {
var scale = 0.7 + 0.5 * (self.life / 8);
outline.scaleX = scale;
outline.scaleY = scale;
} else {
outline.scaleX = 1.2;
outline.scaleY = 1.2;
}
// Hit enemies in range
for (var i = enemyBikes.length - 1; i >= 0; i--) {
var eb = enemyBikes[i];
if (self.hitEnemies.indexOf(eb) === -1 && self.intersects(eb)) {
// Remove enemy on hit
eb.destroy();
enemyBikes.splice(i, 1);
self.hitEnemies.push(eb);
score += 5;
scoreTxt.setText(score);
}
}
// Hit obstacles in range
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
if (self.hitEnemies.indexOf(obs) === -1 && self.intersects(obs)) {
obs.destroy();
obstacles.splice(i, 1);
self.hitEnemies.push(obs);
score += 2;
scoreTxt.setText(score);
}
}
// Remove slash after duration
if (self.life > self.maxLife) {
self.destroy();
}
};
return self;
});
// Motorcycle class: player-controlled bike
var Motorcycle = Container.expand(function () {
var self = Container.call(this);
// Attach motorcycle asset (image, facing upward)
var bike = self.attachAsset('motorcycle', {
anchorX: 0.5,
anchorY: 0.5
});
// Set initial speed and direction
self.speedY = 18; // vertical speed (track scrolls down)
self.laneSpeed = 0; // horizontal speed (player control)
self.maxX = 2048 - bike.width / 2;
self.minX = bike.width / 2;
// Track lastX for event triggers
self.lastX = self.x;
// Update method: move forward, apply lane movement
self.update = function () {
self.lastX = self.x;
self.x += self.laneSpeed;
// Clamp to track bounds
if (self.x < self.minX) self.x = self.minX;
if (self.x > self.maxX) self.x = self.maxX;
};
return self;
});
// Obstacle class: static/dynamic hazards
var Obstacle = Container.expand(function () {
var self = Container.call(this);
// Attach obstacle asset (box, red)
var obs = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
// Set vertical speed (scrolls with track)
self.speedY = 18;
// Track lastY for event triggers
self.lastY = self.y;
self.update = function () {
self.lastY = self.y;
self.y += self.speedY;
};
return self;
});
// PowerUp class: collectible items
var PowerUp = Container.expand(function () {
var self = Container.call(this);
// Attach powerup asset (ellipse, yellow)
var pu = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedY = 18;
self.lastY = self.y;
self.update = function () {
self.lastY = self.y;
self.y += self.speedY;
};
return self;
});
/****
* Initialize Game
****/
// Motorcycle asset (blue box)
// Obstacle asset (red box)
// PowerUp asset (yellow ellipse)
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// --- Road Background ---
// Motorcycle asset (blue box)
// Obstacle asset (red box)
// PowerUp asset (yellow ellipse)
// --- Game State ---
// Road background: gray
// (punchProjectile logic removed)
var roadCenterX = 2048 / 2;
var roadBg1 = LK.getAsset('roadBg', {
anchorX: 0.5,
anchorY: 0,
width: 1200,
height: 2732,
x: roadCenterX,
y: 0
});
var roadBg2 = LK.getAsset('roadBg', {
anchorX: 0.5,
anchorY: 0,
width: 1200,
height: 2732,
x: roadCenterX,
y: -2732
});
// If the asset doesn't exist, create it as a gray box
if (!roadBg1) {
roadBg1 = LK.getAsset('roadBg', {
anchorX: 0.5,
anchorY: 0,
width: 1200,
height: 2732,
x: roadCenterX,
y: 0
});
roadBg2 = LK.getAsset('roadBg', {
anchorX: 0.5,
anchorY: 0,
width: 1200,
height: 2732,
x: roadCenterX,
y: -2732
});
}
game.addChild(roadBg1);
game.addChild(roadBg2);
// Lane definitions for 3-lane road (centered, full width 2048)
var laneCount = 3;
var laneWidth = 400;
var laneX = [2048 / 2 - laneWidth,
// left lane center
2048 / 2,
// center lane center
2048 / 2 + laneWidth // right lane center
];
// --- Lane Lines (dashed) ---
var laneLineContainers = [];
var laneLineCount = 2; // 2 lines between 3 lanes
var dashHeight = 80;
var dashGap = 80;
var lineWidth = 16;
var lineColor = 0xffffff;
var roadTop = 0;
var roadBottom = 2732;
var dashesPerLine = Math.ceil((roadBottom - roadTop) / (dashHeight + dashGap)) + 2;
for (var i = 0; i < laneLineCount; i++) {
var lineContainer = new Container();
var x = (laneX[i] + laneX[i + 1]) / 2;
for (var d = 0; d < dashesPerLine; d++) {
// Use the laneDash asset for white dashes
var dash = LK.getAsset('laneDash', {
width: lineWidth,
height: dashHeight,
anchorX: 0.5,
anchorY: 0
});
dash.x = x;
dash.y = roadTop + d * (dashHeight + dashGap);
lineContainer.addChild(dash);
}
laneLineContainers.push(lineContainer);
game.addChild(lineContainer);
}
var player = new Motorcycle();
player.x = 2048 / 2; // Center horizontally
player.y = 2732 - 220; // Place near bottom (220 is half the motorcycle height)
game.addChild(player);
var obstacles = [];
var enemyBikes = [];
var powerups = [];
// --- Katana Slash Timer ---
var katanaSlashTimer = 0;
var katanaSlashReady = false;
// --- Score ---
var score = 0;
var distance = 0;
// --- Health ---
var playerHealth = 3;
var maxPlayerHealth = 3;
// Container for tire icons
var healthIcons = new Container();
healthIcons.x = 110;
healthIcons.y = 0;
LK.gui.top.addChild(healthIcons);
// Helper to update tire icons
function updateHealthIcons() {
// Remove all previous icons
while (healthIcons.children.length > 0) {
var c = healthIcons.children.pop();
if (c && typeof c.destroy === "function") c.destroy();
}
// Add one tire icon per health
for (var h = 0; h < playerHealth; h++) {
var tire = LK.getAsset('tireIcon', {
anchorX: 0,
anchorY: 0,
width: 90,
height: 90
});
tire.x = h * 100;
tire.y = 10;
healthIcons.addChild(tire);
}
}
updateHealthIcons();
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
// Anchor to the right edge, top (1, 0)
scoreTxt.anchor.set(1, 0);
// Add to top-right GUI overlay
LK.gui.topRight.addChild(scoreTxt);
// (Punch button removed)
// Touch drag to steer
var dragActive = false;
var dragOffsetX = 0;
game.down = function (x, y, obj) {
// (Punch logic on right half tap removed)
// Only start drag if touch is near the player
var dx = x - player.x;
var dy = y - player.y;
if (dx * dx + dy * dy < 300 * 300) {
dragActive = true;
dragOffsetX = player.x - x;
}
};
game.move = function (x, y, obj) {
if (dragActive) {
player.x = x + dragOffsetX;
}
};
game.up = function (x, y, obj) {
dragActive = false;
};
// --- Spawning logic ---
var obstacleTimer = 0;
var powerupTimer = 0;
// --- Difficulty scaling ---
var enemyBaseSpeed = 24; // initial EnemyBike speed
var enemySpeed = enemyBaseSpeed;
var enemyBaseSpawnInterval = 40; // initial spawn interval (frames)
var enemySpawnInterval = enemyBaseSpawnInterval;
var difficultyTimer = 0; // counts frames for difficulty increase
var difficultyInterval = 600; // every 600 frames (~10s at 60fps), increase difficulty
var enemySpeedIncrement = 2; // how much to increase speed each interval
var enemySpawnDecrement = 4; // how much to decrease spawn interval each interval (minimum capped)
var minEnemySpawnInterval = 12; // minimum allowed spawn interval
// --- Main update loop ---
game.update = function () {
// Scroll road background downward to simulate forward motion
roadBg1.y += player.speedY;
roadBg2.y += player.speedY;
// Loop backgrounds
if (roadBg1.y >= 2732) {
roadBg1.y = roadBg2.y - 2732;
}
if (roadBg2.y >= 2732) {
roadBg2.y = roadBg1.y - 2732;
}
// Scroll and loop lane lines downward
for (var i = 0; i < laneLineContainers.length; i++) {
var lineContainer = laneLineContainers[i];
for (var j = 0; j < lineContainer.children.length; j++) {
var dash = lineContainer.children[j];
dash.y += player.speedY;
if (dash.y > 2732) {
dash.y -= (dashHeight + dashGap) * lineContainer.children.length;
// This ensures the dash loops back to the top
}
}
}
// Move player (handled in class)
player.update();
// Scroll obstacles and powerups
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.update();
// Remove if off screen
if (obs.lastY < 2732 && obs.y >= 2732 + 100) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision detection (trigger on first intersect)
if (!obs.lastWasIntersecting && obs.intersects(player)) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
obs.lastWasIntersecting = obs.intersects(player);
}
// Handle enemyBikes
for (var i = enemyBikes.length - 1; i >= 0; i--) {
var eb = enemyBikes[i];
eb.update();
// Remove if off screen
if (eb.lastY < 2732 && eb.y >= 2732 + 100) {
eb.destroy();
enemyBikes.splice(i, 1);
continue;
}
// Collision detection (trigger on first intersect)
if (!eb.lastWasIntersecting && eb.intersects(player)) {
LK.effects.flashScreen(0xff0000, 800);
playerHealth--;
// Update health icon display
updateHealthIcons();
if (playerHealth <= 0) {
LK.showGameOver();
return;
}
}
eb.lastWasIntersecting = eb.intersects(player);
// (auto-punch logic removed)
}
for (var i = powerups.length - 1; i >= 0; i--) {
var pu = powerups[i];
pu.update();
// Remove if off screen
if (pu.lastY < 2732 && pu.y >= 2732 + 100) {
pu.destroy();
powerups.splice(i, 1);
continue;
}
// Collect powerup
if (!pu.lastWasIntersecting && pu.intersects(player)) {
score += 10;
scoreTxt.setText(score);
pu.destroy();
powerups.splice(i, 1);
continue;
}
pu.lastWasIntersecting = pu.intersects(player);
}
// --- Katana Slash Timer ---
katanaSlashTimer++;
if (katanaSlashTimer >= 120) {
// 2 seconds at 60fps
katanaSlashTimer = 0;
katanaSlashReady = true;
}
if (katanaSlashReady) {
// Trigger katanaSlash attack
var slash = new KatanaSlash();
slash.x = player.x;
slash.y = player.y;
game.addChild(slash);
katanaSlashReady = false;
}
// --- Difficulty scaling ---
difficultyTimer++;
if (difficultyTimer >= difficultyInterval) {
difficultyTimer = 0;
// Increase enemy speed
enemySpeed += enemySpeedIncrement;
// Decrease spawn interval, but not below minimum
enemySpawnInterval -= enemySpawnDecrement;
if (enemySpawnInterval < minEnemySpawnInterval) enemySpawnInterval = minEnemySpawnInterval;
}
// --- Spawning ---
obstacleTimer++;
if (obstacleTimer > enemySpawnInterval) {
obstacleTimer = 0;
// Randomly decide to spawn an Obstacle or an EnemyBike (e.g. 70% car, 30% enemyBike)
if (Math.random() < 0.3) {
var laneIdx = Math.floor(Math.random() * laneCount);
var eb = new EnemyBike();
eb.laneIdx = laneIdx; // Store lane index for reference
eb.x = laneX[laneIdx];
eb.y = -100;
eb.lastWasIntersecting = false;
eb.speedY = enemySpeed; // Set current enemy speed
game.addChild(eb);
enemyBikes.push(eb);
} else {
var obs = new Obstacle();
// Place obstacle in a random lane
var laneIdx = Math.floor(Math.random() * laneCount);
obs.x = laneX[laneIdx];
obs.y = -100;
obs.lastWasIntersecting = false;
game.addChild(obs);
obstacles.push(obs);
}
}
powerupTimer++;
if (powerupTimer > 120) {
powerupTimer = 0;
var pu = new PowerUp();
// Place powerup in a random lane
var laneIdx = Math.floor(Math.random() * laneCount);
pu.x = laneX[laneIdx];
pu.y = -100;
pu.lastWasIntersecting = false;
game.addChild(pu);
powerups.push(pu);
}
// --- Distance/score ---
distance += player.speedY;
if (distance % 1000 < player.speedY) {
score += 1;
scoreTxt.setText(score);
}
// Win condition: reach distance
if (distance > 20000) {
LK.showYouWin();
}
}; /****
* Classes
****/
// EnemyBike class: faster enemy type
var EnemyBike = Container.expand(function () {
var self = Container.call(this);
// Attach enemyBike asset (image, facing upward)
var bike = self.attachAsset('enemyBike', {
anchorX: 0.5,
anchorY: 0.5
});
// Set vertical speed (will be set on spawn)
self.speedY = 24;
// Track lastY for event triggers
self.lastY = self.y;
self.update = function () {
self.lastY = self.y;
self.y += self.speedY;
// EnemyBike moves straight down in its lane
};
return self;
});
// KatanaSlash class: 360-degree melee attack with visible circular slash animation
var KatanaSlash = Container.expand(function () {
var self = Container.call(this);
// Visual: large transparent ellipse to represent slash area
var slashRadius = 260; // covers close range around player
var slashAsset = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
width: slashRadius * 2,
height: slashRadius * 2
});
slashAsset.alpha = 0.35; // semi-transparent
// Tint to blueish for katana effect
slashAsset.tint = 0x66ccff;
// Add a visible circular outline for the slash animation
var outline = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5,
width: slashRadius * 2 + 24,
height: slashRadius * 2 + 24
});
outline.alpha = 0.7;
outline.tint = 0xffffff;
outline.blendMode = "add"; // visually pop the outline if supported
// Animate the outline: scale up and fade out
outline.scaleX = 0.7;
outline.scaleY = 0.7;
// Track lifetime
self.life = 0;
self.maxLife = 18; // ~0.3s at 60fps
// Only trigger hit once per enemy per slash
if (typeof self.hitEnemies === "undefined" || !self.hitEnemies) self.hitEnemies = [];
if (typeof self.maxLife === "undefined") self.maxLife = 18;
self.update = function () {
// Defensive: ensure hitEnemies and maxLife are always defined
if (typeof self.hitEnemies === "undefined" || !self.hitEnemies) self.hitEnemies = [];
if (typeof self.maxLife === "undefined") self.maxLife = 18;
// Defensive: ensure hitEnemies and maxLife are always defined
if (typeof self.hitEnemies === "undefined" || !self.hitEnemies) self.hitEnemies = [];
if (typeof self.maxLife === "undefined") self.maxLife = 18;
// Defensive: ensure hitEnemies and maxLife are always defined at the top of update
if (typeof self.hitEnemies === "undefined" || !self.hitEnemies) self.hitEnemies = [];
if (typeof self.maxLife === "undefined") self.maxLife = 18;
// Defensive: ensure hitEnemies and maxLife are always defined at the top of update
if (typeof self.hitEnemies === "undefined" || !self.hitEnemies) self.hitEnemies = [];
if (typeof self.maxLife === "undefined") self.maxLife = 18;
// Defensive: ensure hitEnemies and maxLife are always defined at the top of update (for every call, every frame)
if (typeof self.hitEnemies === "undefined" || !self.hitEnemies) self.hitEnemies = [];
if (typeof self.maxLife === "undefined") self.maxLife = 18;
self.life++;
// Fade out as it ends
if (self.life > self.maxLife - 8) {
slashAsset.alpha = 0.35 * ((self.maxLife - self.life) / 8);
outline.alpha = 0.7 * ((self.maxLife - self.life) / 8);
} else {
outline.alpha = 0.7;
}
// Animate outline scale for a "slash" effect
if (self.life <= 8) {
var scale = 0.7 + 0.5 * (self.life / 8);
outline.scaleX = scale;
outline.scaleY = scale;
} else {
outline.scaleX = 1.2;
outline.scaleY = 1.2;
}
// Hit enemies in range
for (var i = enemyBikes.length - 1; i >= 0; i--) {
var eb = enemyBikes[i];
if (self.hitEnemies.indexOf(eb) === -1 && self.intersects(eb)) {
// Remove enemy on hit
eb.destroy();
enemyBikes.splice(i, 1);
self.hitEnemies.push(eb);
score += 5;
scoreTxt.setText(score);
}
}
// Hit obstacles in range
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
if (self.hitEnemies.indexOf(obs) === -1 && self.intersects(obs)) {
obs.destroy();
obstacles.splice(i, 1);
self.hitEnemies.push(obs);
score += 2;
scoreTxt.setText(score);
}
}
// Remove slash after duration
if (self.life > self.maxLife) {
self.destroy();
}
};
return self;
});
// Motorcycle class: player-controlled bike
var Motorcycle = Container.expand(function () {
var self = Container.call(this);
// Attach motorcycle asset (image, facing upward)
var bike = self.attachAsset('motorcycle', {
anchorX: 0.5,
anchorY: 0.5
});
// Set initial speed and direction
self.speedY = 18; // vertical speed (track scrolls down)
self.laneSpeed = 0; // horizontal speed (player control)
self.maxX = 2048 - bike.width / 2;
self.minX = bike.width / 2;
// Track lastX for event triggers
self.lastX = self.x;
// Update method: move forward, apply lane movement
self.update = function () {
self.lastX = self.x;
self.x += self.laneSpeed;
// Clamp to track bounds
if (self.x < self.minX) self.x = self.minX;
if (self.x > self.maxX) self.x = self.maxX;
};
return self;
});
// Obstacle class: static/dynamic hazards
var Obstacle = Container.expand(function () {
var self = Container.call(this);
// Attach obstacle asset (box, red)
var obs = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
// Set vertical speed (scrolls with track)
self.speedY = 18;
// Track lastY for event triggers
self.lastY = self.y;
self.update = function () {
self.lastY = self.y;
self.y += self.speedY;
};
return self;
});
// PowerUp class: collectible items
var PowerUp = Container.expand(function () {
var self = Container.call(this);
// Attach powerup asset (ellipse, yellow)
var pu = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedY = 18;
self.lastY = self.y;
self.update = function () {
self.lastY = self.y;
self.y += self.speedY;
};
return self;
});
/****
* Initialize Game
****/
// Motorcycle asset (blue box)
// Obstacle asset (red box)
// PowerUp asset (yellow ellipse)
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// --- Road Background ---
// Motorcycle asset (blue box)
// Obstacle asset (red box)
// PowerUp asset (yellow ellipse)
// --- Game State ---
// Road background: gray
// (punchProjectile logic removed)
var roadCenterX = 2048 / 2;
var roadBg1 = LK.getAsset('roadBg', {
anchorX: 0.5,
anchorY: 0,
width: 1200,
height: 2732,
x: roadCenterX,
y: 0
});
var roadBg2 = LK.getAsset('roadBg', {
anchorX: 0.5,
anchorY: 0,
width: 1200,
height: 2732,
x: roadCenterX,
y: -2732
});
// If the asset doesn't exist, create it as a gray box
if (!roadBg1) {
roadBg1 = LK.getAsset('roadBg', {
anchorX: 0.5,
anchorY: 0,
width: 1200,
height: 2732,
x: roadCenterX,
y: 0
});
roadBg2 = LK.getAsset('roadBg', {
anchorX: 0.5,
anchorY: 0,
width: 1200,
height: 2732,
x: roadCenterX,
y: -2732
});
}
game.addChild(roadBg1);
game.addChild(roadBg2);
// Lane definitions for 3-lane road (centered, full width 2048)
var laneCount = 3;
var laneWidth = 400;
var laneX = [2048 / 2 - laneWidth,
// left lane center
2048 / 2,
// center lane center
2048 / 2 + laneWidth // right lane center
];
// --- Lane Lines (dashed) ---
var laneLineContainers = [];
var laneLineCount = 2; // 2 lines between 3 lanes
var dashHeight = 80;
var dashGap = 80;
var lineWidth = 16;
var lineColor = 0xffffff;
var roadTop = 0;
var roadBottom = 2732;
var dashesPerLine = Math.ceil((roadBottom - roadTop) / (dashHeight + dashGap)) + 2;
for (var i = 0; i < laneLineCount; i++) {
var lineContainer = new Container();
var x = (laneX[i] + laneX[i + 1]) / 2;
for (var d = 0; d < dashesPerLine; d++) {
// Use the laneDash asset for white dashes
var dash = LK.getAsset('laneDash', {
width: lineWidth,
height: dashHeight,
anchorX: 0.5,
anchorY: 0
});
dash.x = x;
dash.y = roadTop + d * (dashHeight + dashGap);
lineContainer.addChild(dash);
}
laneLineContainers.push(lineContainer);
game.addChild(lineContainer);
}
var player = new Motorcycle();
player.x = 2048 / 2; // Center horizontally
player.y = 2732 - 220; // Place near bottom (220 is half the motorcycle height)
game.addChild(player);
var obstacles = [];
var enemyBikes = [];
var powerups = [];
// --- Katana Slash Timer ---
var katanaSlashTimer = 0;
var katanaSlashReady = false;
// --- Score ---
var score = 0;
var distance = 0;
// --- Health ---
var playerHealth = 3;
var maxPlayerHealth = 3;
// Container for tire icons
var healthIcons = new Container();
healthIcons.x = 110;
healthIcons.y = 0;
LK.gui.top.addChild(healthIcons);
// Helper to update tire icons
function updateHealthIcons() {
// Remove all previous icons
while (healthIcons.children.length > 0) {
var c = healthIcons.children.pop();
if (c && typeof c.destroy === "function") c.destroy();
}
// Add one tire icon per health
for (var h = 0; h < playerHealth; h++) {
var tire = LK.getAsset('tireIcon', {
anchorX: 0,
anchorY: 0,
width: 90,
height: 90
});
tire.x = h * 100;
tire.y = 10;
healthIcons.addChild(tire);
}
}
updateHealthIcons();
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
// Anchor to the right edge, top (1, 0)
scoreTxt.anchor.set(1, 0);
// Add to top-right GUI overlay
LK.gui.topRight.addChild(scoreTxt);
// (Punch button removed)
// Touch drag to steer
var dragActive = false;
var dragOffsetX = 0;
game.down = function (x, y, obj) {
// (Punch logic on right half tap removed)
// Only start drag if touch is near the player
var dx = x - player.x;
var dy = y - player.y;
if (dx * dx + dy * dy < 300 * 300) {
dragActive = true;
dragOffsetX = player.x - x;
}
};
game.move = function (x, y, obj) {
if (dragActive) {
player.x = x + dragOffsetX;
}
};
game.up = function (x, y, obj) {
dragActive = false;
};
// --- Spawning logic ---
var obstacleTimer = 0;
var powerupTimer = 0;
// --- Difficulty scaling ---
var enemyBaseSpeed = 24; // initial EnemyBike speed
var enemySpeed = enemyBaseSpeed;
var enemyBaseSpawnInterval = 40; // initial spawn interval (frames)
var enemySpawnInterval = enemyBaseSpawnInterval;
var difficultyTimer = 0; // counts frames for difficulty increase
var difficultyInterval = 600; // every 600 frames (~10s at 60fps), increase difficulty
var enemySpeedIncrement = 2; // how much to increase speed each interval
var enemySpawnDecrement = 4; // how much to decrease spawn interval each interval (minimum capped)
var minEnemySpawnInterval = 12; // minimum allowed spawn interval
// --- Main update loop ---
game.update = function () {
// Scroll road background downward to simulate forward motion
roadBg1.y += player.speedY;
roadBg2.y += player.speedY;
// Loop backgrounds
if (roadBg1.y >= 2732) {
roadBg1.y = roadBg2.y - 2732;
}
if (roadBg2.y >= 2732) {
roadBg2.y = roadBg1.y - 2732;
}
// Scroll and loop lane lines downward
for (var i = 0; i < laneLineContainers.length; i++) {
var lineContainer = laneLineContainers[i];
for (var j = 0; j < lineContainer.children.length; j++) {
var dash = lineContainer.children[j];
dash.y += player.speedY;
if (dash.y > 2732) {
dash.y -= (dashHeight + dashGap) * lineContainer.children.length;
// This ensures the dash loops back to the top
}
}
}
// Move player (handled in class)
player.update();
// Scroll obstacles and powerups
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.update();
// Remove if off screen
if (obs.lastY < 2732 && obs.y >= 2732 + 100) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision detection (trigger on first intersect)
if (!obs.lastWasIntersecting && obs.intersects(player)) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
obs.lastWasIntersecting = obs.intersects(player);
}
// Handle enemyBikes
for (var i = enemyBikes.length - 1; i >= 0; i--) {
var eb = enemyBikes[i];
eb.update();
// Remove if off screen
if (eb.lastY < 2732 && eb.y >= 2732 + 100) {
eb.destroy();
enemyBikes.splice(i, 1);
continue;
}
// Collision detection (trigger on first intersect)
if (!eb.lastWasIntersecting && eb.intersects(player)) {
LK.effects.flashScreen(0xff0000, 800);
playerHealth--;
// Update health icon display
updateHealthIcons();
if (playerHealth <= 0) {
LK.showGameOver();
return;
}
}
eb.lastWasIntersecting = eb.intersects(player);
// (auto-punch logic removed)
}
for (var i = powerups.length - 1; i >= 0; i--) {
var pu = powerups[i];
pu.update();
// Remove if off screen
if (pu.lastY < 2732 && pu.y >= 2732 + 100) {
pu.destroy();
powerups.splice(i, 1);
continue;
}
// Collect powerup
if (!pu.lastWasIntersecting && pu.intersects(player)) {
score += 10;
scoreTxt.setText(score);
pu.destroy();
powerups.splice(i, 1);
continue;
}
pu.lastWasIntersecting = pu.intersects(player);
}
// --- Katana Slash Timer ---
katanaSlashTimer++;
if (katanaSlashTimer >= 120) {
// 2 seconds at 60fps
katanaSlashTimer = 0;
katanaSlashReady = true;
}
if (katanaSlashReady) {
// Trigger katanaSlash attack
var slash = new KatanaSlash();
slash.x = player.x;
slash.y = player.y;
game.addChild(slash);
katanaSlashReady = false;
}
// --- Difficulty scaling ---
difficultyTimer++;
if (difficultyTimer >= difficultyInterval) {
difficultyTimer = 0;
// Increase enemy speed
enemySpeed += enemySpeedIncrement;
// Decrease spawn interval, but not below minimum
enemySpawnInterval -= enemySpawnDecrement;
if (enemySpawnInterval < minEnemySpawnInterval) enemySpawnInterval = minEnemySpawnInterval;
}
// --- Spawning ---
obstacleTimer++;
if (obstacleTimer > enemySpawnInterval) {
obstacleTimer = 0;
// Randomly decide to spawn an Obstacle or an EnemyBike (e.g. 70% car, 30% enemyBike)
if (Math.random() < 0.3) {
var laneIdx = Math.floor(Math.random() * laneCount);
var eb = new EnemyBike();
eb.laneIdx = laneIdx; // Store lane index for reference
eb.x = laneX[laneIdx];
eb.y = -100;
eb.lastWasIntersecting = false;
eb.speedY = enemySpeed; // Set current enemy speed
game.addChild(eb);
enemyBikes.push(eb);
} else {
var obs = new Obstacle();
// Place obstacle in a random lane
var laneIdx = Math.floor(Math.random() * laneCount);
obs.x = laneX[laneIdx];
obs.y = -100;
obs.lastWasIntersecting = false;
game.addChild(obs);
obstacles.push(obs);
}
}
powerupTimer++;
if (powerupTimer > 120) {
powerupTimer = 0;
var pu = new PowerUp();
// Place powerup in a random lane
var laneIdx = Math.floor(Math.random() * laneCount);
pu.x = laneX[laneIdx];
pu.y = -100;
pu.lastWasIntersecting = false;
game.addChild(pu);
powerups.push(pu);
}
// --- Distance/score ---
distance += player.speedY;
if (distance % 1000 < player.speedY) {
score += 1;
scoreTxt.setText(score);
}
// Win condition: reach distance
if (distance > 20000) {
LK.showYouWin();
}
};
Create a 2D motorcycle sprite viewed from behind, positioned to ride on the road.. In-Game asset. 2d. High contrast. No shadows
Create a top-down 2D car sprite facing downward.. In-Game asset. 2d. High contrast. No shadows
Draw a 2D side-view katana with a sleek silver blade and a black-and-red hilt, in a flat cartoon style suitable for an action game. The sword should be horizontal with a transparent background. In-Game asset. 2d. High contrast. No shadows
Create a shiny golden coin (token) asset for a game. The coin should have a polished, reflective surface with subtle engravings or ridges around the edge. It should look 3D with soft highlights and shadows to give depth. The size should be suitable as a collectible power-up floating slightly above the ground. Style should be clean and vibrant, fitting a modern arcade or action game.. In-Game asset. 2d. High contrast. No shadows
Create a simple 2D animation of an enemy motorcycle falling sideways to the ground. The animation should have 5 frames showing the bike tilting and then lying flat. Use a cartoonish style matching a simple 2D game.. In-Game asset. 2d. High contrast. No shadows