User prompt
When choosing a plugin, creatures should not cause damage, and add more plugins, add plugins that give area damage, etc., and add a background model, I will change it. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
They die without touching me. Add a bullet model and when choosing an add-on, the creatures should not cause damage.
User prompt
There is a level up tab, add it as a model, I will change it and the bullet model should go directly to the man, not as a straight png, but straight
User prompt
add a level screen to show how many levels we have or how much of the other level is left and add an assets screen compatible with the police
User prompt
The issue is that when we get a skill, it should not go to living beings, it should come only to us, and also to living beings with weapons in their hands, and it should slow down the very fast speeds of the living beings a little.
User prompt
Reduce the number of living creatures coming, but increase it by 1 click after 3 minutes, so that it constantly uses weapons, and the gun barrel points to living creatures.
User prompt
Let the gun barrel also look at the creatures, and while you buy the add-ons, the game should pause, and the creatures should be a little smarter, and the creatures should come in stages.
User prompt
Let the gun be visible in our hand and have a bullet model when firing
User prompt
Let the creatures come a little later and give us a weapon model
User prompt
Please fix the bug: 'prepareWave is not defined' in or related to this line: 'prepareWave();' Line Number: 758
User prompt
Knk, look, creatures should behave a little differently from each other because when creatures are gathered somewhere and revolve around them, they cannot do anything. Also, they should come continuously, not in waves, but continuously and without stopping. Also, the game should wait like this while purchasing add-ons.
User prompt
Knk, look, the creatures should behave a little differently from each other because when you gather the creatures somewhere, for example, they cannot do anything when they revolve around you. Also, they should come continuously, not in waves, but continuously and without stopping. Also, the game should wait like this while purchasing add-ons.
User prompt
Let it be a continuous live stream and add something like artificial intelligence to the creatures so that it is not so stupid
User prompt
Don't let the creatures come all at once, let them come continuously and expand the playing area a little.
User prompt
Don't let other creatures come so much, let them increase over time, and make sure that almost no bullets miss. Make a better weapon's mechanic to turn into creatures.
Code edit (1 edits merged)
Please save this source code
Initial prompt
Beast Survivors
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Creature projectile class with unique behaviors var CreatureProjectile = Container.expand(function () { var self = Container.call(this); var asset = self.attachAsset('bulletModel', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 32; self.speed = 32; self.angle = 0; self.damage = 1; // Assign a unique behavior type to each projectile var behaviorTypes = ['homing', 'zigzag', 'boomerang', 'spiral', 'dash', 'orbit', 'bounce']; self.behavior = behaviorTypes[Math.floor(Math.random() * behaviorTypes.length)]; self.behaviorSeed = Math.random() * 10000; self.behaviorTick = 0; self.originX = self.x; self.originY = self.y; self.maxDistance = 1200 + Math.random() * 400; self.orbitAngle = Math.random() * Math.PI * 2; self.bounceCount = 0; self.update = function () { self.behaviorTick++; // --- Unique behaviors --- if (self.behavior === 'homing') { // Homing: as before, but with a little more erratic movement var nearest = null; var minDist = 999999; for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; var dx = e.x - self.x; var dy = e.y - self.y; var d = Math.sqrt(dx * dx + dy * dy); if (d < minDist) { minDist = d; nearest = e; } } if (nearest && minDist > 1) { var lead = 0.18 + Math.random() * 0.08; var ex = nearest.x, ey = nearest.y; if (typeof nearest.lastX === "number" && typeof nearest.lastY === "number") { var vx = nearest.x - nearest.lastX; var vy = nearest.y - nearest.lastY; ex += vx * lead * (minDist / 64); ey += vy * lead * (minDist / 64); } var targetAngle = Math.atan2(ey - self.y, ex - self.x); // Add a little random wiggle targetAngle += Math.sin(self.behaviorTick * 0.13 + self.behaviorSeed) * 0.12; // Smoothly turn toward target var da = targetAngle - self.angle; while (da > Math.PI) da -= Math.PI * 2; while (da < -Math.PI) da += Math.PI * 2; var turnRate = 0.18 + Math.min(0.32, minDist / 400 * 0.25); self.angle += da * turnRate; } // Move forward self.x += Math.cos(self.angle) * self.speed; self.y += Math.sin(self.angle) * self.speed; } else if (self.behavior === 'zigzag') { // Zigzag: moves forward, but oscillates side to side var freq = 0.18 + self.behaviorSeed % 0.2; var amp = 48 + self.behaviorSeed % 32; var zig = Math.sin(self.behaviorTick * freq + self.behaviorSeed) * amp; self.x += Math.cos(self.angle) * self.speed + Math.cos(self.angle + Math.PI / 2) * zig * 0.08; self.y += Math.sin(self.angle) * self.speed + Math.sin(self.angle + Math.PI / 2) * zig * 0.08; } else if (self.behavior === 'boomerang') { // Boomerang: flies out, then returns to player var t = self.behaviorTick; var outTime = 32 + self.behaviorSeed % 32; if (t < outTime) { self.x += Math.cos(self.angle) * self.speed; self.y += Math.sin(self.angle) * self.speed; } else { // Return to player var dx = player.x - self.x; var dy = player.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self.x += dx / dist * self.speed * 1.2; self.y += dy / dist * self.speed * 1.2; } } } else if (self.behavior === 'spiral') { // Spiral: moves in a spiral pattern var spiralSpeed = self.speed * 0.7; var spiralRadius = 80 + self.behaviorSeed % 40; var spiralAngle = self.angle + self.behaviorTick * 0.13; self.x += Math.cos(self.angle) * spiralSpeed + Math.cos(spiralAngle) * spiralRadius * 0.04; self.y += Math.sin(self.angle) * spiralSpeed + Math.sin(spiralAngle) * spiralRadius * 0.04; } else if (self.behavior === 'dash') { // Dash: moves very fast in a straight line, then slows and homes if (self.behaviorTick < 18) { self.x += Math.cos(self.angle) * self.speed * 2.2; self.y += Math.sin(self.angle) * self.speed * 2.2; } else { // Home in after dash var nearest = null; var minDist = 999999; for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; var dx = e.x - self.x; var dy = e.y - self.y; var d = Math.sqrt(dx * dx + dy * dy); if (d < minDist) { minDist = d; nearest = e; } } if (nearest && minDist > 1) { var targetAngle = Math.atan2(nearest.y - self.y, nearest.x - self.x); var da = targetAngle - self.angle; while (da > Math.PI) da -= Math.PI * 2; while (da < -Math.PI) da += Math.PI * 2; self.angle += da * 0.22; } self.x += Math.cos(self.angle) * self.speed * 0.8; self.y += Math.sin(self.angle) * self.speed * 0.8; } } else if (self.behavior === 'orbit') { // Orbit: circles around the player for a while, then launches at nearest enemy if (self.behaviorTick < 36 + self.behaviorSeed % 24) { self.orbitAngle += 0.18 + self.behaviorSeed % 0.1; var orbitRadius = 180 + self.behaviorSeed % 60; self.x = player.x + Math.cos(self.orbitAngle) * orbitRadius; self.y = player.y + Math.sin(self.orbitAngle) * orbitRadius; } else { var nearest = null; var minDist = 999999; for (var i = 0; i < enemies.length; i++) { var e = enemies[i]; var dx = e.x - self.x; var dy = e.y - self.y; var d = Math.sqrt(dx * dx + dy * dy); if (d < minDist) { minDist = d; nearest = e; } } if (nearest && minDist > 1) { var targetAngle = Math.atan2(nearest.y - self.y, nearest.x - self.x); self.angle = targetAngle; } self.x += Math.cos(self.angle) * self.speed * 1.2; self.y += Math.sin(self.angle) * self.speed * 1.2; } } else if (self.behavior === 'bounce') { // Bounce: ricochets off the play area edges a few times self.x += Math.cos(self.angle) * self.speed; self.y += Math.sin(self.angle) * self.speed; var bounced = false; if (self.x < self.radius) { self.x = self.radius; self.angle = Math.PI - self.angle; bounced = true; } if (self.x > GAME_WIDTH - self.radius) { self.x = GAME_WIDTH - self.radius; self.angle = Math.PI - self.angle; bounced = true; } if (self.y < self.radius) { self.y = self.radius; self.angle = -self.angle; bounced = true; } if (self.y > GAME_HEIGHT - self.radius) { self.y = GAME_HEIGHT - self.radius; self.angle = -self.angle; bounced = true; } if (bounced) self.bounceCount++; if (self.bounceCount > 3) { self.destroy(); } } // Save last position for AI self.lastX = self.x; self.lastY = self.y; // Remove projectile if it has traveled too far from its origin var dx0 = self.x - self.originX; var dy0 = self.y - self.originY; if (dx0 * dx0 + dy0 * dy0 > self.maxDistance * self.maxDistance) { self.destroy(); } }; return self; }); // Creature weapon class (auto-attacks for player) var CreatureWeapon = Container.expand(function () { var self = Container.call(this); // Attach asset (box, yellow) var asset = self.attachAsset('creature', { anchorX: 0.5, anchorY: 0.5 }); // Attach weapon model (sword) as a visual var weaponModel = self.attachAsset('weaponModel', { anchorX: 0.5, anchorY: 0.8 }); weaponModel.y = 60; // Offset so it appears in front of the player weaponModel.rotation = Math.PI / 8 * (Math.random() > 0.5 ? 1 : -1); // Slight random angle for variety weaponModel.alpha = 0.85; // Weapon stats self.damage = 1; self.speed = 32; self.cooldown = 60; // frames between shots self.timer = 0; self.projectileCount = 1; self.spread = 0.2; // radians // Update method: fires projectiles if timer is up self.update = function () { if (self.timer > 0) { self.timer--; } else { self.fire(); self.timer = self.cooldown; } }; // Fire projectiles in a spread self.fire = function () { // Projectiles orbit and launch from around the player var now = Date.now(); for (var i = 0; i < self.projectileCount; i++) { // Orbit offset for each projectile var orbitAngle = 2 * Math.PI / self.projectileCount * i + now % 1000 / 1000 * Math.PI * 2; var launchDist = 120 + Math.random() * 30; var px = player.x + Math.cos(orbitAngle) * launchDist; var py = player.y + Math.sin(orbitAngle) * launchDist; // Clamp projectile spawn to play area if (px < 0) px = 0; if (px > GAME_WIDTH) px = GAME_WIDTH; if (py < 0) py = 0; if (py > GAME_HEIGHT) py = GAME_HEIGHT; // Aim at nearest enemy if possible var target = null; var minDist = 999999; for (var j = 0; j < enemies.length; j++) { var e = enemies[j]; var dx = e.x - px; var dy = e.y - py; var d = Math.sqrt(dx * dx + dy * dy); if (d < minDist) { minDist = d; target = e; } } var angle; if (target) { angle = Math.atan2(target.y - py, target.x - px); } else { angle = orbitAngle; } var proj = new CreatureProjectile(); proj.x = px; proj.y = py; proj.angle = angle; proj.speed = self.speed; proj.damage = self.damage; projectiles.push(proj); game.addChild(proj); } }; // Upgrade weapon self.upgrade = function (type) { if (type === 'damage') self.damage++; if (type === 'speed') self.speed += 6; if (type === 'cooldown' && self.cooldown > 20) self.cooldown -= 8; if (type === 'projectile') self.projectileCount++; if (type === 'spread') self.spread += 0.1; }; return self; }); // Enemy class var Enemy = Container.expand(function () { var self = Container.call(this); var asset = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 48; self.speed = 6 + Math.random() * 3; self.hp = 2 + Math.floor(wave * 0.5); self.maxHp = self.hp; // For movement self.update = function () { // Save last position for AI self.lastX = self.x; self.lastY = self.y; // Move towards player var dx = player.x - self.x; var dy = player.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; } }; // Take damage self.takeDamage = function (amount) { self.hp -= amount; LK.effects.flashObject(self, 0xffff00, 200); if (self.hp <= 0) { spawnExp(self.x, self.y, 1 + Math.floor(wave * 0.2)); self.destroy(); return true; } return false; }; return self; }); // Experience gem class var ExpGem = Container.expand(function () { var self = Container.call(this); var asset = self.attachAsset('expGem', { anchorX: 0.5, anchorY: 0.5 }); self.radius = 28; self.value = 1; self.update = function () { // If close to player, move towards player var dx = player.x - self.x; var dy = player.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 300) { self.x += dx / dist * 18; self.y += dy / dist * 18; } }; return self; }); // Player character class var Player = Container.expand(function () { var self = Container.call(this); // Attach player asset (ellipse, green) var playerAsset = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // Attach weapon model (gun) to player's hand var gunModel = self.attachAsset('weaponModel', { anchorX: 0.2, // grip point anchorY: 0.7 }); gunModel.x = 38; // offset to player's right hand gunModel.y = 38; gunModel.rotation = Math.PI / 8; gunModel.alpha = 0.95; self.gunModel = gunModel; // Set up player stats self.radius = 60; // for collision self.speed = 18; // movement speed per frame self.level = 1; self.exp = 0; self.expToLevel = 10; self.hp = 3; self.maxHp = 3; // For movement smoothing self.targetX = GAME_WIDTH / 2; self.targetY = GAME_HEIGHT / 2; // For invulnerability after hit self.invulnTicks = 0; // Update method self.update = function () { // Smoothly move towards target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > self.speed) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } else { self.x = self.targetX; self.y = self.targetY; } // Clamp to game area if (self.x < self.radius) self.x = self.radius; if (self.x > GAME_WIDTH - self.radius) self.x = GAME_WIDTH - self.radius; if (self.y < self.radius) self.y = self.radius; if (self.y > GAME_HEIGHT - self.radius) self.y = GAME_HEIGHT - self.radius; // Invulnerability timer if (self.invulnTicks > 0) { self.invulnTicks--; playerAsset.alpha = self.invulnTicks % 10 < 5 ? 0.5 : 1; } else { playerAsset.alpha = 1; } // Update gun model to follow hand (right side of player) if (self.gunModel) { // Gun follows player's facing direction (right side) self.gunModel.x = self.radius * 0.55; self.gunModel.y = self.radius * 0.25; // Optionally, add a little bobbing for effect self.gunModel.rotation = Math.PI / 8 + Math.sin(LK.ticks * 0.08) * 0.08; } }; // Level up self.gainExp = function (amount) { self.exp += amount; while (self.exp >= self.expToLevel) { self.exp -= self.expToLevel; self.level++; self.expToLevel = Math.floor(self.expToLevel * 1.3 + 5); showLevelUp(); } updateExpBar(); }; // Take damage self.takeDamage = function () { if (self.invulnTicks > 0) return; self.hp--; updateHpBar(); self.invulnTicks = 60; LK.effects.flashObject(self, 0xff0000, 500); if (self.hp <= 0) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a1a }); /**** * Game Code ****/ // Weapon model asset (simple sword shape) // --- Global variables --- var player; var creatureWeapon; var projectiles = []; var enemies = []; var expGems = []; var wave = 1; // still used for scaling difficulty var dragNode = null; // --- GUI Elements --- var scoreTxt = new Text2('0', { size: 100, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var expBar = new Text2('', { size: 60, fill: 0xAAFF00 }); expBar.anchor.set(0.5, 0); LK.gui.top.addChild(expBar); var hpBar = new Text2('', { size: 60, fill: 0xFF4444 }); hpBar.anchor.set(0.5, 0); LK.gui.top.addChild(hpBar); function updateExpBar() { expBar.setText('LV ' + player.level + ' EXP: ' + player.exp + '/' + player.expToLevel); } function updateHpBar() { hpBar.setText('HP: ' + player.hp + '/' + player.maxHp); } function updateScore() { scoreTxt.setText('Wave: ' + wave); } // --- Asset initialization (shapes) --- // --- Game setup --- player = new Player(); // Expanded play area var GAME_WIDTH = 3072; var GAME_HEIGHT = 4096; player.x = GAME_WIDTH / 2; player.y = GAME_HEIGHT / 2; game.addChild(player); creatureWeapon = new CreatureWeapon(); game.addChild(creatureWeapon); updateExpBar(); updateHpBar(); updateScore(); // --- Level up popup --- var levelUpPopup = null; function showLevelUp() { if (levelUpPopup) return; // Already showing // Randomly pick 3 upgrades var upgrades = [{ type: 'damage', label: 'Creature Damage +' }, { type: 'speed', label: 'Creature Speed +' }, { type: 'cooldown', label: 'Faster Attacks' }, { type: 'projectile', label: 'More Projectiles' }, { type: 'spread', label: 'Wider Spread' }]; // Shuffle and pick 3 for (var i = upgrades.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var t = upgrades[i]; upgrades[i] = upgrades[j]; upgrades[j] = t; } var options = upgrades.slice(0, 3); // Popup container levelUpPopup = new Container(); var bg = LK.getAsset('levelUpBg', { width: 900, height: 700, color: 0x222244, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); levelUpPopup.addChild(bg); bg.x = 0; bg.y = 0; var title = new Text2('LEVEL UP!', { size: 120, fill: "#fff" }); title.anchor.set(0.5, 0); title.x = 0; title.y = -300; levelUpPopup.addChild(title); // Option buttons for (var i = 0; i < 3; i++) { (function (idx) { var opt = options[idx]; var btn = LK.getAsset('levelUpBtn' + idx, { width: 700, height: 140, color: 0x4444aa, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); btn.x = 0; btn.y = -80 + idx * 180; levelUpPopup.addChild(btn); var txt = new Text2(opt.label, { size: 70, fill: "#fff" }); txt.anchor.set(0.5, 0.5); txt.x = 0; txt.y = btn.y; levelUpPopup.addChild(txt); btn.down = function (x, y, obj) { creatureWeapon.upgrade(opt.type); // Remove popup LK.gui.center.removeChild(levelUpPopup); levelUpPopup = null; }; })(i); } levelUpPopup.x = 0; levelUpPopup.y = 0; LK.gui.center.addChild(levelUpPopup); } // --- Spawn experience gem --- function spawnExp(x, y, value) { var gem = new ExpGem(); gem.x = x; gem.y = y; gem.value = value; expGems.push(gem); game.addChild(gem); } // --- Continuous enemy spawn system --- var spawnDelay = 32; // frames between spawns, will decrease as wave increases var spawnDelayTimer = 0; // Add a delay before the first enemy spawns var initialSpawnDelay = 120; // 2 seconds at 60fps var initialSpawnDelayTimer = 0; function updateSpawnRate() { // Increase spawn rate over time, but clamp to a minimum spawnDelay = Math.max(4, 32 - Math.floor(wave * 1.2)); } function spawnEnemy() { var enemy = new Enemy(); // Spawn at random edge var edge = Math.floor(Math.random() * 4); if (edge === 0) { // top enemy.x = Math.random() * GAME_WIDTH; enemy.y = -100; } else if (edge === 1) { // bottom enemy.x = Math.random() * GAME_WIDTH; enemy.y = GAME_HEIGHT + 100; } else if (edge === 2) { // left enemy.x = -100; enemy.y = Math.random() * GAME_HEIGHT; } else { // right enemy.x = GAME_WIDTH + 100; enemy.y = Math.random() * GAME_HEIGHT; } enemies.push(enemy); game.addChild(enemy); } // --- Game move handler (touch/mouse drag to move player) --- function handleMove(x, y, obj) { // Don't allow movement if level up popup is open if (levelUpPopup) return; // Clamp to avoid top left menu if (x < 100) x = 100; if (y < 0) y = 0; player.targetX = x; player.targetY = y; } game.move = handleMove; game.down = function (x, y, obj) { handleMove(x, y, obj); }; game.up = function (x, y, obj) { // No dragNode needed, movement is always allowed }; // --- Main game update loop --- game.update = function () { // Pause all game logic except GUI and popup when level up popup is open if (levelUpPopup) { // Only update GUI, skip all gameplay logic return; } // Update player player.update(); // Update weapon creatureWeapon.update(); // Update projectiles for (var i = projectiles.length - 1; i >= 0; i--) { var proj = projectiles[i]; proj.update(); // Remove if out of bounds if (proj.x < -100 || proj.x > GAME_WIDTH + 100 || proj.y < -100 || proj.y > GAME_HEIGHT + 100) { proj.destroy(); projectiles.splice(i, 1); continue; } // Check collision with enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; var dx = proj.x - enemy.x; var dy = proj.y - enemy.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < proj.radius + enemy.radius) { var killed = enemy.takeDamage(proj.damage); proj.destroy(); projectiles.splice(i, 1); if (killed) { enemies.splice(j, 1); } break; } } } // Update enemies for (var i = enemies.length - 1; i >= 0; i--) { var enemy = enemies[i]; enemy.update(); // Check collision with player var dx = enemy.x - player.x; var dy = enemy.y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < enemy.radius + player.radius) { player.takeDamage(); // Knockback enemy var angle = Math.atan2(dy, dx); enemy.x += Math.cos(angle) * 120; enemy.y += Math.sin(angle) * 120; } } // Update exp gems for (var i = expGems.length - 1; i >= 0; i--) { var gem = expGems[i]; gem.update(); // Collect if close to player var dx = gem.x - player.x; var dy = gem.y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < gem.radius + player.radius) { player.gainExp(gem.value); gem.destroy(); expGems.splice(i, 1); } } // Continuous enemy spawn (no waves) if (!levelUpPopup) { // Wait for initial spawn delay before starting enemy spawns if (initialSpawnDelayTimer < initialSpawnDelay) { initialSpawnDelayTimer++; } else { spawnDelayTimer++; if (spawnDelayTimer >= spawnDelay) { spawnEnemy(); spawnDelayTimer = 0; } // Increase difficulty over time, every 10 seconds if (LK.ticks % (60 * 10) === 0) { wave++; updateScore(); updateSpawnRate(); } } } }; // --- GUI positioning --- scoreTxt.x = GAME_WIDTH / 2; scoreTxt.y = 20; expBar.x = GAME_WIDTH / 2; expBar.y = 140; hpBar.x = GAME_WIDTH / 2; hpBar.y = 220; // --- Start first wave --- // No prepareWave needed; enemy spawning is now continuous.
===================================================================
--- original.js
+++ change.js
@@ -8,9 +8,9 @@
****/
// Creature projectile class with unique behaviors
var CreatureProjectile = Container.expand(function () {
var self = Container.call(this);
- var asset = self.attachAsset('creatureProj', {
+ var asset = self.attachAsset('bulletModel', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = 32;
@@ -348,8 +348,19 @@
var playerAsset = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
+ // Attach weapon model (gun) to player's hand
+ var gunModel = self.attachAsset('weaponModel', {
+ anchorX: 0.2,
+ // grip point
+ anchorY: 0.7
+ });
+ gunModel.x = 38; // offset to player's right hand
+ gunModel.y = 38;
+ gunModel.rotation = Math.PI / 8;
+ gunModel.alpha = 0.95;
+ self.gunModel = gunModel;
// Set up player stats
self.radius = 60; // for collision
self.speed = 18; // movement speed per frame
self.level = 1;
@@ -386,8 +397,16 @@
playerAsset.alpha = self.invulnTicks % 10 < 5 ? 0.5 : 1;
} else {
playerAsset.alpha = 1;
}
+ // Update gun model to follow hand (right side of player)
+ if (self.gunModel) {
+ // Gun follows player's facing direction (right side)
+ self.gunModel.x = self.radius * 0.55;
+ self.gunModel.y = self.radius * 0.25;
+ // Optionally, add a little bobbing for effect
+ self.gunModel.rotation = Math.PI / 8 + Math.sin(LK.ticks * 0.08) * 0.08;
+ }
};
// Level up
self.gainExp = function (amount) {
self.exp += amount;
police pixel art. In-Game asset. 2d. High contrast. No shadows
black person pixel art. In-Game asset. High contrast. No shadows
glock pixel art. In-Game asset. High contrast. No shadows
pixel art bullet. In-Game asset. High contrast. No shadows
money pixel art. In-Game asset. High contrast. No shadows
a police themed level up screen pixel art. In-Game asset. High contrast. No shadows