User prompt
silah sıkınca ses te olsun
User prompt
silah mavi bir renk olsun bide yeni nesneye yap
User prompt
sen yapsan
User prompt
oyuncunu elinde silah olsun
User prompt
hareket edelim
Code edit (1 edits merged)
Please save this source code
User prompt
Zombie Escape: Shoot & Survive
Initial prompt
silahlar olsun bide zombiler olsun biz onlardan kaçıp vuralım
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGfx = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = bulletGfx.width / 2;
self.speed = 32; // Fast bullet
self.vx = 0;
self.vy = 0;
// Set direction
self.setDirection = function (dx, dy) {
var len = Math.sqrt(dx * dx + dy * dy);
if (len > 0) {
self.vx = dx / len * self.speed;
self.vy = dy / len * self.speed;
}
};
self.update = function () {
// Move bullet
self.x += self.vx;
self.y += self.vy;
};
return self;
});
// Hero class
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGfx = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
// Add a gun to hero's hand
// Use the new blue gun asset, positioned to the right hand
var gunGfx = self.attachAsset('bluegun', {
anchorX: 0.2,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 0.6,
x: heroGfx.width * 0.38,
// offset to right hand
y: 0
});
// Track gun rotation
self.gunGfx = gunGfx;
self.gunAngle = 0;
// For future upgrades: health, weapon, etc.
self.radius = heroGfx.width / 2;
return self;
});
// Zombie class
var Zombie = Container.expand(function () {
var self = Container.call(this);
var zombieGfx = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = zombieGfx.width / 2;
// Speed will be set on spawn
// Make zombies move at half the speed of the hero
var heroBaseSpeed = 6; // Set hero base speed (if not defined elsewhere)
self.speed = heroBaseSpeed * 0.5 + Math.random() * (heroBaseSpeed * 0.1); // 50% slower, small random
// Direction vector
self.vx = 0;
self.vy = 0;
// Health for zombie: 1 heart
self.maxHealth = 1;
self.health = self.maxHealth;
// Heart icon(s) above zombie
self.heartIcons = [];
for (var i = 0; i < self.maxHealth; i++) {
var heartIcon = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5,
x: (i - (self.maxHealth - 1) / 2) * 60,
// center hearts
y: -self.radius - 40,
scaleX: 0.7,
scaleY: 0.7
});
self.addChild(heartIcon);
self.heartIcons.push(heartIcon);
}
// Set direction towards hero
self.setDirection = function (targetX, targetY) {
var dx = targetX - self.x;
var dy = targetY - self.y;
var len = Math.sqrt(dx * dx + dy * dy);
if (len > 0) {
self.vx = dx / len * self.speed;
self.vy = dy / len * self.speed;
}
};
// Move towards direction
self.update = function () {
self.x += self.vx;
self.y += self.vy;
// Keep health text above zombie
if (self.healthTxt) {
self.healthTxt.x = 0;
self.healthTxt.y = -self.radius - 10;
}
};
// Method to take damage
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health < 0) self.health = 0;
// Update heart icons
for (var i = 0; i < self.heartIcons.length; i++) {
self.heartIcons[i].visible = i < self.health;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Sound for shooting
// Bullet asset: yellow box
// Zombie asset: green ellipse
// Hero asset: red box
// Game area
// New blue gun asset
var GAME_W = 2048;
var GAME_H = 2732;
// Hero base speed for zombie speed calculation
var heroBaseSpeed = 6;
// Hero setup
var hero = new Hero();
hero.x = GAME_W / 2;
hero.y = GAME_H / 2;
game.addChild(hero);
// Bullets and zombies arrays
var bullets = [];
var zombies = [];
// --- Şarjör/Magazine System ---
var MAG_SIZE = 7; // şarjör kapasitesi
var TOTAL_BULLETS = 20; // toplam yedek mermi
var magazine = MAG_SIZE; // şarjördeki mermi
var reserveBullets = TOTAL_BULLETS - MAG_SIZE; // yedek mermi
var isReloading = false;
var reloadTime = 3000; // ms
var reloadTimeout = null;
// --- Bullet Type System (auto change every 2 seconds) ---
var bulletTypes = [{
id: 'bullet',
speed: 32
},
// default
{
id: 'bullet',
speed: 48
},
// fast
{
id: 'bullet',
speed: 16
} // slow
];
var currentBulletTypeIndex = 0;
var bulletTypeChangeInterval = null;
// Start auto bullet type change
function startBulletTypeAutoChange() {
if (bulletTypeChangeInterval) LK.clearInterval(bulletTypeChangeInterval);
bulletTypeChangeInterval = LK.setInterval(function () {
currentBulletTypeIndex = (currentBulletTypeIndex + 1) % bulletTypes.length;
}, 2000);
}
startBulletTypeAutoChange();
// Mermi UI - Text-based bullet count at the bottom left
var bulletTxt = new Text2(magazine + " / " + reserveBullets, {
size: 90,
fill: "#fff"
});
// Anchor to left-bottom
bulletTxt.anchor.set(0, 1);
bulletTxt.x = 60;
bulletTxt.y = 2732 - 40;
LK.gui.bottomLeft.addChild(bulletTxt);
function updateBulletIcons() {
bulletTxt.setText(magazine + " / " + reserveBullets);
if (typeof outOfAmmoTxt !== "undefined" && outOfAmmoTxt && outOfAmmoTxt.visible) {
outOfAmmoTxt.setText("Mermi bitti\n" + magazine + " / " + reserveBullets);
}
}
updateBulletIcons();
// "Mermi bitti" UI
var outOfAmmoTxt = new Text2("Mermi bitti\n" + magazine + " / " + reserveBullets, {
size: 260,
fill: "#fff",
align: "center"
});
// Bottom center: anchor to center-bottom, x=center, y=height
outOfAmmoTxt.anchor.set(0.5, 1);
outOfAmmoTxt.x = 2048 / 2;
outOfAmmoTxt.y = 2732 - 40;
outOfAmmoTxt.visible = false;
LK.gui.bottom.addChild(outOfAmmoTxt);
// Score
var score = 0;
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Hearts (health)
var maxHearts = 5;
var hearts = [];
for (var i = 0; i < maxHearts; i++) {
var heart = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5,
x: 160 + i * 120,
y: 80,
scaleX: 1.1,
scaleY: 1.1
});
LK.gui.top.addChild(heart);
hearts.push(heart);
}
var currentHearts = maxHearts;
// Dragging
var dragNode = null;
// Touch/move controls
function handleMove(x, y, obj) {
// Drag hero
if (dragNode === hero) {
// Clamp hero inside game area, avoid top left 100x100
var minX = hero.radius + 100;
var maxX = GAME_W - hero.radius;
var minY = hero.radius;
var maxY = GAME_H - hero.radius;
hero.x = Math.max(minX, Math.min(maxX, x));
hero.y = Math.max(minY, Math.min(maxY, y));
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only drag if touch is on hero
var dx = x - hero.x;
var dy = y - hero.y;
if (dx * dx + dy * dy <= hero.radius * hero.radius) {
dragNode = hero;
handleMove(x, y, obj);
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Shooting: tap anywhere not on hero to shoot
game.tap = function (x, y, obj) {
// Don't shoot if tap is on hero
var dx = x - hero.x;
var dy = y - hero.y;
if (dx * dx + dy * dy <= hero.radius * hero.radius) return;
// Create bullet
var bullet = new Bullet();
bullet.x = hero.x;
bullet.y = hero.y;
// Set bullet speed/type
var bulletType = bulletTypes[currentBulletTypeIndex];
bullet.speed = bulletType.speed;
bullet.setDirection(dx, dy);
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
// Rotate gun towards shot direction
if (typeof hero.gunGfx !== "undefined") {
hero.gunGfx.rotation = Math.atan2(dy, dx);
}
};
game.down = function (x, y, obj) {
// Drag or shoot
var dx = x - hero.x;
var dy = y - hero.y;
if (dx * dx + dy * dy <= hero.radius * hero.radius) {
dragNode = hero;
handleMove(x, y, obj);
} else {
// --- Şarjör/Magazine Logic ---
if (isReloading) {
// Reloading, can't shoot
return;
}
if (magazine > 0) {
// Shoot
var bullet = new Bullet();
bullet.x = hero.x;
bullet.y = hero.y;
// Set bullet speed/type
var bulletType = bulletTypes[currentBulletTypeIndex];
bullet.speed = bulletType.speed;
bullet.setDirection(dx, dy);
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
// Rotate gun towards shot direction
if (typeof hero.gunGfx !== "undefined") {
hero.gunGfx.rotation = Math.atan2(dy, dx);
}
magazine--;
updateBulletIcons();
outOfAmmoTxt.visible = false;
// If şarjör bitti, start reload if possible
if (magazine === 0) {
if (reserveBullets > 0) {
isReloading = true;
LK.getSound('reload').play();
// Stop reload sound after 1 second to ensure it only plays for 1s
LK.setTimeout(function () {
if (LK.getSound('reload').stop) LK.getSound('reload').stop();
}, 1000);
outOfAmmoTxt.setText("Mermi bitti\n" + magazine + " / " + reserveBullets);
outOfAmmoTxt.visible = true;
reloadTimeout = LK.setTimeout(function () {
// Calculate how many bullets to reload
var reloadAmount = Math.min(MAG_SIZE, reserveBullets);
magazine = reloadAmount;
reserveBullets -= reloadAmount;
updateBulletIcons();
isReloading = false;
outOfAmmoTxt.visible = false;
}, reloadTime);
} else {
// No reserve, show out of ammo
outOfAmmoTxt.setText("Mermi bitti\n" + magazine + " / " + reserveBullets);
outOfAmmoTxt.visible = true;
}
}
} else {
// No bullets in magazine
if (!isReloading) {
// If reserve bullets available, start reload
if (reserveBullets > 0) {
isReloading = true;
LK.getSound('reload').play();
// Stop reload sound after 1 second to ensure it only plays for 1s
LK.setTimeout(function () {
if (LK.getSound('reload').stop) LK.getSound('reload').stop();
}, 1000);
outOfAmmoTxt.setText("Mermi bitti\n" + magazine + " / " + reserveBullets);
outOfAmmoTxt.visible = true;
reloadTimeout = LK.setTimeout(function () {
var reloadAmount = Math.min(MAG_SIZE, reserveBullets);
magazine = reloadAmount;
reserveBullets -= reloadAmount;
updateBulletIcons();
isReloading = false;
outOfAmmoTxt.visible = false;
}, reloadTime);
} else {
// No reserve, show out of ammo
outOfAmmoTxt.setText("Mermi bitti\n" + magazine + " / " + reserveBullets);
outOfAmmoTxt.visible = true;
}
}
}
}
};
// Zombie spawn timer
var zombieSpawnInterval = 90; // frames
var zombieSpawnTimer = 0;
// Helper: spawn zombie at random edge
function spawnZombie() {
var zombie = new Zombie();
// Randomize health: 15% get 3, 30% get 2, rest get 1
var r = Math.random();
if (r < 0.15) {
zombie.maxHealth = 3;
} else if (r < 0.45) {
zombie.maxHealth = 2;
} else {
zombie.maxHealth = 1;
}
zombie.health = zombie.maxHealth;
// Remove old heart icons if any
if (zombie.heartIcons && zombie.heartIcons.length > 0) {
for (var h = 0; h < zombie.heartIcons.length; h++) {
zombie.heartIcons[h].destroy && zombie.heartIcons[h].destroy();
}
zombie.heartIcons = [];
}
// Add heart icons for new health
for (var i = 0; i < zombie.maxHealth; i++) {
var heartIcon = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5,
x: (i - (zombie.maxHealth - 1) / 2) * 60,
y: -zombie.radius - 40,
scaleX: 0.7,
scaleY: 0.7
});
zombie.addChild(heartIcon);
zombie.heartIcons.push(heartIcon);
}
// Random edge: 0=top,1=bottom,2=left,3=right
var edge = Math.floor(Math.random() * 4);
var margin = 80;
if (edge === 0) {
// top
zombie.x = margin + Math.random() * (GAME_W - 2 * margin);
zombie.y = -zombie.radius;
} else if (edge === 1) {
// bottom
zombie.x = margin + Math.random() * (GAME_W - 2 * margin);
zombie.y = GAME_H + zombie.radius;
} else if (edge === 2) {
// left
zombie.x = -zombie.radius;
zombie.y = margin + Math.random() * (GAME_H - 2 * margin);
} else {
// right
zombie.x = GAME_W + zombie.radius;
zombie.y = margin + Math.random() * (GAME_H - 2 * margin);
}
zombie.setDirection(hero.x, hero.y);
zombies.push(zombie);
game.addChild(zombie);
}
// Main update loop
game.update = function () {
// Update zombies
for (var i = zombies.length - 1; i >= 0; i--) {
var z = zombies[i];
// Always update direction towards hero
z.setDirection(hero.x, hero.y);
z.update();
// Check collision with hero
var dx = z.x - hero.x;
var dy = z.y - hero.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < z.radius + hero.radius - 10) {
// Lose a heart
if (currentHearts > 0) {
currentHearts--;
// Hide a heart visually
if (hearts[currentHearts]) {
hearts[currentHearts].visible = false;
}
LK.effects.flashObject(hero, 0xff0000, 400);
// Move zombie that hit away from hero instead of destroying
// Calculate vector from hero to zombie
var awayDx = z.x - hero.x;
var awayDy = z.y - hero.y;
var awayLen = Math.sqrt(awayDx * awayDx + awayDy * awayDy);
// Move zombie 400px away from hero, but clamp inside game area
if (awayLen > 0) {
var moveDist = 400;
var newX = hero.x + awayDx / awayLen * moveDist;
var newY = hero.y + awayDy / awayLen * moveDist;
// Clamp to game area (with margin for zombie size)
var margin = z.radius + 20;
newX = Math.max(margin, Math.min(GAME_W - margin, newX));
newY = Math.max(margin, Math.min(GAME_H - margin, newY));
z.x = newX;
z.y = newY;
}
// If no hearts left, game over
if (currentHearts === 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
}
}
// Update bullets and check collision with zombies
for (var j = bullets.length - 1; j >= 0; j--) {
var b = bullets[j];
b.update && b.update();
// Remove bullet if out of bounds
if (b.x < -b.radius || b.x > GAME_W + b.radius || b.y < -b.radius || b.y > GAME_H + b.radius) {
b.destroy();
bullets.splice(j, 1);
continue;
}
// Check collision with zombies
for (var k = zombies.length - 1; k >= 0; k--) {
var z2 = zombies[k];
var dx2 = b.x - z2.x;
var dy2 = b.y - z2.y;
var dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
if (dist2 < b.radius + z2.radius - 10) {
// Zombie takes damage
if (typeof z2.takeDamage === "function") {
z2.takeDamage(1);
// If health reaches zero, destroy
if (z2.health <= 0) {
// 5% chance to drop a heart
if (Math.random() < 0.05) {
var heartDrop = new Container();
var heartGfx = heartDrop.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
heartDrop.x = z2.x;
heartDrop.y = z2.y;
heartDrop.radius = heartGfx.width * 0.6;
heartDrop.update = function () {
// Animate heart (optional: float up and down)
if (typeof this.floatDir === "undefined") this.floatDir = 1;
if (typeof this.floatOffset === "undefined") this.floatOffset = 0;
this.floatOffset += this.floatDir * 1.2;
if (this.floatOffset > 18) this.floatDir = -1;
if (this.floatOffset < -18) this.floatDir = 1;
this.y += this.floatDir * 0.7;
// Check collision with hero
var dxh = this.x - hero.x;
var dyh = this.y - hero.y;
var distH = Math.sqrt(dxh * dxh + dyh * dyh);
if (distH < hero.radius + this.radius - 10) {
// Collect heart: refill all hearts
for (var h = 0; h < hearts.length; h++) {
hearts[h].visible = true;
}
currentHearts = maxHearts;
this.destroy();
// Remove from heartDrops array
for (var hd = 0; hd < heartDrops.length; hd++) {
if (heartDrops[hd] === this) {
heartDrops.splice(hd, 1);
break;
}
}
}
};
if (typeof heartDrops === "undefined") heartDrops = [];
heartDrops.push(heartDrop);
game.addChild(heartDrop);
}
// 10% chance to drop a bullet pack
if (Math.random() < 0.10) {
// Determine bullet amount: random between 5 and 50, but not less than 5, not more than 50
var minBullets = 5;
var maxBullets = 50;
// The initial TOTAL_BULLETS is 20, but drop can be more or less
var bulletAmount = Math.floor(Math.random() * (maxBullets - minBullets + 1)) + minBullets;
// Create bullet drop container
var bulletDrop = new Container();
var bulletGfx = bulletDrop.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5 + (bulletAmount - 5) / 45,
// scale from 1.5 (5 bullets) up to ~2.5 (50 bullets)
scaleY: 1.5 + (bulletAmount - 5) / 45
});
bulletDrop.x = z2.x;
bulletDrop.y = z2.y;
bulletDrop.radius = bulletGfx.width * 0.7 * bulletGfx.scaleX; // slightly larger for easier pickup
// Show bullet amount above the bullet
var bulletAmtTxt = new Text2(bulletAmount + "", {
size: 70,
fill: 0xFFE600,
align: "center"
});
bulletAmtTxt.anchor.set(0.5, 1);
bulletAmtTxt.x = 0;
bulletAmtTxt.y = -bulletGfx.height * bulletGfx.scaleY / 2 - 10;
bulletDrop.addChild(bulletAmtTxt);
bulletDrop.update = function () {
// Animate bullet (optional: float up and down)
if (typeof this.floatDir === "undefined") this.floatDir = 1;
if (typeof this.floatOffset === "undefined") this.floatOffset = 0;
this.floatOffset += this.floatDir * 1.2;
if (this.floatOffset > 18) this.floatDir = -1;
if (this.floatOffset < -18) this.floatDir = 1;
this.y += this.floatDir * 0.7;
// Check collision with hero
var dxh = this.x - hero.x;
var dyh = this.y - hero.y;
var distH = Math.sqrt(dxh * dxh + dyh * dyh);
if (distH < hero.radius + this.radius - 10) {
// Collect bullet: add to reserveBullets, but never above 999
reserveBullets += bulletAmount;
if (reserveBullets > 999) reserveBullets = 999;
updateBulletIcons();
this.destroy();
// Remove from bulletDrops array
for (var bd = 0; bd < bulletDrops.length; bd++) {
if (bulletDrops[bd] === this) {
bulletDrops.splice(bd, 1);
break;
}
}
}
};
if (typeof bulletDrops === "undefined") bulletDrops = [];
bulletDrops.push(bulletDrop);
game.addChild(bulletDrop);
}
z2.destroy();
zombies.splice(k, 1);
// Score up
score += 1;
scoreTxt.setText(score);
}
} else {
// fallback: destroy if no health system
z2.destroy();
zombies.splice(k, 1);
score += 1;
scoreTxt.setText(score);
}
b.destroy();
bullets.splice(j, 1);
break;
}
}
}
// Animate and check collision for heart drops
if (typeof heartDrops !== "undefined" && heartDrops.length > 0) {
for (var hd = heartDrops.length - 1; hd >= 0; hd--) {
var hdrop = heartDrops[hd];
if (hdrop && typeof hdrop.update === "function") hdrop.update();
}
}
// Animate and check collision for bullet drops
if (typeof bulletDrops !== "undefined" && bulletDrops.length > 0) {
for (var bd = bulletDrops.length - 1; bd >= 0; bd--) {
var bdrop = bulletDrops[bd];
if (bdrop && typeof bdrop.update === "function") bdrop.update();
}
}
// Spawn zombies
zombieSpawnTimer++;
if (zombieSpawnTimer >= zombieSpawnInterval) {
// Spawn more zombies as time goes on
// Calculate how many zombies to spawn: start at 1, increase by 1 every 10 kills, max 6
var zombiesToSpawn = 1 + Math.floor(score / 10);
if (zombiesToSpawn > 6) zombiesToSpawn = 6;
for (var s = 0; s < zombiesToSpawn; s++) {
spawnZombie();
}
zombieSpawnTimer = 0;
// Gradually increase spawn rate (lower interval)
if (zombieSpawnInterval > 30) zombieSpawnInterval -= 1;
}
// No random bullet spawn at corners
};
// Center hero on start
hero.x = GAME_W / 2;
hero.y = GAME_H / 2;
// Reset şarjör and reserve on game start
magazine = MAG_SIZE;
reserveBullets = TOTAL_BULLETS - MAG_SIZE;
isReloading = false;
if (reloadTimeout) {
LK.clearTimeout(reloadTimeout);
reloadTimeout = null;
}
updateBulletIcons();
outOfAmmoTxt.visible = false;
// Initial zombie spawn
for (var i = 0; i < 3; i++) {
spawnZombie();
} /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGfx = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = bulletGfx.width / 2;
self.speed = 32; // Fast bullet
self.vx = 0;
self.vy = 0;
// Set direction
self.setDirection = function (dx, dy) {
var len = Math.sqrt(dx * dx + dy * dy);
if (len > 0) {
self.vx = dx / len * self.speed;
self.vy = dy / len * self.speed;
}
};
self.update = function () {
// Move bullet
self.x += self.vx;
self.y += self.vy;
};
return self;
});
// Hero class
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGfx = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
// Add a gun to hero's hand
// Use the new blue gun asset, positioned to the right hand
var gunGfx = self.attachAsset('bluegun', {
anchorX: 0.2,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 0.6,
x: heroGfx.width * 0.38,
// offset to right hand
y: 0
});
// Track gun rotation
self.gunGfx = gunGfx;
self.gunAngle = 0;
// For future upgrades: health, weapon, etc.
self.radius = heroGfx.width / 2;
return self;
});
// Zombie class
var Zombie = Container.expand(function () {
var self = Container.call(this);
var zombieGfx = self.attachAsset('zombie', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = zombieGfx.width / 2;
// Speed will be set on spawn
// Make zombies move at half the speed of the hero
var heroBaseSpeed = 6; // Set hero base speed (if not defined elsewhere)
self.speed = heroBaseSpeed * 0.5 + Math.random() * (heroBaseSpeed * 0.1); // 50% slower, small random
// Direction vector
self.vx = 0;
self.vy = 0;
// Health for zombie: 1 heart
self.maxHealth = 1;
self.health = self.maxHealth;
// Heart icon(s) above zombie
self.heartIcons = [];
for (var i = 0; i < self.maxHealth; i++) {
var heartIcon = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5,
x: (i - (self.maxHealth - 1) / 2) * 60,
// center hearts
y: -self.radius - 40,
scaleX: 0.7,
scaleY: 0.7
});
self.addChild(heartIcon);
self.heartIcons.push(heartIcon);
}
// Set direction towards hero
self.setDirection = function (targetX, targetY) {
var dx = targetX - self.x;
var dy = targetY - self.y;
var len = Math.sqrt(dx * dx + dy * dy);
if (len > 0) {
self.vx = dx / len * self.speed;
self.vy = dy / len * self.speed;
}
};
// Move towards direction
self.update = function () {
self.x += self.vx;
self.y += self.vy;
// Keep health text above zombie
if (self.healthTxt) {
self.healthTxt.x = 0;
self.healthTxt.y = -self.radius - 10;
}
};
// Method to take damage
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health < 0) self.health = 0;
// Update heart icons
for (var i = 0; i < self.heartIcons.length; i++) {
self.heartIcons[i].visible = i < self.health;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Sound for shooting
// Bullet asset: yellow box
// Zombie asset: green ellipse
// Hero asset: red box
// Game area
// New blue gun asset
var GAME_W = 2048;
var GAME_H = 2732;
// Hero base speed for zombie speed calculation
var heroBaseSpeed = 6;
// Hero setup
var hero = new Hero();
hero.x = GAME_W / 2;
hero.y = GAME_H / 2;
game.addChild(hero);
// Bullets and zombies arrays
var bullets = [];
var zombies = [];
// --- Şarjör/Magazine System ---
var MAG_SIZE = 7; // şarjör kapasitesi
var TOTAL_BULLETS = 20; // toplam yedek mermi
var magazine = MAG_SIZE; // şarjördeki mermi
var reserveBullets = TOTAL_BULLETS - MAG_SIZE; // yedek mermi
var isReloading = false;
var reloadTime = 3000; // ms
var reloadTimeout = null;
// --- Bullet Type System (auto change every 2 seconds) ---
var bulletTypes = [{
id: 'bullet',
speed: 32
},
// default
{
id: 'bullet',
speed: 48
},
// fast
{
id: 'bullet',
speed: 16
} // slow
];
var currentBulletTypeIndex = 0;
var bulletTypeChangeInterval = null;
// Start auto bullet type change
function startBulletTypeAutoChange() {
if (bulletTypeChangeInterval) LK.clearInterval(bulletTypeChangeInterval);
bulletTypeChangeInterval = LK.setInterval(function () {
currentBulletTypeIndex = (currentBulletTypeIndex + 1) % bulletTypes.length;
}, 2000);
}
startBulletTypeAutoChange();
// Mermi UI - Text-based bullet count at the bottom left
var bulletTxt = new Text2(magazine + " / " + reserveBullets, {
size: 90,
fill: "#fff"
});
// Anchor to left-bottom
bulletTxt.anchor.set(0, 1);
bulletTxt.x = 60;
bulletTxt.y = 2732 - 40;
LK.gui.bottomLeft.addChild(bulletTxt);
function updateBulletIcons() {
bulletTxt.setText(magazine + " / " + reserveBullets);
if (typeof outOfAmmoTxt !== "undefined" && outOfAmmoTxt && outOfAmmoTxt.visible) {
outOfAmmoTxt.setText("Mermi bitti\n" + magazine + " / " + reserveBullets);
}
}
updateBulletIcons();
// "Mermi bitti" UI
var outOfAmmoTxt = new Text2("Mermi bitti\n" + magazine + " / " + reserveBullets, {
size: 260,
fill: "#fff",
align: "center"
});
// Bottom center: anchor to center-bottom, x=center, y=height
outOfAmmoTxt.anchor.set(0.5, 1);
outOfAmmoTxt.x = 2048 / 2;
outOfAmmoTxt.y = 2732 - 40;
outOfAmmoTxt.visible = false;
LK.gui.bottom.addChild(outOfAmmoTxt);
// Score
var score = 0;
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Hearts (health)
var maxHearts = 5;
var hearts = [];
for (var i = 0; i < maxHearts; i++) {
var heart = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5,
x: 160 + i * 120,
y: 80,
scaleX: 1.1,
scaleY: 1.1
});
LK.gui.top.addChild(heart);
hearts.push(heart);
}
var currentHearts = maxHearts;
// Dragging
var dragNode = null;
// Touch/move controls
function handleMove(x, y, obj) {
// Drag hero
if (dragNode === hero) {
// Clamp hero inside game area, avoid top left 100x100
var minX = hero.radius + 100;
var maxX = GAME_W - hero.radius;
var minY = hero.radius;
var maxY = GAME_H - hero.radius;
hero.x = Math.max(minX, Math.min(maxX, x));
hero.y = Math.max(minY, Math.min(maxY, y));
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only drag if touch is on hero
var dx = x - hero.x;
var dy = y - hero.y;
if (dx * dx + dy * dy <= hero.radius * hero.radius) {
dragNode = hero;
handleMove(x, y, obj);
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Shooting: tap anywhere not on hero to shoot
game.tap = function (x, y, obj) {
// Don't shoot if tap is on hero
var dx = x - hero.x;
var dy = y - hero.y;
if (dx * dx + dy * dy <= hero.radius * hero.radius) return;
// Create bullet
var bullet = new Bullet();
bullet.x = hero.x;
bullet.y = hero.y;
// Set bullet speed/type
var bulletType = bulletTypes[currentBulletTypeIndex];
bullet.speed = bulletType.speed;
bullet.setDirection(dx, dy);
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
// Rotate gun towards shot direction
if (typeof hero.gunGfx !== "undefined") {
hero.gunGfx.rotation = Math.atan2(dy, dx);
}
};
game.down = function (x, y, obj) {
// Drag or shoot
var dx = x - hero.x;
var dy = y - hero.y;
if (dx * dx + dy * dy <= hero.radius * hero.radius) {
dragNode = hero;
handleMove(x, y, obj);
} else {
// --- Şarjör/Magazine Logic ---
if (isReloading) {
// Reloading, can't shoot
return;
}
if (magazine > 0) {
// Shoot
var bullet = new Bullet();
bullet.x = hero.x;
bullet.y = hero.y;
// Set bullet speed/type
var bulletType = bulletTypes[currentBulletTypeIndex];
bullet.speed = bulletType.speed;
bullet.setDirection(dx, dy);
bullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
// Rotate gun towards shot direction
if (typeof hero.gunGfx !== "undefined") {
hero.gunGfx.rotation = Math.atan2(dy, dx);
}
magazine--;
updateBulletIcons();
outOfAmmoTxt.visible = false;
// If şarjör bitti, start reload if possible
if (magazine === 0) {
if (reserveBullets > 0) {
isReloading = true;
LK.getSound('reload').play();
// Stop reload sound after 1 second to ensure it only plays for 1s
LK.setTimeout(function () {
if (LK.getSound('reload').stop) LK.getSound('reload').stop();
}, 1000);
outOfAmmoTxt.setText("Mermi bitti\n" + magazine + " / " + reserveBullets);
outOfAmmoTxt.visible = true;
reloadTimeout = LK.setTimeout(function () {
// Calculate how many bullets to reload
var reloadAmount = Math.min(MAG_SIZE, reserveBullets);
magazine = reloadAmount;
reserveBullets -= reloadAmount;
updateBulletIcons();
isReloading = false;
outOfAmmoTxt.visible = false;
}, reloadTime);
} else {
// No reserve, show out of ammo
outOfAmmoTxt.setText("Mermi bitti\n" + magazine + " / " + reserveBullets);
outOfAmmoTxt.visible = true;
}
}
} else {
// No bullets in magazine
if (!isReloading) {
// If reserve bullets available, start reload
if (reserveBullets > 0) {
isReloading = true;
LK.getSound('reload').play();
// Stop reload sound after 1 second to ensure it only plays for 1s
LK.setTimeout(function () {
if (LK.getSound('reload').stop) LK.getSound('reload').stop();
}, 1000);
outOfAmmoTxt.setText("Mermi bitti\n" + magazine + " / " + reserveBullets);
outOfAmmoTxt.visible = true;
reloadTimeout = LK.setTimeout(function () {
var reloadAmount = Math.min(MAG_SIZE, reserveBullets);
magazine = reloadAmount;
reserveBullets -= reloadAmount;
updateBulletIcons();
isReloading = false;
outOfAmmoTxt.visible = false;
}, reloadTime);
} else {
// No reserve, show out of ammo
outOfAmmoTxt.setText("Mermi bitti\n" + magazine + " / " + reserveBullets);
outOfAmmoTxt.visible = true;
}
}
}
}
};
// Zombie spawn timer
var zombieSpawnInterval = 90; // frames
var zombieSpawnTimer = 0;
// Helper: spawn zombie at random edge
function spawnZombie() {
var zombie = new Zombie();
// Randomize health: 15% get 3, 30% get 2, rest get 1
var r = Math.random();
if (r < 0.15) {
zombie.maxHealth = 3;
} else if (r < 0.45) {
zombie.maxHealth = 2;
} else {
zombie.maxHealth = 1;
}
zombie.health = zombie.maxHealth;
// Remove old heart icons if any
if (zombie.heartIcons && zombie.heartIcons.length > 0) {
for (var h = 0; h < zombie.heartIcons.length; h++) {
zombie.heartIcons[h].destroy && zombie.heartIcons[h].destroy();
}
zombie.heartIcons = [];
}
// Add heart icons for new health
for (var i = 0; i < zombie.maxHealth; i++) {
var heartIcon = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5,
x: (i - (zombie.maxHealth - 1) / 2) * 60,
y: -zombie.radius - 40,
scaleX: 0.7,
scaleY: 0.7
});
zombie.addChild(heartIcon);
zombie.heartIcons.push(heartIcon);
}
// Random edge: 0=top,1=bottom,2=left,3=right
var edge = Math.floor(Math.random() * 4);
var margin = 80;
if (edge === 0) {
// top
zombie.x = margin + Math.random() * (GAME_W - 2 * margin);
zombie.y = -zombie.radius;
} else if (edge === 1) {
// bottom
zombie.x = margin + Math.random() * (GAME_W - 2 * margin);
zombie.y = GAME_H + zombie.radius;
} else if (edge === 2) {
// left
zombie.x = -zombie.radius;
zombie.y = margin + Math.random() * (GAME_H - 2 * margin);
} else {
// right
zombie.x = GAME_W + zombie.radius;
zombie.y = margin + Math.random() * (GAME_H - 2 * margin);
}
zombie.setDirection(hero.x, hero.y);
zombies.push(zombie);
game.addChild(zombie);
}
// Main update loop
game.update = function () {
// Update zombies
for (var i = zombies.length - 1; i >= 0; i--) {
var z = zombies[i];
// Always update direction towards hero
z.setDirection(hero.x, hero.y);
z.update();
// Check collision with hero
var dx = z.x - hero.x;
var dy = z.y - hero.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < z.radius + hero.radius - 10) {
// Lose a heart
if (currentHearts > 0) {
currentHearts--;
// Hide a heart visually
if (hearts[currentHearts]) {
hearts[currentHearts].visible = false;
}
LK.effects.flashObject(hero, 0xff0000, 400);
// Move zombie that hit away from hero instead of destroying
// Calculate vector from hero to zombie
var awayDx = z.x - hero.x;
var awayDy = z.y - hero.y;
var awayLen = Math.sqrt(awayDx * awayDx + awayDy * awayDy);
// Move zombie 400px away from hero, but clamp inside game area
if (awayLen > 0) {
var moveDist = 400;
var newX = hero.x + awayDx / awayLen * moveDist;
var newY = hero.y + awayDy / awayLen * moveDist;
// Clamp to game area (with margin for zombie size)
var margin = z.radius + 20;
newX = Math.max(margin, Math.min(GAME_W - margin, newX));
newY = Math.max(margin, Math.min(GAME_H - margin, newY));
z.x = newX;
z.y = newY;
}
// If no hearts left, game over
if (currentHearts === 0) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
}
}
// Update bullets and check collision with zombies
for (var j = bullets.length - 1; j >= 0; j--) {
var b = bullets[j];
b.update && b.update();
// Remove bullet if out of bounds
if (b.x < -b.radius || b.x > GAME_W + b.radius || b.y < -b.radius || b.y > GAME_H + b.radius) {
b.destroy();
bullets.splice(j, 1);
continue;
}
// Check collision with zombies
for (var k = zombies.length - 1; k >= 0; k--) {
var z2 = zombies[k];
var dx2 = b.x - z2.x;
var dy2 = b.y - z2.y;
var dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
if (dist2 < b.radius + z2.radius - 10) {
// Zombie takes damage
if (typeof z2.takeDamage === "function") {
z2.takeDamage(1);
// If health reaches zero, destroy
if (z2.health <= 0) {
// 5% chance to drop a heart
if (Math.random() < 0.05) {
var heartDrop = new Container();
var heartGfx = heartDrop.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
heartDrop.x = z2.x;
heartDrop.y = z2.y;
heartDrop.radius = heartGfx.width * 0.6;
heartDrop.update = function () {
// Animate heart (optional: float up and down)
if (typeof this.floatDir === "undefined") this.floatDir = 1;
if (typeof this.floatOffset === "undefined") this.floatOffset = 0;
this.floatOffset += this.floatDir * 1.2;
if (this.floatOffset > 18) this.floatDir = -1;
if (this.floatOffset < -18) this.floatDir = 1;
this.y += this.floatDir * 0.7;
// Check collision with hero
var dxh = this.x - hero.x;
var dyh = this.y - hero.y;
var distH = Math.sqrt(dxh * dxh + dyh * dyh);
if (distH < hero.radius + this.radius - 10) {
// Collect heart: refill all hearts
for (var h = 0; h < hearts.length; h++) {
hearts[h].visible = true;
}
currentHearts = maxHearts;
this.destroy();
// Remove from heartDrops array
for (var hd = 0; hd < heartDrops.length; hd++) {
if (heartDrops[hd] === this) {
heartDrops.splice(hd, 1);
break;
}
}
}
};
if (typeof heartDrops === "undefined") heartDrops = [];
heartDrops.push(heartDrop);
game.addChild(heartDrop);
}
// 10% chance to drop a bullet pack
if (Math.random() < 0.10) {
// Determine bullet amount: random between 5 and 50, but not less than 5, not more than 50
var minBullets = 5;
var maxBullets = 50;
// The initial TOTAL_BULLETS is 20, but drop can be more or less
var bulletAmount = Math.floor(Math.random() * (maxBullets - minBullets + 1)) + minBullets;
// Create bullet drop container
var bulletDrop = new Container();
var bulletGfx = bulletDrop.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5 + (bulletAmount - 5) / 45,
// scale from 1.5 (5 bullets) up to ~2.5 (50 bullets)
scaleY: 1.5 + (bulletAmount - 5) / 45
});
bulletDrop.x = z2.x;
bulletDrop.y = z2.y;
bulletDrop.radius = bulletGfx.width * 0.7 * bulletGfx.scaleX; // slightly larger for easier pickup
// Show bullet amount above the bullet
var bulletAmtTxt = new Text2(bulletAmount + "", {
size: 70,
fill: 0xFFE600,
align: "center"
});
bulletAmtTxt.anchor.set(0.5, 1);
bulletAmtTxt.x = 0;
bulletAmtTxt.y = -bulletGfx.height * bulletGfx.scaleY / 2 - 10;
bulletDrop.addChild(bulletAmtTxt);
bulletDrop.update = function () {
// Animate bullet (optional: float up and down)
if (typeof this.floatDir === "undefined") this.floatDir = 1;
if (typeof this.floatOffset === "undefined") this.floatOffset = 0;
this.floatOffset += this.floatDir * 1.2;
if (this.floatOffset > 18) this.floatDir = -1;
if (this.floatOffset < -18) this.floatDir = 1;
this.y += this.floatDir * 0.7;
// Check collision with hero
var dxh = this.x - hero.x;
var dyh = this.y - hero.y;
var distH = Math.sqrt(dxh * dxh + dyh * dyh);
if (distH < hero.radius + this.radius - 10) {
// Collect bullet: add to reserveBullets, but never above 999
reserveBullets += bulletAmount;
if (reserveBullets > 999) reserveBullets = 999;
updateBulletIcons();
this.destroy();
// Remove from bulletDrops array
for (var bd = 0; bd < bulletDrops.length; bd++) {
if (bulletDrops[bd] === this) {
bulletDrops.splice(bd, 1);
break;
}
}
}
};
if (typeof bulletDrops === "undefined") bulletDrops = [];
bulletDrops.push(bulletDrop);
game.addChild(bulletDrop);
}
z2.destroy();
zombies.splice(k, 1);
// Score up
score += 1;
scoreTxt.setText(score);
}
} else {
// fallback: destroy if no health system
z2.destroy();
zombies.splice(k, 1);
score += 1;
scoreTxt.setText(score);
}
b.destroy();
bullets.splice(j, 1);
break;
}
}
}
// Animate and check collision for heart drops
if (typeof heartDrops !== "undefined" && heartDrops.length > 0) {
for (var hd = heartDrops.length - 1; hd >= 0; hd--) {
var hdrop = heartDrops[hd];
if (hdrop && typeof hdrop.update === "function") hdrop.update();
}
}
// Animate and check collision for bullet drops
if (typeof bulletDrops !== "undefined" && bulletDrops.length > 0) {
for (var bd = bulletDrops.length - 1; bd >= 0; bd--) {
var bdrop = bulletDrops[bd];
if (bdrop && typeof bdrop.update === "function") bdrop.update();
}
}
// Spawn zombies
zombieSpawnTimer++;
if (zombieSpawnTimer >= zombieSpawnInterval) {
// Spawn more zombies as time goes on
// Calculate how many zombies to spawn: start at 1, increase by 1 every 10 kills, max 6
var zombiesToSpawn = 1 + Math.floor(score / 10);
if (zombiesToSpawn > 6) zombiesToSpawn = 6;
for (var s = 0; s < zombiesToSpawn; s++) {
spawnZombie();
}
zombieSpawnTimer = 0;
// Gradually increase spawn rate (lower interval)
if (zombieSpawnInterval > 30) zombieSpawnInterval -= 1;
}
// No random bullet spawn at corners
};
// Center hero on start
hero.x = GAME_W / 2;
hero.y = GAME_H / 2;
// Reset şarjör and reserve on game start
magazine = MAG_SIZE;
reserveBullets = TOTAL_BULLETS - MAG_SIZE;
isReloading = false;
if (reloadTimeout) {
LK.clearTimeout(reloadTimeout);
reloadTimeout = null;
}
updateBulletIcons();
outOfAmmoTxt.visible = false;
// Initial zombie spawn
for (var i = 0; i < 3; i++) {
spawnZombie();
}
mermi. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
oyuncu,karekter. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
silah. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
zombi. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat