User prompt
Please fix the bug: 'TypeError: right-hand side of 'in' should be an object, got null' in or related to this line: 'tween(self.weapon, {' Line Number: 239 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'TypeError: can't access property "toGlobal", obj.parent is undefined' in or related to this line: 'var localPos = joystick.parent.toLocal(obj.parent.toGlobal({' Line Number: 669
Code edit (1 edits merged)
Please save this source code
User prompt
Stickman Physics Arena
Initial prompt
Make a 2D physics-based fighting game similar to "Supreme Duelist Stickman" for mobile and PC. Game Style: Minimalistic stickman graphics with smooth ragdoll physics. Modes: Single Player (fight against AI with increasing difficulty) 2 Player Local (same device multiplayer) Endless Survival Mode Controls: Left/right joystick for movement, one attack button, and one special ability button. Weapons: Swords, spears, guns, laser weapons, random power-ups. Mechanics: Characters can pick up random weapons, physics-based hits cause knockback, environmental hazards (lava, spikes). Levels: 15 maps with different layouts and traps. Customization: Player can change stickman color, hat, and weapon skin. AI Behavior: Challenging but fair, reacts to player movement and weapon use. Sound: Cartoon-style sound effects and energetic background music. Extra: Random weapon drops every 10 seconds Slow-motion effect on final hit Simple but fun ragdoll animations
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bullet = Container.expand(function (x, y, velocityX, velocityY) {
var self = Container.call(this);
self.velocityX = velocityX;
self.velocityY = velocityY;
self.damage = 30;
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x;
self.y = y;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
// Check collision with stickmen
for (var i = 0; i < stickmen.length; i++) {
var stickman = stickmen[i];
if (stickman.isDead) continue;
var distance = Math.sqrt(Math.pow(stickman.x - self.x, 2) + Math.pow(stickman.y - self.y, 2));
if (distance < 40) {
stickman.takeDamage(self.damage, {
x: self.x,
y: self.y
});
self.destroy();
// Remove from bullets array
var index = bullets.indexOf(self);
if (index > -1) {
bullets.splice(index, 1);
}
return;
}
}
// Remove if out of bounds
if (self.x < -100 || self.x > 2148 || self.y > 2832) {
self.destroy();
var index = bullets.indexOf(self);
if (index > -1) {
bullets.splice(index, 1);
}
}
};
return self;
});
var ControlStick = Container.expand(function (x, y) {
var self = Container.call(this);
self.baseX = x;
self.baseY = y;
self.active = false;
self.inputX = 0;
self.inputY = 0;
var base = self.attachAsset('joystickBase', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6
});
var knob = self.attachAsset('joystickKnob', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.x = x;
self.y = y;
self.updateInput = function (touchX, touchY) {
if (!self.active) return;
var deltaX = touchX - self.x;
var deltaY = touchY - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
var maxDistance = 50;
if (distance > maxDistance) {
deltaX = deltaX / distance * maxDistance;
deltaY = deltaY / distance * maxDistance;
}
knob.x = deltaX;
knob.y = deltaY;
self.inputX = deltaX / maxDistance;
self.inputY = deltaY / maxDistance;
};
self.reset = function () {
self.active = false;
knob.x = 0;
knob.y = 0;
self.inputX = 0;
self.inputY = 0;
};
return self;
});
var Stickman = Container.expand(function (x, y, color, isAI) {
var self = Container.call(this);
// Properties
self.isAI = isAI || false;
self.health = 100;
self.maxHealth = 100;
self.velocityX = 0;
self.velocityY = 0;
self.grounded = false;
self.weapon = null;
self.weaponType = 'none';
self.facingRight = true;
self.attackCooldown = 0;
self.specialCooldown = 0;
self.isDead = false;
self.ragdollMode = false;
// Physics properties
self.mass = 1;
self.friction = 0.85;
self.jumpPower = 15;
self.moveSpeed = 5;
// Create body parts
self.head = self.attachAsset('stickmanHead', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -60,
tint: color || 0xFFFFFF
});
self.body = self.attachAsset('stickmanBody', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -20,
tint: color || 0xFFFFFF
});
self.leftArm = self.attachAsset('stickmanArm', {
anchorX: 0.5,
anchorY: 0.1,
x: -15,
y: -40,
tint: color || 0xFFFFFF
});
self.rightArm = self.attachAsset('stickmanArm', {
anchorX: 0.5,
anchorY: 0.1,
x: 15,
y: -40,
tint: color || 0xFFFFFF
});
self.leftLeg = self.attachAsset('stickmanLeg', {
anchorX: 0.5,
anchorY: 0.1,
x: -10,
y: 20,
tint: color || 0xFFFFFF
});
self.rightLeg = self.attachAsset('stickmanLeg', {
anchorX: 0.5,
anchorY: 0.1,
x: 10,
y: 20,
tint: color || 0xFFFFFF
});
// Position
self.x = x || 0;
self.y = y || 0;
// Movement methods
self.move = function (direction) {
if (self.isDead || self.ragdollMode) return;
self.velocityX += direction * 0.8;
self.facingRight = direction > 0;
// Animation
if (direction !== 0) {
self.animateWalk();
}
};
self.jump = function () {
if (self.isDead || self.ragdollMode || !self.grounded) return;
self.velocityY = -self.jumpPower;
self.grounded = false;
};
self.attack = function () {
if (self.isDead || self.ragdollMode || self.attackCooldown > 0) return;
self.attackCooldown = 30;
if (self.weaponType === 'sword' || self.weaponType === 'spear') {
self.meleeAttack();
} else if (self.weaponType === 'gun') {
self.shootBullet();
} else if (self.weaponType === 'laser') {
self.fireLaser();
} else {
self.punchAttack();
}
};
self.meleeAttack = function () {
var swingAngle = self.facingRight ? -Math.PI / 4 : Math.PI / 4;
if (self.weapon) {
tween(self.weapon, {
rotation: swingAngle
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self.weapon, {
rotation: 0
}, {
duration: 300
});
}
});
}
LK.getSound('swordHit').play();
// Check for hits
self.checkMeleeHit();
};
self.shootBullet = function () {
var bullet = new Bullet(self.x + (self.facingRight ? 30 : -30), self.y - 40, self.facingRight ? 15 : -15, -2);
game.addChild(bullet);
bullets.push(bullet);
LK.getSound('gunShot').play();
};
self.fireLaser = function () {
var laser = self.attachAsset('laserBeam', {
anchorX: 0,
anchorY: 0.5,
x: self.facingRight ? 30 : -430,
y: -40,
alpha: 0.8
});
// Laser damage check
self.checkLaserHit();
LK.getSound('laserFire').play();
// Remove laser after short duration
LK.setTimeout(function () {
if (laser.parent) {
laser.parent.removeChild(laser);
}
}, 200);
};
self.punchAttack = function () {
var arm = self.facingRight ? self.rightArm : self.leftArm;
var originalX = arm.x;
tween(arm, {
x: originalX + (self.facingRight ? 20 : -20)
}, {
duration: 150,
onFinish: function onFinish() {
tween(arm, {
x: originalX
}, {
duration: 200
});
}
});
self.checkMeleeHit();
};
self.checkMeleeHit = function () {
var attackRange = 80;
var attackX = self.x + (self.facingRight ? attackRange / 2 : -attackRange / 2);
for (var i = 0; i < stickmen.length; i++) {
var target = stickmen[i];
if (target === self || target.isDead) continue;
var distance = Math.abs(target.x - attackX);
var verticalDistance = Math.abs(target.y - self.y);
if (distance < attackRange && verticalDistance < 100) {
var damage = self.weaponType === 'spear' ? 40 : self.weaponType === 'sword' ? 35 : 25;
target.takeDamage(damage, self);
break;
}
}
};
self.checkLaserHit = function () {
for (var i = 0; i < stickmen.length; i++) {
var target = stickmen[i];
if (target === self || target.isDead) continue;
var inLaserPath = self.facingRight ? target.x > self.x && target.x < self.x + 400 : target.x < self.x && target.x > self.x - 400;
var verticalDistance = Math.abs(target.y - self.y);
if (inLaserPath && verticalDistance < 50) {
target.takeDamage(50, self);
}
}
};
self.takeDamage = function (damage, attacker) {
if (self.isDead) return;
self.health -= damage;
// Knockback
var knockbackForce = 8;
var direction = attacker.x < self.x ? 1 : -1;
self.velocityX += direction * knockbackForce;
self.velocityY -= 5;
// Flash red
LK.effects.flashObject(self, 0xFF0000, 300);
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
self.isDead = true;
self.ragdollMode = true;
// Drop weapon
if (self.weapon) {
self.dropWeapon();
}
LK.getSound('death').play();
// Slow motion effect
gameSpeed = 0.3;
LK.setTimeout(function () {
gameSpeed = 1.0;
}, 1000);
// Update score if player died
if (!self.isAI) {
// Game over logic handled by main game
} else {
LK.setScore(LK.getScore() + 100);
}
};
self.pickupWeapon = function (weaponType) {
self.dropWeapon();
var weaponAsset = weaponType;
self.weapon = self.attachAsset(weaponAsset, {
anchorX: 0.5,
anchorY: 0.9,
x: self.facingRight ? 20 : -20,
y: -30
});
self.weaponType = weaponType;
LK.getSound('weaponPickup').play();
};
self.dropWeapon = function () {
if (self.weapon) {
// Create weapon drop
var weaponDrop = new WeaponDrop(self.x, self.y - 40, self.weaponType);
game.addChild(weaponDrop);
weaponDrops.push(weaponDrop);
self.removeChild(self.weapon);
self.weapon = null;
self.weaponType = 'none';
}
};
self.animateWalk = function () {
if (LK.ticks % 10 === 0) {
var legSwing = Math.sin(LK.ticks * 0.2) * 0.2;
self.leftLeg.rotation = legSwing;
self.rightLeg.rotation = -legSwing;
var armSwing = Math.sin(LK.ticks * 0.2) * 0.15;
self.leftArm.rotation = -armSwing;
self.rightArm.rotation = armSwing;
}
};
self.updatePhysics = function () {
// Apply gravity
if (!self.grounded) {
self.velocityY += gravity * gameSpeed;
}
// Apply friction
self.velocityX *= self.friction;
// Update position
self.x += self.velocityX * gameSpeed;
self.y += self.velocityY * gameSpeed;
// Ground collision
if (self.y > groundY - 50) {
self.y = groundY - 50;
self.velocityY = 0;
self.grounded = true;
}
// Boundary collision
if (self.x < 50) {
self.x = 50;
self.velocityX = 0;
}
if (self.x > 1998) {
self.x = 1998;
self.velocityX = 0;
}
// Update weapon position
if (self.weapon) {
self.weapon.x = self.facingRight ? 20 : -20;
if (!self.facingRight) {
self.weapon.scaleX = -1;
} else {
self.weapon.scaleX = 1;
}
}
// Update cooldowns
if (self.attackCooldown > 0) self.attackCooldown--;
if (self.specialCooldown > 0) self.specialCooldown--;
};
self.updateAI = function () {
if (self.isDead || self.ragdollMode || !self.isAI) return;
// Find nearest enemy (player)
var target = null;
var minDistance = Infinity;
for (var i = 0; i < stickmen.length; i++) {
var enemy = stickmen[i];
if (enemy === self || enemy.isDead || enemy.isAI) continue;
var distance = Math.abs(enemy.x - self.x);
if (distance < minDistance) {
minDistance = distance;
target = enemy;
}
}
if (!target) return;
var distance = Math.abs(target.x - self.x);
var direction = target.x > self.x ? 1 : -1;
// AI Behavior
if (distance > 100) {
// Move towards target
self.move(direction * 0.7);
} else if (distance < 50) {
// Too close, back away sometimes
if (Math.random() < 0.3) {
self.move(-direction * 0.5);
}
}
// Attack when in range
if (distance < 90 && Math.random() < 0.1) {
self.attack();
}
// Jump randomly or when stuck
if (Math.random() < 0.02 || Math.abs(self.velocityX) < 0.1 && distance > 80) {
self.jump();
}
// Pick up weapons
for (var j = 0; j < weaponDrops.length; j++) {
var weapon = weaponDrops[j];
var weaponDistance = Math.abs(weapon.x - self.x);
if (weaponDistance < 60 && !self.weapon) {
weapon.pickup(self);
break;
}
}
};
self.update = function () {
self.updatePhysics();
self.updateAI();
};
return self;
});
var WeaponDrop = Container.expand(function (x, y, weaponType) {
var self = Container.call(this);
self.weaponType = weaponType;
self.pickupTimer = 0;
var weaponGraphics = self.attachAsset(weaponType, {
anchorX: 0.5,
anchorY: 0.5
});
self.x = x;
self.y = y;
self.pickup = function (stickman) {
stickman.pickupWeapon(self.weaponType);
self.destroy();
var index = weaponDrops.indexOf(self);
if (index > -1) {
weaponDrops.splice(index, 1);
}
};
self.update = function () {
// Floating animation
self.y += Math.sin(LK.ticks * 0.1) * 0.5;
// Auto-pickup timer
self.pickupTimer++;
if (self.pickupTimer > 600) {
// 10 seconds
self.destroy();
var index = weaponDrops.indexOf(self);
if (index > -1) {
weaponDrops.splice(index, 1);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Sounds
// UI Elements
// Environment
// Weapons
// Stickman body parts
// Game variables
var stickmen = [];
var bullets = [];
var weaponDrops = [];
var platforms = [];
var hazards = [];
// Physics constants
var gravity = 0.8;
var groundY = 2600;
var gameSpeed = 1.0;
// Game state
var gameMode = 'single'; // 'single', 'multiplayer', 'survival'
var currentWave = 1;
var enemiesSpawned = 0;
var maxEnemies = 2;
// Weapon spawn timer
var weaponSpawnTimer = 0;
var weaponSpawnInterval = 600; // 10 seconds at 60fps
// Controls
var joystick;
var attackButton;
var specialButton;
var dragNode = null;
// Create ground
var ground = game.addChild(LK.getAsset('ground', {
anchorX: 0.5,
anchorY: 0,
x: 1024,
y: groundY
}));
// Create platforms
var platform1 = game.addChild(LK.getAsset('platform', {
anchorX: 0.5,
anchorY: 0,
x: 512,
y: groundY - 200
}));
platforms.push(platform1);
var platform2 = game.addChild(LK.getAsset('platform', {
anchorX: 0.5,
anchorY: 0,
x: 1536,
y: groundY - 300
}));
platforms.push(platform2);
// Create environmental hazards
var lava1 = game.addChild(LK.getAsset('lava', {
anchorX: 0.5,
anchorY: 0,
x: 800,
y: groundY
}));
hazards.push({
obj: lava1,
type: 'lava'
});
var spike1 = game.addChild(LK.getAsset('spike', {
anchorX: 0.5,
anchorY: 0,
x: 1200,
y: groundY - 60
}));
hazards.push({
obj: spike1,
type: 'spike'
});
// Create player
var player = new Stickman(300, groundY - 100, 0x00FF00, false);
game.addChild(player);
stickmen.push(player);
// Create initial enemies
for (var i = 0; i < maxEnemies; i++) {
var enemy = new Stickman(1500 + i * 100, groundY - 100, 0xFF0000, true);
game.addChild(enemy);
stickmen.push(enemy);
enemiesSpawned++;
}
// Create controls
joystick = new ControlStick(150, 2550);
LK.gui.bottomLeft.addChild(joystick);
attackButton = LK.gui.bottomRight.addChild(LK.getAsset('attackButton', {
anchorX: 0.5,
anchorY: 0.5,
x: -150,
y: -150,
alpha: 0.7
}));
specialButton = LK.gui.bottomRight.addChild(LK.getAsset('specialButton', {
anchorX: 0.5,
anchorY: 0.5,
x: -150,
y: -280,
alpha: 0.7
}));
// Health bar
var healthBarBg = LK.gui.topLeft.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 120,
y: 50,
width: 200,
height: 20,
tint: 0x333333
}));
var healthBar = LK.gui.topLeft.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 120,
y: 50,
width: 200,
height: 20,
tint: 0x00FF00
}));
// Score display
var scoreText = new Text2('Score: 0', {
size: 40,
fill: '#FFFFFF'
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
// Wave display
var waveText = new Text2('Wave: 1', {
size: 35,
fill: '#FFFF00'
});
waveText.anchor.set(1, 0);
LK.gui.topRight.addChild(waveText);
// Control handlers
game.down = function (x, y, obj) {
var localPos = joystick.parent.toLocal(obj.parent.toGlobal({
x: x,
y: y
}));
var distance = Math.sqrt(Math.pow(localPos.x - joystick.x, 2) + Math.pow(localPos.y - joystick.y, 2));
if (distance < 80) {
joystick.active = true;
joystick.updateInput(localPos.x, localPos.y);
dragNode = 'joystick';
}
// Check attack button
var attackPos = attackButton.parent.toLocal(obj.parent.toGlobal({
x: x,
y: y
}));
var attackDistance = Math.sqrt(Math.pow(attackPos.x - attackButton.x, 2) + Math.pow(attackPos.y - attackButton.y, 2));
if (attackDistance < 60) {
player.attack();
}
// Check special button
var specialPos = specialButton.parent.toLocal(obj.parent.toGlobal({
x: x,
y: y
}));
var specialDistance = Math.sqrt(Math.pow(specialPos.x - specialButton.x, 2) + Math.pow(specialPos.y - specialButton.y, 2));
if (specialDistance < 50 && player.specialCooldown === 0) {
player.jump();
player.specialCooldown = 120; // 2 second cooldown
}
};
game.move = function (x, y, obj) {
if (dragNode === 'joystick') {
var localPos = joystick.parent.toLocal(obj.parent.toGlobal({
x: x,
y: y
}));
joystick.updateInput(localPos.x, localPos.y);
}
};
game.up = function (x, y, obj) {
if (dragNode === 'joystick') {
joystick.reset();
}
dragNode = null;
};
// Spawn random weapon
function spawnRandomWeapon() {
var weaponTypes = ['sword', 'spear', 'gun', 'laser'];
var randomType = weaponTypes[Math.floor(Math.random() * weaponTypes.length)];
var randomX = 200 + Math.random() * 1648;
var weaponDrop = new WeaponDrop(randomX, groundY - 200, randomType);
game.addChild(weaponDrop);
weaponDrops.push(weaponDrop);
}
// Check hazard collisions
function checkHazardCollisions() {
for (var i = 0; i < stickmen.length; i++) {
var stickman = stickmen[i];
if (stickman.isDead) continue;
for (var j = 0; j < hazards.length; j++) {
var hazard = hazards[j];
var distance = Math.abs(stickman.x - hazard.obj.x);
if (distance < 60 && Math.abs(stickman.y - hazard.obj.y) < 60) {
if (hazard.type === 'lava') {
stickman.takeDamage(5, {
x: hazard.obj.x,
y: hazard.obj.y
});
} else if (hazard.type === 'spike') {
stickman.takeDamage(20, {
x: hazard.obj.x,
y: hazard.obj.y
});
}
}
}
}
}
// Spawn new enemies
function spawnEnemies() {
var aliveEnemies = 0;
for (var i = 0; i < stickmen.length; i++) {
if (stickmen[i].isAI && !stickmen[i].isDead) {
aliveEnemies++;
}
}
if (aliveEnemies === 0) {
// Next wave
currentWave++;
maxEnemies = Math.min(2 + Math.floor(currentWave / 2), 6);
for (var j = 0; j < maxEnemies; j++) {
var spawnX = Math.random() < 0.5 ? 100 : 1900;
var enemy = new Stickman(spawnX, groundY - 100, 0xFF0000, true);
// Give some enemies weapons based on wave
if (currentWave > 2 && Math.random() < 0.4) {
var weaponTypes = ['sword', 'spear'];
if (currentWave > 4) weaponTypes.push('gun');
if (currentWave > 6) weaponTypes.push('laser');
var randomWeapon = weaponTypes[Math.floor(Math.random() * weaponTypes.length)];
enemy.pickupWeapon(randomWeapon);
}
game.addChild(enemy);
stickmen.push(enemy);
}
waveText.setText('Wave: ' + currentWave);
}
}
// Main game loop
game.update = function () {
// Apply game speed (for slow motion effects)
if (gameSpeed < 1.0) {
gameSpeed = Math.min(gameSpeed + 0.02, 1.0);
}
// Update player movement from joystick
if (joystick.active && !player.isDead) {
if (Math.abs(joystick.inputX) > 0.2) {
player.move(joystick.inputX);
}
}
// Update all stickmen
for (var i = stickmen.length - 1; i >= 0; i--) {
var stickman = stickmen[i];
if (stickman.isDead && stickman.ragdollMode) {
// Remove dead stickmen after some time
if (LK.ticks % 600 === 0) {
// 10 seconds
stickman.destroy();
stickmen.splice(i, 1);
}
}
}
// Update bullets
for (var j = bullets.length - 1; j >= 0; j--) {
// Bullet update is handled in bullet class
}
// Update weapon drops
for (var k = weaponDrops.length - 1; k >= 0; k--) {
var weaponDrop = weaponDrops[k];
// Check player pickup
var distance = Math.abs(player.x - weaponDrop.x);
if (distance < 60 && Math.abs(player.y - weaponDrop.y) < 60 && !player.weapon) {
weaponDrop.pickup(player);
}
}
// Spawn weapons periodically
weaponSpawnTimer++;
if (weaponSpawnTimer >= weaponSpawnInterval) {
spawnRandomWeapon();
weaponSpawnTimer = 0;
}
// Check hazard collisions
checkHazardCollisions();
// Spawn new enemies
if (gameMode === 'single') {
spawnEnemies();
}
// Update UI
scoreText.setText('Score: ' + LK.getScore());
// Update health bar
var healthPercent = Math.max(0, player.health / player.maxHealth);
healthBar.width = 200 * healthPercent;
if (healthPercent > 0.6) {
healthBar.tint = 0x00FF00;
} else if (healthPercent > 0.3) {
healthBar.tint = 0xFFFF00;
} else {
healthBar.tint = 0xFF0000;
}
// Game over check
if (player.isDead) {
LK.showGameOver();
}
// Camera follow player (simple implementation)
var targetX = -player.x + 1024;
targetX = Math.max(-500, Math.min(500, targetX));
game.x += (targetX - game.x) * 0.05;
};
// Start background music
LK.playMusic('battleMusic'); ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,793 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1");
+
+/****
+* Classes
+****/
+var Bullet = Container.expand(function (x, y, velocityX, velocityY) {
+ var self = Container.call(this);
+ self.velocityX = velocityX;
+ self.velocityY = velocityY;
+ self.damage = 30;
+ var bulletGraphics = self.attachAsset('bullet', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.x = x;
+ self.y = y;
+ self.update = function () {
+ self.x += self.velocityX;
+ self.y += self.velocityY;
+ // Check collision with stickmen
+ for (var i = 0; i < stickmen.length; i++) {
+ var stickman = stickmen[i];
+ if (stickman.isDead) continue;
+ var distance = Math.sqrt(Math.pow(stickman.x - self.x, 2) + Math.pow(stickman.y - self.y, 2));
+ if (distance < 40) {
+ stickman.takeDamage(self.damage, {
+ x: self.x,
+ y: self.y
+ });
+ self.destroy();
+ // Remove from bullets array
+ var index = bullets.indexOf(self);
+ if (index > -1) {
+ bullets.splice(index, 1);
+ }
+ return;
+ }
+ }
+ // Remove if out of bounds
+ if (self.x < -100 || self.x > 2148 || self.y > 2832) {
+ self.destroy();
+ var index = bullets.indexOf(self);
+ if (index > -1) {
+ bullets.splice(index, 1);
+ }
+ }
+ };
+ return self;
+});
+var ControlStick = Container.expand(function (x, y) {
+ var self = Container.call(this);
+ self.baseX = x;
+ self.baseY = y;
+ self.active = false;
+ self.inputX = 0;
+ self.inputY = 0;
+ var base = self.attachAsset('joystickBase', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.6
+ });
+ var knob = self.attachAsset('joystickKnob', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.8
+ });
+ self.x = x;
+ self.y = y;
+ self.updateInput = function (touchX, touchY) {
+ if (!self.active) return;
+ var deltaX = touchX - self.x;
+ var deltaY = touchY - self.y;
+ var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
+ var maxDistance = 50;
+ if (distance > maxDistance) {
+ deltaX = deltaX / distance * maxDistance;
+ deltaY = deltaY / distance * maxDistance;
+ }
+ knob.x = deltaX;
+ knob.y = deltaY;
+ self.inputX = deltaX / maxDistance;
+ self.inputY = deltaY / maxDistance;
+ };
+ self.reset = function () {
+ self.active = false;
+ knob.x = 0;
+ knob.y = 0;
+ self.inputX = 0;
+ self.inputY = 0;
+ };
+ return self;
+});
+var Stickman = Container.expand(function (x, y, color, isAI) {
+ var self = Container.call(this);
+ // Properties
+ self.isAI = isAI || false;
+ self.health = 100;
+ self.maxHealth = 100;
+ self.velocityX = 0;
+ self.velocityY = 0;
+ self.grounded = false;
+ self.weapon = null;
+ self.weaponType = 'none';
+ self.facingRight = true;
+ self.attackCooldown = 0;
+ self.specialCooldown = 0;
+ self.isDead = false;
+ self.ragdollMode = false;
+ // Physics properties
+ self.mass = 1;
+ self.friction = 0.85;
+ self.jumpPower = 15;
+ self.moveSpeed = 5;
+ // Create body parts
+ self.head = self.attachAsset('stickmanHead', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 0,
+ y: -60,
+ tint: color || 0xFFFFFF
+ });
+ self.body = self.attachAsset('stickmanBody', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 0,
+ y: -20,
+ tint: color || 0xFFFFFF
+ });
+ self.leftArm = self.attachAsset('stickmanArm', {
+ anchorX: 0.5,
+ anchorY: 0.1,
+ x: -15,
+ y: -40,
+ tint: color || 0xFFFFFF
+ });
+ self.rightArm = self.attachAsset('stickmanArm', {
+ anchorX: 0.5,
+ anchorY: 0.1,
+ x: 15,
+ y: -40,
+ tint: color || 0xFFFFFF
+ });
+ self.leftLeg = self.attachAsset('stickmanLeg', {
+ anchorX: 0.5,
+ anchorY: 0.1,
+ x: -10,
+ y: 20,
+ tint: color || 0xFFFFFF
+ });
+ self.rightLeg = self.attachAsset('stickmanLeg', {
+ anchorX: 0.5,
+ anchorY: 0.1,
+ x: 10,
+ y: 20,
+ tint: color || 0xFFFFFF
+ });
+ // Position
+ self.x = x || 0;
+ self.y = y || 0;
+ // Movement methods
+ self.move = function (direction) {
+ if (self.isDead || self.ragdollMode) return;
+ self.velocityX += direction * 0.8;
+ self.facingRight = direction > 0;
+ // Animation
+ if (direction !== 0) {
+ self.animateWalk();
+ }
+ };
+ self.jump = function () {
+ if (self.isDead || self.ragdollMode || !self.grounded) return;
+ self.velocityY = -self.jumpPower;
+ self.grounded = false;
+ };
+ self.attack = function () {
+ if (self.isDead || self.ragdollMode || self.attackCooldown > 0) return;
+ self.attackCooldown = 30;
+ if (self.weaponType === 'sword' || self.weaponType === 'spear') {
+ self.meleeAttack();
+ } else if (self.weaponType === 'gun') {
+ self.shootBullet();
+ } else if (self.weaponType === 'laser') {
+ self.fireLaser();
+ } else {
+ self.punchAttack();
+ }
+ };
+ self.meleeAttack = function () {
+ var swingAngle = self.facingRight ? -Math.PI / 4 : Math.PI / 4;
+ if (self.weapon) {
+ tween(self.weapon, {
+ rotation: swingAngle
+ }, {
+ duration: 200,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(self.weapon, {
+ rotation: 0
+ }, {
+ duration: 300
+ });
+ }
+ });
+ }
+ LK.getSound('swordHit').play();
+ // Check for hits
+ self.checkMeleeHit();
+ };
+ self.shootBullet = function () {
+ var bullet = new Bullet(self.x + (self.facingRight ? 30 : -30), self.y - 40, self.facingRight ? 15 : -15, -2);
+ game.addChild(bullet);
+ bullets.push(bullet);
+ LK.getSound('gunShot').play();
+ };
+ self.fireLaser = function () {
+ var laser = self.attachAsset('laserBeam', {
+ anchorX: 0,
+ anchorY: 0.5,
+ x: self.facingRight ? 30 : -430,
+ y: -40,
+ alpha: 0.8
+ });
+ // Laser damage check
+ self.checkLaserHit();
+ LK.getSound('laserFire').play();
+ // Remove laser after short duration
+ LK.setTimeout(function () {
+ if (laser.parent) {
+ laser.parent.removeChild(laser);
+ }
+ }, 200);
+ };
+ self.punchAttack = function () {
+ var arm = self.facingRight ? self.rightArm : self.leftArm;
+ var originalX = arm.x;
+ tween(arm, {
+ x: originalX + (self.facingRight ? 20 : -20)
+ }, {
+ duration: 150,
+ onFinish: function onFinish() {
+ tween(arm, {
+ x: originalX
+ }, {
+ duration: 200
+ });
+ }
+ });
+ self.checkMeleeHit();
+ };
+ self.checkMeleeHit = function () {
+ var attackRange = 80;
+ var attackX = self.x + (self.facingRight ? attackRange / 2 : -attackRange / 2);
+ for (var i = 0; i < stickmen.length; i++) {
+ var target = stickmen[i];
+ if (target === self || target.isDead) continue;
+ var distance = Math.abs(target.x - attackX);
+ var verticalDistance = Math.abs(target.y - self.y);
+ if (distance < attackRange && verticalDistance < 100) {
+ var damage = self.weaponType === 'spear' ? 40 : self.weaponType === 'sword' ? 35 : 25;
+ target.takeDamage(damage, self);
+ break;
+ }
+ }
+ };
+ self.checkLaserHit = function () {
+ for (var i = 0; i < stickmen.length; i++) {
+ var target = stickmen[i];
+ if (target === self || target.isDead) continue;
+ var inLaserPath = self.facingRight ? target.x > self.x && target.x < self.x + 400 : target.x < self.x && target.x > self.x - 400;
+ var verticalDistance = Math.abs(target.y - self.y);
+ if (inLaserPath && verticalDistance < 50) {
+ target.takeDamage(50, self);
+ }
+ }
+ };
+ self.takeDamage = function (damage, attacker) {
+ if (self.isDead) return;
+ self.health -= damage;
+ // Knockback
+ var knockbackForce = 8;
+ var direction = attacker.x < self.x ? 1 : -1;
+ self.velocityX += direction * knockbackForce;
+ self.velocityY -= 5;
+ // Flash red
+ LK.effects.flashObject(self, 0xFF0000, 300);
+ if (self.health <= 0) {
+ self.die();
+ }
+ };
+ self.die = function () {
+ self.isDead = true;
+ self.ragdollMode = true;
+ // Drop weapon
+ if (self.weapon) {
+ self.dropWeapon();
+ }
+ LK.getSound('death').play();
+ // Slow motion effect
+ gameSpeed = 0.3;
+ LK.setTimeout(function () {
+ gameSpeed = 1.0;
+ }, 1000);
+ // Update score if player died
+ if (!self.isAI) {
+ // Game over logic handled by main game
+ } else {
+ LK.setScore(LK.getScore() + 100);
+ }
+ };
+ self.pickupWeapon = function (weaponType) {
+ self.dropWeapon();
+ var weaponAsset = weaponType;
+ self.weapon = self.attachAsset(weaponAsset, {
+ anchorX: 0.5,
+ anchorY: 0.9,
+ x: self.facingRight ? 20 : -20,
+ y: -30
+ });
+ self.weaponType = weaponType;
+ LK.getSound('weaponPickup').play();
+ };
+ self.dropWeapon = function () {
+ if (self.weapon) {
+ // Create weapon drop
+ var weaponDrop = new WeaponDrop(self.x, self.y - 40, self.weaponType);
+ game.addChild(weaponDrop);
+ weaponDrops.push(weaponDrop);
+ self.removeChild(self.weapon);
+ self.weapon = null;
+ self.weaponType = 'none';
+ }
+ };
+ self.animateWalk = function () {
+ if (LK.ticks % 10 === 0) {
+ var legSwing = Math.sin(LK.ticks * 0.2) * 0.2;
+ self.leftLeg.rotation = legSwing;
+ self.rightLeg.rotation = -legSwing;
+ var armSwing = Math.sin(LK.ticks * 0.2) * 0.15;
+ self.leftArm.rotation = -armSwing;
+ self.rightArm.rotation = armSwing;
+ }
+ };
+ self.updatePhysics = function () {
+ // Apply gravity
+ if (!self.grounded) {
+ self.velocityY += gravity * gameSpeed;
+ }
+ // Apply friction
+ self.velocityX *= self.friction;
+ // Update position
+ self.x += self.velocityX * gameSpeed;
+ self.y += self.velocityY * gameSpeed;
+ // Ground collision
+ if (self.y > groundY - 50) {
+ self.y = groundY - 50;
+ self.velocityY = 0;
+ self.grounded = true;
+ }
+ // Boundary collision
+ if (self.x < 50) {
+ self.x = 50;
+ self.velocityX = 0;
+ }
+ if (self.x > 1998) {
+ self.x = 1998;
+ self.velocityX = 0;
+ }
+ // Update weapon position
+ if (self.weapon) {
+ self.weapon.x = self.facingRight ? 20 : -20;
+ if (!self.facingRight) {
+ self.weapon.scaleX = -1;
+ } else {
+ self.weapon.scaleX = 1;
+ }
+ }
+ // Update cooldowns
+ if (self.attackCooldown > 0) self.attackCooldown--;
+ if (self.specialCooldown > 0) self.specialCooldown--;
+ };
+ self.updateAI = function () {
+ if (self.isDead || self.ragdollMode || !self.isAI) return;
+ // Find nearest enemy (player)
+ var target = null;
+ var minDistance = Infinity;
+ for (var i = 0; i < stickmen.length; i++) {
+ var enemy = stickmen[i];
+ if (enemy === self || enemy.isDead || enemy.isAI) continue;
+ var distance = Math.abs(enemy.x - self.x);
+ if (distance < minDistance) {
+ minDistance = distance;
+ target = enemy;
+ }
+ }
+ if (!target) return;
+ var distance = Math.abs(target.x - self.x);
+ var direction = target.x > self.x ? 1 : -1;
+ // AI Behavior
+ if (distance > 100) {
+ // Move towards target
+ self.move(direction * 0.7);
+ } else if (distance < 50) {
+ // Too close, back away sometimes
+ if (Math.random() < 0.3) {
+ self.move(-direction * 0.5);
+ }
+ }
+ // Attack when in range
+ if (distance < 90 && Math.random() < 0.1) {
+ self.attack();
+ }
+ // Jump randomly or when stuck
+ if (Math.random() < 0.02 || Math.abs(self.velocityX) < 0.1 && distance > 80) {
+ self.jump();
+ }
+ // Pick up weapons
+ for (var j = 0; j < weaponDrops.length; j++) {
+ var weapon = weaponDrops[j];
+ var weaponDistance = Math.abs(weapon.x - self.x);
+ if (weaponDistance < 60 && !self.weapon) {
+ weapon.pickup(self);
+ break;
+ }
+ }
+ };
+ self.update = function () {
+ self.updatePhysics();
+ self.updateAI();
+ };
+ return self;
+});
+var WeaponDrop = Container.expand(function (x, y, weaponType) {
+ var self = Container.call(this);
+ self.weaponType = weaponType;
+ self.pickupTimer = 0;
+ var weaponGraphics = self.attachAsset(weaponType, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.x = x;
+ self.y = y;
+ self.pickup = function (stickman) {
+ stickman.pickupWeapon(self.weaponType);
+ self.destroy();
+ var index = weaponDrops.indexOf(self);
+ if (index > -1) {
+ weaponDrops.splice(index, 1);
+ }
+ };
+ self.update = function () {
+ // Floating animation
+ self.y += Math.sin(LK.ticks * 0.1) * 0.5;
+ // Auto-pickup timer
+ self.pickupTimer++;
+ if (self.pickupTimer > 600) {
+ // 10 seconds
+ self.destroy();
+ var index = weaponDrops.indexOf(self);
+ if (index > -1) {
+ weaponDrops.splice(index, 1);
+ }
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x87CEEB
+});
+
+/****
+* Game Code
+****/
+// Sounds
+// UI Elements
+// Environment
+// Weapons
+// Stickman body parts
+// Game variables
+var stickmen = [];
+var bullets = [];
+var weaponDrops = [];
+var platforms = [];
+var hazards = [];
+// Physics constants
+var gravity = 0.8;
+var groundY = 2600;
+var gameSpeed = 1.0;
+// Game state
+var gameMode = 'single'; // 'single', 'multiplayer', 'survival'
+var currentWave = 1;
+var enemiesSpawned = 0;
+var maxEnemies = 2;
+// Weapon spawn timer
+var weaponSpawnTimer = 0;
+var weaponSpawnInterval = 600; // 10 seconds at 60fps
+// Controls
+var joystick;
+var attackButton;
+var specialButton;
+var dragNode = null;
+// Create ground
+var ground = game.addChild(LK.getAsset('ground', {
+ anchorX: 0.5,
+ anchorY: 0,
+ x: 1024,
+ y: groundY
+}));
+// Create platforms
+var platform1 = game.addChild(LK.getAsset('platform', {
+ anchorX: 0.5,
+ anchorY: 0,
+ x: 512,
+ y: groundY - 200
+}));
+platforms.push(platform1);
+var platform2 = game.addChild(LK.getAsset('platform', {
+ anchorX: 0.5,
+ anchorY: 0,
+ x: 1536,
+ y: groundY - 300
+}));
+platforms.push(platform2);
+// Create environmental hazards
+var lava1 = game.addChild(LK.getAsset('lava', {
+ anchorX: 0.5,
+ anchorY: 0,
+ x: 800,
+ y: groundY
+}));
+hazards.push({
+ obj: lava1,
+ type: 'lava'
+});
+var spike1 = game.addChild(LK.getAsset('spike', {
+ anchorX: 0.5,
+ anchorY: 0,
+ x: 1200,
+ y: groundY - 60
+}));
+hazards.push({
+ obj: spike1,
+ type: 'spike'
+});
+// Create player
+var player = new Stickman(300, groundY - 100, 0x00FF00, false);
+game.addChild(player);
+stickmen.push(player);
+// Create initial enemies
+for (var i = 0; i < maxEnemies; i++) {
+ var enemy = new Stickman(1500 + i * 100, groundY - 100, 0xFF0000, true);
+ game.addChild(enemy);
+ stickmen.push(enemy);
+ enemiesSpawned++;
+}
+// Create controls
+joystick = new ControlStick(150, 2550);
+LK.gui.bottomLeft.addChild(joystick);
+attackButton = LK.gui.bottomRight.addChild(LK.getAsset('attackButton', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: -150,
+ y: -150,
+ alpha: 0.7
+}));
+specialButton = LK.gui.bottomRight.addChild(LK.getAsset('specialButton', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: -150,
+ y: -280,
+ alpha: 0.7
+}));
+// Health bar
+var healthBarBg = LK.gui.topLeft.addChild(LK.getAsset('ground', {
+ anchorX: 0,
+ anchorY: 0,
+ x: 120,
+ y: 50,
+ width: 200,
+ height: 20,
+ tint: 0x333333
+}));
+var healthBar = LK.gui.topLeft.addChild(LK.getAsset('ground', {
+ anchorX: 0,
+ anchorY: 0,
+ x: 120,
+ y: 50,
+ width: 200,
+ height: 20,
+ tint: 0x00FF00
+}));
+// Score display
+var scoreText = new Text2('Score: 0', {
+ size: 40,
+ fill: '#FFFFFF'
+});
+scoreText.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreText);
+// Wave display
+var waveText = new Text2('Wave: 1', {
+ size: 35,
+ fill: '#FFFF00'
+});
+waveText.anchor.set(1, 0);
+LK.gui.topRight.addChild(waveText);
+// Control handlers
+game.down = function (x, y, obj) {
+ var localPos = joystick.parent.toLocal(obj.parent.toGlobal({
+ x: x,
+ y: y
+ }));
+ var distance = Math.sqrt(Math.pow(localPos.x - joystick.x, 2) + Math.pow(localPos.y - joystick.y, 2));
+ if (distance < 80) {
+ joystick.active = true;
+ joystick.updateInput(localPos.x, localPos.y);
+ dragNode = 'joystick';
+ }
+ // Check attack button
+ var attackPos = attackButton.parent.toLocal(obj.parent.toGlobal({
+ x: x,
+ y: y
+ }));
+ var attackDistance = Math.sqrt(Math.pow(attackPos.x - attackButton.x, 2) + Math.pow(attackPos.y - attackButton.y, 2));
+ if (attackDistance < 60) {
+ player.attack();
+ }
+ // Check special button
+ var specialPos = specialButton.parent.toLocal(obj.parent.toGlobal({
+ x: x,
+ y: y
+ }));
+ var specialDistance = Math.sqrt(Math.pow(specialPos.x - specialButton.x, 2) + Math.pow(specialPos.y - specialButton.y, 2));
+ if (specialDistance < 50 && player.specialCooldown === 0) {
+ player.jump();
+ player.specialCooldown = 120; // 2 second cooldown
+ }
+};
+game.move = function (x, y, obj) {
+ if (dragNode === 'joystick') {
+ var localPos = joystick.parent.toLocal(obj.parent.toGlobal({
+ x: x,
+ y: y
+ }));
+ joystick.updateInput(localPos.x, localPos.y);
+ }
+};
+game.up = function (x, y, obj) {
+ if (dragNode === 'joystick') {
+ joystick.reset();
+ }
+ dragNode = null;
+};
+// Spawn random weapon
+function spawnRandomWeapon() {
+ var weaponTypes = ['sword', 'spear', 'gun', 'laser'];
+ var randomType = weaponTypes[Math.floor(Math.random() * weaponTypes.length)];
+ var randomX = 200 + Math.random() * 1648;
+ var weaponDrop = new WeaponDrop(randomX, groundY - 200, randomType);
+ game.addChild(weaponDrop);
+ weaponDrops.push(weaponDrop);
+}
+// Check hazard collisions
+function checkHazardCollisions() {
+ for (var i = 0; i < stickmen.length; i++) {
+ var stickman = stickmen[i];
+ if (stickman.isDead) continue;
+ for (var j = 0; j < hazards.length; j++) {
+ var hazard = hazards[j];
+ var distance = Math.abs(stickman.x - hazard.obj.x);
+ if (distance < 60 && Math.abs(stickman.y - hazard.obj.y) < 60) {
+ if (hazard.type === 'lava') {
+ stickman.takeDamage(5, {
+ x: hazard.obj.x,
+ y: hazard.obj.y
+ });
+ } else if (hazard.type === 'spike') {
+ stickman.takeDamage(20, {
+ x: hazard.obj.x,
+ y: hazard.obj.y
+ });
+ }
+ }
+ }
+ }
+}
+// Spawn new enemies
+function spawnEnemies() {
+ var aliveEnemies = 0;
+ for (var i = 0; i < stickmen.length; i++) {
+ if (stickmen[i].isAI && !stickmen[i].isDead) {
+ aliveEnemies++;
+ }
+ }
+ if (aliveEnemies === 0) {
+ // Next wave
+ currentWave++;
+ maxEnemies = Math.min(2 + Math.floor(currentWave / 2), 6);
+ for (var j = 0; j < maxEnemies; j++) {
+ var spawnX = Math.random() < 0.5 ? 100 : 1900;
+ var enemy = new Stickman(spawnX, groundY - 100, 0xFF0000, true);
+ // Give some enemies weapons based on wave
+ if (currentWave > 2 && Math.random() < 0.4) {
+ var weaponTypes = ['sword', 'spear'];
+ if (currentWave > 4) weaponTypes.push('gun');
+ if (currentWave > 6) weaponTypes.push('laser');
+ var randomWeapon = weaponTypes[Math.floor(Math.random() * weaponTypes.length)];
+ enemy.pickupWeapon(randomWeapon);
+ }
+ game.addChild(enemy);
+ stickmen.push(enemy);
+ }
+ waveText.setText('Wave: ' + currentWave);
+ }
+}
+// Main game loop
+game.update = function () {
+ // Apply game speed (for slow motion effects)
+ if (gameSpeed < 1.0) {
+ gameSpeed = Math.min(gameSpeed + 0.02, 1.0);
+ }
+ // Update player movement from joystick
+ if (joystick.active && !player.isDead) {
+ if (Math.abs(joystick.inputX) > 0.2) {
+ player.move(joystick.inputX);
+ }
+ }
+ // Update all stickmen
+ for (var i = stickmen.length - 1; i >= 0; i--) {
+ var stickman = stickmen[i];
+ if (stickman.isDead && stickman.ragdollMode) {
+ // Remove dead stickmen after some time
+ if (LK.ticks % 600 === 0) {
+ // 10 seconds
+ stickman.destroy();
+ stickmen.splice(i, 1);
+ }
+ }
+ }
+ // Update bullets
+ for (var j = bullets.length - 1; j >= 0; j--) {
+ // Bullet update is handled in bullet class
+ }
+ // Update weapon drops
+ for (var k = weaponDrops.length - 1; k >= 0; k--) {
+ var weaponDrop = weaponDrops[k];
+ // Check player pickup
+ var distance = Math.abs(player.x - weaponDrop.x);
+ if (distance < 60 && Math.abs(player.y - weaponDrop.y) < 60 && !player.weapon) {
+ weaponDrop.pickup(player);
+ }
+ }
+ // Spawn weapons periodically
+ weaponSpawnTimer++;
+ if (weaponSpawnTimer >= weaponSpawnInterval) {
+ spawnRandomWeapon();
+ weaponSpawnTimer = 0;
+ }
+ // Check hazard collisions
+ checkHazardCollisions();
+ // Spawn new enemies
+ if (gameMode === 'single') {
+ spawnEnemies();
+ }
+ // Update UI
+ scoreText.setText('Score: ' + LK.getScore());
+ // Update health bar
+ var healthPercent = Math.max(0, player.health / player.maxHealth);
+ healthBar.width = 200 * healthPercent;
+ if (healthPercent > 0.6) {
+ healthBar.tint = 0x00FF00;
+ } else if (healthPercent > 0.3) {
+ healthBar.tint = 0xFFFF00;
+ } else {
+ healthBar.tint = 0xFF0000;
+ }
+ // Game over check
+ if (player.isDead) {
+ LK.showGameOver();
+ }
+ // Camera follow player (simple implementation)
+ var targetX = -player.x + 1024;
+ targetX = Math.max(-500, Math.min(500, targetX));
+ game.x += (targetX - game.x) * 0.05;
+};
+// Start background music
+LK.playMusic('battleMusic');
\ No newline at end of file