/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Enemy = Container.expand(function () { var self = Container.call(this); // Create enemy visual using enemy image asset var enemyBody = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5, scaleX: 4.0, scaleY: 4.0 }); // Create left leg var leftLeg = self.attachAsset('enemyLeg', { anchorX: 0.5, anchorY: 0, x: -80, y: 200 }); // Create right leg var rightLeg = self.attachAsset('enemyLeg', { anchorX: 0.5, anchorY: 0, x: 160, y: 200 }); // Create right hand var rightHand = self.attachAsset('enemyRightHand', { anchorX: 0.5, anchorY: 0.5, x: 140, y: -20, scaleX: 1.5, scaleY: 1.5 }); // Create left hand var leftHand = self.attachAsset('enemyLeftHand', { anchorX: 0.5, anchorY: 0.5, x: -70, y: -70, scaleX: 1.5, scaleY: 1.5 }); // Initialize animation timer for other effects self.animationTimer = 0; // Create enemy eyes var leftEnemyEye = self.attachAsset('eyeWhite', { anchorX: 0.5, anchorY: 0.5, x: 48, y: -150, scaleX: 0.4, scaleY: 0.4 }); var rightEnemyEye = self.attachAsset('eyeWhite', { anchorX: 0.5, anchorY: 0.5, x: 108, y: -150, scaleX: 0.4, scaleY: 0.4 }); // Create black pupils inside the enemy white eyes var leftEnemyPupil = self.attachAsset('eye', { anchorX: 0.5, anchorY: 0.5, x: 48, y: -150, scaleX: 0.6, scaleY: 0.6 }); var rightEnemyPupil = self.attachAsset('eye', { anchorX: 0.5, anchorY: 0.5, x: 108, y: -150, scaleX: 0.6, scaleY: 0.6 }); // Create enemy mouth var enemyMouth = self.attachAsset('enemyMouthImage', { anchorX: 0.5, anchorY: 0.5, x: 78, y: -100, scaleX: 1.2, scaleY: 1.2, visible: false // Initially hidden }); self.speed = 3; self.baseSpeed = 3; // Store original speed self.direction = 1; self.shootTimer = 0; self.speedChangeTimer = 0; // Timer for speed variations self.shootInterval = 30; // Shoot every 0.5 seconds at 60fps (increased spawn rate) self.walkAnimationTimer = 0; self.isFrozen = false; // Track if enemy is frozen after hitting player with second projectile self.freezeTimer = 0; // Timer for freeze duration self.update = function () { // Handle frozen state if (self.isFrozen) { self.freezeTimer--; if (self.freezeTimer <= 0) { self.isFrozen = false; } return; // Skip all movement and shooting when frozen } // Move horizontally self.x += self.speed * self.direction; // Bounce at screen edges if (self.x <= 100 || self.x >= 1948) { self.direction *= -1; } // Random direction change system - enemy can change direction at any time if (Math.random() < 0.008) { // 0.8% chance per frame to change direction self.direction *= -1; // Reverse current direction } // Random speed variation system self.speedChangeTimer++; if (self.speedChangeTimer >= 120) { // Every 2 seconds at 60fps self.speedChangeTimer = 0; // Randomly vary speed between 2 and 5 self.speed = self.baseSpeed + (Math.random() - 0.5) * 2; if (self.speed < 1) self.speed = 1; // Minimum speed if (self.speed > 6) self.speed = 6; // Maximum speed } // Walking animation - alternate leg positions self.walkAnimationTimer++; if (self.walkAnimationTimer >= 15) { // Change leg position every 15 frames self.walkAnimationTimer = 0; // Animate left leg with walking motion (horizontal and vertical) tween(leftLeg, { x: leftLeg.x === -80 ? -100 : -80, y: leftLeg.y === 200 ? 180 : 200 }, { duration: 200, easing: tween.easeInOut }); // Animate right leg with walking motion (opposite to left leg) tween(rightLeg, { x: rightLeg.x === 160 ? 180 : 160, y: rightLeg.y === 200 ? 180 : 200 }, { duration: 200, easing: tween.easeInOut }); } // Update enemy pupils to track player if (player) { // Calculate angle from enemy pupils to player var leftEyeCenterX = self.x + 48; var leftEyeCenterY = self.y - 150; var rightEyeCenterX = self.x + 108; var rightEyeCenterY = self.y - 150; // Maximum distance pupils can move from center var maxPupilDistance = 8; // Calculate angles from eye centers to player var leftAngle = Math.atan2(player.y - leftEyeCenterY, player.x - leftEyeCenterX); var rightAngle = Math.atan2(player.y - rightEyeCenterY, player.x - rightEyeCenterX); // Position pupils to track player within eye boundaries leftEnemyPupil.x = 48 + Math.cos(leftAngle) * maxPupilDistance; leftEnemyPupil.y = -150 + Math.sin(leftAngle) * maxPupilDistance; rightEnemyPupil.x = 108 + Math.cos(rightAngle) * maxPupilDistance; rightEnemyPupil.y = -150 + Math.sin(rightAngle) * maxPupilDistance; } // General animation timer for other effects self.animationTimer++; if (self.animationTimer >= 5) { self.animationTimer = 0; } // Shooting logic self.shootTimer++; if (self.shootTimer >= self.shootInterval) { self.shootTimer = 0; // Randomly choose projectile type with increased probability for second projectile if (Math.random() > 0.4) { // Create regular projectile var projectile = new EnemyProjectile(); projectile.x = self.x; projectile.y = self.y + 50; enemyProjectiles.push(projectile); game.addChild(projectile); } else { // Only create EnemyProjectile2 if there are less than 4 on screen if (enemyProjectiles2.length < 4) { // Create new projectile type from right arm area var projectile2 = new EnemyProjectile2(); projectile2.x = self.x + 140; // Position at right arm/hand area projectile2.y = self.y + 50; enemyProjectiles2.push(projectile2); game.addChild(projectile2); } } // Play enemy shooting sound LK.getSound('enemyShoot').play(); } }; // Method to show mouth when player is hit by second projectile self.showMouth = function () { enemyMouth.visible = true; // Play enemy mouth sound LK.getSound('enemyMouthSound').play(); // Hide mouth after 4 seconds using tween tween(enemyMouth, { alpha: 0 }, { duration: 4000, easing: tween.easeOut, onFinish: function onFinish() { enemyMouth.visible = false; enemyMouth.alpha = 1; // Reset alpha for next time } }); }; // Method to freeze enemy when player is hit by second projectile self.freezeEnemy = function () { self.isFrozen = true; self.freezeTimer = shieldDuration; // Freeze for same duration as shield (240 frames = 4 seconds) // Play enemy laughing sound when frozen LK.getSound('enemyLaugh').play(); // Add shaking animation while laughing tween(self, { x: self.x + 10 }, { duration: 150, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { x: self.x - 20 }, { duration: 150, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { x: self.x + 10 }, { duration: 150, easing: tween.easeInOut }); } }); } }); }; return self; }); var EnemyProjectile = Container.expand(function () { var self = Container.call(this); var projectileBody = self.attachAsset('enemyProjectile', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.0, scaleY: 2.0 }); self.speed = 6; self.update = function () { self.y += self.speed * gameSpeedMultiplier; }; return self; }); var EnemyProjectile2 = Container.expand(function () { var self = Container.call(this); var projectileBody = self.attachAsset('enemyProjectile2', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); self.speed = 4; self.sideSpeed = 2; self.direction = Math.random() > 0.5 ? 1 : -1; self.effectTimer = 0; self.update = function () { self.y += self.speed * gameSpeedMultiplier; self.x += self.sideSpeed * self.direction * gameSpeedMultiplier; // Bounce off screen edges if (self.x <= 0 || self.x >= 2048) { self.direction *= -1; } // Create flame and smoke effects self.effectTimer++; if (self.effectTimer >= 5) { self.effectTimer = 0; // Create flame particles if (Math.random() < 0.03) { var flameParticle = game.attachAsset('flame', { anchorX: 0.5, anchorY: 0.5, x: self.x + 35 + (Math.random() - 0.5) * 30, y: self.y - 50 + (Math.random() - 0.5) * 20, scaleX: 0.5 + Math.random() * 0.3, scaleY: 0.5 + Math.random() * 0.3, alpha: 0.8 + Math.random() * 0.2 }); // Animate flame trailing behind projectile tween(flameParticle, { y: flameParticle.y + 40 + Math.random() * 30, x: flameParticle.x + (Math.random() - 0.5) * 20, alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 300 + Math.random() * 200, easing: tween.easeOut, onFinish: function onFinish() { flameParticle.destroy(); } }); } // Create smoke particles if (Math.random() < 0.02) { var smokeParticle = game.attachAsset('smoke', { anchorX: 0.5, anchorY: 0.5, x: self.x + (Math.random() - 0.5) * 25, y: self.y + (Math.random() - 0.5) * 15, scaleX: 0.3 + Math.random() * 0.2, scaleY: 0.3 + Math.random() * 0.2, alpha: 0.6 }); // Animate smoke trailing and dispersing tween(smokeParticle, { y: smokeParticle.y + 50 + Math.random() * 25, x: smokeParticle.x + (Math.random() - 0.5) * 15, alpha: 0, scaleX: 0.8 + Math.random() * 0.4, scaleY: 0.8 + Math.random() * 0.4 }, { duration: 400 + Math.random() * 300, easing: tween.easeOut, onFinish: function onFinish() { smokeParticle.destroy(); } }); } // Create additional particle effects if (Math.random() < 0.01) { var projectileParticle = new Particle(); projectileParticle.x = self.x + (Math.random() - 0.5) * 40; projectileParticle.y = self.y - 10 + (Math.random() - 0.5) * 15; projectileParticle.velocityX = (Math.random() - 0.5) * 6; projectileParticle.velocityY = -Math.random() * 4 - 2; particles.push(projectileParticle); game.addChild(projectileParticle); } } }; return self; }); var Particle = Container.expand(function () { var self = Container.call(this); // Choose random particle color/type var particleTypes = ['redParticle', 'orangeParticle', 'yellowParticle', 'whiteParticle', 'smoke']; var randomType = particleTypes[Math.floor(Math.random() * particleTypes.length)]; var particleBody = self.attachAsset(randomType, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3 + Math.random() * 0.6, scaleY: 0.3 + Math.random() * 0.6 }); // Random particle properties self.velocityX = (Math.random() - 0.5) * 8; self.velocityY = -Math.random() * 6 - 2; self.gravity = 0.2; self.life = 90 + Math.random() * 60; // 1.5-2.5 seconds at 60fps self.maxLife = self.life; self.update = function () { // Apply physics self.x += self.velocityX; self.y += self.velocityY; self.velocityY += self.gravity; // Fade out over time self.life--; self.alpha = self.life / self.maxLife; // Remove when life is over or off screen if (self.life <= 0 || self.y > 2732 + 100 || self.y < -100 || self.x < -100 || self.x > 2148) { self.destroy(); // Remove from particles array for (var p = particles.length - 1; p >= 0; p--) { if (particles[p] === self) { particles.splice(p, 1); break; } } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x8B4513 }); /**** * Game Code ****/ var backgroundImage = game.attachAsset('background', { x: 0, y: 0, width: 2048, height: 2732 }); // Add new background layer var backgroundLayer = game.attachAsset('backgroundLayer', { x: 0, y: 0, width: 2100, height: 700 }); // Create ground terrain var ground = game.attachAsset('ground', { x: 0, y: 2682, // Position at bottom (2732 - 50 = 2682) width: 2048, height: 50 }); // Create and position player on the ground var player = game.attachAsset('player', { x: 2048 / 2, // Center horizontally y: 2682, // Position touching the ground scaleX: 1.0, scaleY: 1.0, anchorX: 0.5, anchorY: 1.0 }); // Scale player to 3.0 using tween animation tween(player, { scaleX: 3.0, scaleY: 3.0 }, { duration: 500, easing: tween.easeOut }); // Create white eyes on the player var leftEye = game.attachAsset('eyeWhite', { x: player.x - 50, y: player.y - 245, anchorX: 0.5, anchorY: 0.5 }); var rightEye = game.attachAsset('eyeWhite', { x: player.x + 10, y: player.y - 245, anchorX: 0.5, anchorY: 0.5 }); // Create black pupils inside the white eyes var leftPupil = game.attachAsset('eye', { x: player.x - 50, y: player.y - 245, anchorX: 0.5, anchorY: 0.5 }); var rightPupil = game.attachAsset('eye', { x: player.x + 10, y: player.y - 245, anchorX: 0.5, anchorY: 0.5 }); // Create player feet var leftFoot = game.attachAsset('playerLeftFoot', { x: player.x - 80, y: player.y + 10, anchorX: 0.5, anchorY: 0.5, scaleX: 2.0, scaleY: 2.0 }); var rightFoot = game.attachAsset('playerRightFoot', { x: player.x + 80, y: player.y + 10, anchorX: 0.5, anchorY: 0.5, scaleX: 2.0, scaleY: 2.0 }); // Create player right hand var playerRightHand = game.attachAsset('playerRightHand', { x: player.x + 120, y: player.y - 120, anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); // Variables for player movement var playerSpeed = 12; var targetX = player.x; var isMoving = false; var playerLives = 3; var isShielded = false; var shieldTimer = 0; var shieldDuration = 240; // 4 seconds at 60fps var isFlying = false; // Track if player is currently flying after being hit var shieldBubble = null; // Shield bubble visual element var walkAnimationTimer = 0; // Timer for walking animation // Game speed system var gameSpeedMultiplier = 1.0; var speedIncreaseTimer = 0; var speedIncreaseInterval = 600; // Increase speed every 10 seconds at 60fps // Create life hearts on the left side var lifeHearts = []; for (var h = 0; h < 3; h++) { // Create heart using image asset var heartImage = game.attachAsset('lifeHeartImage', { x: 150 + h * 100, y: 750, anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0, alpha: 1.0 }); lifeHearts.push(heartImage); } // Create score display var scoreText = new Text2('PUAN: 0', { size: 120, fill: 0xFFFFFF, font: "'Montserrat', 'Open Sans', 'Lato', 'Source Sans Pro', 'Ubuntu', sans-serif" }); scoreText.anchor.set(0.5, 0); scoreText.x = 2048 / 2; scoreText.y = 850; game.addChild(scoreText); // Enemy and projectile tracking var enemy = null; var enemyProjectiles = []; var enemyProjectiles2 = []; var particles = []; // Create enemy at top of screen enemy = game.addChild(new Enemy()); enemy.x = 1124; // Move slightly to the right enemy.y = 450; // Moved up from previous position // Touch/mouse controls for player movement game.down = function (x, y, obj) { // Set target position to touch/click location targetX = x; isMoving = true; // Keep player within screen bounds if (targetX < 0) targetX = 0; if (targetX > 2048) targetX = 2048; }; // Update player movement game.update = function () { // Update game speed system speedIncreaseTimer++; if (speedIncreaseTimer >= speedIncreaseInterval) { speedIncreaseTimer = 0; gameSpeedMultiplier += 0.1; // Increase speed by 10% every 10 seconds // Cap maximum speed at 3x original speed if (gameSpeedMultiplier > 3.0) { gameSpeedMultiplier = 3.0; } } if (isMoving) { // Calculate distance to target var distance = targetX - player.x; // Move towards target if (Math.abs(distance) > 5) { if (distance > 0) { player.x += playerSpeed; } else { player.x -= playerSpeed; } // Animate walking - move feet up and down alternately walkAnimationTimer++; if (walkAnimationTimer >= 10) { walkAnimationTimer = 0; // Animate left foot up and down tween(leftFoot, { y: leftFoot.y === player.y + 10 ? player.y - 10 : player.y + 10 }, { duration: 150, easing: tween.easeInOut }); // Animate right foot up and down (opposite to left foot) tween(rightFoot, { y: rightFoot.y === player.y + 10 ? player.y - 10 : player.y + 10 }, { duration: 150, easing: tween.easeInOut }); } } else { // Snap to target when close enough player.x = targetX; isMoving = false; } // Keep player within bounds if (player.x < 0) player.x = 0; if (player.x > 2048) player.x = 2048; } // Update feet positions to follow player leftFoot.x = player.x - 80; rightFoot.x = player.x + 80; // Update right hand position to follow player playerRightHand.x = player.x + 120; playerRightHand.y = player.y - 120; // Reset feet position when not moving if (!isMoving) { leftFoot.y = player.y + 10; rightFoot.y = player.y + 10; } // Update shield system if (isShielded) { shieldTimer--; // Hide player right hand when shield is active playerRightHand.visible = false; // Show shield bubble if not already visible if (!shieldBubble) { shieldBubble = game.attachAsset('shieldBubble', { x: player.x, y: player.y - 150, anchorX: 0.5, anchorY: 0.5, alpha: 0.1, tint: 0xffffff }); // Add pulsing animation to shield bubble tween(shieldBubble, { scaleX: 1.1, scaleY: 1.1, alpha: 0.2 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { if (shieldBubble) { tween(shieldBubble, { scaleX: 1.0, scaleY: 1.0, alpha: 0.05 }, { duration: 500, easing: tween.easeInOut }); } } }); } // Update shield bubble position to follow player if (shieldBubble) { shieldBubble.x = player.x; shieldBubble.y = player.y - 150; } // Flash player blue to indicate shield if (shieldTimer % 20 < 10) { player.tint = 0x00ffff; } else { player.tint = 0xffffff; } // Deactivate shield when timer expires if (shieldTimer <= 0) { isShielded = false; player.tint = 0xffffff; // Show player right hand when shield is deactivated playerRightHand.visible = true; // Stop pupil spinning and reset rotation tween.stop(leftPupil, { rotation: true }); tween.stop(rightPupil, { rotation: true }); leftPupil.rotation = 0; rightPupil.rotation = 0; // Remove shield bubble if (shieldBubble) { shieldBubble.destroy(); shieldBubble = null; } // Clear shield sound interval if (game.shieldSoundInterval) { LK.clearInterval(game.shieldSoundInterval); game.shieldSoundInterval = null; } } } // Update eye positions to follow player leftEye.x = player.x - 50; leftEye.y = player.y - 245; rightEye.x = player.x + 10; rightEye.y = player.y - 245; // Keep pupils centered when not shielded, but track falling projectiles if (!isShielded) { // Default pupil positions (eye centers) var leftEyeCenterX = player.x - 50; var leftEyeCenterY = player.y - 245; var rightEyeCenterX = player.x + 10; var rightEyeCenterY = player.y - 245; // Maximum distance pupils can move from center var maxPupilDistance = 8; // Find closest falling projectile to track var closestProjectile = null; var closestDistance = Infinity; // Check all enemy projectiles for (var p = 0; p < enemyProjectiles.length; p++) { var proj = enemyProjectiles[p]; var distance = Math.sqrt(Math.pow(proj.x - player.x, 2) + Math.pow(proj.y - player.y, 2)); if (distance < closestDistance) { closestDistance = distance; closestProjectile = proj; } } // Check all enemy projectiles type 2 for (var p2 = 0; p2 < enemyProjectiles2.length; p2++) { var proj2 = enemyProjectiles2[p2]; var distance2 = Math.sqrt(Math.pow(proj2.x - player.x, 2) + Math.pow(proj2.y - player.y, 2)); if (distance2 < closestDistance) { closestDistance = distance2; closestProjectile = proj2; } } if (closestProjectile) { // Calculate angles from eye centers to the closest projectile var leftAngle = Math.atan2(closestProjectile.y - leftEyeCenterY, closestProjectile.x - leftEyeCenterX); var rightAngle = Math.atan2(closestProjectile.y - rightEyeCenterY, closestProjectile.x - rightEyeCenterX); // Position pupils within eye boundaries, tracking the projectile leftPupil.x = leftEyeCenterX + Math.cos(leftAngle) * maxPupilDistance; leftPupil.y = leftEyeCenterY + Math.sin(leftAngle) * maxPupilDistance; rightPupil.x = rightEyeCenterX + Math.cos(rightAngle) * maxPupilDistance; rightPupil.y = rightEyeCenterY + Math.sin(rightAngle) * maxPupilDistance; } else { // No projectiles to track, center pupils leftPupil.x = leftEyeCenterX; leftPupil.y = leftEyeCenterY; rightPupil.x = rightEyeCenterX; rightPupil.y = rightEyeCenterY; } } else { // When shield is active, make pupils move diagonally (down-left and diagonally) var leftEyeCenterX = player.x - 50; var leftEyeCenterY = player.y - 245; var rightEyeCenterX = player.x + 10; var rightEyeCenterY = player.y - 245; var maxBounceDistance = 12; // Use diagonal movement patterns based on time var bounceTime = LK.ticks * 0.12; // Create diagonal movements: down-left and cross-diagonal var bounceX = Math.sin(bounceTime) * maxBounceDistance; var bounceY = Math.cos(bounceTime * 0.8) * (maxBounceDistance * 0.7); // Position pupils with diagonal movement patterns leftPupil.x = leftEyeCenterX + bounceX; leftPupil.y = leftEyeCenterY + bounceY; rightPupil.x = rightEyeCenterX - bounceX; // Opposite X movement for variety rightPupil.y = rightEyeCenterY + bounceY; } // Update enemy projectiles for (var i = enemyProjectiles.length - 1; i >= 0; i--) { var projectile = enemyProjectiles[i]; // Remove projectiles that go off screen (any direction) if (projectile.y > 2732 + 100 || projectile.y < -100 || projectile.x < -100 || projectile.x > 2148) { projectile.destroy(); enemyProjectiles.splice(i, 1); continue; } // Check collision with player if (projectile.intersects(player)) { // Check if player is protected by shield if (!isShielded) { // Award points when hit by enemy projectile LK.setScore(LK.getScore() + 10); // Update score display scoreText.setText('PUAN: ' + LK.getScore()); // Play sound effect for first projectile hit LK.getSound('enemyProjectileHit').play(); // Create reduced particle burst effect at player's mouth area for (var particleCount = 0; particleCount < 1; particleCount++) { var particle = new Particle(); particle.x = player.x + (Math.random() - 0.5) * 40; particle.y = player.y - 130 + (Math.random() - 0.5) * 30; // Position higher up from mouth area // Reduce particle velocity for better performance particle.velocityX = (Math.random() - 0.5) * 10; particle.velocityY = -Math.random() * 8 - 3; particles.push(particle); game.addChild(particle); } // Simplified mouth trembling effect tween(player, { scaleX: 3.2, scaleY: 2.8 }, { duration: 150, easing: tween.easeInOut, onFinish: function onFinish() { tween(player, { scaleX: 3.0, scaleY: 3.0 }, { duration: 150, easing: tween.easeOut }); } }); } projectile.destroy(); enemyProjectiles.splice(i, 1); } } // Update enemy projectiles type 2 for (var j = enemyProjectiles2.length - 1; j >= 0; j--) { var projectile2 = enemyProjectiles2[j]; // Remove projectiles that go off screen (any direction) if (projectile2.y > 2732 + 100 || projectile2.y < -100 || projectile2.x < -100 || projectile2.x > 2148) { projectile2.destroy(); enemyProjectiles2.splice(j, 1); continue; } // Check collision with player if (projectile2.intersects(player) && !isShielded && !isFlying) { // Show enemy mouth when hit by second projectile enemy.showMouth(); // Freeze enemy movement and shooting enemy.freezeEnemy(); // Play sound effect for second projectile hit LK.getSound('enemyProjectile2Hit').play(); // Stop current player movement isMoving = false; // Set flying state to true isFlying = true; // Player flies off screen to the left while spinning tween(player, { x: -200, y: player.y - 800, rotation: Math.PI * 4 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { // Return player from right side after flying off player.x = 2248; player.y = 2682; player.rotation = 0; // Reset flying state isFlying = false; // Activate shield protection isShielded = true; shieldTimer = shieldDuration; // Play shield activation sound LK.getSound('shieldSound').play(); // Set up repeating shield sound during shield duration var shieldSoundInterval = LK.setInterval(function () { if (isShielded && shieldTimer > 0) { LK.getSound('shieldSound').play(); } }, 1750); // Play every 1750ms // Store interval reference for cleanup game.shieldSoundInterval = shieldSoundInterval; // Shield bubble will be created in the shield update section // Animate player returning to screen tween(player, { x: 2048 / 2 }, { duration: 800, easing: tween.easeOut }); } }); // Update feet positions during flight animation tween(leftFoot, { x: -330, y: player.y - 790 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { leftFoot.x = 2168; leftFoot.y = 2692; tween(leftFoot, { x: 2048 / 2 - 80 }, { duration: 800, easing: tween.easeOut }); } }); tween(rightFoot, { x: -120, y: player.y - 790 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { rightFoot.x = 2128; rightFoot.y = 2692; tween(rightFoot, { x: 2048 / 2 + 80 }, { duration: 800, easing: tween.easeOut }); } }); // Update eye positions during flight animation tween(leftEye, { x: -250, y: player.y - 1045 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { leftEye.x = 2198; leftEye.y = 2437; tween(leftEye, { x: 2048 / 2 - 50 }, { duration: 800, easing: tween.easeOut }); } }); tween(rightEye, { x: -190, y: player.y - 1045 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { rightEye.x = 2258; rightEye.y = 2437; tween(rightEye, { x: 2048 / 2 + 10 }, { duration: 800, easing: tween.easeOut }); } }); tween(leftPupil, { x: -250, y: player.y - 1045 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { leftPupil.x = 2198; leftPupil.y = 2437; tween(leftPupil, { x: 2048 / 2 - 50 }, { duration: 800, easing: tween.easeOut }); } }); tween(rightPupil, { x: -190, y: player.y - 1045 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { rightPupil.x = 2258; rightPupil.y = 2437; tween(rightPupil, { x: 2048 / 2 + 10 }, { duration: 800, easing: tween.easeOut }); } }); // Update right hand position during flight animation tween(playerRightHand, { x: -80, y: player.y - 920 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { playerRightHand.x = 2368; playerRightHand.y = 2562; tween(playerRightHand, { x: 2048 / 2 + 120 }, { duration: 800, easing: tween.easeOut }); } }); // Create particle burst effect for (var particleCount = 0; particleCount < 5; particleCount++) { var particle = new Particle(); particle.x = player.x + (Math.random() - 0.5) * 80; particle.y = player.y - 50 + (Math.random() - 0.5) * 70; // Give particles more dramatic velocities for this bigger explosion particle.velocityX = (Math.random() - 0.5) * 18; particle.velocityY = -Math.random() * 12 - 4; particles.push(particle); game.addChild(particle); } // Create smoke and flame effects for (var smokeCount = 0; smokeCount < 2; smokeCount++) { var smoke = game.attachAsset('smoke', { x: player.x + (Math.random() - 0.5) * 200, y: player.y - 100 + (Math.random() - 0.5) * 100, anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); // Animate smoke rising and fading tween(smoke, { y: smoke.y - 200 - Math.random() * 100, alpha: 0, scaleX: 2 + Math.random(), scaleY: 2 + Math.random() }, { duration: 2000 + Math.random() * 1000, easing: tween.easeOut, onFinish: function onFinish() { smoke.destroy(); } }); } for (var flameCount = 0; flameCount < 1; flameCount++) { var flame = game.attachAsset('flame', { x: player.x + (Math.random() - 0.5) * 150, y: player.y - 50 + (Math.random() - 0.5) * 80, anchorX: 0.5, anchorY: 0.5, alpha: 1 }); // Animate flames flickering and rising tween(flame, { y: flame.y - 150 - Math.random() * 50, alpha: 0, scaleX: 1.5 + Math.random() * 0.5, scaleY: 1.5 + Math.random() * 0.5 }, { duration: 1500 + Math.random() * 500, easing: tween.easeOut, onFinish: function onFinish() { flame.destroy(); } }); } // Create fire animation effect on player tween(player, { tint: 0xff4500 }, { duration: 200, easing: tween.easeInOut, onFinish: function onFinish() { tween(player, { tint: 0xff0000 }, { duration: 200, easing: tween.easeInOut, onFinish: function onFinish() { tween(player, { tint: 0xffffff }, { duration: 300, easing: tween.easeOut }); } }); } }); // Reduce player lives playerLives--; // Update heart visibility based on remaining lives for (var heartIndex = 0; heartIndex < lifeHearts.length; heartIndex++) { if (heartIndex >= playerLives) { // Hide heart with fade out animation tween(lifeHearts[heartIndex], { alpha: 0.2, scaleX: 0.5, scaleY: 0.5 }, { duration: 300, easing: tween.easeOut }); } } if (playerLives <= 0) { // Show game over when no lives left LK.showGameOver(); } projectile2.destroy(); enemyProjectiles2.splice(j, 1); } } // Comprehensive cleanup system - remove all off-screen elements every frame var allChildren = game.children.slice(); // Create a copy to avoid modification during iteration var screenBuffer = 100; // Buffer zone around visible area for (var c = 0; c < allChildren.length; c++) { var child = allChildren[c]; // Skip essential game elements that should always stay if (child === player || child === enemy || child === backgroundImage || child === backgroundLayer || child === ground || child === scoreText || child === leftEye || child === rightEye || child === leftPupil || child === rightPupil || child === leftFoot || child === rightFoot || child === playerRightHand || child === shieldBubble) { continue; } // Skip life hearts var isLifeHeart = false; for (var h = 0; h < lifeHearts.length; h++) { if (child === lifeHearts[h]) { isLifeHeart = true; break; } } if (isLifeHeart) { continue; } // Remove if off screen in any direction with buffer zone if (child.x < -screenBuffer || child.x > 2048 + screenBuffer || child.y < -screenBuffer || child.y > 2732 + screenBuffer) { child.destroy(); } } // Clean up particle arrays - remove destroyed particles for (var p = particles.length - 1; p >= 0; p--) { if (!particles[p] || particles[p].destroyed) { particles.splice(p, 1); } } // Clean up projectile arrays - ensure no destroyed projectiles remain for (var ep = enemyProjectiles.length - 1; ep >= 0; ep--) { if (!enemyProjectiles[ep] || enemyProjectiles[ep].destroyed) { enemyProjectiles.splice(ep, 1); } } for (var ep2 = enemyProjectiles2.length - 1; ep2 >= 0; ep2--) { if (!enemyProjectiles2[ep2] || enemyProjectiles2[ep2].destroyed) { enemyProjectiles2.splice(ep2, 1); } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Enemy = Container.expand(function () {
var self = Container.call(this);
// Create enemy visual using enemy image asset
var enemyBody = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4.0,
scaleY: 4.0
});
// Create left leg
var leftLeg = self.attachAsset('enemyLeg', {
anchorX: 0.5,
anchorY: 0,
x: -80,
y: 200
});
// Create right leg
var rightLeg = self.attachAsset('enemyLeg', {
anchorX: 0.5,
anchorY: 0,
x: 160,
y: 200
});
// Create right hand
var rightHand = self.attachAsset('enemyRightHand', {
anchorX: 0.5,
anchorY: 0.5,
x: 140,
y: -20,
scaleX: 1.5,
scaleY: 1.5
});
// Create left hand
var leftHand = self.attachAsset('enemyLeftHand', {
anchorX: 0.5,
anchorY: 0.5,
x: -70,
y: -70,
scaleX: 1.5,
scaleY: 1.5
});
// Initialize animation timer for other effects
self.animationTimer = 0;
// Create enemy eyes
var leftEnemyEye = self.attachAsset('eyeWhite', {
anchorX: 0.5,
anchorY: 0.5,
x: 48,
y: -150,
scaleX: 0.4,
scaleY: 0.4
});
var rightEnemyEye = self.attachAsset('eyeWhite', {
anchorX: 0.5,
anchorY: 0.5,
x: 108,
y: -150,
scaleX: 0.4,
scaleY: 0.4
});
// Create black pupils inside the enemy white eyes
var leftEnemyPupil = self.attachAsset('eye', {
anchorX: 0.5,
anchorY: 0.5,
x: 48,
y: -150,
scaleX: 0.6,
scaleY: 0.6
});
var rightEnemyPupil = self.attachAsset('eye', {
anchorX: 0.5,
anchorY: 0.5,
x: 108,
y: -150,
scaleX: 0.6,
scaleY: 0.6
});
// Create enemy mouth
var enemyMouth = self.attachAsset('enemyMouthImage', {
anchorX: 0.5,
anchorY: 0.5,
x: 78,
y: -100,
scaleX: 1.2,
scaleY: 1.2,
visible: false // Initially hidden
});
self.speed = 3;
self.baseSpeed = 3; // Store original speed
self.direction = 1;
self.shootTimer = 0;
self.speedChangeTimer = 0; // Timer for speed variations
self.shootInterval = 30; // Shoot every 0.5 seconds at 60fps (increased spawn rate)
self.walkAnimationTimer = 0;
self.isFrozen = false; // Track if enemy is frozen after hitting player with second projectile
self.freezeTimer = 0; // Timer for freeze duration
self.update = function () {
// Handle frozen state
if (self.isFrozen) {
self.freezeTimer--;
if (self.freezeTimer <= 0) {
self.isFrozen = false;
}
return; // Skip all movement and shooting when frozen
}
// Move horizontally
self.x += self.speed * self.direction;
// Bounce at screen edges
if (self.x <= 100 || self.x >= 1948) {
self.direction *= -1;
}
// Random direction change system - enemy can change direction at any time
if (Math.random() < 0.008) {
// 0.8% chance per frame to change direction
self.direction *= -1; // Reverse current direction
}
// Random speed variation system
self.speedChangeTimer++;
if (self.speedChangeTimer >= 120) {
// Every 2 seconds at 60fps
self.speedChangeTimer = 0;
// Randomly vary speed between 2 and 5
self.speed = self.baseSpeed + (Math.random() - 0.5) * 2;
if (self.speed < 1) self.speed = 1; // Minimum speed
if (self.speed > 6) self.speed = 6; // Maximum speed
}
// Walking animation - alternate leg positions
self.walkAnimationTimer++;
if (self.walkAnimationTimer >= 15) {
// Change leg position every 15 frames
self.walkAnimationTimer = 0;
// Animate left leg with walking motion (horizontal and vertical)
tween(leftLeg, {
x: leftLeg.x === -80 ? -100 : -80,
y: leftLeg.y === 200 ? 180 : 200
}, {
duration: 200,
easing: tween.easeInOut
});
// Animate right leg with walking motion (opposite to left leg)
tween(rightLeg, {
x: rightLeg.x === 160 ? 180 : 160,
y: rightLeg.y === 200 ? 180 : 200
}, {
duration: 200,
easing: tween.easeInOut
});
}
// Update enemy pupils to track player
if (player) {
// Calculate angle from enemy pupils to player
var leftEyeCenterX = self.x + 48;
var leftEyeCenterY = self.y - 150;
var rightEyeCenterX = self.x + 108;
var rightEyeCenterY = self.y - 150;
// Maximum distance pupils can move from center
var maxPupilDistance = 8;
// Calculate angles from eye centers to player
var leftAngle = Math.atan2(player.y - leftEyeCenterY, player.x - leftEyeCenterX);
var rightAngle = Math.atan2(player.y - rightEyeCenterY, player.x - rightEyeCenterX);
// Position pupils to track player within eye boundaries
leftEnemyPupil.x = 48 + Math.cos(leftAngle) * maxPupilDistance;
leftEnemyPupil.y = -150 + Math.sin(leftAngle) * maxPupilDistance;
rightEnemyPupil.x = 108 + Math.cos(rightAngle) * maxPupilDistance;
rightEnemyPupil.y = -150 + Math.sin(rightAngle) * maxPupilDistance;
}
// General animation timer for other effects
self.animationTimer++;
if (self.animationTimer >= 5) {
self.animationTimer = 0;
}
// Shooting logic
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shootTimer = 0;
// Randomly choose projectile type with increased probability for second projectile
if (Math.random() > 0.4) {
// Create regular projectile
var projectile = new EnemyProjectile();
projectile.x = self.x;
projectile.y = self.y + 50;
enemyProjectiles.push(projectile);
game.addChild(projectile);
} else {
// Only create EnemyProjectile2 if there are less than 4 on screen
if (enemyProjectiles2.length < 4) {
// Create new projectile type from right arm area
var projectile2 = new EnemyProjectile2();
projectile2.x = self.x + 140; // Position at right arm/hand area
projectile2.y = self.y + 50;
enemyProjectiles2.push(projectile2);
game.addChild(projectile2);
}
}
// Play enemy shooting sound
LK.getSound('enemyShoot').play();
}
};
// Method to show mouth when player is hit by second projectile
self.showMouth = function () {
enemyMouth.visible = true;
// Play enemy mouth sound
LK.getSound('enemyMouthSound').play();
// Hide mouth after 4 seconds using tween
tween(enemyMouth, {
alpha: 0
}, {
duration: 4000,
easing: tween.easeOut,
onFinish: function onFinish() {
enemyMouth.visible = false;
enemyMouth.alpha = 1; // Reset alpha for next time
}
});
};
// Method to freeze enemy when player is hit by second projectile
self.freezeEnemy = function () {
self.isFrozen = true;
self.freezeTimer = shieldDuration; // Freeze for same duration as shield (240 frames = 4 seconds)
// Play enemy laughing sound when frozen
LK.getSound('enemyLaugh').play();
// Add shaking animation while laughing
tween(self, {
x: self.x + 10
}, {
duration: 150,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
x: self.x - 20
}, {
duration: 150,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
x: self.x + 10
}, {
duration: 150,
easing: tween.easeInOut
});
}
});
}
});
};
return self;
});
var EnemyProjectile = Container.expand(function () {
var self = Container.call(this);
var projectileBody = self.attachAsset('enemyProjectile', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
});
self.speed = 6;
self.update = function () {
self.y += self.speed * gameSpeedMultiplier;
};
return self;
});
var EnemyProjectile2 = Container.expand(function () {
var self = Container.call(this);
var projectileBody = self.attachAsset('enemyProjectile2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.speed = 4;
self.sideSpeed = 2;
self.direction = Math.random() > 0.5 ? 1 : -1;
self.effectTimer = 0;
self.update = function () {
self.y += self.speed * gameSpeedMultiplier;
self.x += self.sideSpeed * self.direction * gameSpeedMultiplier;
// Bounce off screen edges
if (self.x <= 0 || self.x >= 2048) {
self.direction *= -1;
}
// Create flame and smoke effects
self.effectTimer++;
if (self.effectTimer >= 5) {
self.effectTimer = 0;
// Create flame particles
if (Math.random() < 0.03) {
var flameParticle = game.attachAsset('flame', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x + 35 + (Math.random() - 0.5) * 30,
y: self.y - 50 + (Math.random() - 0.5) * 20,
scaleX: 0.5 + Math.random() * 0.3,
scaleY: 0.5 + Math.random() * 0.3,
alpha: 0.8 + Math.random() * 0.2
});
// Animate flame trailing behind projectile
tween(flameParticle, {
y: flameParticle.y + 40 + Math.random() * 30,
x: flameParticle.x + (Math.random() - 0.5) * 20,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300 + Math.random() * 200,
easing: tween.easeOut,
onFinish: function onFinish() {
flameParticle.destroy();
}
});
}
// Create smoke particles
if (Math.random() < 0.02) {
var smokeParticle = game.attachAsset('smoke', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x + (Math.random() - 0.5) * 25,
y: self.y + (Math.random() - 0.5) * 15,
scaleX: 0.3 + Math.random() * 0.2,
scaleY: 0.3 + Math.random() * 0.2,
alpha: 0.6
});
// Animate smoke trailing and dispersing
tween(smokeParticle, {
y: smokeParticle.y + 50 + Math.random() * 25,
x: smokeParticle.x + (Math.random() - 0.5) * 15,
alpha: 0,
scaleX: 0.8 + Math.random() * 0.4,
scaleY: 0.8 + Math.random() * 0.4
}, {
duration: 400 + Math.random() * 300,
easing: tween.easeOut,
onFinish: function onFinish() {
smokeParticle.destroy();
}
});
}
// Create additional particle effects
if (Math.random() < 0.01) {
var projectileParticle = new Particle();
projectileParticle.x = self.x + (Math.random() - 0.5) * 40;
projectileParticle.y = self.y - 10 + (Math.random() - 0.5) * 15;
projectileParticle.velocityX = (Math.random() - 0.5) * 6;
projectileParticle.velocityY = -Math.random() * 4 - 2;
particles.push(projectileParticle);
game.addChild(projectileParticle);
}
}
};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
// Choose random particle color/type
var particleTypes = ['redParticle', 'orangeParticle', 'yellowParticle', 'whiteParticle', 'smoke'];
var randomType = particleTypes[Math.floor(Math.random() * particleTypes.length)];
var particleBody = self.attachAsset(randomType, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3 + Math.random() * 0.6,
scaleY: 0.3 + Math.random() * 0.6
});
// Random particle properties
self.velocityX = (Math.random() - 0.5) * 8;
self.velocityY = -Math.random() * 6 - 2;
self.gravity = 0.2;
self.life = 90 + Math.random() * 60; // 1.5-2.5 seconds at 60fps
self.maxLife = self.life;
self.update = function () {
// Apply physics
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityY += self.gravity;
// Fade out over time
self.life--;
self.alpha = self.life / self.maxLife;
// Remove when life is over or off screen
if (self.life <= 0 || self.y > 2732 + 100 || self.y < -100 || self.x < -100 || self.x > 2148) {
self.destroy();
// Remove from particles array
for (var p = particles.length - 1; p >= 0; p--) {
if (particles[p] === self) {
particles.splice(p, 1);
break;
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x8B4513
});
/****
* Game Code
****/
var backgroundImage = game.attachAsset('background', {
x: 0,
y: 0,
width: 2048,
height: 2732
});
// Add new background layer
var backgroundLayer = game.attachAsset('backgroundLayer', {
x: 0,
y: 0,
width: 2100,
height: 700
});
// Create ground terrain
var ground = game.attachAsset('ground', {
x: 0,
y: 2682,
// Position at bottom (2732 - 50 = 2682)
width: 2048,
height: 50
});
// Create and position player on the ground
var player = game.attachAsset('player', {
x: 2048 / 2,
// Center horizontally
y: 2682,
// Position touching the ground
scaleX: 1.0,
scaleY: 1.0,
anchorX: 0.5,
anchorY: 1.0
});
// Scale player to 3.0 using tween animation
tween(player, {
scaleX: 3.0,
scaleY: 3.0
}, {
duration: 500,
easing: tween.easeOut
});
// Create white eyes on the player
var leftEye = game.attachAsset('eyeWhite', {
x: player.x - 50,
y: player.y - 245,
anchorX: 0.5,
anchorY: 0.5
});
var rightEye = game.attachAsset('eyeWhite', {
x: player.x + 10,
y: player.y - 245,
anchorX: 0.5,
anchorY: 0.5
});
// Create black pupils inside the white eyes
var leftPupil = game.attachAsset('eye', {
x: player.x - 50,
y: player.y - 245,
anchorX: 0.5,
anchorY: 0.5
});
var rightPupil = game.attachAsset('eye', {
x: player.x + 10,
y: player.y - 245,
anchorX: 0.5,
anchorY: 0.5
});
// Create player feet
var leftFoot = game.attachAsset('playerLeftFoot', {
x: player.x - 80,
y: player.y + 10,
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
});
var rightFoot = game.attachAsset('playerRightFoot', {
x: player.x + 80,
y: player.y + 10,
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
});
// Create player right hand
var playerRightHand = game.attachAsset('playerRightHand', {
x: player.x + 120,
y: player.y - 120,
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
// Variables for player movement
var playerSpeed = 12;
var targetX = player.x;
var isMoving = false;
var playerLives = 3;
var isShielded = false;
var shieldTimer = 0;
var shieldDuration = 240; // 4 seconds at 60fps
var isFlying = false; // Track if player is currently flying after being hit
var shieldBubble = null; // Shield bubble visual element
var walkAnimationTimer = 0; // Timer for walking animation
// Game speed system
var gameSpeedMultiplier = 1.0;
var speedIncreaseTimer = 0;
var speedIncreaseInterval = 600; // Increase speed every 10 seconds at 60fps
// Create life hearts on the left side
var lifeHearts = [];
for (var h = 0; h < 3; h++) {
// Create heart using image asset
var heartImage = game.attachAsset('lifeHeartImage', {
x: 150 + h * 100,
y: 750,
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
alpha: 1.0
});
lifeHearts.push(heartImage);
}
// Create score display
var scoreText = new Text2('PUAN: 0', {
size: 120,
fill: 0xFFFFFF,
font: "'Montserrat', 'Open Sans', 'Lato', 'Source Sans Pro', 'Ubuntu', sans-serif"
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 2048 / 2;
scoreText.y = 850;
game.addChild(scoreText);
// Enemy and projectile tracking
var enemy = null;
var enemyProjectiles = [];
var enemyProjectiles2 = [];
var particles = [];
// Create enemy at top of screen
enemy = game.addChild(new Enemy());
enemy.x = 1124; // Move slightly to the right
enemy.y = 450; // Moved up from previous position
// Touch/mouse controls for player movement
game.down = function (x, y, obj) {
// Set target position to touch/click location
targetX = x;
isMoving = true;
// Keep player within screen bounds
if (targetX < 0) targetX = 0;
if (targetX > 2048) targetX = 2048;
};
// Update player movement
game.update = function () {
// Update game speed system
speedIncreaseTimer++;
if (speedIncreaseTimer >= speedIncreaseInterval) {
speedIncreaseTimer = 0;
gameSpeedMultiplier += 0.1; // Increase speed by 10% every 10 seconds
// Cap maximum speed at 3x original speed
if (gameSpeedMultiplier > 3.0) {
gameSpeedMultiplier = 3.0;
}
}
if (isMoving) {
// Calculate distance to target
var distance = targetX - player.x;
// Move towards target
if (Math.abs(distance) > 5) {
if (distance > 0) {
player.x += playerSpeed;
} else {
player.x -= playerSpeed;
}
// Animate walking - move feet up and down alternately
walkAnimationTimer++;
if (walkAnimationTimer >= 10) {
walkAnimationTimer = 0;
// Animate left foot up and down
tween(leftFoot, {
y: leftFoot.y === player.y + 10 ? player.y - 10 : player.y + 10
}, {
duration: 150,
easing: tween.easeInOut
});
// Animate right foot up and down (opposite to left foot)
tween(rightFoot, {
y: rightFoot.y === player.y + 10 ? player.y - 10 : player.y + 10
}, {
duration: 150,
easing: tween.easeInOut
});
}
} else {
// Snap to target when close enough
player.x = targetX;
isMoving = false;
}
// Keep player within bounds
if (player.x < 0) player.x = 0;
if (player.x > 2048) player.x = 2048;
}
// Update feet positions to follow player
leftFoot.x = player.x - 80;
rightFoot.x = player.x + 80;
// Update right hand position to follow player
playerRightHand.x = player.x + 120;
playerRightHand.y = player.y - 120;
// Reset feet position when not moving
if (!isMoving) {
leftFoot.y = player.y + 10;
rightFoot.y = player.y + 10;
}
// Update shield system
if (isShielded) {
shieldTimer--;
// Hide player right hand when shield is active
playerRightHand.visible = false;
// Show shield bubble if not already visible
if (!shieldBubble) {
shieldBubble = game.attachAsset('shieldBubble', {
x: player.x,
y: player.y - 150,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.1,
tint: 0xffffff
});
// Add pulsing animation to shield bubble
tween(shieldBubble, {
scaleX: 1.1,
scaleY: 1.1,
alpha: 0.2
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (shieldBubble) {
tween(shieldBubble, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.05
}, {
duration: 500,
easing: tween.easeInOut
});
}
}
});
}
// Update shield bubble position to follow player
if (shieldBubble) {
shieldBubble.x = player.x;
shieldBubble.y = player.y - 150;
}
// Flash player blue to indicate shield
if (shieldTimer % 20 < 10) {
player.tint = 0x00ffff;
} else {
player.tint = 0xffffff;
}
// Deactivate shield when timer expires
if (shieldTimer <= 0) {
isShielded = false;
player.tint = 0xffffff;
// Show player right hand when shield is deactivated
playerRightHand.visible = true;
// Stop pupil spinning and reset rotation
tween.stop(leftPupil, {
rotation: true
});
tween.stop(rightPupil, {
rotation: true
});
leftPupil.rotation = 0;
rightPupil.rotation = 0;
// Remove shield bubble
if (shieldBubble) {
shieldBubble.destroy();
shieldBubble = null;
}
// Clear shield sound interval
if (game.shieldSoundInterval) {
LK.clearInterval(game.shieldSoundInterval);
game.shieldSoundInterval = null;
}
}
}
// Update eye positions to follow player
leftEye.x = player.x - 50;
leftEye.y = player.y - 245;
rightEye.x = player.x + 10;
rightEye.y = player.y - 245;
// Keep pupils centered when not shielded, but track falling projectiles
if (!isShielded) {
// Default pupil positions (eye centers)
var leftEyeCenterX = player.x - 50;
var leftEyeCenterY = player.y - 245;
var rightEyeCenterX = player.x + 10;
var rightEyeCenterY = player.y - 245;
// Maximum distance pupils can move from center
var maxPupilDistance = 8;
// Find closest falling projectile to track
var closestProjectile = null;
var closestDistance = Infinity;
// Check all enemy projectiles
for (var p = 0; p < enemyProjectiles.length; p++) {
var proj = enemyProjectiles[p];
var distance = Math.sqrt(Math.pow(proj.x - player.x, 2) + Math.pow(proj.y - player.y, 2));
if (distance < closestDistance) {
closestDistance = distance;
closestProjectile = proj;
}
}
// Check all enemy projectiles type 2
for (var p2 = 0; p2 < enemyProjectiles2.length; p2++) {
var proj2 = enemyProjectiles2[p2];
var distance2 = Math.sqrt(Math.pow(proj2.x - player.x, 2) + Math.pow(proj2.y - player.y, 2));
if (distance2 < closestDistance) {
closestDistance = distance2;
closestProjectile = proj2;
}
}
if (closestProjectile) {
// Calculate angles from eye centers to the closest projectile
var leftAngle = Math.atan2(closestProjectile.y - leftEyeCenterY, closestProjectile.x - leftEyeCenterX);
var rightAngle = Math.atan2(closestProjectile.y - rightEyeCenterY, closestProjectile.x - rightEyeCenterX);
// Position pupils within eye boundaries, tracking the projectile
leftPupil.x = leftEyeCenterX + Math.cos(leftAngle) * maxPupilDistance;
leftPupil.y = leftEyeCenterY + Math.sin(leftAngle) * maxPupilDistance;
rightPupil.x = rightEyeCenterX + Math.cos(rightAngle) * maxPupilDistance;
rightPupil.y = rightEyeCenterY + Math.sin(rightAngle) * maxPupilDistance;
} else {
// No projectiles to track, center pupils
leftPupil.x = leftEyeCenterX;
leftPupil.y = leftEyeCenterY;
rightPupil.x = rightEyeCenterX;
rightPupil.y = rightEyeCenterY;
}
} else {
// When shield is active, make pupils move diagonally (down-left and diagonally)
var leftEyeCenterX = player.x - 50;
var leftEyeCenterY = player.y - 245;
var rightEyeCenterX = player.x + 10;
var rightEyeCenterY = player.y - 245;
var maxBounceDistance = 12;
// Use diagonal movement patterns based on time
var bounceTime = LK.ticks * 0.12;
// Create diagonal movements: down-left and cross-diagonal
var bounceX = Math.sin(bounceTime) * maxBounceDistance;
var bounceY = Math.cos(bounceTime * 0.8) * (maxBounceDistance * 0.7);
// Position pupils with diagonal movement patterns
leftPupil.x = leftEyeCenterX + bounceX;
leftPupil.y = leftEyeCenterY + bounceY;
rightPupil.x = rightEyeCenterX - bounceX; // Opposite X movement for variety
rightPupil.y = rightEyeCenterY + bounceY;
}
// Update enemy projectiles
for (var i = enemyProjectiles.length - 1; i >= 0; i--) {
var projectile = enemyProjectiles[i];
// Remove projectiles that go off screen (any direction)
if (projectile.y > 2732 + 100 || projectile.y < -100 || projectile.x < -100 || projectile.x > 2148) {
projectile.destroy();
enemyProjectiles.splice(i, 1);
continue;
}
// Check collision with player
if (projectile.intersects(player)) {
// Check if player is protected by shield
if (!isShielded) {
// Award points when hit by enemy projectile
LK.setScore(LK.getScore() + 10);
// Update score display
scoreText.setText('PUAN: ' + LK.getScore());
// Play sound effect for first projectile hit
LK.getSound('enemyProjectileHit').play();
// Create reduced particle burst effect at player's mouth area
for (var particleCount = 0; particleCount < 1; particleCount++) {
var particle = new Particle();
particle.x = player.x + (Math.random() - 0.5) * 40;
particle.y = player.y - 130 + (Math.random() - 0.5) * 30; // Position higher up from mouth area
// Reduce particle velocity for better performance
particle.velocityX = (Math.random() - 0.5) * 10;
particle.velocityY = -Math.random() * 8 - 3;
particles.push(particle);
game.addChild(particle);
}
// Simplified mouth trembling effect
tween(player, {
scaleX: 3.2,
scaleY: 2.8
}, {
duration: 150,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(player, {
scaleX: 3.0,
scaleY: 3.0
}, {
duration: 150,
easing: tween.easeOut
});
}
});
}
projectile.destroy();
enemyProjectiles.splice(i, 1);
}
}
// Update enemy projectiles type 2
for (var j = enemyProjectiles2.length - 1; j >= 0; j--) {
var projectile2 = enemyProjectiles2[j];
// Remove projectiles that go off screen (any direction)
if (projectile2.y > 2732 + 100 || projectile2.y < -100 || projectile2.x < -100 || projectile2.x > 2148) {
projectile2.destroy();
enemyProjectiles2.splice(j, 1);
continue;
}
// Check collision with player
if (projectile2.intersects(player) && !isShielded && !isFlying) {
// Show enemy mouth when hit by second projectile
enemy.showMouth();
// Freeze enemy movement and shooting
enemy.freezeEnemy();
// Play sound effect for second projectile hit
LK.getSound('enemyProjectile2Hit').play();
// Stop current player movement
isMoving = false;
// Set flying state to true
isFlying = true;
// Player flies off screen to the left while spinning
tween(player, {
x: -200,
y: player.y - 800,
rotation: Math.PI * 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Return player from right side after flying off
player.x = 2248;
player.y = 2682;
player.rotation = 0;
// Reset flying state
isFlying = false;
// Activate shield protection
isShielded = true;
shieldTimer = shieldDuration;
// Play shield activation sound
LK.getSound('shieldSound').play();
// Set up repeating shield sound during shield duration
var shieldSoundInterval = LK.setInterval(function () {
if (isShielded && shieldTimer > 0) {
LK.getSound('shieldSound').play();
}
}, 1750); // Play every 1750ms
// Store interval reference for cleanup
game.shieldSoundInterval = shieldSoundInterval;
// Shield bubble will be created in the shield update section
// Animate player returning to screen
tween(player, {
x: 2048 / 2
}, {
duration: 800,
easing: tween.easeOut
});
}
});
// Update feet positions during flight animation
tween(leftFoot, {
x: -330,
y: player.y - 790
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
leftFoot.x = 2168;
leftFoot.y = 2692;
tween(leftFoot, {
x: 2048 / 2 - 80
}, {
duration: 800,
easing: tween.easeOut
});
}
});
tween(rightFoot, {
x: -120,
y: player.y - 790
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
rightFoot.x = 2128;
rightFoot.y = 2692;
tween(rightFoot, {
x: 2048 / 2 + 80
}, {
duration: 800,
easing: tween.easeOut
});
}
});
// Update eye positions during flight animation
tween(leftEye, {
x: -250,
y: player.y - 1045
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
leftEye.x = 2198;
leftEye.y = 2437;
tween(leftEye, {
x: 2048 / 2 - 50
}, {
duration: 800,
easing: tween.easeOut
});
}
});
tween(rightEye, {
x: -190,
y: player.y - 1045
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
rightEye.x = 2258;
rightEye.y = 2437;
tween(rightEye, {
x: 2048 / 2 + 10
}, {
duration: 800,
easing: tween.easeOut
});
}
});
tween(leftPupil, {
x: -250,
y: player.y - 1045
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
leftPupil.x = 2198;
leftPupil.y = 2437;
tween(leftPupil, {
x: 2048 / 2 - 50
}, {
duration: 800,
easing: tween.easeOut
});
}
});
tween(rightPupil, {
x: -190,
y: player.y - 1045
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
rightPupil.x = 2258;
rightPupil.y = 2437;
tween(rightPupil, {
x: 2048 / 2 + 10
}, {
duration: 800,
easing: tween.easeOut
});
}
});
// Update right hand position during flight animation
tween(playerRightHand, {
x: -80,
y: player.y - 920
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
playerRightHand.x = 2368;
playerRightHand.y = 2562;
tween(playerRightHand, {
x: 2048 / 2 + 120
}, {
duration: 800,
easing: tween.easeOut
});
}
});
// Create particle burst effect
for (var particleCount = 0; particleCount < 5; particleCount++) {
var particle = new Particle();
particle.x = player.x + (Math.random() - 0.5) * 80;
particle.y = player.y - 50 + (Math.random() - 0.5) * 70;
// Give particles more dramatic velocities for this bigger explosion
particle.velocityX = (Math.random() - 0.5) * 18;
particle.velocityY = -Math.random() * 12 - 4;
particles.push(particle);
game.addChild(particle);
}
// Create smoke and flame effects
for (var smokeCount = 0; smokeCount < 2; smokeCount++) {
var smoke = game.attachAsset('smoke', {
x: player.x + (Math.random() - 0.5) * 200,
y: player.y - 100 + (Math.random() - 0.5) * 100,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
// Animate smoke rising and fading
tween(smoke, {
y: smoke.y - 200 - Math.random() * 100,
alpha: 0,
scaleX: 2 + Math.random(),
scaleY: 2 + Math.random()
}, {
duration: 2000 + Math.random() * 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
smoke.destroy();
}
});
}
for (var flameCount = 0; flameCount < 1; flameCount++) {
var flame = game.attachAsset('flame', {
x: player.x + (Math.random() - 0.5) * 150,
y: player.y - 50 + (Math.random() - 0.5) * 80,
anchorX: 0.5,
anchorY: 0.5,
alpha: 1
});
// Animate flames flickering and rising
tween(flame, {
y: flame.y - 150 - Math.random() * 50,
alpha: 0,
scaleX: 1.5 + Math.random() * 0.5,
scaleY: 1.5 + Math.random() * 0.5
}, {
duration: 1500 + Math.random() * 500,
easing: tween.easeOut,
onFinish: function onFinish() {
flame.destroy();
}
});
}
// Create fire animation effect on player
tween(player, {
tint: 0xff4500
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(player, {
tint: 0xff0000
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(player, {
tint: 0xffffff
}, {
duration: 300,
easing: tween.easeOut
});
}
});
}
});
// Reduce player lives
playerLives--;
// Update heart visibility based on remaining lives
for (var heartIndex = 0; heartIndex < lifeHearts.length; heartIndex++) {
if (heartIndex >= playerLives) {
// Hide heart with fade out animation
tween(lifeHearts[heartIndex], {
alpha: 0.2,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeOut
});
}
}
if (playerLives <= 0) {
// Show game over when no lives left
LK.showGameOver();
}
projectile2.destroy();
enemyProjectiles2.splice(j, 1);
}
}
// Comprehensive cleanup system - remove all off-screen elements every frame
var allChildren = game.children.slice(); // Create a copy to avoid modification during iteration
var screenBuffer = 100; // Buffer zone around visible area
for (var c = 0; c < allChildren.length; c++) {
var child = allChildren[c];
// Skip essential game elements that should always stay
if (child === player || child === enemy || child === backgroundImage || child === backgroundLayer || child === ground || child === scoreText || child === leftEye || child === rightEye || child === leftPupil || child === rightPupil || child === leftFoot || child === rightFoot || child === playerRightHand || child === shieldBubble) {
continue;
}
// Skip life hearts
var isLifeHeart = false;
for (var h = 0; h < lifeHearts.length; h++) {
if (child === lifeHearts[h]) {
isLifeHeart = true;
break;
}
}
if (isLifeHeart) {
continue;
}
// Remove if off screen in any direction with buffer zone
if (child.x < -screenBuffer || child.x > 2048 + screenBuffer || child.y < -screenBuffer || child.y > 2732 + screenBuffer) {
child.destroy();
}
}
// Clean up particle arrays - remove destroyed particles
for (var p = particles.length - 1; p >= 0; p--) {
if (!particles[p] || particles[p].destroyed) {
particles.splice(p, 1);
}
}
// Clean up projectile arrays - ensure no destroyed projectiles remain
for (var ep = enemyProjectiles.length - 1; ep >= 0; ep--) {
if (!enemyProjectiles[ep] || enemyProjectiles[ep].destroyed) {
enemyProjectiles.splice(ep, 1);
}
}
for (var ep2 = enemyProjectiles2.length - 1; ep2 >= 0; ep2--) {
if (!enemyProjectiles2[ep2] || enemyProjectiles2[ep2].destroyed) {
enemyProjectiles2.splice(ep2, 1);
}
}
};
3d köstebek. In-Game asset. 2d. High contrast. No shadows
Elinde havuç olan kızgın bir çiftçi. Karakter ayakkabısı siyah
Havuç. In-Game asset. 2d. High contrast. No shadows
Bomba. In-Game asset. 2d. High contrast. No shadows
Alev. In-Game asset. 2d. High contrast. No shadows
Agız. In-Game asset. 2d. High contrast. No shadows
Kalp 3d. In-Game asset. 2d. High contrast. No shadows