User prompt
can you make the texture reset more faster ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
remove any fade effects for exture reset and reset the ttextures imideatl ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
can you make the texture reset more faser and smoother to prevent flickering texture chage ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
can you add one additional walk asset to cycle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
prevent flickering asset change for a smoother and complete anim ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
the characters asset is not changing at the mment, and it is locked on base hero asset can you make a walking animthhat cycles betwen herowalk assets ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
walking animisnt working can you fixit ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
when charater is wlking the assets change between walk assets ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
can you enlarge the map verical borders
User prompt
make he walking anim via chancing charrachter asset texture ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make a walking animation to pllayer ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
add a background asset for player to know whether the cahractr is movıngg or not ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
if a enemy is alerted it wont stoop followıng
User prompt
increaase the enemys attraction radius and enemy will alertd if take damage with knife
User prompt
show hwmany enemis left
User prompt
the knife asset should face to enemys when thrown ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
speed up the char
User prompt
the route should end to mob assets middle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
the knife route should start from middle of the char asset
User prompt
the knives shouldnt ricochet and deal damage to the first mob they onterfered
User prompt
speed up the knives ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
the players take damage when knife assets hits them.
User prompt
the players take damage when knife assets hits them. spped upo the knife ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
the knife should follow the route ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
remove the route 0.5 sec after creating ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.collectTimer = 0;
self.update = function () {
// Auto-collect after short delay
self.collectTimer++;
if (self.collectTimer > 30) {
// 0.5 seconds
self.collect();
}
// Spin animation
coinGraphics.rotation += 0.1;
};
self.collect = function () {
LK.getSound('coin').play();
// Remove from coins array
for (var i = coins.length - 1; i >= 0; i--) {
if (coins[i] === self) {
coins.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 1.0
});
self.health = 2;
self.speed = 1;
self.attackCooldown = 0;
self.fromLeft = true;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
var distanceToHero = Math.sqrt(Math.pow(self.x - hero.x, 2) + Math.pow(self.y - hero.y, 2));
var canSeeHero = distanceToHero < 300; // Line of sight range
if (canSeeHero) {
// Chase hero
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var newX = self.x + dx / distance * self.speed;
var newY = self.y + dy / distance * self.speed;
// Check collision with other enemies before moving
var wouldCollide = false;
for (var i = 0; i < enemies.length; i++) {
var otherEnemy = enemies[i];
if (otherEnemy === self) continue; // Skip self
var edx = newX - otherEnemy.x;
var edy = newY - otherEnemy.y;
var edistance = Math.sqrt(edx * edx + edy * edy);
if (edistance < 70) {
// Collision threshold between enemies
wouldCollide = true;
break;
}
}
// Only move if no collision would occur
if (!wouldCollide) {
self.lastX = self.x;
self.lastY = self.y;
self.x = newX;
self.y = newY;
}
// Face direction of movement
enemyGraphics.scaleX = dx > 0 ? 1 : -1;
}
// Attack hero if close enough
if (distanceToHero < 100 && self.attackCooldown <= 0) {
hero.takeDamage();
self.attackCooldown = 120; // 2 seconds at 60fps
}
} else {
// Roam randomly
if (!self.roamDirection || Math.random() < 0.01) {
self.roamDirection = {
x: (Math.random() - 0.5) * 2,
y: (Math.random() - 0.5) * 2
};
}
var newX = self.x + self.roamDirection.x * self.speed * 0.5;
var newY = self.y + self.roamDirection.y * self.speed * 0.5;
// Check collision with other enemies before roaming
var wouldCollide = false;
for (var i = 0; i < enemies.length; i++) {
var otherEnemy = enemies[i];
if (otherEnemy === self) continue; // Skip self
var edx = newX - otherEnemy.x;
var edy = newY - otherEnemy.y;
var edistance = Math.sqrt(edx * edx + edy * edy);
if (edistance < 70) {
// Collision threshold between enemies
wouldCollide = true;
break;
}
}
// Keep within level bounds and check collisions
if (!wouldCollide && newX > 100 && newX < currentLevelData.width - 100) {
self.lastX = self.x;
self.x = newX;
enemyGraphics.scaleX = self.roamDirection.x > 0 ? 1 : -1;
}
if (!wouldCollide && newY > 1800 && newY < 2200) {
self.lastY = self.y;
self.y = newY;
}
}
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
};
self.takeDamage = function () {
self.health--;
LK.effects.flashObject(self, 0xffffff, 200);
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
// Drop coin
var coin = game.addChild(new Coin());
coin.x = self.x;
coin.y = self.y;
// Add score and combo
var baseScore = 10;
var comboMultiplier = Math.floor(hero.comboCount / 5) + 1;
var finalScore = baseScore * comboMultiplier;
LK.setScore(LK.getScore() + finalScore);
hero.addCombo();
// Remove from enemies array
for (var i = enemies.length - 1; i >= 0; i--) {
if (enemies[i] === self) {
enemies.splice(i, 1);
break;
}
}
self.destroy();
updateScoreDisplay();
updateEnemiesLeftDisplay();
};
return self;
});
var EnemyWarning = Container.expand(function () {
var self = Container.call(this);
self.targetEnemy = null;
self.direction = 'left'; // 'left', 'right', 'up', 'down'
self.warningGraphics = null;
self.lastAlpha = 0;
self.isVisible = false;
self.setDirection = function (direction) {
if (self.warningGraphics) {
self.warningGraphics.destroy();
}
var assetName = 'warningArrow' + direction.charAt(0).toUpperCase() + direction.slice(1);
self.warningGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.direction = direction;
};
self.update = function () {
if (!self.targetEnemy || !self.warningGraphics) return;
// Check if enemy is still alive
var enemyExists = false;
for (var i = 0; i < enemies.length; i++) {
if (enemies[i] === self.targetEnemy) {
enemyExists = true;
break;
}
}
if (!enemyExists) {
self.hide();
return;
}
// Calculate distance from hero to enemy
var distanceToHero = Math.sqrt(Math.pow(self.targetEnemy.x - hero.x, 2) + Math.pow(self.targetEnemy.y - hero.y, 2));
// Check if enemy is visible on screen
var enemyScreenX = self.targetEnemy.x - camera.x;
var enemyScreenY = self.targetEnemy.y - camera.y;
var isOnScreen = enemyScreenX >= -100 && enemyScreenX <= 2148 && enemyScreenY >= -100 && enemyScreenY <= 2832;
if (isOnScreen) {
self.hide();
return;
}
// Calculate warning opacity based on distance (closer = more visible)
var maxDistance = 800;
var minDistance = 300;
var targetAlpha = 0;
if (distanceToHero <= maxDistance) {
var normalizedDistance = Math.max(0, Math.min(1, (maxDistance - distanceToHero) / (maxDistance - minDistance)));
targetAlpha = normalizedDistance * 0.8;
}
// Smooth alpha transition
if (Math.abs(targetAlpha - self.lastAlpha) > 0.01) {
tween.stop(self.warningGraphics, {
alpha: true
});
tween(self.warningGraphics, {
alpha: targetAlpha
}, {
duration: 200
});
self.lastAlpha = targetAlpha;
}
// Position warning at screen edge
var screenCenterX = 1024;
var screenCenterY = 1366;
var dx = self.targetEnemy.x - hero.x;
var dy = self.targetEnemy.y - hero.y;
if (Math.abs(dx) > Math.abs(dy)) {
// Horizontal warning
if (dx > 0) {
self.setDirection('right');
self.x = screenCenterX + 900;
self.y = screenCenterY + Math.max(-600, Math.min(600, dy * 0.5));
} else {
self.setDirection('left');
self.x = screenCenterX - 900;
self.y = screenCenterY + Math.max(-600, Math.min(600, dy * 0.5));
}
} else {
// Vertical warning
if (dy > 0) {
self.setDirection('down');
self.x = screenCenterX + Math.max(-800, Math.min(800, dx * 0.5));
self.y = screenCenterY + 1200;
} else {
self.setDirection('up');
self.x = screenCenterX + Math.max(-800, Math.min(800, dx * 0.5));
self.y = screenCenterY - 1200;
}
}
};
self.hide = function () {
if (self.warningGraphics && self.warningGraphics.alpha > 0) {
tween.stop(self.warningGraphics, {
alpha: true
});
tween(self.warningGraphics, {
alpha: 0
}, {
duration: 300
});
self.lastAlpha = 0;
}
};
return self;
});
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroGraphics = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 1.0
});
self.maxHealth = 5;
self.health = self.maxHealth;
self.isAttacking = false;
self.invulnerable = false;
self.damageBoost = false;
self.comboCount = 0;
self.lastX = 0;
self.lastY = 0;
self.attack = function (targetX) {
if (self.isAttacking) return;
self.isAttacking = true;
// Face direction of attack
if (targetX < self.x) {
heroGraphics.scaleX = -1;
} else {
heroGraphics.scaleX = 1;
}
// Attack animation
tween(heroGraphics, {
scaleY: 1.2
}, {
duration: 100
});
tween(heroGraphics, {
scaleY: 1.0
}, {
duration: 100,
onFinish: function onFinish() {
self.isAttacking = false;
}
});
// Create punch effect
var effect = game.addChild(LK.getAsset('punchEffect', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
}));
effect.x = self.x + heroGraphics.scaleX * 80;
effect.y = self.y - 80;
tween(effect, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
effect.destroy();
}
});
LK.getSound('punch').play();
};
self.takeDamage = function () {
if (self.invulnerable) return;
self.health--;
self.comboCount = 0;
// Flash red when hit
LK.effects.flashObject(self, 0xff0000, 500);
// Temporary invulnerability
self.invulnerable = true;
LK.setTimeout(function () {
self.invulnerable = false;
}, 1000);
LK.getSound('hit').play();
updateHealthDisplay();
if (self.health <= 0) {
LK.showGameOver();
}
};
self.heal = function () {
if (self.health < self.maxHealth) {
self.health++;
updateHealthDisplay();
}
};
self.addCombo = function () {
self.comboCount++;
};
self.move = function (direction) {
var speed = 8;
var newX = self.x;
var newY = self.y;
if (direction === 'left' && self.x > 100) {
newX = self.x - speed;
heroGraphics.scaleX = -1;
} else if (direction === 'right' && self.x < currentLevelData.width - 100) {
newX = self.x + speed;
heroGraphics.scaleX = 1;
} else if (direction === 'up' && self.y > 1800) {
newY = self.y - speed;
} else if (direction === 'down' && self.y < 2200) {
newY = self.y + speed;
}
// Check collision with enemies before moving
var wouldCollide = false;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = newX - enemy.x;
var dy = newY - enemy.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 80) {
// Collision threshold
wouldCollide = true;
break;
}
}
// Only move if no collision would occur
if (!wouldCollide) {
self.lastX = self.x;
self.lastY = self.y;
self.x = newX;
self.y = newY;
}
// Update camera target
camera.targetX = self.x - 1024;
camera.targetY = self.y - 1366;
// Clamp camera to level bounds
camera.targetX = Math.max(0, Math.min(camera.targetX, currentLevelData.width - 2048));
camera.targetY = Math.max(0, Math.min(camera.targetY, currentLevelData.height - 2732));
};
return self;
});
var Knife = Container.expand(function () {
var self = Container.call(this);
var knifeGraphics = self.attachAsset('knife', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 15;
self.direction = 1; // 1 for right, -1 for left
self.routePoints = []; // Points to follow along the route
self.currentRouteIndex = 0; // Current target point index
self.velocityX = 0; // Velocity for precise targeting
self.velocityY = 0; // Velocity for precise targeting
self.lastX = 0;
self.lastY = 0;
self.setRoute = function (routePoints) {
self.routePoints = routePoints;
self.currentRouteIndex = 0;
};
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Follow route if available
if (self.routePoints.length > 0 && self.currentRouteIndex < self.routePoints.length) {
var targetPoint = self.routePoints[self.currentRouteIndex];
var dx = targetPoint.x - self.x;
var dy = targetPoint.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 20) {
// Close enough to current target, move to next point
self.currentRouteIndex++;
} else {
// Move toward current target point
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
// Calculate rotation angle to face target direction
var angle = Math.atan2(dy, dx);
knifeGraphics.rotation = angle;
}
}
} else if (self.velocityX !== 0 || self.velocityY !== 0) {
// Use velocity if set, otherwise use direction-based movement
self.x += self.velocityX;
self.y += self.velocityY;
// Calculate rotation for velocity-based movement
var angle = Math.atan2(self.velocityY, self.velocityX);
knifeGraphics.rotation = angle;
} else {
self.x += self.speed * self.direction;
self.y -= 2; // Slight upward arc
// Calculate rotation for direction-based movement
var angle = Math.atan2(-2, self.speed * self.direction);
knifeGraphics.rotation = angle;
}
// Check if knife went off screen
if (self.x < -100 || self.x > currentLevelData.width + 100 || self.y < -100 || self.y > 2900) {
self.destroy();
// Remove from knives array
for (var i = knives.length - 1; i >= 0; i--) {
if (knives[i] === self) {
knives.splice(i, 1);
break;
}
}
}
// Check collision with enemies (hit enemy center)
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var dx = self.x - enemy.x;
var dy = self.y - (enemy.y - 70); // Target enemy center
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 50) {
// Hit enemy center - deal damage only to first enemy encountered
enemy.takeDamage();
self.destroy();
// Remove from knives array
for (var j = knives.length - 1; j >= 0; j--) {
if (knives[j] === self) {
knives.splice(j, 1);
break;
}
}
return; // Exit update immediately to prevent further movement or collision checks
}
}
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerupGraphics = self.attachAsset('powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.type = 'health'; // 'health', 'invulnerable', 'damage'
self.lifetime = 600; // 10 seconds
self.update = function () {
self.lifetime--;
if (self.lifetime <= 0) {
self.expire();
}
// Check collision with hero
if (self.intersects(hero)) {
self.collect();
}
// Pulse animation
var scale = 1 + Math.sin(LK.ticks * 0.2) * 0.2;
powerupGraphics.scaleX = scale;
powerupGraphics.scaleY = scale;
};
self.collect = function () {
LK.getSound('powerup').play();
if (self.type === 'health') {
hero.heal();
} else if (self.type === 'invulnerable') {
hero.invulnerable = true;
LK.setTimeout(function () {
hero.invulnerable = false;
}, 5000);
} else if (self.type === 'damage') {
hero.damageBoost = true;
LK.setTimeout(function () {
hero.damageBoost = false;
}, 5000);
}
// Remove from powerups array
for (var i = powerups.length - 1; i >= 0; i--) {
if (powerups[i] === self) {
powerups.splice(i, 1);
break;
}
}
self.destroy();
};
self.expire = function () {
// Remove from powerups array
for (var i = powerups.length - 1; i >= 0; i--) {
if (powerups[i] === self) {
powerups.splice(i, 1);
break;
}
}
self.destroy();
};
return self;
});
var RouteEffect = Container.expand(function () {
var self = Container.call(this);
self.routePoints = [];
self.routePositions = []; // Store just the x,y coordinates for knife to follow
self.targetEnemy = null;
self.createRoute = function (enemy) {
self.targetEnemy = enemy;
self.clearRoute();
// Calculate direct path from hero center to enemy center
var heroStartX = hero.x;
var heroStartY = hero.y - 80; // Middle of hero asset
var enemyMiddleX = enemy.x;
var enemyMiddleY = enemy.y - 70; // Middle of enemy asset (enemy height is 140, so middle is -70 from bottom)
var dx = enemyMiddleX - heroStartX;
var dy = enemyMiddleY - heroStartY;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Create route points along the path
var numPoints = Math.floor(distance / 50); // Point every 50 pixels
for (var i = 0; i <= numPoints; i++) {
var t = i / numPoints;
var x = heroStartX + dx * t;
var y = heroStartY + dy * t;
var routePoint = self.addChild(LK.getAsset('routeLine', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
}));
routePoint.x = x;
routePoint.y = y;
self.routePoints.push(routePoint);
// Store position for knife to follow
self.routePositions.push({
x: x,
y: y
});
// Animate route points appearing with delay
tween(routePoint, {
alpha: 0.8,
scaleX: 2,
scaleY: 2
}, {
duration: 100 + i * 20
});
}
// Add impact effect at enemy position
var impactEffect = self.addChild(LK.getAsset('routeEffect', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}));
impactEffect.x = enemyMiddleX;
impactEffect.y = enemyMiddleY;
self.routePoints.push(impactEffect);
// Animate impact effect
tween(impactEffect, {
alpha: 1,
scaleX: 3,
scaleY: 3
}, {
duration: 300,
easing: tween.easeOut
});
// Remove route after 0.5 seconds
LK.setTimeout(function () {
self.destroy();
// Remove from routeEffects array
for (var i = routeEffects.length - 1; i >= 0; i--) {
if (routeEffects[i] === self) {
routeEffects.splice(i, 1);
break;
}
}
}, 500);
}
};
self.clearRoute = function () {
for (var i = self.routePoints.length - 1; i >= 0; i--) {
self.routePoints[i].destroy();
}
self.routePoints = [];
};
self.fadeOut = function () {
for (var i = 0; i < self.routePoints.length; i++) {
tween(self.routePoints[i], {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 200
});
}
LK.setTimeout(function () {
self.destroy();
}, 300);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c3e50
});
/****
* Game Code
****/
// Game variables
var hero;
var enemies = [];
var coins = [];
var powerups = [];
var enemyWarnings = [];
var knives = [];
var knivesRemaining = 5;
var routeEffects = [];
var currentLevel = 1;
var levelComplete = false;
var hearts = [];
// Movement state tracking
var movementState = {
left: false,
right: false,
up: false,
down: false
};
// Camera system
var camera = {
x: 0,
y: 0,
targetX: 0,
targetY: 0,
smoothing: 0.1
};
// Level configuration
var levels = [{
enemies: [{
type: 'basic',
count: 3
}],
width: 4096,
height: 2732
}, {
enemies: [{
type: 'basic',
count: 5
}, {
type: 'strong',
count: 2
}],
width: 5120,
height: 2732
}, {
enemies: [{
type: 'basic',
count: 7
}, {
type: 'strong',
count: 3
}, {
type: 'fast',
count: 2
}],
width: 6144,
height: 2732
}];
var currentLevelData = levels[0];
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
scoreText.x = 150;
scoreText.y = 50;
LK.gui.topLeft.addChild(scoreText);
var levelText = new Text2('Level: 1', {
size: 80,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
levelText.y = 50;
var comboText = new Text2('Combo: 0x', {
size: 60,
fill: 0xFFFF00
});
comboText.anchor.set(1, 0);
LK.gui.topRight.addChild(comboText);
comboText.x = -50;
comboText.y = 120;
var knivesText = new Text2('Knives: 5', {
size: 60,
fill: 0x8e44ad
});
knivesText.anchor.set(1, 0);
LK.gui.topRight.addChild(knivesText);
knivesText.x = -50;
knivesText.y = 190;
var enemiesLeftText = new Text2('Enemies: 0', {
size: 60,
fill: 0xff4444
});
enemiesLeftText.anchor.set(1, 0);
LK.gui.topRight.addChild(enemiesLeftText);
enemiesLeftText.x = -50;
enemiesLeftText.y = 260;
// Create movement and attack buttons
var leftButton = LK.getAsset('leftButton', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
leftButton.x = 120;
leftButton.y = -250;
LK.gui.bottomLeft.addChild(leftButton);
var rightButton = LK.getAsset('rightButton', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
rightButton.x = 400;
rightButton.y = -250;
LK.gui.bottomLeft.addChild(rightButton);
var upButton = LK.getAsset('upButton', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
upButton.x = 260;
upButton.y = -380;
LK.gui.bottomLeft.addChild(upButton);
var downButton = LK.getAsset('downButton', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
downButton.x = 260;
downButton.y = -120;
LK.gui.bottomLeft.addChild(downButton);
var attackButton = LK.getAsset('attackButton', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
attackButton.x = -150;
attackButton.y = -200;
LK.gui.bottomRight.addChild(attackButton);
var knifeButton = LK.getAsset('knifeButton', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
knifeButton.x = -350;
knifeButton.y = -200;
LK.gui.bottomRight.addChild(knifeButton);
// Create hero
hero = game.addChild(new Hero());
hero.x = 1024; // Center of screen
hero.y = 2200; // Near bottom
// Create health display
function updateHealthDisplay() {
// Remove existing hearts
for (var i = hearts.length - 1; i >= 0; i--) {
hearts[i].destroy();
}
hearts = [];
// Create new hearts
for (var i = 0; i < hero.health; i++) {
var heart = LK.getAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
heart.x = 200 + i * 80;
heart.y = 200;
LK.gui.topLeft.addChild(heart);
hearts.push(heart);
}
}
function updateScoreDisplay() {
scoreText.setText('Score: ' + LK.getScore());
var comboMultiplier = Math.floor(hero.comboCount / 5) + 1;
comboText.setText('Combo: ' + comboMultiplier + 'x');
}
function updateKnivesDisplay() {
knivesText.setText('Knives: ' + knivesRemaining);
// Update button alpha based on availability
knifeButton.alpha = knivesRemaining > 0 ? 0.9 : 0.3;
}
function updateEnemiesLeftDisplay() {
enemiesLeftText.setText('Enemies: ' + enemies.length);
}
function initializeLevel() {
// Clear existing enemies
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
}
enemies = [];
// Clear existing warnings
for (var i = enemyWarnings.length - 1; i >= 0; i--) {
enemyWarnings[i].destroy();
}
enemyWarnings = [];
// Clear existing knives
for (var i = knives.length - 1; i >= 0; i--) {
knives[i].destroy();
}
knives = [];
// Clear existing route effects
for (var i = routeEffects.length - 1; i >= 0; i--) {
routeEffects[i].destroy();
}
routeEffects = [];
// Reset knife count
knivesRemaining = 5;
currentLevelData = levels[currentLevel - 1] || levels[levels.length - 1];
levelComplete = false;
// Spawn enemies for this level
for (var j = 0; j < currentLevelData.enemies.length; j++) {
var enemyGroup = currentLevelData.enemies[j];
for (var k = 0; k < enemyGroup.count; k++) {
spawnEnemy(enemyGroup.type);
}
}
levelText.setText('Level: ' + currentLevel);
updateKnivesDisplay();
updateEnemiesLeftDisplay();
}
function spawnEnemy(type) {
var enemy = game.addChild(new Enemy());
// Random spawn position within level bounds
enemy.x = 200 + Math.random() * (currentLevelData.width - 400);
enemy.y = 1900 + Math.random() * 200;
// Set enemy properties based on type
if (type === 'basic') {
enemy.health = 2;
enemy.speed = 1;
} else if (type === 'strong') {
enemy.health = 4;
enemy.speed = 0.8;
enemy.getChildAt(0).tint = 0x8b4513; // Brown tint
} else if (type === 'fast') {
enemy.health = 1;
enemy.speed = 2;
enemy.getChildAt(0).tint = 0x00ff00; // Green tint
}
enemies.push(enemy);
}
function spawnPowerUp() {
var powerup = game.addChild(new PowerUp());
powerup.x = 500 + Math.random() * 1048; // Random x position
powerup.y = 2000; // Above ground level
// Random powerup type
var types = ['health', 'invulnerable', 'damage'];
powerup.type = types[Math.floor(Math.random() * types.length)];
// Color by type
var powerupGraphics = powerup.getChildAt(0);
if (powerup.type === 'health') {
powerupGraphics.tint = 0x00ff00; // Green
} else if (powerup.type === 'invulnerable') {
powerupGraphics.tint = 0x0088ff; // Blue
} else if (powerup.type === 'damage') {
powerupGraphics.tint = 0xff8800; // Orange
}
powerups.push(powerup);
}
function findNearestEnemy(x, y) {
var nearest = null;
var shortestDistance = Infinity;
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var distance = Math.sqrt(Math.pow(enemy.x - x, 2) + Math.pow(enemy.y - y, 2));
if (distance < shortestDistance) {
shortestDistance = distance;
nearest = enemy;
}
}
return nearest;
}
function updateEnemyWarnings() {
// Remove warnings for dead enemies
for (var i = enemyWarnings.length - 1; i >= 0; i--) {
var warning = enemyWarnings[i];
var enemyExists = false;
for (var j = 0; j < enemies.length; j++) {
if (enemies[j] === warning.targetEnemy) {
enemyExists = true;
break;
}
}
if (!enemyExists) {
warning.destroy();
enemyWarnings.splice(i, 1);
}
}
// Create warnings for new enemies
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
var hasWarning = false;
for (var j = 0; j < enemyWarnings.length; j++) {
if (enemyWarnings[j].targetEnemy === enemy) {
hasWarning = true;
break;
}
}
if (!hasWarning) {
var warning = LK.gui.center.addChild(new EnemyWarning());
warning.targetEnemy = enemy;
warning.setDirection('left');
enemyWarnings.push(warning);
}
}
}
// Initialize UI
updateHealthDisplay();
updateScoreDisplay();
updateKnivesDisplay();
updateEnemiesLeftDisplay();
// Initialize first level
initializeLevel();
// Set initial camera position
camera.targetX = hero.x - 1024;
camera.targetY = hero.y - 1366;
camera.x = camera.targetX;
camera.y = camera.targetY;
// Button event handlers
leftButton.down = function (x, y, obj) {
movementState.left = true;
};
leftButton.up = function (x, y, obj) {
movementState.left = false;
};
rightButton.down = function (x, y, obj) {
movementState.right = true;
};
rightButton.up = function (x, y, obj) {
movementState.right = false;
};
upButton.down = function (x, y, obj) {
movementState.up = true;
};
upButton.up = function (x, y, obj) {
movementState.up = false;
};
downButton.down = function (x, y, obj) {
movementState.down = true;
};
downButton.up = function (x, y, obj) {
movementState.down = false;
};
attackButton.down = function (x, y, obj) {
if (!hero.isAttacking) {
var nearestEnemy = findNearestEnemy(hero.x, hero.y);
if (nearestEnemy) {
hero.attack(nearestEnemy.x);
// Check if attack hits with increased range
var distanceToEnemy = Math.sqrt(Math.pow(hero.x - nearestEnemy.x, 2) + Math.pow(hero.y - nearestEnemy.y, 2));
if (distanceToEnemy < 250) {
// Increased from 150 to 250
var damage = hero.damageBoost ? 2 : 1;
for (var i = 0; i < damage; i++) {
nearestEnemy.takeDamage();
}
}
} else {
// Attack in hero's facing direction
hero.attack(hero.x + (hero.getChildAt(0).scaleX > 0 ? 100 : -100));
}
}
};
knifeButton.down = function (x, y, obj) {
if (knivesRemaining > 0) {
// Find nearest enemy for targeting
var nearestEnemy = findNearestEnemy(hero.x, hero.y);
if (nearestEnemy) {
// Clear existing route effects before creating new one
for (var i = routeEffects.length - 1; i >= 0; i--) {
routeEffects[i].destroy();
routeEffects.splice(i, 1);
}
// Create route visualization
var routeEffect = game.addChild(new RouteEffect());
routeEffect.createRoute(nearestEnemy);
routeEffects.push(routeEffect);
// Throw knife to follow the route
var knife = game.addChild(new Knife());
knife.x = hero.x;
knife.y = hero.y - 80;
// Set the route for the knife to follow
knife.setRoute(routeEffect.routePositions);
// Rotation will be handled automatically in knife update based on target direction
knives.push(knife);
knivesRemaining--;
updateKnivesDisplay();
LK.getSound('knifeThrow').play();
} else {
// No enemy found, throw in hero facing direction
var knife = game.addChild(new Knife());
knife.x = hero.x;
knife.y = hero.y - 80;
var heroGraphics = hero.getChildAt(0);
knife.direction = heroGraphics.scaleX > 0 ? 1 : -1;
// Rotation will be handled automatically in knife update based on movement direction
knives.push(knife);
knivesRemaining--;
updateKnivesDisplay();
LK.getSound('knifeThrow').play();
}
}
};
// Game input (fallback for screen taps outside buttons)
game.down = function (x, y, obj) {
// Convert screen coordinates to world coordinates
var worldX = x + camera.x;
var worldY = y + camera.y;
// Check if tap is for movement or attack
var distanceToHero = Math.sqrt(Math.pow(worldX - hero.x, 2) + Math.pow(worldY - hero.y, 2));
if (distanceToHero > 200) {
// Movement - move toward tap position
var dx = worldX - hero.x;
var dy = worldY - hero.y;
if (Math.abs(dx) > Math.abs(dy)) {
hero.move(dx > 0 ? 'right' : 'left');
} else {
hero.move(dy > 0 ? 'down' : 'up');
}
} else {
// Attack
if (!hero.isAttacking) {
var nearestEnemy = findNearestEnemy(worldX, worldY);
if (nearestEnemy) {
hero.attack(nearestEnemy.x);
// Check if attack hits with increased range
var distanceToEnemy = Math.sqrt(Math.pow(hero.x - nearestEnemy.x, 2) + Math.pow(hero.y - nearestEnemy.y, 2));
if (distanceToEnemy < 250) {
// Increased from 150 to 250
var damage = hero.damageBoost ? 2 : 1;
for (var i = 0; i < damage; i++) {
nearestEnemy.takeDamage();
}
}
} else {
// Attack in direction of tap
hero.attack(worldX);
}
}
}
};
// Main game loop
game.update = function () {
// Handle continuous movement based on button states
if (movementState.left) {
hero.move('left');
}
if (movementState.right) {
hero.move('right');
}
if (movementState.up) {
hero.move('up');
}
if (movementState.down) {
hero.move('down');
}
// Update camera position smoothly
camera.x += (camera.targetX - camera.x) * camera.smoothing;
camera.y += (camera.targetY - camera.y) * camera.smoothing;
// Apply camera position to game
game.x = -camera.x;
game.y = -camera.y;
// Update all game objects
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.update();
}
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].update();
}
for (var i = powerups.length - 1; i >= 0; i--) {
powerups[i].update();
}
for (var i = knives.length - 1; i >= 0; i--) {
knives[i].update();
}
// Clean up destroyed route effects
for (var i = routeEffects.length - 1; i >= 0; i--) {
var routeEffect = routeEffects[i];
if (!routeEffect.parent) {
routeEffects.splice(i, 1);
}
}
// Update enemy warnings
updateEnemyWarnings();
for (var i = 0; i < enemyWarnings.length; i++) {
enemyWarnings[i].update();
}
// Check for level completion
if (!levelComplete && enemies.length === 0) {
levelComplete = true;
currentLevel++;
if (currentLevel <= levels.length) {
// Start next level after delay
LK.setTimeout(function () {
initializeLevel();
}, 2000);
} else {
// Game completed
LK.showYouWin();
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -153,8 +153,9 @@
}
}
self.destroy();
updateScoreDisplay();
+ updateEnemiesLeftDisplay();
};
return self;
});
var EnemyWarning = Container.expand(function () {
@@ -739,8 +740,16 @@
knivesText.anchor.set(1, 0);
LK.gui.topRight.addChild(knivesText);
knivesText.x = -50;
knivesText.y = 190;
+var enemiesLeftText = new Text2('Enemies: 0', {
+ size: 60,
+ fill: 0xff4444
+});
+enemiesLeftText.anchor.set(1, 0);
+LK.gui.topRight.addChild(enemiesLeftText);
+enemiesLeftText.x = -50;
+enemiesLeftText.y = 260;
// Create movement and attack buttons
var leftButton = LK.getAsset('leftButton', {
anchorX: 0.5,
anchorY: 0.5,
@@ -821,8 +830,11 @@
knivesText.setText('Knives: ' + knivesRemaining);
// Update button alpha based on availability
knifeButton.alpha = knivesRemaining > 0 ? 0.9 : 0.3;
}
+function updateEnemiesLeftDisplay() {
+ enemiesLeftText.setText('Enemies: ' + enemies.length);
+}
function initializeLevel() {
// Clear existing enemies
for (var i = enemies.length - 1; i >= 0; i--) {
enemies[i].destroy();
@@ -855,8 +867,9 @@
}
}
levelText.setText('Level: ' + currentLevel);
updateKnivesDisplay();
+ updateEnemiesLeftDisplay();
}
function spawnEnemy(type) {
var enemy = game.addChild(new Enemy());
// Random spawn position within level bounds
@@ -945,8 +958,9 @@
// Initialize UI
updateHealthDisplay();
updateScoreDisplay();
updateKnivesDisplay();
+updateEnemiesLeftDisplay();
// Initialize first level
initializeLevel();
// Set initial camera position
camera.targetX = hero.x - 1024;