User prompt
Destroy the green entity that appears when I sprint and analyze the game to fix the bug. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Acceleration is now a sprint ability that lasts for 0.9 seconds and then slows the character by 1.5x. There's a bar just below the health bar that shows how many seconds of sprint time we have left. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The monster does not follow the player during the dash, it simply runs in that direction.
User prompt
The monster dashes every 5 seconds and if it hits an obstacle while dashing, it will be stunned for 1 second. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
We can make the character follow the cursor faster by pressing the left mouse button.
User prompt
When we hit obstacles, we lose 2 health, but every time we take damage, we jump a distance away from the creature we damaged. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add a monster that chases us and deals 3 damage when it catches us ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add a health bar with 10 lives
Code edit (1 edits merged)
Please save this source code
User prompt
Bird's Eye Adventure
Initial prompt
Take the area as the ground and place a character in the middle so that we can look at this character from above with a bird's eye view.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Character = Container.expand(function () {
var self = Container.call(this);
var characterGraphics = self.attachAsset('character', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.targetX = self.x;
self.targetY = self.y;
self.update = function () {
// Smooth movement towards target position
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 2) {
// Determine current speed based on sprint state
var currentSpeed = self.speed;
if (sprintActive) {
currentSpeed = self.speed * 2; // 2x speed during sprint
} else if (sprintSlowdown) {
currentSpeed = self.speed / 1.5; // 1.5x slower after sprint
}
self.x += dx / distance * currentSpeed;
self.y += dy / distance * currentSpeed;
}
};
return self;
});
var Collectible = Container.expand(function () {
var self = Container.call(this);
var collectibleGraphics = self.attachAsset('collectible', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.update = function () {
// Gentle floating animation
collectibleGraphics.y = Math.sin(LK.ticks * 0.1) * 5;
};
return self;
});
var Monster = Container.expand(function () {
var self = Container.call(this);
var monsterGraphics = self.attachAsset('monster', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.targetX = self.x;
self.targetY = self.y;
self.lastIntersecting = false;
self.isDashing = false;
self.isStunned = false;
self.dashSpeed = 12;
self.dashDirectionX = 0;
self.dashDirectionY = 0;
self.lastDashTime = 0;
self.dashCooldown = 5000; // 5 seconds in milliseconds
self.update = function () {
// Handle stunning - monster can't move when stunned
if (self.isStunned) {
// Don't move or dash while stunned
return;
}
// Check for dash timing (every 5 seconds)
var currentTime = LK.ticks * (1000 / 60); // Convert ticks to milliseconds
if (!self.isDashing && currentTime - self.lastDashTime >= self.dashCooldown) {
// Start dash - calculate direction towards player and store it
var dx = character.x - self.x;
var dy = character.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.dashDirectionX = dx / distance;
self.dashDirectionY = dy / distance;
} else {
self.dashDirectionX = 1; // Default direction
self.dashDirectionY = 0;
}
self.isDashing = true;
self.lastDashTime = currentTime;
// Visual indication of dash - tint monster
tween(monsterGraphics, {
tint: 0xffff00
}, {
duration: 100
});
// Dash lasts for 1 second
LK.setTimeout(function () {
self.isDashing = false;
// Return to normal color
tween(monsterGraphics, {
tint: 0xffffff
}, {
duration: 200
});
}, 1000);
}
if (self.isDashing) {
// During dash, move in stored dash direction
self.x += self.dashDirectionX * self.dashSpeed;
self.y += self.dashDirectionY * self.dashSpeed;
} else {
// Chase the player character when not dashing
var dx = character.x - self.x;
var dy = character.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
}
// Check for collision with obstacles while dashing
if (self.isDashing) {
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (self.intersects(obstacle)) {
// Monster hits obstacle while dashing - get stunned
self.isDashing = false;
self.isStunned = true;
// Visual indication of stun - tint red
tween(monsterGraphics, {
tint: 0x666666
}, {
duration: 200
});
// Stun lasts for 1 second
LK.setTimeout(function () {
self.isStunned = false;
// Return to normal color
tween(monsterGraphics, {
tint: 0xffffff
}, {
duration: 300
});
}, 1000);
break; // Exit loop after hitting first obstacle
}
}
}
// Check for collision with character
var currentIntersecting = self.intersects(character);
if (!self.lastIntersecting && currentIntersecting) {
// Just started intersecting - deal 3 damage
currentHealth -= 3;
// Flash monster red when dealing damage
tween(monsterGraphics, {
tint: 0xff0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(monsterGraphics, {
tint: 0xffffff
}, {
duration: 200
});
}
});
// Update health bar display
for (var j = 0; j < healthBars.length; j++) {
if (j < currentHealth) {
healthBars[j].alpha = 1.0;
} else {
healthBars[j].alpha = 0.3;
}
}
// Check game over condition
if (currentHealth <= 0) {
LK.showGameOver();
}
// Jump character away from monster with tween animation
var jumpDistance = 200;
var jumpTargetX = self.x + dx / distance * jumpDistance;
var jumpTargetY = self.y + dy / distance * jumpDistance;
// Keep within bounds
jumpTargetX = Math.max(groundBounds.left, Math.min(groundBounds.right, jumpTargetX));
jumpTargetY = Math.max(groundBounds.top, Math.min(groundBounds.bottom, jumpTargetY));
// Animate jump with tween
tween(character, {
x: jumpTargetX,
y: jumpTargetY
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
character.targetX = character.x;
character.targetY = character.y;
}
});
}
self.lastIntersecting = currentIntersecting;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
//Import tween plugin for smooth monster movement animations
// Create the ground/play area
var ground = LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 0.5
});
ground.x = 2048 / 2;
ground.y = 2732 / 2;
game.addChild(ground);
// Create character in center
var character = new Character();
character.x = 2048 / 2;
character.y = 2732 / 2;
character.targetX = character.x;
character.targetY = character.y;
game.addChild(character);
// Create obstacles around the play area
var obstacles = [];
for (var i = 0; i < 8; i++) {
var obstacle = new Obstacle();
var angle = i / 8 * Math.PI * 2;
var radius = 600;
obstacle.x = 2048 / 2 + Math.cos(angle) * radius;
obstacle.y = 2732 / 2 + Math.sin(angle) * radius;
obstacles.push(obstacle);
game.addChild(obstacle);
}
// Create collectibles
var collectibles = [];
for (var i = 0; i < 12; i++) {
var collectible = new Collectible();
var angle = Math.random() * Math.PI * 2;
var radius = 200 + Math.random() * 400;
collectible.x = 2048 / 2 + Math.cos(angle) * radius;
collectible.y = 2732 / 2 + Math.sin(angle) * radius;
collectibles.push(collectible);
game.addChild(collectible);
}
// Create score display
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Initialize health system
var maxHealth = 10;
var currentHealth = 10;
var healthBars = [];
// Create health bar display
for (var i = 0; i < maxHealth; i++) {
var healthBar = LK.getAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 150 + i * 50;
healthBar.y = 80;
healthBars.push(healthBar);
LK.gui.topLeft.addChild(healthBar);
}
// Create monster that chases the player
var monster = new Monster();
monster.x = 2048 / 2 - 400; // Start to the left of center
monster.y = 2732 / 2 - 400; // Start above center
game.addChild(monster);
// Game bounds (keep character within ground area)
var groundBounds = {
left: 2048 / 2 - 850,
right: 2048 / 2 + 850,
top: 2732 / 2 - 850,
bottom: 2732 / 2 + 850
};
// Track mouse button state and sprint system
var mousePressed = false;
var sprintActive = false;
var sprintSlowdown = false;
var sprintDuration = 900; // 0.9 seconds in milliseconds
var sprintStartTime = 0;
var sprintTimeRemaining = 0;
// Create sprint bar display
var sprintBarBg = LK.getAsset('sprintBarBg', {
anchorX: 0,
anchorY: 0.5
});
sprintBarBg.x = 150;
sprintBarBg.y = 130; // Below health bar
LK.gui.topLeft.addChild(sprintBarBg);
var sprintBarFill = LK.getAsset('sprintBar', {
anchorX: 0,
anchorY: 0.5
});
sprintBarFill.x = 150;
sprintBarFill.y = 130;
LK.gui.topLeft.addChild(sprintBarFill);
// Touch/mouse controls
game.down = function (x, y, obj) {
// Set mouse pressed state and start sprint
mousePressed = true;
if (!sprintActive && !sprintSlowdown) {
sprintActive = true;
sprintStartTime = LK.ticks * (1000 / 60); // Convert to milliseconds
sprintTimeRemaining = sprintDuration;
// Visual indication - tint character green during sprint
var characterGraphics = character.children[0];
tween(characterGraphics, {
tint: 0x00ff00
}, {
duration: 100
});
}
// Set character target to touch position, but keep within bounds
character.targetX = Math.max(groundBounds.left, Math.min(groundBounds.right, x));
character.targetY = Math.max(groundBounds.top, Math.min(groundBounds.bottom, y));
};
game.move = function (x, y, obj) {
// Continue moving to touch position while dragging
character.targetX = Math.max(groundBounds.left, Math.min(groundBounds.right, x));
character.targetY = Math.max(groundBounds.top, Math.min(groundBounds.bottom, y));
};
game.up = function (x, y, obj) {
// Set mouse pressed state to false when button is released
mousePressed = false;
};
// Game update loop
game.update = function () {
// Handle sprint system timing
var currentTime = LK.ticks * (1000 / 60);
if (sprintActive) {
sprintTimeRemaining = sprintDuration - (currentTime - sprintStartTime);
if (sprintTimeRemaining <= 0) {
// Sprint finished - start slowdown period
sprintActive = false;
sprintSlowdown = true;
sprintTimeRemaining = 0;
// Visual indication - tint character red during slowdown
var characterGraphics = character.children[0];
tween(characterGraphics, {
tint: 0xff0000
}, {
duration: 200
});
// Slowdown lasts for 1 second
LK.setTimeout(function () {
sprintSlowdown = false;
// Return to normal color
tween(characterGraphics, {
tint: 0xffffff
}, {
duration: 200
});
}, 1000);
}
}
// Update sprint bar display
var sprintProgress = sprintTimeRemaining / sprintDuration;
if (sprintActive) {
sprintBarFill.scaleX = Math.max(0, sprintProgress);
sprintBarFill.tint = 0x00ff00; // Green during sprint
} else if (sprintSlowdown) {
sprintBarFill.scaleX = 0;
sprintBarFill.tint = 0xff0000; // Red during slowdown
} else {
sprintBarFill.scaleX = 1;
sprintBarFill.tint = 0x00ff00; // Full green when ready
}
// Check for collectible collection
for (var i = collectibles.length - 1; i >= 0; i--) {
var collectible = collectibles[i];
if (!collectible.collected && character.intersects(collectible)) {
collectible.collected = true;
LK.setScore(LK.getScore() + 10);
scoreTxt.setText('Score: ' + LK.getScore());
// Remove collectible
collectible.destroy();
collectibles.splice(i, 1);
// Check win condition
if (collectibles.length === 0) {
LK.showYouWin();
}
}
}
// Check collision with obstacles
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (obstacle.lastIntersecting === undefined) obstacle.lastIntersecting = false;
var currentIntersecting = character.intersects(obstacle);
if (!obstacle.lastIntersecting && currentIntersecting) {
// Just started intersecting - reduce health by 2
currentHealth -= 2;
// Update health bar display
for (var j = 0; j < healthBars.length; j++) {
if (j < currentHealth) {
healthBars[j].alpha = 1.0;
} else {
healthBars[j].alpha = 0.3;
}
}
// Check game over condition
if (currentHealth <= 0) {
LK.showGameOver();
}
// Jump character away from obstacle with tween animation
var dx = character.x - obstacle.x;
var dy = character.y - obstacle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var jumpDistance = 200;
var jumpTargetX = obstacle.x + dx / distance * jumpDistance;
var jumpTargetY = obstacle.y + dy / distance * jumpDistance;
// Keep within bounds
jumpTargetX = Math.max(groundBounds.left, Math.min(groundBounds.right, jumpTargetX));
jumpTargetY = Math.max(groundBounds.top, Math.min(groundBounds.bottom, jumpTargetY));
// Animate jump with tween
tween(character, {
x: jumpTargetX,
y: jumpTargetY
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
character.targetX = character.x;
character.targetY = character.y;
}
});
}
}
if (currentIntersecting) {
// Push character away from obstacle
var dx = character.x - obstacle.x;
var dy = character.y - obstacle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var pushDistance = 100;
character.targetX = obstacle.x + dx / distance * pushDistance;
character.targetY = obstacle.y + dy / distance * pushDistance;
// Keep within bounds
character.targetX = Math.max(groundBounds.left, Math.min(groundBounds.right, character.targetX));
character.targetY = Math.max(groundBounds.top, Math.min(groundBounds.bottom, character.targetY));
}
}
obstacle.lastIntersecting = currentIntersecting;
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Character = Container.expand(function () {
var self = Container.call(this);
var characterGraphics = self.attachAsset('character', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.targetX = self.x;
self.targetY = self.y;
self.update = function () {
// Smooth movement towards target position
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 2) {
// Determine current speed based on sprint state
var currentSpeed = self.speed;
if (sprintActive) {
currentSpeed = self.speed * 2; // 2x speed during sprint
} else if (sprintSlowdown) {
currentSpeed = self.speed / 1.5; // 1.5x slower after sprint
}
self.x += dx / distance * currentSpeed;
self.y += dy / distance * currentSpeed;
}
};
return self;
});
var Collectible = Container.expand(function () {
var self = Container.call(this);
var collectibleGraphics = self.attachAsset('collectible', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.update = function () {
// Gentle floating animation
collectibleGraphics.y = Math.sin(LK.ticks * 0.1) * 5;
};
return self;
});
var Monster = Container.expand(function () {
var self = Container.call(this);
var monsterGraphics = self.attachAsset('monster', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 3;
self.targetX = self.x;
self.targetY = self.y;
self.lastIntersecting = false;
self.isDashing = false;
self.isStunned = false;
self.dashSpeed = 12;
self.dashDirectionX = 0;
self.dashDirectionY = 0;
self.lastDashTime = 0;
self.dashCooldown = 5000; // 5 seconds in milliseconds
self.update = function () {
// Handle stunning - monster can't move when stunned
if (self.isStunned) {
// Don't move or dash while stunned
return;
}
// Check for dash timing (every 5 seconds)
var currentTime = LK.ticks * (1000 / 60); // Convert ticks to milliseconds
if (!self.isDashing && currentTime - self.lastDashTime >= self.dashCooldown) {
// Start dash - calculate direction towards player and store it
var dx = character.x - self.x;
var dy = character.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.dashDirectionX = dx / distance;
self.dashDirectionY = dy / distance;
} else {
self.dashDirectionX = 1; // Default direction
self.dashDirectionY = 0;
}
self.isDashing = true;
self.lastDashTime = currentTime;
// Visual indication of dash - tint monster
tween(monsterGraphics, {
tint: 0xffff00
}, {
duration: 100
});
// Dash lasts for 1 second
LK.setTimeout(function () {
self.isDashing = false;
// Return to normal color
tween(monsterGraphics, {
tint: 0xffffff
}, {
duration: 200
});
}, 1000);
}
if (self.isDashing) {
// During dash, move in stored dash direction
self.x += self.dashDirectionX * self.dashSpeed;
self.y += self.dashDirectionY * self.dashSpeed;
} else {
// Chase the player character when not dashing
var dx = character.x - self.x;
var dy = character.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
}
// Check for collision with obstacles while dashing
if (self.isDashing) {
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (self.intersects(obstacle)) {
// Monster hits obstacle while dashing - get stunned
self.isDashing = false;
self.isStunned = true;
// Visual indication of stun - tint red
tween(monsterGraphics, {
tint: 0x666666
}, {
duration: 200
});
// Stun lasts for 1 second
LK.setTimeout(function () {
self.isStunned = false;
// Return to normal color
tween(monsterGraphics, {
tint: 0xffffff
}, {
duration: 300
});
}, 1000);
break; // Exit loop after hitting first obstacle
}
}
}
// Check for collision with character
var currentIntersecting = self.intersects(character);
if (!self.lastIntersecting && currentIntersecting) {
// Just started intersecting - deal 3 damage
currentHealth -= 3;
// Flash monster red when dealing damage
tween(monsterGraphics, {
tint: 0xff0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(monsterGraphics, {
tint: 0xffffff
}, {
duration: 200
});
}
});
// Update health bar display
for (var j = 0; j < healthBars.length; j++) {
if (j < currentHealth) {
healthBars[j].alpha = 1.0;
} else {
healthBars[j].alpha = 0.3;
}
}
// Check game over condition
if (currentHealth <= 0) {
LK.showGameOver();
}
// Jump character away from monster with tween animation
var jumpDistance = 200;
var jumpTargetX = self.x + dx / distance * jumpDistance;
var jumpTargetY = self.y + dy / distance * jumpDistance;
// Keep within bounds
jumpTargetX = Math.max(groundBounds.left, Math.min(groundBounds.right, jumpTargetX));
jumpTargetY = Math.max(groundBounds.top, Math.min(groundBounds.bottom, jumpTargetY));
// Animate jump with tween
tween(character, {
x: jumpTargetX,
y: jumpTargetY
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
character.targetX = character.x;
character.targetY = character.y;
}
});
}
self.lastIntersecting = currentIntersecting;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb
});
/****
* Game Code
****/
//Import tween plugin for smooth monster movement animations
// Create the ground/play area
var ground = LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 0.5
});
ground.x = 2048 / 2;
ground.y = 2732 / 2;
game.addChild(ground);
// Create character in center
var character = new Character();
character.x = 2048 / 2;
character.y = 2732 / 2;
character.targetX = character.x;
character.targetY = character.y;
game.addChild(character);
// Create obstacles around the play area
var obstacles = [];
for (var i = 0; i < 8; i++) {
var obstacle = new Obstacle();
var angle = i / 8 * Math.PI * 2;
var radius = 600;
obstacle.x = 2048 / 2 + Math.cos(angle) * radius;
obstacle.y = 2732 / 2 + Math.sin(angle) * radius;
obstacles.push(obstacle);
game.addChild(obstacle);
}
// Create collectibles
var collectibles = [];
for (var i = 0; i < 12; i++) {
var collectible = new Collectible();
var angle = Math.random() * Math.PI * 2;
var radius = 200 + Math.random() * 400;
collectible.x = 2048 / 2 + Math.cos(angle) * radius;
collectible.y = 2732 / 2 + Math.sin(angle) * radius;
collectibles.push(collectible);
game.addChild(collectible);
}
// Create score display
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Initialize health system
var maxHealth = 10;
var currentHealth = 10;
var healthBars = [];
// Create health bar display
for (var i = 0; i < maxHealth; i++) {
var healthBar = LK.getAsset('healthBar', {
anchorX: 0.5,
anchorY: 0.5
});
healthBar.x = 150 + i * 50;
healthBar.y = 80;
healthBars.push(healthBar);
LK.gui.topLeft.addChild(healthBar);
}
// Create monster that chases the player
var monster = new Monster();
monster.x = 2048 / 2 - 400; // Start to the left of center
monster.y = 2732 / 2 - 400; // Start above center
game.addChild(monster);
// Game bounds (keep character within ground area)
var groundBounds = {
left: 2048 / 2 - 850,
right: 2048 / 2 + 850,
top: 2732 / 2 - 850,
bottom: 2732 / 2 + 850
};
// Track mouse button state and sprint system
var mousePressed = false;
var sprintActive = false;
var sprintSlowdown = false;
var sprintDuration = 900; // 0.9 seconds in milliseconds
var sprintStartTime = 0;
var sprintTimeRemaining = 0;
// Create sprint bar display
var sprintBarBg = LK.getAsset('sprintBarBg', {
anchorX: 0,
anchorY: 0.5
});
sprintBarBg.x = 150;
sprintBarBg.y = 130; // Below health bar
LK.gui.topLeft.addChild(sprintBarBg);
var sprintBarFill = LK.getAsset('sprintBar', {
anchorX: 0,
anchorY: 0.5
});
sprintBarFill.x = 150;
sprintBarFill.y = 130;
LK.gui.topLeft.addChild(sprintBarFill);
// Touch/mouse controls
game.down = function (x, y, obj) {
// Set mouse pressed state and start sprint
mousePressed = true;
if (!sprintActive && !sprintSlowdown) {
sprintActive = true;
sprintStartTime = LK.ticks * (1000 / 60); // Convert to milliseconds
sprintTimeRemaining = sprintDuration;
// Visual indication - tint character green during sprint
var characterGraphics = character.children[0];
tween(characterGraphics, {
tint: 0x00ff00
}, {
duration: 100
});
}
// Set character target to touch position, but keep within bounds
character.targetX = Math.max(groundBounds.left, Math.min(groundBounds.right, x));
character.targetY = Math.max(groundBounds.top, Math.min(groundBounds.bottom, y));
};
game.move = function (x, y, obj) {
// Continue moving to touch position while dragging
character.targetX = Math.max(groundBounds.left, Math.min(groundBounds.right, x));
character.targetY = Math.max(groundBounds.top, Math.min(groundBounds.bottom, y));
};
game.up = function (x, y, obj) {
// Set mouse pressed state to false when button is released
mousePressed = false;
};
// Game update loop
game.update = function () {
// Handle sprint system timing
var currentTime = LK.ticks * (1000 / 60);
if (sprintActive) {
sprintTimeRemaining = sprintDuration - (currentTime - sprintStartTime);
if (sprintTimeRemaining <= 0) {
// Sprint finished - start slowdown period
sprintActive = false;
sprintSlowdown = true;
sprintTimeRemaining = 0;
// Visual indication - tint character red during slowdown
var characterGraphics = character.children[0];
tween(characterGraphics, {
tint: 0xff0000
}, {
duration: 200
});
// Slowdown lasts for 1 second
LK.setTimeout(function () {
sprintSlowdown = false;
// Return to normal color
tween(characterGraphics, {
tint: 0xffffff
}, {
duration: 200
});
}, 1000);
}
}
// Update sprint bar display
var sprintProgress = sprintTimeRemaining / sprintDuration;
if (sprintActive) {
sprintBarFill.scaleX = Math.max(0, sprintProgress);
sprintBarFill.tint = 0x00ff00; // Green during sprint
} else if (sprintSlowdown) {
sprintBarFill.scaleX = 0;
sprintBarFill.tint = 0xff0000; // Red during slowdown
} else {
sprintBarFill.scaleX = 1;
sprintBarFill.tint = 0x00ff00; // Full green when ready
}
// Check for collectible collection
for (var i = collectibles.length - 1; i >= 0; i--) {
var collectible = collectibles[i];
if (!collectible.collected && character.intersects(collectible)) {
collectible.collected = true;
LK.setScore(LK.getScore() + 10);
scoreTxt.setText('Score: ' + LK.getScore());
// Remove collectible
collectible.destroy();
collectibles.splice(i, 1);
// Check win condition
if (collectibles.length === 0) {
LK.showYouWin();
}
}
}
// Check collision with obstacles
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (obstacle.lastIntersecting === undefined) obstacle.lastIntersecting = false;
var currentIntersecting = character.intersects(obstacle);
if (!obstacle.lastIntersecting && currentIntersecting) {
// Just started intersecting - reduce health by 2
currentHealth -= 2;
// Update health bar display
for (var j = 0; j < healthBars.length; j++) {
if (j < currentHealth) {
healthBars[j].alpha = 1.0;
} else {
healthBars[j].alpha = 0.3;
}
}
// Check game over condition
if (currentHealth <= 0) {
LK.showGameOver();
}
// Jump character away from obstacle with tween animation
var dx = character.x - obstacle.x;
var dy = character.y - obstacle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var jumpDistance = 200;
var jumpTargetX = obstacle.x + dx / distance * jumpDistance;
var jumpTargetY = obstacle.y + dy / distance * jumpDistance;
// Keep within bounds
jumpTargetX = Math.max(groundBounds.left, Math.min(groundBounds.right, jumpTargetX));
jumpTargetY = Math.max(groundBounds.top, Math.min(groundBounds.bottom, jumpTargetY));
// Animate jump with tween
tween(character, {
x: jumpTargetX,
y: jumpTargetY
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
character.targetX = character.x;
character.targetY = character.y;
}
});
}
}
if (currentIntersecting) {
// Push character away from obstacle
var dx = character.x - obstacle.x;
var dy = character.y - obstacle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var pushDistance = 100;
character.targetX = obstacle.x + dx / distance * pushDistance;
character.targetY = obstacle.y + dy / distance * pushDistance;
// Keep within bounds
character.targetX = Math.max(groundBounds.left, Math.min(groundBounds.right, character.targetX));
character.targetY = Math.max(groundBounds.top, Math.min(groundBounds.bottom, character.targetY));
}
}
obstacle.lastIntersecting = currentIntersecting;
}
};