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
});
// Create 3 individual energy bars
self.energyBars = [];
for (var i = 0; i < 3; i++) {
var energyBar = self.attachAsset('energyBar', {
anchorX: 0,
anchorY: 0
});
energyBar.x = i * 135; // Space bars evenly (400/3 ≈ 133)
energyBar.width = 125; // Slightly smaller to have gaps
self.energyBars.push(energyBar);
}
self.update = function () {
// Show energy bars based on current energy level (0-3)
var energyLevel = Math.floor(self.fighter.energy / (self.fighter.maxEnergy / 3));
for (var i = 0; i < 3; i++) {
self.energyBars[i].visible = i < energyLevel;
}
};
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 = 3; // Changed to 3 energy units
self.energy = 3; // Start with full energy
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 = 15; // Reduced from 25 to 15
self.specialCost = 1; // 1 energy bar per special attack
break;
case 2:
// Blue Fighter - Fast
self.attackDamage = 12;
self.specialDamage = 12; // Reduced from 20 to 12
self.specialCost = 1; // 1 energy bar per special attack
self.speed = 4;
break;
case 3:
// Green Fighter - Strong
self.attackDamage = 18;
self.specialDamage = 18; // Reduced from 30 to 18
self.specialCost = 1; // 1 energy bar per special attack
self.speed = 2;
break;
case 4:
// Yellow Fighter - Energy Efficient
self.attackDamage = 14;
self.specialDamage = 14; // Reduced from 22 to 14
self.specialCost = 1; // 1 energy bar per special attack
break;
case 5:
// Purple Fighter - High Health
self.attackDamage = 13;
self.specialDamage = 13; // Reduced from 24 to 13
self.specialCost = 1; // 1 energy bar per special attack
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 - regenerate 1 energy every 10 seconds (600 ticks), one bar at a time
if (self.energy < self.maxEnergy && LK.ticks % 600 === 0) {
self.energy = Math.min(self.maxEnergy, self.energy + 1);
}
};
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
****/
// Game states
// Character assets
// UI elements
// Combat elements
// Sounds
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 = [];
var punchButton = null;
var kickButton = null;
var rangeButton = null;
var blockButton = null;
var punchButtonText = null;
var kickButtonText = null;
var rangeButtonText = null;
var blockButtonText = null;
var leftMoveButton = null;
var rightMoveButton = null;
var leftMoveButtonText = null;
var rightMoveButtonText = null;
// 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));
// Create combat control buttons
punchButton = LK.getAsset('punchButton', {
anchorX: 0.5,
anchorY: 0.5
});
punchButton.x = 350;
punchButton.y = 2500;
game.addChild(punchButton);
kickButton = LK.getAsset('kickButton', {
anchorX: 0.5,
anchorY: 0.5
});
kickButton.x = 700;
kickButton.y = 2500;
game.addChild(kickButton);
rangeButton = LK.getAsset('rangeButton', {
anchorX: 0.5,
anchorY: 0.5
});
rangeButton.x = 1050;
rangeButton.y = 2500;
game.addChild(rangeButton);
blockButton = LK.getAsset('blockButton', {
anchorX: 0.5,
anchorY: 0.5
});
blockButton.x = 1400;
blockButton.y = 2500;
game.addChild(blockButton);
// Create movement buttons on the right side
leftMoveButton = LK.getAsset('leftMoveButton', {
anchorX: 0.5,
anchorY: 0.5
});
leftMoveButton.x = 1750;
leftMoveButton.y = 2350;
game.addChild(leftMoveButton);
rightMoveButton = LK.getAsset('rightMoveButton', {
anchorX: 0.5,
anchorY: 0.5
});
rightMoveButton.x = 1750;
rightMoveButton.y = 2550;
game.addChild(rightMoveButton);
// Add button labels
punchButtonText = new Text2('PUNCH', {
size: 30,
fill: 0xFFFFFF
});
punchButtonText.anchor.set(0.5, 0.5);
punchButtonText.x = punchButton.x;
punchButtonText.y = punchButton.y;
game.addChild(punchButtonText);
kickButtonText = new Text2('KICK', {
size: 30,
fill: 0xFFFFFF
});
kickButtonText.anchor.set(0.5, 0.5);
kickButtonText.x = kickButton.x;
kickButtonText.y = kickButton.y;
game.addChild(kickButtonText);
rangeButtonText = new Text2('RANGE', {
size: 30,
fill: 0xFFFFFF
});
rangeButtonText.anchor.set(0.5, 0.5);
rangeButtonText.x = rangeButton.x;
rangeButtonText.y = rangeButton.y;
game.addChild(rangeButtonText);
blockButtonText = new Text2('BLOCK', {
size: 30,
fill: 0xFFFFFF
});
blockButtonText.anchor.set(0.5, 0.5);
blockButtonText.x = blockButton.x;
blockButtonText.y = blockButton.y;
game.addChild(blockButtonText);
leftMoveButtonText = new Text2('←', {
size: 60,
fill: 0xFFFFFF
});
leftMoveButtonText.anchor.set(0.5, 0.5);
leftMoveButtonText.x = leftMoveButton.x;
leftMoveButtonText.y = leftMoveButton.y;
game.addChild(leftMoveButtonText);
rightMoveButtonText = new Text2('→', {
size: 60,
fill: 0xFFFFFF
});
rightMoveButtonText.anchor.set(0.5, 0.5);
rightMoveButtonText.x = rightMoveButton.x;
rightMoveButtonText.y = rightMoveButton.y;
game.addChild(rightMoveButtonText);
// Add controls text
controlsText.setText('Tap buttons to fight! Use arrow buttons to move.');
controlsText.y = 2600;
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;
// Check button presses first
if (punchButton && Math.abs(x - punchButton.x) < 100 && Math.abs(y - punchButton.y) < 40) {
// Punch button pressed
if (player.attack()) {
checkMeleeHit(player, enemy, player.attackDamage);
LK.getSound('punch').play();
}
return;
}
if (kickButton && Math.abs(x - kickButton.x) < 100 && Math.abs(y - kickButton.y) < 40) {
// Kick button pressed
if (player.attack()) {
checkMeleeHit(player, enemy, player.attackDamage + 3);
LK.getSound('kick').play();
}
return;
}
if (rangeButton && Math.abs(x - rangeButton.x) < 100 && Math.abs(y - rangeButton.y) < 40) {
// Range attack button pressed
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();
}
return;
}
if (blockButton && Math.abs(x - blockButton.x) < 100 && Math.abs(y - blockButton.y) < 40) {
// Block button pressed
player.isBlocking = true;
LK.getSound('block').play();
return;
}
if (leftMoveButton && Math.abs(x - leftMoveButton.x) < 75 && Math.abs(y - leftMoveButton.y) < 75) {
// Left movement button pressed
if (player.x > 200) {
player.x -= player.speed * 10;
}
return;
}
if (rightMoveButton && Math.abs(x - rightMoveButton.x) < 75 && Math.abs(y - rightMoveButton.y) < 75) {
// Right movement button pressed
if (player.x < 1848) {
player.x += player.speed * 10;
}
return;
}
// Movement is now handled by dedicated buttons above
}
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() * 5);
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.attack()) {
checkMeleeHit(enemy, player, enemy.attackDamage + 3);
LK.getSound('kick').play();
} else if (action === 2) {
enemy.isBlocking = true;
}
} else {
// Medium distance - use range attacks or move strategically
if (action <= 2 && enemy.energy >= 1 && enemy.specialAttack()) {
// Use range attack when enemy has energy
var projectile = new Projectile(enemy.x - 50, enemy.y - 100, -1, enemy.specialDamage, enemy);
projectiles.push(projectile);
game.addChild(projectile);
LK.getSound('special').play();
} else if (action === 3) {
// Move closer occasionally
if (enemy.x > player.x) {
enemy.x -= enemy.speed * 4;
} else {
enemy.x += enemy.speed * 4;
}
} else if (action === 4) {
// Stay at range and block
enemy.isBlocking = true;
}
}
}
// 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 button availability visual feedback
if (rangeButtonText && player) {
if (player.energy >= player.specialCost) {
rangeButtonText.tint = 0xFFFFFF; // White when available
} else {
rangeButtonText.tint = 0x666666; // Gray when not available
}
}
// 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();
}
};
// Keyboard event handler
LK.on('keydown', function (event) {
if (gameState !== 'combat' || !player) return;
var key = event.key.toLowerCase();
if (key === 'z') {
// Z key - Punch
if (player.attack()) {
checkMeleeHit(player, enemy, player.attackDamage);
LK.getSound('punch').play();
}
} else if (key === 'x') {
// X key - Kick
if (player.attack()) {
checkMeleeHit(player, enemy, player.attackDamage + 3);
LK.getSound('kick').play();
}
} else if (key === 'c') {
// C key - Range attack (special)
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();
}
}
});
// Initialize character selection screen
initCharacterSelection();
; ===================================================================
--- original.js
+++ change.js
@@ -203,8 +203,12 @@
var punchButtonText = null;
var kickButtonText = null;
var rangeButtonText = null;
var blockButtonText = null;
+var leftMoveButton = null;
+var rightMoveButton = null;
+var leftMoveButtonText = null;
+var rightMoveButtonText = null;
// UI elements
var titleText = new Text2('Arena Warriors', {
size: 80,
fill: 0xFFFFFF
@@ -305,8 +309,23 @@
});
blockButton.x = 1400;
blockButton.y = 2500;
game.addChild(blockButton);
+ // Create movement buttons on the right side
+ leftMoveButton = LK.getAsset('leftMoveButton', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ leftMoveButton.x = 1750;
+ leftMoveButton.y = 2350;
+ game.addChild(leftMoveButton);
+ rightMoveButton = LK.getAsset('rightMoveButton', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ rightMoveButton.x = 1750;
+ rightMoveButton.y = 2550;
+ game.addChild(rightMoveButton);
// Add button labels
punchButtonText = new Text2('PUNCH', {
size: 30,
fill: 0xFFFFFF
@@ -338,10 +357,26 @@
blockButtonText.anchor.set(0.5, 0.5);
blockButtonText.x = blockButton.x;
blockButtonText.y = blockButton.y;
game.addChild(blockButtonText);
+ leftMoveButtonText = new Text2('←', {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ leftMoveButtonText.anchor.set(0.5, 0.5);
+ leftMoveButtonText.x = leftMoveButton.x;
+ leftMoveButtonText.y = leftMoveButton.y;
+ game.addChild(leftMoveButtonText);
+ rightMoveButtonText = new Text2('→', {
+ size: 60,
+ fill: 0xFFFFFF
+ });
+ rightMoveButtonText.anchor.set(0.5, 0.5);
+ rightMoveButtonText.x = rightMoveButton.x;
+ rightMoveButtonText.y = rightMoveButton.y;
+ game.addChild(rightMoveButtonText);
// Add controls text
- controlsText.setText('Tap buttons to fight! Use left/right sides to move.');
+ controlsText.setText('Tap buttons to fight! Use arrow buttons to move.');
controlsText.y = 2600;
game.addChild(controlsText);
// Add player and enemy name labels
var playerLabel = new Text2('Player', {
@@ -397,20 +432,23 @@
player.isBlocking = true;
LK.getSound('block').play();
return;
}
- // Movement controls - simplified to left and right halves
- if (x < gameWidth * 0.5) {
- // Left side - Move left
+ if (leftMoveButton && Math.abs(x - leftMoveButton.x) < 75 && Math.abs(y - leftMoveButton.y) < 75) {
+ // Left movement button pressed
if (player.x > 200) {
player.x -= player.speed * 10;
}
- } else {
- // Right side - Move right
+ return;
+ }
+ if (rightMoveButton && Math.abs(x - rightMoveButton.x) < 75 && Math.abs(y - rightMoveButton.y) < 75) {
+ // Right movement button pressed
if (player.x < 1848) {
player.x += player.speed * 10;
}
+ return;
}
+ // Movement is now handled by dedicated buttons above
}
function checkMeleeHit(attacker, target, damage) {
var distance = Math.abs(attacker.x - target.x);
if (distance < 200) {
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