User prompt
reduce the time to 8 88% say obi wan
User prompt
darthvadersound1-2-3-5 play sound randomly every 10 seconds
User prompt
Darth Vader will speak at certain intervals, I will do the installation, you will create the files.
User prompt
When we die in the game, Darth Vader should shout Obi Wan. Remove the lightsaber sound
User prompt
Use the sound file to play the lightsaber sound from a different second each time you press it
User prompt
"Play Star Wars lightsaber battle sounds with each click."
User prompt
"Place both of them at the very top, one below the other."
User prompt
put it just below the score
User prompt
Put it somewhere nice that won't disrupt gameplay above.
User prompt
place the timer in the middle
User prompt
Please fix the bug: 'Uncaught ReferenceError: timerBarExplodeAnim is not defined' in or related to this line: 'timerBarExplodeAnim();' Line Number: 570
User prompt
put out timer
User prompt
make a better visual this is so bad character has 3 arms fix that make the main character dark wader
User prompt
turn trees into something suitable for space. turn tree branches into katana
User prompt
remove clouds, make snowflakes shooting stars, pretend the game takes place in space
User prompt
Ok remove the league system fix the game
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'storage.leaderboard = leaderboardObj;' Line Number: 1034 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'storage.leaderboard = sanitizedScores;' Line Number: 1029 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'TypeError: storage.set is not a function' in or related to this line: 'storage.set('leaderboard', sanitizedScores);' Line Number: 1029
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'storage.leaderboard = sanitizedScores;' Line Number: 1029
User prompt
Please fix the bug: 'Error: Invalid value. Only literals or 1-level deep objects/arrays containing literals are allowed.' in or related to this line: 'storage.leaderboard = allScores;' Line Number: 1019
User prompt
undo the development. make a login screen for the game, start it and have a leaderboard. when you say start, the game starts. when you say leaderboard, the score of all the people who have played this game so far comes up. take the first 100, the one with the best score comes second, the one after that. take the weapon in the character's hand and break the wood with your fist. ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
no, it's too bad, keep improving
User prompt
No, it didn't turn out exactly as I wanted. Improve this game more.
User prompt
No, it should look like real tree wood, like the bear in the Timberlake game.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Cloud: A vivid, realistic, moving cloud with randomized shape, transparency, and slow drift var Cloud = Container.expand(function () { var self = Container.call(this); // Main cloud body var main = self.attachAsset('cloud', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.5 + Math.random() * 3.5, scaleY: 1.2 + Math.random() * 1.8, x: 0, y: 0 }); main.alpha = 0.45 + Math.random() * 0.15; // Add 3-5 extra puffs for realism and volume var puffCount = 3 + Math.floor(Math.random() * 3); for (var i = 0; i < puffCount; i++) { var puff = self.attachAsset('cloud', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2 + Math.random() * 2.2, scaleY: 0.7 + Math.random() * 1.5, x: -100 + Math.random() * 200, y: -40 + Math.random() * 80 }); puff.alpha = 0.28 + Math.random() * 0.22; } // Set initial position and movement: anywhere on the screen, at various heights self.x = Math.random() * 2048; self.y = 40 + Math.random() * 1800; self.speedX = 0.04 + Math.random() * 0.10; // even slower drift for realism self.amp = 20 + Math.random() * 40; // vertical amplitude self.phase = Math.random() * Math.PI * 2; // Update for movement self.update = function () { self.x += self.speedX; self.y += Math.sin(Date.now() / (1800 + Math.random() * 800) + self.phase) * 0.10; // Wrap around screen horizontally, randomize vertical position for sky spread if (self.x > 2048 + 300) { self.x = -300; self.y = 40 + Math.random() * 1800; } }; return self; }); // Old Kung Fu Master: anime style, funny, with long white moustache, eyebrows, and beard var Lumberjack = Container.expand(function () { var self = Container.call(this); // Side: 'left' or 'right' self.side = 'left'; // --- Construction --- // Boots (simple black) var bootL = self.attachAsset('karate_leg', { anchorX: 0.5, anchorY: 0.1, x: -18, y: 0, scaleX: 1.1, scaleY: 1.1, tint: 0x222222 }); var bootR = self.attachAsset('karate_leg', { anchorX: 0.5, anchorY: 0.1, x: 18, y: 0, scaleX: 1.1, scaleY: 1.1, tint: 0x222222 }); // Pants (loose, light blue) var pants = self.attachAsset('karate_leg', { anchorX: 0.5, anchorY: 1, x: 0, y: -10, scaleX: 1.3, scaleY: 1.2, tint: 0x7ec8e3 }); // Robe (white, flowing) var robe = self.attachAsset('karate_body', { anchorX: 0.5, anchorY: 1, x: 0, y: -60, scaleX: 1.2, scaleY: 1.15, tint: 0xffffff }); // Sash (red) var sash = self.attachAsset('karate_belt', { anchorX: 0.5, anchorY: 0, x: 0, y: -110, scaleX: 1.2, scaleY: 1.1, tint: 0xff3333 }); // Head (round, pale skin) var head = self.attachAsset('karate_head', { anchorX: 0.5, anchorY: 1, x: 0, y: -160, scaleX: 1.1, scaleY: 1.1, tint: 0xfaf3e3 }); // Hair (bald top, white sides) var hairL = self.attachAsset('karate_hair', { anchorX: 0.5, anchorY: 1, x: -18, y: -180, scaleX: 0.5, scaleY: 0.7, tint: 0xffffff }); hairL.alpha = 0.85; var hairR = self.attachAsset('karate_hair', { anchorX: 0.5, anchorY: 1, x: 18, y: -180, scaleX: 0.5, scaleY: 0.7, tint: 0xffffff }); hairR.alpha = 0.85; // Long white eyebrows (anime style) var browL = self.attachAsset('karate_belt', { anchorX: 0.5, anchorY: 0.5, x: -12, y: -170, scaleX: 0.7, scaleY: 0.18, tint: 0xffffff }); var browR = self.attachAsset('karate_belt', { anchorX: 0.5, anchorY: 0.5, x: 12, y: -170, scaleX: 0.7, scaleY: 0.18, tint: 0xffffff }); // Long white moustache (drooping, anime style) var moustacheL = self.attachAsset('karate_belt', { anchorX: 1, anchorY: 0.5, x: -7, y: -150, scaleX: 0.5, scaleY: 0.13, rotation: 0.3, tint: 0xffffff }); var moustacheR = self.attachAsset('karate_belt', { anchorX: 0, anchorY: 0.5, x: 7, y: -150, scaleX: 0.5, scaleY: 0.13, rotation: -0.3, tint: 0xffffff }); // Long single beard (white, thin, anime style) var beard = self.attachAsset('karate_belt', { anchorX: 0.5, anchorY: 0, x: 0, y: -135, scaleX: 0.18, scaleY: 1.1, tint: 0xffffff }); beard.alpha = 0.85; // Left Arm (sleeve, hand) var larm = self.attachAsset('karate_arm', { anchorX: 0.5, anchorY: 0.1, x: -38, y: -90, rotation: -0.25, scaleX: 1.1, scaleY: 1.1, tint: 0xfaf3e3 }); // Right Arm (sleeve, hand) var rarm = self.attachAsset('karate_arm', { anchorX: 0.5, anchorY: 0.1, x: 38, y: -90, rotation: 0.25, scaleX: 1.1, scaleY: 1.1, tint: 0xfaf3e3 }); // Axe (wooden handle, steel blade) var axeHandle = self.attachAsset('treeBranch', { anchorX: 0.1, anchorY: 0.5, x: -55, y: -100, scaleX: 0.5, scaleY: 0.5, tint: 0x8d5524 }); var axeBlade = self.attachAsset('karate_belt', { anchorX: 0.1, anchorY: 0.5, x: -70, y: -100, scaleX: 0.5, scaleY: 1.2, tint: 0xc0c0c0 }); // Set side ('left' or 'right') self.setSide = function (side) { self.side = side; // Use robe width for offset var charWidth = robe.width; if (side === 'left') { self.x = treeX - trunkWidth / 2 - charWidth / 2 - 40; self.scaleX = 1; } else { self.x = treeX + trunkWidth / 2 + charWidth / 2 + 40; self.scaleX = -1; } }; // Chop animation: swing axe! self.chop = function () { // Animate a quick scale for feedback tween(self, { scaleY: 0.92 }, { duration: 60, easing: tween.cubicOut, onFinish: function onFinish() { tween(self, { scaleY: 1 }, { duration: 80, easing: tween.cubicIn }); } }); // Axe swing animation (right arm if facing right, left arm if facing left) var arm = self.side === 'left' ? larm : rarm; var origRot = arm.rotation; tween(arm, { rotation: origRot + (self.side === 'left' ? -1.0 : 1.0) }, { duration: 60, easing: tween.cubicOut, onFinish: function onFinish() { tween(arm, { rotation: origRot }, { duration: 80, easing: tween.cubicIn }); } }); // Axe blade swing var origAxeRot = axeHandle.rotation; tween(axeHandle, { rotation: origAxeRot + (self.side === 'left' ? -0.7 : 0.7) }, { duration: 60, easing: tween.cubicOut, onFinish: function onFinish() { tween(axeHandle, { rotation: origAxeRot }, { duration: 80, easing: tween.cubicIn }); } }); tween(axeBlade, { rotation: origAxeRot + (self.side === 'left' ? -0.7 : 0.7) }, { duration: 60, easing: tween.cubicOut, onFinish: function onFinish() { tween(axeBlade, { rotation: origAxeRot }, { duration: 80, easing: tween.cubicIn }); } }); }; return self; }); // Snowflake: A single falling snow particle var Snowflake = Container.expand(function () { var self = Container.call(this); // Create a small white ellipse as snowflake var flake = self.attachAsset('snowflake', { anchorX: 0.5, anchorY: 0.5 }); // Randomize size and speed var scale = 0.3 + Math.random() * 0.5; flake.scaleX = scale; flake.scaleY = scale; self.speedY = 1.5 + Math.random() * 1.5; self.speedX = -0.5 + Math.random(); // Set initial alpha for some depth flake.alpha = 0.7 + Math.random() * 0.3; // Set initial position: anywhere above, left, or right of the screen for natural spread var edge = Math.floor(Math.random() * 4); if (edge === 0) { // top self.x = Math.random() * 2048; self.y = -40 - Math.random() * 100; } else if (edge === 1) { // left self.x = -30 - Math.random() * 60; self.y = Math.random() * 2732; } else if (edge === 2) { // right self.x = 2048 + 30 + Math.random() * 60; self.y = Math.random() * 2732; } else { // random top area self.x = Math.random() * 2048; self.y = -40 - Math.random() * 200; } // Update method for falling self.update = function () { self.y += self.speedY; self.x += self.speedX; // Sway a little self.x += Math.sin(Date.now() / 400 + self.y) * 0.2; // If out of screen, mark for removal if (self.y > 2732 + 40) { self.toRemove = true; } }; return self; }); // TreeSegment: A single segment of the tree, may have a branch (left/right/none) var TreeSegment = Container.expand(function () { var self = Container.call(this); // Default: no branch self.branch = 'none'; // 'left', 'right', 'none' // Tree trunk (realistic) var trunk = self.attachAsset('treeTrunk', { anchorX: 0.5, anchorY: 0.5 }); // Overlay moss for realism var moss = self.attachAsset('treeTrunkMoss', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0, scaleX: 0.92 + Math.random() * 0.12, scaleY: 0.7 + Math.random() * 0.18, alpha: 0.13 + Math.random() * 0.08 }); // Overlay bark lines for realism var barkLines = self.attachAsset('treeTrunkBarkLines', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0, scaleX: 0.95 + Math.random() * 0.1, scaleY: 0.95 + Math.random() * 0.1, alpha: 0.18 + Math.random() * 0.10 }); // Branch (if any) self.branchNode = null; // Set up the segment (branchSide: 'left', 'right', or 'none') self.setup = function (branchSide) { self.branch = branchSide; if (self.branchNode) { self.removeChild(self.branchNode); self.branchNode = null; } if (branchSide === 'left') { self.branchNode = self.attachAsset('treeBranch', { anchorX: 1, anchorY: 0.5, x: -trunk.width / 2, y: 0 }); // Overlay bark lines for branch var barkBranchLines = self.attachAsset('treeBranchBarkLines', { anchorX: 1, anchorY: 0.5, x: -trunk.width / 2, y: 0, scaleX: 1, scaleY: 1, alpha: 0.22 + Math.random() * 0.10 }); } else if (branchSide === 'right') { self.branchNode = self.attachAsset('treeBranch', { anchorX: 0, anchorY: 0.5, x: trunk.width / 2, y: 0, flipX: 1 }); // Overlay bark lines for branch var barkBranchLines = self.attachAsset('treeBranchBarkLines', { anchorX: 0, anchorY: 0.5, x: trunk.width / 2, y: 0, scaleX: 1, scaleY: 1, alpha: 0.22 + Math.random() * 0.10 }); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xbbeeff // Even lighter sky blue for a dreamy sky }); /**** * Game Code ****/ // Add a bark lines overlay for branch realism // Realistic branch: slightly curved, lighter brown, thinner // Add a bark lines overlay for trunk realism // Add a subtle greenish moss overlay for trunk realism // Realistic tree trunk and branch assets, inspired by Timberlake bear game // Add a bark texture overlay for trunk and branch (semi-transparent, dark lines) // More realistic tree branch: slightly curved, lighter brown, and a bit thinner // More realistic tree trunk: deeper brown, subtle greenish tint for moss, and a bit wider // Karate master (Jackie Chan inspired): head, body, arms, legs, belt // Add vivid, moving clouds all over the screen for a sky-filled effect var clouds = []; for (var i = 0; i < 18; i++) { var cloud = new Cloud(); clouds.push(cloud); game.addChild(cloud); } // --- Game Variables --- // --- Asset Initialization (auto by LK engine) --- // Tree trunk segment // Branch // Lumberjack // Chop sound // Fail sound var treeSegments = []; // Array of TreeSegment var treeX = 2048 / 2; var treeBaseY = 2732 - 350; // Y position of the bottom segment var trunkWidth = 180; var trunkHeight = 120; var visibleSegments = 10; // Number of segments visible on screen var branchChance = 0.35; // Probability of a branch per segment var lastBranch = 'none'; // To avoid impossible patterns var player = null; var scoreTxt = null; var timerBar = null; var timeLeft = 2000; // ms, time before game over var maxTime = 2000; // ms, resets to this on chop var timerInterval = null; var isGameOver = false; // --- Snow System --- var snowflakes = []; var snowSpawnTimer = 0; var snowSpawnInterval = 10; // frames between spawns (smaller = more snow) // --- UI Setup --- scoreTxt = new Text2('0', { size: 120, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Timer bar with improved visuals timerBar = LK.getAsset('timerBar', { width: 800, height: 38, color: 0x00b050, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 120 }); timerBar.alpha = 0.93; timerBar.border = LK.getAsset('timerBar', { width: 820, height: 48, color: 0x222222, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 120 }); timerBar.border.alpha = 0.25; LK.gui.top.addChild(timerBar.border); LK.gui.top.addChild(timerBar); // Timer bar hit animation function timerBarHitAnim() { tween(timerBar, { scaleY: 1.25 }, { duration: 60, easing: tween.cubicOut, onFinish: function onFinish() { tween(timerBar, { scaleY: 1 }, { duration: 100, easing: tween.cubicIn }); } }); tween(timerBar, { alpha: 1 }, { duration: 60, onFinish: function onFinish() { tween(timerBar, { alpha: 0.93 }, { duration: 100 }); } }); } // Timer bar explosion animation function timerBarExplodeAnim() { tween(timerBar, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 350, easing: tween.cubicOut }); tween(timerBar.border, { alpha: 0 }, { duration: 350 }); } // --- Tree Setup --- function randomBranch(prevBranch) { // Avoid two branches on the same side in a row var r = Math.random(); if (r < branchChance) { if (prevBranch === 'left') return 'right'; if (prevBranch === 'right') return 'left'; return Math.random() < 0.5 ? 'left' : 'right'; } return 'none'; } function createInitialTree() { var prev = 'none'; for (var i = 0; i < visibleSegments + 2; i++) { var seg = new TreeSegment(); var branch = randomBranch(prev); seg.setup(branch); seg.x = treeX; seg.y = treeBaseY - i * trunkHeight; treeSegments.push(seg); game.addChild(seg); prev = branch; } } function shiftTree() { // Remove bottom segment var bottom = treeSegments.shift(); bottom.destroy(); // Move all segments down for (var i = 0; i < treeSegments.length; i++) { tween(treeSegments[i], { y: treeBaseY - i * trunkHeight }, { duration: 80, easing: tween.cubicOut }); } // Add new segment at the top var prevBranch = treeSegments[treeSegments.length - 1].branch; var newSeg = new TreeSegment(); var branch = randomBranch(prevBranch); newSeg.setup(branch); newSeg.x = treeX; newSeg.y = treeSegments[treeSegments.length - 1].y - trunkHeight; treeSegments.push(newSeg); game.addChild(newSeg); } // --- Player Setup --- player = new Lumberjack(); player.setSide('left'); player.y = treeBaseY + trunkHeight / 2 + 10; game.addChild(player); // --- Game State --- var score = 0; // --- Timer --- function resetTimer() { timeLeft = maxTime; updateTimerBar(); } function updateTimerBar() { var pct = Math.max(0, timeLeft / maxTime); timerBar.width = 800 * pct; if (pct > 0.5) { timerBar.tint = 0x00b050; } else if (pct > 0.2) { timerBar.tint = 0xffc300; } else { timerBar.tint = 0xff0000; } } // --- Game Over --- function triggerGameOver() { if (isGameOver) return; isGameOver = true; timerBarExplodeAnim(); LK.effects.flashScreen(0xff0000, 800); // Play a better wood explosion sound and effect LK.getSound('fail').play(); LK.effects.flashObject(treeSegments[0], 0xffe066, 400); // flash the bottom segment yellow for a wood burst tween(treeSegments[0], { scaleX: 2.2, scaleY: 2.2, alpha: 0 }, { duration: 420, easing: tween.cubicOut }); LK.showGameOver(); } // --- Chop Action --- function chop() { if (isGameOver) return; // Check for collision with branch on current side at the bottom segment var bottomSeg = treeSegments[0]; if (bottomSeg.branch === player.side) { triggerGameOver(); return; } // Chop: remove bottom, shift tree, add new at top shiftTree(); // Animate player player.chop(); timerBarHitAnim(); // Play sound LK.getSound('chop').play(); // Score score += 1; LK.setScore(score); scoreTxt.setText(score); // Reset timer, but make it a bit shorter as score increases maxTime = Math.max(800, 2000 - score * 10); resetTimer(); } // --- Input Handling --- var touchStartX = null; var touchStartY = null; var dragThreshold = 40; // px function handleDown(x, y, obj) { touchStartX = x; touchStartY = y; } function handleUp(x, y, obj) { if (isGameOver) return; if (touchStartX === null || touchStartY === null) return; var dx = x - touchStartX; var dy = y - touchStartY; // Swipe detection if (Math.abs(dx) > dragThreshold && Math.abs(dx) > Math.abs(dy)) { // Horizontal swipe if (dx > 0 && player.side === 'left') { player.setSide('right'); } else if (dx < 0 && player.side === 'right') { player.setSide('left'); } } else if (Math.abs(dx) < dragThreshold && Math.abs(dy) < dragThreshold) { // Tap: chop chop(); } touchStartX = null; touchStartY = null; } game.down = handleDown; game.up = handleUp; // --- Main Update Loop --- game.update = function () { // --- Cloud update --- for (var i = 0; i < clouds.length; i++) { if (clouds[i].update) clouds[i].update(); } // --- Snow update --- snowSpawnTimer++; if (snowSpawnTimer >= snowSpawnInterval) { snowSpawnTimer = 0; // Light snow: only a few flakes per second if (snowflakes.length < 40) { var flake = new Snowflake(); snowflakes.push(flake); game.addChild(flake); } } // Update and remove snowflakes for (var i = snowflakes.length - 1; i >= 0; i--) { var flake = snowflakes[i]; if (flake.update) flake.update(); if (flake.toRemove) { flake.destroy(); snowflakes.splice(i, 1); } } if (isGameOver) return; // Timer timeLeft -= 1000 / 60; updateTimerBar(); if (timeLeft <= 0) { triggerGameOver(); } }; // --- Game Initialization --- function resetGame() { // Remove old tree for (var i = 0; i < treeSegments.length; i++) { treeSegments[i].destroy(); } treeSegments = []; // Remove old snowflakes for (var i = 0; i < snowflakes.length; i++) { snowflakes[i].destroy(); } snowflakes = []; // Reset variables score = 0; LK.setScore(0); scoreTxt.setText('0'); isGameOver = false; maxTime = 2000; timerBar.scaleX = 1; timerBar.scaleY = 1; timerBar.alpha = 0.93; if (timerBar.border) timerBar.border.alpha = 0.25; resetTimer(); // Recreate tree createInitialTree(); // Reset player player.setSide('left'); player.y = treeBaseY + trunkHeight / 2 + 10; } // --- Start Game --- resetGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Cloud: A vivid, realistic, moving cloud with randomized shape, transparency, and slow drift
var Cloud = Container.expand(function () {
var self = Container.call(this);
// Main cloud body
var main = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5 + Math.random() * 3.5,
scaleY: 1.2 + Math.random() * 1.8,
x: 0,
y: 0
});
main.alpha = 0.45 + Math.random() * 0.15;
// Add 3-5 extra puffs for realism and volume
var puffCount = 3 + Math.floor(Math.random() * 3);
for (var i = 0; i < puffCount; i++) {
var puff = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2 + Math.random() * 2.2,
scaleY: 0.7 + Math.random() * 1.5,
x: -100 + Math.random() * 200,
y: -40 + Math.random() * 80
});
puff.alpha = 0.28 + Math.random() * 0.22;
}
// Set initial position and movement: anywhere on the screen, at various heights
self.x = Math.random() * 2048;
self.y = 40 + Math.random() * 1800;
self.speedX = 0.04 + Math.random() * 0.10; // even slower drift for realism
self.amp = 20 + Math.random() * 40; // vertical amplitude
self.phase = Math.random() * Math.PI * 2;
// Update for movement
self.update = function () {
self.x += self.speedX;
self.y += Math.sin(Date.now() / (1800 + Math.random() * 800) + self.phase) * 0.10;
// Wrap around screen horizontally, randomize vertical position for sky spread
if (self.x > 2048 + 300) {
self.x = -300;
self.y = 40 + Math.random() * 1800;
}
};
return self;
});
// Old Kung Fu Master: anime style, funny, with long white moustache, eyebrows, and beard
var Lumberjack = Container.expand(function () {
var self = Container.call(this);
// Side: 'left' or 'right'
self.side = 'left';
// --- Construction ---
// Boots (simple black)
var bootL = self.attachAsset('karate_leg', {
anchorX: 0.5,
anchorY: 0.1,
x: -18,
y: 0,
scaleX: 1.1,
scaleY: 1.1,
tint: 0x222222
});
var bootR = self.attachAsset('karate_leg', {
anchorX: 0.5,
anchorY: 0.1,
x: 18,
y: 0,
scaleX: 1.1,
scaleY: 1.1,
tint: 0x222222
});
// Pants (loose, light blue)
var pants = self.attachAsset('karate_leg', {
anchorX: 0.5,
anchorY: 1,
x: 0,
y: -10,
scaleX: 1.3,
scaleY: 1.2,
tint: 0x7ec8e3
});
// Robe (white, flowing)
var robe = self.attachAsset('karate_body', {
anchorX: 0.5,
anchorY: 1,
x: 0,
y: -60,
scaleX: 1.2,
scaleY: 1.15,
tint: 0xffffff
});
// Sash (red)
var sash = self.attachAsset('karate_belt', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: -110,
scaleX: 1.2,
scaleY: 1.1,
tint: 0xff3333
});
// Head (round, pale skin)
var head = self.attachAsset('karate_head', {
anchorX: 0.5,
anchorY: 1,
x: 0,
y: -160,
scaleX: 1.1,
scaleY: 1.1,
tint: 0xfaf3e3
});
// Hair (bald top, white sides)
var hairL = self.attachAsset('karate_hair', {
anchorX: 0.5,
anchorY: 1,
x: -18,
y: -180,
scaleX: 0.5,
scaleY: 0.7,
tint: 0xffffff
});
hairL.alpha = 0.85;
var hairR = self.attachAsset('karate_hair', {
anchorX: 0.5,
anchorY: 1,
x: 18,
y: -180,
scaleX: 0.5,
scaleY: 0.7,
tint: 0xffffff
});
hairR.alpha = 0.85;
// Long white eyebrows (anime style)
var browL = self.attachAsset('karate_belt', {
anchorX: 0.5,
anchorY: 0.5,
x: -12,
y: -170,
scaleX: 0.7,
scaleY: 0.18,
tint: 0xffffff
});
var browR = self.attachAsset('karate_belt', {
anchorX: 0.5,
anchorY: 0.5,
x: 12,
y: -170,
scaleX: 0.7,
scaleY: 0.18,
tint: 0xffffff
});
// Long white moustache (drooping, anime style)
var moustacheL = self.attachAsset('karate_belt', {
anchorX: 1,
anchorY: 0.5,
x: -7,
y: -150,
scaleX: 0.5,
scaleY: 0.13,
rotation: 0.3,
tint: 0xffffff
});
var moustacheR = self.attachAsset('karate_belt', {
anchorX: 0,
anchorY: 0.5,
x: 7,
y: -150,
scaleX: 0.5,
scaleY: 0.13,
rotation: -0.3,
tint: 0xffffff
});
// Long single beard (white, thin, anime style)
var beard = self.attachAsset('karate_belt', {
anchorX: 0.5,
anchorY: 0,
x: 0,
y: -135,
scaleX: 0.18,
scaleY: 1.1,
tint: 0xffffff
});
beard.alpha = 0.85;
// Left Arm (sleeve, hand)
var larm = self.attachAsset('karate_arm', {
anchorX: 0.5,
anchorY: 0.1,
x: -38,
y: -90,
rotation: -0.25,
scaleX: 1.1,
scaleY: 1.1,
tint: 0xfaf3e3
});
// Right Arm (sleeve, hand)
var rarm = self.attachAsset('karate_arm', {
anchorX: 0.5,
anchorY: 0.1,
x: 38,
y: -90,
rotation: 0.25,
scaleX: 1.1,
scaleY: 1.1,
tint: 0xfaf3e3
});
// Axe (wooden handle, steel blade)
var axeHandle = self.attachAsset('treeBranch', {
anchorX: 0.1,
anchorY: 0.5,
x: -55,
y: -100,
scaleX: 0.5,
scaleY: 0.5,
tint: 0x8d5524
});
var axeBlade = self.attachAsset('karate_belt', {
anchorX: 0.1,
anchorY: 0.5,
x: -70,
y: -100,
scaleX: 0.5,
scaleY: 1.2,
tint: 0xc0c0c0
});
// Set side ('left' or 'right')
self.setSide = function (side) {
self.side = side;
// Use robe width for offset
var charWidth = robe.width;
if (side === 'left') {
self.x = treeX - trunkWidth / 2 - charWidth / 2 - 40;
self.scaleX = 1;
} else {
self.x = treeX + trunkWidth / 2 + charWidth / 2 + 40;
self.scaleX = -1;
}
};
// Chop animation: swing axe!
self.chop = function () {
// Animate a quick scale for feedback
tween(self, {
scaleY: 0.92
}, {
duration: 60,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(self, {
scaleY: 1
}, {
duration: 80,
easing: tween.cubicIn
});
}
});
// Axe swing animation (right arm if facing right, left arm if facing left)
var arm = self.side === 'left' ? larm : rarm;
var origRot = arm.rotation;
tween(arm, {
rotation: origRot + (self.side === 'left' ? -1.0 : 1.0)
}, {
duration: 60,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(arm, {
rotation: origRot
}, {
duration: 80,
easing: tween.cubicIn
});
}
});
// Axe blade swing
var origAxeRot = axeHandle.rotation;
tween(axeHandle, {
rotation: origAxeRot + (self.side === 'left' ? -0.7 : 0.7)
}, {
duration: 60,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(axeHandle, {
rotation: origAxeRot
}, {
duration: 80,
easing: tween.cubicIn
});
}
});
tween(axeBlade, {
rotation: origAxeRot + (self.side === 'left' ? -0.7 : 0.7)
}, {
duration: 60,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(axeBlade, {
rotation: origAxeRot
}, {
duration: 80,
easing: tween.cubicIn
});
}
});
};
return self;
});
// Snowflake: A single falling snow particle
var Snowflake = Container.expand(function () {
var self = Container.call(this);
// Create a small white ellipse as snowflake
var flake = self.attachAsset('snowflake', {
anchorX: 0.5,
anchorY: 0.5
});
// Randomize size and speed
var scale = 0.3 + Math.random() * 0.5;
flake.scaleX = scale;
flake.scaleY = scale;
self.speedY = 1.5 + Math.random() * 1.5;
self.speedX = -0.5 + Math.random();
// Set initial alpha for some depth
flake.alpha = 0.7 + Math.random() * 0.3;
// Set initial position: anywhere above, left, or right of the screen for natural spread
var edge = Math.floor(Math.random() * 4);
if (edge === 0) {
// top
self.x = Math.random() * 2048;
self.y = -40 - Math.random() * 100;
} else if (edge === 1) {
// left
self.x = -30 - Math.random() * 60;
self.y = Math.random() * 2732;
} else if (edge === 2) {
// right
self.x = 2048 + 30 + Math.random() * 60;
self.y = Math.random() * 2732;
} else {
// random top area
self.x = Math.random() * 2048;
self.y = -40 - Math.random() * 200;
}
// Update method for falling
self.update = function () {
self.y += self.speedY;
self.x += self.speedX;
// Sway a little
self.x += Math.sin(Date.now() / 400 + self.y) * 0.2;
// If out of screen, mark for removal
if (self.y > 2732 + 40) {
self.toRemove = true;
}
};
return self;
});
// TreeSegment: A single segment of the tree, may have a branch (left/right/none)
var TreeSegment = Container.expand(function () {
var self = Container.call(this);
// Default: no branch
self.branch = 'none'; // 'left', 'right', 'none'
// Tree trunk (realistic)
var trunk = self.attachAsset('treeTrunk', {
anchorX: 0.5,
anchorY: 0.5
});
// Overlay moss for realism
var moss = self.attachAsset('treeTrunkMoss', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 0.92 + Math.random() * 0.12,
scaleY: 0.7 + Math.random() * 0.18,
alpha: 0.13 + Math.random() * 0.08
});
// Overlay bark lines for realism
var barkLines = self.attachAsset('treeTrunkBarkLines', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 0.95 + Math.random() * 0.1,
scaleY: 0.95 + Math.random() * 0.1,
alpha: 0.18 + Math.random() * 0.10
});
// Branch (if any)
self.branchNode = null;
// Set up the segment (branchSide: 'left', 'right', or 'none')
self.setup = function (branchSide) {
self.branch = branchSide;
if (self.branchNode) {
self.removeChild(self.branchNode);
self.branchNode = null;
}
if (branchSide === 'left') {
self.branchNode = self.attachAsset('treeBranch', {
anchorX: 1,
anchorY: 0.5,
x: -trunk.width / 2,
y: 0
});
// Overlay bark lines for branch
var barkBranchLines = self.attachAsset('treeBranchBarkLines', {
anchorX: 1,
anchorY: 0.5,
x: -trunk.width / 2,
y: 0,
scaleX: 1,
scaleY: 1,
alpha: 0.22 + Math.random() * 0.10
});
} else if (branchSide === 'right') {
self.branchNode = self.attachAsset('treeBranch', {
anchorX: 0,
anchorY: 0.5,
x: trunk.width / 2,
y: 0,
flipX: 1
});
// Overlay bark lines for branch
var barkBranchLines = self.attachAsset('treeBranchBarkLines', {
anchorX: 0,
anchorY: 0.5,
x: trunk.width / 2,
y: 0,
scaleX: 1,
scaleY: 1,
alpha: 0.22 + Math.random() * 0.10
});
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xbbeeff // Even lighter sky blue for a dreamy sky
});
/****
* Game Code
****/
// Add a bark lines overlay for branch realism
// Realistic branch: slightly curved, lighter brown, thinner
// Add a bark lines overlay for trunk realism
// Add a subtle greenish moss overlay for trunk realism
// Realistic tree trunk and branch assets, inspired by Timberlake bear game
// Add a bark texture overlay for trunk and branch (semi-transparent, dark lines)
// More realistic tree branch: slightly curved, lighter brown, and a bit thinner
// More realistic tree trunk: deeper brown, subtle greenish tint for moss, and a bit wider
// Karate master (Jackie Chan inspired): head, body, arms, legs, belt
// Add vivid, moving clouds all over the screen for a sky-filled effect
var clouds = [];
for (var i = 0; i < 18; i++) {
var cloud = new Cloud();
clouds.push(cloud);
game.addChild(cloud);
}
// --- Game Variables ---
// --- Asset Initialization (auto by LK engine) ---
// Tree trunk segment
// Branch
// Lumberjack
// Chop sound
// Fail sound
var treeSegments = []; // Array of TreeSegment
var treeX = 2048 / 2;
var treeBaseY = 2732 - 350; // Y position of the bottom segment
var trunkWidth = 180;
var trunkHeight = 120;
var visibleSegments = 10; // Number of segments visible on screen
var branchChance = 0.35; // Probability of a branch per segment
var lastBranch = 'none'; // To avoid impossible patterns
var player = null;
var scoreTxt = null;
var timerBar = null;
var timeLeft = 2000; // ms, time before game over
var maxTime = 2000; // ms, resets to this on chop
var timerInterval = null;
var isGameOver = false;
// --- Snow System ---
var snowflakes = [];
var snowSpawnTimer = 0;
var snowSpawnInterval = 10; // frames between spawns (smaller = more snow)
// --- UI Setup ---
scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Timer bar with improved visuals
timerBar = LK.getAsset('timerBar', {
width: 800,
height: 38,
color: 0x00b050,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 120
});
timerBar.alpha = 0.93;
timerBar.border = LK.getAsset('timerBar', {
width: 820,
height: 48,
color: 0x222222,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 120
});
timerBar.border.alpha = 0.25;
LK.gui.top.addChild(timerBar.border);
LK.gui.top.addChild(timerBar);
// Timer bar hit animation
function timerBarHitAnim() {
tween(timerBar, {
scaleY: 1.25
}, {
duration: 60,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(timerBar, {
scaleY: 1
}, {
duration: 100,
easing: tween.cubicIn
});
}
});
tween(timerBar, {
alpha: 1
}, {
duration: 60,
onFinish: function onFinish() {
tween(timerBar, {
alpha: 0.93
}, {
duration: 100
});
}
});
}
// Timer bar explosion animation
function timerBarExplodeAnim() {
tween(timerBar, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 350,
easing: tween.cubicOut
});
tween(timerBar.border, {
alpha: 0
}, {
duration: 350
});
}
// --- Tree Setup ---
function randomBranch(prevBranch) {
// Avoid two branches on the same side in a row
var r = Math.random();
if (r < branchChance) {
if (prevBranch === 'left') return 'right';
if (prevBranch === 'right') return 'left';
return Math.random() < 0.5 ? 'left' : 'right';
}
return 'none';
}
function createInitialTree() {
var prev = 'none';
for (var i = 0; i < visibleSegments + 2; i++) {
var seg = new TreeSegment();
var branch = randomBranch(prev);
seg.setup(branch);
seg.x = treeX;
seg.y = treeBaseY - i * trunkHeight;
treeSegments.push(seg);
game.addChild(seg);
prev = branch;
}
}
function shiftTree() {
// Remove bottom segment
var bottom = treeSegments.shift();
bottom.destroy();
// Move all segments down
for (var i = 0; i < treeSegments.length; i++) {
tween(treeSegments[i], {
y: treeBaseY - i * trunkHeight
}, {
duration: 80,
easing: tween.cubicOut
});
}
// Add new segment at the top
var prevBranch = treeSegments[treeSegments.length - 1].branch;
var newSeg = new TreeSegment();
var branch = randomBranch(prevBranch);
newSeg.setup(branch);
newSeg.x = treeX;
newSeg.y = treeSegments[treeSegments.length - 1].y - trunkHeight;
treeSegments.push(newSeg);
game.addChild(newSeg);
}
// --- Player Setup ---
player = new Lumberjack();
player.setSide('left');
player.y = treeBaseY + trunkHeight / 2 + 10;
game.addChild(player);
// --- Game State ---
var score = 0;
// --- Timer ---
function resetTimer() {
timeLeft = maxTime;
updateTimerBar();
}
function updateTimerBar() {
var pct = Math.max(0, timeLeft / maxTime);
timerBar.width = 800 * pct;
if (pct > 0.5) {
timerBar.tint = 0x00b050;
} else if (pct > 0.2) {
timerBar.tint = 0xffc300;
} else {
timerBar.tint = 0xff0000;
}
}
// --- Game Over ---
function triggerGameOver() {
if (isGameOver) return;
isGameOver = true;
timerBarExplodeAnim();
LK.effects.flashScreen(0xff0000, 800);
// Play a better wood explosion sound and effect
LK.getSound('fail').play();
LK.effects.flashObject(treeSegments[0], 0xffe066, 400); // flash the bottom segment yellow for a wood burst
tween(treeSegments[0], {
scaleX: 2.2,
scaleY: 2.2,
alpha: 0
}, {
duration: 420,
easing: tween.cubicOut
});
LK.showGameOver();
}
// --- Chop Action ---
function chop() {
if (isGameOver) return;
// Check for collision with branch on current side at the bottom segment
var bottomSeg = treeSegments[0];
if (bottomSeg.branch === player.side) {
triggerGameOver();
return;
}
// Chop: remove bottom, shift tree, add new at top
shiftTree();
// Animate player
player.chop();
timerBarHitAnim();
// Play sound
LK.getSound('chop').play();
// Score
score += 1;
LK.setScore(score);
scoreTxt.setText(score);
// Reset timer, but make it a bit shorter as score increases
maxTime = Math.max(800, 2000 - score * 10);
resetTimer();
}
// --- Input Handling ---
var touchStartX = null;
var touchStartY = null;
var dragThreshold = 40; // px
function handleDown(x, y, obj) {
touchStartX = x;
touchStartY = y;
}
function handleUp(x, y, obj) {
if (isGameOver) return;
if (touchStartX === null || touchStartY === null) return;
var dx = x - touchStartX;
var dy = y - touchStartY;
// Swipe detection
if (Math.abs(dx) > dragThreshold && Math.abs(dx) > Math.abs(dy)) {
// Horizontal swipe
if (dx > 0 && player.side === 'left') {
player.setSide('right');
} else if (dx < 0 && player.side === 'right') {
player.setSide('left');
}
} else if (Math.abs(dx) < dragThreshold && Math.abs(dy) < dragThreshold) {
// Tap: chop
chop();
}
touchStartX = null;
touchStartY = null;
}
game.down = handleDown;
game.up = handleUp;
// --- Main Update Loop ---
game.update = function () {
// --- Cloud update ---
for (var i = 0; i < clouds.length; i++) {
if (clouds[i].update) clouds[i].update();
}
// --- Snow update ---
snowSpawnTimer++;
if (snowSpawnTimer >= snowSpawnInterval) {
snowSpawnTimer = 0;
// Light snow: only a few flakes per second
if (snowflakes.length < 40) {
var flake = new Snowflake();
snowflakes.push(flake);
game.addChild(flake);
}
}
// Update and remove snowflakes
for (var i = snowflakes.length - 1; i >= 0; i--) {
var flake = snowflakes[i];
if (flake.update) flake.update();
if (flake.toRemove) {
flake.destroy();
snowflakes.splice(i, 1);
}
}
if (isGameOver) return;
// Timer
timeLeft -= 1000 / 60;
updateTimerBar();
if (timeLeft <= 0) {
triggerGameOver();
}
};
// --- Game Initialization ---
function resetGame() {
// Remove old tree
for (var i = 0; i < treeSegments.length; i++) {
treeSegments[i].destroy();
}
treeSegments = [];
// Remove old snowflakes
for (var i = 0; i < snowflakes.length; i++) {
snowflakes[i].destroy();
}
snowflakes = [];
// Reset variables
score = 0;
LK.setScore(0);
scoreTxt.setText('0');
isGameOver = false;
maxTime = 2000;
timerBar.scaleX = 1;
timerBar.scaleY = 1;
timerBar.alpha = 0.93;
if (timerBar.border) timerBar.border.alpha = 0.25;
resetTimer();
// Recreate tree
createInitialTree();
// Reset player
player.setSide('left');
player.y = treeBaseY + trunkHeight / 2 + 10;
}
// --- Start Game ---
resetGame();