User prompt
Add more velocity to bounce of ropes
User prompt
Make launcher invisible
User prompt
Replace slingshot launch method with draw a path method and show the path ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Remove ropes in middle of arena
User prompt
Fix
User prompt
Show path lines
User prompt
Trace a path for chicken jockey to follow ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make lines of popcorn coming from 1 corner at a time chicken jockey needs to collect all popcorn in one launch
User prompt
Add a SuperPopcorn class for special high-value popcorn ✅ Add variables to track super popcorn in game state ✅ Add create super popcorn function ✅ Update game initialization to include super popcorn timer ✅ Add super popcorn collision detection to ChickenJockey update method ✅ Add super popcorn and multiple popcorns update in game update function 🔄 Update chicken jockey stop handler to create super popcorn sometimes
User prompt
Player returns to Centre of ring once popcorn has been collected
User prompt
Once popcorn is collected reset chicken to centre of the arena
User prompt
Increase amount of popcorn thrown by crowd
User prompt
Have popcorn throw in from the crowd outside the arena
User prompt
Prevent chicken getting stuck in the ropes
User prompt
Ensure player returns to centre of arena after every launch
User prompt
Remove all game over triggers
User prompt
Increase text size in instructions page
User prompt
Remove instruction text from title page
User prompt
Remove random movement code
User prompt
Fix this bug
User prompt
Please fix the bug: 'Uncaught ReferenceError: createRopes is not defined' in or related to this line: 'createRopes();' Line Number: 763
User prompt
Please fix the bug: 'PathTracer is not defined' in or related to this line: 'var pathTracer = game.addChild(new PathTracer());' Line Number: 651
User prompt
Remove all dead code that isn't used in game
User prompt
Move instruction text up 20
User prompt
Move instruction text down 100
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var ChickenJockey = Container.expand(function () { var self = Container.call(this); // Create and attach chicken asset var chickenGraphics = self.attachAsset('chicken', { anchorX: 0.5, anchorY: 0.5 }); // Physics properties self.vx = 0; self.vy = 0; self.gravity = 0; self.bounceDecay = 0.7; // Reduced bounce decay for more sustained bounces self.friction = 0.998; // Increased horizontal friction for less horizontal drift self.launched = false; self.bounceCount = 0; self.maxBounces = 5; // Allow 5 bounces per swipe // Rotation properties self.rotationSpeed = 0; self.launch = function (power, angle) { // Convert angle to radians var radians = angle * Math.PI / 180; // Set initial velocity based on power and angle self.vx = Math.cos(radians) * power; self.vy = Math.sin(radians) * power; // Set rotation speed based on velocity self.rotationSpeed = power / 50; self.launched = true; self.bounceCount = 0; // Play launch sound LK.getSound('launch').play(); }; self.reset = function () { self.vx = 0; self.vy = 0; self.rotation = 0; self.rotationSpeed = 0; self.launched = false; self.bounceCount = 0; self.maxBounces = 300; // Set the max bounces here too }; self.update = function () { if (!self.launched) { return; } // Apply physics with speed limiting self.vy += self.gravity; // Cap maximum velocity to prevent freezing var maxSpeed = 30; self.vx = Math.max(-maxSpeed, Math.min(maxSpeed, self.vx)); self.vy = Math.max(-maxSpeed, Math.min(maxSpeed, self.vy)); self.x += self.vx; self.y += self.vy; self.vx *= self.friction; // Apply rotation with speed limiting self.rotationSpeed = Math.max(-0.2, Math.min(0.2, self.rotationSpeed)); self.rotation += self.rotationSpeed; // Check if stopped if (Math.abs(self.vx) < 0.5 && Math.abs(self.vy) < 0.5 && self.bounceCount > 0) { self.launched = false; // Notify game that chicken jockey has stopped if (typeof game.onChickenJockeyStop === 'function') { game.onChickenJockeyStop(); } } // Track last intersecting state for popcorn collision if (typeof self.lastIntersectsPopcorn === 'undefined') { self.lastIntersectsPopcorn = false; } // Check for collision with popcorn if (popcorn !== null) { var currentIntersects = self.intersects(popcorn); if (currentIntersects && !popcorn.isThrowing) { // Collect popcorn only if it's not mid-throw popcorn.collect(); // Set to null (will be recreated on stop) popcorn = null; // Speed up throwing interval as game progresses if (popcornThrower.throwInterval > 2000) { popcornThrower.throwInterval -= 100; } } self.lastIntersectsPopcorn = currentIntersects; } // Track last intersecting state for x2 bonus collision if (typeof self.lastIntersectsX2Bonus === 'undefined') { self.lastIntersectsX2Bonus = false; } // Check for collision with x2 bonus if (x2Bonus !== null) { var currentIntersectsX2 = self.intersects(x2Bonus); if (currentIntersectsX2) { // Collect x2 bonus LK.getSound('collect').play(); // Flash effect LK.effects.flashObject(x2Bonus, 0xFFFFFF, 300); // Animate collection tween(x2Bonus, { y: x2Bonus.y - 150, alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { // Remove from parent if (x2Bonus !== null && x2Bonus.parent) { x2Bonus.parent.removeChild(x2Bonus); } } }); // Double the score game.addScore(score); // Show message showMessage("Score Doubled!", 0xFFD700); // Set to null x2Bonus = null; } self.lastIntersectsX2Bonus = currentIntersectsX2; } // Track last intersecting state for x5 bonus collision if (typeof self.lastIntersectsX5Bonus === 'undefined') { self.lastIntersectsX5Bonus = false; } // Check for collision with x5 bonus if (x5Bonus !== null) { var currentIntersectsX5 = self.intersects(x5Bonus); if (currentIntersectsX5) { // Collect x5 bonus LK.getSound('collect').play(); // Flash effect LK.effects.flashObject(x5Bonus, 0xFFFFFF, 300); // Animate collection tween(x5Bonus, { y: x5Bonus.y - 150, alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { // Remove from parent if (x5Bonus !== null && x5Bonus.parent) { x5Bonus.parent.removeChild(x5Bonus); } } }); // Multiply score by 5 game.addScore(score * 4); // Add 4x more score (1x original + 4x new = 5x total) // Show message showMessage("Score Multiplied x5!", 0xFF4500); // Set to null and clear timer x5Bonus = null; if (x5BonusTimer !== null) { LK.clearTimeout(x5BonusTimer); x5BonusTimer = null; } } self.lastIntersectsX5Bonus = currentIntersectsX5; } // Track previous positions before bounce var prevX = self.x; var prevY = self.y; // Track previous positions for more accurate collision detection var prevX = self.x; var prevY = self.y; // Improved boundary bounce handling with minimum velocity thresholds // Horizontal boundaries with more dramatic bounce effect if (self.x <= bounds.left) { self.x = bounds.left; if (self.vx < 0 && Math.abs(self.vx) > 1) { // Enhance bounce effect with slightly more force self.vx = -self.vx * (self.bounceDecay + 0.1); self.bounceCount++; LK.getSound('bounce').play(); // Add slight vertical boost for more interesting motion self.vy -= 2 * Math.random(); } } else if (self.x >= bounds.right) { self.x = bounds.right; if (self.vx > 0 && Math.abs(self.vx) > 1) { // Enhance bounce effect with slightly more force self.vx = -self.vx * (self.bounceDecay + 0.1); self.bounceCount++; LK.getSound('bounce').play(); game.addScore(2000); // Add slight vertical boost for more interesting motion self.vy -= 2 * Math.random(); } } // Vertical boundary bounce handling with more dramatic effect if (self.y <= bounds.top) { self.y = bounds.top; if (self.vy < 0 && Math.abs(self.vy) > 1) { // Enhance bounce effect with slightly more force self.vy = -self.vy * (self.bounceDecay + 0.1); self.bounceCount++; LK.getSound('bounce').play(); // Add slight horizontal boost for more interesting motion self.vx += (Math.random() - 0.5) * 4; } } else if (self.y >= bounds.bottom) { self.y = bounds.bottom; if (self.vy > 0 && Math.abs(self.vy) > 1) { // Enhance bounce effect with slightly more force self.vy = -self.vy * (self.bounceDecay + 0.1); self.bounceCount++; LK.getSound('bounce').play(); // Add slight horizontal boost for more interesting motion self.vx += (Math.random() - 0.5) * 4; } } // Check if max bounces reached if (self.bounceCount >= self.maxBounces) { self.launched = false; // Notify game that max bounces reached if (typeof game.onMaxBouncesReached === 'function') { game.onMaxBouncesReached(); } } }; return self; }); var HighScoreTally = Container.expand(function () { var self = Container.call(this); // Background container var background = self.attachAsset('Hiscorebackdrop', { anchorX: 0.5, anchorY: 0.5 }); background.width = 1400; background.height = 1200; background.alpha = 0.8; // Title text var titleText = new Text2("HIGH SCORES", { size: 100, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0); titleText.y = -background.height / 2 + 100; self.addChild(titleText); // Score entries container var scoreEntries = []; self.updateScores = function (highScores) { // Clear existing entries for (var i = 0; i < scoreEntries.length; i++) { if (scoreEntries[i].parent) { scoreEntries[i].parent.removeChild(scoreEntries[i]); } } scoreEntries = []; // Create new entries var startY = -background.height / 2 + 250; var padding = 80; for (var i = 0; i < highScores.length && i < 5; i++) { var entry = new Container(); // Rank var rankText = new Text2(i + 1 + ".", { size: 70, fill: 0xFFFFFF }); rankText.anchor.set(0, 0.5); rankText.x = -background.width / 2 + 200; entry.addChild(rankText); // Score var scoreText = new Text2(highScores[i] ? highScores[i].toLocaleString() : "0", { size: 70, fill: 0xFFD700 }); scoreText.anchor.set(1, 0.5); scoreText.x = background.width / 2 - 200; entry.addChild(scoreText); // Position entry entry.y = startY + i * padding; self.addChild(entry); scoreEntries.push(entry); } // If no scores available if (highScores.length === 0) { var noScoreText = new Text2("No scores yet!", { size: 70, fill: 0xFFFFFF }); noScoreText.anchor.set(0.5, 0.5); noScoreText.y = 0; self.addChild(noScoreText); scoreEntries.push(noScoreText); } }; // Start button var startButton = new Container(); var buttonBg = startButton.attachAsset('rope', { anchorX: 0.5, anchorY: 0.5 }); buttonBg.width = 600; buttonBg.height = 150; buttonBg.tint = 0x00AA00; var buttonText = new Text2("PLAY GAME", { size: 70, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); startButton.addChild(buttonText); startButton.y = background.height / 2 - 200; self.addChild(startButton); startButton.interactive = true; startButton.down = function () { buttonBg.tint = 0x007700; }; startButton.up = function () { buttonBg.tint = 0x00AA00; if (typeof self.onStart === 'function') { self.onStart(); } }; // Reset high scores button var resetButton = new Container(); var resetBg = resetButton.attachAsset('rope', { anchorX: 0.5, anchorY: 0.5 }); resetBg.width = 600; resetBg.height = 150; resetBg.tint = 0xAA0000; var resetText = new Text2("RESET SCORES", { size: 70, fill: 0xFFFFFF }); resetText.anchor.set(0.5, 0.5); resetButton.addChild(resetText); resetButton.y = background.height / 2 - 400; self.addChild(resetButton); resetButton.interactive = true; resetButton.down = function () { resetBg.tint = 0x770000; }; resetButton.up = function () { resetBg.tint = 0xAA0000; if (typeof self.onResetScores === 'function') { self.onResetScores(); } }; // Make container position in center of screen self.x = 2048 / 2; self.y = 2732 / 2; return self; }); var InstructionsScreen = Container.expand(function () { var self = Container.call(this); // Create black background var background = self.attachAsset('Hiscorebackdrop', { anchorX: 0.5, anchorY: 0.5 }); background.width = 1400; background.height = 1500; background.alpha = 0.8; // Title var titleText = new Text2("HOW TO PLAY", { size: 80, fill: 0xFFD700 }); titleText.anchor.set(0.5, 0); titleText.y = -background.height / 2 + 100; self.addChild(titleText); // Instructions - split into smaller lines for better fitting var instructions = ["1: Swipe or flick any direction to launch Chicken Jockey.", "2: Aim Chicken Jockey at the popcorn pieces to eat popcorn.", "3: If you miss the popcorn, it will be GAME OVER.", "4: Scoring system starts at 1 point per popcorn, but", " a multiplier increases the score per popcorn every 10 launches.", "5: Look out for X2 and X5 bonuses to maximise your total score,", " but be careful...", " if you miss the popcorn it will be game over so be patient", " and wait till the popcorn is in the right place before", " launching towards these bonuses.", "6: Good luck!"]; var instructionContainer = new Container(); var startY = -background.height / 2 + 250; var padding = 50; // Reduced padding to fit more lines for (var i = 0; i < instructions.length; i++) { var instructionText = new Text2(instructions[i], { size: 50, fill: 0xFFFFFF }); instructionText.anchor.set(0, 0.5); instructionText.y = startY + i * padding; instructionContainer.addChild(instructionText); } instructionContainer.x = -700; // Move instructions text left 700 pixels self.addChild(instructionContainer); // Back button var backButton = new Container(); var buttonBg = backButton.attachAsset('rope', { anchorX: 0.5, anchorY: 0.5 }); buttonBg.width = 600; buttonBg.height = 150; buttonBg.tint = 0x0000AA; var buttonText = new Text2("BACK", { size: 70, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); backButton.addChild(buttonText); backButton.y = background.height / 2 - 200; self.addChild(backButton); // Make button interactive backButton.interactive = true; backButton.down = function () { buttonBg.tint = 0x000077; }; backButton.up = function () { buttonBg.tint = 0x0000AA; if (typeof self.onBack === 'function') { self.onBack(); } }; // Position in center of screen self.x = 2048 / 2; self.y = 2732 / 2; return self; }); var PathTracer = Container.expand(function () { var self = Container.call(this); self.points = []; self.maxPoints = 50; self.lineWidth = 5; self.lineColor = 0xFFFFFF; self.active = false; // Create visual representation of the path var pathGraphics = self.attachAsset('rope', { anchorX: 0.5, anchorY: 0.5 }); // Initialize path graphics pathGraphics.alpha = 0.5; pathGraphics.width = 0; pathGraphics.height = 0; self.startTracing = function (x, y) { self.points = [{ x: x, y: y }]; self.active = true; }; self.addPoint = function (x, y) { if (!self.active) { return; } // Only add point if it's significantly different from last point var lastPoint = self.points[self.points.length - 1]; var dx = x - lastPoint.x; var dy = y - lastPoint.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 20) { self.points.push({ x: x, y: y }); // Limit number of points if (self.points.length > self.maxPoints) { self.points.shift(); } } }; self.stopTracing = function () { self.active = false; return self.points.length >= 2 ? self.points : null; }; self.clear = function () { self.points = []; self.active = false; }; self.update = function () { // Update path visualization based on current points if (self.points.length < 2) { pathGraphics.alpha = 0; return; } pathGraphics.alpha = 0.5; // Calculate path visual representation var firstPoint = self.points[0]; var lastPoint = self.points[self.points.length - 1]; // Position at midpoint of path self.x = (firstPoint.x + lastPoint.x) / 2; self.y = (firstPoint.y + lastPoint.y) / 2; // Calculate path length and angle var dx = lastPoint.x - firstPoint.x; var dy = lastPoint.y - firstPoint.y; var length = Math.sqrt(dx * dx + dy * dy); var angle = Math.atan2(dy, dx); // Update path graphics pathGraphics.width = length; pathGraphics.height = self.lineWidth; pathGraphics.rotation = angle; }; return self; }); var Popcorn = Container.expand(function () { var self = Container.call(this); // Create and attach popcorn asset with smaller size var popcornGraphics = self.attachAsset('popcorn', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); // Popcorn properties self.collected = false; self.baseY = 0; self.animationOffset = Math.random() * Math.PI * 2; self.animationSpeed = 0.05 + Math.random() * 0.03; self.vx = 0; // Velocity for throwing self.vy = 0; // Velocity for throwing self.isThrowing = false; // Flag to track if popcorn is being thrown self.collect = function () { // Play collect sound LK.getSound('collect').play(); // Flash effect LK.effects.flashObject(self, 0xFFFFFF, 300); // Animate collection tween(self, { y: self.y - 150, alpha: 0, scaleX: 4.5, scaleY: 4.5 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { // Remove from parent if (self.parent) { self.parent.removeChild(self); } } }); // Add points if (typeof game.addScore === 'function') { game.addScore(1); } self.collected = true; }; self.update = function () { // Hover animation if (self.baseY === 0) { self.baseY = self.y; // Start movement tween when popcorn is created self.startMovementTween(); } // Vertical hover self.y = self.baseY + Math.sin(LK.ticks * self.animationSpeed + self.animationOffset) * 8; }; // Method to start the popcorn moving around the arena self.startMovementTween = function () { // Calculate a random position within the arena bounds var randomX = bounds.left + 150 + Math.random() * (arena.width - 300); var randomY = bounds.top + 150 + Math.random() * (arena.height - 300); // Move to the new position over a few seconds tween(self, { x: randomX // Update baseY to keep hover effect consistent }, { duration: popcornMoveSpeed + Math.random() * 1000, // Use global popcorn speed variable plus some randomness easing: tween.easeInOut, onFinish: function onFinish() { // When movement completes, start a new movement if (self.parent) { self.startMovementTween(); } } }); }; return self; }); var PopcornThrower = Container.expand(function () { var self = Container.call(this); // Properties self.active = false; self.interval = null; self.throwInterval = 5000; // Time between throws // Start throwing popcorn self.startThrowing = function () { if (self.active) { return; } self.active = true; self.throwNextPopcorn(); // Set interval for regular throws self.interval = LK.setInterval(function () { if (self.active) { self.throwNextPopcorn(); } }, self.throwInterval); }; // Stop throwing popcorn self.stopThrowing = function () { self.active = false; if (self.interval !== null) { LK.clearInterval(self.interval); self.interval = null; } }; // Throw a single popcorn from outside the arena self.throwNextPopcorn = function () { // If there's already popcorn on the screen, don't throw another if (popcorn !== null) { return; } // Choose a random side of the arena to throw from var side = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left // Create a new popcorn var newPopcorn = new Popcorn(); // Position popcorn outside the arena based on the chosen side switch (side) { case 0: // Top newPopcorn.x = bounds.left + Math.random() * arena.width; newPopcorn.y = bounds.top - 200; newPopcorn.vx = 0; newPopcorn.vy = 5 + Math.random() * 5; break; case 1: // Right newPopcorn.x = bounds.right + 200; newPopcorn.y = bounds.top + Math.random() * arena.height; newPopcorn.vx = -(5 + Math.random() * 5); newPopcorn.vy = 0; break; case 2: // Bottom newPopcorn.x = bounds.left + Math.random() * arena.width; newPopcorn.y = bounds.bottom + 200; newPopcorn.vx = 0; newPopcorn.vy = -(5 + Math.random() * 5); break; case 3: // Left newPopcorn.x = bounds.left - 200; newPopcorn.y = bounds.top + Math.random() * arena.height; newPopcorn.vx = 5 + Math.random() * 5; newPopcorn.vy = 0; break; } // Add throwing physics to popcorn newPopcorn.isThrowing = true; // Override update method to handle throwing animation var originalUpdate = newPopcorn.update; newPopcorn.update = function () { if (newPopcorn.isThrowing) { // Apply velocity newPopcorn.x += newPopcorn.vx; newPopcorn.y += newPopcorn.vy; // Apply slight gravity and rotation during throw newPopcorn.vy += 0.1; newPopcorn.rotation += 0.05; // Check if popcorn has entered the arena if (newPopcorn.x > bounds.left + 100 && newPopcorn.x < bounds.right - 100 && newPopcorn.y > bounds.top + 100 && newPopcorn.y < bounds.bottom - 100) { // Switch to normal behavior once inside newPopcorn.isThrowing = false; // Play sound effect for landing LK.getSound('Chickencluck').play(); // Flash effect for landing LK.effects.flashObject(newPopcorn, 0xFFFFFF, 200); } } else { // Call the original update function for normal behavior originalUpdate.call(newPopcorn); } }; // Add to game and set as current popcorn game.addChild(newPopcorn); popcorn = newPopcorn; }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); // Create and attach power-up asset (using popcorn as base) var powerUpGraphics = self.attachAsset('popcorn', { anchorX: 0.5, anchorY: 0.5 }); // Make it visually distinct powerUpGraphics.tint = 0x00FFFF; // PowerUp properties self.type = "multiplier"; // Default type self.value = 2; // Default multiplier value self.duration = 10000; // 10 seconds self.active = false; // Animation properties self.animationOffset = Math.random() * Math.PI * 2; self.animationSpeed = 0.05 + Math.random() * 0.03; self.baseY = 0; self.scale = 1.5; // Make power-ups slightly larger // Pulse animation self.pulseDirection = 1; self.pulseSpeed = 0.02; self.minScale = 1.3; self.maxScale = 1.7; self.collect = function () { // Play collect sound with higher pitch var sound = LK.getSound('collect'); sound.play(); // Flash effect LK.effects.flashObject(self, 0xFFFFFF, 300); // Animate collection (flying up) tween(self, { y: self.y - 150, alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { // Remove from parent if (self.parent) { self.parent.removeChild(self); } } }); // Activate the powerup effect if (typeof game.activatePowerUp === 'function') { game.activatePowerUp(self.type, self.value, self.duration); } }; self.update = function () { // Hover animation if (self.baseY === 0) { self.baseY = self.y; } // Vertical hover self.y = self.baseY + Math.sin(LK.ticks * self.animationSpeed + self.animationOffset) * 8; // Pulsing animation var currentScale = self.scale; currentScale += self.pulseDirection * self.pulseSpeed; if (currentScale > self.maxScale) { currentScale = self.maxScale; self.pulseDirection = -1; } else if (currentScale < self.minScale) { currentScale = self.minScale; self.pulseDirection = 1; } self.scale = currentScale; self.scaleX = self.scale; self.scaleY = self.scale; }; return self; }); var Rope = Container.expand(function () { var self = Container.call(this); // Create and attach rope asset var ropeGraphics = self.attachAsset('rope', { anchorX: 0.5, anchorY: 0.5 }); // Rope properties self.tension = 0.8; // Increased tension for more springy, elastic bounces self.bounce = function (chickenJockey) { // Store original position for rope displacement effect var originalX = self.x; var originalY = self.y; // Calculate normal angle (perpendicular to rope) var normalAngle = Math.atan2(chickenJockey.y - self.y, chickenJockey.x - self.x); // Account for rope rotation when calculating normal normalAngle += self.rotation + Math.PI / 2; // Calculate velocity components var speed = Math.sqrt(chickenJockey.vx * chickenJockey.vx + chickenJockey.vy * chickenJockey.vy); var incomingAngle = Math.atan2(chickenJockey.vy, chickenJockey.vx); // Calculate angle of reflection var bounceAngle = 2 * normalAngle - incomingAngle; // Calculate new velocity with enhanced force based on incoming speed // Higher incoming speed = stronger bounce back effect var bounceForce = speed * self.tension * (1 + Math.min(0.5, speed / 40)); // Reduce random angle variation for more predictable wrestling-style bounces var angleVariation = (Math.random() - 0.5) * 0.1; // Smaller random angle adjustment bounceAngle += angleVariation; // Better two-phase bounce: complete stop, then dramatic spring-off // First phase: completely stop the chicken to simulate "sticking" to rope chickenJockey.vx = 0; chickenJockey.vy = 0; // Add a slightly longer delay for more dramatic pause before the spring-off LK.setTimeout(function () { // Second phase: apply a much stronger bounce force with enhanced velocity var enhancedForce = bounceForce * 1.5; // Significantly increase spring force chickenJockey.vx = Math.cos(bounceAngle) * enhancedForce * chickenJockey.bounceDecay; chickenJockey.vy = Math.sin(bounceAngle) * enhancedForce * chickenJockey.bounceDecay; // Add a more dramatic burst of rotation to simulate impact force chickenJockey.rotationSpeed = (Math.random() - 0.5) * 0.25; // Play a sound to enhance the spring effect LK.getSound('bounce').play(); }, 200); // Slightly longer delay for more dramatic effect // Create much more dramatic bounce visual effect with exaggerated rope "give" tween(self, { scaleY: 2.2, // More extreme stretch alpha: 0.7, // Add more significant displacement in direction of impact x: originalX + Math.cos(incomingAngle) * 20, y: originalY + Math.sin(incomingAngle) * 20 }, { duration: 300, // Longer stretch duration for more dramatic effect easing: tween.easeOut, onFinish: function onFinish() { // Snap the rope back with way more dramatic effect tween(self, { scaleY: 1.0, alpha: 1.0, x: originalX, y: originalY }, { duration: 800, //{3l} // Much longer snap-back for even more visual impact easing: tween.elasticOut, amplitude: 2.0 // Higher amplitude for more dramatic snap back }); } }); // Increment bounce count chickenJockey.bounceCount++; // Create a more dramatic visual and audio experience // Play bounce sound with slightly randomized pitch for variety var bounceSound = LK.getSound('bounce'); bounceSound.play(); // More dramatic flash effect on the rope LK.effects.flashObject(self, 0xFFFFFF, 300); // Create a "pow" text effect at collision point var powText = new Text2("nomnomnom", { size: 120, fill: 0xFFFF00 }); powText.anchor.set(0.5, 0.5); powText.x = chickenJockey.x; powText.y = chickenJockey.y - 80; game.addChild(powText); // Animate the text tween(powText, { y: powText.y - 100, alpha: 0, scaleX: 1.5, scaleY: 1.5 }, { duration: 600, easing: tween.easeOut, onFinish: function onFinish() { if (powText.parent) { powText.parent.removeChild(powText); } } }); }; self.intersectsWithPoint = function (x, y) { var halfWidth = ropeGraphics.width / 2; var halfHeight = ropeGraphics.height / 2; // Check if point is within the rope's bounding box return x >= self.x - halfWidth && x <= self.x + halfWidth && y >= self.y - halfHeight && y <= self.y + halfHeight; }; return self; }); var TitleScreen = Container.expand(function () { var self = Container.call(this); // Create and attach title screen background var titleGraphics = self.attachAsset('Titlescreen', { anchorX: 0.5, anchorY: 0.5 }); // Start button var startButton = new Container(); var buttonBg = startButton.attachAsset('rope', { anchorX: 0.5, anchorY: 0.5 }); buttonBg.width = 600; buttonBg.height = 150; buttonBg.tint = 0x00AA00; var buttonText = new Text2("START GAME", { size: 70, fill: 0xFFFFFF }); buttonText.anchor.set(0.5, 0.5); startButton.addChild(buttonText); startButton.y = 200; self.addChild(startButton); // Make button interactive startButton.interactive = true; startButton.down = function () { buttonBg.tint = 0x007700; }; startButton.up = function () { buttonBg.tint = 0x00AA00; // Call start game function if defined if (typeof self.onStart === 'function') { self.onStart(); } }; // High scores button var scoresButton = new Container(); var scoresBg = scoresButton.attachAsset('rope', { anchorX: 0.5, anchorY: 0.5 }); scoresBg.width = 600; scoresBg.height = 150; scoresBg.tint = 0x0000AA; var scoresText = new Text2("HIGH SCORES", { size: 70, fill: 0xFFFFFF }); scoresText.anchor.set(0.5, 0.5); scoresButton.addChild(scoresText); scoresButton.y = 400; self.addChild(scoresButton); // Make button interactive scoresButton.interactive = true; scoresButton.down = function () { scoresBg.tint = 0x000077; }; scoresButton.up = function () { scoresBg.tint = 0x0000AA; // Call show high scores function if defined if (typeof self.onHighScores === 'function') { self.onHighScores(); } }; // Instructions button var instructionsButton = new Container(); var instructionsBg = instructionsButton.attachAsset('rope', { anchorX: 0.5, anchorY: 0.5 }); instructionsBg.width = 600; instructionsBg.height = 150; instructionsBg.tint = 0xAA7700; var instructionsText = new Text2("INSTRUCTIONS", { size: 70, fill: 0xFFFFFF }); instructionsText.anchor.set(0.5, 0.5); instructionsButton.addChild(instructionsText); instructionsButton.y = 600; self.addChild(instructionsButton); // Make button interactive instructionsButton.interactive = true; instructionsButton.down = function () { instructionsBg.tint = 0x774400; }; instructionsButton.up = function () { instructionsBg.tint = 0xAA7700; // Call show instructions function if defined if (typeof self.onInstructions === 'function') { self.onInstructions(); } }; // Position in center of screen self.x = 2048 / 2; self.y = 2732 / 2; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 // Black background }); /**** * Game Code ****/ // Game state var gameState = "ready"; // ready, aiming, launched, gameOver var score = 0; var launches = 0; var maxLaunches = 5; var ropes = []; var powerUps = []; var popcorn = null; // Track the active popcorn var x2Bonus = null; // Track the active x2 bonus var x5Bonus = null; // Track the active x5 bonus var x5BonusTimer = null; // Timer for x5 bonus removal var scoreMultiplier = 1; var multiplierEndTime = 0; var launchMultiplier = 1; // Track multiplier from launches var popcornMoveSpeed = 5000; // Base popcorn movement duration in ms var highScoresKey = 'chickenJockeyHighScores'; var pathTracer = game.addChild(new PathTracer()); // Create popcorn thrower var popcornThrower = new PopcornThrower(); // Add backdrop first var backdrop = game.addChild(LK.getAsset('Backdrop', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 })); // Create wrestling arena var arena = game.addChild(LK.getAsset('arena', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 })); // Create chicken jockey var chickenJockey = game.addChild(new ChickenJockey()); // Game boundaries var bounds = { left: arena.x - arena.width / 2, right: arena.x + arena.width / 2, top: arena.y - arena.height / 2, bottom: arena.y + arena.height / 2 }; // Create GUI elements var scoreText = new Text2("Score: 0", { size: 70, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); var launchesText = new Text2("Launches: 0/" + maxLaunches, { size: 50, fill: 0xFFFFFF }); launchesText.anchor.set(0, 0); launchesText.x = 120; // Avoid top-left corner launchesText.y = 140; // Moved down 120 pixels from original position of 20 LK.gui.topLeft.addChild(launchesText); var instructionText = new Text2("", { size: 40, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 0); instructionText.y = 100; LK.gui.top.addChild(instructionText); // Initialize game function initGame() { // Reset variables score = 0; launches = 0; maxLaunches = 5; scoreMultiplier = 1; multiplierEndTime = 0; popcornMoveSpeed = 5000; // Reset popcorn movement speed gameState = "ready"; // Clear x2 bonus if exists if (x2Bonus !== null) { if (x2Bonus.parent) { x2Bonus.parent.removeChild(x2Bonus); } x2Bonus = null; } // Clear x5 bonus if exists if (x5Bonus !== null) { if (x5Bonus.parent) { x5Bonus.parent.removeChild(x5Bonus); } x5Bonus = null; } // Clear any existing x5 bonus timer if (x5BonusTimer !== null) { LK.clearTimeout(x5BonusTimer); x5BonusTimer = null; } // Update UI scoreText.setText("Score: " + score); launchesText.setText("Launches: " + launches); instructionText.setText("Swipe or flick Chicken Jockey to launch!"); // Reset chicken jockey resetChickenJockey(); // Clear existing popcorn and ropes clearPopcornsAndRopes(); // Create ropes around the arena createRopes(); // Create a few power-ups for (var i = 0; i < 3; i++) { createPowerUp(); } // Start popcorn thrower popcornThrower.startThrowing(); // Play game start sound LK.getSound('Gamestart').play(); // Play background music after a short delay to ensure it starts after the game start sound LK.setTimeout(function () { LK.playMusic('gameMusic', { loop: true }); }, 1000); // Delay of 1000ms (1 second) } function resetChickenJockey() { chickenJockey.reset(); // Position chicken in the center of the arena chickenJockey.x = arena.x; chickenJockey.y = arena.y; } function clearPopcornsAndRopes() { // Remove all ropes for (var i = 0; i < ropes.length; i++) { if (ropes[i].parent) { ropes[i].parent.removeChild(ropes[i]); } } ropes = []; // Remove all power-ups for (var i = 0; i < powerUps.length; i++) { if (powerUps[i].parent) { powerUps[i].parent.removeChild(powerUps[i]); } } powerUps = []; } function createRopes() { // Create top rope var topRope = new Rope(); topRope.x = arena.x; topRope.y = bounds.top + 100; game.addChild(topRope); ropes.push(topRope); // Create right rope var rightRope = new Rope(); rightRope.x = bounds.right - 100; rightRope.y = arena.y; rightRope.rotation = Math.PI / 2; // Rotate 90 degrees game.addChild(rightRope); ropes.push(rightRope); // Create bottom rope var bottomRope = new Rope(); bottomRope.x = arena.x; bottomRope.y = bounds.bottom - 100; game.addChild(bottomRope); ropes.push(bottomRope); // Create left rope var leftRope = new Rope(); leftRope.x = bounds.left + 100; leftRope.y = arena.y; leftRope.rotation = Math.PI / 2; // Rotate 90 degrees game.addChild(leftRope); ropes.push(leftRope); // Center horizontal rope removed } function createPowerUp() { var powerUp = new PowerUp(); // Random position within arena bounds powerUp.x = bounds.left + 150 + Math.random() * (arena.width - 300); powerUp.y = bounds.top + 150 + Math.random() * (arena.height - 300); // Random power-up type var types = ["multiplier", "extraLaunch", "superBounce"]; var randomType = types[Math.floor(Math.random() * types.length)]; powerUp.type = randomType; // Configure based on type if (randomType === "multiplier") { powerUp.tint = 0x00FFFF; // Cyan powerUp.value = 2 + Math.floor(Math.random() * 3); // 2x to 4x multiplier } else if (randomType === "extraLaunch") { powerUp.tint = 0xFF00FF; // Purple powerUp.value = 1; // Extra launch } else if (randomType === "superBounce") { powerUp.tint = 0xFFFF00; // Yellow powerUp.value = 2; // Double bounce points } // Add to game game.addChild(powerUp); powerUps.push(powerUp); } function createPopcorn() { // Only create if no popcorn exists if (popcorn === null) { // Use the popcorn thrower to throw popcorn from outside popcornThrower.throwNextPopcorn(); } } function createX2Bonus() { // Only create if no x2 bonus exists if (x2Bonus === null) { var newX2Bonus = LK.getAsset('X2', { anchorX: 0.5, anchorY: 0.5 }); // Random position within arena bounds newX2Bonus.x = bounds.left + 150 + Math.random() * (arena.width - 300); newX2Bonus.y = bounds.top + 150 + Math.random() * (arena.height - 300); // Add to game game.addChild(newX2Bonus); x2Bonus = newX2Bonus; // Add hover animation var baseY = newX2Bonus.y; var animationOffset = Math.random() * Math.PI * 2; var animationSpeed = 0.05 + Math.random() * 0.03; newX2Bonus.update = function () { // Vertical hover animation newX2Bonus.y = baseY + Math.sin(LK.ticks * animationSpeed + animationOffset) * 8; }; } } function createX5Bonus() { // Only create if no x5 bonus exists if (x5Bonus === null) { var newX5Bonus = LK.getAsset('X5', { anchorX: 0.5, anchorY: 0.5 }); // Random position within arena bounds newX5Bonus.x = bounds.left + 150 + Math.random() * (arena.width - 300); newX5Bonus.y = bounds.top + 150 + Math.random() * (arena.height - 300); // Add to game game.addChild(newX5Bonus); x5Bonus = newX5Bonus; // Add hover animation var baseY = newX5Bonus.y; var animationOffset = Math.random() * Math.PI * 2; var animationSpeed = 0.05 + Math.random() * 0.03; newX5Bonus.update = function () { // Vertical hover animation newX5Bonus.y = baseY + Math.sin(LK.ticks * animationSpeed + animationOffset) * 8; }; // Set timer to remove X5 bonus after 5 seconds if (x5BonusTimer !== null) { LK.clearTimeout(x5BonusTimer); } x5BonusTimer = LK.setTimeout(function () { if (x5Bonus !== null) { // Animate disappearing tween(x5Bonus, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { if (x5Bonus && x5Bonus.parent) { x5Bonus.parent.removeChild(x5Bonus); } x5Bonus = null; } }); } }, 5000); // 5 seconds } } // Game events game.onChickenJockeyStop = function () { // Always create new popcorn when chicken stops if (popcorn !== null) { // Create new popcorn right away createPopcorn(); instructionText.setText("New popcorn appeared! Drag to aim and launch the chicken!"); } else { gameState = "ready"; // Occasionally add a power-up when chicken stops if (Math.random() < 0.3 && powerUps.length < 5) { createPowerUp(); } // Check if chicken is close to the center of the arena var centerX = arena.x; var centerY = arena.y; var distanceToCenter = Math.sqrt(Math.pow(chickenJockey.x - centerX, 2) + Math.pow(chickenJockey.y - centerY, 2)); var centerThreshold = 200; // Threshold distance to consider "at center" if (distanceToCenter <= centerThreshold) { // Create a new popcorn only when player is near the center createPopcorn(); instructionText.setText("New popcorn appeared! Drag to aim and launch the chicken!"); } else { instructionText.setText("What's the highest score you can get?"); } // Instead of checking if out of launches, increase max launches maxLaunches++; // Increase max launches with each launch // Reset for next launch resetChickenJockey(); } }; game.onMaxBouncesReached = function () { // Same as onChickenJockeyStop for now game.onChickenJockeyStop(); }; // Input handling var dragStartX = 0; var dragStartY = 0; var dragEndX = 0; var dragEndY = 0; game.down = function (x, y, obj) { if (gameState === "ready") { gameState = "aiming"; dragStartX = x; dragStartY = y; pathTracer.startTracing(x, y); instructionText.setText("Draw a path for the chicken!"); } }; game.move = function (x, y, obj) { if (gameState === "aiming") { pathTracer.addPoint(x, y); } }; game.up = function (x, y, obj) { if (gameState === "aiming") { // Get the path from the path tracer var path = pathTracer.stopTracing(); // Only launch if we have a valid path if (path && path.length >= 2) { // Record drag end position dragEndX = x; dragEndY = y; // Calculate direction from the path var firstPoint = path[0]; var lastPoint = path[path.length - 1]; var dx = lastPoint.x - firstPoint.x; var dy = lastPoint.y - firstPoint.y; var distance = Math.sqrt(dx * dx + dy * dy); // Calculate power based on path length (with a more controlled range) var power = Math.min(distance, 200) * 0.2; // Calculate angle based on path direction var angle = Math.atan2(dy, dx) * 180 / Math.PI; chickenJockey.launch(power, angle); // Update game state gameState = "launched"; launches++; // Create x2 bonus every 13 launches if (launches % 13 === 0 && x2Bonus === null) { createX2Bonus(); } // Create x5 bonus every 26 launches if (launches % 26 === 0 && x5Bonus === null) { createX5Bonus(); } // Update launch multiplier (1x for first 10, 2x for 11-20, etc.) var newMultiplier = Math.floor(launches / 10) + 1; // If multiplier changed, speed up popcorn movement if (newMultiplier > launchMultiplier) { popcornMoveSpeed = Math.max(2000, popcornMoveSpeed - 500); // Speed up by 500ms each level, minimum 2000ms // Play Bogerk sound every 10 launches LK.getSound('Bogerk').play(); } launchMultiplier = newMultiplier; launchesText.setText("Launches: " + launches); instructionText.setText("Watch the chicken bounce!"); } else { // Cancel the launch if the path was too short gameState = "ready"; } // Clear the path tracer regardless pathTracer.clear(); } }; // Add helper to update score game.addScore = function (points) { // Apply multiplier if active var finalPoints = points; if (Date.now() < multiplierEndTime) { finalPoints = Math.floor(points * scoreMultiplier); } // Apply launch multiplier finalPoints = Math.floor(finalPoints * launchMultiplier); score += finalPoints; scoreText.setText("Score: " + score); LK.setScore(score); }; // Power-up activation function game.activatePowerUp = function (type, value, duration) { // Visual feedback for power-up activation LK.effects.flashScreen(0x00FFFF, 500); if (type === "multiplier") { // Set score multiplier scoreMultiplier = value; // Display message showMessage("Score x" + value + " for " + duration / 1000 + "s!", 0x00FFFF); // Set timer to end effect multiplierEndTime = Date.now() + duration; } else if (type === "extraLaunch") { // Add extra launches maxLaunches += value; launches = Math.max(0, launches - value); // Refund a launch launchesText.setText("Launches: " + launches); // Display message showMessage("+" + value + " Extra Launch!", 0xFF00FF); } else if (type === "superBounce") { // Temporarily increase bounce values var oldBounceDecay = chickenJockey.bounceDecay; chickenJockey.bounceDecay = Math.min(1.0, chickenJockey.bounceDecay * 1.3); // Display message showMessage("Super Bounce for " + duration / 1000 + "s!", 0xFFFF00); // Set timer to end effect LK.setTimeout(function () { chickenJockey.bounceDecay = oldBounceDecay; }, duration); } }; // Helper function to show temporary messages function showMessage(text, color) { var message = new Text2(text, { size: 60, fill: color || 0xFFFFFF }); message.anchor.set(0.5, 0.5); message.x = 2048 / 2; message.y = 400; LK.gui.center.addChild(message); // Animate in message.alpha = 0; message.scaleX = 0.5; message.scaleY = 0.5; tween(message, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeOut }); // Animate out after delay LK.setTimeout(function () { tween(message, { alpha: 0, y: message.y - 100 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { if (message.parent) { message.parent.removeChild(message); } } }); }, 2000); } // Main game loop game.update = function () { // Update all game objects if (gameState === "launched") { chickenJockey.update(); // Check for collisions with arena boundaries - only detect boundaries // Horizontal boundaries are handled in ChickenJockey class if (chickenJockey.x < bounds.left) { chickenJockey.x = bounds.left; } else if (chickenJockey.x > bounds.right) { chickenJockey.x = bounds.right; } // Check vertical boundaries - only detect boundaries // Vertical boundaries are handled in ChickenJockey class if (chickenJockey.y < bounds.top) { chickenJockey.y = bounds.top; } else if (chickenJockey.y > bounds.bottom) { chickenJockey.y = bounds.bottom; } // Update x2 bonus if it exists if (x2Bonus !== null && typeof x2Bonus.update === 'function') { x2Bonus.update(); } // Update x5 bonus if it exists if (x5Bonus !== null && typeof x5Bonus.update === 'function') { x5Bonus.update(); } // Track last collision time for all ropes to prevent multiple bounces if (!chickenJockey.lastCollisionTime) { chickenJockey.lastCollisionTime = 0; } // Improved collision detection for ropes with proper cooldown var currentTime = Date.now(); var collisionCooldown = 1000; // 1 second cooldown between any rope bounces var canBounce = currentTime - chickenJockey.lastCollisionTime > collisionCooldown; // Only check for rope collisions if cooldown period has passed if (canBounce && chickenJockey.launched && Math.abs(chickenJockey.vx) + Math.abs(chickenJockey.vy) > 1) { for (var i = 0; i < ropes.length; i++) { if (chickenJockey.intersects(ropes[i])) { // Perform the bounce ropes[i].bounce(chickenJockey); // Record collision time chickenJockey.lastCollisionTime = currentTime; // Flash screen slightly to emphasize impact LK.effects.flashScreen(0xFFFFFF, 100, 0.3); // Only bounce on one rope per cooldown period break; } } } // Check for collisions with power-ups for (var i = powerUps.length - 1; i >= 0; i--) { if (chickenJockey.intersects(powerUps[i])) { // Collect power-up powerUps[i].collect(); // Remove from array powerUps.splice(i, 1); } } // Update popcorn baseY when its position changes from tween if (popcorn !== null && popcorn.baseY !== 0 && Math.abs(popcorn.baseY - popcorn.y) > 10) { popcorn.baseY = popcorn.y; } // Create a new popcorn after a delay if popcorn is null if (popcorn === null && gameState === "launched") { LK.setTimeout(function () { createPopcorn(); }, 1000); // 1 second delay before creating new popcorn } } // Update power-up animations for (var i = 0; i < powerUps.length; i++) { powerUps[i].update(); } // Update popcorn animation if (popcorn !== null) { popcorn.update(); } // Randomly spawn new power-ups (rare) if (gameState === "launched" && Math.random() < 0.001 && powerUps.length < 5) { createPowerUp(); } // Update path tracer pathTracer.update(); // Update score multiplier UI if active or if launch multiplier is greater than 1 if (Date.now() < multiplierEndTime && scoreMultiplier > 1 || launchMultiplier > 1) { var multiplierString = "x" + launchMultiplier; if (Date.now() < multiplierEndTime && scoreMultiplier > 1) { var remainingSecs = Math.ceil((multiplierEndTime - Date.now()) / 1000); multiplierString += " (x" + scoreMultiplier + " for " + remainingSecs + "s)"; } scoreText.setText("Score: " + score + " (" + multiplierString + ")"); } else { scoreText.setText("Score: " + score); } // Award extra launch for every million points if (score >= 1000000 && score % 1000000 < 10000) { // Only award once when crossing each million point threshold if (!game.lastMillionMark || Math.floor(score / 1000000) > Math.floor(game.lastMillionMark / 1000000)) { maxLaunches++; showMessage("Extra Launch for 1,000,000 points!", 0xFFFF00); launchesText.setText("Launches: " + launches); game.lastMillionMark = score; // Create animated free launch text var freeText = new Text2("FREE LAUNCH!", { size: 100, fill: 0xFFFF00 }); freeText.anchor.set(0.5, 0.5); freeText.x = 2048 / 2; freeText.y = 2732 / 2; freeText.alpha = 0; freeText.scaleX = 0.5; freeText.scaleY = 0.5; LK.gui.center.addChild(freeText); // Animate in with bounce effect tween(freeText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.elasticOut, onFinish: function onFinish() { // Pulse animation tween(freeText, { scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { // Animate out with upward movement tween(freeText, { alpha: 0, y: freeText.y - 200 }, { duration: 800, easing: tween.easeIn, onFinish: function onFinish() { if (freeText.parent) { freeText.parent.removeChild(freeText); } } }); } }); } }); } } }; // High score management functions function getHighScores() { return storage[highScoresKey] || []; } function saveHighScore(score) { var highScores = getHighScores(); highScores.push(score); // Sort in descending order highScores.sort(function (a, b) { return b - a; }); // Keep only top 10 scores if (highScores.length > 10) { highScores = highScores.slice(0, 10); } // Save to storage storage[highScoresKey] = highScores; } // Create high score tally var highScoreTally = new HighScoreTally(); highScoreTally.visible = true; highScoreTally.onStart = function () { game.removeChild(highScoreTally); initGame(); }; // Add reset scores functionality highScoreTally.onResetScores = function () { // Clear high scores from storage storage[highScoresKey] = []; // Update display with empty scores highScoreTally.updateScores([]); // Show confirmation message var confirmText = new Text2("High scores reset!", { size: 60, fill: 0xFF0000 }); confirmText.anchor.set(0.5, 0.5); confirmText.x = 2048 / 2; confirmText.y = 2732 / 2 + 200; LK.gui.center.addChild(confirmText); // Animate and remove after delay tween(confirmText, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { LK.setTimeout(function () { tween(confirmText, { alpha: 0, y: confirmText.y - 100 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { if (confirmText.parent) { confirmText.parent.removeChild(confirmText); } } }); }, 1500); } }); }; // Create and show title screen at start var titleScreen = new TitleScreen(); game.addChild(titleScreen); // Set up title screen event handlers titleScreen.onStart = function () { // Hide title screen and start game game.removeChild(titleScreen); initGame(); // Play start sound LK.getSound('Gamestart').play(); }; titleScreen.onHighScores = function () { // Hide title screen and show high scores game.removeChild(titleScreen); game.addChild(highScoreTally); highScoreTally.updateScores(getHighScores()); }; // Create instructions screen var instructionsScreen = new InstructionsScreen(); instructionsScreen.onBack = function () { game.removeChild(instructionsScreen); game.addChild(titleScreen); }; // Add instructions button handler titleScreen.onInstructions = function () { // Hide title screen and show instructions game.removeChild(titleScreen); game.addChild(instructionsScreen); }; // Add a way to return to title screen from high scores var originalOnStart = highScoreTally.onStart; highScoreTally.onStart = function () { game.removeChild(highScoreTally); game.addChild(titleScreen); }; // Modified game over handling var originalOnChickenJockeyStop = game.onChickenJockeyStop; game.onChickenJockeyStop = function () { // Call original function first originalOnChickenJockeyStop(); // If game over, save score // Never go to game over state, just keep playing if (false) { saveHighScore(score); // We'll show high scores after game over in LK.showGameOver callback } }; // Handle game over LK.onGameOver = function () { // Save high score saveHighScore(score); // Show high score tally after game over game.addChild(highScoreTally); highScoreTally.updateScores(getHighScores()); // Back button to return to title screen highScoreTally.onStart = function () { game.removeChild(highScoreTally); game.addChild(titleScreen); }; };
===================================================================
--- original.js
+++ change.js
@@ -77,13 +77,17 @@
}
// Check for collision with popcorn
if (popcorn !== null) {
var currentIntersects = self.intersects(popcorn);
- if (currentIntersects) {
- // Collect popcorn
+ if (currentIntersects && !popcorn.isThrowing) {
+ // Collect popcorn only if it's not mid-throw
popcorn.collect();
// Set to null (will be recreated on stop)
popcorn = null;
+ // Speed up throwing interval as game progresses
+ if (popcornThrower.throwInterval > 2000) {
+ popcornThrower.throwInterval -= 100;
+ }
}
self.lastIntersectsPopcorn = currentIntersects;
}
// Track last intersecting state for x2 bonus collision
@@ -508,8 +512,11 @@
self.collected = false;
self.baseY = 0;
self.animationOffset = Math.random() * Math.PI * 2;
self.animationSpeed = 0.05 + Math.random() * 0.03;
+ self.vx = 0; // Velocity for throwing
+ self.vy = 0; // Velocity for throwing
+ self.isThrowing = false; // Flag to track if popcorn is being thrown
self.collect = function () {
// Play collect sound
LK.getSound('collect').play();
// Flash effect
@@ -568,8 +575,109 @@
});
};
return self;
});
+var PopcornThrower = Container.expand(function () {
+ var self = Container.call(this);
+ // Properties
+ self.active = false;
+ self.interval = null;
+ self.throwInterval = 5000; // Time between throws
+ // Start throwing popcorn
+ self.startThrowing = function () {
+ if (self.active) {
+ return;
+ }
+ self.active = true;
+ self.throwNextPopcorn();
+ // Set interval for regular throws
+ self.interval = LK.setInterval(function () {
+ if (self.active) {
+ self.throwNextPopcorn();
+ }
+ }, self.throwInterval);
+ };
+ // Stop throwing popcorn
+ self.stopThrowing = function () {
+ self.active = false;
+ if (self.interval !== null) {
+ LK.clearInterval(self.interval);
+ self.interval = null;
+ }
+ };
+ // Throw a single popcorn from outside the arena
+ self.throwNextPopcorn = function () {
+ // If there's already popcorn on the screen, don't throw another
+ if (popcorn !== null) {
+ return;
+ }
+ // Choose a random side of the arena to throw from
+ var side = Math.floor(Math.random() * 4); // 0: top, 1: right, 2: bottom, 3: left
+ // Create a new popcorn
+ var newPopcorn = new Popcorn();
+ // Position popcorn outside the arena based on the chosen side
+ switch (side) {
+ case 0:
+ // Top
+ newPopcorn.x = bounds.left + Math.random() * arena.width;
+ newPopcorn.y = bounds.top - 200;
+ newPopcorn.vx = 0;
+ newPopcorn.vy = 5 + Math.random() * 5;
+ break;
+ case 1:
+ // Right
+ newPopcorn.x = bounds.right + 200;
+ newPopcorn.y = bounds.top + Math.random() * arena.height;
+ newPopcorn.vx = -(5 + Math.random() * 5);
+ newPopcorn.vy = 0;
+ break;
+ case 2:
+ // Bottom
+ newPopcorn.x = bounds.left + Math.random() * arena.width;
+ newPopcorn.y = bounds.bottom + 200;
+ newPopcorn.vx = 0;
+ newPopcorn.vy = -(5 + Math.random() * 5);
+ break;
+ case 3:
+ // Left
+ newPopcorn.x = bounds.left - 200;
+ newPopcorn.y = bounds.top + Math.random() * arena.height;
+ newPopcorn.vx = 5 + Math.random() * 5;
+ newPopcorn.vy = 0;
+ break;
+ }
+ // Add throwing physics to popcorn
+ newPopcorn.isThrowing = true;
+ // Override update method to handle throwing animation
+ var originalUpdate = newPopcorn.update;
+ newPopcorn.update = function () {
+ if (newPopcorn.isThrowing) {
+ // Apply velocity
+ newPopcorn.x += newPopcorn.vx;
+ newPopcorn.y += newPopcorn.vy;
+ // Apply slight gravity and rotation during throw
+ newPopcorn.vy += 0.1;
+ newPopcorn.rotation += 0.05;
+ // Check if popcorn has entered the arena
+ if (newPopcorn.x > bounds.left + 100 && newPopcorn.x < bounds.right - 100 && newPopcorn.y > bounds.top + 100 && newPopcorn.y < bounds.bottom - 100) {
+ // Switch to normal behavior once inside
+ newPopcorn.isThrowing = false;
+ // Play sound effect for landing
+ LK.getSound('Chickencluck').play();
+ // Flash effect for landing
+ LK.effects.flashObject(newPopcorn, 0xFFFFFF, 200);
+ }
+ } else {
+ // Call the original update function for normal behavior
+ originalUpdate.call(newPopcorn);
+ }
+ };
+ // Add to game and set as current popcorn
+ game.addChild(newPopcorn);
+ popcorn = newPopcorn;
+ };
+ return self;
+});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
// Create and attach power-up asset (using popcorn as base)
var powerUpGraphics = self.attachAsset('popcorn', {
@@ -670,22 +778,23 @@
var bounceForce = speed * self.tension * (1 + Math.min(0.5, speed / 40));
// Reduce random angle variation for more predictable wrestling-style bounces
var angleVariation = (Math.random() - 0.5) * 0.1; // Smaller random angle adjustment
bounceAngle += angleVariation;
- // Immediately apply a repulsive force to prevent sticking
- var minForce = 10; // Minimum bounce force to ensure chicken never gets stuck
- bounceForce = Math.max(minForce, bounceForce);
- // Apply immediate bounce to prevent sticking
- chickenJockey.vx = Math.cos(bounceAngle) * bounceForce * chickenJockey.bounceDecay;
- chickenJockey.vy = Math.sin(bounceAngle) * bounceForce * chickenJockey.bounceDecay;
- // Add a small random rotation for visual effect
- chickenJockey.rotationSpeed = (Math.random() - 0.5) * 0.15;
- // Play a sound to enhance the bounce effect
- LK.getSound('bounce').play();
- // Push chicken away from rope to prevent intersection
- var pushDistance = 20;
- chickenJockey.x += Math.cos(bounceAngle) * pushDistance;
- chickenJockey.y += Math.sin(bounceAngle) * pushDistance;
+ // Better two-phase bounce: complete stop, then dramatic spring-off
+ // First phase: completely stop the chicken to simulate "sticking" to rope
+ chickenJockey.vx = 0;
+ chickenJockey.vy = 0;
+ // Add a slightly longer delay for more dramatic pause before the spring-off
+ LK.setTimeout(function () {
+ // Second phase: apply a much stronger bounce force with enhanced velocity
+ var enhancedForce = bounceForce * 1.5; // Significantly increase spring force
+ chickenJockey.vx = Math.cos(bounceAngle) * enhancedForce * chickenJockey.bounceDecay;
+ chickenJockey.vy = Math.sin(bounceAngle) * enhancedForce * chickenJockey.bounceDecay;
+ // Add a more dramatic burst of rotation to simulate impact force
+ chickenJockey.rotationSpeed = (Math.random() - 0.5) * 0.25;
+ // Play a sound to enhance the spring effect
+ LK.getSound('bounce').play();
+ }, 200); // Slightly longer delay for more dramatic effect
// Create much more dramatic bounce visual effect with exaggerated rope "give"
tween(self, {
scaleY: 2.2,
// More extreme stretch
@@ -879,8 +988,10 @@
var launchMultiplier = 1; // Track multiplier from launches
var popcornMoveSpeed = 5000; // Base popcorn movement duration in ms
var highScoresKey = 'chickenJockeyHighScores';
var pathTracer = game.addChild(new PathTracer());
+// Create popcorn thrower
+var popcornThrower = new PopcornThrower();
// Add backdrop first
var backdrop = game.addChild(LK.getAsset('Backdrop', {
anchorX: 0.5,
anchorY: 0.5,
@@ -967,10 +1078,10 @@
// Create a few power-ups
for (var i = 0; i < 3; i++) {
createPowerUp();
}
- // Create the initial popcorn
- createPopcorn();
+ // Start popcorn thrower
+ popcornThrower.startThrowing();
// Play game start sound
LK.getSound('Gamestart').play();
// Play background music after a short delay to ensure it starts after the game start sound
LK.setTimeout(function () {
@@ -1056,15 +1167,10 @@
}
function createPopcorn() {
// Only create if no popcorn exists
if (popcorn === null) {
- var newPopcorn = new Popcorn();
- // Random position within arena bounds
- newPopcorn.x = bounds.left + 150 + Math.random() * (arena.width - 300);
- newPopcorn.y = bounds.top + 150 + Math.random() * (arena.height - 300);
- // Add to game
- game.addChild(newPopcorn);
- popcorn = newPopcorn;
+ // Use the popcorn thrower to throw popcorn from outside
+ popcornThrower.throwNextPopcorn();
}
}
function createX2Bonus() {
// Only create if no x2 bonus exists
@@ -1157,24 +1263,15 @@
// Create a new popcorn only when player is near the center
createPopcorn();
instructionText.setText("New popcorn appeared! Drag to aim and launch the chicken!");
} else {
- gameState = "ready";
- // Check if chicken is close to the center of the arena
- var centerX = arena.x;
- var centerY = arena.y;
- var distanceToCenter = Math.sqrt(Math.pow(chickenJockey.x - centerX, 2) + Math.pow(chickenJockey.y - centerY, 2));
- var centerThreshold = 200; // Threshold distance to consider "at center"
- // Force chicken to return to center after stopping
- resetChickenJockey();
- // Create a new popcorn only when player is near the center
- createPopcorn();
- instructionText.setText("New popcorn appeared! Drag to aim and launch the chicken!");
- // Instead of checking if out of launches, increase max launches
- maxLaunches++; // Increase max launches with each launch
+ instructionText.setText("What's the highest score you can get?");
}
+ // Instead of checking if out of launches, increase max launches
+ maxLaunches++; // Increase max launches with each launch
+ // Reset for next launch
+ resetChickenJockey();
}
- ;
};
game.onMaxBouncesReached = function () {
// Same as onChickenJockeyStop for now
game.onChickenJockeyStop();
@@ -1359,37 +1456,16 @@
// Track last collision time for all ropes to prevent multiple bounces
if (!chickenJockey.lastCollisionTime) {
chickenJockey.lastCollisionTime = 0;
}
- // Improved collision detection for ropes with shorter cooldown to prevent sticking
+ // Improved collision detection for ropes with proper cooldown
var currentTime = Date.now();
- var collisionCooldown = 300; // Shorter cooldown to prevent getting stuck
+ var collisionCooldown = 1000; // 1 second cooldown between any rope bounces
var canBounce = currentTime - chickenJockey.lastCollisionTime > collisionCooldown;
// Only check for rope collisions if cooldown period has passed
- if (canBounce && chickenJockey.launched && Math.abs(chickenJockey.vx) + Math.abs(chickenJockey.vy) > 0.5) {
+ if (canBounce && chickenJockey.launched && Math.abs(chickenJockey.vx) + Math.abs(chickenJockey.vy) > 1) {
for (var i = 0; i < ropes.length; i++) {
if (chickenJockey.intersects(ropes[i])) {
- // Check for "stuck" condition (multiple bounces at same location)
- var stuckThreshold = 50;
- if (!chickenJockey.lastBounceX) {
- chickenJockey.lastBounceX = chickenJockey.x;
- chickenJockey.lastBounceY = chickenJockey.y;
- chickenJockey.stuckBounceCount = 0;
- } else {
- var distanceSinceLastBounce = Math.sqrt(Math.pow(chickenJockey.x - chickenJockey.lastBounceX, 2) + Math.pow(chickenJockey.y - chickenJockey.lastBounceY, 2));
- if (distanceSinceLastBounce < stuckThreshold) {
- chickenJockey.stuckBounceCount++;
- } else {
- chickenJockey.stuckBounceCount = 0;
- }
- chickenJockey.lastBounceX = chickenJockey.x;
- chickenJockey.lastBounceY = chickenJockey.y;
- // If we detect being stuck, force chicken back to center
- if (chickenJockey.stuckBounceCount >= 3) {
- resetChickenJockey();
- return;
- }
- }
// Perform the bounce
ropes[i].bounce(chickenJockey);
// Record collision time
chickenJockey.lastCollisionTime = currentTime;
X5 symbol. In-Game asset. 2d. High contrast. No shadows
X2 symbol. In-Game asset. 2d. High contrast. No shadows
Super popcorn yellow. In-Game asset. 2d. High contrast. No shadows
Start button. In-Game asset. 2d. High contrast. No shadows
High score button. In-Game asset. 2d. High contrast. No shadows
Back button. In-Game asset. 2d. High contrast. No shadows
SELECT YOUR CHARACTER button. In-Game asset. 2d. High contrast. No shadows
Launches button. In-Game asset. 2d. High contrast. No shadows
How to play button. In-Game asset. 2d. High contrast. No shadows
Score button. In-Game asset. 2d. High contrast. No shadows
High Scores button. In-Game asset. 2d. High contrast. No shadows
Transparent padlock. In-Game asset. 2d. High contrast. No shadows
Chicken jockey character. In-Game asset. 2d. High contrast. No shadows
Reset scores button. In-Game asset. 2d. High contrast. No shadows
Spider jockey unlocked button. In-Game asset. 2d. High contrast. No shadows
Minecraft Steve unlocked button. In-Game asset. 2d. High contrast. No shadows
Piglin unlocked button. In-Game asset. 2d. High contrast. No shadows
Minecraft skeleton unlocked button. In-Game asset. 2d. High contrast. No shadows
Minecraft villager unlocked button. In-Game asset. 2d. High contrast. No shadows
Star. In-Game asset. 2d. High contrast. No shadows
White star. In-Game asset. 2d. High contrast. No shadows
Red heart. In-Game asset. 2d. High contrast. No shadows
Purple heart. In-Game asset. 2d. High contrast. No shadows
A peanut. In-Game asset. 2d. High contrast. No shadows
Cashew nut. In-Game asset. 2d. High contrast. No shadows
Grimace shake. In-Game asset. 2d. High contrast. No shadows
MacDonald's fries. In-Game asset. 2d. High contrast. No shadows
Grimace unlocked button. In-Game asset. 2d. High contrast. No shadows
Michael Jackson unlocked button. In-Game asset. 2d. High contrast. No shadows
John Cena unlocked button. In-Game asset. 2d. High contrast. No shadows
Deez nuts unlocked button. In-Game asset. 2d. High contrast. No shadows
Shooting stars unlocked button. In-Game asset. 2d. High contrast. No shadows
Rick roll unlocked button. In-Game asset. 2d. High contrast. No shadows
Popcorn chicken. In-Game asset. 2d. High contrast. No shadows
Fried chicken drumstick. In-Game asset. 2d. High contrast. No shadows
Amazing digital circus button. In-Game asset. 2d. High contrast. No shadows
Select game mode button. In-Game asset. 2d. High contrast. No shadows
Diamond shaped colourful classic mode button. In-Game asset. 2d. High contrast. No shadows
Diamond shaped colourful mini games button. In-Game asset. 2d. High contrast. No shadows
Same picture in high definition
Diamond shaped colourful button that says sling shot mode. In-Game asset. 2d. High contrast. No shadows
Make picture transparent
Bullet. In-Game asset. 2d. High contrast. No shadows
Start game button. In-Game asset. 2d. High contrast. No shadows
Shooting gallery button. In-Game asset. 2d. High contrast. No shadows
launch
Sound effect
Gamestart
Sound effect
collect
Sound effect
gameMusic
Music
Gamemusic
Sound effect
Bogerk
Sound effect
pop
Sound effect
Pignoise
Sound effect
Steve
Sound effect
Villager
Sound effect
Spider
Sound effect
Skeleton
Sound effect
Shootingstars
Music
Maccas
Sound effect
Grimace
Sound effect
Thriller
Music
MJ
Sound effect
Cenaentrance
Music
Johncena
Sound effect
Chickencluck
Sound effect
Deeznuts
Sound effect
Deeznutstrap
Music
Rickroll
Sound effect
Nevergonna
Music
Starz
Sound effect
Grimaceshake
Music
Joenugget
Sound effect
gegagedi
Music
Shrek
Sound effect
Raveswamp
Music
Pomni
Sound effect
Digcircus
Music
Runandgo
Music
Gunshot
Sound effect