Code edit (4 edits merged)
Please save this source code
Code edit (8 edits merged)
Please save this source code
User prompt
play knight-bonus when bonus taken
Code edit (1 edits merged)
Please save this source code
User prompt
bonus thow move should be slower and look more the result of an explosion ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
when spawned, bonus should be thrown with animation to one of the corners;move should look parabolic (game is in top down view) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
when spawned, animate bonus movement to one of the corners;move should look parabolic (game is in top down view) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
bonus spawn move should look parabolic ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
when spawned, animate bonus movement to a random corner ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
knight only collects the bonus if active
User prompt
add a boolean self.active=false; to bonus
Code edit (2 edits merged)
Please save this source code
User prompt
Now when knight boundingbox intersects bonusLight take the bonus (destory bonus and add 2 to health
Code edit (1 edits merged)
Please save this source code
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Background = Container.expand(function () { var self = Container.call(this); var backgroundGraphics = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5 }); self.addChild(backgroundGraphics); self.x = 2048 / 2; self.y = 2732 / 2; // Move the down handler to the Background class self.down = function (x, y, obj) { var game_position = game.toLocal(obj.global); target.x = Math.max(corners[0].x, Math.min(game_position.x, corners[3].x)); target.y = Math.max(corners[0].y, Math.min(game_position.y, corners[3].y)); }; }); var Bonus = Container.expand(function (x, y) { var self = Container.call(this); self.x = x; self.y = y; // Create shadow for bonus var shadowBonus = LK.getAsset('bonusHealth', { anchorX: 0.5, anchorY: 0.5 }); shadowBonus.alpha = 0.5; shadowBonus.tint = 0x000000; shadowBonus.x = 10; // Offset shadow position shadowBonus.y = 10; // Offset shadow position self.addChild(shadowBonus); self.active = false; var bonusGraphics = LK.getAsset('bonusHealth', { anchorX: 0.5, anchorY: 0.5 }); self.addChild(bonusGraphics); self.bonusLight = LK.getAsset('bonusHealthLight', { anchorX: 0.5, anchorY: 0.5, tint: 0x00FF00 }); self.addChild(self.bonusLight); self.animLight = function () { function loopTint() { tween(self.bonusLight, { tint: 0xFFFFFF }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { tween(self.bonusLight, { tint: 0x00FF00 }, { duration: 600, easing: tween.easeInOut, onFinish: loopTint }); } }); } loopTint(); }; self.animLight(); self.animMove = function () { function loopMove() { tween(self, { y: self.y + 10 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { y: self.y - 10 }, { duration: 500, easing: tween.easeInOut, onFinish: loopMove }); } }); } loopMove(); }; self.animMove(); self.moveToRandomCorner = function () { var randomCorner = corners[Math.floor(Math.random() * corners.length)]; tween(self, { x: randomCorner.x, y: randomCorner.y }, { duration: 2000, easing: tween.easeInOut, onFinish: function onFinish() { self.active = true; // Activate bonus after reaching the corner } }); }; self.moveToRandomCorner(); }); var ButtonPunch = Container.expand(function () { var self = Container.call(this); var buttonGraphics = LK.getAsset('buttonPunch', { anchorX: 0.5, anchorY: 0.5 }); self.addChild(buttonGraphics); // Add click/tap handler self.down = function () { // Trigger knight attack when button is pressed if (!isDied && knight && knight.health >= 0 && !knight.isAttacking) { knight.attack(); } }; }); // Import the tween plugin var Drone = Container.expand(function (level) { var self = Container.call(this); self.level = level || 0; // Set level to the passed parameter or default to 0 self.health = (isDebug ? 2 : 4) + self.level * 2; // Add level*2 to drone's health var droneWidth = 200; // Increase size based on level var levelGrowth = self.level * self.level * 100; self.droneScanLaser = LK.getAsset('droneScanLaser', { anchorX: 0, anchorY: 0.5 }); self.droneScanLaser.visible = true; // Always visible self.droneScanLaser.x = droneWidth / 2; self.droneScanLaser.alpha = 0.3; // Set alpha to 0.3 self.droneScanLaser.width += levelGrowth; self.droneScanLaser.height += levelGrowth; self.addChild(self.droneScanLaser); self.droneScanBar = LK.getAsset('droneScanBar', { anchorX: 0, anchorY: 0.5 }); self.droneScanBar.x = droneWidth / 2; self.droneScanBar.blendMode = 3; self.droneScanBar.width = self.droneScanLaser.width; self.addChild(self.droneScanBar); var droneGraphics = LK.getAsset('drone', { anchorX: 0.5, anchorY: 0.5, width: droneWidth, height: droneWidth }); var shadowDrone = LK.getAsset('drone', { anchorX: 0.5, anchorY: 0.5, width: droneWidth, height: droneWidth }); self.shadowOffset = { x: -30, y: 40 }; // Define shadow offset property shadowDrone.alpha = 0.5; shadowDrone.tint = 0x000000; shadowDrone.x = -10; shadowDrone.y = 40; self.addChild(shadowDrone); self.addChild(droneGraphics); // Add health bar under the drone self.healthBar = LK.getAsset('healthBar', { anchorX: 0.5, anchorY: 0.5, width: 100, height: 10, color: 0x00FF00 // Green color for health }); self.healthBar.y = droneWidth / 2 + 20; // Position the health bar under the drone self.addChild(self.healthBar); function loopScanLaserTint() { if (self.state !== 'scanning') { return; } tween(self.droneScanLaser, { tint: 0x00FF00 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { tween(self.droneScanLaser, { tint: 0x00AA00 }, { duration: 1000, easing: tween.easeInOut, onFinish: loopScanLaserTint // Recursively call to loop }); } }); } function animateScanBar() { if (self.state !== 'scanning') { return; } tween(self.droneScanBar, { alpha: 0.3, rotation: Math.PI / 6.75 }, { duration: 600 - self.level * 50, //{V} // Decrease duration to increase frequency with level easing: tween.easeInOut, onFinish: function onFinish() { tween(self.droneScanBar, { alpha: 0.6, rotation: -Math.PI / 6.75 }, { duration: 1000, easing: tween.easeInOut, onFinish: animateScanBar // Recursively call to loop }); // Ensure the tween is started } }); // Ensure the tween is started } self.speed = 5; self.state = ''; // Possible states: scanning, attacking // Add debug text to track drone state self.debugText = new Text2(self.state, { size: 50, fill: 0xFFFFFF }); self.debugText.x = -droneGraphics.width / 2; self.debugText.y = -droneGraphics.height / 2 - 50; self.debugText.visible = isDebug; // Set visibility based on debug mode self.addChild(self.debugText); self.fireRange = 300; // Example fire range value self.fireDelay = 1200; self.currentTargetIndex = -1; self.target = { x: 0, y: 0 }; self.lastKnightCheckTime = 0; // Track when we last checked for knight intersection self.lastFireTime = 0; // Track when we last fired at the knight self.lastRotationTime = 0; // Track the last time we updated rotation self.isRotating = false; // Flag to track if we're currently rotating self.isMoving = false; // Flag to track if we're currently moving self.needsRotation = false; // Flag to track if we need to rotate before moving self.justSwitchedFromAttacking = false; // Flag to track if we just switched from attacking mode // Function to select a new random target self.selectTarget = function () { log("selectTarget...:"); var newTargetIndex; do { newTargetIndex = Math.floor(Math.random() * corners.length); } while (newTargetIndex === self.currentTargetIndex); self.currentTargetIndex = newTargetIndex; self.target = corners[newTargetIndex]; log("New target selected at position:", self.target.x, self.target.y); // Set a flag to indicate the target is new and needs rotation first self.needsRotation = true; // Return the new target (not used currently but could be useful) return self.target; }; // Function to fire a laser beam self.fire = function () { log("Drone firing laser beam..."); LK.getSound('drone-beam').play(); var laserBeam = new LaserBeam(); laserBeam.fire(self.x, self.y, self.rotation); }; // Function to handle state transitions self.switchState = function (newState) { // Don't do anything if the state isn't changing if (self.state === newState) { return; } log("Switching drone state from " + self.state + " to " + newState); // Stop any existing tweens to ensure clean state transition tween.stop(self); // Clear scan sound interval if it exists if (self.scanSoundInterval) { LK.clearInterval(self.scanSoundInterval); self.scanSoundInterval = null; } // Reset movement flags self.isRotating = false; self.isMoving = false; self.justSwitchedFromAttacking = newState === 'scanning' && self.state === 'attacking'; // Update the state self.state = newState; self.debugText.setText(self.state); // Update debug text with current state // Handle entry actions for new state if (newState === 'scanning') { // Play drone-scan sound self.scanSoundInterval = LK.setInterval(function () { LK.getSound('drone-scan').play(); }, 1000); // Entering scanning state self.debugText.tint = 0xFFFFFF; // Reset tint to white for other states self.droneScanLaser.tint = 0x00FF00; // Reset tint to green for scanning mode // Clear current target and set flag to select a new one //self.target = null; //self.needsRotation = true; animateScanBar(); // Select a new target (this will be handled in updateScanning on next update) } else if (newState === 'attacking') { // don't fire directly, consider a part of fire delay self.lastFireTime = Date.now() - self.fireDelay * 0.5; // Entering attacking state self.debugText.tint = 0xFFA500; // Change tint to orange when attacking self.droneScanLaser.tint = 0xFFA500; // Change tint to orange when attacking // Start following the knight self.followKnight(); } }; self.init = function () { log("Drone initialized at position:", self.x, self.y); // Reset state flags self.isRotating = false; self.isMoving = false; self.needsRotation = true; // Start the animations animateScanBar(); loopScanLaserTint(); // Switch to scanning state to begin patrol self.switchState('scanning'); }; self.collectBonus = function collectBonus(bonus) { // Increase knight's health by 2 knight.health += 2; // Destroy the bonus bonus.destroy(); }; self.update = function () { if (self.state === 'scanning') { self.updateScanning(); } else if (self.state === 'attacking') { // Update function to check for intersection between knight and bonusLight self.updateAttacking(); //<Write game logic code here, including initializing arrays and variables> // Function to handle bonus collection game.update = function () { // Iterate over all bonuses in the middlegroundContainer for (var i = middlegroundContainer.children.length - 1; i >= 0; i--) { var child = middlegroundContainer.children[i]; if (child instanceof Bonus) { // Check if knight's boundingBox intersects with bonusLight if (child.active && knight.boundingBox.intersects(child.bonusLight)) { self.collectBonus(child); } } } }; self.healthBar.width = Math.max(0, (self.health + 1) / 4 * 100); // Assuming max health is 4 // Change health bar color based on health var healthPercentage = self.health / 4; // Assuming max health is 4 var red, green; // Transition from green to orange if (healthPercentage > 0.5) { red = Math.min(255, Math.floor((1 - healthPercentage) * 2 * 255)); green = 255; } else { // Transition from orange to red red = 255; green = Math.min(255, Math.floor(healthPercentage * 2 * 255)); } self.healthBar.tint = red << 16 | green << 8; // Combine red and green to form the color } // Update shadow position shadowDrone.x = self.shadowOffset.x * Math.cos(self.rotation); shadowDrone.y = self.shadowOffset.y * Math.sin(self.rotation); // Update droneScanBar width based on its rotation self.droneScanBar.width = self.droneScanLaser.width * (1 + 0.1 * Math.abs(Math.sin(self.droneScanBar.rotation))); }; // Function to perform a full 360° scan self.performFullScan = function (callback) { // Calculate duration based on a consistent rotation speed var scanRotationSpeed = 1.0; // Radians per second (slower for scanning) var fullRotationDuration = Math.PI * 2 / scanRotationSpeed * 1000; // ms // Store current rotation var startRotation = self.rotation; // Mark that we're rotating to prevent updateScanning from starting other rotations self.isRotating = true; log("Performing 360° scan"); // Perform a full 360° rotation tween(self, { rotation: startRotation + Math.PI * 2 // Full 360° rotation }, { duration: fullRotationDuration, easing: tween.linear, // Linear easing for constant speed onFinish: function onFinish() { // Clear rotation flag when done self.isRotating = false; log("Full scan complete"); // Call callback if provided if (callback) { callback(); } } }); }; // Handle scanning mode behavior self.updateScanning = function () { // Check for intersection with knight if (!isDied && self.droneScanBar.intersects(knight.boundingBox)) { self.switchState('attacking'); log("Drone switched to attacking mode!"); return; } // If no target is set, select one if (!self.target) { log("No target set, selecting a new one"); // If we just switched from attacking to scanning mode, do a 360° scan first if (self.justSwitchedFromAttacking) { self.justSwitchedFromAttacking = false; self.fire(); // Perform full scan before selecting a new target self.performFullScan(function () { // After scan is complete, select a new target self.selectTarget(); }); return; } // Otherwise just select a new target self.selectTarget(); return; } // Calculate direction and distance to target var dx = self.target.x - self.x; var dy = self.target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // If very close to target, select a new one if (distance < 10) { log("Reached target, selecting a new one"); self.selectTarget(); return; } // Calculate target angle var targetAngle = Math.atan2(dy, dx); // Check if rotation is needed var angleDiff = Math.abs(calculateAngleDiff(targetAngle, self.rotation)); // If rotation is needed (more than 0.1 radians difference or flag is set) if (angleDiff > 0.1 || self.needsRotation) { // Only start a new rotation if not already rotating if (!self.isRotating) { log("Rotating to face target"); self.isRotating = true; // Use the updateRotation function with callback to clear isRotating flag self.updateRotation(targetAngle, 600, function () { self.isRotating = false; self.needsRotation = false; log("Rotation complete"); }); } } // If rotation is close enough and we're not currently moving, start movement else if (!self.isMoving) { log("Starting movement to target"); self.isMoving = true; // Calculate duration based on distance var moveSpeed = 0.2; // Adjust this value to control drone speed var duration = distance / moveSpeed; // Start moving toward the target tween(self, { x: self.target.x, y: self.target.y }, { duration: duration, easing: tween.easeInOut, onFinish: function onFinish() { self.isMoving = false; log("Movement complete"); // Don't automatically select a new target, let updateScanning handle it } }); } }; // Handle attacking mode behavior self.updateAttacking = function () { var currentTime = Date.now(); // Fire using separate counter if (currentTime - self.lastFireTime > self.fireDelay) { // Fire every 1.2 seconds self.lastFireTime = currentTime; self.fire(); } var dx = knight.x - self.x; var dy = knight.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var angle = Math.atan2(dy, dx); // Drone rotation logic - directly rotate the drone to face the knight // Only do smooth rotation tracking when not already moving to a new position //self.lastRotationTime = currentTime; // Calculate a smoother intermediate angle for natural tracking var currentAngle = self.rotation; var angleDiff = calculateAngleDiff(angle, currentAngle); // Only rotate a portion of the way to the target for smoother tracking // This creates a slight lag effect that looks more natural var partialAngle = currentAngle + angleDiff * 0.3; // Directly set rotation instead of using updateRotation self.rotation = partialAngle; //self.isRotating = false; // No need for callback since we're setting directly // Rotate droneScanBar to point at knight within limits var relativeAngle = calculateAngleDiff(angle, self.rotation); // Clamp the scan bar rotation to the maximum allowed range var maxRotation = Math.PI / 6.5; var clampedRotation = Math.max(-maxRotation, Math.min(maxRotation, relativeAngle)); // Set the scan bar rotation directly self.droneScanBar.rotation = clampedRotation; self.droneScanBar.alpha = 0.1; // First check if knight is still in range - do this every second if (currentTime - self.lastKnightCheckTime > 1000) { self.lastKnightCheckTime = currentTime; // Check if we can still see the knight if (!self.droneScanBar.intersects(knight.boundingBox)) { log("Knight lost! Returning to scanning mode."); self.switchState('scanning'); return; } log("Knight still in range at distance: " + distance); } // Position update logic - if we're not currently moving but need to if (isDied) { log("Knight is dead, returning to scanning mode."); self.switchState('scanning'); return; } if (!self.isMoving && distance > 550) { log("Knight moved - updating drone position"); // Move to a better position self.followKnight(); return; } }; self.followKnight = function () { log("followKnight..."); // Cancel any existing movement tweens tween.stop(self); // Calculate direction to knight var dx = knight.x - self.x; var dy = knight.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var angle = Math.atan2(dy, dx); // Set the movement flag self.isMoving = true; self.isRotating = true; // After rotation is complete, start moving toward knight self.moveTowardKnight(); }; // Function to calculate distance to knight self.distanceToKnight = function () { var dx = knight.x - self.x; var dy = knight.y - self.y; return Math.sqrt(dx * dx + dy * dy); }; self.moveTowardKnight = function () { var dx = knight.x - self.x; var dy = knight.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // If already within the desired distance, stop moving if (distance <= 500) { return; } // Calculate target position that's 500 units away from knight var ratio = (distance - 500) / distance; var targetX = self.x + dx * ratio; var targetY = self.y + dy * ratio; // Move toward the target tween(self, { x: targetX, y: targetY }, { duration: distance * 2, // Speed based on distance easing: tween.linear, onUpdate: function onUpdate() { // Update rotation to continuously face the knight during movement var currentDx = knight.x - self.x; var currentDy = knight.y - self.y; var currentDistance = Math.sqrt(currentDx * currentDx + currentDy * currentDy); // Only update rotation if not very close to the target if (currentDistance > 10) { var currentAngle = Math.atan2(currentDy, currentDx); // Calculate target rotation with a smaller adjustment for smoothness using the utility function var newRotation = self.rotation + calculateAngleDiff(currentAngle, self.rotation) * 0.1; // Create a separate quick tween for the rotation tween(self, { rotation: newRotation }, { duration: 600, // Very short duration for responsive updates easing: tween.linear }); } }, onFinish: function onFinish() { // Check if we're still in attacking mode before continuing to follow if (self.state === 'attacking') { // Check if knight has moved and we need to follow again if (self.distanceToKnight() > 500) { self.moveTowardKnight(); } } } }); }; self.updateRotation = function (targetAngle, maxDuration, callback) { maxDuration = maxDuration || 500; // Default max duration if not specified // Cancel any existing rotation tweens to prevent conflicts tween.stop(self, 'rotation'); // Normalize angles to be between -PI and PI for proper comparison var normalizedCurrentAngle = self.rotation % (2 * Math.PI); if (normalizedCurrentAngle > Math.PI) { normalizedCurrentAngle -= 2 * Math.PI; } if (normalizedCurrentAngle < -Math.PI) { normalizedCurrentAngle += 2 * Math.PI; } // Normalize target angle var normalizedTargetAngle = targetAngle % (2 * Math.PI); if (normalizedTargetAngle > Math.PI) { normalizedTargetAngle -= 2 * Math.PI; } if (normalizedTargetAngle < -Math.PI) { normalizedTargetAngle += 2 * Math.PI; } // Calculate the angle difference using the normalized angles var angleDiff = calculateAngleDiff(normalizedTargetAngle, normalizedCurrentAngle); var absDiff = Math.abs(angleDiff); // If the angle difference is greater than PI, rotate in the shorter direction if (absDiff > Math.PI) { if (angleDiff > 0) { angleDiff -= 2 * Math.PI; } else { angleDiff += 2 * Math.PI; } } // Calculate duration based on angle difference to achieve constant rotation speed // Use radians per second as the speed unit var rotationSpeed = 6; // Radians per second var duration = Math.min(absDiff / rotationSpeed * 1000, maxDuration); // Ensure a minimum duration for very small rotations duration = Math.max(duration, 50); // Calculate the target rotation by adding the angle difference to the current rotation var targetRotation = self.rotation + angleDiff; // Log the rotation parameters for debugging log("Rotating: angle diff=" + absDiff + ", duration=" + duration + "ms"); // Perform the rotation tween tween(self, { rotation: targetRotation }, { duration: duration, easing: tween.easeInOut, onFinish: function onFinish() { log("Rotation complete"); if (callback) { callback(); } } }); }; self.takeHit = function (bullet) { // Play drone-hit sound LK.getSound('drone-hit').play(); // Flash the drone red to indicate damage droneGraphics.tint = 0xff0000; // Red tint // After a short delay, restore the original tint LK.setTimeout(function () { droneGraphics.tint = 0xFFFFFF; // Restore original color }, 200); // Log hit for debugging log("Drone hit by attack!"); // Reduce health when hit self.health -= 1; // Check if drone is destroyed if (self.health <= 0) { log("Drone destroyed!"); self.explode(); return; } // Switch to attacking state immediately if not already attacking if (self.state !== 'attacking') { self.switchState('attacking'); } // Reset the lastKnightCheckTime to ensure we don't immediately check for knight visibility self.lastKnightCheckTime = Date.now(); // Add knockback effect based on bullet direction var knockbackDistance = 50; var knockbackAngle = bullet.rotation; // Calculate potential new position var newX = self.x + Math.cos(knockbackAngle) * knockbackDistance; var newY = self.y + Math.sin(knockbackAngle) * knockbackDistance; // Check if new position would be too close to a corner var tooCloseToCorner = false; var cornerSafeDistance = 100; // Distance to stay away from corners for (var i = 0; i < corners.length; i++) { var dx = newX - corners[i].x; var dy = newY - corners[i].y; var distToCorner = Math.sqrt(dx * dx + dy * dy); if (distToCorner < cornerSafeDistance) { tooCloseToCorner = true; break; } } // If too close to a corner, adjust the knockback to push away from corner if (tooCloseToCorner) { // Find the center of the playfield var centerX = (corners[0].x + corners[3].x) / 2; var centerY = (corners[0].y + corners[3].y) / 2; // Calculate direction toward center var dxToCenter = centerX - self.x; var dyToCenter = centerY - self.y; var angleToCenter = Math.atan2(dyToCenter, dxToCenter); // Use this angle for knockback instead newX = self.x + Math.cos(angleToCenter) * knockbackDistance; newY = self.y + Math.sin(angleToCenter) * knockbackDistance; } // Clamp new position using corners newX = Math.max(corners[0].x + cornerSafeDistance, Math.min(newX, corners[3].x - cornerSafeDistance)); newY = Math.max(corners[0].y + cornerSafeDistance, Math.min(newY, corners[3].y - cornerSafeDistance)); // Apply knockback using tween tween(self, { x: newX, y: newY }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { // After knockback, immediately rotate the drone toward the knight // Calculate angle to knight var dx = knight.x - self.x; var dy = knight.y - self.y; var angleToKnight = Math.atan2(dy, dx); // Calculate the angle difference for proper duration var normalizedCurrentAngle = self.rotation % (2 * Math.PI); if (normalizedCurrentAngle > Math.PI) { normalizedCurrentAngle -= 2 * Math.PI; } if (normalizedCurrentAngle < -Math.PI) { normalizedCurrentAngle += 2 * Math.PI; } var normalizedTargetAngle = angleToKnight % (2 * Math.PI); if (normalizedTargetAngle > Math.PI) { normalizedTargetAngle -= 2 * Math.PI; } if (normalizedTargetAngle < -Math.PI) { normalizedTargetAngle += 2 * Math.PI; } var angleDiff = calculateAngleDiff(normalizedTargetAngle, normalizedCurrentAngle); if (Math.abs(angleDiff) > Math.PI) { if (angleDiff > 0) { angleDiff -= 2 * Math.PI; } else { angleDiff += 2 * Math.PI; } } // Calculate duration based on angle difference var rotationSpeed = 6; // Radians per second var absDiff = Math.abs(angleDiff); var duration = Math.min(absDiff / rotationSpeed * 1000, 500); duration = Math.max(duration, 50); // Ensure minimum duration // Rotate drone to face knight with calculated duration tween(self, { rotation: self.rotation + angleDiff }, { duration: duration, easing: tween.easeInOut, onFinish: function onFinish() { // Switch to attacking state if not already attacking if (self.state !== 'attacking') { self.switchState('attacking'); } // Reset the lastKnightCheckTime to ensure we don't immediately check for knight visibility self.lastKnightCheckTime = Date.now(); } }); } }); }; self.explode = function () { // Simply destroy the drone tween.stop(self); // Stop all tweens on the drone var explosion = new Explosion(); explosion.init(self.x, self.y); middlegroundContainer.addChild(explosion); // Clear scan sound interval if it exists if (self.scanSoundInterval) { LK.clearInterval(self.scanSoundInterval); self.scanSoundInterval = null; } LK.getSound('drone-explode').play(); // Spawn a bonus at the drone's position var bonus = new Bonus(self.x, self.y); middlegroundContainer.addChild(bonus); self.destroy(); droneManager.start(); }; }); var Explosion = Container.expand(function () { var self = Container.call(this); for (var i = 0; i < 30; i++) { var particle = LK.getAsset('explosionParticle', { anchorX: 0.5, anchorY: 0.5 }); var scale = Math.random() * 0.5 + 0.5; // Random scale between 0.5 and 1.0 particle.scale.set(scale); var colors = [0xFF4500, 0xFF6347, 0xFFFFFF, 0xFFFF00, 0x8B0000]; // Array of colors: orange, red, white, yellow, dark red particle.tint = colors[Math.floor(Math.random() * colors.length)]; // Randomly choose a color from the array var angle = Math.random() * Math.PI * 2; // Random direction var speed = Math.random() * 5 + 100; // Random speed between 2 and 7 particle.vx = Math.cos(angle) * speed; particle.vy = Math.sin(angle) * speed; particle.rotation = angle; // Rotate particle in the direction of movement self.addChild(particle); } // Initialize explosion properties self.init = function (x, y) { self.x = x; self.y = y; self.scale.set(0.8); // Start small self.alpha = 1.0; // Fully visible // Animate the explosion var particles = self.children; var duration = 2000; // Duration for particles to move and fade out particles.forEach(function (particle) { tween(particle, { x: particle.x + particle.vx * duration / 1000, y: particle.y + particle.vy * duration / 1000, alpha: 0.0 }, { duration: duration, easing: tween.easeOut }); }); LK.setTimeout(function () { self.destroy(); // Remove explosion after animation }, duration); }; }); var ExplosionKnight = Container.expand(function () { var self = Container.call(this); for (var i = 0; i < 80; i++) { var particle = LK.getAsset('explosionParticle', { anchorX: 0.5, anchorY: 0.5 }); var scale = Math.random() * 0.5 + 0.5; // Random scale between 0.5 and 1.0 particle.scale.set(scale); particle.tint = 0x000000; // Set particle color to black var speed = 100 + Math.random() * 100; // Random speed between 2 and 7 particle.vx = 0; // No horizontal movement particle.vy = -speed; // Negative vertical movement particle.rotation = Math.PI / 2; // Rotate by PI/2 self.addChild(particle); } // Initialize explosion properties self.init = function (x, y) { self.x = x; self.y = y; self.scale.set(0.8); // Start small self.alpha = 1.0; // Fully visible // Animate the explosion var particles = self.children; var duration = 2000; // Duration for particles to move and fade out particles.forEach(function (particle) { particle.x += -40 + Math.random() * 80; particle.y += -40 + Math.random() * 80; tween(particle, { x: particle.x + particle.vx * duration / 500, y: particle.y + particle.vy * duration / 500, alpha: 0.0, scaleY: 0 }, { duration: duration, easing: tween.easeOut }); }); LK.setTimeout(function () { self.destroy(); // Remove explosion after animation }, duration); }; }); var Knight = Container.expand(function () { var self = Container.call(this); self.health = isDebug ? 10 : 3; // Initialize health property with a value of 3 // Add boundingBox for collision detection self.boundingBox = LK.getAsset('boundingBox', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 150, y: -50 }); self.addChild(self.boundingBox); self.boundingBox.alpha = isDebug ? 0.5 : 0; // Set to false if you don't want it visible var directionMapping = { 'down-left': 'dir1', 'left': 'dir2', 'up-left': 'dir3', 'up': 'dir4', 'up-right': 'dir5', 'right': 'dir6', 'down-right': 'dir7', 'down': 'dir8' }; // Pre-create a list of assets for each direction var knightAssets = {}; var shadowAssets = {}; // Shadow assets for the knight var knightIdleAssets = {}; // Idle assets for the knight var shadowIdleAssets = {}; // Shadow idle assets for the knight var knightAttackAssets = {}; // Attack assets for the knight var shadowAttackAssets = {}; // Shadow attack assets for the knight var color = 0xFFFFFF; // Original blue / 0xff4d4d; // Red / 0x9aff9a; // Green // Initialize run animation assets for (var dir in directionMapping) { knightAssets[dir] = []; shadowAssets[dir] = []; // Initialize shadow assets array for each direction knightAttackAssets[dir] = []; // Initialize attack assets array for each direction shadowAttackAssets[dir] = []; // Initialize shadow attack assets array for each direction // Load run animation frames (8 frames) for (var i = 1; i <= 8; i++) { var frameNumber = i.toString().padStart(3, '0'); // Create knight sprite knightAssets[dir].push(LK.getAsset('knight-run-' + directionMapping[dir] + '-' + frameNumber, { anchorX: 0.5, anchorY: 0.5, tint: color })); // Create shadow sprite using the same assets but with modifications var shadowSprite = LK.getAsset('knight-run-' + directionMapping[dir] + '-' + frameNumber, { anchorX: 0.5, anchorY: 0.5 }); // Apply shadow properties shadowSprite.alpha = 0.5; shadowSprite.tint = 0x000000; shadowSprite.rotation = Math.PI / 12; // Rotate by 15 degrees (π/12 radians) shadowSprite.scale.y = 0.5; // Flatten the shadow vertically shadowAssets[dir].push(shadowSprite); } // Load attack animation frames (15 frames) for (var i = 1; i <= 15; i++) { var frameNumber = i.toString().padStart(3, '0'); // Create attack sprite knightAttackAssets[dir].push(LK.getAsset('knight-attack-' + directionMapping[dir] + '-' + frameNumber, { anchorX: 0.5, anchorY: 0.5, tint: color })); // Create shadow attack sprite using the same assets but with modifications var shadowAttackSprite = LK.getAsset('knight-attack-' + directionMapping[dir] + '-' + frameNumber, { anchorX: 0.5, anchorY: 0.5 }); // Apply shadow properties shadowAttackSprite.alpha = 0.5; shadowAttackSprite.tint = 0x000000; shadowAttackSprite.rotation = Math.PI / 12; // Rotate by 15 degrees (π/12 radians) shadowAttackSprite.scale.y = 0.5; // Flatten the shadow vertically shadowAttackAssets[dir].push(shadowAttackSprite); } // Initialize idle animation assets (one frame per direction) knightIdleAssets[dir] = LK.getAsset('knight-idle-' + directionMapping[dir] + '-001', { anchorX: 0.5, anchorY: 0.5, tint: color }); // Create shadow for idle animation var shadowIdleSprite = LK.getAsset('knight-idle-' + directionMapping[dir] + '-001', { anchorX: 0.5, anchorY: 0.5 }); // Apply shadow properties shadowIdleSprite.alpha = 0.5; shadowIdleSprite.tint = 0x000000; shadowIdleSprite.rotation = Math.PI / 12; shadowIdleSprite.scale.y = 0.5; shadowIdleAssets[dir] = shadowIdleSprite; } var currentFrame = 0; var animationSpeed = 0.2; // Controls how fast the animation plays var frameCounter = 0; var knightGraphics = knightIdleAssets['down']; // Initialize with the 'down' direction idle asset var shadowGraphics = shadowIdleAssets['down']; // Initialize shadow with the 'down' direction idle asset // Add health bar under the knight self.healthBar = LK.getAsset('healthBar', { anchorX: 0.5, anchorY: 0.5, width: 100, height: 10, color: 0x00FF00 // Green color for health }); self.healthBar.y = 60; // Position the health bar under the knight self.addChild(self.healthBar); // Add shadow first (so it appears behind the knight) self.addChild(shadowGraphics); // Then add the knight self.addChild(knightGraphics); knightGraphics.anchor.set(0.5, 0.5); knightGraphics.visible = true; shadowGraphics.visible = true; // Position the shadow slightly offset from the knight var shadowOffsetX = -5; var shadowOffsetY = 20; shadowGraphics.x = shadowOffsetX; shadowGraphics.y = shadowOffsetY; self.lastDirection = 'down'; // Initialize lastDirection to track previous direction self.isMoving = false; // Track if the knight is currently moving self.isAttacking = false; // Track if the knight is currently attacking self.speed = 9; var distanceThreshold = 8; // Define a threshold to avoid small movements var directionThreshold = 5; // Define a threshold for direction changes to avoid shaking self.update = function () { // Update health bar width based on knight's health self.healthBar.width = Math.max(0, (self.health + 1) / 4 * 100); // Assuming max health is 3 // Change health bar color based on health var healthPercentage = self.health / 3; // Assuming max health is 3 var red, green; // Transition from green to orange if (healthPercentage > 0.5) { red = Math.min(255, Math.floor((1 - healthPercentage) * 2 * 255)); green = 255; } else { // Transition from orange to red red = 255; green = Math.min(255, Math.floor(healthPercentage * 2 * 255)); } self.healthBar.tint = red << 16 | green << 8; // Combine red and green to form the color // Don't process movement if attacking if (isDied || self.health < 0 || self.isAttacking) { return; } var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > distanceThreshold) { // Set knight to moving state if not already moving if (!self.isMoving) { self.isMoving = true; self.switchAsset(self.lastDirection || 'down'); // Update asset to running animation } // Determine the primary direction based on the larger component (dx or dy) if (Math.abs(dx) > Math.abs(dy) + directionThreshold) { // Horizontal movement dominates if (dx > 0) { if (dy > directionThreshold) { self.moveToDirection('down-right'); } else if (dy < -directionThreshold) { self.moveToDirection('up-right'); } else { self.moveToDirection('right'); } } else { if (dy > directionThreshold) { self.moveToDirection('down-left'); } else if (dy < -directionThreshold) { self.moveToDirection('up-left'); } else { self.moveToDirection('left'); } } } else if (Math.abs(dy) > Math.abs(dx) + directionThreshold) { // Vertical movement dominates if (dy > 0) { if (dx > directionThreshold) { self.moveToDirection('down-right'); } else if (dx < -directionThreshold) { self.moveToDirection('down-left'); } else { self.moveToDirection('down'); } } else { if (dx > directionThreshold) { self.moveToDirection('up-right'); } else if (dx < -directionThreshold) { self.moveToDirection('up-left'); } else { self.moveToDirection('up'); } } } else { // The difference between dx and dy is small, use diagonal movement if (dx > 0 && dy > 0) { self.moveToDirection('down-right'); } else if (dx > 0 && dy < 0) { self.moveToDirection('up-right'); } else if (dx < 0 && dy > 0) { self.moveToDirection('down-left'); } else if (dx < 0 && dy < 0) { self.moveToDirection('up-left'); } } } else { // Check if knight is not moving and distance to drone is less than 400 if (!self.isMoving) { if (droneManager && droneManager.drones.length > 0) { var drone = droneManager.drones[0]; // Assuming single drone for simplicity var dx = drone.x - self.x; var dy = drone.y - self.y; var distanceToDrone = Math.sqrt(dx * dx + dy * dy); } if (distanceToDrone < 400) { // Calculate angle to orient knight towards drone var angleToDrone = Math.atan2(dy, dx); var directionToDrone; if (angleToDrone >= -Math.PI / 8 && angleToDrone < Math.PI / 8) { directionToDrone = 'right'; } else if (angleToDrone >= Math.PI / 8 && angleToDrone < 3 * Math.PI / 8) { directionToDrone = 'down-right'; } else if (angleToDrone >= 3 * Math.PI / 8 && angleToDrone < 5 * Math.PI / 8) { directionToDrone = 'down'; } else if (angleToDrone >= 5 * Math.PI / 8 && angleToDrone < 7 * Math.PI / 8) { directionToDrone = 'down-left'; } else if (angleToDrone >= 7 * Math.PI / 8 || angleToDrone < -7 * Math.PI / 8) { directionToDrone = 'left'; } else if (angleToDrone >= -7 * Math.PI / 8 && angleToDrone < -5 * Math.PI / 8) { directionToDrone = 'up-left'; } else if (angleToDrone >= -5 * Math.PI / 8 && angleToDrone < -3 * Math.PI / 8) { directionToDrone = 'up'; } else if (angleToDrone >= -3 * Math.PI / 8 && angleToDrone < -Math.PI / 8) { directionToDrone = 'up-right'; } if (directionToDrone) { self.switchAsset(directionToDrone); } } } // Set knight to idle state if currently moving if (self.isMoving) { self.isMoving = false; self.switchAsset(self.lastDirection || 'down'); // Update asset to idle animation } } // Update knight animation self.updateAnimation(); }; self.switchAsset = function (direction) { if (!knightGraphics) { return; } // If currently attacking, don't switch assets if (isDied || self.health < 0 || self.isAttacking) { return; } // Detach current assets // Hide current assets knightGraphics.visible = false; shadowGraphics.visible = false; // Switch to new assets based on direction and movement state if (self.isMoving) { // Use running animation knightGraphics = knightAssets[direction][currentFrame]; shadowGraphics = shadowAssets[direction][currentFrame]; } else { // Use idle animation knightGraphics = knightIdleAssets[direction]; shadowGraphics = shadowIdleAssets[direction]; } self.addChild(shadowGraphics); self.addChild(knightGraphics); // Show new assets knightGraphics.visible = true; shadowGraphics.visible = true; // Position the shadow slightly offset from the knight shadowGraphics.x = shadowOffsetX; shadowGraphics.y = shadowOffsetY; // Update last direction self.lastDirection = direction; }; self.updateAnimation = function () { // If currently attacking, don't switch assets if (isDied || self.health < 0 || self.isAttacking) { return; } if (self.isMoving) { // Only update animation if moving frameCounter += animationSpeed; if (frameCounter >= 1) { frameCounter = 0; currentFrame = (currentFrame + 1) % 8; // Cycle through 8 frames if (self.lastDirection) { self.switchAsset(self.lastDirection); } } } else if (self.lastDirection) { // Make sure we're showing the idle animation when not moving self.switchAsset(self.lastDirection); } }; self.moveToDirection = function (direction) { if (isDied || self.health < 0 || self.isAttacking) { return; } if (self.lastDirection !== direction) { self.switchAsset(direction); self.lastDirection = direction; } switch (direction) { case 'up': self.y -= self.speed; break; case 'down': self.y += self.speed; break; case 'left': self.x -= self.speed; break; case 'right': self.x += self.speed; break; case 'up-left': self.x -= self.speed / Math.sqrt(2); self.y -= self.speed / Math.sqrt(2); break; case 'up-right': self.x += self.speed / Math.sqrt(2); self.y -= self.speed / Math.sqrt(2); break; case 'down-left': self.x -= self.speed / Math.sqrt(2); self.y += self.speed / Math.sqrt(2); break; case 'down-right': self.x += self.speed / Math.sqrt(2); self.y += self.speed / Math.sqrt(2); break; } }; self.takeHit = function (bullet) { if (isDied) { return; } // Flash the knight red to indicate damage self.tint = 0xff0000; // Red tint // After a short delay, restore the original tint LK.setTimeout(function () { self.tint = color; // Restore original color }, 200); // Optional: Add knockback effect based on bullet direction var knockbackDistance = 30; var knockbackAngle = bullet.rotation; // Apply knockback self.x += Math.cos(knockbackAngle) * knockbackDistance; self.y += Math.sin(knockbackAngle) * knockbackDistance; self.health--; if (self.health < 0) { self.dieAnim(); } else { // Play knight-hit sound LK.getSound('knight-hit').play(); } // Log hit for debugging log("Knight hit by laser beam!"); }; self.dieAnim = function () { // Animate knight tint to black LK.getSound('knight-die').play(); punchButton.visible = false; // Hide attackButton when the knight is dead if (isDied) { return; } isDied = true; tween(self, { tint: 0x000000 }, { duration: 1000, // 1 second duration easing: tween.easeInOut, onFinish: function onFinish() { var explosion = new ExplosionKnight(); explosion.init(self.x, self.y - 50); middlegroundContainer.addChild(explosion); LK.getSound('knight-killed').play(); self.destroy(); // Destroy knight after animation LK.setTimeout(function () { LK.showGameOver(); }, 3000); // Call game over after 2 seconds } }); }; self.attack = function () { // Check if already attacking if (self.isAttacking) { return; } // Play knight-attack sound LK.getSound('knight-attack').play(); self.isAttacking = true; log("Knight attacking!"); // Store current direction var direction = self.lastDirection || 'down'; // Get attack animation frames for current direction var attackFrames = knightAttackAssets[direction]; var shadowAttackFrames = shadowAttackAssets[direction]; // Hide current graphics // knightGraphics.visible = false; // shadowGraphics.visible = false; // Add all frames but make them invisible initially for (var i = 0; i < attackFrames.length; i++) { self.addChild(shadowAttackFrames[i]); self.addChild(attackFrames[i]); shadowAttackFrames[i].visible = false; attackFrames[i].visible = false; } // Create attack animation var currentFrame = 0; var attackInterval = LK.setInterval(function () { if (self.isDied) { return; } // Hide previous frame if it exists if (currentFrame > 0) { attackFrames[currentFrame - 1].visible = false; shadowAttackFrames[currentFrame - 1].visible = false; } // Hide current graphics knightGraphics.visible = false; shadowGraphics.visible = false; // Show current frame shadowAttackFrames[currentFrame].visible = true; attackFrames[currentFrame].visible = true; // Check for collision with drones (middle of the attack animation) if (currentFrame === Math.floor(attackFrames.length / 2)) { // Calculate attack range and direction var attackRange = 100; // Range of the knight's attack var attackDirection = direction; var attackAngle; // Determine attack angle based on direction if (attackDirection === 'right') { attackAngle = 0; } else if (attackDirection === 'down-right') { attackAngle = Math.PI / 4; } else if (attackDirection === 'down') { attackAngle = Math.PI / 2; } else if (attackDirection === 'down-left') { attackAngle = 3 * Math.PI / 4; } else if (attackDirection === 'left') { attackAngle = Math.PI; } else if (attackDirection === 'up-left') { attackAngle = 5 * Math.PI / 4; } else if (attackDirection === 'up') { attackAngle = 3 * Math.PI / 2; } else if (attackDirection === 'up-right') { attackAngle = 7 * Math.PI / 4; } // Calculate attack point in front of the knight var attackX = self.x + Math.cos(attackAngle) * attackRange; var attackY = self.y + Math.sin(attackAngle) * attackRange; // Check if any drone is within attack range for (var i = 0; i < droneManager.drones.length; i++) { var drone = droneManager.drones[i]; var dx = drone.x - attackX; var dy = drone.y - attackY; var distance = Math.sqrt(dx * dx + dy * dy); // If drone is within attack range, call its takeHit method if (distance < 120) { // Adjust hit radius as needed drone.takeHit({ rotation: attackAngle // Pass attack angle for knockback direction }); } } } // Move to next frame currentFrame++; // Check if animation is complete if (currentFrame >= attackFrames.length) { // Clear interval LK.clearInterval(attackInterval); // Hide all attack frames for (var i = 0; i < attackFrames.length; i++) { attackFrames[i].visible = false; shadowAttackFrames[i].visible = false; } // Show regular graphics again knightGraphics.visible = true; shadowGraphics.visible = true; // Reset attacking flag self.isAttacking = false; // Reset the global target position to knight's current position target.x = self.x; target.y = self.y; } }, 50); // 50ms per frame for a fast attack animation }; }); var LaserBeam = Container.expand(function () { var self = Container.call(this); var laserBeamGraphics = LK.getAsset('droneLaserBeam', { anchorX: 0.5, anchorY: 0.5, blendMode: 1 }); self.addChild(laserBeamGraphics); self.speed = 1500; // Speed of the laser beam in pixels per second self.fire = function (x, y, rotation) { self.x = x; self.y = y; self.rotation = rotation; middlegroundContainer.addChild(self); // Calculate the distance the laser beam will travel var distance = 3000; // Calculate the duration based on speed var duration = distance / self.speed * 1000; // Convert to milliseconds // Tween the laser beam to move forward tween(self, { x: self.x + Math.cos(self.rotation) * distance, y: self.y + Math.sin(self.rotation) * distance }, { duration: duration, easing: tween.linear, onFinish: function onFinish() { self.destroy(); } }); }; self.update = function () { if (self.intersects(knight.boundingBox)) { knight.takeHit(self); self.destroy(); } }; }); var Room = Container.expand(function () { var self = Container.call(this); var background = LK.getAsset('backgroundWalls', { anchorX: 0.5, anchorY: 0.5 }); self.addChild(background); self.x = 2048 / 2; self.y = 2732 / 2; }); var Target = Container.expand(function () { var self = Container.call(this); self.x = 0; self.y = 0; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 //Init game with black background }); /**** * Game Code ****/ // Utility function to calculate the angle difference function calculateAngleDiff(targetAngle, currentAngle) { var angleDiff = targetAngle - currentAngle; // Normalize angle difference to [-PI, PI] while (angleDiff > Math.PI) { angleDiff -= 2 * Math.PI; } while (angleDiff < -Math.PI) { angleDiff += 2 * Math.PI; } return angleDiff; } //<Write entity 'classes' with empty functions for important behavior here> //<Write imports for supported plugins here> //<Assets used in the game will automatically appear here> //<Write game logic code here, including initializing arrays and variables> var DroneManager = function DroneManager() { var self = this; self.droneCounter = 0; // Initialize droneCounter to track the number of drones self.drones = []; self.start = function () { // Clear previous drones from the scene and the drones array self.drones.forEach(function (drone) { drone.destroy(); }); self.drones = []; // Create the drone var drone = new Drone(self.droneCounter); // Pass the current level to the Drone constructor // Increment counter after drone creation so first drone is level 0 self.droneCounter++; // Check win condition after incrementing counter if (self.droneCounter > 3) { LK.getSound('knight-win').play(); // Play knight-win sound LK.setTimeout(function () { LK.showYouWin(); // Show win screen after 2000ms delay }, 2000); return; } // Explicitly set position before adding to the scene drone.x = Math.random() < 0.5 ? -1024 : 3072; drone.y = 1366; // Store the current target index //drone.currentTargetIndex = currentTargetIndex; // Set the initial target to the current corner position drone.target = { x: 1024, y: 1366 }; // Add to container and array middlegroundContainer.addChild(drone); self.drones.push(drone); // This ensures all properties are set before tweening begins LK.setTimeout(function () { drone.init(); }, 100); }; }; /**** * Global variables ****/ var isDebug = true; var isDied = false; // Global flag to track if the knight has died var gameStarted = false; var droneManager = new DroneManager(); var backgroundContainer; var middlegroundContainer; var foregroundContainer; var knight; var background; // Declare a global variable for the background var target; var punchButton; var runSoundInterval; var borderOffset = 380; var corners = [{ x: borderOffset, y: borderOffset }, { x: 2048 - borderOffset, y: borderOffset }, { x: borderOffset, y: 2732 - borderOffset }, { x: 2048 - borderOffset, y: 2732 - borderOffset }]; function log() { if (isDebug) { console.log.apply(console, arguments); } } function initializeGame() { // Create containers backgroundContainer = new Container(); middlegroundContainer = new Container(); foregroundContainer = new Container(); // Add containers to game game.addChild(backgroundContainer); game.addChild(middlegroundContainer); game.addChild(foregroundContainer); // Initialize background background = new Background(); // Use Background class instead of LK.getAsset backgroundContainer.addChild(background); // Initialize room var room = new Room(); backgroundContainer.addChild(room); // Initialize knight knight = new Knight(); knight.x = 2048 / 2; knight.y = 2732 / 2; middlegroundContainer.addChild(knight); // Initialize target target = new Target(); target.x = knight.x; target.y = knight.y; foregroundContainer.addChild(target); // Initialize punch button punchButton = new ButtonPunch(); punchButton.x = 2048 - 220; punchButton.y = 220; foregroundContainer.addChild(punchButton); // Initialize sound runSoundInterval = LK.setInterval(playRunSound, 350); droneManager = new DroneManager(); LK.setTimeout(function () { gameStarted = true; droneManager.start(); }, 1000); } function playRunSound() { if (knight.isMoving) { LK.getSound('knight-run').play(); } } initializeGame();
===================================================================
--- original.js
+++ change.js
@@ -89,8 +89,22 @@
}
loopMove();
};
self.animMove();
+ self.moveToRandomCorner = function () {
+ var randomCorner = corners[Math.floor(Math.random() * corners.length)];
+ tween(self, {
+ x: randomCorner.x,
+ y: randomCorner.y
+ }, {
+ duration: 2000,
+ easing: tween.easeInOut,
+ onFinish: function onFinish() {
+ self.active = true; // Activate bonus after reaching the corner
+ }
+ });
+ };
+ self.moveToRandomCorner();
});
var ButtonPunch = Container.expand(function () {
var self = Container.call(this);
var buttonGraphics = LK.getAsset('buttonPunch', {