User prompt
do it
User prompt
do all of that
User prompt
enemies starting before count down. make them wait
User prompt
make a count down before starting the round
Code edit (1 edits merged)
Please save this source code
User prompt
Mini Strike: Top-Down Tactics
Initial prompt
Create a top down counter-strike like game
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bullet class var Bullet = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 20; self.dx = 0; self.dy = 0; self.speed = 38; self.isPlayer = false; self.lifetime = 60; // frames self.update = function () { self.x += self.dx * self.speed; self.y += self.dy * self.speed; self.lifetime--; }; return self; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 55; self.speed = 7 + Math.random() * 3; self.shootCooldown = 0; self.shootDelay = 60 + Math.floor(Math.random() * 30); self.targetX = 0; self.targetY = 0; self.isAlive = true; self.aiTimer = 0; self.update = function () { if (countdownActive) return; if (!self.isAlive) return; // AI: Move toward player, avoid obstacles if (self.aiTimer <= 0) { // Pick a new target near player, with some randomness var px = player.x + (Math.random() - 0.5) * 300; var py = player.y + (Math.random() - 0.5) * 300; // Clamp to arena px = Math.max(arena.x + 100, Math.min(arena.x + arena.w - 100, px)); py = Math.max(arena.y + 100, Math.min(arena.y + arena.h - 100, py)); self.targetX = px; self.targetY = py; self.aiTimer = 30 + Math.floor(Math.random() * 30); } else { self.aiTimer--; } // Move toward target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var mag = Math.sqrt(dx * dx + dy * dy); if (mag > 10) { var mx = dx / mag * self.speed; var my = dy / mag * self.speed; // Try to move, but avoid obstacles var nx = self.x + mx; var ny = self.y + my; var blocked = false; for (var i = 0; i < obstacles.length; ++i) { if (rectCircleCollide(obstacles[i], nx, ny, self.radius)) { blocked = true; break; } } if (!blocked) { self.x = nx; self.y = ny; } } // Shoot at player if in line of sight if (self.shootCooldown > 0) self.shootCooldown--;else { if (canSee(self.x, self.y, player.x, player.y)) { var ddx = player.x - self.x; var ddy = player.y - self.y; var dmag = Math.sqrt(ddx * ddx + ddy * ddy); if (dmag > 0) { var bullet = new Bullet(); bullet.x = self.x + ddx / dmag * (self.radius + 30); bullet.y = self.y + ddy / dmag * (self.radius + 30); bullet.dx = ddx / dmag; bullet.dy = ddy / dmag; bullet.isPlayer = false; bullets.push(bullet); game.addChild(bullet); self.shootCooldown = self.shootDelay; } } } }; // Take damage self.hit = function () { if (!self.isAlive) return; self.isAlive = false; tween(sprite, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { self.destroy(); } }); }; return self; }); // Obstacle class var Obstacle = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); self.width = sprite.width; self.height = sprite.height; return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 60; self.speed = 18; self.shootCooldown = 0; self.shootDelay = 18; // frames self.isAlive = true; self.invincible = 0; // frames left of invincibility // For touch drag self.down = function (x, y, obj) {}; self.up = function (x, y, obj) {}; // For powerup self.powered = false; self.powerTimer = 0; self.update = function () { if (!self.isAlive) return; if (self.invincible > 0) self.invincible--; if (self.powered) { self.powerTimer--; if (self.powerTimer <= 0) { self.powered = false; sprite.tint = 0x2a6cff; } } if (self.shootCooldown > 0) self.shootCooldown--; }; // Shoot a bullet in direction (dx, dy) self.shoot = function (dx, dy) { if (!self.isAlive) return; if (self.shootCooldown > 0) return; var mag = Math.sqrt(dx * dx + dy * dy); if (mag < 0.1) return; var bullet = new Bullet(); bullet.x = self.x + dx / mag * (self.radius + 30); bullet.y = self.y + dy / mag * (self.radius + 30); bullet.dx = dx / mag; bullet.dy = dy / mag; bullet.isPlayer = true; bullets.push(bullet); game.addChild(bullet); self.shootCooldown = self.powered ? 5 : self.shootDelay; }; // Take damage self.hit = function () { if (self.invincible > 0 || !self.isAlive) return; self.isAlive = false; tween(sprite, { alpha: 0 }, { duration: 400, onFinish: function onFinish() { LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); } }); }; // Powerup self.powerup = function () { self.powered = true; self.powerTimer = 360; // 6 seconds sprite.tint = 0x3be14a; }; return self; }); // Powerup class var Powerup = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('powerup', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 30; self.type = 'rapid'; self.lifetime = 600; // 10 seconds self.update = function () { self.lifetime--; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Arena bounds // Player character: blue box // Enemy: red box // Bullet: yellow ellipse // Obstacle: gray box // Powerup: green ellipse var arena = { x: 180, y: 300, w: 2048 - 360, h: 2732 - 600 }; // Game state var player; var enemies = []; var bullets = []; var obstacles = []; var powerups = []; var round = 1; var roundActive = false; var roundTimer = 0; var spawnTimer = 0; var dragNode = null; var lastTouch = { x: 0, y: 0 }; var scoreTxt; var roundTxt; var powerupTxt; var gameOver = false; // Countdown state var countdownActive = false; var countdownValue = 0; var countdownTxt = null; var countdownTimeout = null; // GUI scoreTxt = new Text2('Score: 0', { size: 90, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); roundTxt = new Text2('Round 1', { size: 70, fill: 0xFFCC00 }); roundTxt.anchor.set(0.5, 0); LK.gui.top.addChild(roundTxt); powerupTxt = new Text2('', { size: 60, fill: 0x3BE14A }); powerupTxt.anchor.set(0.5, 0); LK.gui.bottom.addChild(powerupTxt); // Place obstacles function setupObstacles() { for (var i = 0; i < obstacles.length; ++i) obstacles[i].destroy(); obstacles = []; // Place 4-6 obstacles randomly var obsCount = 4 + Math.floor(Math.random() * 3); for (var i = 0; i < obsCount; ++i) { var obs = new Obstacle(); obs.x = arena.x + 200 + Math.random() * (arena.w - 400); obs.y = arena.y + 200 + Math.random() * (arena.h - 400); if (i % 2 == 0) obs.rotation = Math.PI / 2; obstacles.push(obs); game.addChild(obs); } } // Place player function setupPlayer() { if (player) player.destroy(); player = new Player(); player.x = arena.x + arena.w / 2; player.y = arena.y + arena.h - 200; game.addChild(player); } // Place enemies function setupEnemies(n) { for (var i = 0; i < enemies.length; ++i) enemies[i].destroy(); enemies = []; for (var i = 0; i < n; ++i) { var e = new Enemy(); // Spawn at top or sides var edge = Math.floor(Math.random() * 4); if (edge == 0) { // top e.x = arena.x + 200 + Math.random() * (arena.w - 400); e.y = arena.y + 120; } else if (edge == 1) { // left e.x = arena.x + 120; e.y = arena.y + 200 + Math.random() * (arena.h - 400); } else if (edge == 2) { // right e.x = arena.x + arena.w - 120; e.y = arena.y + 200 + Math.random() * (arena.h - 400); } else { // bottom e.x = arena.x + 200 + Math.random() * (arena.w - 400); e.y = arena.y + arena.h - 120; } enemies.push(e); game.addChild(e); } } // Place powerup function spawnPowerup() { var p = new Powerup(); p.x = arena.x + 150 + Math.random() * (arena.w - 300); p.y = arena.y + 150 + Math.random() * (arena.h - 300); powerups.push(p); game.addChild(p); } // Start round function startRound() { // Start countdown before round actually starts roundActive = false; countdownActive = true; countdownValue = 3; // Remove previous countdown text if exists if (countdownTxt) { countdownTxt.destroy(); countdownTxt = null; } countdownTxt = new Text2('3', { size: 300, fill: 0xFFCC00 }); countdownTxt.anchor.set(0.5, 0.5); LK.gui.center.addChild(countdownTxt); // Setup everything for the round, but don't activate yet roundTimer = 0; spawnTimer = 0; setupObstacles(); setupPlayer(); setupEnemies(2 + round); for (var i = 0; i < bullets.length; ++i) bullets[i].destroy(); bullets = []; for (var i = 0; i < powerups.length; ++i) powerups[i].destroy(); powerups = []; roundTxt.setText('Round ' + round); powerupTxt.setText(''); LK.setScore(LK.getScore()); scoreTxt.setText('Score: ' + LK.getScore()); // Start countdown timer function doCountdown() { if (!countdownActive) return; countdownValue--; if (countdownValue > 0) { countdownTxt.setText(countdownValue + ''); countdownTimeout = LK.setTimeout(doCountdown, 800); } else { // Go! countdownTxt.setText('GO!'); countdownTimeout = LK.setTimeout(function () { if (countdownTxt) { countdownTxt.destroy(); countdownTxt = null; } countdownActive = false; roundActive = true; }, 600); } } countdownTimeout = LK.setTimeout(doCountdown, 800); } // Utility: circle-rectangle collision function rectCircleCollide(obs, cx, cy, cr) { var rx = obs.x - obs.width / 2; var ry = obs.y - obs.height / 2; var rw = obs.width; var rh = obs.height; var closestX = Math.max(rx, Math.min(cx, rx + rw)); var closestY = Math.max(ry, Math.min(cy, ry + rh)); var dx = cx - closestX; var dy = cy - closestY; return dx * dx + dy * dy < cr * cr; } // Utility: circle-circle collision function circleCollide(a, b) { var dx = a.x - b.x; var dy = a.y - b.y; var r = (a.radius || 0) + (b.radius || 0); return dx * dx + dy * dy < r * r; } // Utility: line of sight (returns true if no obstacle blocks) function canSee(x1, y1, x2, y2) { for (var i = 0; i < obstacles.length; ++i) { if (lineRectIntersect(x1, y1, x2, y2, obstacles[i])) return false; } return true; } // Utility: line-rectangle intersection function lineRectIntersect(x1, y1, x2, y2, obs) { var rx = obs.x - obs.width / 2; var ry = obs.y - obs.height / 2; var rw = obs.width; var rh = obs.height; // Check each side if (lineLineIntersect(x1, y1, x2, y2, rx, ry, rx + rw, ry)) return true; if (lineLineIntersect(x1, y1, x2, y2, rx + rw, ry, rx + rw, ry + rh)) return true; if (lineLineIntersect(x1, y1, x2, y2, rx + rw, ry + rh, rx, ry + rh)) return true; if (lineLineIntersect(x1, y1, x2, y2, rx, ry + rh, rx, ry)) return true; return false; } // Utility: line-line intersection function lineLineIntersect(x1, y1, x2, y2, x3, y3, x4, y4) { var denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); if (denom == 0) return false; var ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denom; var ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denom; return ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1; } // Clamp player inside arena and avoid obstacles function clampPlayer(px, py) { // Clamp to arena px = Math.max(arena.x + player.radius, Math.min(arena.x + arena.w - player.radius, px)); py = Math.max(arena.y + player.radius, Math.min(arena.y + arena.h - player.radius, py)); // Avoid obstacles for (var i = 0; i < obstacles.length; ++i) { if (rectCircleCollide(obstacles[i], px, py, player.radius)) { // Push out var ox = obstacles[i].x; var oy = obstacles[i].y; var dx = px - ox; var dy = py - oy; var mag = Math.sqrt(dx * dx + dy * dy); if (mag > 0) { px = ox + dx / mag * (obstacles[i].width / 2 + player.radius + 2); py = oy + dy / mag * (obstacles[i].height / 2 + player.radius + 2); } } } return { x: px, y: py }; } // Touch controls: drag to move, tap to shoot game.down = function (x, y, obj) { if (countdownActive) return; if (!player.isAlive) return; // If touch is near player, start drag var dx = x - player.x; var dy = y - player.y; if (dx * dx + dy * dy < player.radius * player.radius * 2) { dragNode = player; } else { // Else, shoot toward touch var dirx = x - player.x; var diry = y - player.y; player.shoot(dirx, diry); } lastTouch.x = x; lastTouch.y = y; }; game.move = function (x, y, obj) { if (countdownActive) return; if (!player.isAlive) return; if (dragNode === player) { // Move player toward touch, but clamp var dx = x - player.x; var dy = y - player.y; var mag = Math.sqrt(dx * dx + dy * dy); if (mag > 0) { var step = Math.min(player.speed, mag); var nx = player.x + dx / mag * step; var ny = player.y + dy / mag * step; var clamped = clampPlayer(nx, ny); player.x = clamped.x; player.y = clamped.y; } lastTouch.x = x; lastTouch.y = y; } }; game.up = function (x, y, obj) { dragNode = null; }; // Main update loop game.update = function () { // If countdown is active, pause gameplay updates if (countdownActive) { return; } if (!roundActive) { startRound(); return; } if (!player.isAlive) return; // Update player player.update(); // Update enemies for (var i = enemies.length - 1; i >= 0; --i) { var e = enemies[i]; e.update(); // If dead, remove if (!e.isAlive && e.alpha <= 0) { e.destroy(); enemies.splice(i, 1); LK.setScore(LK.getScore() + 1); scoreTxt.setText('Score: ' + LK.getScore()); } } // Update bullets for (var i = bullets.length - 1; i >= 0; --i) { var b = bullets[i]; b.update(); // Remove if out of bounds or expired if (b.x < arena.x - 100 || b.x > arena.x + arena.w + 100 || b.y < arena.y - 100 || b.y > arena.y + arena.h + 100 || b.lifetime <= 0) { b.destroy(); bullets.splice(i, 1); continue; } // Collide with obstacles var hitObs = false; for (var j = 0; j < obstacles.length; ++j) { if (rectCircleCollide(obstacles[j], b.x, b.y, b.radius)) { hitObs = true; break; } } if (hitObs) { b.destroy(); bullets.splice(i, 1); continue; } // Collide with enemies (if player bullet) if (b.isPlayer) { for (var j = 0; j < enemies.length; ++j) { if (enemies[j].isAlive && circleCollide(b, enemies[j])) { enemies[j].hit(); b.destroy(); bullets.splice(i, 1); break; } } } else { // Collide with player if (player.isAlive && circleCollide(b, player)) { if (player.invincible <= 0) { player.hit(); } b.destroy(); bullets.splice(i, 1); } } } // Update powerups for (var i = powerups.length - 1; i >= 0; --i) { var p = powerups[i]; p.update(); if (p.lifetime <= 0) { p.destroy(); powerups.splice(i, 1); continue; } // Collide with player if (player.isAlive && circleCollide(p, player)) { player.powerup(); powerupTxt.setText('Rapid Fire!'); p.destroy(); powerups.splice(i, 1); } } // Spawn powerup occasionally if (LK.ticks % 600 == 0 && powerups.length == 0) { spawnPowerup(); } // End round if all enemies dead if (enemies.length == 0) { roundActive = false; round++; LK.setTimeout(function () { startRound(); }, 1200); } }; // Initial round startRound();
===================================================================
--- original.js
+++ change.js
@@ -41,8 +41,9 @@
self.targetY = 0;
self.isAlive = true;
self.aiTimer = 0;
self.update = function () {
+ if (countdownActive) return;
if (!self.isAlive) return;
// AI: Move toward player, avoid obstacles
if (self.aiTimer <= 0) {
// Pick a new target near player, with some randomness
@@ -219,14 +220,14 @@
/****
* Game Code
****/
-// Powerup: green ellipse
-// Obstacle: gray box
-// Bullet: yellow ellipse
-// Enemy: red box
-// Player character: blue box
// Arena bounds
+// Player character: blue box
+// Enemy: red box
+// Bullet: yellow ellipse
+// Obstacle: gray box
+// Powerup: green ellipse
var arena = {
x: 180,
y: 300,
w: 2048 - 360,