/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var DialogueBox = Container.expand(function () { var self = Container.call(this); // Create dialogue bubble background var dialogueBubble = self.attachAsset('dialogueBubble', { anchorX: 0.5, anchorY: 0.5, width: 800, height: 150 }); var dialogueText = new Text2('', { size: 60, fill: 0xFF4444 }); dialogueText.anchor.set(0.5, 0.5); self.addChild(dialogueText); self.showMessage = function (message, duration) { dialogueText.setText(message); self.alpha = 1; if (duration) { LK.setTimeout(function () { tween(self, { alpha: 0 }, { duration: 500 }); }, duration); } }; self.hide = function () { tween(self, { alpha: 0 }, { duration: 500 }); }; return self; }); var Monster = Container.expand(function () { var self = Container.call(this); var monsterGraphics = self.attachAsset('monster', { anchorX: 0.5, anchorY: 0.5 }); self.huntingPlayer = null; self.teleportTimer = 0; self.teleportDelay = 180; // 3 seconds at 60fps self.startHunting = function (player) { self.huntingPlayer = player; self.teleportTimer = 0; }; self.teleportToBlockPlayer = function () { if (!self.huntingPlayer) return; // Calculate escape routes and block them var playerX = self.huntingPlayer.x; var playerY = self.huntingPlayer.y; // Choose a strategic position to block escape var blockPositions = [{ x: playerX + 200, y: playerY }, { x: playerX - 200, y: playerY }, { x: playerX, y: playerY + 200 }, { x: playerX, y: playerY - 200 }, { x: playerX + 150, y: playerY + 150 }, { x: playerX - 150, y: playerY - 150 }]; // Filter valid positions (within bounds) var validPositions = blockPositions.filter(function (pos) { return pos.x > 100 && pos.x < 1948 && pos.y > 100 && pos.y < 2632; }); if (validPositions.length > 0) { var chosenPos = validPositions[Math.floor(Math.random() * validPositions.length)]; self.x = chosenPos.x; self.y = chosenPos.y; LK.getSound('growl').play(); // Teleport effect tween(monsterGraphics, { scaleX: 0.5, scaleY: 0.5, alpha: 0.7 }, { duration: 150, onFinish: function onFinish() { tween(monsterGraphics, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 150 }); } }); } }; self.update = function () { if (self.huntingPlayer) { self.teleportTimer++; if (self.teleportTimer >= self.teleportDelay) { self.teleportToBlockPlayer(); self.teleportTimer = 0; // Decrease delay over time to increase difficulty (slower scaling) if (self.teleportDelay > 90) { self.teleportDelay -= 1; } } } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 12; self.targetX = self.x; self.targetY = self.y; self.moveToPosition = function (x, y) { self.targetX = x; self.targetY = y; LK.getSound('teleport').play(); // Flash effect when teleporting tween(playerGraphics, { alpha: 0.3 }, { duration: 100, onFinish: function onFinish() { tween(playerGraphics, { alpha: 1 }, { duration: 100 }); } }); }; self.update = function () { // Smooth movement towards target var dx = self.targetX - self.x; var dy = self.targetY - self.y; if (Math.abs(dx) > 2) { self.x += dx * 0.25; } if (Math.abs(dy) > 2) { self.y += dy * 0.25; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game state variables var gamePhase = 'darkness'; // 'darkness', 'reveal', 'dialogue', 'chase', 'gameover' var phaseTimer = 0; var survivalTime = 0; // Game objects var player; var monster; var darknessOverlay; var dialogue; var pit; // Initialize darkness overlay darknessOverlay = game.addChild(LK.getAsset('darkness', { anchorX: 0, anchorY: 0, x: 0, y: 0 })); // Initialize player player = game.addChild(new Player()); player.x = 1024; player.y = 1366; player.targetX = player.x; player.targetY = player.y; // Initialize monster (hidden initially) monster = game.addChild(new Monster()); monster.x = 200; monster.y = 200; monster.alpha = 0; // Initialize dialogue dialogue = game.addChild(new DialogueBox()); dialogue.x = 1024; dialogue.y = 400; dialogue.alpha = 0; // Initialize pit (hidden initially) - add to background first pit = LK.getAsset('pit', { anchorX: 0.5, anchorY: 0.5 }); game.addChildAt(pit, 0); // Add at index 0 to put it behind other elements pit.x = 1500; pit.y = 2000; pit.alpha = 0; // Score display var scoreText = new Text2('Survival Time: 0s', { size: 80, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); // Game input handling game.down = function (x, y, obj) { if (gamePhase === 'chase') { // Player teleports to tap location var validX = Math.max(60, Math.min(1988, x)); var validY = Math.max(60, Math.min(2672, y)); player.moveToPosition(validX, validY); } }; // Main game loop game.update = function () { phaseTimer++; if (gamePhase === 'darkness') { // Wait in darkness for 3 seconds if (phaseTimer >= 180) { gamePhase = 'reveal'; phaseTimer = 0; // Start revealing the scene tween(darknessOverlay, { alpha: 0 }, { duration: 2000, onFinish: function onFinish() { gamePhase = 'dialogue'; phaseTimer = 0; } }); // Fade in monster tween(monster, { alpha: 1 }, { duration: 2000 }); // Start atmospheric music LK.playMusic('atmosphere'); } } else if (gamePhase === 'dialogue') { if (phaseTimer === 60) { dialogue.showMessage("You cannot escape me...", 2000); } else if (phaseTimer === 240) { dialogue.showMessage("I see you hiding there!", 2000); } else if (phaseTimer === 420) { dialogue.showMessage("The hunt begins NOW!", 1500); } else if (phaseTimer >= 510) { gamePhase = 'chase'; phaseTimer = 0; survivalTime = 0; dialogue.hide(); monster.startHunting(player); } } else if (gamePhase === 'chase') { survivalTime++; // Update survival time display var seconds = Math.floor(survivalTime / 60); scoreText.setText('Survival Time: ' + seconds + 's'); LK.setScore(seconds); // Check if monster caught player if (player.intersects(monster)) { gamePhase = 'gameover'; LK.effects.flashScreen(0xff0000, 1000); LK.setTimeout(function () { LK.showGameOver(); }, 1000); } // Win condition - survive for 20 seconds if (survivalTime >= 1200) { // 20 seconds * 60 fps - trigger cinematic sequence gamePhase = 'victory'; phaseTimer = 0; // Show pit pit.alpha = 1; // Monster dialogue before falling dialogue.showMessage("What?! No! This cannot be!", 2000); // Monster moves toward pit tween(monster, { x: pit.x, y: pit.y }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { // Monster falls into pit dialogue.showMessage("NOOOOOO!", 1500); // Monster falling animation tween(monster, { scaleX: 0.1, scaleY: 0.1, alpha: 0, y: pit.y + 100 }, { duration: 1500, easing: tween.easeIn, onFinish: function onFinish() { // Cinematic zoom on player - much closer for victory tween(player, { scaleX: 3, scaleY: 3 }, { duration: 1000, easing: tween.easeOut }); // Victory message LK.setTimeout(function () { dialogue.showMessage("I'm finally free!", 2000); // Create door at the edge of screen var door = LK.getAsset('door', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2 }); game.addChild(door); door.x = 2000; door.y = player.y; door.alpha = 0; // Fade in door tween(door, { alpha: 1 }, { duration: 1000 }); // Player walks to door LK.setTimeout(function () { tween(player, { x: door.x - 80, scaleX: 1, scaleY: 1 }, { duration: 2000, easing: tween.linear, onFinish: function onFinish() { // Player walks through door and fades out tween(player, { x: door.x + 50, alpha: 0 }, { duration: 800, onFinish: function onFinish() { LK.setTimeout(function () { LK.showYouWin(); }, 500); } }); } }); }, 1500); }, 1000); } }); } }); } // Increase monster threat over time if (survivalTime % 600 === 0 && survivalTime > 0) { // Every 10 seconds LK.effects.flashScreen(0x660000, 500); } } else if (gamePhase === 'victory') { // Victory cinematic is playing - do nothing but wait // All victory logic is handled by the tween sequences above } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var DialogueBox = Container.expand(function () {
var self = Container.call(this);
// Create dialogue bubble background
var dialogueBubble = self.attachAsset('dialogueBubble', {
anchorX: 0.5,
anchorY: 0.5,
width: 800,
height: 150
});
var dialogueText = new Text2('', {
size: 60,
fill: 0xFF4444
});
dialogueText.anchor.set(0.5, 0.5);
self.addChild(dialogueText);
self.showMessage = function (message, duration) {
dialogueText.setText(message);
self.alpha = 1;
if (duration) {
LK.setTimeout(function () {
tween(self, {
alpha: 0
}, {
duration: 500
});
}, duration);
}
};
self.hide = function () {
tween(self, {
alpha: 0
}, {
duration: 500
});
};
return self;
});
var Monster = Container.expand(function () {
var self = Container.call(this);
var monsterGraphics = self.attachAsset('monster', {
anchorX: 0.5,
anchorY: 0.5
});
self.huntingPlayer = null;
self.teleportTimer = 0;
self.teleportDelay = 180; // 3 seconds at 60fps
self.startHunting = function (player) {
self.huntingPlayer = player;
self.teleportTimer = 0;
};
self.teleportToBlockPlayer = function () {
if (!self.huntingPlayer) return;
// Calculate escape routes and block them
var playerX = self.huntingPlayer.x;
var playerY = self.huntingPlayer.y;
// Choose a strategic position to block escape
var blockPositions = [{
x: playerX + 200,
y: playerY
}, {
x: playerX - 200,
y: playerY
}, {
x: playerX,
y: playerY + 200
}, {
x: playerX,
y: playerY - 200
}, {
x: playerX + 150,
y: playerY + 150
}, {
x: playerX - 150,
y: playerY - 150
}];
// Filter valid positions (within bounds)
var validPositions = blockPositions.filter(function (pos) {
return pos.x > 100 && pos.x < 1948 && pos.y > 100 && pos.y < 2632;
});
if (validPositions.length > 0) {
var chosenPos = validPositions[Math.floor(Math.random() * validPositions.length)];
self.x = chosenPos.x;
self.y = chosenPos.y;
LK.getSound('growl').play();
// Teleport effect
tween(monsterGraphics, {
scaleX: 0.5,
scaleY: 0.5,
alpha: 0.7
}, {
duration: 150,
onFinish: function onFinish() {
tween(monsterGraphics, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 150
});
}
});
}
};
self.update = function () {
if (self.huntingPlayer) {
self.teleportTimer++;
if (self.teleportTimer >= self.teleportDelay) {
self.teleportToBlockPlayer();
self.teleportTimer = 0;
// Decrease delay over time to increase difficulty (slower scaling)
if (self.teleportDelay > 90) {
self.teleportDelay -= 1;
}
}
}
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.targetX = self.x;
self.targetY = self.y;
self.moveToPosition = function (x, y) {
self.targetX = x;
self.targetY = y;
LK.getSound('teleport').play();
// Flash effect when teleporting
tween(playerGraphics, {
alpha: 0.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(playerGraphics, {
alpha: 1
}, {
duration: 100
});
}
});
};
self.update = function () {
// Smooth movement towards target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
if (Math.abs(dx) > 2) {
self.x += dx * 0.25;
}
if (Math.abs(dy) > 2) {
self.y += dy * 0.25;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game state variables
var gamePhase = 'darkness'; // 'darkness', 'reveal', 'dialogue', 'chase', 'gameover'
var phaseTimer = 0;
var survivalTime = 0;
// Game objects
var player;
var monster;
var darknessOverlay;
var dialogue;
var pit;
// Initialize darkness overlay
darknessOverlay = game.addChild(LK.getAsset('darkness', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Initialize player
player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
player.targetX = player.x;
player.targetY = player.y;
// Initialize monster (hidden initially)
monster = game.addChild(new Monster());
monster.x = 200;
monster.y = 200;
monster.alpha = 0;
// Initialize dialogue
dialogue = game.addChild(new DialogueBox());
dialogue.x = 1024;
dialogue.y = 400;
dialogue.alpha = 0;
// Initialize pit (hidden initially) - add to background first
pit = LK.getAsset('pit', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChildAt(pit, 0); // Add at index 0 to put it behind other elements
pit.x = 1500;
pit.y = 2000;
pit.alpha = 0;
// Score display
var scoreText = new Text2('Survival Time: 0s', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Game input handling
game.down = function (x, y, obj) {
if (gamePhase === 'chase') {
// Player teleports to tap location
var validX = Math.max(60, Math.min(1988, x));
var validY = Math.max(60, Math.min(2672, y));
player.moveToPosition(validX, validY);
}
};
// Main game loop
game.update = function () {
phaseTimer++;
if (gamePhase === 'darkness') {
// Wait in darkness for 3 seconds
if (phaseTimer >= 180) {
gamePhase = 'reveal';
phaseTimer = 0;
// Start revealing the scene
tween(darknessOverlay, {
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
gamePhase = 'dialogue';
phaseTimer = 0;
}
});
// Fade in monster
tween(monster, {
alpha: 1
}, {
duration: 2000
});
// Start atmospheric music
LK.playMusic('atmosphere');
}
} else if (gamePhase === 'dialogue') {
if (phaseTimer === 60) {
dialogue.showMessage("You cannot escape me...", 2000);
} else if (phaseTimer === 240) {
dialogue.showMessage("I see you hiding there!", 2000);
} else if (phaseTimer === 420) {
dialogue.showMessage("The hunt begins NOW!", 1500);
} else if (phaseTimer >= 510) {
gamePhase = 'chase';
phaseTimer = 0;
survivalTime = 0;
dialogue.hide();
monster.startHunting(player);
}
} else if (gamePhase === 'chase') {
survivalTime++;
// Update survival time display
var seconds = Math.floor(survivalTime / 60);
scoreText.setText('Survival Time: ' + seconds + 's');
LK.setScore(seconds);
// Check if monster caught player
if (player.intersects(monster)) {
gamePhase = 'gameover';
LK.effects.flashScreen(0xff0000, 1000);
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
// Win condition - survive for 20 seconds
if (survivalTime >= 1200) {
// 20 seconds * 60 fps - trigger cinematic sequence
gamePhase = 'victory';
phaseTimer = 0;
// Show pit
pit.alpha = 1;
// Monster dialogue before falling
dialogue.showMessage("What?! No! This cannot be!", 2000);
// Monster moves toward pit
tween(monster, {
x: pit.x,
y: pit.y
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Monster falls into pit
dialogue.showMessage("NOOOOOO!", 1500);
// Monster falling animation
tween(monster, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0,
y: pit.y + 100
}, {
duration: 1500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Cinematic zoom on player - much closer for victory
tween(player, {
scaleX: 3,
scaleY: 3
}, {
duration: 1000,
easing: tween.easeOut
});
// Victory message
LK.setTimeout(function () {
dialogue.showMessage("I'm finally free!", 2000);
// Create door at the edge of screen
var door = LK.getAsset('door', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
game.addChild(door);
door.x = 2000;
door.y = player.y;
door.alpha = 0;
// Fade in door
tween(door, {
alpha: 1
}, {
duration: 1000
});
// Player walks to door
LK.setTimeout(function () {
tween(player, {
x: door.x - 80,
scaleX: 1,
scaleY: 1
}, {
duration: 2000,
easing: tween.linear,
onFinish: function onFinish() {
// Player walks through door and fades out
tween(player, {
x: door.x + 50,
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
LK.setTimeout(function () {
LK.showYouWin();
}, 500);
}
});
}
});
}, 1500);
}, 1000);
}
});
}
});
}
// Increase monster threat over time
if (survivalTime % 600 === 0 && survivalTime > 0) {
// Every 10 seconds
LK.effects.flashScreen(0x660000, 500);
}
} else if (gamePhase === 'victory') {
// Victory cinematic is playing - do nothing but wait
// All victory logic is handled by the tween sequences above
}
};
Make a dark 2d hallway very dark 8 bit. In-Game asset. 2d. High contrast. No shadows
Make an 8 bit boy with brown hair. In-Game asset. 2d. High contrast. No shadows
Make a dialogue bubble with NO TEXT!. In-Game asset. 2d. High contrast. No shadows
Make a horrifying 8 bit monster that is very scary and disturbing. In-Game asset. 2d. High contrast. No shadows
Make a 8 bit broken pit. In-Game asset. 2d. High contrast. No shadows
Make an 8 bit iron door. In-Game asset. 2d. High contrast. No shadows