/****
* 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