Code edit (1 edits merged)
Please save this source code
User prompt
add shooter mechanichs to the hero. add some obstacles. refuel the bullet time everytime hero kills an enemy
Code edit (1 edits merged)
Please save this source code
User prompt
Bullet Time Hero
Initial prompt
make a game exactly like max payne
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Boss = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bossEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.health = 10;
self.maxHealth = 10;
self.shootTimer = 0;
self.shootInterval = 60; // 1 second at 60fps
self.isBoss = true;
self.update = function () {
// Move toward player
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var moveX = dx / distance * self.speed * enemySpeedMultiplier * timeScale;
var moveY = dy / distance * self.speed * enemySpeedMultiplier * timeScale;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Check collision with obstacles
var canMove = true;
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (newX + 75 > obstacle.x - 60 && newX - 75 < obstacle.x + 60 && newY + 75 > obstacle.y - 60 && newY - 75 < obstacle.y + 60) {
canMove = false;
break;
}
}
if (canMove) {
self.x = newX;
self.y = newY;
}
}
// Shoot at player more frequently
self.shootTimer += timeScale;
if (self.shootTimer >= self.shootInterval) {
self.shoot();
self.shootTimer = 0;
}
};
self.shoot = function () {
// Boss shoots 3 bullets in spread pattern
for (var i = -1; i <= 1; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x + i * 30;
bullet.y = self.y;
// Calculate base direction towards hero
var dx = hero.x - bullet.x;
var dy = hero.y - bullet.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var baseAngle = Math.atan2(dy, dx);
var spreadAngle = baseAngle + i * 0.3; // 0.3 radians spread
bullet.directionX = Math.cos(spreadAngle);
bullet.directionY = Math.sin(spreadAngle);
} else {
bullet.directionX = 0;
bullet.directionY = 1;
}
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
LK.effects.flashObject(self, 0xFFFFFF, 500);
LK.getSound('enemyHit').play();
return true; // Boss destroyed
}
// Flash red when taking damage
LK.effects.flashObject(self, 0xFF0000, 200);
return false;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.health = 1;
self.shootTimer = 0;
self.shootInterval = 120; // 2 seconds at 60fps
self.update = function () {
// Move toward player
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var moveX = dx / distance * self.speed * enemySpeedMultiplier * timeScale;
var moveY = dy / distance * self.speed * enemySpeedMultiplier * timeScale;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Check collision with obstacles
var canMove = true;
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (newX + 30 > obstacle.x - 60 && newX - 30 < obstacle.x + 60 && newY + 30 > obstacle.y - 60 && newY - 30 < obstacle.y + 60) {
canMove = false;
break;
}
}
if (canMove) {
self.x = newX;
self.y = newY;
}
}
// Shoot at player
self.shootTimer += timeScale;
if (self.shootTimer >= self.shootInterval) {
self.shoot();
self.shootTimer = 0;
}
};
self.shoot = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
// Calculate direction towards hero
var dx = hero.x - bullet.x;
var dy = hero.y - bullet.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
bullet.directionX = dx / distance;
bullet.directionY = dy / distance;
} else {
bullet.directionX = 0;
bullet.directionY = 1;
}
enemyBullets.push(bullet);
game.addChild(bullet);
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
LK.effects.flashObject(self, 0xFFFFFF, 200);
LK.getSound('enemyHit').play();
return true; // Enemy destroyed
}
return false;
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.damage = 1;
self.directionX = 0;
self.directionY = 1;
self.update = function () {
self.x += self.directionX * self.speed * timeScale;
self.y += self.directionY * self.speed * timeScale;
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 100;
self.health = self.maxHealth;
self.shootTimer = 0;
self.shootInterval = 45; // Slower shooting
self.update = function () {
// Always shoot when enemies exist
if (enemies.length > 0) {
self.shootTimer += timeScale;
if (self.shootTimer >= self.shootInterval) {
self.shoot();
self.shootTimer = 0;
}
}
};
self.shoot = function () {
var bullet;
if (rpgAmmo > 0) {
bullet = new RPGBullet();
rpgAmmo--;
updateRPGDisplay();
} else {
bullet = new HeroBullet();
}
bullet.x = self.x;
bullet.y = self.y - 40;
// Find nearest enemy to aim at
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
// Set bullet direction towards nearest enemy
if (nearestEnemy) {
var dx = nearestEnemy.x - bullet.x;
var dy = nearestEnemy.y - bullet.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
bullet.directionX = dx / distance;
bullet.directionY = dy / distance;
} else {
bullet.directionX = 0;
bullet.directionY = -1;
}
} else {
bullet.directionX = 0;
bullet.directionY = -1;
}
heroBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 500);
LK.getSound('playerHit').play();
// Use extra health if health drops to 20 or below and we have uses available
if (self.health <= 20 && extraHealthUses > 0) {
self.health += 50;
if (self.health > self.maxHealth) {
self.health = self.maxHealth;
}
extraHealthUses--;
updateExtraHealthDisplay();
LK.effects.flashObject(self, 0x00FF00, 800); // Green flash for healing
}
updateHealthBar();
if (self.health <= 0) {
LK.showGameOver();
}
};
return self;
});
var HeroBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('heroBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.damage = 1;
self.directionX = 0;
self.directionY = -1;
self.update = function () {
self.x += self.directionX * self.speed * timeScale;
self.y += self.directionY * self.speed * timeScale;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var RPGBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('heroBullet', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xFF0000; // Red color for RPG
graphics.scaleX = 2;
graphics.scaleY = 2;
self.speed = 8;
self.damage = 999; // One shot kill
self.directionX = 0;
self.directionY = -1;
self.update = function () {
self.x += self.directionX * self.speed * timeScale;
self.y += self.directionY * self.speed * timeScale;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Game variables
var enemies = [];
var enemyBullets = [];
var heroBullets = [];
var obstacles = [];
var timeScale = 1.0;
var isBulletTimeActive = false;
var bulletTimeEnergy = 100;
var maxBulletTimeEnergy = 100;
var bulletTimeDecayRate = 0.5;
var bulletTimeRechargeRate = 0.1;
var bulletTimeSlowFactor = 0.2;
var dragNode = null;
var enemySpawnTimer = 0;
var enemySpawnInterval = 180; // 3 seconds
var waveNumber = 1;
var enemiesPerWave = 3;
var extraHealthUses = 3;
var maxExtraHealthUses = 3;
var enemiesKilled = 0;
var bossActive = false;
var lastScoreCheck = 0;
var enemySpeedMultiplier = 1.0;
var bossesKilled = 0;
var rpgAmmo = 0;
// UI elements
var scoreTxt = new Text2('0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 50;
var healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
var healthBar = LK.getAsset('healthBar', {
anchorX: 0,
anchorY: 0
});
var bulletTimeBarBg = LK.getAsset('bulletTimeBarBg', {
anchorX: 0,
anchorY: 0
});
var bulletTimeBar = LK.getAsset('bulletTimeBar', {
anchorX: 0,
anchorY: 0
});
LK.gui.topLeft.addChild(healthBarBg);
LK.gui.topLeft.addChild(healthBar);
LK.gui.topLeft.addChild(bulletTimeBarBg);
LK.gui.topLeft.addChild(bulletTimeBar);
healthBarBg.x = 120;
healthBarBg.y = 20;
healthBar.x = 122;
healthBar.y = 22;
bulletTimeBarBg.x = 120;
bulletTimeBarBg.y = 60;
bulletTimeBar.x = 122;
bulletTimeBar.y = 62;
// Add extra health display text first
var extraHealthText = new Text2('Extra Health: 3', {
size: 40,
fill: 0x00FF00
});
extraHealthText.anchor.set(0, 0);
LK.gui.topLeft.addChild(extraHealthText);
extraHealthText.x = 120;
extraHealthText.y = 100;
// Add extra health icons after text on the right side
var extraHealthIcons = [];
for (var i = 0; i < maxExtraHealthUses; i++) {
var icon = LK.getAsset('extraHealthIcon', {
anchorX: 0.5,
anchorY: 0.5
});
LK.gui.topLeft.addChild(icon);
icon.x = 380 + i * 40;
icon.y = 115;
extraHealthIcons.push(icon);
}
// Add RPG ammo display
var rpgText = new Text2('RPG: 0', {
size: 40,
fill: 0xFF0000
});
rpgText.anchor.set(0, 0);
LK.gui.topLeft.addChild(rpgText);
rpgText.x = 120;
rpgText.y = 140;
// Add city background
var cityBg = LK.getAsset('cityBackground', {
anchorX: 0,
anchorY: 0
});
game.addChild(cityBg);
// Initialize hero
hero = game.addChild(new Hero());
hero.x = 1024;
hero.y = 2200;
// Create obstacles
for (var i = 0; i < 6; i++) {
var obstacle = new Obstacle();
obstacle.x = 400 + i % 3 * 600;
obstacle.y = 800 + Math.floor(i / 3) * 600;
obstacles.push(obstacle);
game.addChild(obstacle);
}
// Update score display
function updateScore() {
scoreTxt.setText(LK.getScore());
}
// Update health bar
function updateHealthBar() {
var healthPercent = hero.health / hero.maxHealth;
healthBar.width = 400 * healthPercent;
}
// Update bullet time bar
function updateBulletTimeBar() {
var energyPercent = bulletTimeEnergy / maxBulletTimeEnergy;
bulletTimeBar.width = 300 * energyPercent;
}
// Update extra health display
function updateExtraHealthDisplay() {
extraHealthText.setText('Extra Health: ' + extraHealthUses);
for (var i = 0; i < extraHealthIcons.length; i++) {
extraHealthIcons[i].alpha = i < extraHealthUses ? 1.0 : 0.3;
}
}
// Update RPG display
function updateRPGDisplay() {
rpgText.setText('RPG: ' + rpgAmmo);
}
// Spawn enemy
function spawnEnemy() {
var enemy = new Enemy();
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
enemy.x = Math.random() * 2048;
enemy.y = -50;
break;
case 1:
// Right
enemy.x = 2098;
enemy.y = Math.random() * 1000 + 100;
break;
case 2:
// Bottom
enemy.x = Math.random() * 2048;
enemy.y = -50;
break;
case 3:
// Left
enemy.x = -50;
enemy.y = Math.random() * 1000 + 100;
break;
}
// Scale enemy stats with wave number
enemy.speed = 2 + waveNumber * 0.3;
enemy.shootInterval = Math.max(60, 120 - waveNumber * 5);
enemies.push(enemy);
game.addChild(enemy);
}
// Spawn boss enemy
function spawnBoss() {
var boss = new Boss();
boss.x = 1024; // Center horizontally
boss.y = 200; // Top of screen
enemies.push(boss);
game.addChild(boss);
bossActive = true;
}
// Spawn additional enemies based on score
function spawnScoreBasedEnemies() {
for (var i = 0; i < 2; i++) {
spawnEnemy();
}
}
// Create explosion effect
function createExplosion(x, y, isBigExplosion) {
var explosion = LK.getAsset('heroBullet', {
anchorX: 0.5,
anchorY: 0.5
});
explosion.x = x;
explosion.y = y;
explosion.tint = isBigExplosion ? 0xFFFF00 : 0xFF4400; // Yellow for big explosions, orange for normal
explosion.scaleX = 0.1;
explosion.scaleY = 0.1;
game.addChild(explosion);
// Animate explosion - scale up and fade out
var targetScale = isBigExplosion ? 5 : 3;
var duration = isBigExplosion ? 500 : 300;
tween(explosion, {
scaleX: targetScale,
scaleY: targetScale,
alpha: 0
}, {
duration: duration,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
}
// Increase enemy speed every 300 points
function checkEnemySpeedIncrease(currentScore) {
var speedLevel = Math.floor(currentScore / 300);
var newSpeedMultiplier = 1.0 + speedLevel * 0.5;
if (newSpeedMultiplier > enemySpeedMultiplier) {
enemySpeedMultiplier = newSpeedMultiplier;
}
}
// Handle bullet time activation
function activateBulletTime() {
if (bulletTimeEnergy > 0) {
isBulletTimeActive = true;
timeScale = bulletTimeSlowFactor;
}
}
// Handle bullet time deactivation
function deactivateBulletTime() {
isBulletTimeActive = false;
timeScale = 1.0;
}
// Event handlers
function handleMove(x, y, obj) {
if (dragNode) {
var newX = x;
var newY = y;
// Keep hero within bounds
newX = Math.max(40, Math.min(2008, newX));
newY = Math.max(40, Math.min(2692, newY));
// Check collision with obstacles
var canMove = true;
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
var tempHero = {
x: newX,
y: newY,
width: 80,
height: 80
};
if (newX + 40 > obstacle.x - 60 && newX - 40 < obstacle.x + 60 && newY + 40 > obstacle.y - 60 && newY - 40 < obstacle.y + 60) {
canMove = false;
break;
}
}
if (canMove) {
dragNode.x = newX;
dragNode.y = newY;
}
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
dragNode = hero;
activateBulletTime();
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
deactivateBulletTime();
};
// Main game update loop
game.update = function () {
// Update bullet time energy
if (isBulletTimeActive) {
bulletTimeEnergy -= bulletTimeDecayRate;
if (bulletTimeEnergy <= 0) {
bulletTimeEnergy = 0;
deactivateBulletTime();
}
} else {
bulletTimeEnergy += bulletTimeRechargeRate;
if (bulletTimeEnergy > maxBulletTimeEnergy) {
bulletTimeEnergy = maxBulletTimeEnergy;
}
}
updateBulletTimeBar();
// Check for score-based enemy spawning every 200 points
var currentScore = LK.getScore();
if (currentScore >= lastScoreCheck + 200) {
spawnScoreBasedEnemies();
lastScoreCheck = Math.floor(currentScore / 200) * 200;
}
// Check for enemy speed increase every 300 points
checkEnemySpeedIncrease(currentScore);
// Spawn enemies (but not when boss is active)
if (!bossActive) {
enemySpawnTimer += timeScale;
if (enemySpawnTimer >= enemySpawnInterval) {
if (enemies.length < enemiesPerWave) {
spawnEnemy();
}
enemySpawnTimer = 0;
// Start new wave if no enemies left
if (enemies.length === 0) {
waveNumber++;
enemiesPerWave = Math.min(8, 3 + Math.floor(waveNumber / 2));
enemySpawnInterval = Math.max(60, 180 - waveNumber * 10);
}
}
}
// Update hero bullets
for (var i = heroBullets.length - 1; i >= 0; i--) {
var bullet = heroBullets[i];
if (bullet.lastY === undefined) {
bullet.lastY = bullet.y;
}
// Remove bullets that go off screen
if (bullet.lastY >= -20 && bullet.y < -20) {
bullet.destroy();
heroBullets.splice(i, 1);
continue;
}
// Check collision with enemy bullets first
var hitEnemyBullet = false;
for (var k = enemyBullets.length - 1; k >= 0; k--) {
var enemyBullet = enemyBullets[k];
if (bullet.intersects(enemyBullet)) {
// Create big explosion at collision point
createExplosion((bullet.x + enemyBullet.x) / 2, (bullet.y + enemyBullet.y) / 2, true);
// Destroy both bullets
bullet.destroy();
enemyBullet.destroy();
heroBullets.splice(i, 1);
enemyBullets.splice(k, 1);
hitEnemyBullet = true;
break;
}
}
if (hitEnemyBullet) {
continue;
}
// Check collision with enemies
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
// Create explosion effect at enemy position
createExplosion(enemy.x, enemy.y);
if (enemy.takeDamage(bullet.damage)) {
// Enemy destroyed
enemy.destroy();
enemies.splice(j, 1);
// Award more points for boss
var points = enemy.isBoss ? 100 : 10;
LK.setScore(LK.getScore() + points);
updateScore();
// Track kills and spawn boss
if (!enemy.isBoss) {
enemiesKilled++;
if (enemiesKilled % 10 === 0 && !bossActive) {
spawnBoss();
}
} else {
bossActive = false;
bossesKilled++;
// Give RPG after every 2 bosses
if (bossesKilled % 2 === 0) {
rpgAmmo += 1;
updateRPGDisplay();
// Flash effect to show RPG gained
LK.effects.flashScreen(0xFF0000, 500);
}
}
// Refuel bullet time on enemy kill
bulletTimeEnergy += 20;
if (bulletTimeEnergy > maxBulletTimeEnergy) {
bulletTimeEnergy = maxBulletTimeEnergy;
}
}
bullet.destroy();
heroBullets.splice(i, 1);
hitEnemy = true;
break;
}
}
if (!hitEnemy) {
// Check collision with obstacles
for (var j = obstacles.length - 1; j >= 0; j--) {
var obstacle = obstacles[j];
if (bullet.intersects(obstacle)) {
bullet.destroy();
heroBullets.splice(i, 1);
hitEnemy = true;
break;
}
}
}
if (!hitEnemy) {
bullet.lastY = bullet.y;
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.lastY === undefined) {
bullet.lastY = bullet.y;
}
// Remove bullets that go off screen
if (bullet.lastY <= 2752 && bullet.y > 2752) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with hero
if (bullet.intersects(hero)) {
hero.takeDamage(bullet.damage);
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with obstacles
var hitObstacle = false;
for (var j = obstacles.length - 1; j >= 0; j--) {
var obstacle = obstacles[j];
if (bullet.intersects(obstacle)) {
bullet.destroy();
enemyBullets.splice(i, 1);
hitObstacle = true;
break;
}
}
if (!hitObstacle) {
bullet.lastY = bullet.y;
}
}
// Check enemy collision with hero
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.intersects(hero)) {
hero.takeDamage(1);
enemy.destroy();
enemies.splice(i, 1);
}
}
};
// Initialize UI
updateScore();
updateHealthBar();
updateBulletTimeBar();
updateExtraHealthDisplay();
updateRPGDisplay(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Boss = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bossEnemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1;
self.health = 10;
self.maxHealth = 10;
self.shootTimer = 0;
self.shootInterval = 60; // 1 second at 60fps
self.isBoss = true;
self.update = function () {
// Move toward player
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var moveX = dx / distance * self.speed * enemySpeedMultiplier * timeScale;
var moveY = dy / distance * self.speed * enemySpeedMultiplier * timeScale;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Check collision with obstacles
var canMove = true;
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (newX + 75 > obstacle.x - 60 && newX - 75 < obstacle.x + 60 && newY + 75 > obstacle.y - 60 && newY - 75 < obstacle.y + 60) {
canMove = false;
break;
}
}
if (canMove) {
self.x = newX;
self.y = newY;
}
}
// Shoot at player more frequently
self.shootTimer += timeScale;
if (self.shootTimer >= self.shootInterval) {
self.shoot();
self.shootTimer = 0;
}
};
self.shoot = function () {
// Boss shoots 3 bullets in spread pattern
for (var i = -1; i <= 1; i++) {
var bullet = new EnemyBullet();
bullet.x = self.x + i * 30;
bullet.y = self.y;
// Calculate base direction towards hero
var dx = hero.x - bullet.x;
var dy = hero.y - bullet.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var baseAngle = Math.atan2(dy, dx);
var spreadAngle = baseAngle + i * 0.3; // 0.3 radians spread
bullet.directionX = Math.cos(spreadAngle);
bullet.directionY = Math.sin(spreadAngle);
} else {
bullet.directionX = 0;
bullet.directionY = 1;
}
enemyBullets.push(bullet);
game.addChild(bullet);
}
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
LK.effects.flashObject(self, 0xFFFFFF, 500);
LK.getSound('enemyHit').play();
return true; // Boss destroyed
}
// Flash red when taking damage
LK.effects.flashObject(self, 0xFF0000, 200);
return false;
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.health = 1;
self.shootTimer = 0;
self.shootInterval = 120; // 2 seconds at 60fps
self.update = function () {
// Move toward player
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var moveX = dx / distance * self.speed * enemySpeedMultiplier * timeScale;
var moveY = dy / distance * self.speed * enemySpeedMultiplier * timeScale;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Check collision with obstacles
var canMove = true;
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (newX + 30 > obstacle.x - 60 && newX - 30 < obstacle.x + 60 && newY + 30 > obstacle.y - 60 && newY - 30 < obstacle.y + 60) {
canMove = false;
break;
}
}
if (canMove) {
self.x = newX;
self.y = newY;
}
}
// Shoot at player
self.shootTimer += timeScale;
if (self.shootTimer >= self.shootInterval) {
self.shoot();
self.shootTimer = 0;
}
};
self.shoot = function () {
var bullet = new EnemyBullet();
bullet.x = self.x;
bullet.y = self.y;
// Calculate direction towards hero
var dx = hero.x - bullet.x;
var dy = hero.y - bullet.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
bullet.directionX = dx / distance;
bullet.directionY = dy / distance;
} else {
bullet.directionX = 0;
bullet.directionY = 1;
}
enemyBullets.push(bullet);
game.addChild(bullet);
};
self.takeDamage = function (damage) {
self.health -= damage;
if (self.health <= 0) {
LK.effects.flashObject(self, 0xFFFFFF, 200);
LK.getSound('enemyHit').play();
return true; // Enemy destroyed
}
return false;
};
return self;
});
var EnemyBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('enemyBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.damage = 1;
self.directionX = 0;
self.directionY = 1;
self.update = function () {
self.x += self.directionX * self.speed * timeScale;
self.y += self.directionY * self.speed * timeScale;
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
self.maxHealth = 100;
self.health = self.maxHealth;
self.shootTimer = 0;
self.shootInterval = 45; // Slower shooting
self.update = function () {
// Always shoot when enemies exist
if (enemies.length > 0) {
self.shootTimer += timeScale;
if (self.shootTimer >= self.shootInterval) {
self.shoot();
self.shootTimer = 0;
}
}
};
self.shoot = function () {
var bullet;
if (rpgAmmo > 0) {
bullet = new RPGBullet();
rpgAmmo--;
updateRPGDisplay();
} else {
bullet = new HeroBullet();
}
bullet.x = self.x;
bullet.y = self.y - 40;
// Find nearest enemy to aim at
var nearestEnemy = null;
var nearestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = enemy.x - self.x;
var dy = enemy.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < nearestDistance) {
nearestDistance = distance;
nearestEnemy = enemy;
}
}
// Set bullet direction towards nearest enemy
if (nearestEnemy) {
var dx = nearestEnemy.x - bullet.x;
var dy = nearestEnemy.y - bullet.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
bullet.directionX = dx / distance;
bullet.directionY = dy / distance;
} else {
bullet.directionX = 0;
bullet.directionY = -1;
}
} else {
bullet.directionX = 0;
bullet.directionY = -1;
}
heroBullets.push(bullet);
game.addChild(bullet);
LK.getSound('shoot').play();
};
self.takeDamage = function (damage) {
self.health -= damage;
LK.effects.flashObject(self, 0xFF0000, 500);
LK.getSound('playerHit').play();
// Use extra health if health drops to 20 or below and we have uses available
if (self.health <= 20 && extraHealthUses > 0) {
self.health += 50;
if (self.health > self.maxHealth) {
self.health = self.maxHealth;
}
extraHealthUses--;
updateExtraHealthDisplay();
LK.effects.flashObject(self, 0x00FF00, 800); // Green flash for healing
}
updateHealthBar();
if (self.health <= 0) {
LK.showGameOver();
}
};
return self;
});
var HeroBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('heroBullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.damage = 1;
self.directionX = 0;
self.directionY = -1;
self.update = function () {
self.x += self.directionX * self.speed * timeScale;
self.y += self.directionY * self.speed * timeScale;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var RPGBullet = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('heroBullet', {
anchorX: 0.5,
anchorY: 0.5
});
graphics.tint = 0xFF0000; // Red color for RPG
graphics.scaleX = 2;
graphics.scaleY = 2;
self.speed = 8;
self.damage = 999; // One shot kill
self.directionX = 0;
self.directionY = -1;
self.update = function () {
self.x += self.directionX * self.speed * timeScale;
self.y += self.directionY * self.speed * timeScale;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Game variables
var enemies = [];
var enemyBullets = [];
var heroBullets = [];
var obstacles = [];
var timeScale = 1.0;
var isBulletTimeActive = false;
var bulletTimeEnergy = 100;
var maxBulletTimeEnergy = 100;
var bulletTimeDecayRate = 0.5;
var bulletTimeRechargeRate = 0.1;
var bulletTimeSlowFactor = 0.2;
var dragNode = null;
var enemySpawnTimer = 0;
var enemySpawnInterval = 180; // 3 seconds
var waveNumber = 1;
var enemiesPerWave = 3;
var extraHealthUses = 3;
var maxExtraHealthUses = 3;
var enemiesKilled = 0;
var bossActive = false;
var lastScoreCheck = 0;
var enemySpeedMultiplier = 1.0;
var bossesKilled = 0;
var rpgAmmo = 0;
// UI elements
var scoreTxt = new Text2('0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 50;
var healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
var healthBar = LK.getAsset('healthBar', {
anchorX: 0,
anchorY: 0
});
var bulletTimeBarBg = LK.getAsset('bulletTimeBarBg', {
anchorX: 0,
anchorY: 0
});
var bulletTimeBar = LK.getAsset('bulletTimeBar', {
anchorX: 0,
anchorY: 0
});
LK.gui.topLeft.addChild(healthBarBg);
LK.gui.topLeft.addChild(healthBar);
LK.gui.topLeft.addChild(bulletTimeBarBg);
LK.gui.topLeft.addChild(bulletTimeBar);
healthBarBg.x = 120;
healthBarBg.y = 20;
healthBar.x = 122;
healthBar.y = 22;
bulletTimeBarBg.x = 120;
bulletTimeBarBg.y = 60;
bulletTimeBar.x = 122;
bulletTimeBar.y = 62;
// Add extra health display text first
var extraHealthText = new Text2('Extra Health: 3', {
size: 40,
fill: 0x00FF00
});
extraHealthText.anchor.set(0, 0);
LK.gui.topLeft.addChild(extraHealthText);
extraHealthText.x = 120;
extraHealthText.y = 100;
// Add extra health icons after text on the right side
var extraHealthIcons = [];
for (var i = 0; i < maxExtraHealthUses; i++) {
var icon = LK.getAsset('extraHealthIcon', {
anchorX: 0.5,
anchorY: 0.5
});
LK.gui.topLeft.addChild(icon);
icon.x = 380 + i * 40;
icon.y = 115;
extraHealthIcons.push(icon);
}
// Add RPG ammo display
var rpgText = new Text2('RPG: 0', {
size: 40,
fill: 0xFF0000
});
rpgText.anchor.set(0, 0);
LK.gui.topLeft.addChild(rpgText);
rpgText.x = 120;
rpgText.y = 140;
// Add city background
var cityBg = LK.getAsset('cityBackground', {
anchorX: 0,
anchorY: 0
});
game.addChild(cityBg);
// Initialize hero
hero = game.addChild(new Hero());
hero.x = 1024;
hero.y = 2200;
// Create obstacles
for (var i = 0; i < 6; i++) {
var obstacle = new Obstacle();
obstacle.x = 400 + i % 3 * 600;
obstacle.y = 800 + Math.floor(i / 3) * 600;
obstacles.push(obstacle);
game.addChild(obstacle);
}
// Update score display
function updateScore() {
scoreTxt.setText(LK.getScore());
}
// Update health bar
function updateHealthBar() {
var healthPercent = hero.health / hero.maxHealth;
healthBar.width = 400 * healthPercent;
}
// Update bullet time bar
function updateBulletTimeBar() {
var energyPercent = bulletTimeEnergy / maxBulletTimeEnergy;
bulletTimeBar.width = 300 * energyPercent;
}
// Update extra health display
function updateExtraHealthDisplay() {
extraHealthText.setText('Extra Health: ' + extraHealthUses);
for (var i = 0; i < extraHealthIcons.length; i++) {
extraHealthIcons[i].alpha = i < extraHealthUses ? 1.0 : 0.3;
}
}
// Update RPG display
function updateRPGDisplay() {
rpgText.setText('RPG: ' + rpgAmmo);
}
// Spawn enemy
function spawnEnemy() {
var enemy = new Enemy();
var side = Math.floor(Math.random() * 4);
switch (side) {
case 0:
// Top
enemy.x = Math.random() * 2048;
enemy.y = -50;
break;
case 1:
// Right
enemy.x = 2098;
enemy.y = Math.random() * 1000 + 100;
break;
case 2:
// Bottom
enemy.x = Math.random() * 2048;
enemy.y = -50;
break;
case 3:
// Left
enemy.x = -50;
enemy.y = Math.random() * 1000 + 100;
break;
}
// Scale enemy stats with wave number
enemy.speed = 2 + waveNumber * 0.3;
enemy.shootInterval = Math.max(60, 120 - waveNumber * 5);
enemies.push(enemy);
game.addChild(enemy);
}
// Spawn boss enemy
function spawnBoss() {
var boss = new Boss();
boss.x = 1024; // Center horizontally
boss.y = 200; // Top of screen
enemies.push(boss);
game.addChild(boss);
bossActive = true;
}
// Spawn additional enemies based on score
function spawnScoreBasedEnemies() {
for (var i = 0; i < 2; i++) {
spawnEnemy();
}
}
// Create explosion effect
function createExplosion(x, y, isBigExplosion) {
var explosion = LK.getAsset('heroBullet', {
anchorX: 0.5,
anchorY: 0.5
});
explosion.x = x;
explosion.y = y;
explosion.tint = isBigExplosion ? 0xFFFF00 : 0xFF4400; // Yellow for big explosions, orange for normal
explosion.scaleX = 0.1;
explosion.scaleY = 0.1;
game.addChild(explosion);
// Animate explosion - scale up and fade out
var targetScale = isBigExplosion ? 5 : 3;
var duration = isBigExplosion ? 500 : 300;
tween(explosion, {
scaleX: targetScale,
scaleY: targetScale,
alpha: 0
}, {
duration: duration,
easing: tween.easeOut,
onFinish: function onFinish() {
explosion.destroy();
}
});
}
// Increase enemy speed every 300 points
function checkEnemySpeedIncrease(currentScore) {
var speedLevel = Math.floor(currentScore / 300);
var newSpeedMultiplier = 1.0 + speedLevel * 0.5;
if (newSpeedMultiplier > enemySpeedMultiplier) {
enemySpeedMultiplier = newSpeedMultiplier;
}
}
// Handle bullet time activation
function activateBulletTime() {
if (bulletTimeEnergy > 0) {
isBulletTimeActive = true;
timeScale = bulletTimeSlowFactor;
}
}
// Handle bullet time deactivation
function deactivateBulletTime() {
isBulletTimeActive = false;
timeScale = 1.0;
}
// Event handlers
function handleMove(x, y, obj) {
if (dragNode) {
var newX = x;
var newY = y;
// Keep hero within bounds
newX = Math.max(40, Math.min(2008, newX));
newY = Math.max(40, Math.min(2692, newY));
// Check collision with obstacles
var canMove = true;
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
var tempHero = {
x: newX,
y: newY,
width: 80,
height: 80
};
if (newX + 40 > obstacle.x - 60 && newX - 40 < obstacle.x + 60 && newY + 40 > obstacle.y - 60 && newY - 40 < obstacle.y + 60) {
canMove = false;
break;
}
}
if (canMove) {
dragNode.x = newX;
dragNode.y = newY;
}
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
dragNode = hero;
activateBulletTime();
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
deactivateBulletTime();
};
// Main game update loop
game.update = function () {
// Update bullet time energy
if (isBulletTimeActive) {
bulletTimeEnergy -= bulletTimeDecayRate;
if (bulletTimeEnergy <= 0) {
bulletTimeEnergy = 0;
deactivateBulletTime();
}
} else {
bulletTimeEnergy += bulletTimeRechargeRate;
if (bulletTimeEnergy > maxBulletTimeEnergy) {
bulletTimeEnergy = maxBulletTimeEnergy;
}
}
updateBulletTimeBar();
// Check for score-based enemy spawning every 200 points
var currentScore = LK.getScore();
if (currentScore >= lastScoreCheck + 200) {
spawnScoreBasedEnemies();
lastScoreCheck = Math.floor(currentScore / 200) * 200;
}
// Check for enemy speed increase every 300 points
checkEnemySpeedIncrease(currentScore);
// Spawn enemies (but not when boss is active)
if (!bossActive) {
enemySpawnTimer += timeScale;
if (enemySpawnTimer >= enemySpawnInterval) {
if (enemies.length < enemiesPerWave) {
spawnEnemy();
}
enemySpawnTimer = 0;
// Start new wave if no enemies left
if (enemies.length === 0) {
waveNumber++;
enemiesPerWave = Math.min(8, 3 + Math.floor(waveNumber / 2));
enemySpawnInterval = Math.max(60, 180 - waveNumber * 10);
}
}
}
// Update hero bullets
for (var i = heroBullets.length - 1; i >= 0; i--) {
var bullet = heroBullets[i];
if (bullet.lastY === undefined) {
bullet.lastY = bullet.y;
}
// Remove bullets that go off screen
if (bullet.lastY >= -20 && bullet.y < -20) {
bullet.destroy();
heroBullets.splice(i, 1);
continue;
}
// Check collision with enemy bullets first
var hitEnemyBullet = false;
for (var k = enemyBullets.length - 1; k >= 0; k--) {
var enemyBullet = enemyBullets[k];
if (bullet.intersects(enemyBullet)) {
// Create big explosion at collision point
createExplosion((bullet.x + enemyBullet.x) / 2, (bullet.y + enemyBullet.y) / 2, true);
// Destroy both bullets
bullet.destroy();
enemyBullet.destroy();
heroBullets.splice(i, 1);
enemyBullets.splice(k, 1);
hitEnemyBullet = true;
break;
}
}
if (hitEnemyBullet) {
continue;
}
// Check collision with enemies
var hitEnemy = false;
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (bullet.intersects(enemy)) {
// Create explosion effect at enemy position
createExplosion(enemy.x, enemy.y);
if (enemy.takeDamage(bullet.damage)) {
// Enemy destroyed
enemy.destroy();
enemies.splice(j, 1);
// Award more points for boss
var points = enemy.isBoss ? 100 : 10;
LK.setScore(LK.getScore() + points);
updateScore();
// Track kills and spawn boss
if (!enemy.isBoss) {
enemiesKilled++;
if (enemiesKilled % 10 === 0 && !bossActive) {
spawnBoss();
}
} else {
bossActive = false;
bossesKilled++;
// Give RPG after every 2 bosses
if (bossesKilled % 2 === 0) {
rpgAmmo += 1;
updateRPGDisplay();
// Flash effect to show RPG gained
LK.effects.flashScreen(0xFF0000, 500);
}
}
// Refuel bullet time on enemy kill
bulletTimeEnergy += 20;
if (bulletTimeEnergy > maxBulletTimeEnergy) {
bulletTimeEnergy = maxBulletTimeEnergy;
}
}
bullet.destroy();
heroBullets.splice(i, 1);
hitEnemy = true;
break;
}
}
if (!hitEnemy) {
// Check collision with obstacles
for (var j = obstacles.length - 1; j >= 0; j--) {
var obstacle = obstacles[j];
if (bullet.intersects(obstacle)) {
bullet.destroy();
heroBullets.splice(i, 1);
hitEnemy = true;
break;
}
}
}
if (!hitEnemy) {
bullet.lastY = bullet.y;
}
}
// Update enemy bullets
for (var i = enemyBullets.length - 1; i >= 0; i--) {
var bullet = enemyBullets[i];
if (bullet.lastY === undefined) {
bullet.lastY = bullet.y;
}
// Remove bullets that go off screen
if (bullet.lastY <= 2752 && bullet.y > 2752) {
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with hero
if (bullet.intersects(hero)) {
hero.takeDamage(bullet.damage);
bullet.destroy();
enemyBullets.splice(i, 1);
continue;
}
// Check collision with obstacles
var hitObstacle = false;
for (var j = obstacles.length - 1; j >= 0; j--) {
var obstacle = obstacles[j];
if (bullet.intersects(obstacle)) {
bullet.destroy();
enemyBullets.splice(i, 1);
hitObstacle = true;
break;
}
}
if (!hitObstacle) {
bullet.lastY = bullet.y;
}
}
// Check enemy collision with hero
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
if (enemy.intersects(hero)) {
hero.takeDamage(1);
enemy.destroy();
enemies.splice(i, 1);
}
}
};
// Initialize UI
updateScore();
updateHealthBar();
updateBulletTimeBar();
updateExtraHealthDisplay();
updateRPGDisplay();
draw a man like max payne. In-Game asset. 2d. High contrast. No shadows
draw a mafia guy with gun. In-Game asset. 2d. High contrast. No shadows
draw a city road map. In-Game asset. 2d. High contrast. No shadows
draw a mafia guy like a monster with gun. In-Game asset. 2d. High contrast. No shadows
draw a skyscraper. In-Game asset. 2d. High contrast. No shadows
draw a pistol bullet 50 calibre. In-Game asset. 2d. High contrast. No shadows
draw a heart with pixel art. In-Game asset. 2d. High contrast. No shadows