User prompt
add movement keys as buttoms on the ricth of the screen
User prompt
visible buttoms for kick, punch and range attack
User prompt
kick and punch dont consume energy
User prompt
enemy also can use range attack
User prompt
regen the bars one by one
User prompt
the energy bar is 3 little bars, every range attack consumes one
User prompt
energy regens slower and enemy can use it aswell
User prompt
range attack deals less damage and consumes more energy
User prompt
need to press Z to punch, X to kick and C for range attack
User prompt
cant move
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var localPos = fighter.parent.toLocal(obj.position);' Line Number: 406
Code edit (1 edits merged)
Please save this source code
User prompt
Arena Warriors: Character Combat
Initial prompt
lest make a fighting game with character selection, every character with their own avilities, a character selection menu to chose a character for the player and one for the oponent, a single player mode(player vs a bot) , the basic move set of every character being kicks, punchs and block attacks, only 5 characters to chose, healtbars and energy bars , use a and d keys to move space bar to block attacks, z to kick and x for punch then a special range attack that consumes energy
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var EnergyBar = Container.expand(function (fighter, x, y) {
var self = Container.call(this);
self.x = x;
self.y = y;
self.fighter = fighter;
var bgBar = self.attachAsset('energyBarBg', {
anchorX: 0,
anchorY: 0
});
var energyBar = self.attachAsset('energyBar', {
anchorX: 0,
anchorY: 0
});
self.update = function () {
var energyPercent = self.fighter.energy / self.fighter.maxEnergy;
energyBar.width = 400 * energyPercent;
};
return self;
});
var Fighter = Container.expand(function (fighterType, isPlayer) {
var self = Container.call(this);
// Fighter properties
self.fighterType = fighterType || 1;
self.isPlayer = isPlayer || false;
self.maxHealth = 100;
self.health = 100;
self.maxEnergy = 100;
self.energy = 100;
self.speed = 3;
self.isBlocking = false;
self.attackCooldown = 0;
self.specialCooldown = 0;
// Create fighter graphics
var fighterGraphics = self.attachAsset('fighter' + self.fighterType, {
anchorX: 0.5,
anchorY: 1.0
});
// Fighter stats based on type
switch (self.fighterType) {
case 1:
// Red Fighter - Balanced
self.attackDamage = 15;
self.specialDamage = 25;
self.specialCost = 30;
break;
case 2:
// Blue Fighter - Fast
self.attackDamage = 12;
self.specialDamage = 20;
self.specialCost = 25;
self.speed = 4;
break;
case 3:
// Green Fighter - Strong
self.attackDamage = 18;
self.specialDamage = 30;
self.specialCost = 35;
self.speed = 2;
break;
case 4:
// Yellow Fighter - Energy Efficient
self.attackDamage = 14;
self.specialDamage = 22;
self.specialCost = 20;
break;
case 5:
// Purple Fighter - High Health
self.attackDamage = 13;
self.specialDamage = 24;
self.specialCost = 28;
self.maxHealth = 120;
self.health = 120;
break;
}
self.takeDamage = function (damage) {
if (self.isBlocking) {
damage = Math.floor(damage * 0.3);
}
self.health = Math.max(0, self.health - damage);
// Flash red when taking damage
LK.effects.flashObject(fighterGraphics, 0xFF0000, 300);
};
self.useEnergy = function (amount) {
if (self.energy >= amount) {
self.energy -= amount;
return true;
}
return false;
};
self.attack = function () {
if (self.attackCooldown <= 0) {
self.attackCooldown = 30;
return true;
}
return false;
};
self.specialAttack = function () {
if (self.specialCooldown <= 0 && self.useEnergy(self.specialCost)) {
self.specialCooldown = 90;
return true;
}
return false;
};
self.update = function () {
// Cooldown management
if (self.attackCooldown > 0) self.attackCooldown--;
if (self.specialCooldown > 0) self.specialCooldown--;
// Energy regeneration
if (self.energy < self.maxEnergy) {
self.energy = Math.min(self.maxEnergy, self.energy + 0.2);
}
};
return self;
});
var HealthBar = Container.expand(function (fighter, x, y) {
var self = Container.call(this);
self.x = x;
self.y = y;
self.fighter = fighter;
var bgBar = self.attachAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
var healthBar = self.attachAsset('healthBar', {
anchorX: 0,
anchorY: 0
});
self.update = function () {
var healthPercent = self.fighter.health / self.fighter.maxHealth;
healthBar.width = 400 * healthPercent;
};
return self;
});
var Projectile = Container.expand(function (x, y, direction, damage, owner) {
var self = Container.call(this);
self.x = x;
self.y = y;
self.direction = direction; // 1 for right, -1 for left
self.damage = damage;
self.owner = owner;
self.speed = 8;
var projectileGraphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.x += self.speed * self.direction;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2C1810
});
/****
* Game Code
****/
// Sounds
// Combat elements
// UI elements
// Character assets
// Game states
var gameState = 'characterSelect'; // 'characterSelect', 'combat', 'gameOver'
var selectedCharacter = 1;
var enemyCharacter = 2;
// Character selection
var characterSelectors = [];
var selectionBorder = null;
// Combat variables
var player = null;
var enemy = null;
var playerHealthBar = null;
var playerEnergyBar = null;
var enemyHealthBar = null;
var enemyEnergyBar = null;
var projectiles = [];
// UI elements
var titleText = new Text2('Arena Warriors', {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
LK.gui.top.addChild(titleText);
titleText.y = 50;
var instructionText = new Text2('Select Your Fighter', {
size: 50,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0.5);
// Combat controls text
var controlsText = new Text2('Left: Move | Right: Move | Center Left: Punch | Center Right: Kick | Top: Block | Bottom: Special', {
size: 30,
fill: 0xFFFFFF
});
controlsText.anchor.set(0.5, 1);
function initCharacterSelection() {
instructionText.y = 200;
game.addChild(instructionText);
// Create character selection grid
for (var i = 1; i <= 5; i++) {
var fighter = LK.getAsset('fighter' + i, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7
});
var col = (i - 1) % 3;
var row = Math.floor((i - 1) / 3);
fighter.x = 400 + col * 300;
fighter.y = 600 + row * 350;
fighter.fighterIndex = i;
characterSelectors.push(fighter);
game.addChild(fighter);
}
// Create selection border
selectionBorder = LK.getAsset('selectionBorder', {
anchorX: 0.5,
anchorY: 0.5
});
selectionBorder.alpha = 0.3;
updateSelectionBorder();
game.addChild(selectionBorder);
}
function updateSelectionBorder() {
if (selectionBorder && characterSelectors[selectedCharacter - 1]) {
selectionBorder.x = characterSelectors[selectedCharacter - 1].x;
selectionBorder.y = characterSelectors[selectedCharacter - 1].y;
}
}
function startCombat() {
gameState = 'combat';
// Clear character selection
game.removeChild(instructionText);
for (var i = 0; i < characterSelectors.length; i++) {
game.removeChild(characterSelectors[i]);
}
game.removeChild(selectionBorder);
// Create fighters
player = game.addChild(new Fighter(selectedCharacter, true));
player.x = 400;
player.y = 2200;
enemy = game.addChild(new Fighter(enemyCharacter, false));
enemy.x = 1648;
enemy.y = 2200;
// Create health and energy bars
playerHealthBar = game.addChild(new HealthBar(player, 150, 150));
playerEnergyBar = game.addChild(new EnergyBar(player, 150, 200));
enemyHealthBar = game.addChild(new HealthBar(enemy, 1498, 150));
enemyEnergyBar = game.addChild(new EnergyBar(enemy, 1498, 200));
// Add controls text
controlsText.y = 2650;
game.addChild(controlsText);
// Add player and enemy name labels
var playerLabel = new Text2('Player', {
size: 40,
fill: 0xFFFFFF
});
playerLabel.anchor.set(0, 0);
playerLabel.x = 150;
playerLabel.y = 100;
game.addChild(playerLabel);
var enemyLabel = new Text2('Enemy', {
size: 40,
fill: 0xFFFFFF
});
enemyLabel.anchor.set(1, 0);
enemyLabel.x = 1898;
enemyLabel.y = 100;
game.addChild(enemyLabel);
}
function handleCombatInput(x, y) {
if (!player || gameState !== 'combat') return;
var gameWidth = 2048;
var gameHeight = 2732;
// Determine input zones
if (x < gameWidth * 0.2) {
// Left side - Move left
if (player.x > 200) {
player.x -= player.speed * 10;
}
} else if (x > gameWidth * 0.8) {
// Right side - Move right
if (player.x < 1848) {
player.x += player.speed * 10;
}
} else if (y < gameHeight * 0.3) {
// Top center - Block
player.isBlocking = true;
LK.getSound('block').play();
} else if (y > gameHeight * 0.7) {
// Bottom center - Special attack
if (player.specialAttack()) {
var projectile = new Projectile(player.x + 50, player.y - 100, 1, player.specialDamage, player);
projectiles.push(projectile);
game.addChild(projectile);
LK.getSound('special').play();
}
} else if (x < gameWidth * 0.6) {
// Center left - Punch
if (player.attack()) {
checkMeleeHit(player, enemy, player.attackDamage);
LK.getSound('punch').play();
}
} else {
// Center right - Kick
if (player.attack()) {
checkMeleeHit(player, enemy, player.attackDamage + 3);
LK.getSound('kick').play();
}
}
}
function checkMeleeHit(attacker, target, damage) {
var distance = Math.abs(attacker.x - target.x);
if (distance < 200) {
target.takeDamage(damage);
}
}
function updateAI() {
if (!enemy || !player) return;
var distance = Math.abs(enemy.x - player.x);
// Simple AI behavior
if (LK.ticks % 60 === 0) {
var action = Math.floor(Math.random() * 4);
if (distance > 300) {
// Move closer
if (enemy.x > player.x) {
enemy.x -= enemy.speed * 8;
} else {
enemy.x += enemy.speed * 8;
}
} else if (distance < 150) {
// Attack or block
if (action === 0 && enemy.attack()) {
checkMeleeHit(enemy, player, enemy.attackDamage);
LK.getSound('punch').play();
} else if (action === 1) {
enemy.isBlocking = true;
}
} else {
// Use special attack occasionally
if (action === 0 && enemy.specialAttack()) {
var projectile = new Projectile(enemy.x - 50, enemy.y - 100, -1, enemy.specialDamage, enemy);
projectiles.push(projectile);
game.addChild(projectile);
LK.getSound('special').play();
}
}
}
// Reset blocking
if (LK.ticks % 30 === 0) {
enemy.isBlocking = false;
}
}
function checkGameOver() {
if (player && player.health <= 0) {
LK.showGameOver();
} else if (enemy && enemy.health <= 0) {
LK.showYouWin();
}
}
// Character selection input
game.down = function (x, y, obj) {
if (gameState === 'characterSelect') {
// Check which character was selected
for (var i = 0; i < characterSelectors.length; i++) {
var fighter = characterSelectors[i];
// Use x,y coordinates directly since they're already in game coordinates
if (Math.abs(x - fighter.x) < 100 && Math.abs(y - fighter.y) < 150) {
selectedCharacter = fighter.fighterIndex;
enemyCharacter = selectedCharacter % 5 + 1; // Simple enemy selection
updateSelectionBorder();
// Start combat after selection
LK.setTimeout(function () {
startCombat();
}, 500);
break;
}
}
} else if (gameState === 'combat') {
handleCombatInput(x, y);
}
};
game.up = function (x, y, obj) {
if (player && gameState === 'combat') {
player.isBlocking = false;
}
};
game.update = function () {
if (gameState === 'combat') {
// Update fighters
if (player) player.update();
if (enemy) enemy.update();
// Update UI bars
if (playerHealthBar) playerHealthBar.update();
if (playerEnergyBar) playerEnergyBar.update();
if (enemyHealthBar) enemyHealthBar.update();
if (enemyEnergyBar) enemyEnergyBar.update();
// Update projectiles
for (var i = projectiles.length - 1; i >= 0; i--) {
var proj = projectiles[i];
proj.update();
// Check projectile hits
var target = proj.owner === player ? enemy : player;
if (target && Math.abs(proj.x - target.x) < 100 && Math.abs(proj.y - target.y) < 150) {
target.takeDamage(proj.damage);
proj.destroy();
projectiles.splice(i, 1);
continue;
}
// Remove off-screen projectiles
if (proj.x < -50 || proj.x > 2098) {
proj.destroy();
projectiles.splice(i, 1);
}
}
// Update AI
updateAI();
// Check game over
checkGameOver();
}
};
// Initialize character selection screen
initCharacterSelection(); ===================================================================
--- original.js
+++ change.js
@@ -375,10 +375,10 @@
if (gameState === 'characterSelect') {
// Check which character was selected
for (var i = 0; i < characterSelectors.length; i++) {
var fighter = characterSelectors[i];
- var localPos = fighter.parent.toLocal(obj.position);
- if (Math.abs(localPos.x - fighter.x) < 100 && Math.abs(localPos.y - fighter.y) < 150) {
+ // Use x,y coordinates directly since they're already in game coordinates
+ if (Math.abs(x - fighter.x) < 100 && Math.abs(y - fighter.y) < 150) {
selectedCharacter = fighter.fighterIndex;
enemyCharacter = selectedCharacter % 5 + 1; // Simple enemy selection
updateSelectionBorder();
// Start combat after selection
transparent bubble. In-Game asset. 2d. High contrast. No shadows
shield
arm with a fist
band-aid
a little bit smaller image
hornless
whitte
whole gloves
fire
transparent kicking feet simbol. In-Game asset. 2d. High contrast. No shadows
red
2D
crouching with blue background
teeth close to bite
scratch attack
teeth
toothless open mouth
shark teeth. In-Game asset. 2d. High contrast. No shadows
simbolo transparente de bala. In-Game asset. 2d. High contrast. No shadows
transparent fist simbol. In-Game asset. 2d. High contrast. No shadows
transparent fire simbol. In-Game asset. 2d. High contrast. No shadows
right arrow. In-Game asset. 2d. High contrast. No shadows
add sand
building roof