/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var NPC = Container.expand(function () {
var self = Container.call(this);
var npcGraphics = self.attachAsset('Player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
// Movement tracking
self.lastX = 0;
self.lastY = 0;
self.isMoving = false;
self.moveThreshold = 2;
self.isDead = false;
self.moveTimer = 0;
self.nextMoveTime = Math.random() * 40 + 20; // Random time between 0.33-1 seconds
// Enhanced bounce animation method identical to Player
self.bounceAnimation = function () {
tween(self, {
scaleX: 1.3,
scaleY: 0.8
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 0.9,
scaleY: 1.2
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
};
// Enhanced transition animation method identical to Player
self.transitionAnimation = function () {
tween(self, {
scaleX: 1.2,
scaleY: 0.9
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.bounceOut
});
}
});
};
self.eliminateNPC = function () {
if (self.isDead) return;
self.isDead = true;
// Play elimination sound
LK.getSound('eliminate').play();
// Create blood splatter effect
for (var i = 0; i < 6; i++) {
var bloodDrop = game.addChild(LK.getAsset('redLight', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
scaleX: 0.1,
scaleY: 0.1
}));
var angle = i / 6 * Math.PI * 2 + (Math.random() - 0.5) * 0.5;
var distance = 80 + Math.random() * 120;
var targetX = self.x + Math.cos(angle) * distance;
var targetY = self.y + Math.sin(angle) * distance;
tween(bloodDrop, {
x: targetX,
y: targetY,
scaleX: 0.2 + Math.random() * 0.15,
scaleY: 0.2 + Math.random() * 0.15,
alpha: 0
}, {
duration: 600 + Math.random() * 300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (bloodDrop.parent) {
bloodDrop.destroy();
}
}
});
}
// Hide NPC after death animation
tween(self, {
alpha: 0
}, {
duration: 1500,
easing: tween.easeOut
});
};
self.update = function () {
if (self.isDead) return;
// Check if NPC reached finish line and stop movement
if (self.y <= 370) {
// NPC reached finish line, stop all movement
self.isMoving = false;
if (!self.reachedFinish) {
self.reachedFinish = true;
self.removeChildren();
npcGraphics = self.attachAsset('Player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Update last position
self.lastX = self.x;
self.lastY = self.y;
return;
}
var deltaX = Math.abs(self.x - self.lastX);
var deltaY = Math.abs(self.y - self.lastY);
var wasMoving = self.isMoving;
self.isMoving = deltaX > self.moveThreshold || deltaY > self.moveThreshold;
// Switch assets based on movement state with enhanced animations
if (wasMoving !== self.isMoving) {
if (self.isMoving) {
// Cancel any pending idle transition
if (self.idleTimeout) {
LK.clearTimeout(self.idleTimeout);
self.idleTimeout = null;
}
// Switch to moving player asset immediately
self.removeChildren();
npcGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Enhanced transition animation identical to Player
self.transitionAnimation();
self.bounceAnimation();
} else {
// Wait 40ms (0.04 seconds) before switching to idle asset
self.idleTimeout = LK.setTimeout(function () {
// Only switch to idle if still not moving
if (!self.isMoving && !self.isDead) {
self.removeChildren();
npcGraphics = self.attachAsset('Player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
}
self.idleTimeout = null;
}, 40);
}
}
// NPC movement logic
if (!isRedLight) {
// During green light, move randomly
self.moveTimer++;
if (self.moveTimer >= self.nextMoveTime) {
var stepSize = 50 + Math.random() * 20;
var newY = self.y - stepSize;
if (newY >= 100) {
self.y = newY;
// Switch to player asset when moving
self.removeChildren();
npcGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Enhanced transition animation identical to Player
self.transitionAnimation();
// Enhanced movement animation with squash and stretch identical to Player
self.bounceAnimation();
// Add additional movement effects like Player
tween(npcGraphics, {
rotation: 0.1
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(npcGraphics, {
rotation: -0.1
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(npcGraphics, {
rotation: 0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
}
self.moveTimer = 0;
self.nextMoveTime = Math.random() * 40 + 20;
}
} else {
// During red light, sometimes make a mistake and move
self.moveTimer++;
var mistakeChance = 0.002; // Much lower chance per frame for NPCs to lose
if (self.moveTimer > 120 && Math.random() < mistakeChance) {
// NPC makes mistake and moves during red light
var stepSize = 40 + Math.random() * 30;
var newY = self.y - stepSize;
if (newY >= 100) {
self.y = newY;
}
// Switch to player asset when moving during mistake
self.removeChildren();
npcGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Enhanced transition animation identical to Player
self.transitionAnimation();
// Enhanced movement animation with squash and stretch identical to Player
self.bounceAnimation();
// Add dramatic mistake animation
tween(npcGraphics, {
tint: 0xff6666,
scaleX: 1.2,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(npcGraphics, {
tint: 0xffffff,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeOut
});
}
});
// Eliminate this NPC for moving during red light
self.eliminateNPC();
}
}
// Continuous idle state checking - if NPC is not moving, ensure it uses idle asset
if (!self.isMoving && !self.isDead && !self.reachedFinish) {
// Check if current asset is not already Player_idle
var currentAsset = self.children[0];
if (currentAsset && currentAsset.texture && !currentAsset.texture.baseTexture.resource.url.includes('Player_idle')) {
// Switch to idle asset immediately
self.removeChildren();
npcGraphics = self.attachAsset('Player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
}
}
// Additional check: when red light is active and NPC is not moving, switch to idle
if (isRedLight && !self.isMoving && !self.isDead && !self.reachedFinish) {
var currentAsset = self.children[0];
if (currentAsset && currentAsset.texture && !currentAsset.texture.baseTexture.resource.url.includes('Player_idle')) {
// Switch to idle asset immediately during red light
self.removeChildren();
npcGraphics = self.attachAsset('Player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
}
}
// Update last position
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('Player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
// Movement tracking
self.lastX = 0;
self.lastY = 0;
self.isMoving = false;
self.moveThreshold = 2; // Minimum movement to detect
// Enhanced bounce animation method
self.bounceAnimation = function () {
tween(self, {
scaleX: 1.3,
scaleY: 0.8
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 0.9,
scaleY: 1.2
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
};
self.update = function () {
// Check if player is moving
var deltaX = Math.abs(self.x - self.lastX);
var deltaY = Math.abs(self.y - self.lastY);
var wasMoving = self.isMoving;
self.isMoving = deltaX > self.moveThreshold || deltaY > self.moveThreshold;
// Switch assets based on movement state
if (wasMoving !== self.isMoving) {
if (self.isMoving) {
// Cancel any pending idle transition
if (self.idleTimeout) {
tween.stop(self.idleTimeout);
self.idleTimeout = null;
}
// Switch to moving player asset
self.removeChildren();
playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Enhanced transition animation
self.bounceAnimation();
} else {
// Wait 300ms before switching to idle asset
self.idleTimeout = {};
tween(self.idleTimeout, {}, {
duration: 300,
onFinish: function onFinish() {
// Only switch to idle if still not moving
if (!self.isMoving) {
self.removeChildren();
playerGraphics = self.attachAsset('Player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
}
self.idleTimeout = null;
}
});
}
}
// Update last position
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
/****
* Initialize Game
****/
// Game state variables
var game = new LK.Game({
backgroundColor: 0x2c2c2c // Dark grey background for dramatic effect
});
/****
* Game Code
****/
// Game state variables
// Traffic light states
// Player character
// Finish line
// Sound effects
var isRedLight = false;
var lightChangeTimer = 0;
var nextLightChange = 180; // 3 seconds at 60fps
var player;
var trafficLight;
var finishLine;
var isDragging = false;
var gameStarted = false;
var showingMenu = true;
var npcs = [];
var gamePaused = false;
var showingGameMenu = false;
// Swipe detection variables declared in down handler
// Create arena background
var arenaBackground = game.addChild(LK.getAsset('Arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 3.5,
scaleY: 4.5
}));
// Create traffic light at center
trafficLight = game.addChild(LK.getAsset('greenLight', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
}));
// Create finish line at top
finishLine = game.addChild(LK.getAsset('finishLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 350,
alpha: 1
}));
// Create main menu elements
var logoImage = game.addChild(LK.getAsset('Logo', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 900,
scaleX: 5.0,
scaleY: 5.0
}));
var playButton = game.addChild(LK.getAsset('Play', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1600,
scaleX: 6.0,
scaleY: 6.0
}));
// Create countdown display (initially hidden)
var countdownText = new Text2('3', {
size: 600,
fill: 0xFFFFFF,
font: "'Impact', 'Arial Black', sans-serif"
});
countdownText.anchor.set(0.5, 0.5);
countdownText.x = 2048 / 2;
countdownText.y = 2732 / 2;
countdownText.alpha = 0;
game.addChild(countdownText);
// Create player at bottom with countdown delay
player = new Player();
player.x = 2048 / 2;
player.y = 2500;
player.alpha = 0; // Start invisible
game.addChild(player); // Add player to game scene immediately
// Start countdown animation
function startCountdown() {
// Show "3"
countdownText.setText('3');
countdownText.alpha = 1;
countdownText.scaleX = 0.1;
countdownText.scaleY = 0.1;
countdownText.tint = 0x00ff00; // Green for "3"
countdownText.rotation = -0.5;
tween(countdownText, {
scaleX: 1.8,
scaleY: 1.8,
rotation: 0,
alpha: 0
}, {
duration: 1000,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Show "2"
countdownText.setText('2');
countdownText.alpha = 1;
countdownText.scaleX = 0.1;
countdownText.scaleY = 0.1;
countdownText.tint = 0xff0000; // Red for "2"
countdownText.rotation = 0.5;
tween(countdownText, {
scaleX: 1.8,
scaleY: 1.8,
rotation: 0,
alpha: 0
}, {
duration: 1000,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Show "1"
countdownText.setText('1');
countdownText.alpha = 1;
countdownText.scaleX = 0.1;
countdownText.scaleY = 0.1;
countdownText.tint = 0xff69b4; // Pink for "1"
countdownText.rotation = -0.3;
tween(countdownText, {
scaleX: 1.8,
scaleY: 1.8,
rotation: 0,
alpha: 0
}, {
duration: 1000,
easing: tween.backOut,
onFinish: function onFinish() {
// Show "GO!"
countdownText.setText('GO!');
countdownText.alpha = 1;
countdownText.scaleX = 0.2;
countdownText.scaleY = 0.2;
countdownText.tint = 0x4caf50;
countdownText.rotation = 0;
tween(countdownText, {
scaleX: 2.2,
scaleY: 2.2,
alpha: 0
}, {
duration: 800,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Hide countdown and show player
countdownText.alpha = 0;
tween(player, {
alpha: 1
}, {
duration: 500,
easing: tween.easeIn
});
// Create players appearing from bottom
for (var i = 0; i < 8; i++) {
var appearingPlayer = new NPC();
// Position players at bottom of screen
appearingPlayer.x = 300 + i * 200 + Math.random() * 100;
appearingPlayer.y = 2800; // Start below screen
appearingPlayer.alpha = 1;
npcs.push(appearingPlayer);
game.addChild(appearingPlayer);
// Animate player moving up from bottom with delay
var delay = i * 200 + Math.random() * 300;
LK.setTimeout(function (targetPlayer) {
return function () {
tween(targetPlayer, {
y: 2400 + Math.random() * 200
}, {
duration: 800,
easing: tween.easeOut
});
};
}(appearingPlayer), delay);
}
}
});
}
});
}
});
}
});
}
// Add button hover effect
playButton.down = function (x, y, obj) {
if (!showingMenu) return;
// Button press animation with bounce effect
tween(playButton, {
scaleX: 5.2,
scaleY: 5.2,
rotation: 0.1
}, {
duration: 150,
easing: tween.easeOut
});
};
playButton.up = function (x, y, obj) {
if (!showingMenu) return;
showingMenu = false;
// Button release animation with elastic bounce
tween(playButton, {
scaleX: 7.0,
scaleY: 7.0,
rotation: 0
}, {
duration: 200,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Scale back down with bounce
tween(playButton, {
scaleX: 6.0,
scaleY: 6.0
}, {
duration: 300,
easing: tween.bounceOut
});
}
});
// Hide menu elements with animation
tween(logoImage, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 500,
easing: tween.easeIn
});
tween(playButton, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Start countdown after menu disappears
startCountdown();
// Show pause button when game starts
showPauseButton();
}
});
};
// Don't start countdown immediately - wait for menu interaction
// startCountdown();
// Create pause menu elements (initially hidden)
var pauseMenuBackground = game.addChild(LK.getAsset('Arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 3.5,
scaleY: 4.5,
alpha: 0
}));
var pauseMenuTitle = new Text2('PAUSED', {
size: 200,
fill: 0xFFFFFF,
font: "'Impact', 'Arial Black', sans-serif"
});
pauseMenuTitle.anchor.set(0.5, 0.5);
pauseMenuTitle.x = 2048 / 2;
pauseMenuTitle.y = 800;
pauseMenuTitle.alpha = 0;
game.addChild(pauseMenuTitle);
var resumeButton = game.addChild(LK.getAsset('greenLight', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1400,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}));
var resumeText = new Text2('RESUME', {
size: 100,
fill: 0x000000,
font: "'Impact', 'Arial Black', sans-serif"
});
resumeText.anchor.set(0.5, 0.5);
resumeText.x = 2048 / 2;
resumeText.y = 1400;
resumeText.alpha = 0;
game.addChild(resumeText);
var restartButton = game.addChild(LK.getAsset('redLight', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1800,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}));
var restartText = new Text2('RESTART', {
size: 100,
fill: 0xFFFFFF,
font: "'Impact', 'Arial Black', sans-serif"
});
restartText.anchor.set(0.5, 0.5);
restartText.x = 2048 / 2;
restartText.y = 1800;
restartText.alpha = 0;
game.addChild(restartText);
// Pause button in top right corner
var pauseButton = game.addChild(LK.getAsset('redLight', {
anchorX: 0.5,
anchorY: 0.5,
x: 1900,
y: 150,
scaleX: 0.8,
scaleY: 0.8,
alpha: 0
}));
var pauseButtonText = new Text2('||', {
size: 80,
fill: 0xFFFFFF,
font: "'Impact', 'Arial Black', sans-serif"
});
pauseButtonText.anchor.set(0.5, 0.5);
pauseButtonText.x = 1900;
pauseButtonText.y = 150;
pauseButtonText.alpha = 0;
game.addChild(pauseButtonText);
// Pause button interactions
pauseButton.down = function (x, y, obj) {
if (!gameStarted || showingGameMenu || showingMenu) return;
tween(pauseButton, {
scaleX: 0.7,
scaleY: 0.7
}, {
duration: 100,
easing: tween.easeOut
});
};
pauseButton.up = function (x, y, obj) {
if (!gameStarted || showingGameMenu || showingMenu) return;
tween(pauseButton, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
showPauseMenu();
}
});
};
// Resume button interactions
resumeButton.down = function (x, y, obj) {
if (!showingGameMenu) return;
tween(resumeButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100,
easing: tween.easeOut
});
};
resumeButton.up = function (x, y, obj) {
if (!showingGameMenu) return;
tween(resumeButton, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
hidePauseMenu();
}
});
};
// Restart button interactions
restartButton.down = function (x, y, obj) {
if (!showingGameMenu) return;
tween(restartButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100,
easing: tween.easeOut
});
};
restartButton.up = function (x, y, obj) {
if (!showingGameMenu) return;
tween(restartButton, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
// Reset game state and restart
LK.showGameOver();
}
});
};
// Show pause button when game starts
function showPauseButton() {
tween(pauseButton, {
alpha: 0.8
}, {
duration: 500,
easing: tween.easeIn
});
tween(pauseButtonText, {
alpha: 1
}, {
duration: 500,
easing: tween.easeIn
});
}
// Function to show pause menu
function showPauseMenu() {
if (showingMenu || showingGameMenu) return;
showingGameMenu = true;
gamePaused = true;
// Show all pause menu elements
tween(pauseMenuBackground, {
alpha: 0.9
}, {
duration: 300,
easing: tween.easeOut
});
tween(pauseMenuTitle, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.backOut
});
tween(resumeButton, {
alpha: 1
}, {
duration: 400,
easing: tween.easeOut
});
tween(resumeText, {
alpha: 1
}, {
duration: 400,
easing: tween.easeOut
});
tween(restartButton, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
tween(restartText, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
}
// Function to hide pause menu
function hidePauseMenu() {
if (!showingGameMenu) return;
// Hide all pause menu elements
tween(pauseMenuBackground, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
tween(pauseMenuTitle, {
alpha: 0,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
tween(resumeButton, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
tween(resumeText, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
tween(restartButton, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
showingGameMenu = false;
gamePaused = false;
}
});
tween(restartText, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
}
// NPC spawning function removed
// NPCs removed from game start
// Score display for instructions
var instructionText = new Text2('GREEN: TAP TO MOVE\nRED: FREEZE!', {
size: 80,
fill: 0xFFFFFF,
font: "'Impact', 'Arial Black', sans-serif"
});
instructionText.anchor.set(0.5, 0);
LK.gui.top.addChild(instructionText);
// Light change function
function changeLight() {
isRedLight = !isRedLight;
if (isRedLight) {
// Switch to red light
trafficLight.removeChildren();
var redLightGraphics = trafficLight.attachAsset('redLight', {
anchorX: 0.5,
anchorY: 0.5
});
trafficLight.x = 2048 / 2;
trafficLight.y = 2732 / 2;
instructionText.setText('RED LIGHT - FREEZE!');
instructionText.tint = 0xff0000;
// Random duration for red light (1-4 seconds)
nextLightChange = 60 + Math.random() * 180;
// Play red light music during red light
LK.playMusic('redMusic');
// Enhanced red light visual effect with dramatic entrance and pulsing
trafficLight.scaleX = 0.1;
trafficLight.scaleY = 0.1;
trafficLight.rotation = Math.PI * 2;
trafficLight.alpha = 0;
// First phase: dramatic entrance with spin and flash
tween(trafficLight, {
scaleX: 1.8,
scaleY: 1.8,
rotation: 0,
alpha: 1
}, {
duration: 600,
easing: tween.backOut,
onFinish: function onFinish() {
// Second phase: settle to normal size with bounce
tween(trafficLight, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 400,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Third phase: continuous pulsing effect
function pulseRed() {
if (!isRedLight) return;
tween(trafficLight, {
scaleX: 1.15,
scaleY: 1.15
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!isRedLight) return;
tween(trafficLight, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
pulseRed();
}
});
}
});
}
pulseRed();
}
});
}
});
// Enhanced instruction text animation
tween(instructionText, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(instructionText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
});
// Flash screen red briefly
LK.effects.flashScreen(0xff0000, 500);
} else {
// Switch to green light
trafficLight.removeChildren();
var greenLightGraphics = trafficLight.attachAsset('greenLight', {
anchorX: 0.5,
anchorY: 0.5
});
trafficLight.x = 2048 / 2;
trafficLight.y = 2732 / 2;
instructionText.setText('GREEN LIGHT - TAP!');
instructionText.tint = 0x00ff00;
// Random duration for green light (2-5 seconds)
nextLightChange = 120 + Math.random() * 180;
// Play music during green light
LK.playMusic('greenMusic');
// Enhanced green light visual effect with bouncy entrance and floating
trafficLight.scaleX = 0.05;
trafficLight.scaleY = 0.05;
trafficLight.rotation = -Math.PI * 1.5;
trafficLight.alpha = 0.3;
// First phase: explosive entrance with multiple spins
tween(trafficLight, {
scaleX: 1.5,
scaleY: 1.5,
rotation: 0,
alpha: 1
}, {
duration: 700,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Second phase: settle with multiple bounces
tween(trafficLight, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Third phase: gentle floating effect
function floatGreen() {
if (isRedLight) return;
tween(trafficLight, {
y: trafficLight.y - 20,
scaleX: 1.05,
scaleY: 1.05,
rotation: 0.1
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (isRedLight) return;
tween(trafficLight, {
y: trafficLight.y + 20,
scaleX: 1.0,
scaleY: 1.0,
rotation: -0.1
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (isRedLight) return;
tween(trafficLight, {
rotation: 0
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
floatGreen();
}
});
}
});
}
});
}
floatGreen();
}
});
}
});
// Enhanced instruction text animation
tween(instructionText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(instructionText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeOut
});
}
});
// Flash screen green briefly
LK.effects.flashScreen(0x00ff00, 300);
}
LK.getSound('lightChange').play();
lightChangeTimer = 0;
}
// Tap to step movement
var stepSize = 60; // Size of each step forward
game.down = function (x, y, obj) {
if (showingMenu || showingGameMenu || gamePaused) return; // Don't allow game interaction while menu is showing
if (!gameStarted) {
gameStarted = true;
changeLight(); // Start with first light change
return;
}
// Move player one step forward (upward) regardless of light state
var newY = player.y - stepSize;
// Keep player within bounds
if (newY >= 100) {
player.y = newY;
// Enhanced movement animation with squash and stretch
player.bounceAnimation();
// If moving during red light, trigger death after movement
if (isRedLight) {
// Player moved during red light - eliminate!
LK.getSound('eliminate').play();
LK.getSound('eliminate').play();
LK.effects.flashScreen(0xff0000, 1000);
// Create blood splatter effect
var bloodParticles = [];
for (var i = 0; i < 8; i++) {
var bloodDrop = game.addChild(LK.getAsset('redLight', {
anchorX: 0.5,
anchorY: 0.5,
x: player.x,
y: player.y,
scaleX: 0.1,
scaleY: 0.1
}));
bloodParticles.push(bloodDrop);
// Random direction for each blood particle
var angle = i / 8 * Math.PI * 2 + (Math.random() - 0.5) * 0.5;
var distance = 100 + Math.random() * 150;
var targetX = player.x + Math.cos(angle) * distance;
var targetY = player.y + Math.sin(angle) * distance;
// Animate blood particle
tween(bloodDrop, {
x: targetX,
y: targetY,
scaleX: 0.3 + Math.random() * 0.2,
scaleY: 0.3 + Math.random() * 0.2,
alpha: 0
}, {
duration: 800 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function onFinish() {
if (bloodDrop.parent) {
bloodDrop.destroy();
}
}
});
}
// Death animation - scale up, rotate and fade out
tween(player, {
scaleX: 2,
scaleY: 2,
rotation: Math.PI * 2,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Reset player position and properties after animation
player.x = 2048 / 2;
player.y = 2500;
player.scaleX = 1;
player.scaleY = 1;
player.rotation = 0;
player.alpha = 1;
player.lastX = player.x;
player.lastY = player.y;
// Show game over after animation completes
LK.showGameOver();
}
});
}
}
};
// Main game update
game.update = function () {
if (!gameStarted || gamePaused) return;
// Update light timer
lightChangeTimer++;
if (lightChangeTimer >= nextLightChange) {
changeLight();
}
// Check win condition - player reaches finish line
if (player.intersects(finishLine)) {
// Player reaches finish line - show menu instead of game over
LK.effects.flashScreen(0x00ff00, 1000);
// Reset to main menu instead of showing game over
showingMenu = true;
gameStarted = false;
gamePaused = false;
showingGameMenu = false;
// Reset player position
player.x = 2048 / 2;
player.y = 2500;
player.scaleX = 1;
player.scaleY = 1;
player.rotation = 0;
player.alpha = 0;
player.lastX = player.x;
player.lastY = player.y;
// Reset NPCs
for (var i = 0; i < npcs.length; i++) {
if (npcs[i].parent) {
npcs[i].destroy();
}
}
npcs = [];
// Reset light to green
isRedLight = false;
lightChangeTimer = 0;
nextLightChange = 180;
trafficLight.removeChildren();
var greenLightGraphics = trafficLight.attachAsset('greenLight', {
anchorX: 0.5,
anchorY: 0.5
});
trafficLight.x = 2048 / 2;
trafficLight.y = 2732 / 2;
trafficLight.scaleX = 1.0;
trafficLight.scaleY = 1.0;
trafficLight.rotation = 0;
trafficLight.alpha = 1;
// Show menu elements again
tween(logoImage, {
alpha: 1,
scaleX: 5.0,
scaleY: 5.0
}, {
duration: 500,
easing: tween.easeOut
});
tween(playButton, {
alpha: 1,
scaleX: 6.0,
scaleY: 6.0
}, {
duration: 500,
easing: tween.easeOut
});
// Hide pause button
tween(pauseButton, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
tween(pauseButtonText, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
// Reset instruction text
instructionText.setText('GREEN: TAP TO MOVE\nRED: FREEZE!');
instructionText.tint = 0xFFFFFF;
instructionText.scaleX = 1.0;
instructionText.scaleY = 1.0;
return;
}
// Keep player within bounds
if (player.x < 40) player.x = 40;
if (player.x > 2008) player.x = 2008;
if (player.y > 2600) player.y = 2600;
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var NPC = Container.expand(function () {
var self = Container.call(this);
var npcGraphics = self.attachAsset('Player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
// Movement tracking
self.lastX = 0;
self.lastY = 0;
self.isMoving = false;
self.moveThreshold = 2;
self.isDead = false;
self.moveTimer = 0;
self.nextMoveTime = Math.random() * 40 + 20; // Random time between 0.33-1 seconds
// Enhanced bounce animation method identical to Player
self.bounceAnimation = function () {
tween(self, {
scaleX: 1.3,
scaleY: 0.8
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 0.9,
scaleY: 1.2
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
};
// Enhanced transition animation method identical to Player
self.transitionAnimation = function () {
tween(self, {
scaleX: 1.2,
scaleY: 0.9
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.bounceOut
});
}
});
};
self.eliminateNPC = function () {
if (self.isDead) return;
self.isDead = true;
// Play elimination sound
LK.getSound('eliminate').play();
// Create blood splatter effect
for (var i = 0; i < 6; i++) {
var bloodDrop = game.addChild(LK.getAsset('redLight', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y,
scaleX: 0.1,
scaleY: 0.1
}));
var angle = i / 6 * Math.PI * 2 + (Math.random() - 0.5) * 0.5;
var distance = 80 + Math.random() * 120;
var targetX = self.x + Math.cos(angle) * distance;
var targetY = self.y + Math.sin(angle) * distance;
tween(bloodDrop, {
x: targetX,
y: targetY,
scaleX: 0.2 + Math.random() * 0.15,
scaleY: 0.2 + Math.random() * 0.15,
alpha: 0
}, {
duration: 600 + Math.random() * 300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (bloodDrop.parent) {
bloodDrop.destroy();
}
}
});
}
// Hide NPC after death animation
tween(self, {
alpha: 0
}, {
duration: 1500,
easing: tween.easeOut
});
};
self.update = function () {
if (self.isDead) return;
// Check if NPC reached finish line and stop movement
if (self.y <= 370) {
// NPC reached finish line, stop all movement
self.isMoving = false;
if (!self.reachedFinish) {
self.reachedFinish = true;
self.removeChildren();
npcGraphics = self.attachAsset('Player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Update last position
self.lastX = self.x;
self.lastY = self.y;
return;
}
var deltaX = Math.abs(self.x - self.lastX);
var deltaY = Math.abs(self.y - self.lastY);
var wasMoving = self.isMoving;
self.isMoving = deltaX > self.moveThreshold || deltaY > self.moveThreshold;
// Switch assets based on movement state with enhanced animations
if (wasMoving !== self.isMoving) {
if (self.isMoving) {
// Cancel any pending idle transition
if (self.idleTimeout) {
LK.clearTimeout(self.idleTimeout);
self.idleTimeout = null;
}
// Switch to moving player asset immediately
self.removeChildren();
npcGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Enhanced transition animation identical to Player
self.transitionAnimation();
self.bounceAnimation();
} else {
// Wait 40ms (0.04 seconds) before switching to idle asset
self.idleTimeout = LK.setTimeout(function () {
// Only switch to idle if still not moving
if (!self.isMoving && !self.isDead) {
self.removeChildren();
npcGraphics = self.attachAsset('Player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
}
self.idleTimeout = null;
}, 40);
}
}
// NPC movement logic
if (!isRedLight) {
// During green light, move randomly
self.moveTimer++;
if (self.moveTimer >= self.nextMoveTime) {
var stepSize = 50 + Math.random() * 20;
var newY = self.y - stepSize;
if (newY >= 100) {
self.y = newY;
// Switch to player asset when moving
self.removeChildren();
npcGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Enhanced transition animation identical to Player
self.transitionAnimation();
// Enhanced movement animation with squash and stretch identical to Player
self.bounceAnimation();
// Add additional movement effects like Player
tween(npcGraphics, {
rotation: 0.1
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(npcGraphics, {
rotation: -0.1
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(npcGraphics, {
rotation: 0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
}
self.moveTimer = 0;
self.nextMoveTime = Math.random() * 40 + 20;
}
} else {
// During red light, sometimes make a mistake and move
self.moveTimer++;
var mistakeChance = 0.002; // Much lower chance per frame for NPCs to lose
if (self.moveTimer > 120 && Math.random() < mistakeChance) {
// NPC makes mistake and moves during red light
var stepSize = 40 + Math.random() * 30;
var newY = self.y - stepSize;
if (newY >= 100) {
self.y = newY;
}
// Switch to player asset when moving during mistake
self.removeChildren();
npcGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Enhanced transition animation identical to Player
self.transitionAnimation();
// Enhanced movement animation with squash and stretch identical to Player
self.bounceAnimation();
// Add dramatic mistake animation
tween(npcGraphics, {
tint: 0xff6666,
scaleX: 1.2,
scaleY: 0.8
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(npcGraphics, {
tint: 0xffffff,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeOut
});
}
});
// Eliminate this NPC for moving during red light
self.eliminateNPC();
}
}
// Continuous idle state checking - if NPC is not moving, ensure it uses idle asset
if (!self.isMoving && !self.isDead && !self.reachedFinish) {
// Check if current asset is not already Player_idle
var currentAsset = self.children[0];
if (currentAsset && currentAsset.texture && !currentAsset.texture.baseTexture.resource.url.includes('Player_idle')) {
// Switch to idle asset immediately
self.removeChildren();
npcGraphics = self.attachAsset('Player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
}
}
// Additional check: when red light is active and NPC is not moving, switch to idle
if (isRedLight && !self.isMoving && !self.isDead && !self.reachedFinish) {
var currentAsset = self.children[0];
if (currentAsset && currentAsset.texture && !currentAsset.texture.baseTexture.resource.url.includes('Player_idle')) {
// Switch to idle asset immediately during red light
self.removeChildren();
npcGraphics = self.attachAsset('Player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
}
}
// Update last position
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('Player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
// Movement tracking
self.lastX = 0;
self.lastY = 0;
self.isMoving = false;
self.moveThreshold = 2; // Minimum movement to detect
// Enhanced bounce animation method
self.bounceAnimation = function () {
tween(self, {
scaleX: 1.3,
scaleY: 0.8
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 0.9,
scaleY: 1.2
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
};
self.update = function () {
// Check if player is moving
var deltaX = Math.abs(self.x - self.lastX);
var deltaY = Math.abs(self.y - self.lastY);
var wasMoving = self.isMoving;
self.isMoving = deltaX > self.moveThreshold || deltaY > self.moveThreshold;
// Switch assets based on movement state
if (wasMoving !== self.isMoving) {
if (self.isMoving) {
// Cancel any pending idle transition
if (self.idleTimeout) {
tween.stop(self.idleTimeout);
self.idleTimeout = null;
}
// Switch to moving player asset
self.removeChildren();
playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Enhanced transition animation
self.bounceAnimation();
} else {
// Wait 300ms before switching to idle asset
self.idleTimeout = {};
tween(self.idleTimeout, {}, {
duration: 300,
onFinish: function onFinish() {
// Only switch to idle if still not moving
if (!self.isMoving) {
self.removeChildren();
playerGraphics = self.attachAsset('Player_idle', {
anchorX: 0.5,
anchorY: 0.5
});
}
self.idleTimeout = null;
}
});
}
}
// Update last position
self.lastX = self.x;
self.lastY = self.y;
};
return self;
});
/****
* Initialize Game
****/
// Game state variables
var game = new LK.Game({
backgroundColor: 0x2c2c2c // Dark grey background for dramatic effect
});
/****
* Game Code
****/
// Game state variables
// Traffic light states
// Player character
// Finish line
// Sound effects
var isRedLight = false;
var lightChangeTimer = 0;
var nextLightChange = 180; // 3 seconds at 60fps
var player;
var trafficLight;
var finishLine;
var isDragging = false;
var gameStarted = false;
var showingMenu = true;
var npcs = [];
var gamePaused = false;
var showingGameMenu = false;
// Swipe detection variables declared in down handler
// Create arena background
var arenaBackground = game.addChild(LK.getAsset('Arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 3.5,
scaleY: 4.5
}));
// Create traffic light at center
trafficLight = game.addChild(LK.getAsset('greenLight', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
}));
// Create finish line at top
finishLine = game.addChild(LK.getAsset('finishLine', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 350,
alpha: 1
}));
// Create main menu elements
var logoImage = game.addChild(LK.getAsset('Logo', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 900,
scaleX: 5.0,
scaleY: 5.0
}));
var playButton = game.addChild(LK.getAsset('Play', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1600,
scaleX: 6.0,
scaleY: 6.0
}));
// Create countdown display (initially hidden)
var countdownText = new Text2('3', {
size: 600,
fill: 0xFFFFFF,
font: "'Impact', 'Arial Black', sans-serif"
});
countdownText.anchor.set(0.5, 0.5);
countdownText.x = 2048 / 2;
countdownText.y = 2732 / 2;
countdownText.alpha = 0;
game.addChild(countdownText);
// Create player at bottom with countdown delay
player = new Player();
player.x = 2048 / 2;
player.y = 2500;
player.alpha = 0; // Start invisible
game.addChild(player); // Add player to game scene immediately
// Start countdown animation
function startCountdown() {
// Show "3"
countdownText.setText('3');
countdownText.alpha = 1;
countdownText.scaleX = 0.1;
countdownText.scaleY = 0.1;
countdownText.tint = 0x00ff00; // Green for "3"
countdownText.rotation = -0.5;
tween(countdownText, {
scaleX: 1.8,
scaleY: 1.8,
rotation: 0,
alpha: 0
}, {
duration: 1000,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Show "2"
countdownText.setText('2');
countdownText.alpha = 1;
countdownText.scaleX = 0.1;
countdownText.scaleY = 0.1;
countdownText.tint = 0xff0000; // Red for "2"
countdownText.rotation = 0.5;
tween(countdownText, {
scaleX: 1.8,
scaleY: 1.8,
rotation: 0,
alpha: 0
}, {
duration: 1000,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Show "1"
countdownText.setText('1');
countdownText.alpha = 1;
countdownText.scaleX = 0.1;
countdownText.scaleY = 0.1;
countdownText.tint = 0xff69b4; // Pink for "1"
countdownText.rotation = -0.3;
tween(countdownText, {
scaleX: 1.8,
scaleY: 1.8,
rotation: 0,
alpha: 0
}, {
duration: 1000,
easing: tween.backOut,
onFinish: function onFinish() {
// Show "GO!"
countdownText.setText('GO!');
countdownText.alpha = 1;
countdownText.scaleX = 0.2;
countdownText.scaleY = 0.2;
countdownText.tint = 0x4caf50;
countdownText.rotation = 0;
tween(countdownText, {
scaleX: 2.2,
scaleY: 2.2,
alpha: 0
}, {
duration: 800,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Hide countdown and show player
countdownText.alpha = 0;
tween(player, {
alpha: 1
}, {
duration: 500,
easing: tween.easeIn
});
// Create players appearing from bottom
for (var i = 0; i < 8; i++) {
var appearingPlayer = new NPC();
// Position players at bottom of screen
appearingPlayer.x = 300 + i * 200 + Math.random() * 100;
appearingPlayer.y = 2800; // Start below screen
appearingPlayer.alpha = 1;
npcs.push(appearingPlayer);
game.addChild(appearingPlayer);
// Animate player moving up from bottom with delay
var delay = i * 200 + Math.random() * 300;
LK.setTimeout(function (targetPlayer) {
return function () {
tween(targetPlayer, {
y: 2400 + Math.random() * 200
}, {
duration: 800,
easing: tween.easeOut
});
};
}(appearingPlayer), delay);
}
}
});
}
});
}
});
}
});
}
// Add button hover effect
playButton.down = function (x, y, obj) {
if (!showingMenu) return;
// Button press animation with bounce effect
tween(playButton, {
scaleX: 5.2,
scaleY: 5.2,
rotation: 0.1
}, {
duration: 150,
easing: tween.easeOut
});
};
playButton.up = function (x, y, obj) {
if (!showingMenu) return;
showingMenu = false;
// Button release animation with elastic bounce
tween(playButton, {
scaleX: 7.0,
scaleY: 7.0,
rotation: 0
}, {
duration: 200,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Scale back down with bounce
tween(playButton, {
scaleX: 6.0,
scaleY: 6.0
}, {
duration: 300,
easing: tween.bounceOut
});
}
});
// Hide menu elements with animation
tween(logoImage, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 500,
easing: tween.easeIn
});
tween(playButton, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Start countdown after menu disappears
startCountdown();
// Show pause button when game starts
showPauseButton();
}
});
};
// Don't start countdown immediately - wait for menu interaction
// startCountdown();
// Create pause menu elements (initially hidden)
var pauseMenuBackground = game.addChild(LK.getAsset('Arena', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 3.5,
scaleY: 4.5,
alpha: 0
}));
var pauseMenuTitle = new Text2('PAUSED', {
size: 200,
fill: 0xFFFFFF,
font: "'Impact', 'Arial Black', sans-serif"
});
pauseMenuTitle.anchor.set(0.5, 0.5);
pauseMenuTitle.x = 2048 / 2;
pauseMenuTitle.y = 800;
pauseMenuTitle.alpha = 0;
game.addChild(pauseMenuTitle);
var resumeButton = game.addChild(LK.getAsset('greenLight', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1400,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}));
var resumeText = new Text2('RESUME', {
size: 100,
fill: 0x000000,
font: "'Impact', 'Arial Black', sans-serif"
});
resumeText.anchor.set(0.5, 0.5);
resumeText.x = 2048 / 2;
resumeText.y = 1400;
resumeText.alpha = 0;
game.addChild(resumeText);
var restartButton = game.addChild(LK.getAsset('redLight', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1800,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}));
var restartText = new Text2('RESTART', {
size: 100,
fill: 0xFFFFFF,
font: "'Impact', 'Arial Black', sans-serif"
});
restartText.anchor.set(0.5, 0.5);
restartText.x = 2048 / 2;
restartText.y = 1800;
restartText.alpha = 0;
game.addChild(restartText);
// Pause button in top right corner
var pauseButton = game.addChild(LK.getAsset('redLight', {
anchorX: 0.5,
anchorY: 0.5,
x: 1900,
y: 150,
scaleX: 0.8,
scaleY: 0.8,
alpha: 0
}));
var pauseButtonText = new Text2('||', {
size: 80,
fill: 0xFFFFFF,
font: "'Impact', 'Arial Black', sans-serif"
});
pauseButtonText.anchor.set(0.5, 0.5);
pauseButtonText.x = 1900;
pauseButtonText.y = 150;
pauseButtonText.alpha = 0;
game.addChild(pauseButtonText);
// Pause button interactions
pauseButton.down = function (x, y, obj) {
if (!gameStarted || showingGameMenu || showingMenu) return;
tween(pauseButton, {
scaleX: 0.7,
scaleY: 0.7
}, {
duration: 100,
easing: tween.easeOut
});
};
pauseButton.up = function (x, y, obj) {
if (!gameStarted || showingGameMenu || showingMenu) return;
tween(pauseButton, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
showPauseMenu();
}
});
};
// Resume button interactions
resumeButton.down = function (x, y, obj) {
if (!showingGameMenu) return;
tween(resumeButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100,
easing: tween.easeOut
});
};
resumeButton.up = function (x, y, obj) {
if (!showingGameMenu) return;
tween(resumeButton, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
hidePauseMenu();
}
});
};
// Restart button interactions
restartButton.down = function (x, y, obj) {
if (!showingGameMenu) return;
tween(restartButton, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100,
easing: tween.easeOut
});
};
restartButton.up = function (x, y, obj) {
if (!showingGameMenu) return;
tween(restartButton, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
// Reset game state and restart
LK.showGameOver();
}
});
};
// Show pause button when game starts
function showPauseButton() {
tween(pauseButton, {
alpha: 0.8
}, {
duration: 500,
easing: tween.easeIn
});
tween(pauseButtonText, {
alpha: 1
}, {
duration: 500,
easing: tween.easeIn
});
}
// Function to show pause menu
function showPauseMenu() {
if (showingMenu || showingGameMenu) return;
showingGameMenu = true;
gamePaused = true;
// Show all pause menu elements
tween(pauseMenuBackground, {
alpha: 0.9
}, {
duration: 300,
easing: tween.easeOut
});
tween(pauseMenuTitle, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.backOut
});
tween(resumeButton, {
alpha: 1
}, {
duration: 400,
easing: tween.easeOut
});
tween(resumeText, {
alpha: 1
}, {
duration: 400,
easing: tween.easeOut
});
tween(restartButton, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
tween(restartText, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
}
// Function to hide pause menu
function hidePauseMenu() {
if (!showingGameMenu) return;
// Hide all pause menu elements
tween(pauseMenuBackground, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
tween(pauseMenuTitle, {
alpha: 0,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeIn
});
tween(resumeButton, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
tween(resumeText, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
tween(restartButton, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
showingGameMenu = false;
gamePaused = false;
}
});
tween(restartText, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
}
// NPC spawning function removed
// NPCs removed from game start
// Score display for instructions
var instructionText = new Text2('GREEN: TAP TO MOVE\nRED: FREEZE!', {
size: 80,
fill: 0xFFFFFF,
font: "'Impact', 'Arial Black', sans-serif"
});
instructionText.anchor.set(0.5, 0);
LK.gui.top.addChild(instructionText);
// Light change function
function changeLight() {
isRedLight = !isRedLight;
if (isRedLight) {
// Switch to red light
trafficLight.removeChildren();
var redLightGraphics = trafficLight.attachAsset('redLight', {
anchorX: 0.5,
anchorY: 0.5
});
trafficLight.x = 2048 / 2;
trafficLight.y = 2732 / 2;
instructionText.setText('RED LIGHT - FREEZE!');
instructionText.tint = 0xff0000;
// Random duration for red light (1-4 seconds)
nextLightChange = 60 + Math.random() * 180;
// Play red light music during red light
LK.playMusic('redMusic');
// Enhanced red light visual effect with dramatic entrance and pulsing
trafficLight.scaleX = 0.1;
trafficLight.scaleY = 0.1;
trafficLight.rotation = Math.PI * 2;
trafficLight.alpha = 0;
// First phase: dramatic entrance with spin and flash
tween(trafficLight, {
scaleX: 1.8,
scaleY: 1.8,
rotation: 0,
alpha: 1
}, {
duration: 600,
easing: tween.backOut,
onFinish: function onFinish() {
// Second phase: settle to normal size with bounce
tween(trafficLight, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 400,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Third phase: continuous pulsing effect
function pulseRed() {
if (!isRedLight) return;
tween(trafficLight, {
scaleX: 1.15,
scaleY: 1.15
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!isRedLight) return;
tween(trafficLight, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
pulseRed();
}
});
}
});
}
pulseRed();
}
});
}
});
// Enhanced instruction text animation
tween(instructionText, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(instructionText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
});
// Flash screen red briefly
LK.effects.flashScreen(0xff0000, 500);
} else {
// Switch to green light
trafficLight.removeChildren();
var greenLightGraphics = trafficLight.attachAsset('greenLight', {
anchorX: 0.5,
anchorY: 0.5
});
trafficLight.x = 2048 / 2;
trafficLight.y = 2732 / 2;
instructionText.setText('GREEN LIGHT - TAP!');
instructionText.tint = 0x00ff00;
// Random duration for green light (2-5 seconds)
nextLightChange = 120 + Math.random() * 180;
// Play music during green light
LK.playMusic('greenMusic');
// Enhanced green light visual effect with bouncy entrance and floating
trafficLight.scaleX = 0.05;
trafficLight.scaleY = 0.05;
trafficLight.rotation = -Math.PI * 1.5;
trafficLight.alpha = 0.3;
// First phase: explosive entrance with multiple spins
tween(trafficLight, {
scaleX: 1.5,
scaleY: 1.5,
rotation: 0,
alpha: 1
}, {
duration: 700,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Second phase: settle with multiple bounces
tween(trafficLight, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Third phase: gentle floating effect
function floatGreen() {
if (isRedLight) return;
tween(trafficLight, {
y: trafficLight.y - 20,
scaleX: 1.05,
scaleY: 1.05,
rotation: 0.1
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (isRedLight) return;
tween(trafficLight, {
y: trafficLight.y + 20,
scaleX: 1.0,
scaleY: 1.0,
rotation: -0.1
}, {
duration: 1200,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (isRedLight) return;
tween(trafficLight, {
rotation: 0
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
floatGreen();
}
});
}
});
}
});
}
floatGreen();
}
});
}
});
// Enhanced instruction text animation
tween(instructionText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(instructionText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeOut
});
}
});
// Flash screen green briefly
LK.effects.flashScreen(0x00ff00, 300);
}
LK.getSound('lightChange').play();
lightChangeTimer = 0;
}
// Tap to step movement
var stepSize = 60; // Size of each step forward
game.down = function (x, y, obj) {
if (showingMenu || showingGameMenu || gamePaused) return; // Don't allow game interaction while menu is showing
if (!gameStarted) {
gameStarted = true;
changeLight(); // Start with first light change
return;
}
// Move player one step forward (upward) regardless of light state
var newY = player.y - stepSize;
// Keep player within bounds
if (newY >= 100) {
player.y = newY;
// Enhanced movement animation with squash and stretch
player.bounceAnimation();
// If moving during red light, trigger death after movement
if (isRedLight) {
// Player moved during red light - eliminate!
LK.getSound('eliminate').play();
LK.getSound('eliminate').play();
LK.effects.flashScreen(0xff0000, 1000);
// Create blood splatter effect
var bloodParticles = [];
for (var i = 0; i < 8; i++) {
var bloodDrop = game.addChild(LK.getAsset('redLight', {
anchorX: 0.5,
anchorY: 0.5,
x: player.x,
y: player.y,
scaleX: 0.1,
scaleY: 0.1
}));
bloodParticles.push(bloodDrop);
// Random direction for each blood particle
var angle = i / 8 * Math.PI * 2 + (Math.random() - 0.5) * 0.5;
var distance = 100 + Math.random() * 150;
var targetX = player.x + Math.cos(angle) * distance;
var targetY = player.y + Math.sin(angle) * distance;
// Animate blood particle
tween(bloodDrop, {
x: targetX,
y: targetY,
scaleX: 0.3 + Math.random() * 0.2,
scaleY: 0.3 + Math.random() * 0.2,
alpha: 0
}, {
duration: 800 + Math.random() * 400,
easing: tween.easeOut,
onFinish: function onFinish() {
if (bloodDrop.parent) {
bloodDrop.destroy();
}
}
});
}
// Death animation - scale up, rotate and fade out
tween(player, {
scaleX: 2,
scaleY: 2,
rotation: Math.PI * 2,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Reset player position and properties after animation
player.x = 2048 / 2;
player.y = 2500;
player.scaleX = 1;
player.scaleY = 1;
player.rotation = 0;
player.alpha = 1;
player.lastX = player.x;
player.lastY = player.y;
// Show game over after animation completes
LK.showGameOver();
}
});
}
}
};
// Main game update
game.update = function () {
if (!gameStarted || gamePaused) return;
// Update light timer
lightChangeTimer++;
if (lightChangeTimer >= nextLightChange) {
changeLight();
}
// Check win condition - player reaches finish line
if (player.intersects(finishLine)) {
// Player reaches finish line - show menu instead of game over
LK.effects.flashScreen(0x00ff00, 1000);
// Reset to main menu instead of showing game over
showingMenu = true;
gameStarted = false;
gamePaused = false;
showingGameMenu = false;
// Reset player position
player.x = 2048 / 2;
player.y = 2500;
player.scaleX = 1;
player.scaleY = 1;
player.rotation = 0;
player.alpha = 0;
player.lastX = player.x;
player.lastY = player.y;
// Reset NPCs
for (var i = 0; i < npcs.length; i++) {
if (npcs[i].parent) {
npcs[i].destroy();
}
}
npcs = [];
// Reset light to green
isRedLight = false;
lightChangeTimer = 0;
nextLightChange = 180;
trafficLight.removeChildren();
var greenLightGraphics = trafficLight.attachAsset('greenLight', {
anchorX: 0.5,
anchorY: 0.5
});
trafficLight.x = 2048 / 2;
trafficLight.y = 2732 / 2;
trafficLight.scaleX = 1.0;
trafficLight.scaleY = 1.0;
trafficLight.rotation = 0;
trafficLight.alpha = 1;
// Show menu elements again
tween(logoImage, {
alpha: 1,
scaleX: 5.0,
scaleY: 5.0
}, {
duration: 500,
easing: tween.easeOut
});
tween(playButton, {
alpha: 1,
scaleX: 6.0,
scaleY: 6.0
}, {
duration: 500,
easing: tween.easeOut
});
// Hide pause button
tween(pauseButton, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
tween(pauseButtonText, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn
});
// Reset instruction text
instructionText.setText('GREEN: TAP TO MOVE\nRED: FREEZE!');
instructionText.tint = 0xFFFFFF;
instructionText.scaleX = 1.0;
instructionText.scaleY = 1.0;
return;
}
// Keep player within bounds
if (player.x < 40) player.x = 40;
if (player.x > 2008) player.x = 2008;
if (player.y > 2600) player.y = 2600;
};
Crea al player del juego el calamar con el traja verde corriendo con el numero 456.. In-Game asset. 2d. High contrast. No shadows
Crea el player 456 del juego del calamar quieto parecido al otro que me generastes. In-Game asset. 2d. High contrast. No shadows
Arena como cielo pero arena. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Boton de play de color verde y rosa. In-Game asset. 2d. High contrast. No shadows
Logo red light green light. In-Game asset. 2d. High contrast. No shadows