/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Collectible = Container.expand(function (type) {
var self = Container.call(this);
self.type = 'coin';
var assetId = 'coin';
var collectibleGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.update = function () {
self.x -= gameSpeed;
// Floating animation
self.y += Math.sin(LK.ticks / 10) * 0.5;
// Rotation for coins
collectibleGraphics.rotation += 0.05;
// Remove if off screen
if (self.x < -100) {
self.destroy();
}
};
return self;
});
var Giantess = Container.expand(function () {
var self = Container.call(this);
var giantessGraphics = self.attachAsset('giantess', {
anchorX: 0.5,
anchorY: 0.5
});
self.baseSpeed = 4.2; // Slightly slower than player (gameSpeed=5)
self.speed = self.baseSpeed;
self.maxSpeed = 7;
self.distanceFromPlayer = 400;
self.update = function () {
// Follow player with increasing difficulty
var targetX = hero.x - self.distanceFromPlayer;
self.x += (targetX - self.x) * 0.045; // Move slightly faster than before
// Set y so foot always touches ground (no walking animation)
self.y = groundY - giantessGraphics.height / 2;
giantessGraphics.scale.y = 1;
giantessGraphics.scale.x = 1;
};
self.increaseSpeed = function () {
self.speed = Math.min(self.maxSpeed, self.speed + 0.1);
self.distanceFromPlayer = Math.max(200, self.distanceFromPlayer - 5);
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityY = 0;
self.gravity = 0.8;
self.jumpForce = -20;
self.isJumping = false;
self.isInvincible = false;
self.jump = function () {
if (!self.isJumping) {
self.velocityY = self.jumpForce;
self.isJumping = true;
LK.getSound('jump').play();
}
};
self.makeInvincible = function (duration) {
self.isInvincible = true;
// Flash effect for invincibility
var flashInterval = LK.setInterval(function () {
heroGraphics.alpha = heroGraphics.alpha === 1 ? 0.3 : 1;
}, 100);
LK.setTimeout(function () {
self.isInvincible = false;
heroGraphics.alpha = 1;
LK.clearInterval(flashInterval);
}, duration);
};
self.update = function () {
// Apply gravity
self.velocityY += self.gravity;
self.y += self.velocityY;
// Check if on ground
if (self.y >= groundY - heroGraphics.height / 2) {
self.y = groundY - heroGraphics.height / 2;
self.velocityY = 0;
self.isJumping = false;
}
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.passed = false;
self.update = function () {
// Move obstacle to the left
self.x -= gameSpeed;
// Remove if off screen
if (self.x < -150) {
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
// Obstacle class removed
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var gameSpeed = 5;
var score = 0;
var coins = 0;
var groundY = 2500;
var obstacles = []; // (obstacles array kept for compatibility, but will not be used)
var collectibles = [];
var gameRunning = true;
var difficulty = 1;
var distanceTraveled = 0;
// Create ground
var ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: groundY
}));
// Create hero
var hero = game.addChild(new Hero());
hero.x = 400;
hero.y = groundY - 100;
// Create giantess
var giantess = game.addChild(new Giantess());
giantess.x = -100;
giantess.y = groundY - 350;
// Setup UI
var scoreTxt = new Text2('Distance: 0m', {
size: 70,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 50;
var coinsTxt = new Text2('Coins: 0', {
size: 70,
fill: 0xF1C40F
});
coinsTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(coinsTxt);
coinsTxt.x = -300;
coinsTxt.y = 50;
// Play background music
LK.playMusic('background_music');
// Game functions
// Spawns an obstacle spaced out from the last one
var lastObstacleX = 0;
function spawnObstacle() {
// Only spawn if far enough from last obstacle
var minSpacing = 700 + Math.random() * 300; // 700-1000px apart
if (obstacles.length > 0) {
var lastObs = obstacles[obstacles.length - 1];
if (lastObs.x > 2048 - minSpacing) {
return;
}
}
var obstacle = new Obstacle();
obstacle.x = 2200;
obstacle.y = groundY - 50; // Place on ground
game.addChild(obstacle);
obstacles.push(obstacle);
lastObstacleX = obstacle.x;
}
function spawnCollectible() {
var collectible = new Collectible('coin');
collectible.x = 2200 + Math.random() * 100;
// Position higher for jumps or on ground
if (Math.random() < 0.6) {
collectible.y = groundY - 100 - Math.random() * 150;
} else {
collectible.y = groundY - collectible.height / 2;
}
game.addChild(collectible);
collectibles.push(collectible);
}
function updateScore() {
distanceTraveled += gameSpeed / 30;
score = Math.floor(distanceTraveled);
scoreTxt.setText('Distance: ' + score + 'm');
// Increase difficulty over time
if (score % 200 === 0 && score > 0 && gameSpeed < 12) {
gameSpeed += 0.5;
difficulty += 0.2;
giantess.increaseSpeed();
}
// Continue increasing difficulty as game progresses beyond 1000m
}
function updateCoins() {
coinsTxt.setText('Coins: ' + coins);
}
function checkCollisions() {
// Check obstacle collisions
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
if (hero.intersects(obs) && !hero.isInvincible) {
// Only slow down if not already slowed by this obstacle
if (!obs.hasSlowedHero) {
obs.hasSlowedHero = true;
// Temporarily slow down the player
var originalSpeed = gameSpeed;
gameSpeed = Math.max(2, gameSpeed - 2);
// Optional: flash hero to indicate slow
hero.makeInvincible(700);
// Temporarily speed up the giantess
var originalGiantessSpeed = giantess.speed;
giantess.speed = Math.min(giantess.maxSpeed, giantess.speed + 2);
// Use tween to smoothly animate giantess speed increase effect
tween(giantess, {
distanceFromPlayer: Math.max(150, giantess.distanceFromPlayer - 50)
}, {
duration: 200,
easing: tween.easeOut
});
LK.setTimeout(function () {
gameSpeed = originalSpeed;
giantess.speed = originalGiantessSpeed;
// Tween back to normal distance
tween(giantess, {
distanceFromPlayer: Math.min(400, giantess.distanceFromPlayer + 50)
}, {
duration: 500,
easing: tween.easeInOut
});
}, 700);
}
} else {
// Reset flag if not intersecting, so future collisions can slow again
obs.hasSlowedHero = false;
}
}
// Check collectible collisions
for (var j = collectibles.length - 1; j >= 0; j--) {
if (hero.intersects(collectibles[j]) && !collectibles[j].collected) {
collectibles[j].collected = true;
// Collect coin
coins++;
updateCoins();
LK.getSound('coin_collect').play();
// Remove the collectible
collectibles[j].destroy();
collectibles.splice(j, 1);
}
}
// Check giantess collision - Game Over
if (hero.intersects(giantess) && !hero.isInvincible) {
gameOver();
}
}
function gameOver() {
gameRunning = false;
// Save high score
if (score > storage.highScore) {
storage.highScore = score;
}
// Update score with final
LK.setScore(score);
// Flash screen red and show game over
LK.effects.flashScreen(0xff0000, 1000);
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
// Input handlers
game.down = function (x, y, obj) {
// Jump when touching the screen
hero.jump();
};
// Main game loop
game.update = function () {
if (!gameRunning) return;
// Update game objects
hero.update();
giantess.update();
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].update();
if (!obstacles[i].parent) {
obstacles.splice(i, 1);
}
}
// Spawn obstacles spaced out
if (LK.ticks % Math.floor(120 / difficulty) === 0) {
spawnObstacle();
}
// Update collectibles
for (var j = collectibles.length - 1; j >= 0; j--) {
collectibles[j].update();
if (!collectibles[j].parent) {
collectibles.splice(j, 1);
}
}
// Spawn collectibles
if (LK.ticks % Math.floor(60 / difficulty) === 0) {
spawnCollectible();
}
// Update score
updateScore();
// Check collisions
checkCollisions();
// Update game state
if (hero.x < 100) {
hero.x = 100; // Keep hero from moving off screen to the left
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Collectible = Container.expand(function (type) {
var self = Container.call(this);
self.type = 'coin';
var assetId = 'coin';
var collectibleGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.update = function () {
self.x -= gameSpeed;
// Floating animation
self.y += Math.sin(LK.ticks / 10) * 0.5;
// Rotation for coins
collectibleGraphics.rotation += 0.05;
// Remove if off screen
if (self.x < -100) {
self.destroy();
}
};
return self;
});
var Giantess = Container.expand(function () {
var self = Container.call(this);
var giantessGraphics = self.attachAsset('giantess', {
anchorX: 0.5,
anchorY: 0.5
});
self.baseSpeed = 4.2; // Slightly slower than player (gameSpeed=5)
self.speed = self.baseSpeed;
self.maxSpeed = 7;
self.distanceFromPlayer = 400;
self.update = function () {
// Follow player with increasing difficulty
var targetX = hero.x - self.distanceFromPlayer;
self.x += (targetX - self.x) * 0.045; // Move slightly faster than before
// Set y so foot always touches ground (no walking animation)
self.y = groundY - giantessGraphics.height / 2;
giantessGraphics.scale.y = 1;
giantessGraphics.scale.x = 1;
};
self.increaseSpeed = function () {
self.speed = Math.min(self.maxSpeed, self.speed + 0.1);
self.distanceFromPlayer = Math.max(200, self.distanceFromPlayer - 5);
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityY = 0;
self.gravity = 0.8;
self.jumpForce = -20;
self.isJumping = false;
self.isInvincible = false;
self.jump = function () {
if (!self.isJumping) {
self.velocityY = self.jumpForce;
self.isJumping = true;
LK.getSound('jump').play();
}
};
self.makeInvincible = function (duration) {
self.isInvincible = true;
// Flash effect for invincibility
var flashInterval = LK.setInterval(function () {
heroGraphics.alpha = heroGraphics.alpha === 1 ? 0.3 : 1;
}, 100);
LK.setTimeout(function () {
self.isInvincible = false;
heroGraphics.alpha = 1;
LK.clearInterval(flashInterval);
}, duration);
};
self.update = function () {
// Apply gravity
self.velocityY += self.gravity;
self.y += self.velocityY;
// Check if on ground
if (self.y >= groundY - heroGraphics.height / 2) {
self.y = groundY - heroGraphics.height / 2;
self.velocityY = 0;
self.isJumping = false;
}
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
self.passed = false;
self.update = function () {
// Move obstacle to the left
self.x -= gameSpeed;
// Remove if off screen
if (self.x < -150) {
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
// Obstacle class removed
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var gameSpeed = 5;
var score = 0;
var coins = 0;
var groundY = 2500;
var obstacles = []; // (obstacles array kept for compatibility, but will not be used)
var collectibles = [];
var gameRunning = true;
var difficulty = 1;
var distanceTraveled = 0;
// Create ground
var ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: groundY
}));
// Create hero
var hero = game.addChild(new Hero());
hero.x = 400;
hero.y = groundY - 100;
// Create giantess
var giantess = game.addChild(new Giantess());
giantess.x = -100;
giantess.y = groundY - 350;
// Setup UI
var scoreTxt = new Text2('Distance: 0m', {
size: 70,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 50;
var coinsTxt = new Text2('Coins: 0', {
size: 70,
fill: 0xF1C40F
});
coinsTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(coinsTxt);
coinsTxt.x = -300;
coinsTxt.y = 50;
// Play background music
LK.playMusic('background_music');
// Game functions
// Spawns an obstacle spaced out from the last one
var lastObstacleX = 0;
function spawnObstacle() {
// Only spawn if far enough from last obstacle
var minSpacing = 700 + Math.random() * 300; // 700-1000px apart
if (obstacles.length > 0) {
var lastObs = obstacles[obstacles.length - 1];
if (lastObs.x > 2048 - minSpacing) {
return;
}
}
var obstacle = new Obstacle();
obstacle.x = 2200;
obstacle.y = groundY - 50; // Place on ground
game.addChild(obstacle);
obstacles.push(obstacle);
lastObstacleX = obstacle.x;
}
function spawnCollectible() {
var collectible = new Collectible('coin');
collectible.x = 2200 + Math.random() * 100;
// Position higher for jumps or on ground
if (Math.random() < 0.6) {
collectible.y = groundY - 100 - Math.random() * 150;
} else {
collectible.y = groundY - collectible.height / 2;
}
game.addChild(collectible);
collectibles.push(collectible);
}
function updateScore() {
distanceTraveled += gameSpeed / 30;
score = Math.floor(distanceTraveled);
scoreTxt.setText('Distance: ' + score + 'm');
// Increase difficulty over time
if (score % 200 === 0 && score > 0 && gameSpeed < 12) {
gameSpeed += 0.5;
difficulty += 0.2;
giantess.increaseSpeed();
}
// Continue increasing difficulty as game progresses beyond 1000m
}
function updateCoins() {
coinsTxt.setText('Coins: ' + coins);
}
function checkCollisions() {
// Check obstacle collisions
for (var i = obstacles.length - 1; i >= 0; i--) {
var obs = obstacles[i];
if (hero.intersects(obs) && !hero.isInvincible) {
// Only slow down if not already slowed by this obstacle
if (!obs.hasSlowedHero) {
obs.hasSlowedHero = true;
// Temporarily slow down the player
var originalSpeed = gameSpeed;
gameSpeed = Math.max(2, gameSpeed - 2);
// Optional: flash hero to indicate slow
hero.makeInvincible(700);
// Temporarily speed up the giantess
var originalGiantessSpeed = giantess.speed;
giantess.speed = Math.min(giantess.maxSpeed, giantess.speed + 2);
// Use tween to smoothly animate giantess speed increase effect
tween(giantess, {
distanceFromPlayer: Math.max(150, giantess.distanceFromPlayer - 50)
}, {
duration: 200,
easing: tween.easeOut
});
LK.setTimeout(function () {
gameSpeed = originalSpeed;
giantess.speed = originalGiantessSpeed;
// Tween back to normal distance
tween(giantess, {
distanceFromPlayer: Math.min(400, giantess.distanceFromPlayer + 50)
}, {
duration: 500,
easing: tween.easeInOut
});
}, 700);
}
} else {
// Reset flag if not intersecting, so future collisions can slow again
obs.hasSlowedHero = false;
}
}
// Check collectible collisions
for (var j = collectibles.length - 1; j >= 0; j--) {
if (hero.intersects(collectibles[j]) && !collectibles[j].collected) {
collectibles[j].collected = true;
// Collect coin
coins++;
updateCoins();
LK.getSound('coin_collect').play();
// Remove the collectible
collectibles[j].destroy();
collectibles.splice(j, 1);
}
}
// Check giantess collision - Game Over
if (hero.intersects(giantess) && !hero.isInvincible) {
gameOver();
}
}
function gameOver() {
gameRunning = false;
// Save high score
if (score > storage.highScore) {
storage.highScore = score;
}
// Update score with final
LK.setScore(score);
// Flash screen red and show game over
LK.effects.flashScreen(0xff0000, 1000);
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
// Input handlers
game.down = function (x, y, obj) {
// Jump when touching the screen
hero.jump();
};
// Main game loop
game.update = function () {
if (!gameRunning) return;
// Update game objects
hero.update();
giantess.update();
// Update obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].update();
if (!obstacles[i].parent) {
obstacles.splice(i, 1);
}
}
// Spawn obstacles spaced out
if (LK.ticks % Math.floor(120 / difficulty) === 0) {
spawnObstacle();
}
// Update collectibles
for (var j = collectibles.length - 1; j >= 0; j--) {
collectibles[j].update();
if (!collectibles[j].parent) {
collectibles.splice(j, 1);
}
}
// Spawn collectibles
if (LK.ticks % Math.floor(60 / difficulty) === 0) {
spawnCollectible();
}
// Update score
updateScore();
// Check collisions
checkCollisions();
// Update game state
if (hero.x < 100) {
hero.x = 100; // Keep hero from moving off screen to the left
}
};