/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Player = Container.expand(function (id, color, x, y) { var self = Container.call(this); self.id = id; self.lives = 4; self.isDragging = false; self.isAI = id !== 1; // Player 1 is human, others are AI self.respawning = false; self.speed = 5; self.pushForce = 15; self.mass = 1; self.sensitivity = 1; // Base sensitivity to impacts self.velocity = { x: 0, y: 0 }; self.canMove = true; // Attach the player graphic self.graphic = self.attachAsset('player' + id, { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); // Create lives display self.livesContainer = new Container(); self.addChild(self.livesContainer); self.livesDisplay = []; for (var i = 0; i < self.lives; i++) { var life = LK.getAsset('life', { anchorX: 0.5, anchorY: 0.5 }); life.x = i * 35 - (self.lives - 1) * 35 / 2; life.y = -70; self.livesDisplay.push(life); self.livesContainer.addChild(life); } // Position player self.x = x; self.y = y; // Handle input events self.down = function (x, y, obj) { if (self.id === 1 && self.canMove && !self.respawning) { self.isDragging = true; console.log("Player dragging started"); } }; self.up = function (x, y, obj) { self.isDragging = false; }; // Method to lose a life self.loseLife = function () { if (self.respawning) return; self.lives--; if (self.lives >= 0 && self.livesDisplay[self.lives]) { self.livesContainer.removeChild(self.livesDisplay[self.lives]); } LK.getSound('fall').play(); if (self.lives <= 0) { // Player is eliminated self.canMove = false; self.visible = false; self.eliminated = true; return true; // Player eliminated } else { // Respawn player self.respawn(); return false; // Player still in game } }; // Method to respawn player self.respawn = function () { self.respawning = true; self.alpha = 0.5; // Place player in a safe position var angle = Math.random() * Math.PI * 2; var radius = arena.width * 0.3; self.x = arena.x + Math.cos(angle) * radius; self.y = arena.y + Math.sin(angle) * radius; // Reset velocity self.velocity.x = 0; self.velocity.y = 0; // Partially reset sensitivity on respawn (can't fully escape consequences) var oldSensitivity = self.sensitivity; self.sensitivity = Math.max(1, self.sensitivity * 0.7); // Visual feedback for sensitivity reset if (oldSensitivity > self.sensitivity) { tween(self, { alpha: 0.2 }, { duration: 300, onFinish: function onFinish() { tween(self, { alpha: 0.5 }, { duration: 300 }); } }); } // Make player immune for a short time LK.setTimeout(function () { self.respawning = false; self.alpha = 1; }, 2000); }; // Method to check if player is off the arena self.checkOffArena = function () { if (self.respawning) return false; var dx = self.x - arena.x; var dy = self.y - arena.y; var distanceSquared = dx * dx + dy * dy; // Different check depending on arena shape if (gameState.arenaShape === 'circle') { var radiusSquared = Math.pow(arena.width / 2, 2); return distanceSquared > radiusSquared; } else if (gameState.arenaShape === 'square') { var halfWidth = arena.width / 2; return Math.abs(dx) > halfWidth || Math.abs(dy) > halfWidth; } else if (gameState.arenaShape === 'rectangle') { var halfWidth = arena.width / 2; var halfHeight = arena.height / 2; return Math.abs(dx) > halfWidth || Math.abs(dy) > halfHeight; } return false; }; // AI movement logic self.updateAI = function () { if (!self.isAI || !self.canMove || self.respawning) return; // Simple AI behavior: // 1. Move toward center if close to edge // 2. Otherwise move toward nearest player to push them off var dx = self.x - arena.x; var dy = self.y - arena.y; var distanceToCenter = Math.sqrt(dx * dx + dy * dy); // If close to edge, move toward center if (distanceToCenter > arena.width * 0.4) { var angleToCenter = Math.atan2(arena.y - self.y, arena.x - self.x); self.velocity.x += Math.cos(angleToCenter) * 0.5; self.velocity.y += Math.sin(angleToCenter) * 0.5; } else { // Find nearest player var nearestPlayer = null; var minDistance = Infinity; for (var i = 0; i < players.length; i++) { var otherPlayer = players[i]; if (otherPlayer === self || !otherPlayer.canMove || otherPlayer.respawning) continue; var otherDx = otherPlayer.x - self.x; var otherDy = otherPlayer.y - self.y; var distance = Math.sqrt(otherDx * otherDx + otherDy * otherDy); if (distance < minDistance) { minDistance = distance; nearestPlayer = otherPlayer; } } // Move toward nearest player if (nearestPlayer) { var angleToPlayer = Math.atan2(nearestPlayer.y - self.y, nearestPlayer.x - self.x); self.velocity.x += Math.cos(angleToPlayer) * 0.5; self.velocity.y += Math.sin(angleToPlayer) * 0.5; } } }; // Physics update self.update = function () { if (!self.canMove) return; // Update AI movement self.updateAI(); // Apply physics self.velocity.x *= 0.95; // Apply friction self.velocity.y *= 0.95; self.x += self.velocity.x; self.y += self.velocity.y; // Update visual representation of sensitivity var baseTint = self.id === 1 ? 0xff0000 : self.id === 2 ? 0x0000ff : self.id === 3 ? 0x00ff00 : 0xffff00; // Mix in white based on sensitivity to create a visual indicator var sensitivityFactor = Math.min(1, (self.sensitivity - 1) / 3); // Cap at 4x base sensitivity var r = (baseTint >> 16 & 0xFF) + (255 - (baseTint >> 16 & 0xFF)) * sensitivityFactor; var g = (baseTint >> 8 & 0xFF) + (255 - (baseTint >> 8 & 0xFF)) * sensitivityFactor; var b = (baseTint & 0xFF) + (255 - (baseTint & 0xFF)) * sensitivityFactor; var newTint = Math.floor(r) << 16 | Math.floor(g) << 8 | Math.floor(b); self.graphic.tint = newTint; // Check if off arena if (self.checkOffArena()) { var eliminated = self.loseLife(); if (eliminated) { checkGameEnd(); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Game variables var players = []; var arena; var timerBar; var timerBarFill; var timerText; var statusText; var matchTimer = 45; // 45 seconds until arena starts shrinking var totalMatchTime = 180; // 3 minutes total match time var gameState = { started: false, shrinking: false, ended: false, arenaShape: 'circle', // 'circle', 'square', or 'rectangle' shrinkAmount: 0.995, // Arena shrinks to 0.5% per frame when shrinking roundNumber: 1 }; // Initialize arena function initArena() { // Remove old arena if it exists if (arena) { game.removeChild(arena); } // Create new arena based on current shape arena = LK.getAsset('arena', { anchorX: 0.5, anchorY: 0.5 }); // Set arena dimensions based on shape if (gameState.arenaShape === 'circle') { arena.width = 1800; arena.height = 1800; } else if (gameState.arenaShape === 'square') { arena.width = 1600; arena.height = 1600; arena.tint = 0x8B4513; // Slightly different color for square } else if (gameState.arenaShape === 'rectangle') { arena.width = 2000; arena.height = 1200; arena.tint = 0x996633; // Slightly different color for rectangle } arena.x = 2048 / 2; arena.y = 2732 / 2; game.addChild(arena); // Make sure arena is behind players for (var i = 0; i < players.length; i++) { if (players[i]) { game.removeChild(players[i]); game.addChild(players[i]); } } } // Initialize players function initPlayers() { // Clear existing players for (var i = 0; i < players.length; i++) { if (players[i]) { game.removeChild(players[i]); } } players = []; // Create 4 players var positions = [{ x: arena.x - arena.width * 0.3, y: arena.y - arena.height * 0.3 }, { x: arena.x + arena.width * 0.3, y: arena.y - arena.height * 0.3 }, { x: arena.x - arena.width * 0.3, y: arena.y + arena.height * 0.3 }, { x: arena.x + arena.width * 0.3, y: arena.y + arena.height * 0.3 }]; for (var i = 0; i < 4; i++) { var player = new Player(i + 1, i + 1, positions[i].x, positions[i].y); // Ensure sensitivity starts at base level for new rounds player.sensitivity = 1; players.push(player); game.addChild(player); } } // Initialize UI function initUI() { // Create timer bar timerBar = LK.getAsset('timer', { anchorX: 0.5, anchorY: 0.5 }); timerBar.x = 2048 / 2; timerBar.y = 80; timerBarFill = LK.getAsset('timerFill', { anchorX: 0, anchorY: 0.5 }); timerBarFill.x = -timerBarFill.width / 2; timerBarFill.y = 0; timerBar.addChild(timerBarFill); game.addChild(timerBar); // Create timer text timerText = new Text2("01:00", { size: 50, fill: 0xFFFFFF }); timerText.anchor.set(0.5, 0.5); timerText.x = 2048 / 2; timerText.y = 150; game.addChild(timerText); // Create status text statusText = new Text2("Round " + gameState.roundNumber + " - Push opponents off the arena!", { size: 60, fill: 0xFFFFFF }); statusText.anchor.set(0.5, 0.5); statusText.x = 2048 / 2; statusText.y = 220; game.addChild(statusText); } // Check for game end function checkGameEnd() { var playersAlive = 0; var lastAlivePlayer = null; for (var i = 0; i < players.length; i++) { if (players[i] && players[i].lives > 0) { playersAlive++; lastAlivePlayer = players[i]; } } if (playersAlive <= 1 && !gameState.ended) { gameState.ended = true; if (lastAlivePlayer) { statusText.setText("Player " + lastAlivePlayer.id + " wins!"); LK.setScore(lastAlivePlayer.id); // Show win screen after a short delay LK.setTimeout(function () { LK.showYouWin(); }, 2000); } else { statusText.setText("Draw!"); // Show game over after a short delay LK.setTimeout(function () { LK.showGameOver(); }, 2000); } } } // Reset game for a new round function startNewRound() { // Increment round number gameState.roundNumber++; // Change arena shape for the next round if (gameState.arenaShape === 'circle') { gameState.arenaShape = 'square'; } else if (gameState.arenaShape === 'square') { gameState.arenaShape = 'rectangle'; } else { gameState.arenaShape = 'circle'; } // Reset game state gameState.started = false; gameState.shrinking = false; gameState.ended = false; matchTimer = 45; // Initialize game elements initArena(); initPlayers(); // Update UI statusText.setText("Round " + gameState.roundNumber + " - Push opponents off the arena!"); // Start the game gameState.started = true; } // Handle dragging the human player function handleDrag(x, y) { if (players[0] && players[0].isDragging && players[0].canMove && !players[0].respawning) { // Calculate direction vector var dx = x - players[0].x; var dy = y - players[0].y; var distance = Math.sqrt(dx * dx + dy * dy); // Apply force toward the touch position if (distance > 0) { var maxSpeed = 10; var speedX = Math.min(dx, maxSpeed); var speedY = Math.min(dy, maxSpeed); players[0].velocity.x += speedX * 0.1; players[0].velocity.y += speedY * 0.1; } } } // Collision detection and resolution between players function handleCollisions() { for (var i = 0; i < players.length; i++) { var playerA = players[i]; if (!playerA || !playerA.canMove || playerA.respawning) continue; for (var j = i + 1; j < players.length; j++) { var playerB = players[j]; if (!playerB || !playerB.canMove || playerB.respawning) continue; var dx = playerB.x - playerA.x; var dy = playerB.y - playerA.y; var distance = Math.sqrt(dx * dx + dy * dy); var minDistance = playerA.graphic.width / 2 + playerB.graphic.width / 2; if (distance < minDistance) { // Collision detected LK.getSound('push').play(); // Calculate collision response var angle = Math.atan2(dy, dx); var overlap = minDistance - distance; // Move players apart var moveX = Math.cos(angle) * overlap * 0.5; var moveY = Math.sin(angle) * overlap * 0.5; playerA.x -= moveX; playerA.y -= moveY; playerB.x += moveX; playerB.y += moveY; // Calculate impulse var impulse = 2 * (playerA.velocity.x * Math.cos(angle) + playerA.velocity.y * Math.sin(angle) - playerB.velocity.x * Math.cos(angle) - playerB.velocity.y * Math.sin(angle)) / (playerA.mass + playerB.mass); // Apply impulse with sensitivity factor playerA.velocity.x -= impulse * playerA.mass * Math.cos(angle) * 1.5 * playerA.sensitivity; playerA.velocity.y -= impulse * playerA.mass * Math.sin(angle) * 1.5 * playerA.sensitivity; playerB.velocity.x += impulse * playerB.mass * Math.cos(angle) * 1.5 * playerB.sensitivity; playerB.velocity.y += impulse * playerB.mass * Math.sin(angle) * 1.5 * playerB.sensitivity; // Increase sensitivity on collision playerA.sensitivity += 0.05; playerB.sensitivity += 0.05; // Visual feedback for increased sensitivity tween(playerA.graphic, { alpha: 0.3 }, { duration: 200, onFinish: function onFinish() { tween(playerA.graphic, { alpha: 1 }, { duration: 200 }); } }); tween(playerB.graphic, { alpha: 0.3 }, { duration: 200, onFinish: function onFinish() { tween(playerB.graphic, { alpha: 1 }, { duration: 200 }); } }); } } } } // Format time as MM:SS function formatTime(seconds) { var minutes = Math.floor(seconds / 60); var remainingSeconds = Math.floor(seconds % 60); return (minutes < 10 ? "0" : "") + minutes + ":" + (remainingSeconds < 10 ? "0" : "") + remainingSeconds; } // Update timer function updateTimer() { matchTimer -= 1 / 60; // Decrease by 1/60th of a second (assuming 60 FPS) if (matchTimer <= 0 && !gameState.shrinking) { // Start shrinking the arena gameState.shrinking = true; statusText.setText("Arena is shrinking!"); LK.getSound('warning').play(); // Flash the status text tween(statusText, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { tween(statusText, { alpha: 1 }, { duration: 300 }); } }); } // Update timer display timerText.setText(formatTime(Math.max(0, matchTimer))); // Update timer bar var progress = Math.max(0, matchTimer / 45); timerBarFill.width = 496 * progress; // If arena is shrinking, change timer color to red if (gameState.shrinking) { timerBarFill.tint = 0xFF0000; } } // Initialize the game function initGame() { // Set arena shape to circle for first round gameState.arenaShape = 'circle'; gameState.roundNumber = 1; // Initialize game elements initArena(); initPlayers(); initUI(); // Reset game state gameState.started = true; gameState.shrinking = false; gameState.ended = false; matchTimer = 45; // Play background music LK.playMusic('background'); } // Handle game events game.down = function (x, y, obj) { // Forward touch events to the human player if (players[0]) { players[0].down(x, y, obj); } }; game.up = function (x, y, obj) { // Forward touch events to the human player if (players[0]) { players[0].up(x, y, obj); } }; game.move = function (x, y, obj) { handleDrag(x, y); }; // Main game loop game.update = function () { // Initialize game on first update if (!gameState.started) { initGame(); return; } // Don't update if game ended if (gameState.ended) return; // Update timer updateTimer(); // Update players for (var i = 0; i < players.length; i++) { if (players[i]) { players[i].update(); } } // Handle collisions between players handleCollisions(); // Shrink arena if time has run out if (gameState.shrinking && arena.width > 400) { arena.width *= gameState.shrinkAmount; arena.height *= gameState.shrinkAmount; } }; // Initialize game initGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Player = Container.expand(function (id, color, x, y) {
var self = Container.call(this);
self.id = id;
self.lives = 4;
self.isDragging = false;
self.isAI = id !== 1; // Player 1 is human, others are AI
self.respawning = false;
self.speed = 5;
self.pushForce = 15;
self.mass = 1;
self.sensitivity = 1; // Base sensitivity to impacts
self.velocity = {
x: 0,
y: 0
};
self.canMove = true;
// Attach the player graphic
self.graphic = self.attachAsset('player' + id, {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
// Create lives display
self.livesContainer = new Container();
self.addChild(self.livesContainer);
self.livesDisplay = [];
for (var i = 0; i < self.lives; i++) {
var life = LK.getAsset('life', {
anchorX: 0.5,
anchorY: 0.5
});
life.x = i * 35 - (self.lives - 1) * 35 / 2;
life.y = -70;
self.livesDisplay.push(life);
self.livesContainer.addChild(life);
}
// Position player
self.x = x;
self.y = y;
// Handle input events
self.down = function (x, y, obj) {
if (self.id === 1 && self.canMove && !self.respawning) {
self.isDragging = true;
console.log("Player dragging started");
}
};
self.up = function (x, y, obj) {
self.isDragging = false;
};
// Method to lose a life
self.loseLife = function () {
if (self.respawning) return;
self.lives--;
if (self.lives >= 0 && self.livesDisplay[self.lives]) {
self.livesContainer.removeChild(self.livesDisplay[self.lives]);
}
LK.getSound('fall').play();
if (self.lives <= 0) {
// Player is eliminated
self.canMove = false;
self.visible = false;
self.eliminated = true;
return true; // Player eliminated
} else {
// Respawn player
self.respawn();
return false; // Player still in game
}
};
// Method to respawn player
self.respawn = function () {
self.respawning = true;
self.alpha = 0.5;
// Place player in a safe position
var angle = Math.random() * Math.PI * 2;
var radius = arena.width * 0.3;
self.x = arena.x + Math.cos(angle) * radius;
self.y = arena.y + Math.sin(angle) * radius;
// Reset velocity
self.velocity.x = 0;
self.velocity.y = 0;
// Partially reset sensitivity on respawn (can't fully escape consequences)
var oldSensitivity = self.sensitivity;
self.sensitivity = Math.max(1, self.sensitivity * 0.7);
// Visual feedback for sensitivity reset
if (oldSensitivity > self.sensitivity) {
tween(self, {
alpha: 0.2
}, {
duration: 300,
onFinish: function onFinish() {
tween(self, {
alpha: 0.5
}, {
duration: 300
});
}
});
}
// Make player immune for a short time
LK.setTimeout(function () {
self.respawning = false;
self.alpha = 1;
}, 2000);
};
// Method to check if player is off the arena
self.checkOffArena = function () {
if (self.respawning) return false;
var dx = self.x - arena.x;
var dy = self.y - arena.y;
var distanceSquared = dx * dx + dy * dy;
// Different check depending on arena shape
if (gameState.arenaShape === 'circle') {
var radiusSquared = Math.pow(arena.width / 2, 2);
return distanceSquared > radiusSquared;
} else if (gameState.arenaShape === 'square') {
var halfWidth = arena.width / 2;
return Math.abs(dx) > halfWidth || Math.abs(dy) > halfWidth;
} else if (gameState.arenaShape === 'rectangle') {
var halfWidth = arena.width / 2;
var halfHeight = arena.height / 2;
return Math.abs(dx) > halfWidth || Math.abs(dy) > halfHeight;
}
return false;
};
// AI movement logic
self.updateAI = function () {
if (!self.isAI || !self.canMove || self.respawning) return;
// Simple AI behavior:
// 1. Move toward center if close to edge
// 2. Otherwise move toward nearest player to push them off
var dx = self.x - arena.x;
var dy = self.y - arena.y;
var distanceToCenter = Math.sqrt(dx * dx + dy * dy);
// If close to edge, move toward center
if (distanceToCenter > arena.width * 0.4) {
var angleToCenter = Math.atan2(arena.y - self.y, arena.x - self.x);
self.velocity.x += Math.cos(angleToCenter) * 0.5;
self.velocity.y += Math.sin(angleToCenter) * 0.5;
} else {
// Find nearest player
var nearestPlayer = null;
var minDistance = Infinity;
for (var i = 0; i < players.length; i++) {
var otherPlayer = players[i];
if (otherPlayer === self || !otherPlayer.canMove || otherPlayer.respawning) continue;
var otherDx = otherPlayer.x - self.x;
var otherDy = otherPlayer.y - self.y;
var distance = Math.sqrt(otherDx * otherDx + otherDy * otherDy);
if (distance < minDistance) {
minDistance = distance;
nearestPlayer = otherPlayer;
}
}
// Move toward nearest player
if (nearestPlayer) {
var angleToPlayer = Math.atan2(nearestPlayer.y - self.y, nearestPlayer.x - self.x);
self.velocity.x += Math.cos(angleToPlayer) * 0.5;
self.velocity.y += Math.sin(angleToPlayer) * 0.5;
}
}
};
// Physics update
self.update = function () {
if (!self.canMove) return;
// Update AI movement
self.updateAI();
// Apply physics
self.velocity.x *= 0.95; // Apply friction
self.velocity.y *= 0.95;
self.x += self.velocity.x;
self.y += self.velocity.y;
// Update visual representation of sensitivity
var baseTint = self.id === 1 ? 0xff0000 : self.id === 2 ? 0x0000ff : self.id === 3 ? 0x00ff00 : 0xffff00;
// Mix in white based on sensitivity to create a visual indicator
var sensitivityFactor = Math.min(1, (self.sensitivity - 1) / 3); // Cap at 4x base sensitivity
var r = (baseTint >> 16 & 0xFF) + (255 - (baseTint >> 16 & 0xFF)) * sensitivityFactor;
var g = (baseTint >> 8 & 0xFF) + (255 - (baseTint >> 8 & 0xFF)) * sensitivityFactor;
var b = (baseTint & 0xFF) + (255 - (baseTint & 0xFF)) * sensitivityFactor;
var newTint = Math.floor(r) << 16 | Math.floor(g) << 8 | Math.floor(b);
self.graphic.tint = newTint;
// Check if off arena
if (self.checkOffArena()) {
var eliminated = self.loseLife();
if (eliminated) {
checkGameEnd();
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var players = [];
var arena;
var timerBar;
var timerBarFill;
var timerText;
var statusText;
var matchTimer = 45; // 45 seconds until arena starts shrinking
var totalMatchTime = 180; // 3 minutes total match time
var gameState = {
started: false,
shrinking: false,
ended: false,
arenaShape: 'circle',
// 'circle', 'square', or 'rectangle'
shrinkAmount: 0.995,
// Arena shrinks to 0.5% per frame when shrinking
roundNumber: 1
};
// Initialize arena
function initArena() {
// Remove old arena if it exists
if (arena) {
game.removeChild(arena);
}
// Create new arena based on current shape
arena = LK.getAsset('arena', {
anchorX: 0.5,
anchorY: 0.5
});
// Set arena dimensions based on shape
if (gameState.arenaShape === 'circle') {
arena.width = 1800;
arena.height = 1800;
} else if (gameState.arenaShape === 'square') {
arena.width = 1600;
arena.height = 1600;
arena.tint = 0x8B4513; // Slightly different color for square
} else if (gameState.arenaShape === 'rectangle') {
arena.width = 2000;
arena.height = 1200;
arena.tint = 0x996633; // Slightly different color for rectangle
}
arena.x = 2048 / 2;
arena.y = 2732 / 2;
game.addChild(arena);
// Make sure arena is behind players
for (var i = 0; i < players.length; i++) {
if (players[i]) {
game.removeChild(players[i]);
game.addChild(players[i]);
}
}
}
// Initialize players
function initPlayers() {
// Clear existing players
for (var i = 0; i < players.length; i++) {
if (players[i]) {
game.removeChild(players[i]);
}
}
players = [];
// Create 4 players
var positions = [{
x: arena.x - arena.width * 0.3,
y: arena.y - arena.height * 0.3
}, {
x: arena.x + arena.width * 0.3,
y: arena.y - arena.height * 0.3
}, {
x: arena.x - arena.width * 0.3,
y: arena.y + arena.height * 0.3
}, {
x: arena.x + arena.width * 0.3,
y: arena.y + arena.height * 0.3
}];
for (var i = 0; i < 4; i++) {
var player = new Player(i + 1, i + 1, positions[i].x, positions[i].y);
// Ensure sensitivity starts at base level for new rounds
player.sensitivity = 1;
players.push(player);
game.addChild(player);
}
}
// Initialize UI
function initUI() {
// Create timer bar
timerBar = LK.getAsset('timer', {
anchorX: 0.5,
anchorY: 0.5
});
timerBar.x = 2048 / 2;
timerBar.y = 80;
timerBarFill = LK.getAsset('timerFill', {
anchorX: 0,
anchorY: 0.5
});
timerBarFill.x = -timerBarFill.width / 2;
timerBarFill.y = 0;
timerBar.addChild(timerBarFill);
game.addChild(timerBar);
// Create timer text
timerText = new Text2("01:00", {
size: 50,
fill: 0xFFFFFF
});
timerText.anchor.set(0.5, 0.5);
timerText.x = 2048 / 2;
timerText.y = 150;
game.addChild(timerText);
// Create status text
statusText = new Text2("Round " + gameState.roundNumber + " - Push opponents off the arena!", {
size: 60,
fill: 0xFFFFFF
});
statusText.anchor.set(0.5, 0.5);
statusText.x = 2048 / 2;
statusText.y = 220;
game.addChild(statusText);
}
// Check for game end
function checkGameEnd() {
var playersAlive = 0;
var lastAlivePlayer = null;
for (var i = 0; i < players.length; i++) {
if (players[i] && players[i].lives > 0) {
playersAlive++;
lastAlivePlayer = players[i];
}
}
if (playersAlive <= 1 && !gameState.ended) {
gameState.ended = true;
if (lastAlivePlayer) {
statusText.setText("Player " + lastAlivePlayer.id + " wins!");
LK.setScore(lastAlivePlayer.id);
// Show win screen after a short delay
LK.setTimeout(function () {
LK.showYouWin();
}, 2000);
} else {
statusText.setText("Draw!");
// Show game over after a short delay
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
}
}
}
// Reset game for a new round
function startNewRound() {
// Increment round number
gameState.roundNumber++;
// Change arena shape for the next round
if (gameState.arenaShape === 'circle') {
gameState.arenaShape = 'square';
} else if (gameState.arenaShape === 'square') {
gameState.arenaShape = 'rectangle';
} else {
gameState.arenaShape = 'circle';
}
// Reset game state
gameState.started = false;
gameState.shrinking = false;
gameState.ended = false;
matchTimer = 45;
// Initialize game elements
initArena();
initPlayers();
// Update UI
statusText.setText("Round " + gameState.roundNumber + " - Push opponents off the arena!");
// Start the game
gameState.started = true;
}
// Handle dragging the human player
function handleDrag(x, y) {
if (players[0] && players[0].isDragging && players[0].canMove && !players[0].respawning) {
// Calculate direction vector
var dx = x - players[0].x;
var dy = y - players[0].y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Apply force toward the touch position
if (distance > 0) {
var maxSpeed = 10;
var speedX = Math.min(dx, maxSpeed);
var speedY = Math.min(dy, maxSpeed);
players[0].velocity.x += speedX * 0.1;
players[0].velocity.y += speedY * 0.1;
}
}
}
// Collision detection and resolution between players
function handleCollisions() {
for (var i = 0; i < players.length; i++) {
var playerA = players[i];
if (!playerA || !playerA.canMove || playerA.respawning) continue;
for (var j = i + 1; j < players.length; j++) {
var playerB = players[j];
if (!playerB || !playerB.canMove || playerB.respawning) continue;
var dx = playerB.x - playerA.x;
var dy = playerB.y - playerA.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var minDistance = playerA.graphic.width / 2 + playerB.graphic.width / 2;
if (distance < minDistance) {
// Collision detected
LK.getSound('push').play();
// Calculate collision response
var angle = Math.atan2(dy, dx);
var overlap = minDistance - distance;
// Move players apart
var moveX = Math.cos(angle) * overlap * 0.5;
var moveY = Math.sin(angle) * overlap * 0.5;
playerA.x -= moveX;
playerA.y -= moveY;
playerB.x += moveX;
playerB.y += moveY;
// Calculate impulse
var impulse = 2 * (playerA.velocity.x * Math.cos(angle) + playerA.velocity.y * Math.sin(angle) - playerB.velocity.x * Math.cos(angle) - playerB.velocity.y * Math.sin(angle)) / (playerA.mass + playerB.mass);
// Apply impulse with sensitivity factor
playerA.velocity.x -= impulse * playerA.mass * Math.cos(angle) * 1.5 * playerA.sensitivity;
playerA.velocity.y -= impulse * playerA.mass * Math.sin(angle) * 1.5 * playerA.sensitivity;
playerB.velocity.x += impulse * playerB.mass * Math.cos(angle) * 1.5 * playerB.sensitivity;
playerB.velocity.y += impulse * playerB.mass * Math.sin(angle) * 1.5 * playerB.sensitivity;
// Increase sensitivity on collision
playerA.sensitivity += 0.05;
playerB.sensitivity += 0.05;
// Visual feedback for increased sensitivity
tween(playerA.graphic, {
alpha: 0.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(playerA.graphic, {
alpha: 1
}, {
duration: 200
});
}
});
tween(playerB.graphic, {
alpha: 0.3
}, {
duration: 200,
onFinish: function onFinish() {
tween(playerB.graphic, {
alpha: 1
}, {
duration: 200
});
}
});
}
}
}
}
// Format time as MM:SS
function formatTime(seconds) {
var minutes = Math.floor(seconds / 60);
var remainingSeconds = Math.floor(seconds % 60);
return (minutes < 10 ? "0" : "") + minutes + ":" + (remainingSeconds < 10 ? "0" : "") + remainingSeconds;
}
// Update timer
function updateTimer() {
matchTimer -= 1 / 60; // Decrease by 1/60th of a second (assuming 60 FPS)
if (matchTimer <= 0 && !gameState.shrinking) {
// Start shrinking the arena
gameState.shrinking = true;
statusText.setText("Arena is shrinking!");
LK.getSound('warning').play();
// Flash the status text
tween(statusText, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
tween(statusText, {
alpha: 1
}, {
duration: 300
});
}
});
}
// Update timer display
timerText.setText(formatTime(Math.max(0, matchTimer)));
// Update timer bar
var progress = Math.max(0, matchTimer / 45);
timerBarFill.width = 496 * progress;
// If arena is shrinking, change timer color to red
if (gameState.shrinking) {
timerBarFill.tint = 0xFF0000;
}
}
// Initialize the game
function initGame() {
// Set arena shape to circle for first round
gameState.arenaShape = 'circle';
gameState.roundNumber = 1;
// Initialize game elements
initArena();
initPlayers();
initUI();
// Reset game state
gameState.started = true;
gameState.shrinking = false;
gameState.ended = false;
matchTimer = 45;
// Play background music
LK.playMusic('background');
}
// Handle game events
game.down = function (x, y, obj) {
// Forward touch events to the human player
if (players[0]) {
players[0].down(x, y, obj);
}
};
game.up = function (x, y, obj) {
// Forward touch events to the human player
if (players[0]) {
players[0].up(x, y, obj);
}
};
game.move = function (x, y, obj) {
handleDrag(x, y);
};
// Main game loop
game.update = function () {
// Initialize game on first update
if (!gameState.started) {
initGame();
return;
}
// Don't update if game ended
if (gameState.ended) return;
// Update timer
updateTimer();
// Update players
for (var i = 0; i < players.length; i++) {
if (players[i]) {
players[i].update();
}
}
// Handle collisions between players
handleCollisions();
// Shrink arena if time has run out
if (gameState.shrinking && arena.width > 400) {
arena.width *= gameState.shrinkAmount;
arena.height *= gameState.shrinkAmount;
}
};
// Initialize game
initGame();
bird's eye view of a round rocky arena surrounded by flames decorated with red lava. In-Game asset. 2d. High contrast. No shadows
hearth. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
fighter 1. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
fighter 2. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
fighter 3 . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
fighter 4. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat