User prompt
Not that fast
User prompt
Make him slide faster
User prompt
Make him always slowly slide to the middle
User prompt
Them slide to the middle quicker
User prompt
Add friction to the stickmans sliding
User prompt
Make him slide faster
User prompt
The stick man is kinda falling apart ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Can you fix this
User prompt
Make him slide in a random direction
User prompt
Can you fix that
User prompt
Make the stickman a ragdoll ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Stickman Smasher
Initial prompt
Make a game where you have to beat up a stickman by clicking it and using various tools that you can unlock to help you
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
points: 0,
damage: 1,
tools: [],
level: 1
});
/****
* Classes
****/
var Stickman = Container.expand(function () {
var self = Container.call(this);
// Initialize physics properties for ragdoll effect
var bodyParts = [];
var isRagdolling = false;
var restoreTimer = null;
// Body parts with physics properties
var body = self.attachAsset('stickman', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 1
});
body.velocityX = 0;
body.velocityY = 0;
body.rotationalVelocity = 0;
body.mass = 10;
body.originalX = 0;
body.originalY = 0;
body.originalRotation = 0;
body.elasticity = 0.7;
body.friction = 0.9;
bodyParts.push(body);
var head = self.attachAsset('head', {
anchorX: 0.5,
anchorY: 0.5,
y: -225
});
head.velocityX = 0;
head.velocityY = 0;
head.rotationalVelocity = 0;
head.mass = 5;
head.originalX = 0;
head.originalY = -225;
head.originalRotation = 0;
head.elasticity = 0.8;
head.friction = 0.85;
bodyParts.push(head);
// Arms (using stickman asset but resized)
var leftArm = self.attachAsset('stickman', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.2,
scaleY: 0.6,
x: -70,
y: -150,
rotation: -0.3
});
leftArm.velocityX = 0;
leftArm.velocityY = 0;
leftArm.rotationalVelocity = 0;
leftArm.mass = 3;
leftArm.originalX = -70;
leftArm.originalY = -150;
leftArm.originalRotation = -0.3;
leftArm.elasticity = 0.9;
leftArm.friction = 0.8;
bodyParts.push(leftArm);
var rightArm = self.attachAsset('stickman', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.2,
scaleY: 0.6,
x: 70,
y: -150,
rotation: 0.3
});
rightArm.velocityX = 0;
rightArm.velocityY = 0;
rightArm.rotationalVelocity = 0;
rightArm.mass = 3;
rightArm.originalX = 70;
rightArm.originalY = -150;
rightArm.originalRotation = 0.3;
rightArm.elasticity = 0.9;
rightArm.friction = 0.8;
bodyParts.push(rightArm);
// Legs (using stickman asset but resized)
var leftLeg = self.attachAsset('stickman', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.2,
scaleY: 0.7,
x: -40,
y: 50,
rotation: 0.2
});
leftLeg.velocityX = 0;
leftLeg.velocityY = 0;
leftLeg.rotationalVelocity = 0;
leftLeg.mass = 4;
leftLeg.originalX = -40;
leftLeg.originalY = 50;
leftLeg.originalRotation = 0.2;
leftLeg.elasticity = 0.6;
leftLeg.friction = 0.85;
bodyParts.push(leftLeg);
var rightLeg = self.attachAsset('stickman', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.2,
scaleY: 0.7,
x: 40,
y: 50,
rotation: -0.2
});
rightLeg.velocityX = 0;
rightLeg.velocityY = 0;
rightLeg.rotationalVelocity = 0;
rightLeg.mass = 4;
rightLeg.originalX = 40;
rightLeg.originalY = 50;
rightLeg.originalRotation = -0.2;
rightLeg.elasticity = 0.6;
rightLeg.friction = 0.85;
bodyParts.push(rightLeg);
// Health properties
self.maxHealth = 100;
self.health = self.maxHealth;
self.level = storage.level || 1;
// Apply a force to a body part
function applyForce(part, forceX, forceY, torque) {
part.velocityX += forceX / part.mass;
part.velocityY += forceY / part.mass;
part.rotationalVelocity += torque / part.mass;
}
// Start ragdoll physics
function startRagdoll() {
isRagdolling = true;
// Clear any existing restore timer
if (restoreTimer) {
LK.clearTimeout(restoreTimer);
}
// Set a timer to restore the stickman to normal position
restoreTimer = LK.setTimeout(function () {
restorePosition();
}, 3000);
}
// Restore stickman to normal position
function restorePosition() {
isRagdolling = false;
// Animate each body part back to its original position
bodyParts.forEach(function (part) {
// Stop any ongoing tweens
tween.stop(part, {
x: true,
y: true,
rotation: true
});
// Animate back to original position
tween(part, {
x: part.originalX,
y: part.originalY,
rotation: part.originalRotation
}, {
duration: 1000,
easing: tween.elasticOut
});
// Reset velocities
part.velocityX = 0;
part.velocityY = 0;
part.rotationalVelocity = 0;
});
}
// Update physics simulation
self.update = function () {
if (isRagdolling) {
var gravity = 0.5;
bodyParts.forEach(function (part) {
// Apply gravity
part.velocityY += gravity;
// Apply velocities
part.x += part.velocityX;
part.y += part.velocityY;
part.rotation += part.rotationalVelocity;
// Apply friction
part.velocityX *= part.friction;
part.velocityY *= part.friction;
part.rotationalVelocity *= 0.95;
// Constrain rotation
if (part.rotation > Math.PI * 2) {
part.rotation -= Math.PI * 2;
} else if (part.rotation < -Math.PI * 2) {
part.rotation += Math.PI * 2;
}
// Apply constraints to keep body parts connected
// This is a simplified constraint system - a real physics engine would use proper joint constraints
// Head stays relatively close to body
if (part === head) {
var dx = part.x - body.x;
var dy = part.y - (body.y - 200);
var distance = Math.sqrt(dx * dx + dy * dy);
var maxDistance = 100;
if (distance > maxDistance) {
var ratio = maxDistance / distance;
part.x = body.x + dx * ratio;
part.y = body.y - 200 + dy * ratio;
}
}
// Arms stay connected to body
if (part === leftArm || part === rightArm) {
var shoulderX = body.x + (part === leftArm ? -60 : 60);
var shoulderY = body.y - 150;
var dx = part.x - shoulderX;
var dy = part.y - shoulderY;
var distance = Math.sqrt(dx * dx + dy * dy);
var maxDistance = 80;
if (distance > maxDistance) {
var ratio = maxDistance / distance;
part.x = shoulderX + dx * ratio;
part.y = shoulderY + dy * ratio;
}
}
// Legs stay connected to body
if (part === leftLeg || part === rightLeg) {
var hipX = body.x + (part === leftLeg ? -30 : 30);
var hipY = body.y + 50;
var dx = part.x - hipX;
var dy = part.y - hipY;
var distance = Math.sqrt(dx * dx + dy * dy);
var maxDistance = 100;
if (distance > maxDistance) {
var ratio = maxDistance / distance;
part.x = hipX + dx * ratio;
part.y = hipY + dy * ratio;
}
}
});
}
};
// Hit reaction
self.hit = function (damage) {
// Decrease health
self.health -= damage;
if (self.health <= 0) {
self.health = 0;
self.defeat();
}
// Update health UI
updateHealthBar();
// Visual reaction - flash
LK.effects.flashObject(self, 0xFF0000, 300);
// Get random body part for hit location
var parts = [body, head, leftArm, rightArm, leftLeg, rightLeg];
var randomPart = parts[Math.floor(Math.random() * parts.length)];
// Create hit effect
var hitEffect = LK.getAsset('hitEffect', {
anchorX: 0.5,
anchorY: 0.5,
x: randomPart.x,
y: randomPart.y,
alpha: 0.7,
scaleX: 0.5,
scaleY: 0.5
});
self.addChild(hitEffect);
// Animate the hit effect
tween(hitEffect, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
hitEffect.destroy();
}
});
// Start ragdoll physics if not already in that state
startRagdoll();
// Apply impulse to the hit body part
var hitForceX = (Math.random() - 0.5) * damage * 5;
var hitForceY = (Math.random() - 0.5) * damage * 5;
var hitTorque = (Math.random() - 0.5) * damage * 0.2;
// Apply force with special effects based on the body part hit
if (randomPart === head) {
// Head hits are more impactful
applyForce(randomPart, hitForceX * 1.5, hitForceY * 1.5, hitTorque * 2);
// Also make the head wobble
tween(randomPart, {
rotation: randomPart.rotation + Math.PI * (Math.random() - 0.5)
}, {
duration: 500,
easing: tween.elasticOut
});
} else if (randomPart === leftArm || randomPart === rightArm) {
// Arms swing more
applyForce(randomPart, hitForceX, hitForceY, hitTorque * 3);
} else if (randomPart === leftLeg || randomPart === rightLeg) {
// Legs have more mass, less rotation
applyForce(randomPart, hitForceX * 0.8, hitForceY * 0.8, hitTorque * 0.5);
} else if (randomPart === body) {
// Body affects all parts
bodyParts.forEach(function (part) {
applyForce(part, hitForceX * 0.6, hitForceY * 0.6, hitTorque * 0.3);
});
}
// Play sound
LK.getSound('hit').play();
return true;
};
// When stickman is defeated
self.defeat = function () {
// Massive ragdoll effect on defeat
startRagdoll();
// Apply explosive force to all body parts
bodyParts.forEach(function (part) {
var explosiveForceX = (Math.random() - 0.5) * 50;
var explosiveForceY = (Math.random() - 0.5) * 50;
var explosiveTorque = (Math.random() - 0.5) * 2;
applyForce(part, explosiveForceX, explosiveForceY, explosiveTorque);
});
// Level up
self.level++;
storage.level = self.level;
// Reward player with points
var reward = 10 * self.level;
addPoints(reward);
// Show level up message
showLevelUpMessage(self.level, reward);
// Reset health with increased max health after a delay
LK.setTimeout(function () {
self.maxHealth = 100 + (self.level - 1) * 50;
self.health = self.maxHealth;
updateHealthBar();
restorePosition();
}, 3000);
// Play unlock sound
LK.getSound('unlock').play();
};
// Event handler when clicking on stickman
self.down = function (x, y, obj) {
// Convert coordinates to local space
var localX = x - self.x;
var localY = y - self.y;
// Find closest body part to the click point
var closestPart = body; // Default to body
var closestDistance = Number.MAX_VALUE;
bodyParts.forEach(function (part) {
var dx = part.x - localX;
var dy = part.y - localY;
var distance = dx * dx + dy * dy;
if (distance < closestDistance) {
closestDistance = distance;
closestPart = part;
}
});
// Apply current tool damage
self.hit(currentDamage);
// Additional force to the specific body part that was clicked
var hitForceX = (Math.random() - 0.5) * currentDamage * 8;
var hitForceY = (Math.random() - 0.5) * currentDamage * 8;
var hitTorque = (Math.random() - 0.5) * currentDamage * 0.4;
applyForce(closestPart, hitForceX, hitForceY, hitTorque);
// Add points based on current damage
addPoints(currentDamage);
};
return self;
});
var Tool = Container.expand(function (toolData) {
var self = Container.call(this);
self.data = toolData;
var toolShape = self.attachAsset('tool', {
anchorX: 0.5,
anchorY: 0.5,
tint: toolData.color || 0x8B4513
});
var nameText = new Text2(toolData.name, {
size: 24,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0);
nameText.y = 80;
self.addChild(nameText);
var damageText = new Text2("+" + toolData.damage + " DMG", {
size: 22,
fill: 0xFFFF00
});
damageText.anchor.set(0.5, 0);
damageText.y = 110;
self.addChild(damageText);
var priceText = new Text2(toolData.price + " PTS", {
size: 22,
fill: 0xFFFFFF
});
priceText.anchor.set(0.5, 0);
priceText.y = 140;
self.addChild(priceText);
self.down = function (x, y, obj) {
if (points >= toolData.price && !isToolOwned(toolData.id)) {
// Purchase the tool
addPoints(-toolData.price);
unlockTool(toolData);
// Play unlock sound
LK.getSound('unlock').play();
// Show purchase confirmation
showMessage("You unlocked " + toolData.name + "!");
// Update shop
updateShop();
} else if (isToolOwned(toolData.id)) {
// Equip the tool if already owned
equipTool(toolData.id);
showMessage(toolData.name + " equipped!");
} else {
// Show not enough points message
showMessage("Not enough points!");
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 // Black background for better ragdoll visibility
});
/****
* Game Code
****/
// Game state variables
var points = storage.points || 0;
var baseDamage = storage.damage || 1;
var currentDamage = baseDamage;
var tools = storage.tools || [];
var equippedTool = null;
var isShopOpen = false;
var shopContainer = null;
// Tool definitions
var availableTools = [{
id: 'fist',
name: 'Fist',
damage: 1,
price: 0,
color: 0xFFB380,
owned: true
}, {
id: 'stick',
name: 'Stick',
damage: 2,
price: 50,
color: 0x8B4513
}, {
id: 'bat',
name: 'Baseball Bat',
damage: 5,
price: 200,
color: 0x654321
}, {
id: 'hammer',
name: 'Hammer',
damage: 10,
price: 500,
color: 0x808080
}, {
id: 'pan',
name: 'Frying Pan',
damage: 15,
price: 1000,
color: 0x404040
}, {
id: 'mallet',
name: 'Cartoon Mallet',
damage: 25,
price: 2500,
color: 0xFF0000
}, {
id: 'anvil',
name: 'Anvil',
damage: 50,
price: 5000,
color: 0x303030
}, {
id: 'piano',
name: 'Grand Piano',
damage: 100,
price: 10000,
color: 0x000000
}];
// Set up the stickman
var stickman = new Stickman();
stickman.x = 2048 / 2;
stickman.y = 2732 / 2;
game.addChild(stickman);
// Set up UI elements
var pointsText = new Text2("POINTS: 0", {
size: 70,
fill: 0x000000
});
pointsText.anchor.set(0.5, 0);
pointsText.y = 50;
LK.gui.top.addChild(pointsText);
var damageText = new Text2("DAMAGE: 1", {
size: 50,
fill: 0xFF0000
});
damageText.anchor.set(0.5, 0);
damageText.y = 130;
LK.gui.top.addChild(damageText);
var levelText = new Text2("LEVEL: 1", {
size: 50,
fill: 0x0000FF
});
levelText.anchor.set(0.5, 0);
levelText.y = 190;
LK.gui.top.addChild(levelText);
// Health bar
var healthBarBg = LK.getAsset('stickman', {
anchorX: 0,
anchorY: 0.5,
width: 600,
height: 40,
tint: 0x888888
});
healthBarBg.x = 2048 / 2 - 300;
healthBarBg.y = 300;
game.addChild(healthBarBg);
var healthBar = LK.getAsset('stickman', {
anchorX: 0,
anchorY: 0.5,
width: 600,
height: 40,
tint: 0xFF0000
});
healthBar.x = 2048 / 2 - 300;
healthBar.y = 300;
game.addChild(healthBar);
var healthText = new Text2("100/100", {
size: 30,
fill: 0xFFFFFF
});
healthText.anchor.set(0.5, 0.5);
healthText.x = 2048 / 2;
healthText.y = 300;
game.addChild(healthText);
// Shop button
var shopButton = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5
});
shopButton.x = 2048 - 150;
shopButton.y = 100;
game.addChild(shopButton);
var shopText = new Text2("SHOP", {
size: 40,
fill: 0xFFFFFF
});
shopText.anchor.set(0.5, 0.5);
shopText.x = 2048 - 150;
shopText.y = 100;
game.addChild(shopText);
// Message display
var messageText = new Text2("", {
size: 60,
fill: 0xFF0000
});
messageText.anchor.set(0.5, 0.5);
messageText.x = 2048 / 2;
messageText.y = 500;
messageText.alpha = 0;
game.addChild(messageText);
// Initialize the game
function init() {
// Set up initial values
updatePointsDisplay();
updateDamageDisplay();
updateLevelDisplay();
updateHealthBar();
// Mark tools as owned if in storage
tools.forEach(function (toolId) {
for (var i = 0; i < availableTools.length; i++) {
if (availableTools[i].id === toolId) {
availableTools[i].owned = true;
}
}
});
// Equip the first owned tool
var ownedTools = availableTools.filter(function (tool) {
return tool.owned;
});
if (ownedTools.length > 0) {
equipTool(ownedTools[0].id);
}
// Set shop button interaction
shopButton.interactive = true;
shopButton.down = function () {
toggleShop();
};
// Play background music
LK.playMusic('gameMusic');
}
// Toggle shop visibility
function toggleShop() {
if (isShopOpen) {
closeShop();
} else {
openShop();
}
}
// Open the shop
function openShop() {
isShopOpen = true;
// Create shop container
shopContainer = new Container();
shopContainer.x = 2048 / 2;
shopContainer.y = 2732 / 2;
game.addChild(shopContainer);
// Shop background
var shopBg = LK.getAsset('stickman', {
anchorX: 0.5,
anchorY: 0.5,
width: 1600,
height: 1800,
tint: 0x333333,
alpha: 0.9
});
shopContainer.addChild(shopBg);
// Shop title
var shopTitle = new Text2("TOOL SHOP", {
size: 80,
fill: 0xFFFFFF
});
shopTitle.anchor.set(0.5, 0);
shopTitle.y = -800;
shopContainer.addChild(shopTitle);
// Close button
var closeButton = LK.getAsset('shopButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 700,
y: -800,
tint: 0xFF0000
});
shopContainer.addChild(closeButton);
var closeText = new Text2("CLOSE", {
size: 40,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeText.x = 700;
closeText.y = -800;
shopContainer.addChild(closeText);
closeButton.interactive = true;
closeButton.down = function () {
closeShop();
};
// Layout tools in a grid
var toolsPerRow = 3;
var toolWidth = 300;
var toolHeight = 350;
var startX = -(toolsPerRow - 1) * toolWidth / 2;
var startY = -600;
availableTools.forEach(function (toolData, index) {
var row = Math.floor(index / toolsPerRow);
var col = index % toolsPerRow;
var toolItem = new Tool(toolData);
toolItem.x = startX + col * toolWidth;
toolItem.y = startY + row * toolHeight;
shopContainer.addChild(toolItem);
// Show "OWNED" or "EQUIPPED" if applicable
if (toolData.owned) {
var statusText = new Text2(isToolEquipped(toolData.id) ? "EQUIPPED" : "OWNED", {
size: 24,
fill: isToolEquipped(toolData.id) ? "#00FF00" : "#FFFFFF"
});
statusText.anchor.set(0.5, 0);
statusText.y = 170;
toolItem.addChild(statusText);
}
});
// Animate shop opening
shopContainer.alpha = 0;
shopContainer.scaleX = 0.8;
shopContainer.scaleY = 0.8;
tween(shopContainer, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
// Close the shop
function closeShop() {
if (!isShopOpen || !shopContainer) return;
tween(shopContainer, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
if (shopContainer) {
shopContainer.destroy();
shopContainer = null;
}
isShopOpen = false;
}
});
}
// Check if a tool is owned
function isToolOwned(toolId) {
return tools.indexOf(toolId) !== -1;
}
// Check if a tool is currently equipped
function isToolEquipped(toolId) {
return equippedTool && equippedTool.id === toolId;
}
// Unlock a new tool
function unlockTool(toolData) {
if (!isToolOwned(toolData.id)) {
tools.push(toolData.id);
storage.tools = tools;
// Mark as owned
for (var i = 0; i < availableTools.length; i++) {
if (availableTools[i].id === toolData.id) {
availableTools[i].owned = true;
break;
}
}
// Equip the newly unlocked tool
equipTool(toolData.id);
}
}
// Equip a tool
function equipTool(toolId) {
if (!isToolOwned(toolId)) return;
// Find the tool data
var toolData = null;
for (var i = 0; i < availableTools.length; i++) {
if (availableTools[i].id === toolId) {
toolData = availableTools[i];
break;
}
}
if (toolData) {
equippedTool = toolData;
currentDamage = baseDamage + toolData.damage;
updateDamageDisplay();
}
}
// Update the shop display
function updateShop() {
if (isShopOpen) {
closeShop();
openShop();
}
}
// Add points to the player's total
function addPoints(amount) {
points += amount;
storage.points = points;
updatePointsDisplay();
}
// Update the points display
function updatePointsDisplay() {
pointsText.setText("POINTS: " + points);
}
// Update the damage display
function updateDamageDisplay() {
damageText.setText("DAMAGE: " + currentDamage);
}
// Update the level display
function updateLevelDisplay() {
levelText.setText("LEVEL: " + stickman.level);
}
// Update the health bar
function updateHealthBar() {
var percentage = stickman.health / stickman.maxHealth;
healthBar.width = 600 * percentage;
healthText.setText(stickman.health + "/" + stickman.maxHealth);
}
// Show a message temporarily
function showMessage(text) {
messageText.setText(text);
messageText.alpha = 1;
// Clear any existing tweens
tween.stop(messageText, {
alpha: true
});
// Animate message
tween(messageText, {
alpha: 0
}, {
duration: 2000
});
}
// Show level up message
function showLevelUpMessage(level, reward) {
var levelUpText = new Text2("LEVEL UP!\nNow Level " + level + "\n+" + reward + " Points", {
size: 80,
fill: 0xFFFF00
});
levelUpText.anchor.set(0.5, 0.5);
levelUpText.x = 2048 / 2;
levelUpText.y = 2732 / 2 - 400;
levelUpText.alpha = 0;
game.addChild(levelUpText);
// Animate the level up text
tween(levelUpText, {
alpha: 1,
y: levelUpText.y - 100
}, {
duration: 500,
onFinish: function onFinish() {
tween(levelUpText, {
alpha: 0
}, {
duration: 1000,
delay: 1000,
onFinish: function onFinish() {
levelUpText.destroy();
}
});
}
});
}
// Create hit animation
function createHitAnimation(x, y) {
var hitEffect = LK.getAsset('hitEffect', {
anchorX: 0.5,
anchorY: 0.5,
x: x,
y: y,
alpha: 0.7,
scaleX: 0.5,
scaleY: 0.5
});
game.addChild(hitEffect);
tween(hitEffect, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
hitEffect.destroy();
}
});
}
// Track dragging state
var isDragging = false;
var draggedBodyPart = null;
var dragOffsetX = 0;
var dragOffsetY = 0;
// Mouse/touch handlers for the game
game.down = function (x, y, obj) {
// If the shop is open, don't register clicks on the game
if (isShopOpen) return;
// Create a hit animation at the touch point if not hitting stickman
if (!stickman.getBounds().contains(x, y)) {
createHitAnimation(x, y);
return;
}
// Check if we're starting a drag operation on a specific body part
var localX = x - stickman.x;
var localY = y - stickman.y;
// Find the body part that was clicked
var bodyParts = [stickman.getChildAt(0),
// body
stickman.getChildAt(1),
// head
stickman.getChildAt(2),
// leftArm
stickman.getChildAt(3),
// rightArm
stickman.getChildAt(4),
// leftLeg
stickman.getChildAt(5) // rightLeg
];
var closestPart = null;
var closestDistance = 50 * 50; // Minimum distance squared for dragging
bodyParts.forEach(function (part) {
var dx = part.x - localX;
var dy = part.y - localY;
var distance = dx * dx + dy * dy;
if (distance < closestDistance) {
closestDistance = distance;
closestPart = part;
}
});
if (closestPart) {
isDragging = true;
draggedBodyPart = closestPart;
dragOffsetX = localX - closestPart.x;
dragOffsetY = localY - closestPart.y;
// Start ragdoll mode when dragging
if (!stickman.isRagdolling) {
stickman.startRagdoll();
}
}
};
// Handle move events for dragging
game.move = function (x, y, obj) {
if (isDragging && draggedBodyPart && !isShopOpen) {
var localX = x - stickman.x;
var localY = y - stickman.y;
// Update dragged part position
draggedBodyPart.x = localX - dragOffsetX;
draggedBodyPart.y = localY - dragOffsetY;
// Reset velocity for smooth dragging
draggedBodyPart.velocityX = 0;
draggedBodyPart.velocityY = 0;
}
};
// Handle up events for dragging
game.up = function (x, y, obj) {
if (isDragging && draggedBodyPart && !isShopOpen) {
// On release, give the part some velocity based on movement
var releaseVelocityX = (Math.random() - 0.5) * 10;
var releaseVelocityY = (Math.random() - 0.5) * 10;
draggedBodyPart.velocityX = releaseVelocityX;
draggedBodyPart.velocityY = releaseVelocityY;
isDragging = false;
draggedBodyPart = null;
}
};
// Update function called every tick
game.update = function () {
// No need for additional update logic at this point
};
// Initialize the game
init(); ===================================================================
--- original.js
+++ change.js
@@ -13,20 +13,44 @@
* Classes
****/
var Stickman = Container.expand(function () {
var self = Container.call(this);
- // Body parts
+ // Initialize physics properties for ragdoll effect
+ var bodyParts = [];
+ var isRagdolling = false;
+ var restoreTimer = null;
+ // Body parts with physics properties
var body = self.attachAsset('stickman', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.4,
scaleY: 1
});
+ body.velocityX = 0;
+ body.velocityY = 0;
+ body.rotationalVelocity = 0;
+ body.mass = 10;
+ body.originalX = 0;
+ body.originalY = 0;
+ body.originalRotation = 0;
+ body.elasticity = 0.7;
+ body.friction = 0.9;
+ bodyParts.push(body);
var head = self.attachAsset('head', {
anchorX: 0.5,
anchorY: 0.5,
y: -225
});
+ head.velocityX = 0;
+ head.velocityY = 0;
+ head.rotationalVelocity = 0;
+ head.mass = 5;
+ head.originalX = 0;
+ head.originalY = -225;
+ head.originalRotation = 0;
+ head.elasticity = 0.8;
+ head.friction = 0.85;
+ bodyParts.push(head);
// Arms (using stickman asset but resized)
var leftArm = self.attachAsset('stickman', {
anchorX: 0.5,
anchorY: 0,
@@ -35,8 +59,18 @@
x: -70,
y: -150,
rotation: -0.3
});
+ leftArm.velocityX = 0;
+ leftArm.velocityY = 0;
+ leftArm.rotationalVelocity = 0;
+ leftArm.mass = 3;
+ leftArm.originalX = -70;
+ leftArm.originalY = -150;
+ leftArm.originalRotation = -0.3;
+ leftArm.elasticity = 0.9;
+ leftArm.friction = 0.8;
+ bodyParts.push(leftArm);
var rightArm = self.attachAsset('stickman', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.2,
@@ -44,8 +78,18 @@
x: 70,
y: -150,
rotation: 0.3
});
+ rightArm.velocityX = 0;
+ rightArm.velocityY = 0;
+ rightArm.rotationalVelocity = 0;
+ rightArm.mass = 3;
+ rightArm.originalX = 70;
+ rightArm.originalY = -150;
+ rightArm.originalRotation = 0.3;
+ rightArm.elasticity = 0.9;
+ rightArm.friction = 0.8;
+ bodyParts.push(rightArm);
// Legs (using stickman asset but resized)
var leftLeg = self.attachAsset('stickman', {
anchorX: 0.5,
anchorY: 0,
@@ -54,8 +98,18 @@
x: -40,
y: 50,
rotation: 0.2
});
+ leftLeg.velocityX = 0;
+ leftLeg.velocityY = 0;
+ leftLeg.rotationalVelocity = 0;
+ leftLeg.mass = 4;
+ leftLeg.originalX = -40;
+ leftLeg.originalY = 50;
+ leftLeg.originalRotation = 0.2;
+ leftLeg.elasticity = 0.6;
+ leftLeg.friction = 0.85;
+ bodyParts.push(leftLeg);
var rightLeg = self.attachAsset('stickman', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.2,
@@ -63,12 +117,132 @@
x: 40,
y: 50,
rotation: -0.2
});
+ rightLeg.velocityX = 0;
+ rightLeg.velocityY = 0;
+ rightLeg.rotationalVelocity = 0;
+ rightLeg.mass = 4;
+ rightLeg.originalX = 40;
+ rightLeg.originalY = 50;
+ rightLeg.originalRotation = -0.2;
+ rightLeg.elasticity = 0.6;
+ rightLeg.friction = 0.85;
+ bodyParts.push(rightLeg);
// Health properties
self.maxHealth = 100;
self.health = self.maxHealth;
self.level = storage.level || 1;
+ // Apply a force to a body part
+ function applyForce(part, forceX, forceY, torque) {
+ part.velocityX += forceX / part.mass;
+ part.velocityY += forceY / part.mass;
+ part.rotationalVelocity += torque / part.mass;
+ }
+ // Start ragdoll physics
+ function startRagdoll() {
+ isRagdolling = true;
+ // Clear any existing restore timer
+ if (restoreTimer) {
+ LK.clearTimeout(restoreTimer);
+ }
+ // Set a timer to restore the stickman to normal position
+ restoreTimer = LK.setTimeout(function () {
+ restorePosition();
+ }, 3000);
+ }
+ // Restore stickman to normal position
+ function restorePosition() {
+ isRagdolling = false;
+ // Animate each body part back to its original position
+ bodyParts.forEach(function (part) {
+ // Stop any ongoing tweens
+ tween.stop(part, {
+ x: true,
+ y: true,
+ rotation: true
+ });
+ // Animate back to original position
+ tween(part, {
+ x: part.originalX,
+ y: part.originalY,
+ rotation: part.originalRotation
+ }, {
+ duration: 1000,
+ easing: tween.elasticOut
+ });
+ // Reset velocities
+ part.velocityX = 0;
+ part.velocityY = 0;
+ part.rotationalVelocity = 0;
+ });
+ }
+ // Update physics simulation
+ self.update = function () {
+ if (isRagdolling) {
+ var gravity = 0.5;
+ bodyParts.forEach(function (part) {
+ // Apply gravity
+ part.velocityY += gravity;
+ // Apply velocities
+ part.x += part.velocityX;
+ part.y += part.velocityY;
+ part.rotation += part.rotationalVelocity;
+ // Apply friction
+ part.velocityX *= part.friction;
+ part.velocityY *= part.friction;
+ part.rotationalVelocity *= 0.95;
+ // Constrain rotation
+ if (part.rotation > Math.PI * 2) {
+ part.rotation -= Math.PI * 2;
+ } else if (part.rotation < -Math.PI * 2) {
+ part.rotation += Math.PI * 2;
+ }
+ // Apply constraints to keep body parts connected
+ // This is a simplified constraint system - a real physics engine would use proper joint constraints
+ // Head stays relatively close to body
+ if (part === head) {
+ var dx = part.x - body.x;
+ var dy = part.y - (body.y - 200);
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ var maxDistance = 100;
+ if (distance > maxDistance) {
+ var ratio = maxDistance / distance;
+ part.x = body.x + dx * ratio;
+ part.y = body.y - 200 + dy * ratio;
+ }
+ }
+ // Arms stay connected to body
+ if (part === leftArm || part === rightArm) {
+ var shoulderX = body.x + (part === leftArm ? -60 : 60);
+ var shoulderY = body.y - 150;
+ var dx = part.x - shoulderX;
+ var dy = part.y - shoulderY;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ var maxDistance = 80;
+ if (distance > maxDistance) {
+ var ratio = maxDistance / distance;
+ part.x = shoulderX + dx * ratio;
+ part.y = shoulderY + dy * ratio;
+ }
+ }
+ // Legs stay connected to body
+ if (part === leftLeg || part === rightLeg) {
+ var hipX = body.x + (part === leftLeg ? -30 : 30);
+ var hipY = body.y + 50;
+ var dx = part.x - hipX;
+ var dy = part.y - hipY;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ var maxDistance = 100;
+ if (distance > maxDistance) {
+ var ratio = maxDistance / distance;
+ part.x = hipX + dx * ratio;
+ part.y = hipY + dy * ratio;
+ }
+ }
+ });
+ }
+ };
// Hit reaction
self.hit = function (damage) {
// Decrease health
self.health -= damage;
@@ -77,11 +251,11 @@
self.defeat();
}
// Update health UI
updateHealthBar();
- // Visual reaction - shake and flash
+ // Visual reaction - flash
LK.effects.flashObject(self, 0xFF0000, 300);
- // Random body part reaction
+ // Get random body part for hit location
var parts = [body, head, leftArm, rightArm, leftLeg, rightLeg];
var randomPart = parts[Math.floor(Math.random() * parts.length)];
// Create hit effect
var hitEffect = LK.getAsset('hitEffect', {
@@ -104,53 +278,94 @@
onFinish: function onFinish() {
hitEffect.destroy();
}
});
- // Shake the body part
- var originalX = randomPart.x;
- var originalY = randomPart.y;
- var originalRotation = randomPart.rotation;
- tween(randomPart, {
- x: originalX + (Math.random() * 20 - 10),
- y: originalY + (Math.random() * 20 - 10),
- rotation: originalRotation + (Math.random() * 0.2 - 0.1)
- }, {
- duration: 100,
- onFinish: function onFinish() {
- tween(randomPart, {
- x: originalX,
- y: originalY,
- rotation: originalRotation
- }, {
- duration: 200
- });
- }
- });
+ // Start ragdoll physics if not already in that state
+ startRagdoll();
+ // Apply impulse to the hit body part
+ var hitForceX = (Math.random() - 0.5) * damage * 5;
+ var hitForceY = (Math.random() - 0.5) * damage * 5;
+ var hitTorque = (Math.random() - 0.5) * damage * 0.2;
+ // Apply force with special effects based on the body part hit
+ if (randomPart === head) {
+ // Head hits are more impactful
+ applyForce(randomPart, hitForceX * 1.5, hitForceY * 1.5, hitTorque * 2);
+ // Also make the head wobble
+ tween(randomPart, {
+ rotation: randomPart.rotation + Math.PI * (Math.random() - 0.5)
+ }, {
+ duration: 500,
+ easing: tween.elasticOut
+ });
+ } else if (randomPart === leftArm || randomPart === rightArm) {
+ // Arms swing more
+ applyForce(randomPart, hitForceX, hitForceY, hitTorque * 3);
+ } else if (randomPart === leftLeg || randomPart === rightLeg) {
+ // Legs have more mass, less rotation
+ applyForce(randomPart, hitForceX * 0.8, hitForceY * 0.8, hitTorque * 0.5);
+ } else if (randomPart === body) {
+ // Body affects all parts
+ bodyParts.forEach(function (part) {
+ applyForce(part, hitForceX * 0.6, hitForceY * 0.6, hitTorque * 0.3);
+ });
+ }
// Play sound
LK.getSound('hit').play();
return true;
};
// When stickman is defeated
self.defeat = function () {
+ // Massive ragdoll effect on defeat
+ startRagdoll();
+ // Apply explosive force to all body parts
+ bodyParts.forEach(function (part) {
+ var explosiveForceX = (Math.random() - 0.5) * 50;
+ var explosiveForceY = (Math.random() - 0.5) * 50;
+ var explosiveTorque = (Math.random() - 0.5) * 2;
+ applyForce(part, explosiveForceX, explosiveForceY, explosiveTorque);
+ });
// Level up
self.level++;
storage.level = self.level;
// Reward player with points
var reward = 10 * self.level;
addPoints(reward);
// Show level up message
showLevelUpMessage(self.level, reward);
- // Reset health with increased max health
- self.maxHealth = 100 + (self.level - 1) * 50;
- self.health = self.maxHealth;
- updateHealthBar();
+ // Reset health with increased max health after a delay
+ LK.setTimeout(function () {
+ self.maxHealth = 100 + (self.level - 1) * 50;
+ self.health = self.maxHealth;
+ updateHealthBar();
+ restorePosition();
+ }, 3000);
// Play unlock sound
LK.getSound('unlock').play();
};
// Event handler when clicking on stickman
self.down = function (x, y, obj) {
+ // Convert coordinates to local space
+ var localX = x - self.x;
+ var localY = y - self.y;
+ // Find closest body part to the click point
+ var closestPart = body; // Default to body
+ var closestDistance = Number.MAX_VALUE;
+ bodyParts.forEach(function (part) {
+ var dx = part.x - localX;
+ var dy = part.y - localY;
+ var distance = dx * dx + dy * dy;
+ if (distance < closestDistance) {
+ closestDistance = distance;
+ closestPart = part;
+ }
+ });
// Apply current tool damage
self.hit(currentDamage);
+ // Additional force to the specific body part that was clicked
+ var hitForceX = (Math.random() - 0.5) * currentDamage * 8;
+ var hitForceY = (Math.random() - 0.5) * currentDamage * 8;
+ var hitTorque = (Math.random() - 0.5) * currentDamage * 0.4;
+ applyForce(closestPart, hitForceX, hitForceY, hitTorque);
// Add points based on current damage
addPoints(currentDamage);
};
return self;
@@ -210,9 +425,9 @@
/****
* Initialize Game
****/
var game = new LK.Game({
- backgroundColor: 0xF5F5F5 // Light gray background
+ backgroundColor: 0x000000 // Black background for better ragdoll visibility
});
/****
* Game Code
@@ -638,17 +853,85 @@
hitEffect.destroy();
}
});
}
+// Track dragging state
+var isDragging = false;
+var draggedBodyPart = null;
+var dragOffsetX = 0;
+var dragOffsetY = 0;
// Mouse/touch handlers for the game
game.down = function (x, y, obj) {
// If the shop is open, don't register clicks on the game
if (isShopOpen) return;
// Create a hit animation at the touch point if not hitting stickman
if (!stickman.getBounds().contains(x, y)) {
createHitAnimation(x, y);
+ return;
}
+ // Check if we're starting a drag operation on a specific body part
+ var localX = x - stickman.x;
+ var localY = y - stickman.y;
+ // Find the body part that was clicked
+ var bodyParts = [stickman.getChildAt(0),
+ // body
+ stickman.getChildAt(1),
+ // head
+ stickman.getChildAt(2),
+ // leftArm
+ stickman.getChildAt(3),
+ // rightArm
+ stickman.getChildAt(4),
+ // leftLeg
+ stickman.getChildAt(5) // rightLeg
+ ];
+ var closestPart = null;
+ var closestDistance = 50 * 50; // Minimum distance squared for dragging
+ bodyParts.forEach(function (part) {
+ var dx = part.x - localX;
+ var dy = part.y - localY;
+ var distance = dx * dx + dy * dy;
+ if (distance < closestDistance) {
+ closestDistance = distance;
+ closestPart = part;
+ }
+ });
+ if (closestPart) {
+ isDragging = true;
+ draggedBodyPart = closestPart;
+ dragOffsetX = localX - closestPart.x;
+ dragOffsetY = localY - closestPart.y;
+ // Start ragdoll mode when dragging
+ if (!stickman.isRagdolling) {
+ stickman.startRagdoll();
+ }
+ }
};
+// Handle move events for dragging
+game.move = function (x, y, obj) {
+ if (isDragging && draggedBodyPart && !isShopOpen) {
+ var localX = x - stickman.x;
+ var localY = y - stickman.y;
+ // Update dragged part position
+ draggedBodyPart.x = localX - dragOffsetX;
+ draggedBodyPart.y = localY - dragOffsetY;
+ // Reset velocity for smooth dragging
+ draggedBodyPart.velocityX = 0;
+ draggedBodyPart.velocityY = 0;
+ }
+};
+// Handle up events for dragging
+game.up = function (x, y, obj) {
+ if (isDragging && draggedBodyPart && !isShopOpen) {
+ // On release, give the part some velocity based on movement
+ var releaseVelocityX = (Math.random() - 0.5) * 10;
+ var releaseVelocityY = (Math.random() - 0.5) * 10;
+ draggedBodyPart.velocityX = releaseVelocityX;
+ draggedBodyPart.velocityY = releaseVelocityY;
+ isDragging = false;
+ draggedBodyPart = null;
+ }
+};
// Update function called every tick
game.update = function () {
// No need for additional update logic at this point
};
Curved dark gray square with a white outline. In-Game asset. 2d. High contrast. No shadows
A dark gray circle with a white outline with 2 white dots as eyes. In-Game asset. 2d. High contrast. No shadows
Big light brown beard. In-Game asset. 2d. High contrast. No shadows
Cowboy hat. In-Game asset. 2d. High contrast. No shadows
Crown. In-Game asset. 2d. High contrast. No shadows
Anvil. In-Game asset. 2d. High contrast. No shadows
Mustache. In-Game asset. 2d. High contrast. No shadows
Cool sunglasses. In-Game asset. 2d. High contrast. No shadows. Facing camera
Top hat. In-Game asset. 2d. High contrast. No shadows
Party hat. In-Game asset. 2d. High contrast. No shadows
Green block with curved edges. In-Game asset. 2d. High contrast. No shadows
Baseball bat. In-Game asset. 2d. High contrast. No shadows
White glove curled into a fist. In-Game asset. 2d. High contrast. No shadows
Blue block with curved edges. In-Game asset. 2d. High contrast. No shadows
Rubber mallet. In-Game asset. 2d. High contrast. No shadows
Hammer. In-Game asset. 2d. High contrast. No shadows
Frying pan. In-Game asset. 2d. High contrast. No shadows
Stick. In-Game asset. 2d. High contrast. No shadows
Grand piano. In-Game asset. 2d. High contrast. No shadows
Gray circle with white outline. In-Game asset. 2d. High contrast. No shadows
Explosion. In-Game asset. 2d. High contrast. No shadows
Mohawk with no head. In-Game asset. 2d. High contrast. No shadows
Pirate hat. In-Game asset. 2d. High contrast. No shadows
Headband. In-Game asset. 2d. High contrast. No shadows
Propeller hat. In-Game asset. 2d. High contrast. No shadows