User prompt
set level text font size 44
User prompt
make timer fontsize 64
User prompt
make font size 64
User prompt
15 mor
User prompt
now move the timer 40 down
User prompt
20 more
User prompt
move xp text 10 pixel down
User prompt
can u move the lives and xp text 30 pixel up
User prompt
sorry not above below the lives text
User prompt
move the XP text above the lives text and make it fontsize 54
Code edit (5 edits merged)
Please save this source code
User prompt
make lives text bigger and move it up 20 pixel
User prompt
bring them to the front of background I cant see it now
User prompt
bring them to the front
User prompt
put life bare top right corner with 5 heart assets
User prompt
show the life not with text but with heart assets
User prompt
move the lives text to the top right corner
User prompt
move the timer text to the top middle
User prompt
remove the score text and replace it with the timer from top right corner
User prompt
make all option backgrounds asset color 4eff00
Code edit (1 edits merged)
Please save this source code
Code edit (2 edits merged)
Please save this source code
User prompt
use differents shades of green for popup background and option backgrounds
User prompt
make options backgrounds darker green than pop up background
User prompt
now make a brighter green
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // BossEnemy class (big zombie boss) var BossEnemy = Container.expand(function () { var self = Container.call(this); // Preload both right and left sprites, only one visible at a time var bossSpriteRight = self.attachAsset('boss_enemy', { anchorX: 0.5, anchorY: 0.5 }); bossSpriteRight.assetId = 'boss_enemy'; var bossSpriteLeft = self.attachAsset('boss_enemy_left', { anchorX: 0.5, anchorY: 0.5 }); bossSpriteLeft.assetId = 'boss_enemy_left'; bossSpriteLeft.visible = false; self.radius = 120; self.speed = 0.7; self.hp = 30; self._lastFacingRight = true; // Track last facing direction self.update = function () { if (typeof game !== "undefined" && game._levelUpFrozen) { return; } var dx = hero.x - self.x; var dy = hero.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Face boss left/right depending on hero position, by toggling visibility var shouldFaceRight = hero.x > self.x; if (shouldFaceRight !== self._lastFacingRight) { bossSpriteRight.visible = shouldFaceRight; bossSpriteLeft.visible = !shouldFaceRight; self._lastFacingRight = shouldFaceRight; } }; return self; }); // Bullet class var Bullet = Container.expand(function () { var self = Container.call(this); var bulletSprite = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 18; self.speed = 9.5; self.dirX = 1; self.dirY = 0; self.pierce = 1; // Track enemies already hit by this bullet self._hitEnemies = []; self.update = function () { if (typeof game !== "undefined" && game._levelUpFrozen) { return; } // Homing logic: if enabled, adjust direction toward nearest enemy if (Bullet.prototype.homing && typeof enemies !== "undefined" && enemies.length > 0) { // Spread phase: if more than 1 bullet, spread out for a short time before homing if (typeof bullets !== "undefined" && bullets.length > 1) { if (typeof self._spreadTimer === "undefined") { // Each bullet gets a unique spread angle based on its index in bullets array var idx = 0; for (var bidx = 0; bidx < bullets.length; bidx++) { if (bullets[bidx] === self) { idx = bidx; break; } } var spreadTotal = bullets.length; var spreadAngle = Math.PI / 6; // 30 degrees total spread var baseAngle = Math.atan2(self.dirY, self.dirX); var angleOffset = -spreadAngle / 2 + (spreadTotal === 1 ? 0 : spreadAngle * idx / (spreadTotal - 1)); self._spreadTargetAngle = baseAngle + angleOffset; self._spreadTimer = 12; // frames to spread before homing } if (self._spreadTimer > 0) { // Lerp direction toward spread angle var currentAngle = Math.atan2(self.dirY, self.dirX); var targetAngle = self._spreadTargetAngle; // Shortest angle difference var da = targetAngle - currentAngle; while (da > Math.PI) { da -= Math.PI * 2; } while (da < -Math.PI) { da += Math.PI * 2; } var lerp = 0.25; var newAngle = currentAngle + da * lerp; self.dirX = Math.cos(newAngle); self.dirY = Math.sin(newAngle); self.rotation = newAngle; self._spreadTimer--; } else { // After spread, start homing var minDist = 99999; var nearest = null; for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; // Exclude enemies already hit by this bullet if (self._hitEnemies.indexOf(e) !== -1) { continue; } var dx = e.x - self.x; var dy = e.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < minDist) { minDist = dist; nearest = e; } } if (nearest) { var dx = nearest.x - self.x; var dy = nearest.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { var homingStrength = 0.18; var targetDirX = dx / dist; var targetDirY = dy / dist; self.dirX = self.dirX * (1 - homingStrength) + targetDirX * homingStrength; self.dirY = self.dirY * (1 - homingStrength) + targetDirY * homingStrength; var norm = Math.sqrt(self.dirX * self.dirX + self.dirY * self.dirY); if (norm > 0) { self.dirX /= norm; self.dirY /= norm; } self.rotation = Math.atan2(self.dirY, self.dirX); } } } } else { // Only one bullet, home immediately var minDist = 99999; var nearest = null; for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; // Exclude enemies already hit by this bullet if (self._hitEnemies.indexOf(e) !== -1) { continue; } var dx = e.x - self.x; var dy = e.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < minDist) { minDist = dist; nearest = e; } } if (nearest) { var dx = nearest.x - self.x; var dy = nearest.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { var homingStrength = 0.18; var targetDirX = dx / dist; var targetDirY = dy / dist; self.dirX = self.dirX * (1 - homingStrength) + targetDirX * homingStrength; self.dirY = self.dirY * (1 - homingStrength) + targetDirY * homingStrength; var norm = Math.sqrt(self.dirX * self.dirX + self.dirY * self.dirY); if (norm > 0) { self.dirX /= norm; self.dirY /= norm; } self.rotation = Math.atan2(self.dirY, self.dirX); } } } } self.x += self.dirX * self.speed; self.y += self.dirY * self.speed; // Ricochet logic: if enabled, on hit, bounce to nearest enemy up to N times if (typeof self.ricochetLeft === "undefined" && Bullet.prototype.ricochet) { self.ricochetLeft = Bullet.prototype.ricochet; } if (typeof self.ricochetLeft !== "undefined" && self.ricochetLeft > 0 && typeof enemies !== "undefined") { // Ricochet handled in collision, see main game.update } }; return self; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); // Preload both right and left sprites, only one visible at a time var enemySpriteRight = self.attachAsset('enemy_right', { anchorX: 0.5, anchorY: 0.5 }); enemySpriteRight.assetId = 'enemy_right'; var enemySpriteLeft = self.attachAsset('enemy_left', { anchorX: 0.5, anchorY: 0.5 }); enemySpriteLeft.assetId = 'enemy_left'; enemySpriteLeft.visible = false; self.radius = 50; self.speed = 1.5 + Math.random(); self._lastFacingRight = true; // Track last facing direction self.update = function () { if (typeof game !== "undefined" && game._levelUpFrozen) { return; } var dx = hero.x - self.x; var dy = hero.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Face enemy left/right depending on hero position, by toggling visibility var shouldFaceRight = hero.x > self.x; if (shouldFaceRight !== self._lastFacingRight) { enemySpriteRight.visible = shouldFaceRight; enemySpriteLeft.visible = !shouldFaceRight; self._lastFacingRight = shouldFaceRight; } }; return self; }); // Experience Gem class (handles both normal and big XP gems) var Gem = Container.expand(function (opts) { var self = Container.call(this); // Default to normal gem self.type = opts && opts.type || 'xp'; if (self.type === 'big') { var gemSprite = self.attachAsset('big_xp_gem', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 30; } else { var gemSprite = self.attachAsset('xp_gem', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 20; } self.update = function () {}; return self; }); // HeartPowerup class (can artıran kalp) var HeartPowerup = Container.expand(function () { var self = Container.call(this); self.attachAsset('heart_powerup', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 30; self.update = function () {}; return self; }); // Hero class var Hero = Container.expand(function () { var self = Container.call(this); // Preload both right and left hero sprites, only one visible at a time var heroSpriteRight = self.attachAsset('hero_right', { anchorX: 0.5, anchorY: 0.5 }); heroSpriteRight.assetId = 'hero_right'; var heroSpriteLeft = self.attachAsset('hero_left', { anchorX: 0.5, anchorY: 0.5 }); heroSpriteLeft.assetId = 'hero_left'; heroSpriteLeft.visible = false; self.radius = 60; self.speed = 100; self.targetX = 1024; self.targetY = 1366; self.magnetActive = false; self.magnetDuration = 0; self.magnetRange = 300; self.magnetRangeBoosted = 800; self._lastFacingRight = true; // Track last facing direction self.update = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 10) { var move = Math.min(self.speed, dist); var prevX = self.x; self.x += dx / dist * move; self.y += dy / dist * move; // Face hero left/right depending on movement direction, by toggling visibility var shouldFaceRight = self.x > prevX; if (shouldFaceRight !== self._lastFacingRight) { heroSpriteRight.visible = shouldFaceRight; heroSpriteLeft.visible = !shouldFaceRight; self._lastFacingRight = shouldFaceRight; } } if (self.magnetActive) { // Make hero glow blue while magnet is active if (!self._magnetGlowActive) { LK.effects.flashObject(self, 0x00ffff, 60000); // long duration, will be reset when deactivated self._magnetGlowActive = true; } // Magnet duration is now synchronized with game time (ticksSurvived) if (typeof self.magnetEndTick === "number") { if (typeof ticksSurvived === "number" && ticksSurvived >= self.magnetEndTick) { self.magnetActive = false; self.magnetDuration = 0; self.magnetEndTick = undefined; } else { // Update magnetDuration for UI display if (typeof ticksSurvived === "number") { self.magnetDuration = self.magnetEndTick - ticksSurvived; } } } } else { self._magnetGlowActive = false; } }; return self; }); // Powerup class (now only for magnet) var Powerup = Container.expand(function (opts) { var self = Container.call(this); self.isMagnet = opts && opts.isMagnet || false; if (self.isMagnet) { self.attachAsset('magnet_powerup', { anchorX: 0.5, anchorY: 0.5 }); } self.radius = 30; self.update = function () {}; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1e1b1d }); /**** * Game Code ****/ // <-- Kırmızı kalp powerup shape var hero; var heroLives = 5; var enemies = []; var bullets = []; var gems = []; var powerups = []; var spawnTimer = 0; var spawnInterval = 90; var wave = 1; var xp = 0; var xpToLevel = 10; var level = 1; var dragging = false; var lastGameOver = false; var scoreTxt, xpTxt, levelTxt; var centerX = 2048 / 2; var centerY = 2732 / 2; // --- Option popup at game start --- var startOptionPopup; function showStartOptionPopup() { // Freeze all game logic and input game._levelUpFrozen = true; // Remove any previous popup if present if (typeof startOptionPopup !== "undefined" && startOptionPopup && startOptionPopup.parent) { startOptionPopup.parent.removeChild(startOptionPopup); startOptionPopup = null; } startOptionPopup = new Container(); // Dim background var bg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, color: 0x5e5e5d // green }); bg.width = 1100; bg.height = 1500; bg.alpha = 0.92; bg.x = centerX; bg.y = centerY; // Removed outline (LK.effects.outline not supported) startOptionPopup.addChild(bg); // Title var titleTxt = new Text2('Choose Your Power!', { size: 90, fill: "#fff", font: "Montserrat" // Set font to Montserrat }); titleTxt.anchor.set(0.5, 0); titleTxt.x = centerX; titleTxt.y = centerY - 610; startOptionPopup.addChild(titleTxt); // Option vertical layout var optionStartY = centerY - 320; var optionSpacing = 220; // Option 1: Attack Speed Up var opt1 = new Container(); var opt1Bg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, color: 0x4eff00 // green }); opt1Bg.width = 800; opt1Bg.height = 160; opt1Bg.alpha = 0.98; opt1Bg.x = centerX; opt1Bg.y = optionStartY; // Removed outline (LK.effects.outline not supported) opt1.addChild(opt1Bg); var opt1Txt = new Text2('Attack Speed', { size: 54, fill: 0xF7E967, font: "Montserrat" }); opt1Txt.anchor.set(0.5, 0.5); opt1Txt.x = centerX; opt1Txt.y = optionStartY - 25; opt1.addChild(opt1Txt); var opt1Desc = new Text2('Fire faster from the start!', { size: 40, fill: "#fff", font: "Montserrat" }); opt1Desc.anchor.set(0.5, 0.5); opt1Desc.x = centerX; opt1Desc.y = optionStartY + 35; opt1.addChild(opt1Desc); opt1.interactive = true; opt1.down = function (x, y, obj) { // Apply attack speed boost autoAttackInterval = Math.max(6, autoAttackInterval - 18); // Resume game and remove popup if (startOptionPopup && startOptionPopup.parent) { startOptionPopup.parent.removeChild(startOptionPopup); startOptionPopup = null; } game._levelUpFrozen = false; }; startOptionPopup.addChild(opt1); // Option 2: Ricochet Bullet var opt2 = new Container(); var opt2Bg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, color: 0x4eff00 // green }); opt2Bg.width = 800; opt2Bg.height = 160; opt2Bg.alpha = 0.98; opt2Bg.x = centerX; opt2Bg.y = optionStartY + optionSpacing; // Removed outline (LK.effects.outline not supported) opt2.addChild(opt2Bg); var opt2Txt = new Text2('Ricochet', { size: 54, fill: 0x7BE495, font: "Montserrat" }); opt2Txt.anchor.set(0.5, 0.5); opt2Txt.x = centerX; opt2Txt.y = optionStartY + optionSpacing - 25; opt2.addChild(opt2Txt); var opt2Desc = new Text2('Bullets bounce to another enemy', { size: 40, fill: "#fff", font: "Montserrat" }); opt2Desc.anchor.set(0.5, 0.5); opt2Desc.x = centerX; opt2Desc.y = optionStartY + optionSpacing + 35; opt2.addChild(opt2Desc); opt2.interactive = true; opt2.down = function (x, y, obj) { Bullet.prototype.ricochet = 1; if (startOptionPopup && startOptionPopup.parent) { startOptionPopup.parent.removeChild(startOptionPopup); startOptionPopup = null; } game._levelUpFrozen = false; }; startOptionPopup.addChild(opt2); // Option 3: +1 Bullet (spread shot) var opt3 = new Container(); var opt3Bg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, color: 0x4eff00 // green }); opt3Bg.width = 800; opt3Bg.height = 160; opt3Bg.alpha = 0.98; opt3Bg.x = centerX; opt3Bg.y = optionStartY + optionSpacing * 2; // Removed outline (LK.effects.outline not supported) opt3.addChild(opt3Bg); var opt3Txt = new Text2('Bullet +1', { size: 54, fill: 0xFFB347, font: "Montserrat" }); opt3Txt.anchor.set(0.5, 0.5); opt3Txt.x = centerX; opt3Txt.y = optionStartY + optionSpacing * 2 - 25; opt3.addChild(opt3Txt); var opt3Desc = new Text2('Shoot more bullets at once', { size: 40, fill: "#fff", font: "Montserrat" }); opt3Desc.anchor.set(0.5, 0.5); opt3Desc.x = centerX; opt3Desc.y = optionStartY + optionSpacing * 2 + 35; opt3.addChild(opt3Desc); opt3.interactive = true; opt3.down = function (x, y, obj) { Bullet.prototype.extraBullets = 1; if (startOptionPopup && startOptionPopup.parent) { startOptionPopup.parent.removeChild(startOptionPopup); startOptionPopup = null; } game._levelUpFrozen = false; }; startOptionPopup.addChild(opt3); // Option 4: Pierce +1 var opt4 = new Container(); var opt4Bg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, color: 0x4eff00 // green }); opt4Bg.width = 800; opt4Bg.height = 160; opt4Bg.alpha = 0.98; opt4Bg.x = centerX; opt4Bg.y = optionStartY + optionSpacing * 3; // Removed outline (LK.effects.outline not supported) opt4.addChild(opt4Bg); var opt4Txt = new Text2('Pierce +1', { size: 54, fill: 0x7BE4FF, font: "Montserrat" }); opt4Txt.anchor.set(0.5, 0.5); opt4Txt.x = centerX; opt4Txt.y = optionStartY + optionSpacing * 3 - 25; opt4.addChild(opt4Txt); var opt4Desc = new Text2('Bullets pass through more enemies', { size: 40, fill: "#fff", font: "Montserrat" }); opt4Desc.anchor.set(0.5, 0.5); opt4Desc.x = centerX; opt4Desc.y = optionStartY + optionSpacing * 3 + 35; opt4.addChild(opt4Desc); opt4.interactive = true; opt4.down = function (x, y, obj) { Bullet.prototype.pierce = 2; if (startOptionPopup && startOptionPopup.parent) { startOptionPopup.parent.removeChild(startOptionPopup); startOptionPopup = null; } game._levelUpFrozen = false; }; startOptionPopup.addChild(opt4); // Option 5: Bullets can follow up enemies var opt5 = new Container(); var opt5Bg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, color: 0x4eff00 // green }); opt5Bg.width = 800; opt5Bg.height = 160; opt5Bg.alpha = 0.98; opt5Bg.x = centerX; opt5Bg.y = optionStartY + optionSpacing * 4; // Removed outline (LK.effects.outline not supported) opt5.addChild(opt5Bg); var opt5Txt = new Text2('Missile', { size: 54, fill: 0xFF77FF, font: "Montserrat" }); opt5Txt.anchor.set(0.5, 0.5); opt5Txt.x = centerX; opt5Txt.y = optionStartY + optionSpacing * 4 - 25; opt5.addChild(opt5Txt); var opt5Desc = new Text2('Bullets home in on enemies', { size: 40, fill: "#fff", font: "Montserrat" }); opt5Desc.anchor.set(0.5, 0.5); opt5Desc.x = centerX; opt5Desc.y = optionStartY + optionSpacing * 4 + 35; opt5.addChild(opt5Desc); opt5.interactive = true; opt5.down = function (x, y, obj) { Bullet.prototype.homing = true; if (startOptionPopup && startOptionPopup.parent) { startOptionPopup.parent.removeChild(startOptionPopup); startOptionPopup = null; } game._levelUpFrozen = false; }; startOptionPopup.addChild(opt5); // Add popup to game game.addChild(startOptionPopup); } // Show the popup at game start hero = new Hero(); hero.x = centerX; hero.y = centerY; game.addChild(hero); showStartOptionPopup(); // Removed scoreTxt, replaced by timer in top right var livesTxt = new Text2('Lives: ' + heroLives, { size: 54, fill: 0xFF5555, font: "Montserrat" }); livesTxt.anchor.set(1, 0); livesTxt.y = 10; LK.gui.topRight.addChild(livesTxt); var timerTxt = new Text2('00:00', { size: 64, fill: "#fff", font: "Montserrat" }); timerTxt.anchor.set(0.5, 0); timerTxt.y = 55; LK.gui.top.addChild(timerTxt); var magnetTimerTxt = new Text2('', { size: 44, fill: 0x00FFFF, font: "Montserrat" }); magnetTimerTxt.anchor.set(1, 0); magnetTimerTxt.y = 60; LK.gui.topRight.addChild(magnetTimerTxt); xpTxt = new Text2('XP: 0/10', { size: 54, fill: 0x7BE495, font: "Montserrat" }); xpTxt.anchor.set(1, 0); // Move XP text below the lives text (livesTxt.y + livesTxt.height + 8 for spacing), then 30px further down xpTxt.y = livesTxt.y + livesTxt.height + 8 - 30 + 30; LK.gui.topRight.addChild(xpTxt); levelTxt = new Text2('Level: 1', { size: 44, fill: 0xF7E967, font: "Montserrat" }); levelTxt.anchor.set(0.5, 0); LK.gui.top.addChild(levelTxt); levelTxt.y = 180; function spawnEnemy() { var edge = Math.floor(Math.random() * 4); var x, y; var useRight = false; if (edge === 0) { x = Math.random() * 2048; y = -100; if (x > 1024) { useRight = true; } } else if (edge === 1) { x = 2048 + 100; y = Math.random() * 2732; useRight = true; } else if (edge === 2) { x = Math.random() * 2048; y = 2732 + 100; if (x > 1024) { useRight = true; } } else { x = -100; y = Math.random() * 2732; } var enemy = new Enemy(); // Set initial facing direction based on spawn side if (useRight) { // Face right: right sprite visible, left sprite hidden if (enemy.children && enemy.children.length > 0) { for (var i = 0; i < enemy.children.length; i++) { var child = enemy.children[i]; if (child.assetId === 'enemy_right') { child.visible = true; } if (child.assetId === 'enemy_left') { child.visible = false; } } } enemy._lastFacingRight = true; } else { // Face left: left sprite visible, right sprite hidden if (enemy.children && enemy.children.length > 0) { for (var i = 0; i < enemy.children.length; i++) { var child = enemy.children[i]; if (child.assetId === 'enemy_right') { child.visible = false; } if (child.assetId === 'enemy_left') { child.visible = true; } } } enemy._lastFacingRight = false; } enemy.x = x; enemy.y = y; enemies.push(enemy); game.addChild(enemy); } function spawnGem(x, y, opts) { var gem = new Gem(opts); gem.x = x; gem.y = y; gems.push(gem); game.addChild(gem); } function spawnMagnetPowerup(x, y) { var powerup = new Powerup({ isMagnet: true }); // isMagnet parametresiyle oluştur powerup.x = x; powerup.y = y; powerups.push(powerup); game.addChild(powerup); } function spawnPowerup(x, y) { var powerup = new Powerup({ isMagnet: false }); // Diğer poweruplar powerup.x = x; powerup.y = y; powerups.push(powerup); // Remove and re-add to ensure it's above any background (if present) if (game.children && game.children.length > 0) { game.removeChild(powerup); game.addChild(powerup); } else { game.addChild(powerup); } } // Yeni: kalp powerup spawn fonksiyonu function spawnHeartPowerup(x, y) { var heart = new HeartPowerup(); heart.x = x; heart.y = y; powerups.push(heart); game.addChild(heart); } function fireBullet(dx, dy) { var bullet = new Bullet(); bullet.x = hero.x; bullet.y = hero.y; if (typeof Bullet.prototype.pierce === "undefined") { Bullet.prototype.pierce = 1; } bullet.pierce = Bullet.prototype.pierce; var dist = Math.sqrt(dx * dx + dy * dy); if (dist === 0) { bullet.dirX = 1; bullet.dirY = 0; } else { bullet.dirX = dx / dist; bullet.dirY = dy / dist; } bullet.rotation = Math.atan2(bullet.dirY, bullet.dirX); bullets.push(bullet); game.addChild(bullet); } function randomDir() { var angle = Math.random() * Math.PI * 2; return { x: Math.cos(angle), y: Math.sin(angle) }; } function dist2(a, b) { var dx = a.x - b.x; var dy = a.y - b.y; return Math.sqrt(dx * dx + dy * dy); } game.down = function (x, y, obj) { if (game._levelUpFrozen) { return; } if (x < 100 && y < 100) { return; } hero.targetX = x; hero.targetY = y; dragging = true; }; game.move = function (x, y, obj) { if (game._levelUpFrozen) { return; } hero.targetX = x; hero.targetY = y; }; game.up = function (x, y, obj) { if (game._levelUpFrozen) { return; } dragging = false; }; var ticksSurvived = 0; var autoAttackTimer = 0; var autoAttackInterval = 96; game.update = function () { if (game._levelUpFrozen) { // Freeze all game logic and input while level up popup is active return; } hero.update(); for (var i = enemies.length - 1; i >= 0; i--) { var e = enemies[i]; e.update(); // Track lastWasTouchingHero for exact frame detection if (typeof e.lastWasTouchingHero === "undefined") { e.lastWasTouchingHero = false; } var isTouchingHero = dist2(e, hero) < e.radius + hero.radius; if (!e.lastWasTouchingHero && isTouchingHero) { LK.effects.flashScreen(0xff0000, 1000); heroLives--; livesTxt.setText('Lives: ' + heroLives); if (heroLives <= 0) { LK.showGameOver(); lastGameOver = true; } } e.lastWasTouchingHero = isTouchingHero; } for (var i = bullets.length - 1; i >= 0; i--) { var b = bullets[i]; b.update(); if (b.x < -100 || b.x > 2148 || b.y < -100 || b.y > 2832) { b.destroy(); bullets.splice(i, 1); continue; } for (var j = enemies.length - 1; j >= 0; j--) { var e = enemies[j]; if (dist2(b, e) < b.radius + e.radius) { // Mark this enemy as hit by this bullet if (b._hitEnemies && b._hitEnemies.indexOf(e) === -1) { b._hitEnemies.push(e); } // Boss enemy logic if (typeof e.hp === "number" && e.hp > 0) { e.hp -= 1; LK.effects.flashObject(e, 0xffffff, 120); if (e.hp <= 0) { // Boss defeated: drop multiple big gems and normal gems for (var drop = 0; drop < 3; drop++) { var angle = Math.random() * Math.PI * 2; var dist = 60 + Math.random() * 40; var gemX = e.x + Math.cos(angle) * dist; var gemY = e.y + Math.sin(angle) * dist; spawnGem(gemX, gemY, { type: 'big' }); } for (var drop = 0; drop < 5; drop++) { var angle = Math.random() * Math.PI * 2; var dist = 80 + Math.random() * 60; var gemX = e.x + Math.cos(angle) * dist; var gemY = e.y + Math.sin(angle) * dist; spawnGem(gemX, gemY); } // Always drop a magnet powerup spawnMagnetPowerup(e.x, e.y); // Yeni: boss öldüğünde kalp powerup düşürme (10% şans) if (Math.random() < 0.1) { spawnHeartPowerup(e.x, e.y); } e.destroy(); enemies.splice(j, 1); } } else { var bigGemSpawned = false; if (Math.random() < 0.10) { // Drop big xp gem at 10% rate spawnGem(e.x, e.y, { type: 'big' }); bigGemSpawned = true; } // Offset the normal gem if big gem was spawned to avoid overlap if (bigGemSpawned) { var offsetAngle = Math.random() * Math.PI * 2; var offsetDist = 40; var gemX = e.x + Math.cos(offsetAngle) * offsetDist; var gemY = e.y + Math.sin(offsetAngle) * offsetDist; spawnGem(gemX, gemY); } else { spawnGem(e.x, e.y); } // Set magnet drop rate to 5% (1 in 20 chance) if (Math.random() < 0.05) { spawnMagnetPowerup(e.x, e.y); } // Yeni: normal düşman öldüğünde kalp powerup düşürme (10% şans) if (Math.random() < 0.1) { spawnHeartPowerup(e.x, e.y); } e.destroy(); enemies.splice(j, 1); } b.pierce -= 1; // Ricochet logic: if bullet has ricochetLeft, bounce to nearest enemy if (typeof b.ricochetLeft !== "undefined" && b.ricochetLeft > 0 && enemies.length > 1) { // Find nearest enemy that is not the one just hit var minDist = 99999; var nearest = null; for (var ricI = 0; ricI < enemies.length; ricI++) { var ricE = enemies[ricI]; // Exclude the just-hit enemy and any already-hit enemies if (ricE === e) { continue; } if (b._hitEnemies && b._hitEnemies.indexOf(ricE) !== -1) { continue; } var d = dist2(b, ricE); if (d < minDist) { minDist = d; nearest = ricE; } } if (nearest) { // Ricochet: set bullet position to current, aim at nearest enemy var dx = nearest.x - b.x; var dy = nearest.y - b.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { b.dirX = dx / dist; b.dirY = dy / dist; b.rotation = Math.atan2(b.dirY, b.dirX); b.ricochetLeft--; // Don't destroy or remove bullet, let it continue // Restore pierce for next hit b.pierce = Math.max(1, Bullet.prototype.pierce || 1); // Move bullet slightly toward new direction to avoid instant re-collision b.x += b.dirX * 10; b.y += b.dirY * 10; continue; } } } // If no ricochet, destroy as normal if (b.pierce <= 0) { b.destroy(); bullets.splice(i, 1); } break; } } } for (var i = gems.length - 1; i >= 0; i--) { var g = gems[i]; // Set XP gem attraction area to 800 pixels when magnet is active, otherwise 150 var xpAttractRange = hero.magnetActive ? 800 : 150; var d = dist2(g, hero); if (d < xpAttractRange) { var dx = hero.x - g.x; var dy = hero.y - g.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { g.x += dx / dist * 18; g.y += dy / dist * 18; } } if (dist2(g, hero) < g.radius + hero.radius) { // Big XP gem gives 5 XP, normal gives 1 if (g.type === 'big') { xp += 5; } else { xp += 1; } g.destroy(); gems.splice(i, 1); if (xp >= xpToLevel) { level += 1; xp = 0; // Easier XP curve: gentler growth for faster level up xpToLevel = 8 + level * 5 + Math.floor(level * level * 0.7); LK.effects.flashObject(hero, 0xf7e967, 600); // On level up, spawn a big XP gem near hero spawnGem(hero.x + (Math.random() - 0.5) * 200, hero.y + (Math.random() - 0.5) * 200, { type: 'big' }); // Pause game and show level up popup with two options // Remove any previous popup if present if (typeof levelUpPopup !== "undefined" && levelUpPopup && levelUpPopup.parent) { levelUpPopup.parent.removeChild(levelUpPopup); levelUpPopup = null; } // Freeze all game logic and input game._levelUpFrozen = true; // Create popup container var levelUpPopup = new Container(); // Dim background (match start popup) var bg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, color: 0x008000 // green }); bg.width = 1100; bg.height = 1500; bg.alpha = 0.92; bg.x = centerX; bg.y = centerY; // Removed outline (LK.effects.outline not supported) levelUpPopup.addChild(bg); // Title (match start popup style) var titleTxt = new Text2('Level Up!', { size: 90, fill: "#fff", font: "Montserrat" }); titleTxt.anchor.set(0.5, 0); titleTxt.x = centerX; titleTxt.y = centerY - 550; levelUpPopup.addChild(titleTxt); // Option vertical layout (match start popup) var optionStartY = centerY - 320; var optionSpacing = 220; // Option 1: Permanent Attack Speed Boost var opt1 = new Container(); var opt1Bg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, color: 0x4eff00 // green }); opt1Bg.width = 800; opt1Bg.height = 160; opt1Bg.alpha = 0.98; opt1Bg.x = centerX; opt1Bg.y = optionStartY; // Removed outline (LK.effects.outline not supported) opt1.addChild(opt1Bg); var opt1Txt = new Text2('Attack Speed', { size: 54, fill: 0xF7E967, font: "Montserrat" }); opt1Txt.anchor.set(0.5, 0.5); opt1Txt.x = centerX; opt1Txt.y = optionStartY - 25; opt1.addChild(opt1Txt); var opt1Desc = new Text2('Fire faster every level!', { size: 40, fill: "#fff", font: "Montserrat" }); opt1Desc.anchor.set(0.5, 0.5); opt1Desc.x = centerX; opt1Desc.y = optionStartY + 35; opt1.addChild(opt1Desc); opt1.interactive = true; opt1.down = function (x, y, obj) { autoAttackInterval = Math.max(6, autoAttackInterval - 12); if (levelUpPopup && levelUpPopup.parent) { levelUpPopup.parent.removeChild(levelUpPopup); levelUpPopup = null; } game._levelUpFrozen = false; }; levelUpPopup.addChild(opt1); // Option 2: Ricochet bullet var opt2 = new Container(); var opt2Bg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, color: 0x4eff00 // green }); opt2Bg.width = 800; opt2Bg.height = 160; opt2Bg.alpha = 0.98; opt2Bg.x = centerX; opt2Bg.y = optionStartY + optionSpacing; // Removed outline (LK.effects.outline not supported) opt2.addChild(opt2Bg); var ricochetText = 'Ricochet'; if (typeof Bullet.prototype.ricochet !== "undefined" && Bullet.prototype.ricochet >= 1) { ricochetText = 'Ricochet +1 bounce'; } var opt2Txt = new Text2(ricochetText, { size: 54, fill: 0x7BE495, font: "Montserrat" }); opt2Txt.anchor.set(0.5, 0.5); opt2Txt.x = centerX; opt2Txt.y = optionStartY + optionSpacing - 25; opt2.addChild(opt2Txt); var opt2Desc = new Text2('Bullets bounce to another enemy', { size: 40, fill: "#fff", font: "Montserrat" }); opt2Desc.anchor.set(0.5, 0.5); opt2Desc.x = centerX; opt2Desc.y = optionStartY + optionSpacing + 35; opt2.addChild(opt2Desc); opt2.interactive = true; opt2.down = function (x, y, obj) { if (typeof Bullet.prototype.ricochet === "undefined" || Bullet.prototype.ricochet < 1) { Bullet.prototype.ricochet = 1; } else { Bullet.prototype.ricochet += 1; } if (levelUpPopup && levelUpPopup.parent) { levelUpPopup.parent.removeChild(levelUpPopup); levelUpPopup = null; } game._levelUpFrozen = false; }; levelUpPopup.addChild(opt2); // Option 3: +1 Bullet (spread shot) var opt3 = new Container(); var opt3Bg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, color: 0x4eff00 // green }); opt3Bg.width = 800; opt3Bg.height = 160; opt3Bg.alpha = 0.98; opt3Bg.x = centerX; opt3Bg.y = optionStartY + optionSpacing * 2; // Removed outline (LK.effects.outline not supported) opt3.addChild(opt3Bg); var opt3Txt = new Text2('Bullet +1', { size: 54, fill: 0xFFB347, font: "Montserrat" }); opt3Txt.anchor.set(0.5, 0.5); opt3Txt.x = centerX; opt3Txt.y = optionStartY + optionSpacing * 2 - 25; opt3.addChild(opt3Txt); var opt3Desc = new Text2('Shoot more bullets at once', { size: 40, fill: "#fff", font: "Montserrat" }); opt3Desc.anchor.set(0.5, 0.5); opt3Desc.x = centerX; opt3Desc.y = optionStartY + optionSpacing * 2 + 35; opt3.addChild(opt3Desc); opt3.interactive = true; opt3.down = function (x, y, obj) { if (typeof Bullet.prototype.extraBullets === "undefined") { Bullet.prototype.extraBullets = 1; } else { Bullet.prototype.extraBullets += 1; } if (levelUpPopup && levelUpPopup.parent) { levelUpPopup.parent.removeChild(levelUpPopup); levelUpPopup = null; } game._levelUpFrozen = false; }; levelUpPopup.addChild(opt3); // Option 4: Pierce +1 var opt4 = new Container(); var opt4Bg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, color: 0x4eff00 // green }); opt4Bg.width = 800; opt4Bg.height = 160; opt4Bg.alpha = 0.98; opt4Bg.x = centerX; opt4Bg.y = optionStartY + optionSpacing * 3; // Removed outline (LK.effects.outline not supported) opt4.addChild(opt4Bg); var opt4Txt = new Text2('Pierce +1', { size: 54, fill: 0x7BE4FF, font: "Montserrat" }); opt4Txt.anchor.set(0.5, 0.5); opt4Txt.x = centerX; opt4Txt.y = optionStartY + optionSpacing * 3 - 25; opt4.addChild(opt4Txt); var opt4Desc = new Text2('Bullets pass through more enemies', { size: 40, fill: "#fff", font: "Montserrat" }); opt4Desc.anchor.set(0.5, 0.5); opt4Desc.x = centerX; opt4Desc.y = optionStartY + optionSpacing * 3 + 35; opt4.addChild(opt4Desc); opt4.interactive = true; opt4.down = function (x, y, obj) { if (typeof Bullet.prototype.pierce === "undefined") { Bullet.prototype.pierce = 2; } else { Bullet.prototype.pierce += 1; } if (levelUpPopup && levelUpPopup.parent) { levelUpPopup.parent.removeChild(levelUpPopup); levelUpPopup = null; } game._levelUpFrozen = false; }; levelUpPopup.addChild(opt4); // Option 5: Bullets can follow up enemies var opt5 = new Container(); var opt5Bg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, color: 0x4eff00 // green }); opt5Bg.width = 800; opt5Bg.height = 160; opt5Bg.alpha = 0.98; opt5Bg.x = centerX; opt5Bg.y = optionStartY + optionSpacing * 4; // Removed outline (LK.effects.outline not supported) opt5.addChild(opt5Bg); var opt5Txt = new Text2('Missile', { size: 54, fill: 0xFF77FF, font: "Montserrat" }); opt5Txt.anchor.set(0.5, 0.5); opt5Txt.x = centerX; opt5Txt.y = optionStartY + optionSpacing * 4 - 25; opt5.addChild(opt5Txt); var opt5Desc = new Text2('Bullets home in on enemies', { size: 40, fill: "#fff", font: "Montserrat" }); opt5Desc.anchor.set(0.5, 0.5); opt5Desc.x = centerX; opt5Desc.y = optionStartY + optionSpacing * 4 + 35; opt5.addChild(opt5Desc); opt5.interactive = true; opt5.down = function (x, y, obj) { Bullet.prototype.homing = true; if (levelUpPopup && levelUpPopup.parent) { levelUpPopup.parent.removeChild(levelUpPopup); levelUpPopup = null; } game._levelUpFrozen = false; }; levelUpPopup.addChild(opt5); // Add popup to game game.addChild(levelUpPopup); } } } for (var i = powerups.length - 1; i >= 0; i--) { var p = powerups[i]; // Powerup collection area: always 150px (not affected by magnet) var powerupAttractRange = 150; var d = dist2(p, hero); // Attract powerups (magnet, heart, and others) if within hero's collection area (150px), but NOT by magnet effect if (d < powerupAttractRange && d > p.radius + hero.radius) { // Move powerup toward hero (gentle attraction) var dx = hero.x - p.x; var dy = hero.y - p.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { p.x += dx / dist * 10; p.y += dy / dist * 10; } } // Magnet powerup pickup radius (same as attract range) if (p.isMagnet && d < p.radius + hero.radius) { hero.magnetActive = true; // Set magnetEndTick to 10 seconds (600 frames) from now, synchronized with game time if (typeof ticksSurvived === "number") { hero.magnetEndTick = ticksSurvived + 600; hero.magnetDuration = 600; } else { hero.magnetEndTick = undefined; hero.magnetDuration = 600; } hero._magnetGlowActive = false; // force re-apply blue glow in Hero.update LK.effects.flashObject(hero, 0x00ffff, 800); p.destroy(); powerups.splice(i, 1); } // Yeni: Kalp powerup toplama else if (p.constructor === HeartPowerup && d < p.radius + hero.radius) { heroLives++; if (heroLives > 5) { heroLives = 5; } livesTxt.setText('Lives: ' + heroLives); p.destroy(); powerups.splice(i, 1); } // Diğer poweruplar için (şu an sadece magnet ve heart var) else if (!p.isMagnet && !(p.constructor === HeartPowerup) && d < p.radius + hero.radius) { // Pick up other powerups if needed (future-proof) p.destroy(); powerups.splice(i, 1); } } autoAttackTimer++; if (autoAttackTimer >= autoAttackInterval) { autoAttackTimer = 0; var nearest = null, minDist = 99999; for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; var d = dist2(hero, e); if (d < minDist) { minDist = d; nearest = e; } } if (nearest) { var dx = nearest.x - hero.x; var dy = nearest.y - hero.y; // Remove automatic extra bullets from level; now controlled by upgrade if (typeof Bullet.prototype.extraBullets === "undefined") { Bullet.prototype.extraBullets = 0; } var extraBullets = Bullet.prototype.extraBullets; var totalBullets = 1 + extraBullets; var spread; var baseAngle = Math.atan2(dy, dx); if (totalBullets % 2 === 0 && totalBullets > 1) { // Even number of bullets: 2 center bullets go straight and parallel, others scatter var centerIdx1 = totalBullets / 2 - 1; var centerIdx2 = totalBullets / 2; var offsetDist = 30; var perpAngle = baseAngle + Math.PI / 2; // Fire center two bullets parallel for (var b = 0; b < totalBullets; b++) { if (b === centerIdx1 || b === centerIdx2) { // Parallel bullets var offset = (b === centerIdx1 ? -1 : 1) * offsetDist / 2; var bulletX = hero.x + Math.cos(perpAngle) * offset; var bulletY = hero.y + Math.sin(perpAngle) * offset; var dirX = Math.cos(baseAngle); var dirY = Math.sin(baseAngle); var bullet = new Bullet(); bullet.x = bulletX; bullet.y = bulletY; bullet.pierce = Bullet.prototype.pierce || 1; bullet.dirX = dirX; bullet.dirY = dirY; bullet.rotation = baseAngle; bullets.push(bullet); game.addChild(bullet); } else { // Scattered bullets // Calculate scatter index for non-center bullets var scatterCount = totalBullets - 2; var scatterIdx = b < centerIdx1 ? b : b - 2; var scatterSpread = Math.PI / 32 + (level - 2) * Math.PI / 48; if (scatterSpread > Math.PI / 4) { scatterSpread = Math.PI / 4; } var angle = baseAngle; if (scatterCount > 1) { angle = baseAngle - scatterSpread / 2 + scatterSpread * scatterIdx / (scatterCount - 1); } var dirX = Math.cos(angle); var dirY = Math.sin(angle); fireBullet(dirX, dirY); } } } else if (level > 2) { spread = Math.PI / 32 + (level - 2) * Math.PI / 48; if (spread > Math.PI / 4) { spread = Math.PI / 4; } for (var b = 0; b < totalBullets; b++) { var angle = baseAngle; if (totalBullets > 1) { angle = baseAngle - spread / 2 + spread * b / (totalBullets - 1); } var dirX = Math.cos(angle); var dirY = Math.sin(angle); fireBullet(dirX, dirY); } } else { spread = Math.PI / 16; for (var b = 0; b < totalBullets; b++) { var angle = baseAngle; if (totalBullets > 1) { angle = baseAngle - spread / 2 + spread * b / (totalBullets - 1); } var dirX = Math.cos(angle); var dirY = Math.sin(angle); fireBullet(dirX, dirY); } } } else { var extraBullets = Math.max(0, level - 1); var totalBullets = 1 + extraBullets; var spread; if (level === 2) { spread = Math.PI / 32; } else if (level > 2) { spread = Math.PI / 32 + (level - 2) * Math.PI / 48; if (spread > Math.PI / 4) { spread = Math.PI / 4; } } else { spread = Math.PI / 16; } var baseAngle = Math.random() * Math.PI * 2; for (var b = 0; b < totalBullets; b++) { var angle = baseAngle; if (totalBullets > 1) { angle = baseAngle - spread / 2 + spread * b / (totalBullets - 1); } var dirX = Math.cos(angle); var dirY = Math.sin(angle); fireBullet(dirX, dirY); } } } spawnTimer++; if (spawnTimer >= spawnInterval) { spawnTimer = 0; var toSpawn = Math.max(1, Math.floor((1 + Math.floor(wave / 3)) / 4)); for (var i = 0; i < toSpawn; i++) { spawnEnemy(); } // Boss spawn logic: spawn boss every 30 waves if (typeof bossSpawnedWaves === "undefined") { bossSpawnedWaves = {}; } if (wave % 30 === 0 && !bossSpawnedWaves[wave]) { var boss = new BossEnemy(); // Spawn boss at a random edge var edge = Math.floor(Math.random() * 4); if (edge === 0) { boss.x = Math.random() * 2048; boss.y = -200; } else if (edge === 1) { boss.x = 2048 + 200; boss.y = Math.random() * 2732; } else if (edge === 2) { boss.x = Math.random() * 2048; boss.y = 2732 + 200; } else { boss.x = -200; boss.y = Math.random() * 2732; } enemies.push(boss); game.addChild(boss); bossSpawnedWaves[wave] = true; } wave++; spawnInterval = Math.max(24, 90 - Math.floor(wave / 2)); } ticksSurvived++; // Removed scoreTxt.setText, timer is shown in top right only xpTxt.setText('XP: ' + xp + '/' + xpToLevel); levelTxt.setText('Level: ' + level); var totalSeconds = Math.floor(ticksSurvived / 60); var minutes = Math.floor(totalSeconds / 60); var seconds = totalSeconds % 60; var minStr = minutes < 10 ? '0' + minutes : '' + minutes; var secStr = seconds < 10 ? '0' + seconds : '' + seconds; timerTxt.setText(minStr + ':' + secStr); // Only reset heroLives and livesTxt on game restart, not every frame if (lastGameOver && hero && hero.parent) { lastGameOver = false; heroLives = 5; if (heroLives > 5) { heroLives = 5; } if (livesTxt) { livesTxt.setText('Lives: ' + heroLives); } } // Magnet timer display if (hero.magnetActive && hero.magnetDuration > 0) { var magnetSeconds = Math.ceil(hero.magnetDuration / 60); magnetTimerTxt.setText('Magnet: ' + magnetSeconds + 's'); } else { magnetTimerTxt.setText(''); } };
===================================================================
--- original.js
+++ change.js
@@ -661,9 +661,9 @@
// Move XP text below the lives text (livesTxt.y + livesTxt.height + 8 for spacing), then 30px further down
xpTxt.y = livesTxt.y + livesTxt.height + 8 - 30 + 30;
LK.gui.topRight.addChild(xpTxt);
levelTxt = new Text2('Level: 1', {
- size: 36,
+ size: 44,
fill: 0xF7E967,
font: "Montserrat"
});
levelTxt.anchor.set(0.5, 0);
16x16 pixel wounded guy holding pistol. In-Game asset. 2d. High contrast. No shadows. pixel art. retro arcade game
3x3 pixel green coin. In-Game asset. 2d. High contrast. No shadows. retro arcade. Pixel art
3x3 pixel blue coin. In-Game asset. 2d. High contrast. No shadows. Pixel art. retro arcade
4x4 pixel art heart. In-Game asset. 2d. High contrast. No shadows. retro arcade. Pixel art. 8 bit
fill the circle with yellow colour
remove cars and buildings
Create an 8-bit style effect representing a magnetic power-up area. The effect should be a circular, glowing field with a soft, pulsing light. The colors should be green and blue, with a slight gradient effect to indicate the area where objects (such as coins or experience points) are attracted towards the character. The circle should have a subtle flicker to show the magnetic pull, and it should be designed to fit within the retro, pixel-art aesthetic of an 8-bit game. In-Game asset. 2d. High contrast. No shadows
Vertical windowed filled rectangle HUD for the 2d zombie theme game. Use green colours. Do not make it too much pixelated. In-Game asset. 2d. High contrast. No shadows. No text. No icon. No background Transparent.Retro arcade theme.
windowed filled rectangle HUD button for the 2d pixel art zombie theme game. Use dark green colours. In-Game asset. 2d. High contrast. No shadows. No text. No icon. No background Transparent.Retro arcade theme.
pixelart magnet In-Game asset. 2d. High contrast. No shadows. Pixel art
pixelart red circular enemy projectile to dodge In-Game asset. 2d. High contrast. No shadows. Pixel art
pixelart yellow circular bullet to shoot enemies In-Game asset. 2d. High contrast. No shadows. Pixel art
pixelart blue circular enemy projectile to dodge In-Game asset. 2d. High contrast. No shadows. Pixel art
4x4pixel bow and arrow. In-Game asset. 2d. High contrast. No shadows. Black outline
8x8 pixel movement speed powerup icon. boot with wings. In-Game asset. 2d. High contrast. No shadows. Black outline