User prompt
increase the cooldown of regular attack to 1.2 secx
User prompt
make a health potion and spawn it randomly
User prompt
make a cooldown for 1 sec to reagular attacks
User prompt
every attack deals less damage
User prompt
Please fix the bug: 'MainMenu is not defined' in or related to this line: 'var mainMenu = new MainMenu();' Line Number: 33
User prompt
Please fix the bug: 'MainMenu is not defined' in or related to this line: 'var mainMenu = new MainMenu();' Line Number: 33
User prompt
make a main menu for the game
User prompt
reduce it to 1.2 secs
User prompt
make the immobility time 1.5 secs
User prompt
if a fighter is hit with a speacial attack he cant move for 1 second
User prompt
Place the counter above the special attack button that shows how much time is left until the next special attack.
User prompt
make buttons bigger
User prompt
ıncrease the cooldown to 6 secs
User prompt
make a cooldown for 3 seconds for the speccial attack
User prompt
significantly reduce the range of regular attacks
User prompt
reduce the range of regular attacks
User prompt
make the knockback of special attack a lot more
User prompt
remove the number healthbars
User prompt
make the knockback a little stronger
User prompt
add a knockback when a fighter is hit
User prompt
move it down more
User prompt
again
User prompt
move the ground txture down
User prompt
make a throwable class
User prompt
make the player cant hold the jump button
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Arena class: handles the ground and background
var Arena = Container.expand(function () {
var self = Container.call(this);
// Attach background asset
self.bg = self.attachAsset('arena_bg', {
anchorX: 0.5,
anchorY: 1.0,
x: 2048 / 2,
y: 2732
});
// Ground Y for fighters
self.groundY = 2100;
return self;
});
// Attack class: represents a punch/kick or special move
var Attack = Container.expand(function (isSpecial) {
var self = Container.call(this);
self.isSpecial = isSpecial === true;
self.owner = null;
self.damage = self.isSpecial ? 22 : 4;
self.lifetime = self.isSpecial ? 30 : 12;
self.frame = 0;
// Attach asset
self.sprite = self.attachAsset(self.isSpecial ? 'special_attack' : 'attack', {
anchorX: 0.5,
anchorY: 0.5
});
// Explosion effect: scale up and fade in, then shrink to normal
self.sprite.scaleX = self.sprite.scaleY = 0.2;
self.sprite.alpha = 0.2;
// Explosion effect: scale up and fade in, then shrink to normal using tween plugin
tween(self.sprite, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 1
}, {
duration: 700,
onFinish: function onFinish() {
tween(self.sprite, {
scaleX: 1,
scaleY: 1
}, {
duration: 700
});
}
});
// Set owner after creation
self.setOwner = function (owner) {
self.owner = owner;
};
// Update per frame
self.update = function () {
self.frame++;
if (self.frame > self.lifetime) {
self.destroy();
}
};
return self;
});
var Fighter = Container.expand(function () {
var self = Container.call(this);
// Immobility state for special attack hit
self.immobile = false;
self.immobileTimer = 0;
// Regular attack cooldown variables
self.attackCooldown = 0; // frames left until next attack allowed
self.attackCooldownDuration = 60; // 1 second at 60fps
// Jump cooldown variables
self.jumpCooldown = 0; // frames left until next jump allowed
self.jumpCooldownDuration = 18; // 0.3s at 60fps
// Attach fighter asset (placeholder box, can be replaced with unique fighter art)
self.sprite = self.attachAsset('fighter', {
anchorX: 0.5,
anchorY: 1.0
});
// Fighter properties
self.maxHealth = 100;
self.health = 100;
self.isFacingRight = true;
self.isJumping = false;
self.isAttacking = false;
self.isSpecialReady = true;
self.specialCooldown = 360; // 6 seconds at 60fps
self.specialTimer = 0;
self.moveSpeed = 18;
self.jumpPower = -38;
self.gravity = 3.2;
self.velY = 0;
self.groundY = 2100; // Default ground Y, will be set by Arena
// Health bar
self.healthBar = new Container();
// Add outline behind healthbar background
self.healthBarOutline = self.healthBar.addChild(LK.getAsset('healthbar_bg', {
anchorX: 0,
anchorY: 0.5,
width: 308,
// 4px border on each side (300+8)
height: 58,
// 4px border on each side (50+8)
color: 0xffffff // white outline
}));
self.healthBarBg = self.healthBar.addChild(LK.getAsset('healthbar_bg', {
anchorX: 0,
anchorY: 0.5
}));
self.healthBarFg = self.healthBar.addChild(LK.getAsset('healthbar_fg', {
anchorX: 0,
anchorY: 0.5
}));
self.healthBar.y = -220;
self.addChild(self.healthBar);
// Update health bar
self.updateHealthBar = function () {
var ratio = Math.max(0, self.health / self.maxHealth);
self.healthBarFg.width = 300 * ratio;
};
// Take damage
self.takeDamage = function (amount, knockbackDir, knockbackStrength) {
// If jumping, do not take damage
if (self.isJumping) return;
self.health = Math.max(0, self.health - amount);
self.updateHealthBar();
// If hit by a special attack, become immobile for 1.2 seconds (72 frames)
if (amount >= 35) {
self.immobile = true;
self.immobileTimer = 72;
}
// Knockback: Only if not jumping and knockbackDir is provided
if (typeof knockbackDir !== "undefined" && typeof knockbackStrength !== "undefined") {
// Apply knockback as a velocity on X
if (!self.knockbackVelX) self.knockbackVelX = 0;
self.knockbackVelX = knockbackStrength * (knockbackDir > 0 ? 1 : -1);
self.knockbackFrames = 12; // frames of knockback
}
};
// Attack
self.attack = function () {
if (self.isAttacking) return;
if (self.attackCooldown > 0) return;
self.isAttacking = true;
self.attackCooldown = self.attackCooldownDuration;
var atk = new Attack(false);
// Significantly reduced range for regular attacks
atk.x = self.x + (self.isFacingRight ? 30 : -30);
atk.y = self.y - 180;
atk.setOwner(self);
self.parent.addChild(atk);
attacks.push(atk);
LK.setTimeout(function () {
self.isAttacking = false;
}, 300);
};
// Special move
self.special = function () {
if (!self.isSpecialReady) return;
self.isSpecialReady = false;
self.specialTimer = self.specialCooldown;
var atk = new Attack(true);
atk.x = self.x + (self.isFacingRight ? 180 : -180);
atk.y = self.y - 180;
atk.setOwner(self);
self.parent.addChild(atk);
attacks.push(atk);
};
// Jump
self.jump = function () {
if (self.isJumping) return;
if (self.jumpCooldown > 0) return;
self.isJumping = true;
self.velY = self.jumpPower;
self.jumpCooldown = self.jumpCooldownDuration;
};
// Update per frame
self.update = function () {
// Immobility timer
if (self.immobile) {
self.immobileTimer--;
if (self.immobileTimer <= 0) {
self.immobile = false;
self.immobileTimer = 0;
}
}
// Special cooldown
if (!self.isSpecialReady) {
self.specialTimer--;
if (self.specialTimer <= 0) {
self.isSpecialReady = true;
}
}
// Regular attack cooldown
if (self.attackCooldown > 0) {
self.attackCooldown--;
}
// Jump cooldown
if (self.jumpCooldown > 0) {
self.jumpCooldown--;
}
// Jump physics
if (self.isJumping) {
self.y += self.velY;
self.velY += self.gravity;
if (self.y >= self.groundY) {
self.y = self.groundY;
self.isJumping = false;
self.velY = 0;
}
}
// Knockback physics (applies even if not jumping)
if (self.knockbackFrames && self.knockbackFrames > 0) {
// Clamp to arena bounds
var minX = 120,
maxX = 2048 - 120;
self.x += self.knockbackVelX || 0;
if (self.x < minX) self.x = minX;
if (self.x > maxX) self.x = maxX;
// Dampen knockback
self.knockbackVelX *= 0.7;
self.knockbackFrames--;
if (self.knockbackFrames <= 0) {
self.knockbackVelX = 0;
}
}
};
// Flip sprite
self.setFacing = function (right) {
self.isFacingRight = right;
self.sprite.scaleX = right ? 1 : -1;
};
// Initialize health bar
self.updateHealthBar();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
//Minimalistic tween library which should be used for animations over time, including tinting / colouring an object, scaling, rotating, or changing any game object property.
//Note game dimensions are 2048x2732
// --- Arena setup ---
var arena = new Arena();
arena.x = 0;
arena.y = 0;
game.addChild(arena);
// --- Fixed ground platform (visual) ---
var groundHeight = 60;
var groundTileWidth = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0
}).width;
var groundY = arena.groundY - 100; // Move ground even further down by reducing the offset (was -300)
var groundTiles = [];
var numGroundTiles = Math.ceil(2048 / groundTileWidth); // Only enough to fill the screen
for (var i = 0; i < numGroundTiles; i++) {
var groundTile = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: i * groundTileWidth,
y: groundY
});
game.addChild(groundTile);
groundTiles.push(groundTile);
}
// No infinite scrolling, ground is fixed and does not move
// --- Fighters ---
var fighter1 = new Fighter();
fighter1.lastJumpPressed = false;
var fighter2 = new Fighter();
// Place fighters on opposite sides
fighter1.x = 600;
fighter1.y = arena.groundY;
fighter1.setFacing(true);
fighter2.x = 2048 - 600;
fighter2.y = arena.groundY;
fighter2.setFacing(false);
game.addChild(fighter1);
game.addChild(fighter2);
// --- Health bar GUI ---
// Removed number healthbars (Text2 healthBar1 and healthBar2)
// Move the box healthbars (fighter healthBar containers) to a more visible, symmetric place below the timer at the top center
// Remove from fighter containers and add to GUI, position symmetrically below timer
fighter1.removeChild(fighter1.healthBar);
fighter2.removeChild(fighter2.healthBar);
// Place both healthbars below the timer, offset horizontally from center
fighter1.healthBar.x = -550;
fighter1.healthBar.y = 170;
fighter2.healthBar.x = 250;
fighter2.healthBar.y = 170;
LK.gui.top.addChild(fighter1.healthBar);
LK.gui.top.addChild(fighter2.healthBar);
// --- Round and timer ---
var round = 1;
var maxRounds = 3;
var wins1 = 0;
var wins2 = 0;
var roundTime = 60 * 30; // 30 seconds at 60fps
var roundTimer = roundTime;
var timerText = new Text2('30', {
size: 80,
fill: "#fff"
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
// --- Touch controls (mobile-friendly) ---
var leftPressed = false,
rightPressed = false,
atkPressed = false,
jumpPressed = false,
spcPressed = false;
// Special attack cooldown overlay for button
var spcCooldownOverlay = LK.getAsset('healthbar_bg', {
anchorX: 0.5,
anchorY: 0.5,
width: 180,
height: 180,
color: 0x000000
});
spcCooldownOverlay.alpha = 0.5;
spcCooldownOverlay.visible = false;
spcCooldownOverlay.x = 2048 - 350;
spcCooldownOverlay.y = 2450;
game.addChild(spcCooldownOverlay);
var spcCooldownText = new Text2('3', {
size: 90,
fill: "#fff"
});
spcCooldownText.anchor.set(0.5, 0.5);
spcCooldownText.x = 2048 - 350;
spcCooldownText.y = 2450;
spcCooldownText.visible = false;
game.addChild(spcCooldownText);
// Special attack cooldown counter above the special attack button
var spcCooldownCounter = new Text2('', {
size: 60,
fill: "#fff"
});
spcCooldownCounter.anchor.set(0.5, 1.0);
// Place above the special button (btnSpc)
spcCooldownCounter.x = 2048 - 350;
spcCooldownCounter.y = 2450 - 120;
spcCooldownCounter.visible = false;
game.addChild(spcCooldownCounter);
// Control buttons (simple rectangles for now)
var btnLeft = LK.getAsset('btn_left', {
anchorX: 0.5,
anchorY: 0.5,
x: 200,
y: 2600,
scaleX: 1.8,
scaleY: 1.8
});
var btnRight = LK.getAsset('btn_right', {
anchorX: 0.5,
anchorY: 0.5,
x: 500,
y: 2600,
scaleX: 1.8,
scaleY: 1.8
});
var btnAtk = LK.getAsset('btn_atk', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - 500,
y: 2600,
scaleX: 1.8,
scaleY: 1.8
});
var btnJump = LK.getAsset('btn_jump', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - 200,
y: 2600,
scaleX: 1.8,
scaleY: 1.8
});
var btnSpc = LK.getAsset('btn_spc', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 - 350,
y: 2450,
scaleX: 1.8,
scaleY: 1.8
});
game.addChild(btnLeft);
game.addChild(btnRight);
game.addChild(btnAtk);
game.addChild(btnJump);
game.addChild(btnSpc);
// Button event helpers
btnLeft.down = function () {
leftPressed = true;
};
btnLeft.up = function () {
leftPressed = false;
};
btnRight.down = function () {
rightPressed = true;
};
btnRight.up = function () {
rightPressed = false;
};
btnAtk.down = function () {
atkPressed = true;
};
btnAtk.up = function () {
atkPressed = false;
};
btnJump.down = function () {
jumpPressed = true;
};
btnJump.up = function () {
jumpPressed = false;
};
btnSpc.down = function () {
spcPressed = true;
};
btnSpc.up = function () {
spcPressed = false;
};
// --- Attacks array ---
var attacks = [];
// --- Game update loop ---
game.update = function () {
// --- Timer ---
if (roundTimer > 0) {
roundTimer--;
timerText.setText(Math.ceil(roundTimer / 60));
}
// --- Ground is fixed, no update needed ---
// --- Player 1 controls (left side) ---
if (!fighter1.immobile) {
if (leftPressed) {
fighter1.x = Math.max(120, fighter1.x - fighter1.moveSpeed);
fighter1.setFacing(false);
}
if (rightPressed) {
fighter1.x = Math.min(2048 - 120, fighter1.x + fighter1.moveSpeed);
fighter1.setFacing(true);
}
// Only trigger jump on the frame the button is pressed (rising edge)
if (jumpPressed && !fighter1.lastJumpPressed) {
fighter1.jump();
}
if (atkPressed) {
fighter1.attack();
}
if (spcPressed) {
if (fighter1.isSpecialReady) {
fighter1.special();
}
}
}
fighter1.lastJumpPressed = jumpPressed;
// --- Special attack cooldown overlay update ---
if (!fighter1.isSpecialReady) {
spcCooldownOverlay.visible = true;
spcCooldownText.visible = true;
var secondsLeft = Math.ceil(fighter1.specialTimer / 60);
spcCooldownText.setText(secondsLeft);
// Show and update the counter above the special button
spcCooldownCounter.visible = true;
spcCooldownCounter.setText(secondsLeft + "s");
} else {
spcCooldownOverlay.visible = false;
spcCooldownText.visible = false;
spcCooldownCounter.visible = false;
}
// --- AI for fighter2 (simple: move toward player, attack if close) ---
if (!fighter2.immobile) {
var dx = fighter1.x - fighter2.x;
if (Math.abs(dx) > 180) {
if (dx < 0) {
fighter2.x -= fighter2.moveSpeed * 0.7;
fighter2.setFacing(false);
} else {
fighter2.x += fighter2.moveSpeed * 0.7;
fighter2.setFacing(true);
}
} else if (!fighter2.isAttacking && Math.random() < 0.04) {
fighter2.attack();
}
if (!fighter2.isJumping && Math.random() < 0.01) {
fighter2.jump();
}
if (fighter2.isSpecialReady && Math.random() < 0.008) {
fighter2.special();
}
}
// --- Update fighters ---
fighter1.update();
fighter2.update();
// --- Update attacks ---
for (var i = attacks.length - 1; i >= 0; i--) {
var atk = attacks[i];
atk.update();
// Remove if destroyed
if (atk.destroyed) {
attacks.splice(i, 1);
continue;
}
// Set owner if not set
if (!atk.owner) {
atk.setOwner(atk.isSpecial ? atk.x < 2048 / 2 ? fighter1 : fighter2 : fighter1);
}
// Check collision
var target = atk.owner === fighter1 ? fighter2 : fighter1;
if (atk.intersects(target) && !atk.hit) {
// Knockback direction: +1 if attacker is facing right, -1 if left
var knockbackDir = atk.owner && atk.owner.isFacingRight ? 1 : -1;
// Knockback strength: special attacks knock back a LOT more (much stronger effect)
var knockbackStrength = atk.isSpecial ? 120 : 32;
target.takeDamage(atk.damage, knockbackDir, knockbackStrength);
atk.hit = true;
atk.destroy();
// Flash on hit
LK.effects.flashObject(target, 0xff0000, 200);
// Show a visible attack effect at the hit location, rotated to match the attack direction
var hitEffect = LK.getAsset(atk.isSpecial ? 'special_attack' : 'attack', {
anchorX: 0.5,
anchorY: 0.5,
x: target.x,
y: target.y - 200
});
// Rotate the effect to match the direction the attacker is facing
if (atk.owner && atk.owner.isFacingRight === false) {
hitEffect.rotation = Math.PI; // Face left
} else {
hitEffect.rotation = 0; // Face right (default)
}
game.addChild(hitEffect);
// Animate the effect: scale up and fade out, then destroy
hitEffect.scaleX = hitEffect.scaleY = 1.2;
hitEffect.alpha = 1;
tween(hitEffect, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0
}, {
duration: 350,
onFinish: function onFinish() {
if (hitEffect && hitEffect.destroy) hitEffect.destroy();
}
});
}
}
// --- Health bar updates ---
// Removed number healthbars update
// --- Win/lose/round logic ---
var roundOver = false;
var winner = null;
if (fighter1.health <= 0) {
wins2++;
roundOver = true;
winner = 2;
} else if (fighter2.health <= 0) {
wins1++;
roundOver = true;
winner = 1;
} else if (roundTimer <= 0) {
if (fighter1.health > fighter2.health) {
wins1++;
winner = 1;
} else if (fighter2.health > fighter1.health) {
wins2++;
winner = 2;
} else {
// Draw, no one gets a win
}
roundOver = true;
}
if (roundOver) {
if (wins1 >= 2) {
LK.showYouWin();
return;
} else if (wins2 >= 2) {
LK.showGameOver();
return;
}
// Next round
round++;
roundTimer = roundTime;
fighter1.health = fighter1.maxHealth;
fighter2.health = fighter2.maxHealth;
fighter1.updateHealthBar();
fighter2.updateHealthBar();
fighter1.x = 600;
fighter2.x = 2048 - 600;
fighter1.setFacing(true);
fighter2.setFacing(false);
// Remove all attacks
for (var j = attacks.length - 1; j >= 0; j--) {
if (attacks[j].destroy) attacks[j].destroy();
}
attacks = [];
}
}; ===================================================================
--- original.js
+++ change.js