/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var HardcoreButton = Container.expand(function () { var self = Container.call(this); // Create button background var btnBackground = self.attachAsset('safeZone', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.3, tint: 0xFF0000 }); // Create button text var btnText = new Text2('HARDCORE MODE', { size: 60, fill: 0xFFFFFF }); btnText.anchor.set(0.5, 0.5); self.addChild(btnText); // Handle button press self.down = function (x, y, obj) { // Visual feedback tween(btnBackground, { scaleX: 0.75, scaleY: 0.28 }, { duration: 100 }); }; // Handle button release self.up = function (x, y, obj) { // Visual feedback tween(btnBackground, { scaleX: 0.8, scaleY: 0.3 }, { duration: 100, onFinish: function onFinish() { // Toggle hardcore mode flag window.hardcoreMode = !window.hardcoreMode; // Update button text and color btnText.setText(window.hardcoreMode ? 'NORMAL MODE' : 'HARDCORE MODE'); btnBackground.tint = window.hardcoreMode ? 0x00FF00 : 0xFF0000; // Stop any currently playing music first LK.stopMusic(); // Play evil laugh when entering hardcore mode if (window.hardcoreMode) { LK.getSound('evilLaugh').play(); // Play hardcore music LK.playMusic('hardcorebg', { fade: { start: 0, end: 1.0, duration: 800 } }); } else { // Play normal mode music LK.playMusic('bgMusic', { fade: { start: 0, end: 1.0, duration: 800 } }); } initGame(); } }); }; return self; }); var PlayerCircle = Container.expand(function () { var self = Container.call(this); var circleGraphics = self.attachAsset('playerCircle', { anchorX: 0.5, anchorY: 0.5 }); // Pulse animation for player self.startPulse = function () { tween(circleGraphics, { scaleX: 1.1, scaleY: 1.1 }, { duration: 400, easing: tween.easeInOut, onFinish: function onFinish() { tween(circleGraphics, { scaleX: 1, scaleY: 1 }, { duration: 400, easing: tween.easeInOut, onFinish: self.startPulse }); } }); }; self.stopPulse = function () { tween.stop(circleGraphics, { scaleX: true, scaleY: true }); tween(circleGraphics, { scaleX: 1, scaleY: 1 }, { duration: 300 }); }; self.applyForce = function (angle, magnitude) { var vx = Math.cos(angle) * magnitude; var vy = Math.sin(angle) * magnitude; self.vx = vx; self.vy = vy; }; self.vx = 0; self.vy = 0; self.friction = 0.95; self.update = function () { // Apply velocity if (!self.isDragging) { self.x += self.vx; self.y += self.vy; // Apply friction self.vx *= self.friction; self.vy *= self.friction; // Stop if velocity is very small if (Math.abs(self.vx) < 0.1) self.vx = 0; if (Math.abs(self.vy) < 0.1) self.vy = 0; // Add slow drift away from center - in both modes, drift away from safe zone var dx = self.x - safeZone.x; var dy = self.y - safeZone.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 10) { // Only apply drift if not exactly at center var angle = Math.atan2(dy, dx); // Keep consistent drift force regardless of mode var driftForce = 0.15; self.vx += Math.cos(angle) * driftForce; self.vy += Math.sin(angle) * driftForce; } } // Constrain to screen bounds if (self.x < 50) { self.x = 50; self.vx *= -0.5; } if (self.x > 2048 - 50) { self.x = 2048 - 50; self.vx *= -0.5; } if (self.y < 50) { self.y = 50; self.vy *= -0.5; } if (self.y > 2732 - 50) { self.y = 2732 - 50; self.vy *= -0.5; } }; self.isDragging = false; // Set initial state self.startPulse(); return self; }); var SafeZone = Container.expand(function () { var self = Container.call(this); var zoneGraphics = self.attachAsset('safeZone', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); // Pulse animation for safe zone self.startPulse = function () { tween(zoneGraphics, { alpha: 0.7 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(zoneGraphics, { alpha: 0.4 }, { duration: 800, easing: tween.easeInOut, onFinish: self.startPulse }); } }); }; self.stopPulse = function () { tween.stop(zoneGraphics, { alpha: true }); }; self.shrink = function () { tween(zoneGraphics, { scaleX: 0.9, scaleY: 0.9 }, { duration: 1000, easing: tween.easeOut }); }; self.grow = function () { tween(zoneGraphics, { scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.bounceOut }); }; // Set initial state self.startPulse(); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x111111 }); /**** * Game Code ****/ // Hardcore mode flag window.hardcoreMode = false; // Game constants var GAME_DURATION = 120000; // 2 minutes var DANGER_TIMEOUT = 7000; // 7 seconds var MIN_BUMP_INTERVAL = 5000; // 5 seconds var MAX_BUMP_INTERVAL = 11000; // 11 seconds var MAX_BUMP_FORCE = 40; // Increased from 25 for stronger bumps // Add hardcore button var hardcoreButton = new HardcoreButton(); hardcoreButton.x = 2048 - 150; hardcoreButton.y = 120; // Update button text based on current mode hardcoreButton.children[1].setText(window.hardcoreMode ? 'NORMAL MODE' : 'HARDCORE MODE'); hardcoreButton.children[0].tint = window.hardcoreMode ? 0x00FF00 : 0xFF0000; game.addChild(hardcoreButton); // Game state variables var gameTimer = 0; var outOfSafeZoneTimer = 0; var isPlayerInSafeZone = true; var lastBumpTime = 0; var nextBumpTime = 0; var dragNode = null; // Create the safe zone var safeZone = new SafeZone(); safeZone.x = 2048 / 2; safeZone.y = 2732 / 2; game.addChild(safeZone); // Create the player circle var player = new PlayerCircle(); player.x = 2048 / 2; player.y = 2732 / 2; game.addChild(player); // UI Elements var timerText = new Text2('2:00', { size: 100, fill: 0xFFFFFF }); timerText.anchor.set(0.5, 0); LK.gui.top.addChild(timerText); var instructionText = new Text2('KEEP THE CIRCLE IN THE MIDDLE', { size: 70, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 0); instructionText.y = 120; LK.gui.top.addChild(instructionText); // Add pulsing animation to instruction text synchronized with beat function pulseInstructionText() { tween(instructionText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(instructionText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeIn, onFinish: pulseInstructionText }); } }); } pulseInstructionText(); var warningText = new Text2('WARNING: RETURN TO SAFE ZONE!', { size: 70, fill: 0xFF3333 }); warningText.anchor.set(0.5, 0); warningText.y = timerText.height + instructionText.height + 150; warningText.alpha = 0; LK.gui.top.addChild(warningText); // Format time as MM:SS function formatTime(ms) { var seconds = Math.floor(ms / 1000); var minutes = Math.floor(seconds / 60); seconds = seconds % 60; return minutes + ':' + (seconds < 10 ? '0' : '') + seconds; } // Schedule the next random bump function scheduleNextBump() { var interval = MIN_BUMP_INTERVAL + Math.random() * (MAX_BUMP_INTERVAL - MIN_BUMP_INTERVAL); nextBumpTime = lastBumpTime + interval; } // Apply a random force to push player away from center function applyRandomBump() { // Calculate angle away from center var centerX = 2048 / 2; var centerY = 2732 / 2; var dx = player.x - centerX; var dy = player.y - centerY; var angle = Math.atan2(dy, dx); // If player is at center, use a random angle if (Math.abs(dx) < 10 && Math.abs(dy) < 10) { angle = Math.random() * Math.PI * 2; } // Get current game progress (0 to 1) var gameProgress = Math.min(gameTimer / GAME_DURATION, 1); if (window.hardcoreMode) { // In hardcore mode, teleport the SAFE ZONE to a random position var screenMargin = 150; var randomX, randomY; // Make sure we don't teleport too close to edges randomX = Math.random() * (2048 - 2 * screenMargin) + screenMargin; randomY = Math.random() * (2732 - 2 * screenMargin) + screenMargin; // Teleport safe zone safeZone.x = randomX; safeZone.y = randomY; // Add stronger visual effect for hardcore mode LK.effects.flashScreen(0xFF4400, 300); // Display "Good Luck" message instructionText.setText("HARDCORE MODE: GOOD LUCK."); } else { // Normal mode - apply force // Increase force based on progress (more force as game goes on) var forceMagnitude = 20 + (MAX_BUMP_FORCE - 20) * gameProgress; // Starting force increased from 10 to 20 // Apply the force player.applyForce(angle, forceMagnitude); } // Play bump sound LK.getSound('bump').play(); // Visual effect - flash screen slightly LK.effects.flashScreen(0xFFFFFF, 200); // Record time of bump and schedule next one lastBumpTime = LK.ticks * (1000 / 60); // Convert ticks to ms scheduleNextBump(); } // Check if player is in safe zone function checkPlayerInSafeZone() { // In both modes, we need to check the distance to the safe zone // In normal mode, safe zone is centered, but in hardcore, it could be anywhere var dx = player.x - safeZone.x; var dy = player.y - safeZone.y; var distance = Math.sqrt(dx * dx + dy * dy); // Safe zone radius is half the width of the safeZone asset var safeZoneRadius = safeZone.children[0].width / 2; return distance < safeZoneRadius; } // Handle warning display function updateWarning() { if (!isPlayerInSafeZone) { // Danger progress (0 to 1) var dangerProgress = outOfSafeZoneTimer / DANGER_TIMEOUT; // Scale warning text based on danger progress var scale = 1 + dangerProgress * 0.3; warningText.scale.set(scale, scale); // Fade in warning if it's not already visible if (warningText.alpha < 1) { tween(warningText, { alpha: 1 }, { duration: 300 }); } // Change text color between red and white for urgency if (dangerProgress > 0.7) { if (LK.ticks % 15 === 0) { // Flash every quarter second warningText.setText(warningText.text); // Ensure text is refreshed if (warningText.style && warningText.style.fill) { warningText.style.fill = warningText.style.fill === "#FF3333" ? "#FFFFFF" : "#FF3333"; } else { // Fallback if style is not properly initialized warningText.setText(warningText.text, { fill: warningText.style && warningText.style.fill === "#FF3333" ? "#FFFFFF" : "#FF3333" }); } } } } else { // Fade out warning if (warningText.alpha > 0) { tween(warningText, { alpha: 0 }, { duration: 300 }); } } } // Start the game function initGame() { // Initialize game state gameTimer = 0; outOfSafeZoneTimer = 0; isPlayerInSafeZone = true; lastBumpTime = 0; scheduleNextBump(); // Reset positions player.x = 2048 / 2; player.y = 2732 / 2; player.vx = 0; player.vy = 0; // Reset safe zone position to center safeZone.x = 2048 / 2; safeZone.y = 2732 / 2; // Update UI for hardcore mode if active if (window.hardcoreMode) { // Change title text to indicate hardcore mode with "Good luck" instructionText.setText("HARDCORE MODE: GOOD LUCK."); if (!instructionText.style) instructionText.style = {}; instructionText.style.fill = "#FF3333"; // Make the safe zone smaller in hardcore mode safeZone.children[0].scale.set(0.8, 0.8); // Update hardcore button text and color if (hardcoreButton) { hardcoreButton.children[1].setText('NORMAL MODE'); hardcoreButton.children[0].tint = 0x00FF00; } } else { // Reset to normal mode text instructionText.setText("KEEP THE CIRCLE IN THE MIDDLE"); if (!instructionText.style) instructionText.style = {}; instructionText.style.fill = "#FFFFFF"; // Reset safe zone size safeZone.children[0].scale.set(1, 1); // Update hardcore button text and color if (hardcoreButton) { hardcoreButton.children[1].setText('HARDCORE MODE'); hardcoreButton.children[0].tint = 0xFF0000; } } // Music is now handled by the hardcore button // We don't need to start music here as it would cause duplicates // when toggling modes via the button // This section is kept for when the game is initially loaded if (gameTimer === 0 && outOfSafeZoneTimer === 0) { if (!window.hardcoreMode) { // Normal mode music LK.playMusic('bgMusic', { fade: { start: 0, end: 1.0, // Set to full volume for intense beat duration: 800 } }); } else { // Hardcore mode music - music is already playing from button press // but ensure it's playing in case initGame is called directly LK.playMusic('hardcorebg', { fade: { start: 0, end: 1.0, duration: 800 } }); } } } // Handle dragging function handleMove(x, y, obj) { if (dragNode) { dragNode.x = x; dragNode.y = y; dragNode.isDragging = true; // Reset velocity when dragging dragNode.vx = 0; dragNode.vy = 0; } } // Mouse/touch handlers game.down = function (x, y, obj) { // Start dragging the player dragNode = player; handleMove(x, y, obj); }; game.up = function (x, y, obj) { if (dragNode) { dragNode.isDragging = false; dragNode = null; } }; game.move = handleMove; // Initialize the game initGame(); // Game update loop game.update = function () { // Update game timer gameTimer += 1000 / 60; // Increment by ms per frame // Update timer display var timeLeft = Math.max(0, GAME_DURATION - gameTimer); timerText.setText(formatTime(timeLeft)); // Check if player is in safe zone var wasInSafeZone = isPlayerInSafeZone; isPlayerInSafeZone = checkPlayerInSafeZone(); // Handle transitions between in/out of safe zone if (wasInSafeZone && !isPlayerInSafeZone) { // Just left safe zone safeZone.shrink(); outOfSafeZoneTimer = 0; } else if (!wasInSafeZone && isPlayerInSafeZone) { // Just returned to safe zone safeZone.grow(); } // Update danger timer if outside safe zone if (!isPlayerInSafeZone) { outOfSafeZoneTimer += 1000 / 60; // Play warning sound at specific thresholds if (outOfSafeZoneTimer >= DANGER_TIMEOUT * 0.5 && LK.ticks % 30 === 0) { LK.getSound('warning').play(); } // Game over condition if (outOfSafeZoneTimer >= DANGER_TIMEOUT) { LK.getSound('lose').play(); LK.effects.flashScreen(0xFF0000, 1000); LK.showGameOver(); return; } } else { outOfSafeZoneTimer = 0; } // Update warning display updateWarning(); // Check for random bump time var currentTime = LK.ticks * (1000 / 60); if (nextBumpTime > 0 && currentTime >= nextBumpTime) { applyRandomBump(); } // Add visual beat pulse every second if (LK.ticks % 60 === 0) { // Flash safe zone with beat LK.effects.flashObject(safeZone, 0x00FFFF, 200); // Apply small "bump" to instruction text with beat tween(instructionText, { y: instructionText.y - 5 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(instructionText, { y: 120 }, { duration: 100, easing: tween.easeIn }); } }); } // Win condition if (gameTimer >= GAME_DURATION) { LK.getSound('win').play(); LK.effects.flashScreen(0x00FF00, 1000); LK.showYouWin(); return; } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var HardcoreButton = Container.expand(function () {
var self = Container.call(this);
// Create button background
var btnBackground = self.attachAsset('safeZone', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.3,
tint: 0xFF0000
});
// Create button text
var btnText = new Text2('HARDCORE MODE', {
size: 60,
fill: 0xFFFFFF
});
btnText.anchor.set(0.5, 0.5);
self.addChild(btnText);
// Handle button press
self.down = function (x, y, obj) {
// Visual feedback
tween(btnBackground, {
scaleX: 0.75,
scaleY: 0.28
}, {
duration: 100
});
};
// Handle button release
self.up = function (x, y, obj) {
// Visual feedback
tween(btnBackground, {
scaleX: 0.8,
scaleY: 0.3
}, {
duration: 100,
onFinish: function onFinish() {
// Toggle hardcore mode flag
window.hardcoreMode = !window.hardcoreMode;
// Update button text and color
btnText.setText(window.hardcoreMode ? 'NORMAL MODE' : 'HARDCORE MODE');
btnBackground.tint = window.hardcoreMode ? 0x00FF00 : 0xFF0000;
// Stop any currently playing music first
LK.stopMusic();
// Play evil laugh when entering hardcore mode
if (window.hardcoreMode) {
LK.getSound('evilLaugh').play();
// Play hardcore music
LK.playMusic('hardcorebg', {
fade: {
start: 0,
end: 1.0,
duration: 800
}
});
} else {
// Play normal mode music
LK.playMusic('bgMusic', {
fade: {
start: 0,
end: 1.0,
duration: 800
}
});
}
initGame();
}
});
};
return self;
});
var PlayerCircle = Container.expand(function () {
var self = Container.call(this);
var circleGraphics = self.attachAsset('playerCircle', {
anchorX: 0.5,
anchorY: 0.5
});
// Pulse animation for player
self.startPulse = function () {
tween(circleGraphics, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(circleGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: self.startPulse
});
}
});
};
self.stopPulse = function () {
tween.stop(circleGraphics, {
scaleX: true,
scaleY: true
});
tween(circleGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 300
});
};
self.applyForce = function (angle, magnitude) {
var vx = Math.cos(angle) * magnitude;
var vy = Math.sin(angle) * magnitude;
self.vx = vx;
self.vy = vy;
};
self.vx = 0;
self.vy = 0;
self.friction = 0.95;
self.update = function () {
// Apply velocity
if (!self.isDragging) {
self.x += self.vx;
self.y += self.vy;
// Apply friction
self.vx *= self.friction;
self.vy *= self.friction;
// Stop if velocity is very small
if (Math.abs(self.vx) < 0.1) self.vx = 0;
if (Math.abs(self.vy) < 0.1) self.vy = 0;
// Add slow drift away from center - in both modes, drift away from safe zone
var dx = self.x - safeZone.x;
var dy = self.y - safeZone.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 10) {
// Only apply drift if not exactly at center
var angle = Math.atan2(dy, dx);
// Keep consistent drift force regardless of mode
var driftForce = 0.15;
self.vx += Math.cos(angle) * driftForce;
self.vy += Math.sin(angle) * driftForce;
}
}
// Constrain to screen bounds
if (self.x < 50) {
self.x = 50;
self.vx *= -0.5;
}
if (self.x > 2048 - 50) {
self.x = 2048 - 50;
self.vx *= -0.5;
}
if (self.y < 50) {
self.y = 50;
self.vy *= -0.5;
}
if (self.y > 2732 - 50) {
self.y = 2732 - 50;
self.vy *= -0.5;
}
};
self.isDragging = false;
// Set initial state
self.startPulse();
return self;
});
var SafeZone = Container.expand(function () {
var self = Container.call(this);
var zoneGraphics = self.attachAsset('safeZone', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
// Pulse animation for safe zone
self.startPulse = function () {
tween(zoneGraphics, {
alpha: 0.7
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(zoneGraphics, {
alpha: 0.4
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: self.startPulse
});
}
});
};
self.stopPulse = function () {
tween.stop(zoneGraphics, {
alpha: true
});
};
self.shrink = function () {
tween(zoneGraphics, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 1000,
easing: tween.easeOut
});
};
self.grow = function () {
tween(zoneGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.bounceOut
});
};
// Set initial state
self.startPulse();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x111111
});
/****
* Game Code
****/
// Hardcore mode flag
window.hardcoreMode = false;
// Game constants
var GAME_DURATION = 120000; // 2 minutes
var DANGER_TIMEOUT = 7000; // 7 seconds
var MIN_BUMP_INTERVAL = 5000; // 5 seconds
var MAX_BUMP_INTERVAL = 11000; // 11 seconds
var MAX_BUMP_FORCE = 40; // Increased from 25 for stronger bumps
// Add hardcore button
var hardcoreButton = new HardcoreButton();
hardcoreButton.x = 2048 - 150;
hardcoreButton.y = 120;
// Update button text based on current mode
hardcoreButton.children[1].setText(window.hardcoreMode ? 'NORMAL MODE' : 'HARDCORE MODE');
hardcoreButton.children[0].tint = window.hardcoreMode ? 0x00FF00 : 0xFF0000;
game.addChild(hardcoreButton);
// Game state variables
var gameTimer = 0;
var outOfSafeZoneTimer = 0;
var isPlayerInSafeZone = true;
var lastBumpTime = 0;
var nextBumpTime = 0;
var dragNode = null;
// Create the safe zone
var safeZone = new SafeZone();
safeZone.x = 2048 / 2;
safeZone.y = 2732 / 2;
game.addChild(safeZone);
// Create the player circle
var player = new PlayerCircle();
player.x = 2048 / 2;
player.y = 2732 / 2;
game.addChild(player);
// UI Elements
var timerText = new Text2('2:00', {
size: 100,
fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
var instructionText = new Text2('KEEP THE CIRCLE IN THE MIDDLE', {
size: 70,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0);
instructionText.y = 120;
LK.gui.top.addChild(instructionText);
// Add pulsing animation to instruction text synchronized with beat
function pulseInstructionText() {
tween(instructionText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(instructionText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: pulseInstructionText
});
}
});
}
pulseInstructionText();
var warningText = new Text2('WARNING: RETURN TO SAFE ZONE!', {
size: 70,
fill: 0xFF3333
});
warningText.anchor.set(0.5, 0);
warningText.y = timerText.height + instructionText.height + 150;
warningText.alpha = 0;
LK.gui.top.addChild(warningText);
// Format time as MM:SS
function formatTime(ms) {
var seconds = Math.floor(ms / 1000);
var minutes = Math.floor(seconds / 60);
seconds = seconds % 60;
return minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
}
// Schedule the next random bump
function scheduleNextBump() {
var interval = MIN_BUMP_INTERVAL + Math.random() * (MAX_BUMP_INTERVAL - MIN_BUMP_INTERVAL);
nextBumpTime = lastBumpTime + interval;
}
// Apply a random force to push player away from center
function applyRandomBump() {
// Calculate angle away from center
var centerX = 2048 / 2;
var centerY = 2732 / 2;
var dx = player.x - centerX;
var dy = player.y - centerY;
var angle = Math.atan2(dy, dx);
// If player is at center, use a random angle
if (Math.abs(dx) < 10 && Math.abs(dy) < 10) {
angle = Math.random() * Math.PI * 2;
}
// Get current game progress (0 to 1)
var gameProgress = Math.min(gameTimer / GAME_DURATION, 1);
if (window.hardcoreMode) {
// In hardcore mode, teleport the SAFE ZONE to a random position
var screenMargin = 150;
var randomX, randomY;
// Make sure we don't teleport too close to edges
randomX = Math.random() * (2048 - 2 * screenMargin) + screenMargin;
randomY = Math.random() * (2732 - 2 * screenMargin) + screenMargin;
// Teleport safe zone
safeZone.x = randomX;
safeZone.y = randomY;
// Add stronger visual effect for hardcore mode
LK.effects.flashScreen(0xFF4400, 300);
// Display "Good Luck" message
instructionText.setText("HARDCORE MODE: GOOD LUCK.");
} else {
// Normal mode - apply force
// Increase force based on progress (more force as game goes on)
var forceMagnitude = 20 + (MAX_BUMP_FORCE - 20) * gameProgress; // Starting force increased from 10 to 20
// Apply the force
player.applyForce(angle, forceMagnitude);
}
// Play bump sound
LK.getSound('bump').play();
// Visual effect - flash screen slightly
LK.effects.flashScreen(0xFFFFFF, 200);
// Record time of bump and schedule next one
lastBumpTime = LK.ticks * (1000 / 60); // Convert ticks to ms
scheduleNextBump();
}
// Check if player is in safe zone
function checkPlayerInSafeZone() {
// In both modes, we need to check the distance to the safe zone
// In normal mode, safe zone is centered, but in hardcore, it could be anywhere
var dx = player.x - safeZone.x;
var dy = player.y - safeZone.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Safe zone radius is half the width of the safeZone asset
var safeZoneRadius = safeZone.children[0].width / 2;
return distance < safeZoneRadius;
}
// Handle warning display
function updateWarning() {
if (!isPlayerInSafeZone) {
// Danger progress (0 to 1)
var dangerProgress = outOfSafeZoneTimer / DANGER_TIMEOUT;
// Scale warning text based on danger progress
var scale = 1 + dangerProgress * 0.3;
warningText.scale.set(scale, scale);
// Fade in warning if it's not already visible
if (warningText.alpha < 1) {
tween(warningText, {
alpha: 1
}, {
duration: 300
});
}
// Change text color between red and white for urgency
if (dangerProgress > 0.7) {
if (LK.ticks % 15 === 0) {
// Flash every quarter second
warningText.setText(warningText.text); // Ensure text is refreshed
if (warningText.style && warningText.style.fill) {
warningText.style.fill = warningText.style.fill === "#FF3333" ? "#FFFFFF" : "#FF3333";
} else {
// Fallback if style is not properly initialized
warningText.setText(warningText.text, {
fill: warningText.style && warningText.style.fill === "#FF3333" ? "#FFFFFF" : "#FF3333"
});
}
}
}
} else {
// Fade out warning
if (warningText.alpha > 0) {
tween(warningText, {
alpha: 0
}, {
duration: 300
});
}
}
}
// Start the game
function initGame() {
// Initialize game state
gameTimer = 0;
outOfSafeZoneTimer = 0;
isPlayerInSafeZone = true;
lastBumpTime = 0;
scheduleNextBump();
// Reset positions
player.x = 2048 / 2;
player.y = 2732 / 2;
player.vx = 0;
player.vy = 0;
// Reset safe zone position to center
safeZone.x = 2048 / 2;
safeZone.y = 2732 / 2;
// Update UI for hardcore mode if active
if (window.hardcoreMode) {
// Change title text to indicate hardcore mode with "Good luck"
instructionText.setText("HARDCORE MODE: GOOD LUCK.");
if (!instructionText.style) instructionText.style = {};
instructionText.style.fill = "#FF3333";
// Make the safe zone smaller in hardcore mode
safeZone.children[0].scale.set(0.8, 0.8);
// Update hardcore button text and color
if (hardcoreButton) {
hardcoreButton.children[1].setText('NORMAL MODE');
hardcoreButton.children[0].tint = 0x00FF00;
}
} else {
// Reset to normal mode text
instructionText.setText("KEEP THE CIRCLE IN THE MIDDLE");
if (!instructionText.style) instructionText.style = {};
instructionText.style.fill = "#FFFFFF";
// Reset safe zone size
safeZone.children[0].scale.set(1, 1);
// Update hardcore button text and color
if (hardcoreButton) {
hardcoreButton.children[1].setText('HARDCORE MODE');
hardcoreButton.children[0].tint = 0xFF0000;
}
}
// Music is now handled by the hardcore button
// We don't need to start music here as it would cause duplicates
// when toggling modes via the button
// This section is kept for when the game is initially loaded
if (gameTimer === 0 && outOfSafeZoneTimer === 0) {
if (!window.hardcoreMode) {
// Normal mode music
LK.playMusic('bgMusic', {
fade: {
start: 0,
end: 1.0,
// Set to full volume for intense beat
duration: 800
}
});
} else {
// Hardcore mode music - music is already playing from button press
// but ensure it's playing in case initGame is called directly
LK.playMusic('hardcorebg', {
fade: {
start: 0,
end: 1.0,
duration: 800
}
});
}
}
}
// Handle dragging
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
dragNode.isDragging = true;
// Reset velocity when dragging
dragNode.vx = 0;
dragNode.vy = 0;
}
}
// Mouse/touch handlers
game.down = function (x, y, obj) {
// Start dragging the player
dragNode = player;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
if (dragNode) {
dragNode.isDragging = false;
dragNode = null;
}
};
game.move = handleMove;
// Initialize the game
initGame();
// Game update loop
game.update = function () {
// Update game timer
gameTimer += 1000 / 60; // Increment by ms per frame
// Update timer display
var timeLeft = Math.max(0, GAME_DURATION - gameTimer);
timerText.setText(formatTime(timeLeft));
// Check if player is in safe zone
var wasInSafeZone = isPlayerInSafeZone;
isPlayerInSafeZone = checkPlayerInSafeZone();
// Handle transitions between in/out of safe zone
if (wasInSafeZone && !isPlayerInSafeZone) {
// Just left safe zone
safeZone.shrink();
outOfSafeZoneTimer = 0;
} else if (!wasInSafeZone && isPlayerInSafeZone) {
// Just returned to safe zone
safeZone.grow();
}
// Update danger timer if outside safe zone
if (!isPlayerInSafeZone) {
outOfSafeZoneTimer += 1000 / 60;
// Play warning sound at specific thresholds
if (outOfSafeZoneTimer >= DANGER_TIMEOUT * 0.5 && LK.ticks % 30 === 0) {
LK.getSound('warning').play();
}
// Game over condition
if (outOfSafeZoneTimer >= DANGER_TIMEOUT) {
LK.getSound('lose').play();
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
return;
}
} else {
outOfSafeZoneTimer = 0;
}
// Update warning display
updateWarning();
// Check for random bump time
var currentTime = LK.ticks * (1000 / 60);
if (nextBumpTime > 0 && currentTime >= nextBumpTime) {
applyRandomBump();
}
// Add visual beat pulse every second
if (LK.ticks % 60 === 0) {
// Flash safe zone with beat
LK.effects.flashObject(safeZone, 0x00FFFF, 200);
// Apply small "bump" to instruction text with beat
tween(instructionText, {
y: instructionText.y - 5
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(instructionText, {
y: 120
}, {
duration: 100,
easing: tween.easeIn
});
}
});
}
// Win condition
if (gameTimer >= GAME_DURATION) {
LK.getSound('win').play();
LK.effects.flashScreen(0x00FF00, 1000);
LK.showYouWin();
return;
}
};