/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Hand = Container.expand(function () {
var self = Container.call(this);
var handGraphics = self.attachAsset('hand', {
anchorX: 0.5,
anchorY: 0
});
self.state = 'rising'; // rising, grabbing, retreating
self.speed = 0;
self.targetY = 0;
self.originalY = 0;
self.riseSpeed = 2 + Math.random() * 3;
self.grabSpeed = 8 + Math.random() * 4;
self.retreatSpeed = 5 + Math.random() * 3;
self.waitCounter = 0;
self.waitTime = 30 + Math.floor(Math.random() * 60);
// Randomly adjust hand appearance for variety
handGraphics.rotation = -0.2 + Math.random() * 0.4;
handGraphics.scaleX = 0.7 + Math.random() * 0.6;
handGraphics.alpha = 0.7 + Math.random() * 0.3;
self.update = function () {
switch (self.state) {
case 'rising':
self.y -= self.riseSpeed;
if (self.y <= self.targetY) {
self.y = self.targetY;
self.state = 'waiting';
}
break;
case 'waiting':
self.waitCounter++;
if (self.waitCounter >= self.waitTime) {
self.waitCounter = 0;
self.state = 'grabbing';
}
break;
case 'grabbing':
self.y -= self.grabSpeed;
if (self.y <= -handGraphics.height) {
self.state = 'retreating';
self.targetY = self.originalY;
}
break;
case 'retreating':
self.y += self.retreatSpeed;
if (self.y >= self.originalY) {
self.y = self.originalY;
self.state = 'rising';
self.targetY = getRandomTargetY();
}
break;
}
};
self.grab = function () {
if (self.state !== 'retreating') {
self.state = 'grabbing';
LK.getSound('handGrab').play();
}
};
function getRandomTargetY() {
return 1800 + Math.random() * 500;
}
return self;
});
var Orb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('orb', {
anchorX: 0.5,
anchorY: 0.5
});
self.glow = 0;
self.glowDirection = 0.05;
self.update = function () {
// Glow effect
self.glow += self.glowDirection;
if (self.glow >= 1) {
self.glow = 1;
self.glowDirection = -0.05;
} else if (self.glow <= 0.2) {
self.glow = 0.2;
self.glowDirection = 0.05;
}
// Apply glow as both scale and brightness
orbGraphics.scale.set(0.8 + self.glow * 0.4);
orbGraphics.alpha = 0.6 + self.glow * 0.4;
};
self.collect = function () {
// Expand and fade out effect
tween(orbGraphics, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
var pulseScale = 1.0;
var pulseDirection = 0.01;
self.isAlive = true;
self.orbsCollected = 0;
self.update = function () {
if (!self.isAlive) {
return;
}
// Subtle pulsing effect
pulseScale += pulseDirection;
if (pulseScale >= 1.1) {
pulseScale = 1.1;
pulseDirection = -0.01;
} else if (pulseScale <= 0.9) {
pulseScale = 0.9;
pulseDirection = 0.01;
}
playerGraphics.scale.x = pulseScale;
playerGraphics.scale.y = pulseScale;
};
self.die = function () {
if (!self.isAlive) {
return;
}
self.isAlive = false;
LK.getSound('playerDeath').play();
// Collapse and fade out effect
tween(playerGraphics, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
LK.showGameOver();
}
});
};
self.collectOrb = function () {
self.orbsCollected++;
LK.setScore(self.orbsCollected);
// Flash effect
LK.effects.flashObject(self, 0x00FFFF, 300);
// Play sound
LK.getSound('orbCollect').play();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game state variables
var player;
var orbs = [];
var hands = [];
var lastOrbSpawnTime = 0;
var orbSpawnDelay = 120; // in frames (60 fps = 2 seconds)
var difficulty = 1;
var shadow;
var gameStarted = false;
var scoreTxt;
// Initialize game elements
function initGame() {
// Create shadow overlay with low opacity
shadow = LK.getAsset('shadow', {
anchorX: 0,
anchorY: 0,
alpha: 0.9
});
game.addChild(shadow);
// Create player
player = new Player();
player.x = 2048 / 2;
player.y = 2732 / 2;
game.addChild(player);
// Initialize score display
scoreTxt = new Text2('0', {
size: 120,
fill: 0x00FFFF
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.setText(LK.getScore());
LK.gui.top.addChild(scoreTxt);
// Initialize tutorial text (disappears after a few seconds)
var tutorialText = new Text2("Collect the glowing orbs.\nAvoid the hands.", {
size: 80,
fill: 0xFFFFFF
});
tutorialText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(tutorialText);
// Fade out tutorial text after 4 seconds
LK.setTimeout(function () {
tween(tutorialText, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
tutorialText.destroy();
}
});
}, 4000);
// Start ambient music
LK.playMusic('creepyAmbience', {
fade: {
start: 0,
end: 0.4,
duration: 3000
}
});
gameStarted = true;
}
// Create a new orb at a random position
function spawnOrb() {
var newOrb = new Orb();
// Place orb in a random position, but keep it away from edges
newOrb.x = 200 + Math.random() * (2048 - 400);
newOrb.y = 200 + Math.random() * (2732 - 400);
// Keep orbs away from player's initial position
var dx = newOrb.x - player.x;
var dy = newOrb.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 200) {
// Too close to player, adjust position
newOrb.x = newOrb.x + (dx > 0 ? 200 : -200);
newOrb.y = newOrb.y + (dy > 0 ? 200 : -200);
}
game.addChild(newOrb);
orbs.push(newOrb);
lastOrbSpawnTime = LK.ticks;
}
// Create a new hand at a random position
function spawnHand() {
var newHand = new Hand();
// Place hand at a random horizontal position at the bottom of the screen
newHand.x = 100 + Math.random() * (2048 - 200);
newHand.y = 2732 + 100; // Start below the screen
newHand.originalY = newHand.y;
newHand.targetY = 1800 + Math.random() * 500; // Target y to rise to
game.addChild(newHand);
hands.push(newHand);
return newHand;
}
// Handle player movement
var isDragging = false;
game.down = function (x, y, obj) {
if (!gameStarted) {
initGame();
}
if (!player.isAlive) {
return;
}
isDragging = true;
player.x = x;
player.y = y;
};
game.move = function (x, y, obj) {
if (!player.isAlive || !isDragging) {
return;
}
player.x = x;
player.y = y;
};
game.up = function (x, y, obj) {
isDragging = false;
};
// Main game update loop
game.update = function () {
if (!gameStarted) {
initGame();
return;
}
// Spawn orbs on a timer
if (LK.ticks - lastOrbSpawnTime > orbSpawnDelay && orbs.length < 10) {
spawnOrb();
// Make orbs spawn faster as the game progresses
orbSpawnDelay = Math.max(60, 120 - player.orbsCollected * 2);
}
// Spawn hands based on difficulty
if (LK.ticks % Math.max(60, 180 - difficulty * 15) === 0 && hands.length < 10 + difficulty) {
spawnHand();
}
// Update difficulty based on orbs collected
difficulty = Math.floor(player.orbsCollected / 5) + 1;
// Process orb collection
for (var i = orbs.length - 1; i >= 0; i--) {
var orb = orbs[i];
if (player.isAlive && player.intersects(orb)) {
player.collectOrb();
orb.collect();
orbs.splice(i, 1);
// Increase difficulty
if (player.orbsCollected % 5 === 0) {
// Spawn extra hands when difficulty increases
for (var j = 0; j < 2; j++) {
var hand = spawnHand();
hand.grab(); // Make it immediately try to grab
}
// Flash screen to indicate difficulty increase
LK.effects.flashScreen(0x880000, 300);
}
// Update score display
scoreTxt.setText(LK.getScore());
// Check for win condition (collect 30 orbs)
if (player.orbsCollected >= 30) {
LK.showYouWin();
}
}
}
// Process hand movement and grabbing
for (var i = hands.length - 1; i >= 0; i--) {
var hand = hands[i];
// Check for collision with player
if (player.isAlive && player.intersects(hand) && (hand.state === 'rising' || hand.state === 'waiting' || hand.state === 'grabbing')) {
player.die();
}
// Remove hands that have been off-screen for too long
if (hand.state === 'retreating' && hand.y > hand.originalY + 300) {
hand.destroy();
hands.splice(i, 1);
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Hand = Container.expand(function () {
var self = Container.call(this);
var handGraphics = self.attachAsset('hand', {
anchorX: 0.5,
anchorY: 0
});
self.state = 'rising'; // rising, grabbing, retreating
self.speed = 0;
self.targetY = 0;
self.originalY = 0;
self.riseSpeed = 2 + Math.random() * 3;
self.grabSpeed = 8 + Math.random() * 4;
self.retreatSpeed = 5 + Math.random() * 3;
self.waitCounter = 0;
self.waitTime = 30 + Math.floor(Math.random() * 60);
// Randomly adjust hand appearance for variety
handGraphics.rotation = -0.2 + Math.random() * 0.4;
handGraphics.scaleX = 0.7 + Math.random() * 0.6;
handGraphics.alpha = 0.7 + Math.random() * 0.3;
self.update = function () {
switch (self.state) {
case 'rising':
self.y -= self.riseSpeed;
if (self.y <= self.targetY) {
self.y = self.targetY;
self.state = 'waiting';
}
break;
case 'waiting':
self.waitCounter++;
if (self.waitCounter >= self.waitTime) {
self.waitCounter = 0;
self.state = 'grabbing';
}
break;
case 'grabbing':
self.y -= self.grabSpeed;
if (self.y <= -handGraphics.height) {
self.state = 'retreating';
self.targetY = self.originalY;
}
break;
case 'retreating':
self.y += self.retreatSpeed;
if (self.y >= self.originalY) {
self.y = self.originalY;
self.state = 'rising';
self.targetY = getRandomTargetY();
}
break;
}
};
self.grab = function () {
if (self.state !== 'retreating') {
self.state = 'grabbing';
LK.getSound('handGrab').play();
}
};
function getRandomTargetY() {
return 1800 + Math.random() * 500;
}
return self;
});
var Orb = Container.expand(function () {
var self = Container.call(this);
var orbGraphics = self.attachAsset('orb', {
anchorX: 0.5,
anchorY: 0.5
});
self.glow = 0;
self.glowDirection = 0.05;
self.update = function () {
// Glow effect
self.glow += self.glowDirection;
if (self.glow >= 1) {
self.glow = 1;
self.glowDirection = -0.05;
} else if (self.glow <= 0.2) {
self.glow = 0.2;
self.glowDirection = 0.05;
}
// Apply glow as both scale and brightness
orbGraphics.scale.set(0.8 + self.glow * 0.4);
orbGraphics.alpha = 0.6 + self.glow * 0.4;
};
self.collect = function () {
// Expand and fade out effect
tween(orbGraphics, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
var pulseScale = 1.0;
var pulseDirection = 0.01;
self.isAlive = true;
self.orbsCollected = 0;
self.update = function () {
if (!self.isAlive) {
return;
}
// Subtle pulsing effect
pulseScale += pulseDirection;
if (pulseScale >= 1.1) {
pulseScale = 1.1;
pulseDirection = -0.01;
} else if (pulseScale <= 0.9) {
pulseScale = 0.9;
pulseDirection = 0.01;
}
playerGraphics.scale.x = pulseScale;
playerGraphics.scale.y = pulseScale;
};
self.die = function () {
if (!self.isAlive) {
return;
}
self.isAlive = false;
LK.getSound('playerDeath').play();
// Collapse and fade out effect
tween(playerGraphics, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
LK.showGameOver();
}
});
};
self.collectOrb = function () {
self.orbsCollected++;
LK.setScore(self.orbsCollected);
// Flash effect
LK.effects.flashObject(self, 0x00FFFF, 300);
// Play sound
LK.getSound('orbCollect').play();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game state variables
var player;
var orbs = [];
var hands = [];
var lastOrbSpawnTime = 0;
var orbSpawnDelay = 120; // in frames (60 fps = 2 seconds)
var difficulty = 1;
var shadow;
var gameStarted = false;
var scoreTxt;
// Initialize game elements
function initGame() {
// Create shadow overlay with low opacity
shadow = LK.getAsset('shadow', {
anchorX: 0,
anchorY: 0,
alpha: 0.9
});
game.addChild(shadow);
// Create player
player = new Player();
player.x = 2048 / 2;
player.y = 2732 / 2;
game.addChild(player);
// Initialize score display
scoreTxt = new Text2('0', {
size: 120,
fill: 0x00FFFF
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.setText(LK.getScore());
LK.gui.top.addChild(scoreTxt);
// Initialize tutorial text (disappears after a few seconds)
var tutorialText = new Text2("Collect the glowing orbs.\nAvoid the hands.", {
size: 80,
fill: 0xFFFFFF
});
tutorialText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(tutorialText);
// Fade out tutorial text after 4 seconds
LK.setTimeout(function () {
tween(tutorialText, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
tutorialText.destroy();
}
});
}, 4000);
// Start ambient music
LK.playMusic('creepyAmbience', {
fade: {
start: 0,
end: 0.4,
duration: 3000
}
});
gameStarted = true;
}
// Create a new orb at a random position
function spawnOrb() {
var newOrb = new Orb();
// Place orb in a random position, but keep it away from edges
newOrb.x = 200 + Math.random() * (2048 - 400);
newOrb.y = 200 + Math.random() * (2732 - 400);
// Keep orbs away from player's initial position
var dx = newOrb.x - player.x;
var dy = newOrb.y - player.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 200) {
// Too close to player, adjust position
newOrb.x = newOrb.x + (dx > 0 ? 200 : -200);
newOrb.y = newOrb.y + (dy > 0 ? 200 : -200);
}
game.addChild(newOrb);
orbs.push(newOrb);
lastOrbSpawnTime = LK.ticks;
}
// Create a new hand at a random position
function spawnHand() {
var newHand = new Hand();
// Place hand at a random horizontal position at the bottom of the screen
newHand.x = 100 + Math.random() * (2048 - 200);
newHand.y = 2732 + 100; // Start below the screen
newHand.originalY = newHand.y;
newHand.targetY = 1800 + Math.random() * 500; // Target y to rise to
game.addChild(newHand);
hands.push(newHand);
return newHand;
}
// Handle player movement
var isDragging = false;
game.down = function (x, y, obj) {
if (!gameStarted) {
initGame();
}
if (!player.isAlive) {
return;
}
isDragging = true;
player.x = x;
player.y = y;
};
game.move = function (x, y, obj) {
if (!player.isAlive || !isDragging) {
return;
}
player.x = x;
player.y = y;
};
game.up = function (x, y, obj) {
isDragging = false;
};
// Main game update loop
game.update = function () {
if (!gameStarted) {
initGame();
return;
}
// Spawn orbs on a timer
if (LK.ticks - lastOrbSpawnTime > orbSpawnDelay && orbs.length < 10) {
spawnOrb();
// Make orbs spawn faster as the game progresses
orbSpawnDelay = Math.max(60, 120 - player.orbsCollected * 2);
}
// Spawn hands based on difficulty
if (LK.ticks % Math.max(60, 180 - difficulty * 15) === 0 && hands.length < 10 + difficulty) {
spawnHand();
}
// Update difficulty based on orbs collected
difficulty = Math.floor(player.orbsCollected / 5) + 1;
// Process orb collection
for (var i = orbs.length - 1; i >= 0; i--) {
var orb = orbs[i];
if (player.isAlive && player.intersects(orb)) {
player.collectOrb();
orb.collect();
orbs.splice(i, 1);
// Increase difficulty
if (player.orbsCollected % 5 === 0) {
// Spawn extra hands when difficulty increases
for (var j = 0; j < 2; j++) {
var hand = spawnHand();
hand.grab(); // Make it immediately try to grab
}
// Flash screen to indicate difficulty increase
LK.effects.flashScreen(0x880000, 300);
}
// Update score display
scoreTxt.setText(LK.getScore());
// Check for win condition (collect 30 orbs)
if (player.orbsCollected >= 30) {
LK.showYouWin();
}
}
}
// Process hand movement and grabbing
for (var i = hands.length - 1; i >= 0; i--) {
var hand = hands[i];
// Check for collision with player
if (player.isAlive && player.intersects(hand) && (hand.state === 'rising' || hand.state === 'waiting' || hand.state === 'grabbing')) {
player.die();
}
// Remove hands that have been off-screen for too long
if (hand.state === 'retreating' && hand.y > hand.originalY + 300) {
hand.destroy();
hands.splice(i, 1);
}
}
};
hand. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
player. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
orb. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
shadow. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows