User prompt
Make a start screen
User prompt
Once destroy the spike balls in your power up form, they make an explosion animation
User prompt
Perfect adjust once you get the golden bird power up you turn into a golden bird
User prompt
Make the golden bird as separate asset
User prompt
Make a power up called the golden Bird when touched it, grant the bird immunity to the obstacle
User prompt
Make obstacles slower
User prompt
Make less projectiles of the Ogbugh
User prompt
Make the obstacles faster and make more of them
User prompt
Please fix the bug: 'TypeError: obs.update is not a function. (In 'obs.update()', 'obs.update' is undefined)' in or related to this line: 'obs.update();' Line Number: 170
User prompt
Make more obstacles
User prompt
Instead of bouncing off objects, and she just falls straight down
Code edit (1 edits merged)
Please save this source code
User prompt
Head Dodge: Face Tracker Challenge
Initial prompt
OK, so I have an idea so basically it’s gonna be an object tracking my head move and they’re gonna be these little obstacles that I have to die using my head tracking
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var facekit = LK.import("@upit/facekit.v1"); /**** * Classes ****/ // Fast obstacle (normal size, very fast) var FastObstacle = Container.expand(function () { var self = Container.call(this); // Tint to distinguish var asset = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); asset.tint = 0x3498db; // Add update method self.update = function () { self.x += self.vx; self.y += self.vy; }; return self; }); // Golden Bird Powerup class var GoldenBirdPowerup = Container.expand(function () { var self = Container.call(this); // Use a separate golden bird asset for the powerup var asset = self.attachAsset('goldenbird', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.1, scaleY: 1.1 }); self.update = function () { // Powerup falls down self.y += self.vy; }; return self; }); // Large obstacle (slower, bigger) var LargeObstacle = Container.expand(function () { var self = Container.call(this); // Override asset var asset = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); // Add update method self.update = function () { self.x += self.vx; self.y += self.vy; }; return self; }); // Obstacle base class var Obstacle = Container.expand(function () { var self = Container.call(this); // Default asset, can be overridden by subclasses var obstacleAsset = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.update = function () { self.x += self.vx; self.y += self.vy; }; return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); self.playerAsset = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.goldenAsset = null; // No update needed; position is set by facekit in main game loop return self; }); // Small obstacle (faster, smaller) var SmallObstacle = Container.expand(function () { var self = Container.call(this); // Override asset var asset = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.7, scaleY: 0.7 }); // Add update method self.update = function () { self.x += self.vx; self.y += self.vy; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Obstacle: red box // Player avatar: green ellipse // Score display var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Player instance var player = new Player(); game.addChild(player); // Start at center player.x = 2048 / 2; player.y = 2732 / 2; // --- Start Screen Overlay --- var startOverlay = new Container(); var overlayBg = LK.getAsset('obstacle', { anchorX: 0.5, anchorY: 0.5, scaleX: 10, scaleY: 10 }); overlayBg.alpha = 0.85; overlayBg.tint = 0x222222; startOverlay.addChild(overlayBg); var titleText = new Text2("Golden Bird Dodge", { size: 160, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 900; startOverlay.addChild(titleText); var subtitleText = new Text2("Move your head to control!\nDodge obstacles, grab the golden bird!", { size: 70, fill: 0xFFFFFF }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 2048 / 2; subtitleText.y = 1200; startOverlay.addChild(subtitleText); var playBtn = new Text2("PLAY", { size: 140, fill: 0x00FF88 }); playBtn.anchor.set(0.5, 0.5); playBtn.x = 2048 / 2; playBtn.y = 1700; playBtn.interactive = true; playBtn.buttonMode = true; startOverlay.addChild(playBtn); // Center overlay background overlayBg.x = 2048 / 2; overlayBg.y = 2732 / 2; // Add overlay to GUI (so it's always on top) LK.gui.center.addChild(startOverlay); // Pause game logic until play is pressed var gameStarted = false; game.update = function () { if (!gameStarted) return; if (isGameOver) return; // Facekit: update player position // Use noseTip if available, else mouthCenter var fx = facekit.noseTip && facekit.noseTip.x ? facekit.noseTip.x : facekit.mouthCenter.x; var fy = facekit.noseTip && facekit.noseTip.y ? facekit.noseTip.y : facekit.mouthCenter.y; // Clamp to keep player inside screen (with margin for player size) var margin = player.width / 2 + 10; player.x = clamp(fx, margin, 2048 - margin); player.y = clamp(fy, margin, 2732 - margin); // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obs = obstacles[i]; obs.update(); // Remove if out of bounds if (obs.x < -200 || obs.x > 2048 + 200 || obs.y < -200 || obs.y > 2732 + 200) { obs.destroy(); obstacles.splice(i, 1); continue; } // Collision detection if (obs.intersects(player)) { if (!isImmune) { // Game over isGameOver = true; LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); return; } else { // If immune, just destroy the obstacle obs.destroy(); obstacles.splice(i, 1); continue; } } } // Score: survive longer = higher score if (LK.ticks % 6 === 0) { // ~10 times per second setScore(LK.getScore() + 1); } // Spawn obstacles at shorter intervals, increase frequency more aggressively as score increases var spawnInterval = 50 - Math.min(35, Math.floor(LK.getScore() / 20) * 5); // Much faster as score increases if (LK.ticks % spawnInterval === 0) { spawnObstacle(); } // Spawn golden bird powerup every 600-900 ticks, if not already present if (LK.ticks % (600 + Math.floor(Math.random() * 300)) === 0 && powerups.length === 0 && !isImmune) { var powerup = new GoldenBirdPowerup(); powerup.x = 200 + Math.random() * (2048 - 400); powerup.y = -80; powerup.vy = 7 + Math.random() * 3; powerups.push(powerup); game.addChild(powerup); } // Update powerups for (var pi = powerups.length - 1; pi >= 0; pi--) { var pup = powerups[pi]; pup.update(); // Remove if out of bounds if (pup.y > 2732 + 200) { pup.destroy(); powerups.splice(pi, 1); continue; } // Collision with player if (pup.intersects(player)) { isImmune = true; immuneTicks = 600; // 10 seconds at 60fps pup.destroy(); powerups.splice(pi, 1); // Flash player gold LK.effects.flashObject(player, 0xFFD700, 800); // Change player to golden bird asset if (player.goldenAsset) { player.removeChild(player.goldenAsset); player.goldenAsset.destroy(); player.goldenAsset = null; } if (player.playerAsset) { player.playerAsset.visible = false; } player.goldenAsset = player.attachAsset('goldenbird', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.1, scaleY: 1.1 }); } } // Handle immunity timer if (isImmune) { immuneTicks--; // Flicker player to show immunity if (LK.ticks % 20 < 10) { player.alpha = 0.6; } else { player.alpha = 1.0; } if (immuneTicks <= 0) { isImmune = false; player.alpha = 1.0; // Restore player asset and remove golden bird asset if (player.goldenAsset) { player.removeChild(player.goldenAsset); player.goldenAsset.destroy(); player.goldenAsset = null; } if (player.playerAsset) { player.playerAsset.visible = true; } } } }; // Play button handler playBtn.down = function (x, y, obj) { if (gameStarted) return; gameStarted = true; if (startOverlay.parent) { startOverlay.parent.removeChild(startOverlay); } }; // Obstacles array var obstacles = []; // Powerup array var powerups = []; // Game state var isGameOver = false; var lastScore = 0; // Immunity state var isImmune = false; var immuneTicks = 0; // Helper: Clamp value between min and max function clamp(val, min, max) { if (val < min) return min; if (val > max) return max; return val; } // Helper: Spawn a batch of new obstacles from random edges, with higher speed function spawnObstacle() { // Spawn 1-2 obstacles per interval for less density var numToSpawn = 1 + Math.floor(Math.random() * 2); // 1-2 for (var n = 0; n < numToSpawn; n++) { // Randomly choose obstacle type var typeRand = Math.random(); var obs, speed; var x = 200 + Math.random() * (2048 - 400); var y = -80; if (typeRand < 0.2) { // 20% Large, slow (slower than before) obs = new LargeObstacle(); speed = 5 + Math.random() * 2; // 5-7 px/frame } else if (typeRand < 0.5) { // 30% Small, fast (but slower than before) obs = new SmallObstacle(); speed = 8 + Math.random() * 4; // 8-12 px/frame } else if (typeRand < 0.7) { // 20% Fast, normal size, blue (but slower than before) obs = new FastObstacle(); speed = 10 + Math.random() * 4; // 10-14 px/frame } else { // 30% Normal (slower than before) obs = new Obstacle(); speed = 7 + Math.random() * 5; // 7-12 px/frame } obs.x = x; obs.y = y; obs.vx = 0; obs.vy = speed; obstacles.push(obs); game.addChild(obs); } } // Score logic function setScore(val) { LK.setScore(val); scoreTxt.setText(val); } // Main update loop game.update = function () { if (isGameOver) return; // Facekit: update player position // Use noseTip if available, else mouthCenter var fx = facekit.noseTip && facekit.noseTip.x ? facekit.noseTip.x : facekit.mouthCenter.x; var fy = facekit.noseTip && facekit.noseTip.y ? facekit.noseTip.y : facekit.mouthCenter.y; // Clamp to keep player inside screen (with margin for player size) var margin = player.width / 2 + 10; player.x = clamp(fx, margin, 2048 - margin); player.y = clamp(fy, margin, 2732 - margin); // Update obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obs = obstacles[i]; obs.update(); // Remove if out of bounds if (obs.x < -200 || obs.x > 2048 + 200 || obs.y < -200 || obs.y > 2732 + 200) { obs.destroy(); obstacles.splice(i, 1); continue; } // Collision detection if (obs.intersects(player)) { if (!isImmune) { // Game over isGameOver = true; LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); return; } else { // If immune, just destroy the obstacle obs.destroy(); obstacles.splice(i, 1); continue; } } } // Score: survive longer = higher score if (LK.ticks % 6 === 0) { // ~10 times per second setScore(LK.getScore() + 1); } // Spawn obstacles at shorter intervals, increase frequency more aggressively as score increases var spawnInterval = 50 - Math.min(35, Math.floor(LK.getScore() / 20) * 5); // Much faster as score increases if (LK.ticks % spawnInterval === 0) { spawnObstacle(); } // Spawn golden bird powerup every 600-900 ticks, if not already present if (LK.ticks % (600 + Math.floor(Math.random() * 300)) === 0 && powerups.length === 0 && !isImmune) { var powerup = new GoldenBirdPowerup(); powerup.x = 200 + Math.random() * (2048 - 400); powerup.y = -80; powerup.vy = 7 + Math.random() * 3; powerups.push(powerup); game.addChild(powerup); } // Update powerups for (var pi = powerups.length - 1; pi >= 0; pi--) { var pup = powerups[pi]; pup.update(); // Remove if out of bounds if (pup.y > 2732 + 200) { pup.destroy(); powerups.splice(pi, 1); continue; } // Collision with player if (pup.intersects(player)) { isImmune = true; immuneTicks = 600; // 10 seconds at 60fps pup.destroy(); powerups.splice(pi, 1); // Flash player gold LK.effects.flashObject(player, 0xFFD700, 800); // Change player to golden bird asset if (player.goldenAsset) { player.removeChild(player.goldenAsset); player.goldenAsset.destroy(); player.goldenAsset = null; } if (player.playerAsset) { player.playerAsset.visible = false; } player.goldenAsset = player.attachAsset('goldenbird', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.1, scaleY: 1.1 }); } } // Handle immunity timer if (isImmune) { immuneTicks--; // Flicker player to show immunity if (LK.ticks % 20 < 10) { player.alpha = 0.6; } else { player.alpha = 1.0; } if (immuneTicks <= 0) { isImmune = false; player.alpha = 1.0; // Restore player asset and remove golden bird asset if (player.goldenAsset) { player.removeChild(player.goldenAsset); player.goldenAsset.destroy(); player.goldenAsset = null; } if (player.playerAsset) { player.playerAsset.visible = true; } } } }; // Reset state on new game game.on('reset', function () { // Remove all obstacles for (var i = 0; i < obstacles.length; i++) { obstacles[i].destroy(); } obstacles = []; // Remove all powerups for (var j = 0; j < powerups.length; j++) { powerups[j].destroy(); } powerups = []; setScore(0); isGameOver = false; isImmune = false; immuneTicks = 0; player.alpha = 1.0; // Remove golden bird asset if present and restore player asset if (player.goldenAsset) { player.removeChild(player.goldenAsset); player.goldenAsset.destroy(); player.goldenAsset = null; } if (player.playerAsset) { player.playerAsset.visible = true; } // Center player player.x = 2048 / 2; player.y = 2732 / 2; }); // Ensure player is not in top-left 100x100 area player.x = 2048 / 2; player.y = 2732 / 2; if (player.x < 180) player.x = 180; if (player.y < 180) player.y = 180;
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var facekit = LK.import("@upit/facekit.v1");
/****
* Classes
****/
// Fast obstacle (normal size, very fast)
var FastObstacle = Container.expand(function () {
var self = Container.call(this);
// Tint to distinguish
var asset = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
asset.tint = 0x3498db;
// Add update method
self.update = function () {
self.x += self.vx;
self.y += self.vy;
};
return self;
});
// Golden Bird Powerup class
var GoldenBirdPowerup = Container.expand(function () {
var self = Container.call(this);
// Use a separate golden bird asset for the powerup
var asset = self.attachAsset('goldenbird', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1
});
self.update = function () {
// Powerup falls down
self.y += self.vy;
};
return self;
});
// Large obstacle (slower, bigger)
var LargeObstacle = Container.expand(function () {
var self = Container.call(this);
// Override asset
var asset = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// Add update method
self.update = function () {
self.x += self.vx;
self.y += self.vy;
};
return self;
});
// Obstacle base class
var Obstacle = Container.expand(function () {
var self = Container.call(this);
// Default asset, can be overridden by subclasses
var obstacleAsset = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.update = function () {
self.x += self.vx;
self.y += self.vy;
};
return self;
});
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
self.playerAsset = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.goldenAsset = null;
// No update needed; position is set by facekit in main game loop
return self;
});
// Small obstacle (faster, smaller)
var SmallObstacle = Container.expand(function () {
var self = Container.call(this);
// Override asset
var asset = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
// Add update method
self.update = function () {
self.x += self.vx;
self.y += self.vy;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Obstacle: red box
// Player avatar: green ellipse
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Player instance
var player = new Player();
game.addChild(player);
// Start at center
player.x = 2048 / 2;
player.y = 2732 / 2;
// --- Start Screen Overlay ---
var startOverlay = new Container();
var overlayBg = LK.getAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10,
scaleY: 10
});
overlayBg.alpha = 0.85;
overlayBg.tint = 0x222222;
startOverlay.addChild(overlayBg);
var titleText = new Text2("Golden Bird Dodge", {
size: 160,
fill: 0xFFD700
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 900;
startOverlay.addChild(titleText);
var subtitleText = new Text2("Move your head to control!\nDodge obstacles, grab the golden bird!", {
size: 70,
fill: 0xFFFFFF
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 2048 / 2;
subtitleText.y = 1200;
startOverlay.addChild(subtitleText);
var playBtn = new Text2("PLAY", {
size: 140,
fill: 0x00FF88
});
playBtn.anchor.set(0.5, 0.5);
playBtn.x = 2048 / 2;
playBtn.y = 1700;
playBtn.interactive = true;
playBtn.buttonMode = true;
startOverlay.addChild(playBtn);
// Center overlay background
overlayBg.x = 2048 / 2;
overlayBg.y = 2732 / 2;
// Add overlay to GUI (so it's always on top)
LK.gui.center.addChild(startOverlay);
// Pause game logic until play is pressed
var gameStarted = false;
game.update = function () {
if (!gameStarted) return;
if (isGameOver) return;
// Facekit: update player position
// Use noseTip if available, else mouthCenter
var fx = facekit.noseTip && facekit.noseTip.x ? facekit.noseTip.x : facekit.mouthCenter.x;
var fy = facekit.noseTip && facekit.noseTip.y ? facekit.noseTip.y : facekit.mouthCenter.y;
// Clamp to keep player inside screen (with margin for player size)
var margin = player.width / 2 + 10;
player.x = clamp(fx, margin, 2048 - margin);
player.y = clamp(fy, margin, 2732 - margin);
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.update();
// Remove if out of bounds
if (obs.x < -200 || obs.x > 2048 + 200 || obs.y < -200 || obs.y > 2732 + 200) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision detection
if (obs.intersects(player)) {
if (!isImmune) {
// Game over
isGameOver = true;
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
} else {
// If immune, just destroy the obstacle
obs.destroy();
obstacles.splice(i, 1);
continue;
}
}
}
// Score: survive longer = higher score
if (LK.ticks % 6 === 0) {
// ~10 times per second
setScore(LK.getScore() + 1);
}
// Spawn obstacles at shorter intervals, increase frequency more aggressively as score increases
var spawnInterval = 50 - Math.min(35, Math.floor(LK.getScore() / 20) * 5); // Much faster as score increases
if (LK.ticks % spawnInterval === 0) {
spawnObstacle();
}
// Spawn golden bird powerup every 600-900 ticks, if not already present
if (LK.ticks % (600 + Math.floor(Math.random() * 300)) === 0 && powerups.length === 0 && !isImmune) {
var powerup = new GoldenBirdPowerup();
powerup.x = 200 + Math.random() * (2048 - 400);
powerup.y = -80;
powerup.vy = 7 + Math.random() * 3;
powerups.push(powerup);
game.addChild(powerup);
}
// Update powerups
for (var pi = powerups.length - 1; pi >= 0; pi--) {
var pup = powerups[pi];
pup.update();
// Remove if out of bounds
if (pup.y > 2732 + 200) {
pup.destroy();
powerups.splice(pi, 1);
continue;
}
// Collision with player
if (pup.intersects(player)) {
isImmune = true;
immuneTicks = 600; // 10 seconds at 60fps
pup.destroy();
powerups.splice(pi, 1);
// Flash player gold
LK.effects.flashObject(player, 0xFFD700, 800);
// Change player to golden bird asset
if (player.goldenAsset) {
player.removeChild(player.goldenAsset);
player.goldenAsset.destroy();
player.goldenAsset = null;
}
if (player.playerAsset) {
player.playerAsset.visible = false;
}
player.goldenAsset = player.attachAsset('goldenbird', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1
});
}
}
// Handle immunity timer
if (isImmune) {
immuneTicks--;
// Flicker player to show immunity
if (LK.ticks % 20 < 10) {
player.alpha = 0.6;
} else {
player.alpha = 1.0;
}
if (immuneTicks <= 0) {
isImmune = false;
player.alpha = 1.0;
// Restore player asset and remove golden bird asset
if (player.goldenAsset) {
player.removeChild(player.goldenAsset);
player.goldenAsset.destroy();
player.goldenAsset = null;
}
if (player.playerAsset) {
player.playerAsset.visible = true;
}
}
}
};
// Play button handler
playBtn.down = function (x, y, obj) {
if (gameStarted) return;
gameStarted = true;
if (startOverlay.parent) {
startOverlay.parent.removeChild(startOverlay);
}
};
// Obstacles array
var obstacles = [];
// Powerup array
var powerups = [];
// Game state
var isGameOver = false;
var lastScore = 0;
// Immunity state
var isImmune = false;
var immuneTicks = 0;
// Helper: Clamp value between min and max
function clamp(val, min, max) {
if (val < min) return min;
if (val > max) return max;
return val;
}
// Helper: Spawn a batch of new obstacles from random edges, with higher speed
function spawnObstacle() {
// Spawn 1-2 obstacles per interval for less density
var numToSpawn = 1 + Math.floor(Math.random() * 2); // 1-2
for (var n = 0; n < numToSpawn; n++) {
// Randomly choose obstacle type
var typeRand = Math.random();
var obs, speed;
var x = 200 + Math.random() * (2048 - 400);
var y = -80;
if (typeRand < 0.2) {
// 20% Large, slow (slower than before)
obs = new LargeObstacle();
speed = 5 + Math.random() * 2; // 5-7 px/frame
} else if (typeRand < 0.5) {
// 30% Small, fast (but slower than before)
obs = new SmallObstacle();
speed = 8 + Math.random() * 4; // 8-12 px/frame
} else if (typeRand < 0.7) {
// 20% Fast, normal size, blue (but slower than before)
obs = new FastObstacle();
speed = 10 + Math.random() * 4; // 10-14 px/frame
} else {
// 30% Normal (slower than before)
obs = new Obstacle();
speed = 7 + Math.random() * 5; // 7-12 px/frame
}
obs.x = x;
obs.y = y;
obs.vx = 0;
obs.vy = speed;
obstacles.push(obs);
game.addChild(obs);
}
}
// Score logic
function setScore(val) {
LK.setScore(val);
scoreTxt.setText(val);
}
// Main update loop
game.update = function () {
if (isGameOver) return;
// Facekit: update player position
// Use noseTip if available, else mouthCenter
var fx = facekit.noseTip && facekit.noseTip.x ? facekit.noseTip.x : facekit.mouthCenter.x;
var fy = facekit.noseTip && facekit.noseTip.y ? facekit.noseTip.y : facekit.mouthCenter.y;
// Clamp to keep player inside screen (with margin for player size)
var margin = player.width / 2 + 10;
player.x = clamp(fx, margin, 2048 - margin);
player.y = clamp(fy, margin, 2732 - margin);
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
obs.update();
// Remove if out of bounds
if (obs.x < -200 || obs.x > 2048 + 200 || obs.y < -200 || obs.y > 2732 + 200) {
obs.destroy();
obstacles.splice(i, 1);
continue;
}
// Collision detection
if (obs.intersects(player)) {
if (!isImmune) {
// Game over
isGameOver = true;
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
} else {
// If immune, just destroy the obstacle
obs.destroy();
obstacles.splice(i, 1);
continue;
}
}
}
// Score: survive longer = higher score
if (LK.ticks % 6 === 0) {
// ~10 times per second
setScore(LK.getScore() + 1);
}
// Spawn obstacles at shorter intervals, increase frequency more aggressively as score increases
var spawnInterval = 50 - Math.min(35, Math.floor(LK.getScore() / 20) * 5); // Much faster as score increases
if (LK.ticks % spawnInterval === 0) {
spawnObstacle();
}
// Spawn golden bird powerup every 600-900 ticks, if not already present
if (LK.ticks % (600 + Math.floor(Math.random() * 300)) === 0 && powerups.length === 0 && !isImmune) {
var powerup = new GoldenBirdPowerup();
powerup.x = 200 + Math.random() * (2048 - 400);
powerup.y = -80;
powerup.vy = 7 + Math.random() * 3;
powerups.push(powerup);
game.addChild(powerup);
}
// Update powerups
for (var pi = powerups.length - 1; pi >= 0; pi--) {
var pup = powerups[pi];
pup.update();
// Remove if out of bounds
if (pup.y > 2732 + 200) {
pup.destroy();
powerups.splice(pi, 1);
continue;
}
// Collision with player
if (pup.intersects(player)) {
isImmune = true;
immuneTicks = 600; // 10 seconds at 60fps
pup.destroy();
powerups.splice(pi, 1);
// Flash player gold
LK.effects.flashObject(player, 0xFFD700, 800);
// Change player to golden bird asset
if (player.goldenAsset) {
player.removeChild(player.goldenAsset);
player.goldenAsset.destroy();
player.goldenAsset = null;
}
if (player.playerAsset) {
player.playerAsset.visible = false;
}
player.goldenAsset = player.attachAsset('goldenbird', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.1,
scaleY: 1.1
});
}
}
// Handle immunity timer
if (isImmune) {
immuneTicks--;
// Flicker player to show immunity
if (LK.ticks % 20 < 10) {
player.alpha = 0.6;
} else {
player.alpha = 1.0;
}
if (immuneTicks <= 0) {
isImmune = false;
player.alpha = 1.0;
// Restore player asset and remove golden bird asset
if (player.goldenAsset) {
player.removeChild(player.goldenAsset);
player.goldenAsset.destroy();
player.goldenAsset = null;
}
if (player.playerAsset) {
player.playerAsset.visible = true;
}
}
}
};
// Reset state on new game
game.on('reset', function () {
// Remove all obstacles
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].destroy();
}
obstacles = [];
// Remove all powerups
for (var j = 0; j < powerups.length; j++) {
powerups[j].destroy();
}
powerups = [];
setScore(0);
isGameOver = false;
isImmune = false;
immuneTicks = 0;
player.alpha = 1.0;
// Remove golden bird asset if present and restore player asset
if (player.goldenAsset) {
player.removeChild(player.goldenAsset);
player.goldenAsset.destroy();
player.goldenAsset = null;
}
if (player.playerAsset) {
player.playerAsset.visible = true;
}
// Center player
player.x = 2048 / 2;
player.y = 2732 / 2;
});
// Ensure player is not in top-left 100x100 area
player.x = 2048 / 2;
player.y = 2732 / 2;
if (player.x < 180) player.x = 180;
if (player.y < 180) player.y = 180;