User prompt
Zıplama da kalça bacak diz hizalı ve aşağı düsun
User prompt
Zıplamada bacaklar ve dizler bağlı olsun.
User prompt
Zıplamadan sonra kollar ve bacaklar yere düşen ik olsun.
User prompt
Yere düşerken çok yavas ol.
User prompt
Zıplamada body parts tam birbirine simetrik olsun
User prompt
Zıplamada body parts simetrik hareket etsin. Stand islevinde kollar iki yana açılsın.
User prompt
Zıplamada body parts simetrik hareket etsin. Zıplamadan sonra yere düserken Slow motion bur efekt uygula
User prompt
Zıplama oturma ve kalkma tüm bunlar belly dancer gibi kıvrak figürlwr olsun.
User prompt
Zıplama dahq gerçekci olsun. Oturma ve kalma kollar açıp kapatsın.
User prompt
Zımplamayı simetrik ik ile güncelle.
User prompt
Zıplamada body parts mirror şekilde yukarı zıplasın.
User prompt
Bacakları da aşağıya düşür.
User prompt
Kolları aşağıya düşür.
User prompt
Dirsekte ters kırilma olmasın kollar aşağıya sarksın
User prompt
Kollar ve dirsek açık dursun
User prompt
Kolları sağa ve sola aç dans eder gibi olsun
User prompt
Kollar dirsek bağlantısıni güncelle
User prompt
Kollar dirsekten aşağıda olsun
User prompt
Dirsek dışarıda olmasın ters çevir
User prompt
Omuz ve kolları ik kinematik tekrar düzenle
User prompt
Kollar ik kinematik ters oldu.
User prompt
update ik kinematik for body parts
User prompt
drum_tap_right davula tıklayınca sese çok uzun reverb efekti uygula
User prompt
drum_tap_left davula tıklayınca sese çok uzun reverb efekti uygula.
User prompt
drum_tap_sit davula tıklayınca sese orta aralıklı 2 kez delay efekti uygula.
/****
* 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
});
// Body
var body = self.attachAsset('puppet_body', {
anchorX: 0.5,
anchorY: 0,
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 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 lower arm
var rLowerArm = self.attachAsset('puppet_lowerarm', {
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 lower leg
var lLowerLeg = self.attachAsset('puppet_lowerleg', {
anchorX: 0.5,
anchorY: 0,
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 lower leg
var rLowerLeg = self.attachAsset('puppet_lowerleg', {
anchorX: 0.5,
anchorY: 0,
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
};
// --- Positioning offsets (relative to puppet center) ---
function updateBodyParts() {
// Head
head.x = 0;
head.y = -bodyH / 2 - headH / 2 + 10;
head.rotation = self.state.headAngle;
// Body
body.x = 0;
body.y = -bodyH / 2;
// Arms
var armY = -bodyH / 2 + 30;
var armX = bodyW / 2 + upperArmW / 2 - 10;
// Shoulder positions
var lShoulderX = -armX;
var lShoulderY = armY;
var rShoulderX = armX;
var rShoulderY = armY;
// --- Improved arm kinematics ---
// Default arm pose angles
var lUpperArmAngle = -0.18;
var rUpperArmAngle = 0.18;
var lLowerArmAngle = 0.25;
var rLowerArmAngle = -0.25;
// Pose-based arm animation
if (self.state.pose === 'sit') {
lUpperArmAngle = -1.25;
rUpperArmAngle = 1.25;
lLowerArmAngle = 1.5;
rLowerArmAngle = -1.5;
} else if (self.state.pose === 'jump') {
lUpperArmAngle = -0.9;
rUpperArmAngle = 0.9;
lLowerArmAngle = 1.2;
rLowerArmAngle = -1.2;
// Symmetric arm movement: mirror left/right
lUpperArmAngle = -Math.abs(lUpperArmAngle);
rUpperArmAngle = Math.abs(rUpperArmAngle);
lLowerArmAngle = Math.abs(lLowerArmAngle);
rLowerArmAngle = -Math.abs(rLowerArmAngle);
} else if (self.state.pose === 'stand') {
// Gentle swing based on horizontal velocity for more life
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 upper arm
lUpperArm.x = lShoulderX;
lUpperArm.y = lShoulderY;
lUpperArm.rotation = lUpperArmAngle;
// Left elbow position
var lElbowX = lUpperArm.x + Math.sin(lUpperArmAngle) * upperArmH;
var lElbowY = lUpperArm.y + Math.cos(lUpperArmAngle) * upperArmH;
// Left lower arm
lLowerArm.x = lElbowX;
lLowerArm.y = lElbowY;
lLowerArm.rotation = lLowerArmAngle;
// Right upper arm
rUpperArm.x = rShoulderX;
rUpperArm.y = rShoulderY;
rUpperArm.rotation = rUpperArmAngle;
// Right elbow position
var rElbowX = rUpperArm.x + Math.sin(rUpperArmAngle) * upperArmH;
var rElbowY = rUpperArm.y + Math.cos(rUpperArmAngle) * upperArmH;
// Right lower arm
rLowerArm.x = rElbowX;
rLowerArm.y = rElbowY;
rLowerArm.rotation = rLowerArmAngle;
// --- Improved leg kinematics ---
var legY = bodyH / 2 - 10;
var legX = bodyW / 2 - 18;
// Default leg pose
var lUpperLegAngle = 0.18;
var rUpperLegAngle = -0.18;
var lLowerLegAngle = 0.25;
var rLowerLegAngle = -0.25;
// Pose-based leg animation
if (self.state.pose === 'sit') {
lUpperLegAngle = 1.35;
rUpperLegAngle = 1.35;
lLowerLegAngle = lUpperLegAngle - Math.PI / 2 + 0.15;
rLowerLegAngle = rUpperLegAngle - Math.PI / 2 - 0.15;
} else if (self.state.pose === 'jump') {
lUpperLegAngle = -0.95;
rUpperLegAngle = -0.95;
lLowerLegAngle = lUpperLegAngle + 1.7;
rLowerLegAngle = rUpperLegAngle + 1.7;
// Symmetric leg movement: mirror left/right
lUpperLegAngle = -Math.abs(lUpperLegAngle);
rUpperLegAngle = -Math.abs(rUpperLegAngle);
lLowerLegAngle = Math.abs(lLowerLegAngle);
rLowerLegAngle = Math.abs(rLowerLegAngle);
} 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 upper leg
lUpperLeg.x = -legX;
lUpperLeg.y = legY;
lUpperLeg.rotation = lUpperLegAngle;
// Calculate left knee position
var lKneeX = lUpperLeg.x + Math.sin(lUpperLegAngle) * upperLegH;
var lKneeY = lUpperLeg.y + Math.cos(lUpperLegAngle) * upperLegH;
// Attach lower leg at knee, rotate for more natural foot placement
lLowerLeg.x = lKneeX;
lLowerLeg.y = lKneeY;
lLowerLeg.rotation = lLowerLegAngle;
// Right upper leg
rUpperLeg.x = legX;
rUpperLeg.y = legY;
rUpperLeg.rotation = rUpperLegAngle;
// Calculate right knee position
var rKneeX = rUpperLeg.x + Math.sin(rUpperLegAngle) * upperLegH;
var rKneeY = rUpperLeg.y + Math.cos(rUpperLegAngle) * upperLegH;
// Attach lower leg at knee, rotate for more natural foot placement
rLowerLeg.x = rKneeX;
rLowerLeg.y = rKneeY;
rLowerLeg.rotation = rLowerLegAngle;
// Pose adjustments
if (self.state.pose === 'sit') {
// Sitting: thighs forward, knees bent, shins down
lUpperLeg.rotation = 1.35;
var lKneeX = lUpperLeg.x + Math.sin(lUpperLeg.rotation) * upperLegH;
var lKneeY = lUpperLeg.y + Math.cos(lUpperLeg.rotation) * upperLegH;
lLowerLeg.x = lKneeX;
lLowerLeg.y = lKneeY;
lLowerLeg.rotation = lUpperLeg.rotation - Math.PI / 2 + 0.15;
rUpperLeg.rotation = 1.35;
var rKneeX = rUpperLeg.x + Math.sin(rUpperLeg.rotation) * upperLegH;
var rKneeY = rUpperLeg.y + Math.cos(rUpperLeg.rotation) * upperLegH;
rLowerLeg.x = rKneeX;
rLowerLeg.y = rKneeY;
rLowerLeg.rotation = rUpperLeg.rotation - Math.PI / 2 - 0.15;
body.rotation = -0.18;
} else if (self.state.pose === 'jump') {
// Jump: legs up, knees bent
lUpperLeg.rotation = -0.95;
var lKneeX = lUpperLeg.x + Math.sin(lUpperLeg.rotation) * upperLegH;
var lKneeY = lUpperLeg.y + Math.cos(lUpperLeg.rotation) * upperLegH;
lLowerLeg.x = lKneeX;
lLowerLeg.y = lKneeY;
lLowerLeg.rotation = lUpperLeg.rotation + 1.7;
rUpperLeg.rotation = -0.95;
var rKneeX = rUpperLeg.x + Math.sin(rUpperLeg.rotation) * upperLegH;
var rKneeY = rUpperLeg.y + Math.cos(rUpperLeg.rotation) * upperLegH;
rLowerLeg.x = rKneeX;
rLowerLeg.y = rKneeY;
rLowerLeg.rotation = rUpperLeg.rotation + 1.7;
body.rotation = 0.12;
} else {
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 () {
// Gravity
if (!self.state.grounded) {
// Detect transition: start of falling after jump
if (typeof self.lastVy === "undefined") self.lastVy = 0;
if (self.lastVy < 0 && self.state.vy >= 0) {
// Just started falling (apex of jump)
if (typeof LK.effects !== "undefined" && LK.effects.blurScreen) {
LK.effects.blurScreen(0.7, 400); // Apply a moderate blur for 400ms
}
if (typeof LK.effects !== "undefined" && LK.effects.slowMotion) {
LK.effects.slowMotion(0.4, 400); // Slow motion to 40% for 400ms
}
}
self.state.vy += 2.2; // gravity
if (self.state.vy > 40) self.state.vy = 40;
self.lastVy = self.state.vy;
} else {
self.lastVy = 0;
}
// Friction
if (self.state.grounded) {
self.state.vx *= 0.82;
if (Math.abs(self.state.vx) < 0.5) self.state.vx = 0;
} else {
self.state.vx *= 0.98;
}
// Move
self.state.x += self.state.vx;
self.state.y += self.state.vy;
// Clamp to world bounds
if (self.state.x < 80) self.state.x = 80;
if (self.state.x > 2048 - 80) self.state.x = 2048 - 80;
// --- Ava: Adjust puppet Y so feet are above ground visually ---
// The puppet's feet are at y + (bodyH/2) + upperLegH + lowerLegH - 10 - 10
// ground.y = 2732 - 80, ground height = 80
// So, puppet.y + (bodyH/2) + upperLegH + lowerLegH - 20 = 2732 - 80
// puppet.y = 2732 - 80 - (bodyH/2) - upperLegH - lowerLegH + 20
var puppetFeetOffset = bodyH / 2 + upperLegH + lowerLegH - 20;
var puppetGroundY = 2732 - 80 - puppetFeetOffset;
if (self.state.y > puppetGroundY) self.state.y = puppetGroundY; // above ground
// Ground collision
if (self.state.y >= puppetGroundY) {
self.state.y = puppetGroundY;
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
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
****/
// Ava: background asset
// Apply reverb to all drum and win/lose sounds
// --- World setup ---
// Puppet body parts (shapes)
// Drums
// Ground
// Finish sign
// Drum tap sound
// Win/lose sound
// Define and initialize the reverb object before using it
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;
}
}
// Start with a shuffled playlist
var shuffledMusicOrder = [];
function reshuffleMusicOrder() {
shuffledMusicOrder = [];
for (var i = 0; i < musicTracks.length; ++i) shuffledMusicOrder.push(i);
shuffleArray(shuffledMusicOrder);
}
reshuffleMusicOrder();
var currentMusicOrderIndex = 0;
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];
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
@@ -199,169 +199,154 @@
head.rotation = self.state.headAngle;
// Body
body.x = 0;
body.y = -bodyH / 2;
- // --- 2D IK for ARMS ---
- // Shoulder positions
+ // Arms
var armY = -bodyH / 2 + 30;
var armX = bodyW / 2 + upperArmW / 2 - 10;
+ // Shoulder positions
var lShoulderX = -armX;
var lShoulderY = armY;
var rShoulderX = armX;
var rShoulderY = armY;
- // Target hand positions (relative to puppet center)
- // Animate hand targets based on pose
- var t = Date.now() * 0.002;
- var bellySway = Math.sin(t * 1.7) * 32;
- var bellyWave = Math.sin(t * 2.7) * 18;
- var bellyTwist = Math.sin(t * 1.1) * 0.18;
- var lHandTarget, rHandTarget;
+ // --- Improved arm kinematics ---
+ // Default arm pose angles
+ var lUpperArmAngle = -0.18;
+ var rUpperArmAngle = 0.18;
+ var lLowerArmAngle = 0.25;
+ var rLowerArmAngle = -0.25;
+ // Pose-based arm animation
if (self.state.pose === 'sit') {
- // Arms open wide in sit, with undulating wrists and elbows
- var open = 200 + Math.sin(t * 2.2) * 40;
- lHandTarget = {
- x: lShoulderX - open + bellySway,
- y: lShoulderY + 520 + Math.sin(t * 3.1) * 30
- };
- rHandTarget = {
- x: rShoulderX + open + bellySway,
- y: rShoulderY + 520 + Math.cos(t * 3.1) * 30
- };
+ lUpperArmAngle = -1.25;
+ rUpperArmAngle = 1.25;
+ lLowerArmAngle = 1.5;
+ rLowerArmAngle = -1.5;
} else if (self.state.pose === 'jump') {
- // Arms up in jump, with a wavy, fluttering motion
- lHandTarget = {
- x: lShoulderX - 40 + Math.sin(t * 4.2) * 30,
- y: lShoulderY - 120 + Math.cos(t * 2.7) * 24
- };
- rHandTarget = {
- x: rShoulderX + 40 + Math.cos(t * 4.2) * 30,
- y: rShoulderY - 120 + Math.sin(t * 2.7) * 24
- };
+ lUpperArmAngle = -0.9;
+ rUpperArmAngle = 0.9;
+ lLowerArmAngle = 1.2;
+ rLowerArmAngle = -1.2;
+ // Symmetric arm movement: mirror left/right
+ lUpperArmAngle = -Math.abs(lUpperArmAngle);
+ rUpperArmAngle = Math.abs(rUpperArmAngle);
+ lLowerArmAngle = Math.abs(lLowerArmAngle);
+ rLowerArmAngle = -Math.abs(rLowerArmAngle);
} else if (self.state.pose === 'stand') {
- // Arms undulate and wrists flick in a belly dance style
- var open = 120 + Math.abs(Math.sin(t)) * 120 + Math.sin(t * 2.1) * 30;
- lHandTarget = {
- x: lShoulderX - open + bellySway,
- y: lShoulderY + 400 + Math.abs(Math.sin(t)) * 30 + bellyWave
- };
- rHandTarget = {
- x: rShoulderX + open + bellySway,
- y: rShoulderY + 400 + Math.abs(Math.sin(t + 0.5)) * 30 + bellyWave
- };
+ // Gentle swing based on horizontal velocity for more life
+ 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;
}
- // 2D IK for left arm
- function solveIK2D(sx, sy, ex, ey, l1, l2) {
- // Returns {ax, ay, bx, by, aAngle, bAngle}
- var dx = ex - sx,
- dy = ey - sy;
- var dist = Math.sqrt(dx * dx + dy * dy);
- dist = Math.min(dist, l1 + l2 - 0.01); // Clamp to reachable
- var a1 = Math.acos((l1 * l1 + dist * dist - l2 * l2) / (2 * l1 * dist));
- var a2 = Math.atan2(dy, dx);
- var upperAngle = a2 - a1;
- var elbowX = sx + Math.cos(upperAngle) * l1;
- var elbowY = sy + Math.sin(upperAngle) * l1;
- var lowerAngle = Math.atan2(ey - elbowY, ex - elbowX);
- return {
- ax: sx,
- ay: sy,
- bx: elbowX,
- by: elbowY,
- aAngle: upperAngle,
- bAngle: lowerAngle
- };
- }
- // Left arm
- var lArmIK = solveIK2D(lShoulderX, lShoulderY, lHandTarget.x, lHandTarget.y, upperArmH, lowerArmH);
- lUpperArm.x = lArmIK.ax;
- lUpperArm.y = lArmIK.ay;
- lUpperArm.rotation = lArmIK.aAngle - Math.PI / 2;
- lLowerArm.x = lArmIK.bx;
- lLowerArm.y = lArmIK.by;
- lLowerArm.rotation = lArmIK.bAngle - Math.PI / 2;
- // Right arm
- var rArmIK = solveIK2D(rShoulderX, rShoulderY, rHandTarget.x, rHandTarget.y, upperArmH, lowerArmH);
- rUpperArm.x = rArmIK.ax;
- rUpperArm.y = rArmIK.ay;
- rUpperArm.rotation = rArmIK.aAngle - Math.PI / 2;
- rLowerArm.x = rArmIK.bx;
- rLowerArm.y = rArmIK.by;
- rLowerArm.rotation = rArmIK.bAngle - Math.PI / 2;
- // --- 2D IK for LEGS ---
+ // Left upper arm
+ lUpperArm.x = lShoulderX;
+ lUpperArm.y = lShoulderY;
+ lUpperArm.rotation = lUpperArmAngle;
+ // Left elbow position
+ var lElbowX = lUpperArm.x + Math.sin(lUpperArmAngle) * upperArmH;
+ var lElbowY = lUpperArm.y + Math.cos(lUpperArmAngle) * upperArmH;
+ // Left lower arm
+ lLowerArm.x = lElbowX;
+ lLowerArm.y = lElbowY;
+ lLowerArm.rotation = lLowerArmAngle;
+ // Right upper arm
+ rUpperArm.x = rShoulderX;
+ rUpperArm.y = rShoulderY;
+ rUpperArm.rotation = rUpperArmAngle;
+ // Right elbow position
+ var rElbowX = rUpperArm.x + Math.sin(rUpperArmAngle) * upperArmH;
+ var rElbowY = rUpperArm.y + Math.cos(rUpperArmAngle) * upperArmH;
+ // Right lower arm
+ rLowerArm.x = rElbowX;
+ rLowerArm.y = rElbowY;
+ rLowerArm.rotation = rLowerArmAngle;
+ // --- Improved leg kinematics ---
var legY = bodyH / 2 - 10;
var legX = bodyW / 2 - 18;
- var lHipX = -legX;
- var lHipY = legY;
- var rHipX = legX;
- var rHipY = legY;
- // Target foot positions (relative to puppet center)
- // Lower both legs by increasing the y value of the foot targets
- var t = Date.now() * 0.002;
- var bellySway = Math.sin(t * 1.7) * 32;
- var bellyWave = Math.sin(t * 2.7) * 18;
- var lFootTarget, rFootTarget;
+ // Default leg pose
+ var lUpperLegAngle = 0.18;
+ var rUpperLegAngle = -0.18;
+ var lLowerLegAngle = 0.25;
+ var rLowerLegAngle = -0.25;
+ // Pose-based leg animation
if (self.state.pose === 'sit') {
- lFootTarget = {
- x: lHipX + 100 + Math.sin(t * 2.2) * 30,
- y: lHipY + upperLegH + lowerLegH + 120 + Math.cos(t * 2.7) * 18
- };
- rFootTarget = {
- x: rHipX + 100 + Math.cos(t * 2.2) * 30,
- y: rHipY + upperLegH + lowerLegH + 120 + Math.sin(t * 2.7) * 18
- };
+ lUpperLegAngle = 1.35;
+ rUpperLegAngle = 1.35;
+ lLowerLegAngle = lUpperLegAngle - Math.PI / 2 + 0.15;
+ rLowerLegAngle = rUpperLegAngle - Math.PI / 2 - 0.15;
} else if (self.state.pose === 'jump') {
- lFootTarget = {
- x: lHipX - 60 + Math.sin(t * 3.1) * 30,
- y: lHipY + 40 + Math.cos(t * 2.1) * 18
- };
- rFootTarget = {
- x: rHipX + 60 + Math.cos(t * 3.1) * 30,
- y: rHipY + 40 + Math.sin(t * 2.1) * 18
- };
+ lUpperLegAngle = -0.95;
+ rUpperLegAngle = -0.95;
+ lLowerLegAngle = lUpperLegAngle + 1.7;
+ rLowerLegAngle = rUpperLegAngle + 1.7;
+ // Symmetric leg movement: mirror left/right
+ lUpperLegAngle = -Math.abs(lUpperLegAngle);
+ rUpperLegAngle = -Math.abs(rUpperLegAngle);
+ lLowerLegAngle = Math.abs(lLowerLegAngle);
+ rLowerLegAngle = Math.abs(rLowerLegAngle);
} else if (self.state.pose === 'stand') {
- // Gentle walk cycle if moving, with belly dance undulation
- var walk = Math.abs(self.state.vx) > 0.5 ? Math.sin(Date.now() * 0.008) * 60 : 0;
- lFootTarget = {
- x: lHipX - 10 + walk + bellySway,
- y: lHipY + upperLegH + lowerLegH + 120 + Math.abs(walk) * 0.2 + bellyWave
- };
- rFootTarget = {
- x: rHipX + 10 - walk + bellySway,
- y: rHipY + upperLegH + lowerLegH + 120 + Math.abs(walk) * 0.2 + bellyWave
- };
+ // 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;
}
- // 2D IK for left leg
- var lLegIK = solveIK2D(lHipX, lHipY, lFootTarget.x, lFootTarget.y, upperLegH, lowerLegH);
- lUpperLeg.x = lLegIK.ax;
- lUpperLeg.y = lLegIK.ay;
- lUpperLeg.rotation = lLegIK.aAngle - Math.PI / 2;
- lLowerLeg.x = lLegIK.bx;
- lLowerLeg.y = lLegIK.by;
- lLowerLeg.rotation = lLegIK.bAngle - Math.PI / 2;
- // 2D IK for right leg
- var rLegIK = solveIK2D(rHipX, rHipY, rFootTarget.x, rFootTarget.y, upperLegH, lowerLegH);
- rUpperLeg.x = rLegIK.ax;
- rUpperLeg.y = rLegIK.ay;
- rUpperLeg.rotation = rLegIK.aAngle - Math.PI / 2;
- rLowerLeg.x = rLegIK.bx;
- rLowerLeg.y = rLegIK.by;
- rLowerLeg.rotation = rLegIK.bAngle - Math.PI / 2;
- // Body rotation and sway for belly dancer style
- var t = Date.now() * 0.002;
- var bellyTwist = Math.sin(t * 1.1) * 0.18;
- var bellySway = Math.sin(t * 1.7) * 32;
+ // Left upper leg
+ lUpperLeg.x = -legX;
+ lUpperLeg.y = legY;
+ lUpperLeg.rotation = lUpperLegAngle;
+ // Calculate left knee position
+ var lKneeX = lUpperLeg.x + Math.sin(lUpperLegAngle) * upperLegH;
+ var lKneeY = lUpperLeg.y + Math.cos(lUpperLegAngle) * upperLegH;
+ // Attach lower leg at knee, rotate for more natural foot placement
+ lLowerLeg.x = lKneeX;
+ lLowerLeg.y = lKneeY;
+ lLowerLeg.rotation = lLowerLegAngle;
+ // Right upper leg
+ rUpperLeg.x = legX;
+ rUpperLeg.y = legY;
+ rUpperLeg.rotation = rUpperLegAngle;
+ // Calculate right knee position
+ var rKneeX = rUpperLeg.x + Math.sin(rUpperLegAngle) * upperLegH;
+ var rKneeY = rUpperLeg.y + Math.cos(rUpperLegAngle) * upperLegH;
+ // Attach lower leg at knee, rotate for more natural foot placement
+ rLowerLeg.x = rKneeX;
+ rLowerLeg.y = rKneeY;
+ rLowerLeg.rotation = rLowerLegAngle;
+ // Pose adjustments
if (self.state.pose === 'sit') {
- body.rotation = -0.18 + bellyTwist * 0.7;
- body.x = bellySway * 0.5;
- head.rotation = self.state.headAngle + bellyTwist * 0.5;
+ // Sitting: thighs forward, knees bent, shins down
+ lUpperLeg.rotation = 1.35;
+ var lKneeX = lUpperLeg.x + Math.sin(lUpperLeg.rotation) * upperLegH;
+ var lKneeY = lUpperLeg.y + Math.cos(lUpperLeg.rotation) * upperLegH;
+ lLowerLeg.x = lKneeX;
+ lLowerLeg.y = lKneeY;
+ lLowerLeg.rotation = lUpperLeg.rotation - Math.PI / 2 + 0.15;
+ rUpperLeg.rotation = 1.35;
+ var rKneeX = rUpperLeg.x + Math.sin(rUpperLeg.rotation) * upperLegH;
+ var rKneeY = rUpperLeg.y + Math.cos(rUpperLeg.rotation) * upperLegH;
+ rLowerLeg.x = rKneeX;
+ rLowerLeg.y = rKneeY;
+ rLowerLeg.rotation = rUpperLeg.rotation - Math.PI / 2 - 0.15;
+ body.rotation = -0.18;
} else if (self.state.pose === 'jump') {
- body.rotation = 0.12 + bellyTwist * 0.8;
- body.x = bellySway * 0.7;
- head.rotation = self.state.headAngle + bellyTwist * 0.7;
+ // Jump: legs up, knees bent
+ lUpperLeg.rotation = -0.95;
+ var lKneeX = lUpperLeg.x + Math.sin(lUpperLeg.rotation) * upperLegH;
+ var lKneeY = lUpperLeg.y + Math.cos(lUpperLeg.rotation) * upperLegH;
+ lLowerLeg.x = lKneeX;
+ lLowerLeg.y = lKneeY;
+ lLowerLeg.rotation = lUpperLeg.rotation + 1.7;
+ rUpperLeg.rotation = -0.95;
+ var rKneeX = rUpperLeg.x + Math.sin(rUpperLeg.rotation) * upperLegH;
+ var rKneeY = rUpperLeg.y + Math.cos(rUpperLeg.rotation) * upperLegH;
+ rLowerLeg.x = rKneeX;
+ rLowerLeg.y = rKneeY;
+ rLowerLeg.rotation = rUpperLeg.rotation + 1.7;
+ body.rotation = 0.12;
} else {
- body.rotation = bellyTwist;
- body.x = bellySway;
- head.rotation = self.state.headAngle + bellyTwist * 0.6;
+ body.rotation = 0;
}
}
// --- Public puppet actions ---
self.pullHeadLeft = function () {
@@ -390,15 +375,20 @@
}
};
self.jump = function () {
if (self.state.grounded) {
- // Give a strong initial jump velocity
- self.state.vy = -52 + Math.abs(self.state.vx) * -0.18; // Higher jump if running
+ self.state.vy = -48; // Increased jump velocity for higher jump
self.state.grounded = false;
self.state.pose = 'jump';
- // Track jump time for variable hang time
- self._jumpStartTime = Date.now();
- // Remove auto-stand, let physics/grounding handle pose
+ 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') {
@@ -417,22 +407,24 @@
// --- Physics update ---
self.update = function () {
// Gravity
if (!self.state.grounded) {
- // Variable gravity: less gravity at jump apex for hang time, more when falling
- var jumpElapsed = self._jumpStartTime ? Date.now() - self._jumpStartTime : 0;
- var isRising = self.state.vy < 0;
- if (isRising && jumpElapsed < 220) {
- // At start of jump, less gravity for floaty effect
- self.state.vy += 1.2;
- } else if (isRising) {
- // Still rising, but more gravity
- self.state.vy += 1.8;
- } else {
- // Falling: increase gravity for snappier land
- self.state.vy += 2.7;
+ // Detect transition: start of falling after jump
+ if (typeof self.lastVy === "undefined") self.lastVy = 0;
+ if (self.lastVy < 0 && self.state.vy >= 0) {
+ // Just started falling (apex of jump)
+ if (typeof LK.effects !== "undefined" && LK.effects.blurScreen) {
+ LK.effects.blurScreen(0.7, 400); // Apply a moderate blur for 400ms
+ }
+ if (typeof LK.effects !== "undefined" && LK.effects.slowMotion) {
+ LK.effects.slowMotion(0.4, 400); // Slow motion to 40% for 400ms
+ }
}
- if (self.state.vy > 44) self.state.vy = 44;
+ self.state.vy += 2.2; // gravity
+ if (self.state.vy > 40) self.state.vy = 40;
+ self.lastVy = self.state.vy;
+ } else {
+ self.lastVy = 0;
}
// Friction
if (self.state.grounded) {
self.state.vx *= 0.82;