/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Player Brawler class var Brawler = Container.expand(function () { var self = Container.call(this); // Attach brawler asset (box, blue) var brawlerAsset = self.attachAsset('brawler', { anchorX: 0.5, anchorY: 0.5 }); // Attach a gun image asset (anchored at left-middle) var gunAsset = self.attachAsset('gun', { anchorX: 0.0, anchorY: 0.5 }); gunAsset.x = 60; // position gun to the right of brawler gunAsset.y = 0; self.gunAsset = gunAsset; // Movement speed (pixels per tick) self.speed = 16; // Direction vector for movement (set by drag) self.moveDir = { x: 0, y: 0 }; // Shooting cooldown (ticks) self.shootCooldown = 0; // Health self.maxHealth = 5; self.health = self.maxHealth; // For hit flash self.isHit = false; self.hitTimer = 0; // Update method called every tick self.update = function () { // Move if (self.moveDir.x !== 0 || self.moveDir.y !== 0) { var mag = Math.sqrt(self.moveDir.x * self.moveDir.x + self.moveDir.y * self.moveDir.y); if (mag > 0) { var dx = self.moveDir.x / mag * self.speed; var dy = self.moveDir.y / mag * self.speed; self.x += dx; self.y += dy; } } // Clamp to arena bounds (with margin) var margin = 100; if (self.x < margin) self.x = margin; if (self.x > 2048 - margin) self.x = 2048 - margin; if (self.y < margin) self.y = margin; if (self.y > 2732 - margin) self.y = 2732 - margin; // Rotate gun to aim at nearest enemy if (typeof enemies !== "undefined" && enemies.length > 0 && self.gunAsset) { var nearest = null; var minDist = 999999; for (var i = 0; i < enemies.length; i++) { var dx = enemies[i].x - self.x; var dy = enemies[i].y - self.y; var dist = dx * dx + dy * dy; if (dist < minDist) { minDist = dist; nearest = enemies[i]; } } if (nearest) { var dx = nearest.x - self.x; var dy = nearest.y - self.y; self.gunAsset.rotation = Math.atan2(dy, dx); } } // Shooting cooldown if (self.shootCooldown > 0) self.shootCooldown--; // Hit flash if (self.isHit) { self.hitTimer--; if (self.hitTimer <= 0) { self.isHit = false; brawlerAsset.tint = 0x3498db; } } }; // Take damage self.takeDamage = function (amount) { self.health -= amount; if (self.health < 0) self.health = 0; // Flash red brawlerAsset.tint = 0xff4444; self.isHit = true; self.hitTimer = 12; }; // Heal self.heal = function (amount) { self.health += amount; if (self.health > self.maxHealth) self.health = self.maxHealth; }; // Reset tint brawlerAsset.tint = 0x3498db; return self; }); // Bullet class (player's bullet) var Bullet = Container.expand(function () { var self = Container.call(this); // Attach bullet asset (box, yellow) var bulletAsset = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); // Direction vector self.dir = { x: 0, y: 0 }; // Speed self.speed = 40; // Lifetime (ticks) self.lifetime = 60; // Set initial rotation to match direction (default 0) self.setRotationFromDir = function () { // Only set if direction is not zero if (self.dir.x !== 0 || self.dir.y !== 0) { self.rotation = Math.atan2(self.dir.y, self.dir.x); } }; // Update method self.update = function () { // Ensure rotation matches direction self.setRotationFromDir(); self.x += self.dir.x * self.speed; self.y += self.dir.y * self.speed; self.lifetime--; }; return self; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); // Attach enemy asset (ellipse, red) var enemyAsset = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); // Movement speed self.speed = 9; // Enemy speed fixed at 9 // Health self.maxHealth = 2; self.health = self.maxHealth; // Target (the player) self.target = null; // For hit flash self.isHit = false; self.hitTimer = 0; // Update method self.update = function () { if (self.target) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var mag = Math.sqrt(dx * dx + dy * dy); if (mag > 0) { self.x += dx / mag * self.speed; self.y += dy / mag * self.speed; } } // Clamp to arena bounds var margin = 80; if (self.x < margin) self.x = margin; if (self.x > 2048 - margin) self.x = 2048 - margin; if (self.y < margin) self.y = margin; if (self.y > 2732 - margin) self.y = 2732 - margin; // Hit flash if (self.isHit) { self.hitTimer--; if (self.hitTimer <= 0) { self.isHit = false; enemyAsset.tint = 0xd83318; } } }; // Take damage self.takeDamage = function (amount) { self.health -= amount; if (self.health < 0) self.health = 0; // Flash yellow enemyAsset.tint = 0xffe066; self.isHit = true; self.hitTimer = 8; }; // Reset tint enemyAsset.tint = 0xd83318; return self; }); // Gem class (collectible) var Gem = Container.expand(function () { var self = Container.call(this); // Attach gem asset (ellipse, green) var gemAsset = self.attachAsset('gem', { anchorX: 0.5, anchorY: 0.5 }); // For floating animation self.floatDir = Math.random() > 0.5 ? 1 : -1; self.floatTick = Math.floor(Math.random() * 60); self.update = function () { self.floatTick++; self.y += Math.sin(self.floatTick / 10) * 0.8 * self.floatDir; }; return self; }); // PowerUp class (heal or speed) var PowerUp = Container.expand(function () { var self = Container.call(this); // Type: 'heal' or 'speed' self.type = 'heal'; // Attach asset (box, purple for speed, pink for heal) var color = self.type === 'speed' ? 0x9b59b6 : 0xff69b4; var powerAsset = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); powerAsset.tint = color; // For floating animation self.floatTick = Math.floor(Math.random() * 60); self.update = function () { self.floatTick++; self.y += Math.sin(self.floatTick / 12) * 0.7; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222a36 }); /**** * Game Code ****/ // Arena bounds (for spawning) // gun image asset var arenaMargin = 120; var arenaWidth = 2048 - 2 * arenaMargin; var arenaHeight = 2732 - 2 * arenaMargin; // Main game objects var player; var enemies = []; var bullets = []; var gems = []; var powerups = []; // Score and UI var score = 0; var gemGoal = 25; var healthTxt, scoreTxt; // Drag control var dragging = false; var dragStart = { x: 0, y: 0 }; var dragCurrent = { x: 0, y: 0 }; // Last tick for enemy spawn var lastEnemySpawnTick = 0; var enemySpawnInterval = 120; // ticks // Last tick for powerup spawn var lastPowerupSpawnTick = 0; var powerupSpawnInterval = 600; // ticks // --- UI Setup --- // Score text (gems) scoreTxt = new Text2('Gems: 0/' + gemGoal, { size: 90, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Health text healthTxt = new Text2('♥♥♥♥♥', { size: 90, fill: 0xFF4444 }); healthTxt.anchor.set(0.5, 0); LK.gui.top.addChild(healthTxt); healthTxt.y = 100; // --- Asset Initialization (shapes) --- // --- Game Setup --- // Spawn player in center player = new Brawler(); player.x = 2048 / 2; player.y = 2732 / 2; game.addChild(player); // Initial enemies function spawnEnemy() { var enemy = new Enemy(); // Spawn at random edge var edge = Math.floor(Math.random() * 4); if (edge === 0) { // top enemy.x = arenaMargin + Math.random() * arenaWidth; enemy.y = arenaMargin; } else if (edge === 1) { // bottom enemy.x = arenaMargin + Math.random() * arenaWidth; enemy.y = 2732 - arenaMargin; } else if (edge === 2) { // left enemy.x = arenaMargin; enemy.y = arenaMargin + Math.random() * arenaHeight; } else { // right enemy.x = 2048 - arenaMargin; enemy.y = arenaMargin + Math.random() * arenaHeight; } enemy.target = player; enemies.push(enemy); game.addChild(enemy); } // Spawn a gem at random position function spawnGem() { var gem = new Gem(); gem.x = arenaMargin + 100 + Math.random() * (arenaWidth - 200); gem.y = arenaMargin + 100 + Math.random() * (arenaHeight - 200); gems.push(gem); game.addChild(gem); } // Spawn a powerup at random position function spawnPowerup() { var power = new PowerUp(); // Randomly choose type power.type = Math.random() > 0.5 ? 'heal' : 'speed'; // Set color var color = power.type === 'speed' ? 0x9b59b6 : 0xff69b4; power.children[0].tint = color; power.x = arenaMargin + 100 + Math.random() * (arenaWidth - 200); power.y = arenaMargin + 100 + Math.random() * (arenaHeight - 200); powerups.push(power); game.addChild(power); } // Initial spawn for (var i = 0; i < 5; i++) spawnEnemy(); for (var i = 0; i < 3; i++) spawnGem(); // --- UI Update --- function updateUI() { // Health var hearts = ''; for (var i = 0; i < player.health; i++) hearts += '♥'; for (var i = player.health; i < player.maxHealth; i++) hearts += '♡'; healthTxt.setText(hearts); // Score scoreTxt.setText('Gems: ' + score + '/' + gemGoal); } // --- Drag Controls --- // Player can be dragged directly to move // Helper to track dragging state var dragging = false; var dragOffsetX = 0; var dragOffsetY = 0; // Handle drag start: if touch/click is on player, start dragging game.down = function (x, y, obj) { // Check if touch/click is on player // Use bounding box for hit test var px = player.x; var py = player.y; var pw = player.width || 120; var ph = player.height || 120; if (x >= px - pw / 2 && x <= px + pw / 2 && y >= py - ph / 2 && y <= py + ph / 2) { dragging = true; dragOffsetX = x - player.x; dragOffsetY = y - player.y; } }; // Handle drag move: move player if dragging game.move = function (x, y, obj) { if (!dragging) return; player.x = x - dragOffsetX; player.y = y - dragOffsetY; // Clamp to arena bounds (with margin) var margin = 100; if (player.x < margin) player.x = margin; if (player.x > 2048 - margin) player.x = 2048 - margin; if (player.y < margin) player.y = margin; if (player.y > 2732 - margin) player.y = 2732 - margin; // Stop any velocity-based movement player.moveDir.x = 0; player.moveDir.y = 0; }; // Handle drag end: stop dragging game.up = function (x, y, obj) { dragging = false; player.moveDir.x = 0; player.moveDir.y = 0; }; // --- Main Game Loop --- game.update = function () { // Update player player.update(); // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; enemy.update(); // Check collision with player if (enemy.intersects(player)) { // Damage player player.takeDamage(1); // Flash screen LK.effects.flashScreen(0xff0000, 300); // Remove enemy enemy.destroy(); enemies.splice(i, 1); // Check for game over if (player.health <= 0) { LK.showGameOver(); return; } continue; } } // Update bullets for (var i = bullets.length - 1; i >= 0; i--) { var bullet = bullets[i]; bullet.update(); // Remove if out of bounds or expired if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732 || bullet.lifetime <= 0) { bullet.destroy(); bullets.splice(i, 1); continue; } // Check collision with enemies var hit = false; for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; if (bullet.intersects(enemy)) { enemy.takeDamage(1); if (enemy.health <= 0) { // Remove enemy enemy.destroy(); enemies.splice(j, 1); // 50% chance to spawn a gem at enemy position if (Math.random() < 0.5) { var gem = new Gem(); gem.x = enemy.x; gem.y = enemy.y; gems.push(gem); game.addChild(gem); } } hit = true; break; } } if (hit) { bullet.destroy(); bullets.splice(i, 1); continue; } } // Update gems for (var i = gems.length - 1; i >= 0; i--) { var gem = gems[i]; gem.update(); // Collect if player touches if (gem.intersects(player)) { score++; gem.destroy(); gems.splice(i, 1); updateUI(); // Win condition if (score >= gemGoal) { LK.showYouWin(); return; } } } // Update powerups for (var i = powerups.length - 1; i >= 0; i--) { var power = powerups[i]; power.update(); // Collect if player touches if (power.intersects(player)) { if (power.type === 'heal') { player.heal(2); } else if (power.type === 'speed') { // Temporary speed boost player.speed = 28; // Tween back to normal speed after 2 seconds tween(player, { speed: 16 }, { duration: 2000, easing: tween.linear }); } power.destroy(); powerups.splice(i, 1); updateUI(); } } // --- Shooting (auto-aim at nearest enemy) --- if (player.shootCooldown <= 0 && enemies.length > 0) { // Find nearest enemy var nearest = null; var minDist = 999999; for (var i = 0; i < enemies.length; i++) { var dx = enemies[i].x - player.x; var dy = enemies[i].y - player.y; var dist = dx * dx + dy * dy; if (dist < minDist) { minDist = dist; nearest = enemies[i]; } } if (nearest) { // Fire bullet toward nearest enemy var dx = nearest.x - player.x; var dy = nearest.y - player.y; var mag = Math.sqrt(dx * dx + dy * dy); if (mag > 0) { var bullet = new Bullet(); bullet.x = player.x; bullet.y = player.y; bullet.dir.x = dx / mag; bullet.dir.y = dy / mag; bullet.setRotationFromDir(); // Set rotation to match direction bullets.push(bullet); game.addChild(bullet); player.shootCooldown = 10; // faster shooting (~6 shots per second) } } } // --- Enemy Spawning --- if (enemies.length < 5) { spawnEnemy(); } if (LK.ticks - lastEnemySpawnTick > enemySpawnInterval) { spawnEnemy(); lastEnemySpawnTick = LK.ticks; // Gradually decrease spawn interval if (enemySpawnInterval > 40) enemySpawnInterval -= 2; } // --- Gem Spawning --- if (gems.length < 3) { spawnGem(); } // --- Powerup Spawning --- if (LK.ticks - lastPowerupSpawnTick > powerupSpawnInterval) { spawnPowerup(); lastPowerupSpawnTick = LK.ticks; } // --- UI --- updateUI(); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Player Brawler class
var Brawler = Container.expand(function () {
var self = Container.call(this);
// Attach brawler asset (box, blue)
var brawlerAsset = self.attachAsset('brawler', {
anchorX: 0.5,
anchorY: 0.5
});
// Attach a gun image asset (anchored at left-middle)
var gunAsset = self.attachAsset('gun', {
anchorX: 0.0,
anchorY: 0.5
});
gunAsset.x = 60; // position gun to the right of brawler
gunAsset.y = 0;
self.gunAsset = gunAsset;
// Movement speed (pixels per tick)
self.speed = 16;
// Direction vector for movement (set by drag)
self.moveDir = {
x: 0,
y: 0
};
// Shooting cooldown (ticks)
self.shootCooldown = 0;
// Health
self.maxHealth = 5;
self.health = self.maxHealth;
// For hit flash
self.isHit = false;
self.hitTimer = 0;
// Update method called every tick
self.update = function () {
// Move
if (self.moveDir.x !== 0 || self.moveDir.y !== 0) {
var mag = Math.sqrt(self.moveDir.x * self.moveDir.x + self.moveDir.y * self.moveDir.y);
if (mag > 0) {
var dx = self.moveDir.x / mag * self.speed;
var dy = self.moveDir.y / mag * self.speed;
self.x += dx;
self.y += dy;
}
}
// Clamp to arena bounds (with margin)
var margin = 100;
if (self.x < margin) self.x = margin;
if (self.x > 2048 - margin) self.x = 2048 - margin;
if (self.y < margin) self.y = margin;
if (self.y > 2732 - margin) self.y = 2732 - margin;
// Rotate gun to aim at nearest enemy
if (typeof enemies !== "undefined" && enemies.length > 0 && self.gunAsset) {
var nearest = null;
var minDist = 999999;
for (var i = 0; i < enemies.length; i++) {
var dx = enemies[i].x - self.x;
var dy = enemies[i].y - self.y;
var dist = dx * dx + dy * dy;
if (dist < minDist) {
minDist = dist;
nearest = enemies[i];
}
}
if (nearest) {
var dx = nearest.x - self.x;
var dy = nearest.y - self.y;
self.gunAsset.rotation = Math.atan2(dy, dx);
}
}
// Shooting cooldown
if (self.shootCooldown > 0) self.shootCooldown--;
// Hit flash
if (self.isHit) {
self.hitTimer--;
if (self.hitTimer <= 0) {
self.isHit = false;
brawlerAsset.tint = 0x3498db;
}
}
};
// Take damage
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health < 0) self.health = 0;
// Flash red
brawlerAsset.tint = 0xff4444;
self.isHit = true;
self.hitTimer = 12;
};
// Heal
self.heal = function (amount) {
self.health += amount;
if (self.health > self.maxHealth) self.health = self.maxHealth;
};
// Reset tint
brawlerAsset.tint = 0x3498db;
return self;
});
// Bullet class (player's bullet)
var Bullet = Container.expand(function () {
var self = Container.call(this);
// Attach bullet asset (box, yellow)
var bulletAsset = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
// Direction vector
self.dir = {
x: 0,
y: 0
};
// Speed
self.speed = 40;
// Lifetime (ticks)
self.lifetime = 60;
// Set initial rotation to match direction (default 0)
self.setRotationFromDir = function () {
// Only set if direction is not zero
if (self.dir.x !== 0 || self.dir.y !== 0) {
self.rotation = Math.atan2(self.dir.y, self.dir.x);
}
};
// Update method
self.update = function () {
// Ensure rotation matches direction
self.setRotationFromDir();
self.x += self.dir.x * self.speed;
self.y += self.dir.y * self.speed;
self.lifetime--;
};
return self;
});
// Enemy class
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Attach enemy asset (ellipse, red)
var enemyAsset = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
// Movement speed
self.speed = 9; // Enemy speed fixed at 9
// Health
self.maxHealth = 2;
self.health = self.maxHealth;
// Target (the player)
self.target = null;
// For hit flash
self.isHit = false;
self.hitTimer = 0;
// Update method
self.update = function () {
if (self.target) {
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var mag = Math.sqrt(dx * dx + dy * dy);
if (mag > 0) {
self.x += dx / mag * self.speed;
self.y += dy / mag * self.speed;
}
}
// Clamp to arena bounds
var margin = 80;
if (self.x < margin) self.x = margin;
if (self.x > 2048 - margin) self.x = 2048 - margin;
if (self.y < margin) self.y = margin;
if (self.y > 2732 - margin) self.y = 2732 - margin;
// Hit flash
if (self.isHit) {
self.hitTimer--;
if (self.hitTimer <= 0) {
self.isHit = false;
enemyAsset.tint = 0xd83318;
}
}
};
// Take damage
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health < 0) self.health = 0;
// Flash yellow
enemyAsset.tint = 0xffe066;
self.isHit = true;
self.hitTimer = 8;
};
// Reset tint
enemyAsset.tint = 0xd83318;
return self;
});
// Gem class (collectible)
var Gem = Container.expand(function () {
var self = Container.call(this);
// Attach gem asset (ellipse, green)
var gemAsset = self.attachAsset('gem', {
anchorX: 0.5,
anchorY: 0.5
});
// For floating animation
self.floatDir = Math.random() > 0.5 ? 1 : -1;
self.floatTick = Math.floor(Math.random() * 60);
self.update = function () {
self.floatTick++;
self.y += Math.sin(self.floatTick / 10) * 0.8 * self.floatDir;
};
return self;
});
// PowerUp class (heal or speed)
var PowerUp = Container.expand(function () {
var self = Container.call(this);
// Type: 'heal' or 'speed'
self.type = 'heal';
// Attach asset (box, purple for speed, pink for heal)
var color = self.type === 'speed' ? 0x9b59b6 : 0xff69b4;
var powerAsset = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
powerAsset.tint = color;
// For floating animation
self.floatTick = Math.floor(Math.random() * 60);
self.update = function () {
self.floatTick++;
self.y += Math.sin(self.floatTick / 12) * 0.7;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222a36
});
/****
* Game Code
****/
// Arena bounds (for spawning)
// gun image asset
var arenaMargin = 120;
var arenaWidth = 2048 - 2 * arenaMargin;
var arenaHeight = 2732 - 2 * arenaMargin;
// Main game objects
var player;
var enemies = [];
var bullets = [];
var gems = [];
var powerups = [];
// Score and UI
var score = 0;
var gemGoal = 25;
var healthTxt, scoreTxt;
// Drag control
var dragging = false;
var dragStart = {
x: 0,
y: 0
};
var dragCurrent = {
x: 0,
y: 0
};
// Last tick for enemy spawn
var lastEnemySpawnTick = 0;
var enemySpawnInterval = 120; // ticks
// Last tick for powerup spawn
var lastPowerupSpawnTick = 0;
var powerupSpawnInterval = 600; // ticks
// --- UI Setup ---
// Score text (gems)
scoreTxt = new Text2('Gems: 0/' + gemGoal, {
size: 90,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Health text
healthTxt = new Text2('♥♥♥♥♥', {
size: 90,
fill: 0xFF4444
});
healthTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(healthTxt);
healthTxt.y = 100;
// --- Asset Initialization (shapes) ---
// --- Game Setup ---
// Spawn player in center
player = new Brawler();
player.x = 2048 / 2;
player.y = 2732 / 2;
game.addChild(player);
// Initial enemies
function spawnEnemy() {
var enemy = new Enemy();
// Spawn at random edge
var edge = Math.floor(Math.random() * 4);
if (edge === 0) {
// top
enemy.x = arenaMargin + Math.random() * arenaWidth;
enemy.y = arenaMargin;
} else if (edge === 1) {
// bottom
enemy.x = arenaMargin + Math.random() * arenaWidth;
enemy.y = 2732 - arenaMargin;
} else if (edge === 2) {
// left
enemy.x = arenaMargin;
enemy.y = arenaMargin + Math.random() * arenaHeight;
} else {
// right
enemy.x = 2048 - arenaMargin;
enemy.y = arenaMargin + Math.random() * arenaHeight;
}
enemy.target = player;
enemies.push(enemy);
game.addChild(enemy);
}
// Spawn a gem at random position
function spawnGem() {
var gem = new Gem();
gem.x = arenaMargin + 100 + Math.random() * (arenaWidth - 200);
gem.y = arenaMargin + 100 + Math.random() * (arenaHeight - 200);
gems.push(gem);
game.addChild(gem);
}
// Spawn a powerup at random position
function spawnPowerup() {
var power = new PowerUp();
// Randomly choose type
power.type = Math.random() > 0.5 ? 'heal' : 'speed';
// Set color
var color = power.type === 'speed' ? 0x9b59b6 : 0xff69b4;
power.children[0].tint = color;
power.x = arenaMargin + 100 + Math.random() * (arenaWidth - 200);
power.y = arenaMargin + 100 + Math.random() * (arenaHeight - 200);
powerups.push(power);
game.addChild(power);
}
// Initial spawn
for (var i = 0; i < 5; i++) spawnEnemy();
for (var i = 0; i < 3; i++) spawnGem();
// --- UI Update ---
function updateUI() {
// Health
var hearts = '';
for (var i = 0; i < player.health; i++) hearts += '♥';
for (var i = player.health; i < player.maxHealth; i++) hearts += '♡';
healthTxt.setText(hearts);
// Score
scoreTxt.setText('Gems: ' + score + '/' + gemGoal);
}
// --- Drag Controls ---
// Player can be dragged directly to move
// Helper to track dragging state
var dragging = false;
var dragOffsetX = 0;
var dragOffsetY = 0;
// Handle drag start: if touch/click is on player, start dragging
game.down = function (x, y, obj) {
// Check if touch/click is on player
// Use bounding box for hit test
var px = player.x;
var py = player.y;
var pw = player.width || 120;
var ph = player.height || 120;
if (x >= px - pw / 2 && x <= px + pw / 2 && y >= py - ph / 2 && y <= py + ph / 2) {
dragging = true;
dragOffsetX = x - player.x;
dragOffsetY = y - player.y;
}
};
// Handle drag move: move player if dragging
game.move = function (x, y, obj) {
if (!dragging) return;
player.x = x - dragOffsetX;
player.y = y - dragOffsetY;
// Clamp to arena bounds (with margin)
var margin = 100;
if (player.x < margin) player.x = margin;
if (player.x > 2048 - margin) player.x = 2048 - margin;
if (player.y < margin) player.y = margin;
if (player.y > 2732 - margin) player.y = 2732 - margin;
// Stop any velocity-based movement
player.moveDir.x = 0;
player.moveDir.y = 0;
};
// Handle drag end: stop dragging
game.up = function (x, y, obj) {
dragging = false;
player.moveDir.x = 0;
player.moveDir.y = 0;
};
// --- Main Game Loop ---
game.update = function () {
// Update player
player.update();
// Update enemies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
// Check collision with player
if (enemy.intersects(player)) {
// Damage player
player.takeDamage(1);
// Flash screen
LK.effects.flashScreen(0xff0000, 300);
// Remove enemy
enemy.destroy();
enemies.splice(i, 1);
// Check for game over
if (player.health <= 0) {
LK.showGameOver();
return;
}
continue;
}
}
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
bullet.update();
// Remove if out of bounds or expired
if (bullet.x < 0 || bullet.x > 2048 || bullet.y < 0 || bullet.y > 2732 || bullet.lifetime <= 0) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
// Check collision with enemies
var hit = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
enemy.takeDamage(1);
if (enemy.health <= 0) {
// Remove enemy
enemy.destroy();
enemies.splice(j, 1);
// 50% chance to spawn a gem at enemy position
if (Math.random() < 0.5) {
var gem = new Gem();
gem.x = enemy.x;
gem.y = enemy.y;
gems.push(gem);
game.addChild(gem);
}
}
hit = true;
break;
}
}
if (hit) {
bullet.destroy();
bullets.splice(i, 1);
continue;
}
}
// Update gems
for (var i = gems.length - 1; i >= 0; i--) {
var gem = gems[i];
gem.update();
// Collect if player touches
if (gem.intersects(player)) {
score++;
gem.destroy();
gems.splice(i, 1);
updateUI();
// Win condition
if (score >= gemGoal) {
LK.showYouWin();
return;
}
}
}
// Update powerups
for (var i = powerups.length - 1; i >= 0; i--) {
var power = powerups[i];
power.update();
// Collect if player touches
if (power.intersects(player)) {
if (power.type === 'heal') {
player.heal(2);
} else if (power.type === 'speed') {
// Temporary speed boost
player.speed = 28;
// Tween back to normal speed after 2 seconds
tween(player, {
speed: 16
}, {
duration: 2000,
easing: tween.linear
});
}
power.destroy();
powerups.splice(i, 1);
updateUI();
}
}
// --- Shooting (auto-aim at nearest enemy) ---
if (player.shootCooldown <= 0 && enemies.length > 0) {
// Find nearest enemy
var nearest = null;
var minDist = 999999;
for (var i = 0; i < enemies.length; i++) {
var dx = enemies[i].x - player.x;
var dy = enemies[i].y - player.y;
var dist = dx * dx + dy * dy;
if (dist < minDist) {
minDist = dist;
nearest = enemies[i];
}
}
if (nearest) {
// Fire bullet toward nearest enemy
var dx = nearest.x - player.x;
var dy = nearest.y - player.y;
var mag = Math.sqrt(dx * dx + dy * dy);
if (mag > 0) {
var bullet = new Bullet();
bullet.x = player.x;
bullet.y = player.y;
bullet.dir.x = dx / mag;
bullet.dir.y = dy / mag;
bullet.setRotationFromDir(); // Set rotation to match direction
bullets.push(bullet);
game.addChild(bullet);
player.shootCooldown = 10; // faster shooting (~6 shots per second)
}
}
}
// --- Enemy Spawning ---
if (enemies.length < 5) {
spawnEnemy();
}
if (LK.ticks - lastEnemySpawnTick > enemySpawnInterval) {
spawnEnemy();
lastEnemySpawnTick = LK.ticks;
// Gradually decrease spawn interval
if (enemySpawnInterval > 40) enemySpawnInterval -= 2;
}
// --- Gem Spawning ---
if (gems.length < 3) {
spawnGem();
}
// --- Powerup Spawning ---
if (LK.ticks - lastPowerupSpawnTick > powerupSpawnInterval) {
spawnPowerup();
lastPowerupSpawnTick = LK.ticks;
}
// --- UI ---
updateUI();
};
gem. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
zombie pixel no text. In-Game asset. 2d. High contrast. No shadows
human head. In-Game asset. 2d. High contrast. No shadows
purple cristal. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
gun pistol . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
bullet . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat