User prompt
Sorunlu ve gereksiz kodları temizle
User prompt
Testten çık
User prompt
Testten çık
User prompt
Kuklayı zemine kadar indir
User prompt
Tüm ik bağlantılarını beyaz renkte ve noktalı çizgilerle en önde gòzukecek şekilde çiz.
User prompt
Tüm ik bağlantılarını beyaz renkte ve noktalı çizgilerle en önde gòzukecek şekilde çiz.
User prompt
Bağlantı çizgileri beyaz olsun
User prompt
Please fix the bug: 'TypeError: LK.getLine is not a function' in or related to this line: 'var line = LK.getLine({' Line Number: 647
User prompt
Tüm ik bağlantılarını beyaz noktalı çizgilerle en önde gòzukecek şekilde çiz.
User prompt
Kalçayı aşağıya çek
User prompt
Üst bacakları sol sağ yer değiştir
User prompt
Üst bacakları aç
User prompt
Bacakların bağdaş durmasın
User prompt
Alt bacaklar zemine deysin
User prompt
Alt bacakların alt kenarları zeminde olsun.
User prompt
Dizler aynı hizada olsun
User prompt
Dizlerin tüm ik bağlantılarını yap
User prompt
Dizlerin tüm ik bağlantılarını resetle
User prompt
Dizler merkezi üst bacakların alt kenarının tam orta noktasında olmalı
User prompt
Dizler bacakların önünde görünmeli
User prompt
Dirsekler bacakların önünde gözüksün
User prompt
Üst bacaklari aç.
User prompt
Üst bacaklar çapraz durmasin
User prompt
Zemine indir
User prompt
Zemine sıfır yap
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Drum class
var Drum = Container.expand(function () {
var self = Container.call(this);
self.drumType = 'none'; // 'large', 'left', 'right', 'sit', 'stand'
self.action = null; // function to call on tap
// Set up drum asset
self.setDrum = function (type) {
self.drumType = type;
var assetId = type === 'large' ? 'drum_large' : 'drum_medium';
var drum = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// (Drum label removed)
};
// Drum tap effect
self.flash = function () {
tween(self, {
scaleX: 1.18,
scaleY: 0.92
}, {
duration: 80,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 120
});
}
});
};
// Touch event
self.down = function (x, y, obj) {
self.flash();
// Play unique sound for each drum type
if (self.drumType === 'large') {
LK.getSound('drum_tap_center').play();
} else if (self.drumType === 'left') {
// Play with very long reverb effect
if (typeof reverb !== "undefined" && reverb.add) {
var leftSound = LK.getSound('drum_tap_left');
reverb.add(leftSound, {
reverbTime: 3.5
}); // simulate very long reverb (if plugin supports param)
leftSound.play();
} else {
LK.getSound('drum_tap_left').play();
}
} else if (self.drumType === 'right') {
// Play with very long reverb effect
if (typeof reverb !== "undefined" && reverb.add) {
var rightSound = LK.getSound('drum_tap_right');
reverb.add(rightSound, {
reverbTime: 3.5
}); // simulate very long reverb (if plugin supports param)
rightSound.play();
} else {
LK.getSound('drum_tap_right').play();
}
} else if (self.drumType === 'sit') {
var sitSound = LK.getSound('drum_tap_sit');
sitSound.play();
LK.setTimeout(function () {
sitSound.play();
}, 120);
} else if (self.drumType === 'stand') {
// Play the sound with 3 fast delay effects (echoes)
var base = LK.getSound('drum_tap_stand');
base.play();
LK.setTimeout(function () {
base.play();
}, 45);
LK.setTimeout(function () {
base.play();
}, 90);
} else {
// No fallback sound
}
if (self.action) self.action();
};
return self;
});
// Puppet class: articulated body with simple kinematics
var Puppet = Container.expand(function () {
var self = Container.call(this);
// --- Body part sizes (for positioning) ---
var headH = 120 * 1.5,
headW = 120 * 1.5;
var bodyH = 200 * 1.5,
bodyW = 80 * 1.5;
var upperArmH = 100 * 1.5,
upperArmW = 40 * 1.5;
var lowerArmH = 90 * 1.5,
lowerArmW = 32 * 1.5;
var upperLegH = 120 * 1.5,
upperLegW = 48 * 1.5;
var lowerLegH = 110 * 1.5,
lowerLegW = 40 * 1.5;
// --- Create body parts ---
// Head
var head = self.attachAsset('puppet_head', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// Neck (between head and body, sized to match hip)
var neck = self.attachAsset('puppet_neck', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
// match hip scale
scaleY: 1.5
});
// Shoulders (left and right)
var lShoulder = self.attachAsset('puppet_shoulder', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
var rShoulder = self.attachAsset('puppet_shoulder', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// Body
var body = self.attachAsset('puppet_body', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.5,
scaleY: 1.5
});
// Dual hips (left and right)
var lHip = self.attachAsset('puppet_hip', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
var rHip = self.attachAsset('puppet_hip', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// Left upper arm
var lUpperArm = self.attachAsset('puppet_upperarm', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.5,
scaleY: 1.5
});
// Left elbow
var lElbow = self.attachAsset('puppet_elbow', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// Left lower arm
var lLowerArm = self.attachAsset('puppet_lowerarm', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.5,
scaleY: 1.5
});
// Right upper arm
var rUpperArm = self.attachAsset('puppet_upperarm', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.5,
scaleY: 1.5
});
// Right elbow
var rElbow = self.attachAsset('puppet_elbow', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// Right lower arm
var rLowerArm = self.attachAsset('puppet_lowerarm', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.5,
scaleY: 1.5
});
// Left lower leg
var lLowerLeg = self.attachAsset('puppet_lowerleg', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.5,
scaleY: 1.5
});
// Right lower leg
var rLowerLeg = self.attachAsset('puppet_lowerleg', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.5,
scaleY: 1.5
});
// Left upper leg
var lUpperLeg = self.attachAsset('puppet_upperleg', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.5,
scaleY: 1.5
});
// Left knee
var lKnee = self.attachAsset('puppet_knee', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// Right upper leg
var rUpperLeg = self.attachAsset('puppet_upperleg', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.5,
scaleY: 1.5
});
// Right knee
var rKnee = self.attachAsset('puppet_knee', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// --- Initial pose state ---
self.state = {
vx: 0,
// horizontal velocity
vy: 0,
// vertical velocity
grounded: false,
pose: 'stand',
// 'stand', 'sit', 'jump'
headAngle: 0,
// radians, for "pull head" actions
x: 0,
// world position
y: 0,
// --- Ava: Leg rotation controls ---
lUpperLegRotation: 0,
// additional rotation for left upper leg
rUpperLegRotation: 0,
// additional rotation for right upper leg
lLowerLegRotation: 0,
// additional rotation for left lower leg
rLowerLegRotation: 0 // additional rotation for right lower leg
};
// --- Positioning offsets (relative to puppet center) ---
function updateBodyParts() {
// Head
head.x = 0;
head.y = -bodyH / 2 - headH / 2 - 30;
head.rotation = self.state.headAngle;
// Neck
var hipH = 44 * 1.5;
var neckH = hipH;
neck.x = 0;
neck.y = -bodyH / 2 - neckH / 2 + 38;
neck.rotation = 0;
// Body
body.x = 0;
body.y = -bodyH / 2;
// --- Symmetric Arms ---
var armY = -bodyH / 2 + 30;
var armX = bodyW / 2 + upperArmW / 2 - 10;
// Shoulders
var lShoulderX = -armX;
var lShoulderY = armY;
var rShoulderX = armX;
var rShoulderY = armY;
lShoulder.x = lShoulderX;
lShoulder.y = lShoulderY;
rShoulder.x = rShoulderX;
rShoulder.y = rShoulderY;
// Default symmetric arm pose
var armAbduction = 0.32;
var baseUpperArmAngle = 0.0;
var baseLowerArmAngle = 0.0;
var lUpperArmAngle = -armAbduction + baseUpperArmAngle;
var rUpperArmAngle = armAbduction + baseUpperArmAngle;
var lLowerArmAngle = baseLowerArmAngle;
var rLowerArmAngle = baseLowerArmAngle;
// Symmetric pose-based arm animation
if (self.state.pose === 'sit') {
lUpperArmAngle = -1.25 - armAbduction;
rUpperArmAngle = 1.25 + armAbduction;
lLowerArmAngle = 1.5;
rLowerArmAngle = -1.5;
} else if (self.state.pose === 'jump') {
lUpperArmAngle = -1.6 - armAbduction;
rUpperArmAngle = 1.6 + armAbduction;
lLowerArmAngle = 2.0;
rLowerArmAngle = -2.0;
} else if (self.state.pose === 'stand') {
lUpperArmAngle += self.state.vx * 0.01;
rUpperArmAngle -= self.state.vx * 0.01;
lLowerArmAngle += Math.sin(Date.now() * 0.003) * 0.08;
rLowerArmAngle -= Math.sin(Date.now() * 0.003) * 0.08;
}
// Left arm
lUpperArm.x = lShoulderX;
lUpperArm.y = lShoulderY;
var lElbowX = lUpperArm.x + Math.sin(lUpperArmAngle) * upperArmH;
var lElbowY = lUpperArm.y + Math.cos(lUpperArmAngle) * upperArmH;
lElbow.x = lElbowX;
lElbow.y = lElbowY;
lUpperArm.rotation = Math.atan2(lElbow.y - lUpperArm.y, lElbow.x - lUpperArm.x) - Math.PI / 2;
lLowerArm.x = lElbowX;
lLowerArm.y = lElbowY;
lLowerArm.rotation = lLowerArmAngle;
// Right arm (mirror of left)
rUpperArm.x = rShoulderX;
rUpperArm.y = rShoulderY;
var rElbowX = rUpperArm.x + Math.sin(rUpperArmAngle) * upperArmH;
var rElbowY = rUpperArm.y + Math.cos(rUpperArmAngle) * upperArmH;
rElbow.x = rElbowX;
rElbow.y = rElbowY;
rUpperArm.rotation = Math.atan2(rElbow.y - rUpperArm.y, rElbow.x - rUpperArm.x) - Math.PI / 2;
rLowerArm.x = rElbowX;
rLowerArm.y = rElbowY;
rLowerArm.rotation = rLowerArmAngle;
// --- Symmetric Legs ---
var legY = bodyH / 2 - 10;
var legX = bodyW / 2 - 18;
// Hips
var lHipX = -legX;
var lHipY = legY;
var rHipX = legX;
var rHipY = legY;
lHip.x = lHipX;
lHip.y = lHipY;
rHip.x = rHipX;
rHip.y = rHipY;
// Default symmetric leg pose
var legAbduction = 0.28;
var lowerLegOutAngle = 0.38;
var lUpperLegAngle = legAbduction + (self.state.lUpperLegRotation || 0);
var rUpperLegAngle = -legAbduction + (self.state.rUpperLegRotation || 0);
var lLowerLegAngle = lowerLegOutAngle + (self.state.lLowerLegRotation || 0);
var rLowerLegAngle = -lowerLegOutAngle + (self.state.rLowerLegRotation || 0);
// Symmetric pose-based leg animation
if (self.state.pose === 'sit') {
// Cross-legged (bağdaş) pose
// Hips
// Move hips slightly closer for a more natural cross-legged look
var hipsMidX = (lHip.x + rHip.x) / 2;
var hipsMidY = (lHip.y + rHip.y) / 2 + 18;
// Cross-legged: knees cross in front of body, ankles under opposite knee
var crossKneeSpread = 60; // horizontal distance from center for knees
var crossKneeForward = 80; // forward (down) distance for knees
var crossAnkleSpread = 90; // horizontal distance from center for ankles
var crossAnkleForward = 170; // forward (down) distance for ankles
// Upper legs: hips to knees (open thighs outward for cross-legged look)
var thighSpreadAngle = 0.55; // radians, how much to open thighs outward
// Calculate upper leg bottom (knee) positions
lUpperLeg.x = lHip.x;
lUpperLeg.y = lHip.y;
lUpperLeg.rotation = Math.atan2(Math.sin(thighSpreadAngle), Math.cos(thighSpreadAngle)) + Math.PI / 2;
rUpperLeg.x = rHip.x;
rUpperLeg.y = rHip.y;
rUpperLeg.rotation = -Math.atan2(Math.sin(thighSpreadAngle), Math.cos(thighSpreadAngle)) - Math.PI / 2;
// Find the bottom center of each upper leg (where knee should be)
var lKneeAttachX = lUpperLeg.x + Math.sin(lUpperLeg.rotation + Math.PI / 2) * upperLegH;
var lKneeAttachY = lUpperLeg.y + Math.cos(lUpperLeg.rotation + Math.PI / 2) * upperLegH;
var rKneeAttachX = rUpperLeg.x + Math.sin(rUpperLeg.rotation + Math.PI / 2) * upperLegH;
var rKneeAttachY = rUpperLeg.y + Math.cos(rUpperLeg.rotation + Math.PI / 2) * upperLegH;
// Place knees at the exact midpoint of the bottom edge of the upper legs
// --- Ava: Make knees at the same y position ---
var avgKneeY = (lKneeAttachY + rKneeAttachY) / 2;
var lKneeX = lKneeAttachX;
var lKneeY = avgKneeY;
var rKneeX = rKneeAttachX;
var rKneeY = avgKneeY;
// Knees (bring knees visually in front of upper/lower legs by setting z-order)
// To ensure knees are drawn in front, remove and re-add them after legs
if (lKnee.parent) lKnee.parent.removeChild(lKnee);
if (rKnee.parent) rKnee.parent.removeChild(rKnee);
// --- Connect knees to both upper and lower legs ---
// Left knee: connect to left upper leg (top) and left lower leg (bottom)
lKnee.x = lKneeX;
lKnee.y = lKneeY;
// Right knee: connect to right upper leg (top) and right lower leg (bottom)
rKnee.x = rKneeX;
rKnee.y = rKneeY;
// Lower legs: knees to opposite ankles (crossed under)
// --- Ava: Place lower leg bottom edges exactly on the ground ---
// The lower leg is anchored at (0.5, 0), so its bottom is at y + Math.cos(rotation + PI/2) * lowerLegH_px
var groundY = 2732 - 80;
var lowerLegH_px = 110 * 1.5;
// For each lower leg, solve for rotation so that the bottom edge is at groundY
// Left lower leg
lLowerLeg.x = lKnee.x;
lLowerLeg.y = lKnee.y;
// Find angle so that lLowerLeg.y + Math.cos(rotation + Math.PI/2) * lowerLegH_px = groundY
// Solve for rotation:
var lDeltaY = groundY - lLowerLeg.y;
var lAngle = Math.acos(Math.max(-1, Math.min(1, lDeltaY / lowerLegH_px))) - Math.PI / 2;
// If the knee is to the right of the hip center, flip the sign
if (lKnee.x < (lHip.x + rHip.x) / 2) lAngle = -lAngle;
lLowerLeg.rotation = lAngle;
// Right lower leg
rLowerLeg.x = rKnee.x;
rLowerLeg.y = rKnee.y;
var rDeltaY = groundY - rLowerLeg.y;
var rAngle = Math.acos(Math.max(-1, Math.min(1, rDeltaY / lowerLegH_px))) - Math.PI / 2;
if (rKnee.x > (lHip.x + rHip.x) / 2) rAngle = -rAngle;
rLowerLeg.rotation = rAngle;
// Now set knee positions and re-add to ensure they are on top
self.addChild(lKnee);
self.addChild(rKnee);
body.rotation = 0;
} else if (self.state.pose === 'jump') {
// Both upper legs up and slightly inward, knees together, feet up, using IK
// --- Keep knees and upper legs connected in jump pose ---
// --- Make both legs perfectly horizontally aligned in jump pose ---
var jumpThighAngle = 0.45;
var jumpKneeBend = 1.25; // radians, how much the knee is bent (smaller = straighter, larger = more bent)
// Set both hips at same y, and both knees at same y, for perfect horizontal alignment
// Calculate the average x between hips for knee position, and set a fixed y offset for knees
var avgHipY = (lHip.y + rHip.y) / 2;
var avgHipX = (lHip.x + rHip.x) / 2;
var kneeYOffset = -upperLegH * Math.cos(jumpThighAngle); // vertical offset from hips to knees
var kneeY = avgHipY + kneeYOffset;
var kneeXLeft = lHip.x + Math.sin(-jumpThighAngle - legAbduction) * upperLegH;
var kneeXRight = rHip.x + Math.sin(jumpThighAngle + legAbduction) * upperLegH;
// Both knees at same y
lKnee.x = kneeXLeft;
lKnee.y = kneeY;
rKnee.x = kneeXRight;
rKnee.y = kneeY;
// Upper legs: hips to knees
lUpperLeg.x = lHip.x;
lUpperLeg.y = lHip.y;
lUpperLeg.rotation = Math.atan2(lKnee.y - lUpperLeg.y, lKnee.x - lUpperLeg.x) - Math.PI / 2;
rUpperLeg.x = rHip.x;
rUpperLeg.y = rHip.y;
rUpperLeg.rotation = Math.atan2(rKnee.y - rUpperLeg.y, rKnee.x - rUpperLeg.x) - Math.PI / 2;
// Lower legs: knees to ankles, both at same y
// Left
lLowerLeg.x = lKnee.x;
lLowerLeg.y = lKnee.y;
var lJumpShinLen = lowerLegH;
var lJumpAnkleX = lKnee.x + Math.sin(lUpperLeg.rotation + Math.PI / 2 + jumpKneeBend) * lJumpShinLen;
var lJumpAnkleY = lKnee.y + Math.cos(lUpperLeg.rotation + Math.PI / 2 + jumpKneeBend) * lJumpShinLen;
lLowerLeg.rotation = Math.atan2(lJumpAnkleY - lKnee.y, lJumpAnkleX - lKnee.x) - Math.PI / 2;
// Right
rLowerLeg.x = rKnee.x;
rLowerLeg.y = rKnee.y;
var rJumpShinLen = lowerLegH;
var rJumpAnkleX = rKnee.x + Math.sin(rUpperLeg.rotation + Math.PI / 2 + jumpKneeBend) * rJumpShinLen;
var rJumpAnkleY = rKnee.y + Math.cos(rUpperLeg.rotation + Math.PI / 2 + jumpKneeBend) * rJumpShinLen;
rLowerLeg.rotation = Math.atan2(rJumpAnkleY - rKnee.y, rJumpAnkleX - rKnee.x) - Math.PI / 2;
// Elbows more bent in jump
lLowerArm.x = lElbow.x;
lLowerArm.y = lElbow.y;
lLowerArm.rotation = 2.0;
rLowerArm.x = rElbow.x;
rLowerArm.y = rElbow.y;
rLowerArm.rotation = -2.0;
body.rotation = 0;
} else if (self.state.pose === 'stand') {
// Gentle walk cycle if moving
var walk = Math.abs(self.state.vx) > 0.5 ? Math.sin(Date.now() * 0.008) * 0.25 : 0;
lUpperLegAngle += walk;
rUpperLegAngle -= walk;
lLowerLegAngle += walk * 0.5;
rLowerLegAngle -= walk * 0.5;
// Left leg
lUpperLeg.x = lHip.x;
lUpperLeg.y = lHip.y;
var lKneeX = lUpperLeg.x + Math.sin(lUpperLegAngle) * upperLegH;
var lKneeY = lUpperLeg.y + Math.cos(lUpperLegAngle) * upperLegH;
lKnee.x = lKneeX;
lKnee.y = lKneeY;
lUpperLeg.rotation = Math.atan2(lKnee.y - lUpperLeg.y, lKnee.x - lUpperLeg.x) - Math.PI / 2;
// Attach left lower leg to left knee
lLowerLeg.x = lKneeX;
lLowerLeg.y = lKneeY;
// Calculate ankle position for left leg
var lStandShinLen = lowerLegH;
var lStandAnkleX = lKneeX + Math.sin(lLowerLegAngle) * lStandShinLen;
var lStandAnkleY = lKneeY + Math.cos(lLowerLegAngle) * lStandShinLen;
lLowerLeg.rotation = Math.atan2(lStandAnkleY - lKneeY, lStandAnkleX - lKneeX) - Math.PI / 2;
// Right leg (mirror)
rUpperLeg.x = rHip.x;
rUpperLeg.y = rHip.y;
var rKneeX = rUpperLeg.x + Math.sin(rUpperLegAngle) * upperLegH;
var rKneeY = rUpperLeg.y + Math.cos(rUpperLegAngle) * upperLegH;
rKnee.x = rKneeX;
rKnee.y = rKneeY;
rUpperLeg.rotation = Math.atan2(rKnee.y - rUpperLeg.y, rKnee.x - rUpperLeg.x) - Math.PI / 2;
// Attach right lower leg to right knee
rLowerLeg.x = rKneeX;
rLowerLeg.y = rKneeY;
// Calculate ankle position for right leg
var rStandShinLen = lowerLegH;
var rStandAnkleX = rKneeX + Math.sin(rLowerLegAngle) * rStandShinLen;
var rStandAnkleY = rKneeY + Math.cos(rLowerLegAngle) * rStandShinLen;
rLowerLeg.rotation = Math.atan2(rStandAnkleY - rKneeY, rStandAnkleX - rKneeX) - Math.PI / 2;
body.rotation = 0;
}
}
// --- Public puppet actions ---
self.pullHeadLeft = function () {
// Pull head left, add leftward velocity
if (self.state.grounded) {
self.state.vx -= 12;
self.state.headAngle = -0.5;
tween(self.state, {
headAngle: 0
}, {
duration: 400,
easing: tween.easeOut
});
}
};
self.pullHeadRight = function () {
if (self.state.grounded) {
self.state.vx += 12;
self.state.headAngle = 0.5;
tween(self.state, {
headAngle: 0
}, {
duration: 400,
easing: tween.easeOut
});
}
};
self.jump = function () {
if (self.state.grounded) {
self.state.vy = -48; // Increased jump velocity for higher jump
self.state.grounded = false;
self.state.pose = 'jump';
tween(self.state, {}, {
duration: 0,
onFinish: function onFinish() {
// After 400ms, return to stand pose
LK.setTimeout(function () {
self.state.pose = 'stand';
}, 400);
}
});
}
};
self.sit = function () {
if (self.state.grounded && self.state.pose !== 'sit') {
self.state.pose = 'sit';
// After 600ms, stand up automatically
LK.setTimeout(function () {
self.stand();
}, 600);
}
};
self.stand = function () {
if (self.state.grounded && self.state.pose !== 'stand') {
self.state.pose = 'stand';
}
};
// --- Physics update ---
self.update = function () {
// --- Physics update ---
// TEST: Force puppet to always stay in sit pose for testing
self.state.pose = 'sit';
self.state.vy += 3.2; // gravity
self.state.x += self.state.vx;
self.state.y += self.state.vy;
// Friction
if (self.state.grounded) {
self.state.vx *= 0.82;
} else {
self.state.vx *= 0.98;
}
// Clamp to world bounds
if (self.state.x < 0) self.state.x = 0;
if (self.state.x > 2048) self.state.x = 2048;
// Ground collision
var groundY = 2732 - 80;
var puppetFeetOffset = bodyH / 2 + upperLegH + lowerLegH - 20;
var feetY = self.state.y + puppetFeetOffset;
if (feetY >= groundY) {
self.state.y = groundY - puppetFeetOffset;
self.state.vy = 0;
self.state.grounded = true;
if (self.state.pose === 'jump') {
self.state.pose = 'stand';
}
} else {
self.state.grounded = false;
}
// Apply to container (keep puppet at current position)
self.x = self.state.x;
self.y = self.state.y;
updateBodyParts();
};
// --- Start position ---
self.state.x = 600; // Moved puppet further right (was 180)
// --- Ava: Set initial Y so feet are above ground visually ---
var puppetFeetOffset = bodyH / 2 + upperLegH + lowerLegH - 20;
self.state.y = 2732 - 80 - puppetFeetOffset;
updateBodyParts();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Define and initialize the reverb object before using it
// Win/lose sound
// Drum tap sound
// Finish sign
// Ground
// Drums
// Puppet body parts (shapes)
// --- World setup ---
// Apply reverb to all drum and win/lose sounds
// Ava: background asset
var reverb = {
add: function add(sound) {
// Dummy implementation: does nothing, but prevents errors
// In a real environment, this would apply a reverb effect to the sound
}
};
reverb.add(LK.getSound('drum_tap_center'));
reverb.add(LK.getSound('drum_tap_left'));
reverb.add(LK.getSound('drum_tap_right'));
reverb.add(LK.getSound('drum_tap_sit'));
reverb.add(LK.getSound('drum_tap_stand'));
reverb.add(LK.getSound('lose'));
reverb.add(LK.getSound('win'));
// --- Background music playlist (4 tracks, play in random order) ---
var musicTracks = [{
id: 'musicId',
volume: 0.1,
start: 0,
end: 1
}, {
id: 'musicId2',
volume: 0.1,
start: 0,
end: 1
}, {
id: 'musicId3',
volume: 0.1,
start: 0,
end: 1
}, {
id: 'musicId4',
volume: 0.1,
start: 0,
end: 1
}];
// Shuffle helper (Fisher-Yates)
function shuffleArray(arr) {
for (var i = arr.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// Maintain a shuffled playlist order
var shuffledMusicOrder = [];
function reshuffleMusicOrder() {
shuffledMusicOrder = [];
for (var i = 0; i < musicTracks.length; ++i) shuffledMusicOrder.push(i);
shuffleArray(shuffledMusicOrder);
}
reshuffleMusicOrder();
var currentMusicOrderIndex = 0;
// Play the next music track in the shuffled order, and keep playing forever
function playNextMusic() {
// If we've played all, reshuffle for a new random order
if (currentMusicOrderIndex >= shuffledMusicOrder.length) {
reshuffleMusicOrder();
currentMusicOrderIndex = 0;
}
var trackIndex = shuffledMusicOrder[currentMusicOrderIndex];
var track = musicTracks[trackIndex];
// Play music and set up onFinish to play the next one
LK.playMusic(track.id, {
loop: false,
volume: track.volume,
start: track.start,
end: track.end,
onFinish: function onFinish() {
currentMusicOrderIndex++;
playNextMusic();
}
});
}
playNextMusic();
game.setBackgroundColor(0x000000);
// --- Background ---
// Ava: Add background image behind all elements
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 1,
scaleY: 1
});
game.addChild(background);
// Ground
var ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0
});
ground.x = 0;
ground.y = 2732 - 80;
game.addChild(ground);
// Finish sign
var finishSign = LK.getAsset('finish_sign', {
anchorX: 0.5,
anchorY: 1,
scaleX: 3,
scaleY: 6 // 2x as tall as before
});
finishSign.x = 2048 - 120;
finishSign.y = 2732 - 80;
game.addChild(finishSign);
// Finish text removed
// --- Puppet ---
var puppet = new Puppet();
game.addChild(puppet);
// --- Drums ---
var drums = [];
// Drum positions (relative to center)
// Move drums higher: set drumCenterY above puppet's head
var drumCenterX = 2048 / 2,
drumCenterY = 900; // was 2732 / 2 + 220, now much higher (puppet head is around y=~1200)
var drumRadius = 220 * 3;
var angleList = [{
type: 'left',
angle: -Math.PI / 2 - 0.7
}, {
type: 'right',
angle: -Math.PI / 2 + 0.7
}, {
type: 'sit',
angle: Math.PI / 2 + 0.7
}, {
type: 'stand',
angle: Math.PI / 2 - 0.7
}];
// --- Drum action pool ---
// Each drum will have all actions, only their order will be shuffled
// Ava: Increase the number of right movement actions (pullHeadRight) in the action pool
var puppetActions = [function () {
puppet.pullHeadLeft();
}, function () {
puppet.pullHeadRight();
}, function () {
puppet.pullHeadRight();
}, function () {
puppet.jump();
}, function () {
puppet.sit();
}, function () {
puppet.stand();
}];
// Large center drum (fixed action sequence)
var drumJump = new Drum();
drumJump.setDrum('large');
drumJump.x = drumCenterX;
drumJump.y = drumCenterY;
// Assign a fixed sequence of all 5 actions, and cycle through them
drumJump._actionSequence = puppetActions.slice();
drumJump._actionIndex = 0;
drumJump.action = function () {
drumJump._actionSequence[drumJump._actionIndex]();
drumJump._actionIndex = (drumJump._actionIndex + 1) % drumJump._actionSequence.length;
};
game.addChild(drumJump);
drums.push(drumJump);
// Four medium drums
for (var i = 0; i < angleList.length; ++i) {
var d = new Drum();
d.setDrum(angleList[i].type);
d.x = drumCenterX + Math.cos(angleList[i].angle) * drumRadius;
d.y = drumCenterY + Math.sin(angleList[i].angle) * drumRadius;
// Each drum gets a fixed sequence of all 5 actions, and cycles through them
d._actionSequence = puppetActions.slice();
d._actionIndex = 0;
d.action = function (drum) {
return function () {
drum._actionSequence[drum._actionIndex]();
drum._actionIndex = (drum._actionIndex + 1) % drum._actionSequence.length;
};
}(d);
game.addChild(d);
drums.push(d);
}
// --- Timer ---
var timeLeft = 60;
function formatTimeDigital(secs) {
var m = Math.floor(secs / 60);
var s = secs % 60;
var mm = m < 10 ? "0" + m : "" + m;
var ss = s < 10 ? "0" + s : "" + s;
return mm + ":" + ss;
}
var timerText = new Text2(formatTimeDigital(60), {
size: 120,
fill: '#ffffff'
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
// --- Score/Win state ---
var gameEnded = false;
// --- Timer logic ---
var timerInterval = LK.setInterval(function () {
if (gameEnded) return;
timeLeft -= 1;
if (timeLeft < 0) timeLeft = 0;
timerText.setText(formatTimeDigital(timeLeft));
if (timeLeft === 0 && !gameEnded) {
gameEnded = true;
LK.getSound('lose').play();
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
}, 1000);
// --- Game update ---
game.update = function () {
if (gameEnded) return;
puppet.update();
// Win condition: puppet body collides with finish sign using intersects
if (!gameEnded && puppet.intersects(finishSign)) {
gameEnded = true;
LK.setScore(timeLeft); // Set score to remaining seconds
LK.getSound('win').play();
LK.effects.flashScreen(0x44c767, 800);
LK.showYouWin();
}
};
// --- Clean up on game over ---
game.onDestroy = function () {
LK.clearInterval(timerInterval);
};
// --- Prevent accidental tap on top left (menu) ---
/* No elements are placed at (0,0)-(100,100) */
// --- UX: drums are always on top ---
for (var i = 0; i < drums.length; ++i) {
game.addChild(drums[i]);
} ===================================================================
--- original.js
+++ change.js
@@ -399,38 +399,29 @@
rKnee.x = rKneeX;
rKnee.y = rKneeY;
// Lower legs: knees to opposite ankles (crossed under)
// --- Ava: Place lower leg bottom edges exactly on the ground ---
+ // The lower leg is anchored at (0.5, 0), so its bottom is at y + Math.cos(rotation + PI/2) * lowerLegH_px
var groundY = 2732 - 80;
var lowerLegH_px = 110 * 1.5;
- var lLowerLegBottomY = groundY;
- var rLowerLegBottomY = groundY;
- // For each lower leg, solve for ankle position so that the bottom edge of the lower leg is at groundY
- // The lower leg is anchored at (0.5, 0), so its bottom is at y + Math.cos(rotation + PI/2) * lowerLegH_px
- // We'll solve for the ankle position so that this is true
+ // For each lower leg, solve for rotation so that the bottom edge is at groundY
// Left lower leg
- var lKneeToAnkleLen = lowerLegH_px;
- var lKneeX_to_ankle = hipsMidX - crossAnkleSpread;
- var lKneeY_to_ankle = groundY - lKnee.y;
- var lLowerLegAngle = Math.atan2(lKneeY_to_ankle, lKneeX_to_ankle - lKnee.x);
- var lAnkleX = lKnee.x + Math.sin(lLowerLegAngle) * lKneeToAnkleLen;
- var lAnkleY = lKnee.y + Math.cos(lLowerLegAngle) * lKneeToAnkleLen;
- // But we want the bottom of the lower leg to be at groundY, so adjust
- lAnkleY = groundY;
lLowerLeg.x = lKnee.x;
lLowerLeg.y = lKnee.y;
- lLowerLeg.rotation = Math.atan2(lAnkleY - lKnee.y, lAnkleX - lKnee.x) - Math.PI / 2;
+ // Find angle so that lLowerLeg.y + Math.cos(rotation + Math.PI/2) * lowerLegH_px = groundY
+ // Solve for rotation:
+ var lDeltaY = groundY - lLowerLeg.y;
+ var lAngle = Math.acos(Math.max(-1, Math.min(1, lDeltaY / lowerLegH_px))) - Math.PI / 2;
+ // If the knee is to the right of the hip center, flip the sign
+ if (lKnee.x < (lHip.x + rHip.x) / 2) lAngle = -lAngle;
+ lLowerLeg.rotation = lAngle;
// Right lower leg
- var rKneeToAnkleLen = lowerLegH_px;
- var rKneeX_to_ankle = hipsMidX + crossAnkleSpread;
- var rKneeY_to_ankle = groundY - rKnee.y;
- var rLowerLegAngle = Math.atan2(rKneeY_to_ankle, rKneeX_to_ankle - rKnee.x);
- var rAnkleX = rKnee.x + Math.sin(rLowerLegAngle) * rKneeToAnkleLen;
- var rAnkleY = rKnee.y + Math.cos(rLowerLegAngle) * rKneeToAnkleLen;
- rAnkleY = groundY;
rLowerLeg.x = rKnee.x;
rLowerLeg.y = rKnee.y;
- rLowerLeg.rotation = Math.atan2(rAnkleY - rKnee.y, rAnkleX - rKnee.x) - Math.PI / 2;
+ var rDeltaY = groundY - rLowerLeg.y;
+ var rAngle = Math.acos(Math.max(-1, Math.min(1, rDeltaY / lowerLegH_px))) - Math.PI / 2;
+ if (rKnee.x > (lHip.x + rHip.x) / 2) rAngle = -rAngle;
+ rLowerLeg.rotation = rAngle;
// Now set knee positions and re-add to ensure they are on top
self.addChild(lKnee);
self.addChild(rKnee);
body.rotation = 0;