/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Coin = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'coin'; // Create sprite based on type self.sprite = self.attachAsset(self.type, { anchorX: 0.5, anchorY: 0.5, tint: 0xFFFFFF // No tint for gems }); self.velocityX = 0; self.velocityY = 0; self.collected = false; self.bounceCount = 0; self.maxBounces = 2; // Get value based on type self.getValue = function () { switch (self.type) { case 'diamond': return 10; case 'emerald': return 5; case 'ruby': return 3; default: return 1; } }; // Rest of the existing Coin code... // Make sure to use self.getValue() in the collect function self.collect = function () { if (!self.collected) { self.collected = true; var value = self.getValue(); scoreManager.addScore(value, self.x, self.y); LK.getSound('coincollect').play(); self.destroy(); } }; self.update = function () { if (self.collected) { return; } // Apply physics self.velocityY += 0.5; // gravity self.x += self.velocityX; self.y += self.velocityY; // Check for platform collision with bounce // Only bounce if we're moving downward and hit a platform if (self.velocityY > 0 && self.checkPlatformCollision()) { if (self.bounceCount < self.maxBounces) { LK.getSound('coinbounce').play(); var impactSpeed = Math.abs(self.velocityY); self.velocityY = -(impactSpeed * 0.5); // Use half of impact speed self.velocityX *= 0.8; self.bounceCount++; } else { self.velocityY = 0; self.velocityX = -5; // Match platform speed } } // Check if off screen if (self.x < -50 || self.x > 2048 + 50 || self.y > 2732) { self.destroy(); } // Player collection detection var playerBounds = player.getBounds(); var coinBounds = { left: self.x - 25, right: self.x + 25, top: self.y - 25, bottom: self.y + 25 }; if (playerBounds.left < coinBounds.right && playerBounds.right > coinBounds.left && playerBounds.top < coinBounds.bottom && playerBounds.bottom > coinBounds.top) { self.collect(); } }; self.checkPlatformCollision = function () { for (var i = 0; i < platforms.length; i++) { var platform = platforms[i]; if (Math.abs(self.y - (platform.y - 80)) < 10 && self.x > platform.x - 500 && self.x < platform.x + 500) { self.y = platform.y - 80; return true; } } return false; }; return self; }); var Enemy = Container.expand(function (type) { var self = Container.call(this); // Enemy properties self.type = type || 'basic'; self.speed = 7; self.isOnGround = true; self.velocityY = 0; self.currentPlatform = null; self.groundY = 2732 / 1.5; // Same as player ground Y self.hitAnimation = ['goblinhit1']; self.dieAnimation = ['goblindie1', 'goblindie2', 'goblindie3', 'goblindie4']; self.isHit = false; self.isDying = false; self.deathTimer = 0; self.throwBackSpeed = 15; // Initial backwards throw speed self.throwBackDistance = 0; // Track distance thrown self.maxThrowBack = 200; // Maximum throw back distance // Add bounding box properties self.hitboxWidth = 200; // Smaller than the 150px sprite width self.hitboxHeight = 260; // Adjusted for goblin height // Animation properties for goblin self.runAnimation = []; self.runFrame = 0; self.animationSpeed = 0.08; self.animationCounter = 0; self.sprites = []; // Add eyeball-specific properties self.isFlying = type === 'eyeball'; self.flyingHeight = 0; self.verticalSpeed = 2; // Speed of vertical adjustment self.maxVerticalSpeed = 4; // Maximum vertical speed self.homingDelay = 80; // Wait 60 frames before homing self.homingTimer = 0; // Track how long the eyeball has been alive // Add eyeball animations self.flyAnimation = ['eyefly1', 'eyefly2', 'eyefly3', 'eyefly4', 'eyefly5', 'eyefly6', 'eyefly7', 'eyefly8']; self.flyFrame = 0; // Initialize based on enemy type if (self.type === 'eyeball') { // Eyeball animations self.flyAnimation = ['eyefly1', 'eyefly2', 'eyefly3', 'eyefly4', 'eyefly5', 'eyefly6', 'eyefly7', 'eyefly8']; self.hitAnimation = ['eyedie1', 'eyedie2']; self.dieAnimation = ['eyedie3', 'eyedie4', 'eyedie5']; } else if (self.type === 'goblin') { // Goblin animations self.runAnimation = ['goblinrun1', 'goblinrun2', 'goblinrun3', 'goblinrun4', 'goblinrun5', 'goblinrun6', 'goblinrun7', 'goblinrun8']; self.hitAnimation = ['goblinhit1']; self.dieAnimation = ['goblindie1', 'goblindie2', 'goblindie3', 'goblindie4']; } // Initialize based on enemy type if (self.type === 'goblin') { // Setup all animations self.runAnimation = ['goblinrun1', 'goblinrun2', 'goblinrun3', 'goblinrun4', 'goblinrun5', 'goblinrun6', 'goblinrun7', 'goblinrun8']; // Pre-attach all animation frames // Run animation for (var i = 0; i < self.runAnimation.length; i++) { var sprite = self.attachAsset(self.runAnimation[i], { anchorX: 0.5, anchorY: 0.5 }); sprite.alpha = i === 0 ? 1 : 0; self.sprites.push(sprite); } // Hit animation for (var i = 0; i < self.hitAnimation.length; i++) { var sprite = self.attachAsset(self.hitAnimation[i], { anchorX: 0.5, anchorY: 0.5 }); sprite.alpha = 0; self.sprites.push(sprite); } // Die animation for (var i = 0; i < self.dieAnimation.length; i++) { var sprite = self.attachAsset(self.dieAnimation[i], { anchorX: 0.5, anchorY: 0.5 }); sprite.alpha = 0; self.sprites.push(sprite); } } else if (self.type === 'eyeball') { // First add fly animations (8 frames) for (var i = 0; i < self.flyAnimation.length; i++) { var sprite = self.attachAsset(self.flyAnimation[i], { anchorX: 0.5, anchorY: 0.5 }); sprite.alpha = i === 0 ? 1 : 0; self.sprites.push(sprite); } // Then hit animations (2 frames) for (var i = 0; i < self.hitAnimation.length; i++) { var sprite = self.attachAsset(self.hitAnimation[i], { anchorX: 0.5, anchorY: 0.5 }); sprite.alpha = 0; self.sprites.push(sprite); } // Then die animations (3 frames) for (var i = 0; i < self.dieAnimation.length; i++) { var sprite = self.attachAsset(self.dieAnimation[i], { anchorX: 0.5, anchorY: 0.5 }); sprite.alpha = 0; self.sprites.push(sprite); } // Adjust hitbox for eyeball self.hitboxWidth = 200; self.hitboxHeight = 90; // Flying enemies don't use ground physics self.isOnGround = false; } else { // Basic enemy (original version) var enemyGraphics = self.attachAsset('enemy', { anchorX: 0.5, anchorY: 0.5 }); } self.checkPlatformCollision = function () { var onAnyPlatform = false; var platformHalfWidth = 500; for (var i = 0; i < platforms.length; i++) { var platform = platforms[i]; var leftEdge = platform.x - platformHalfWidth; var rightEdge = platform.x + platformHalfWidth; // First check if we're on a platform (exact position check) if (self.x >= leftEdge && self.x <= rightEdge) { if (Math.abs(self.y - (platform.y - ENEMY_PLATFORM_OFFSET)) < 5) { onAnyPlatform = true; self.currentPlatform = platform; self.y = platform.y - ENEMY_PLATFORM_OFFSET; self.isOnGround = true; self.velocityY = 0; return true; } // NEW CODE: Check for passing through platform during fall // This detects if the enemy will cross the platform in the next frame if (self.velocityY > 0 && // Must be falling down self.y < platform.y - ENEMY_PLATFORM_OFFSET && self.y + self.velocityY >= platform.y - ENEMY_PLATFORM_OFFSET) { self.y = platform.y - ENEMY_PLATFORM_OFFSET; self.velocityY = 0; self.isOnGround = true; self.currentPlatform = platform; return true; } } } if (!onAnyPlatform) { self.isOnGround = false; self.currentPlatform = null; } return false; }; // Update collision check method self.getBounds = function () { return { left: self.x - self.hitboxWidth / 2, right: self.x + self.hitboxWidth / 2, top: self.y - self.hitboxHeight / 2, bottom: self.y + self.hitboxHeight / 2 }; }; self.hit = function () { if (!self.isHit && !self.isDying) { self.isHit = true; self.throwBackSpeed = 25; // Increased from 25 for more distance self.throwBackDistance = 0; self.hitTimer = 35; // Added hit timer for longer hit frame // Add particle effect here var particleOffset = self.type === 'eyeball' ? 175 : 250; // smaller offset for eyeballs particleSystem.emitFromHit(self.x + particleOffset, self.y, player.x); } }; self.update = function () { // Hide all sprites first for (var i = 0; i < self.sprites.length; i++) { self.sprites[i].alpha = 0; } if (self.type === 'eyeball' && (self.isHit || self.isDying)) { // First handle the hit state if (self.isHit) { var hitOffset = self.flyAnimation.length; self.throwBackDistance += Math.abs(self.throwBackSpeed); self.x += self.throwBackSpeed; self.throwBackSpeed *= 0.95; // Show hit animation (eyedie1, eyedie2) var hitFrame = Math.floor(self.hitTimer / 100) % 2; self.sprites[hitOffset + hitFrame].alpha = 1; self.hitTimer--; if (self.hitTimer <= 0) { self.isHit = false; self.isDying = true; self.deathTimer = 180; // 3 seconds for death sequence self.deathFrame = 0; // Start at first death frame } } // Then handle the dying state else if (self.isDying) { var dieOffset = self.flyAnimation.length + self.hitAnimation.length; // Always check for ground collision during fall if (!self.isOnGround) { self.velocityY += 0.5; self.y += self.velocityY; } //self.x -= 5; // Match platform speed // Progress through death frames if (self.deathTimer > 120) { self.sprites[dieOffset].alpha = 1; // eyedie3 } else if (self.deathTimer > 60) { self.sprites[dieOffset + 1].alpha = 1; // eyedie4 } else { self.sprites[dieOffset + 2].alpha = 1; // eyedie5 } self.deathTimer--; if (self.deathTimer <= 0) { self.alpha -= 0.05; if (self.alpha <= 0) { self.destroy(); } } } return; // Skip regular animation updates } else if (self.type === 'eyeball') { self.x -= self.speed; // Only start homing after delay if (self.homingTimer >= self.homingDelay) { // Home toward player var deltaY = player.y - self.y; self.velocityY += deltaY > 0 ? 0.2 : -0.2; self.velocityY = Math.max(-self.maxVerticalSpeed, Math.min(self.maxVerticalSpeed, self.velocityY)); } else { // Before homing, just maintain height with slight wave motion self.velocityY = Math.sin(self.homingTimer * 0.05) * 2; self.homingTimer++; } self.y += self.velocityY; // Animate self.animationCounter += self.animationSpeed; if (self.animationCounter >= 1) { self.animationCounter = 0; self.flyFrame = (self.flyFrame + 1) % self.flyAnimation.length; } self.sprites[self.flyFrame].alpha = 1; // Check if off screen if (self.x < -50 || self.y > 2732) { self.destroy(); } } else { if (self.isHit) { // Handle throw back motion self.x += self.throwBackSpeed; self.throwBackDistance += Math.abs(self.throwBackSpeed); self.throwBackSpeed *= 0.95; // Slower decay than 0.9 // Show hit animation var hitOffset = self.runAnimation.length; self.sprites[hitOffset].alpha = 1; // Decrease hit timer self.hitTimer--; // Once hit timer expires, start death animation if (self.hitTimer <= 0) { self.isHit = false; self.isDying = true; self.deathTimer = 60; // Increased to 60 frames self.deathFrame = 0; // Explicitly track which frame we're on } } else if (self.isDying) { // Continue throw back during death self.x += self.throwBackSpeed; // After halfway through death animation, match platform speed if (self.deathFrame >= 2) { // Since we have 4 frames, 2 is halfway self.x -= 5; // Platform speed is defined as 5 } self.throwBackSpeed *= 0.95; // Removed vertical movement code // Handle death animation var dieOffset = self.runAnimation.length + self.hitAnimation.length; // Progress frame every 15 frames (60/4 frames = 15) if (self.deathTimer % 15 === 0 && self.deathFrame < self.dieAnimation.length - 1) { self.deathFrame++; } var dieOffset = self.runAnimation.length + self.hitAnimation.length; self.sprites[dieOffset + self.deathFrame].alpha = 1; // Count down death timer self.deathTimer--; // After timer expires, fade out if (self.deathTimer <= 0) { self.alpha -= 0.1; if (self.alpha <= 0) { self.destroy(); } } } else { // Original movement and animation code // Move left self.x -= self.speed; // Original platform and gravity code if (!self.isOnGround) { self.velocityY += 0.7; self.y += self.velocityY; if (!self.checkPlatformCollision()) { // Let them fall if not on platform } } if (self.currentPlatform) { var platformHalfWidth = 500; // Match the existing platform width constant var stillOnPlatform = self.x >= self.currentPlatform.x - platformHalfWidth && self.x <= self.currentPlatform.x + platformHalfWidth; if (!stillOnPlatform) { var foundAnotherPlatform = false; // Check if there's another platform we might have moved to for (var i = 0; i < platforms.length; i++) { var otherPlatform = platforms[i]; if (otherPlatform === self.currentPlatform) { continue; } if (self.x >= otherPlatform.x - platformHalfWidth && self.x <= otherPlatform.x + platformHalfWidth && Math.abs(self.y - (otherPlatform.y - ENEMY_PLATFORM_OFFSET)) < 5) { // Found another platform at the same height self.currentPlatform = otherPlatform; foundAnotherPlatform = true; break; } } // If no other platform found, start falling if (!foundAnotherPlatform) { self.isOnGround = false; self.currentPlatform = null; // Start falling with initial velocity if (self.velocityY === 0) { self.velocityY = 0.1; } } } } // Handle run animation if (self.type === 'goblin') { self.animationCounter += self.animationSpeed; if (self.animationCounter >= 1) { self.animationCounter = 0; self.runFrame = (self.runFrame + 1) % self.runAnimation.length; } self.sprites[self.runFrame].alpha = 1; } } // Destroy if off screen if (self.x < -50 || self.y > 2732) { self.destroy(); } } }; }); var Jar = Container.expand(function () { var self = Container.call(this); // Attach jar sprite self.sprite = self.attachAsset('jar', { anchorX: 0.5, anchorY: 0.5, tint: 0xC0C0C0 // Change tint to an even lighter grey }); self.isBreaking = false; self.currentPlatform = null; self["break"] = function () { if (self.isBreaking) { return; } self.isBreaking = true; // Spawn jar pieces (keep existing piece code) for (var i = 1; i <= 4; i++) { var piece = new JarPiece(i); piece.x = self.x; piece.y = self.y; piece.velocityX = Math.random() * 10 - 5; piece.velocityY = -(Math.random() * 10 + 5); piece.rotationSpeed = Math.random() * 0.2 - 0.1; game.addChild(piece); } // Modified coin spawning with more forward motion var coinCount = Math.floor(Math.random() * 8) + 1; for (var i = 0; i < coinCount; i++) { var coin = new Coin(); coin.x = self.x; coin.y = self.y; // More forward motion and higher initial jump coin.velocityX = Math.random() * 8 + 4; // Minimum 4, maximum 12 right velocity coin.velocityY = -(Math.random() * 10 + 12); // Higher jump game.addChild(coin); coins.push(coin); } LK.getSound('jarbreak').play(); self.destroy(); }; return self; }); var JarPiece = Container.expand(function (pieceNum) { var self = Container.call(this); self.sprite = self.attachAsset('jarpiece' + pieceNum, { anchorX: 0.5, anchorY: 0.5, tint: 0xC0C0C0 // Apply grey tint }); self.velocityX = 0; self.velocityY = 0; self.rotationSpeed = 0; self.fadeSpeed = 0.02; self.bounceCount = 0; self.maxBounces = 2; // Number of bounces before stopping self.update = function () { // Apply physics self.velocityY += 0.5; // gravity self.x += self.velocityX; self.y += self.velocityY; self.rotation += self.rotationSpeed; // Check for platform collision with bounce if (self.checkPlatformCollision()) { if (self.bounceCount < self.maxBounces) { // Bounce with reduced velocity self.velocityY = -(self.velocityY * 0.4); // 40% of original velocity self.velocityX *= 0.8; // Reduce horizontal speed self.bounceCount++; } else { // Stop moving after max bounces self.velocityY = 0; self.velocityX = -5; // Match platform speed // Start fading self.alpha -= self.fadeSpeed; if (self.alpha <= 0) { self.destroy(); } } } // Destroy if off screen if (self.x < -50 || self.y > 2732) { self.destroy(); } }; self.checkPlatformCollision = function () { for (var i = 0; i < platforms.length; i++) { var platform = platforms[i]; if (Math.abs(self.y - (platform.y - 80)) < 10 && self.x > platform.x - 500 && self.x < platform.x + 500) { self.y = platform.y - 80; return true; } } return false; }; return self; }); var ParticlePool = Container.expand(function (maxParticles) { var self = Container.call(this); self.particles = []; self.activeParticles = []; self.redTints = [0xff0000, 0xff3333, 0xcc0000]; for (var i = 0; i < maxParticles; i++) { var particle = self.attachAsset('pixel', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.2, // 4% of original size (4px from 100px) scaleY: 0.2 // 4% of original size (4px from 100px) }); particle.alpha = 0; particle.velocityX = 0; particle.velocityY = 0; particle.lifespan = 0; particle.fadeSpeed = 0; self.particles.push(particle); } self.emitFromHit = function (x, y, playerX) { var directionX = x - playerX; var directionSign = Math.sign(directionX); for (var i = 0; i < 20; i++) { if (self.particles.length === 0) { break; } var particle = self.particles.pop(); self.activeParticles.push(particle); particle.x = x; particle.y = y; particle.alpha = 1; particle.tint = self.redTints[Math.floor(Math.random() * self.redTints.length)]; // Set scale instead of width/height var particleSize = Math.random() * 0.2 + 0.2; // 2-4% of original size particle.scaleX = particleSize; particle.scaleY = particleSize; var angle = Math.random() * Math.PI / 2 - Math.PI / 4; var speed = Math.random() * 5 + 10; particle.velocityX = Math.cos(angle) * speed * directionSign; particle.velocityY = Math.sin(angle) * speed; particle.lifespan = 100; particle.fadeSpeed = 1 / 60; } }; self.update = function () { for (var i = self.activeParticles.length - 1; i >= 0; i--) { var particle = self.activeParticles[i]; particle.x += particle.velocityX; particle.y += particle.velocityY; particle.alpha -= particle.fadeSpeed; particle.lifespan--; if (particle.lifespan <= 0 || particle.alpha <= 0) { particle.alpha = 0; self.activeParticles.splice(i, 1); self.particles.push(particle); } } }; return self; }); var Platform = Container.expand(function () { var self = Container.call(this); var platformGraphics = self.attachAsset('platform', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.passed = false; self.update = function () { self.x -= self.speed; if (self.x < -500) { // Increased value to ensure platforms are fully off-screen self.destroy(); } }; }); //<Assets used in the game will automatically appear here> var Player = Container.expand(function () { var self = Container.call(this); // Animation properties self.runAnimation = ['playerrun1', 'playerrun2', 'playerrun3', 'playerrun4', 'playerrun5', 'playerrun6']; self.jumpAnimation = ['playerjump1', 'playerjump2', 'playerjump3']; self.attackAnimation = ['playerattack1', 'playerattack2', 'playerattack3', 'playerattack4', 'playerattack5']; self.isAttacking = false; self.attackFrame = 0; self.runFrame = 0; self.animationSpeed = 0.08; self.attackAnimationSpeed = 0.15; // Higher number = faster animation self.animationCounter = 0; self.sprites = []; self.groundY = 2732 * 0.9; // Move ground much lower to allow falling from all platforms // Add bounding box properties self.hitboxWidth = 150; // Smaller than the 600px animation frames self.hitboxHeight = 300; // Adjusted for player height self.attackHitboxWidth = 200; // Width of attack hitbox self.attackHitboxHeight = 400; // Height of attack hitbox self.attackHitboxOffset = 50; // How far in front of player the attack hitbox extends // Platform collision properties self.isOnGround = true; self.currentPlatform = null; // Pre-attach all animation frames but make only the first one visible // First add run animation sprites for (var i = 0; i < self.runAnimation.length; i++) { var sprite = self.attachAsset(self.runAnimation[i], { anchorX: 0.5, anchorY: 0.5 }); // Set all frames except the first to be invisible sprite.alpha = i === 0 ? 1 : 0; self.sprites.push(sprite); } // Then add jump animation sprites for (var i = 0; i < self.jumpAnimation.length; i++) { var sprite = self.attachAsset(self.jumpAnimation[i], { anchorX: 0.5, anchorY: 0.5 }); // Set all jump frames to invisible initially sprite.alpha = 0; self.sprites.push(sprite); } for (var i = 0; i < self.attackAnimation.length; i++) { var sprite = self.attachAsset(self.attackAnimation[i], { anchorX: 0.5, anchorY: 0.5 }); sprite.alpha = 0; self.sprites.push(sprite); } // Movement properties self.speed = 5; self.jumpHeight = 40; // Keeping the original jump height self.isJumping = false; self.velocityY = 0; self.jumpState = "none"; // Added to track jump animation phases self.jumpStartTime = 0; // Add method to get actual collision bounds self.getBounds = function () { return { left: self.x - self.hitboxWidth / 2, right: self.x + self.hitboxWidth / 2, top: self.y - self.hitboxHeight / 2, bottom: self.y + self.hitboxHeight / 2 }; }; self.update = function () { // Hide all sprites first for (var i = 0; i < self.sprites.length; i++) { self.sprites[i].alpha = 0; } // Handle platform collision and falling physics first if (!self.isOnGround && !self.isJumping) { self.velocityY += 0.7; self.y += self.velocityY; self.checkPlatformCollision(); } // Handle jumping physics if (self.isJumping) { self.y += self.velocityY; self.velocityY += 0.7; // Get jump frame index offset var jumpOffset = self.runAnimation.length; // Check for landing on platforms while falling during a jump self.checkPlatformCollision(); // End jump if hitting the original ground (for backward compatibility) if (self.y >= self.groundY && !self.currentPlatform) { self.y = self.groundY; self.isJumping = false; self.velocityY = 0; self.jumpState = "none"; self.isOnGround = true; } } // IMPORTANT: Platform collision check - runs EVERY frame var onAnyPlatform = false; var platformHalfWidth = 500; // half of platform width (1000/2) // First, check platform collisions for (var i = 0; i < platforms.length; i++) { var platform = platforms[i]; var leftEdge = platform.x - platformHalfWidth; var rightEdge = platform.x + platformHalfWidth; // Check if player is within horizontal bounds of platform if (self.x >= leftEdge && self.x <= rightEdge) { // If we're at platform height and not jumping if (Math.abs(self.y - (platform.y - 250)) < 5 && !self.isJumping) { onAnyPlatform = true; self.currentPlatform = platform; self.y = platform.y - 250; self.isOnGround = true; self.velocityY = 0; break; } } } // Handle falling state if (!onAnyPlatform && !self.isJumping) { self.isOnGround = false; self.currentPlatform = null; // Apply gravity if (self.velocityY === 0) { self.velocityY = 0.1; } self.velocityY += 0.1; self.y += self.velocityY; // Ground collision check comes AFTER falling movement if (self.y >= self.groundY) { // Reached the bottom of the screen - game over LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } } // Now handle animations - attack takes priority if active if (self.isAttacking) { var attackOffset = self.runAnimation.length + self.jumpAnimation.length; self.animationCounter += self.attackAnimationSpeed; if (self.animationCounter >= 1) { self.animationCounter = 0; self.attackFrame++; if (self.attackFrame >= self.attackAnimation.length) { self.isAttacking = false; self.attackFrame = 0; } } self.sprites[attackOffset + self.attackFrame].alpha = 1; } // If not attacking, show jump or run animation else if (self.isJumping || !self.isOnGround) { var jumpOffset = self.runAnimation.length; var currentTime = Date.now(); if (currentTime - self.jumpStartTime < 100) { self.sprites[jumpOffset + 0].alpha = 1; } else if (self.velocityY < 0) { self.sprites[jumpOffset + 1].alpha = 1; } else if (self.velocityY > 0) { self.sprites[jumpOffset + 2].alpha = 1; } } else if (self.isOnGround) { self.animationCounter += self.animationSpeed; if (self.animationCounter >= 1) { self.animationCounter = 0; self.runFrame = (self.runFrame + 1) % self.runAnimation.length; } self.sprites[self.runFrame].alpha = 1; } // If on a platform, check if we're still above it if (self.currentPlatform) { var platformHalfWidth = platformWidth / 2; // Use platformWidth constant var stillOnPlatform = self.x > self.currentPlatform.x - platformHalfWidth && self.x < self.currentPlatform.x + platformHalfWidth; if (!stillOnPlatform) { var foundAnotherPlatform = false; for (var i = 0; i < platforms.length; i++) { var otherPlatform = platforms[i]; if (otherPlatform === self.currentPlatform) { continue; } var otherHalfWidth = platformWidth / 2; if (self.x > otherPlatform.x - otherHalfWidth && self.x < otherPlatform.x + otherHalfWidth) { // We found another platform directly below player self.currentPlatform = otherPlatform; foundAnotherPlatform = true; break; } } // Only fall if we didn't find another platform if (!foundAnotherPlatform) { self.isOnGround = false; self.currentPlatform = null; // Start falling with initial velocity self.velocityY = 0.1; } } } // Check if player has fallen off the bottom of the screen if (self.y > 2732) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } }; self.getAttackBounds = function () { // Only return attack bounds when actually attacking if (!self.isAttacking) { return null; } // Create a forward-facing hitbox return { left: self.x + (self.attackHitboxOffset - self.attackHitboxWidth / 2), right: self.x + (self.attackHitboxOffset + self.attackHitboxWidth / 2), top: self.y - self.attackHitboxHeight / 2, bottom: self.y + self.attackHitboxHeight / 2 }; }; self.jump = function () { if (self.isOnGround) { self.isJumping = true; self.isOnGround = false; self.velocityY = -self.jumpHeight; self.jumpState = "start"; self.jumpStartTime = Date.now(); LK.getSound('playerjump').play(); self.currentPlatform = null; } else if (self.isJumping && self.velocityY < 10) { // Allow for a small double-jump to reach higher platforms // Only if not falling too fast self.velocityY = -self.jumpHeight * 0.7; self.jumpStartTime = Date.now(); } }; self.attack = function () { if (!self.isAttacking) { self.isAttacking = true; self.attackFrame = 0; self.animationCounter = 0; LK.getSound('swordslash').play(); } }; self.checkPlatformCollision = function () { for (var i = 0; i < platforms.length; i++) { var platform = platforms[i]; var platformHalfWidth = platform.width / 2; // The offset should match exactly how the player aligns with the lower platform initially var playerPlatformOffset = 250; // This is the exact offset between player.y and lowPlatformHeight // Check if player is above the platform and falling if (self.velocityY > 0 && // Must be falling down self.y < platform.y - playerPlatformOffset && self.y + self.velocityY >= platform.y - playerPlatformOffset && self.x > platform.x - platformHalfWidth && self.x < platform.x + platformHalfWidth) { // Land on the platform with the exact same positioning as on the low platform self.y = platform.y - playerPlatformOffset; self.velocityY = 0; self.isJumping = false; self.isOnGround = true; self.currentPlatform = platform; return; } } }; }); // Add this to your existing classes var ScorePopup = Container.expand(function (x, y, amount) { var self = Container.call(this); // Create the text with the actual score amount self.text = new Text2('+' + amount, { size: 80, fill: 0xFFFFFF, anchorX: 0.5, anchorY: 0.5 }); self.addChild(self.text); self.x = x; self.y = y; self.velocityY = -3; self.lifespan = 45; self.update = function () { self.y += self.velocityY; self.lifespan--; if (self.lifespan < 15) { self.alpha -= 0.07; } if (self.alpha <= 0 || self.lifespan <= 0) { self.destroy(); } }; return self; }); var Torch = Container.expand(function () { var self = Container.call(this); // Create base torch sprite self.base = self.attachAsset('torch', { anchorX: 0.5, anchorY: 1 // Anchor at bottom }); // Create flame sprite self.flame = self.attachAsset('torchflame', { anchorX: 0.5, anchorY: 1, // Anchor at bottom to scale from base y: -180 // Position at top of torch }); // Create aura sprite self.aura = self.attachAsset('torchaura', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3, // Start with low opacity y: -250 // Match flame position }); // Animation properties self.flameTime = Math.random() * Math.PI * 2; // Random start phase self.auraTime = Math.random() * Math.PI * 2; self.flameSpeed = 0.05; self.auraSpeed = 0.03; // Update animation self.update = function () { // Animate flame scale self.flameTime += self.flameSpeed; var flameScale = 1 + Math.sin(self.flameTime) * 0.2; // Scale between 0.8 and 1.2 self.flame.scaleY = flameScale; // Random flip chance for flame if (Math.random() < 0.02) { // 2% chance per frame self.flame.scaleX *= -1; } // Animate aura alpha self.auraTime += self.auraSpeed; var auraAlpha = 0.3 + Math.sin(self.auraTime) * 0.15; // Pulse between 0.15 and 0.45 self.aura.alpha = auraAlpha; }; return self; }); var TreasureChest = Container.expand(function () { var self = Container.call(this); // Attach chest sprite self.sprite = self.attachAsset('treasurechest', { anchorX: 0.5, anchorY: 0.5, tint: 0xC0C0C0 // Change tint to match jar's grey tint }); self.isBreaking = false; self.currentPlatform = null; self["break"] = function () { if (self.isBreaking) { return; } self.isBreaking = true; // Spawn chest pieces for (var i = 1; i <= 4; i++) { var piece = new TreasureChestPiece(i); piece.x = self.x; piece.y = self.y; piece.velocityX = Math.random() * 12 - 6; piece.velocityY = -(Math.random() * 12 + 6); piece.rotationSpeed = Math.random() * 0.2 - 0.1; game.addChild(piece); } // Spawn valuables var totalItems = Math.floor(Math.random() * 6) + 3; // 3-8 items for (var i = 0; i < totalItems; i++) { // Random chance for different gems var rand = Math.random(); var item; if (rand < 0.05) { // 5% diamond item = new Coin('diamond'); } else if (rand < 0.15) { // 10% emerald item = new Coin('emerald'); } else if (rand < 0.30) { // 15% ruby item = new Coin('ruby'); } else { // 70% gold coin item = new Coin('coin'); } item.x = self.x; item.y = self.y; item.velocityX = Math.random() * 10 + 2; item.velocityY = -(Math.random() * 12 + 14); game.addChild(item); coins.push(item); } LK.getSound('woodbreak').play(); self.destroy(); }; return self; }); var TreasureChestPiece = Container.expand(function (pieceNum) { var self = Container.call(this); self.sprite = self.attachAsset('treasurechestpiece' + pieceNum, { anchorX: 0.5, anchorY: 0.5, tint: 0xC0C0C0 // Change tint to match jar's grey tint }); self.velocityX = 0; self.velocityY = 0; self.rotationSpeed = 0; self.fadeSpeed = 0.02; self.bounceCount = 0; self.maxBounces = 2; self.update = function () { self.velocityY += 0.5; // gravity self.x += self.velocityX; self.y += self.velocityY; self.rotation += self.rotationSpeed; if (self.checkPlatformCollision()) { if (self.bounceCount < self.maxBounces) { self.velocityY = -(self.velocityY * 0.4); self.velocityX *= 0.8; self.bounceCount++; } else { self.velocityY = 0; self.velocityX = -5; self.alpha -= self.fadeSpeed; if (self.alpha <= 0) { self.destroy(); } } } if (self.x < -50 || self.y > 2732) { self.destroy(); } }; self.checkPlatformCollision = function () { for (var i = 0; i < platforms.length; i++) { var platform = platforms[i]; if (Math.abs(self.y - (platform.y - 80)) < 10 && self.x > platform.x - 500 && self.x < platform.x + 500) { self.y = platform.y - 80; return true; } } return false; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 // Black background }); /**** * Game Code ****/ var ScoreManager = function ScoreManager() { var self = {}; // Initialize score and UI self.score = 0; self.scoreText = new Text2('0', { size: 160, fill: 0xFFFFFF, anchorX: 1, anchorY: 0.5 }); self.coinIcon = LK.getAsset('coin', { anchorX: 0, anchorY: 0.5, scaleX: 2, scaleY: 2 }); // Initialize container self.container = new Container(); self.container.addChild(self.scoreText); self.container.addChild(self.coinIcon); // Position container self.container.x = 2048 - 100; self.container.y = 100; // Position elements self.scoreText.x = -100; self.scoreText.y = -100; self.coinIcon.x = 0; self.coinIcon.y = 0; // Getter and setter for score self.getScore = function () { return self.score; }; self.setScore = function (newScore) { self.score = newScore; self.scoreText.setText(newScore); // Adjust position based on digit count if (newScore >= 10 && newScore < 100) { self.scoreText.x = -200; // Adjust for 2 digits } else if (newScore >= 100 && newScore < 1000) { self.scoreText.x = -300; // Adjust for 3 digits } else if (newScore >= 1000) { self.scoreText.x = -400; // Adjust for 4+ digits } else { self.scoreText.x = -100; // Default for single digit } }; // Add score and display popup self.addScore = function (amount, x, y) { self.setScore(self.score + amount); LK.setScore(self.score); // Update LK score // Create score popup if position is provided if (x !== undefined && y !== undefined) { var popup = new ScorePopup(x, y - 30, amount); game.addChild(popup); } }; return self; }; var backgroundContainer = game.addChild(new Container()); var midgroundContainer = game.addChild(new Container()); var foregroundContainer = game.addChild(new Container()); var scoreManager = new ScoreManager(); game.addChild(scoreManager.container); var scoreContainer = game.addChild(new Container()); var GAME_WIDTH = 2048; var ENEMY_PLATFORM_OFFSET = 225; // Adjust this value var gameStarted = false; var titleScreen; var playButton; // Define playButton in the global scope var platforms = []; var platformWidth = 1000; // Define platform width based on asset size var platformSpawnInterval = 60; var platformSpawnCounter = 0; var platformOverlap = 50; var platformSpeed = 5; // Define platform speed globally var platformSpawnInterval = 190; var chestSpawnInterval = 100; // Longer than jar interval var chestSpawnCounter = 0; // = (1000 - 50) / 5 = 190 // Define the two fixed platform heights var lowPlatformHeight = 2732 / 1.5 + 250; // Regular height (player.y + 250) var highPlatformHeight = lowPlatformHeight - 600; // High platform (600 pixels higher) var minPlatformsInSequence = 2; // Minimum platforms in a sequence var maxPlatformsInSequence = 5; // Maximum platforms in a sequence var platformsUntilNextChange = 5; // Initial longer ground sequence var currentPlatformHeight = lowPlatformHeight; var lastPlatformHeight = lowPlatformHeight; // Simple toggle for alternating platform heights var useHighPlatform = false; var platformGap = 200; // Gap between platforms var lastPlatformX = 0; // Track the last platform position var touchStartX = 0; var touchStartY = 0; var touchEndX = 0; var touchEndY = 0; var jars = []; var coins = []; var collectibles = []; var jarSpawnCounter = 0; var jarSpawnInterval = 20; // Adjust as needed var player; // Initialize enemies var enemies = []; var enemySpawnInterval = 100; var enemySpawnCounter = 0; var goblinSpawnInterval = 100; var goblinSpawnCounter = 0; var eyeballSpawnInterval = 500; // Longer interval for eyeballs var eyeballSpawnCounter = 150; var particleSystem; // Background layer (slowest) var bg1 = backgroundContainer.addChild(LK.getAsset('background', { anchorX: 0, anchorY: 1 })); var bg2 = backgroundContainer.addChild(LK.getAsset('background', { anchorX: 0, anchorY: 1 })); bg1.y = 2732; // Position at bottom of screen bg2.y = 2732; bg2.x = GAME_WIDTH; // Midground layer var mg1 = midgroundContainer.addChild(LK.getAsset('midground', { anchorX: 0, anchorY: 1 })); var mg2 = midgroundContainer.addChild(LK.getAsset('midground', { anchorX: 0, anchorY: 1 })); mg1.y = 2732; mg2.y = 2732; mg2.x = GAME_WIDTH; // Foreground layer (fastest) var fg1 = foregroundContainer.addChild(LK.getAsset('foreground', { anchorX: 0, anchorY: 1 })); var fg2 = foregroundContainer.addChild(LK.getAsset('foreground', { anchorX: 0, anchorY: 1 })); fg1.y = 2732 * 1.25; fg2.y = 2732 * 1.25; fg1.x = 0; fg2.x = GAME_WIDTH; function createTitleScreen() { titleScreen = new Container(); game.addChild(titleScreen); // Add title image var titleImage = titleScreen.attachAsset('title', { anchorX: 0.5, anchorY: 0.5, alpha: 0 // Start with alpha 0 for fade-in effect }); titleImage.x = 2048 / 2; titleImage.y = 2732 / 2.7; // Add fade-in animation for titleImage tween(titleImage, { alpha: 1 }, { duration: 1000, // 1 second fade-in duration easing: tween.easeIn }); // Add play button playButton = titleScreen.attachAsset('playbutton', { anchorX: 0.5, anchorY: 0.5 }); playButton.x = 2048 / 2; playButton.y = 2732 / 1.3; // Add flashing animation to playButton function flashPlayButton() { tween(playButton, { alpha: 0 }, { duration: 250, easing: tween.linear, onFinish: function onFinish() { tween(playButton, { alpha: 1 }, { duration: 250, easing: tween.linear }); } }); } // Set interval to flash every 2 seconds LK.setInterval(flashPlayButton, 2000); initializeTorches(); } function canSpawnAtPosition(x, safeDistance) { safeDistance = safeDistance || 200; // Minimum distance between objects for (var i = 0; i < collectibles.length; i++) { var existingItem = collectibles[i]; if (Math.abs(existingItem.x - x) < safeDistance) { return false; } } return true; } function initializeTorches() { // Calculate number of torches needed based on screen width var torchSpacing = GAME_WIDTH; // One torch per background width // Create two torches for the two background sections var torch1 = new Torch(); torch1.x = 25; torch1.y = 2732 * 0.7; // Adjust Y position as needed midgroundContainer.addChild(torch1); var torch2 = new Torch(); torch2.x = GAME_WIDTH + 25; torch2.y = 2732 * 0.7; midgroundContainer.addChild(torch2); } // Initialize the game with starting platforms function initializeGame() { // Initialize player player = game.addChild(new Player()); player.x = 2048 / 4.5; player.y = 2732 / 1.5; // Create initial platforms at the low level for (var i = 0; i < 5; i++) { var platform = new Platform(); if (i === 0) { // First platform centered on player platform.x = player.x; } else { // Position with slight overlap platform.x = lastPlatformX + platformWidth - platformOverlap; } platform.y = lowPlatformHeight; platforms.push(platform); game.addChild(platform); lastPlatformX = platform.x; } lastPlatformHeight = lowPlatformHeight; player.isOnGround = true; player.currentPlatform = platforms[0]; } function startGame() { gameStarted = true; // Remove title screen titleScreen.destroy(); // Initialize game elements initializeGame(); // Initialize particle system particleSystem = new ParticlePool(100); game.addChild(particleSystem); // Play background music LK.playMusic('backgroundmusic1', { fade: { start: 0, end: 0.7, duration: 1000 } }); } createTitleScreen(); // Handle game updates game.update = function () { // Always scroll backgrounds for visual effect even on title screen bg1.x -= platformSpeed * 0.3; bg2.x -= platformSpeed * 0.3; if (bg1.x <= -GAME_WIDTH) { bg1.x = bg2.x + GAME_WIDTH; } if (bg2.x <= -GAME_WIDTH) { bg2.x = bg1.x + GAME_WIDTH; } mg1.x -= platformSpeed * 0.6; mg2.x -= platformSpeed * 0.6; if (mg1.x <= -GAME_WIDTH) { mg1.x = mg2.x + GAME_WIDTH; } if (mg2.x <= -GAME_WIDTH) { mg2.x = mg1.x + GAME_WIDTH; } // Also scroll foreground on title screen fg1.x -= platformSpeed; fg2.x -= platformSpeed; if (fg1.x <= -GAME_WIDTH) { fg1.x = fg2.x + GAME_WIDTH; } if (fg2.x <= -GAME_WIDTH) { fg2.x = fg1.x + GAME_WIDTH; } for (var i = 0; i < midgroundContainer.children.length; i++) { var child = midgroundContainer.children[i]; if (child instanceof Torch) { child.update(); // Move torch with midground child.x -= platformSpeed * 0.6; // Reset torch position when it goes off screen if (child.x <= -GAME_WIDTH) { child.x = child.x + GAME_WIDTH * 2; } } } if (!gameStarted) { return; } player.update(); if (particleSystem) { particleSystem.update(); } // Check if we need to spawn a new sequence of platforms var lastPlatform = platforms[platforms.length - 1]; if (lastPlatform && lastPlatform.x < GAME_WIDTH + 500) { // Spawn further off-screen to prevent pop-in // Time to spawn a new sequence if (platformsUntilNextChange <= 0) { // Switch height currentPlatformHeight = currentPlatformHeight === lowPlatformHeight ? highPlatformHeight : lowPlatformHeight; // Generate new random sequence length platformsUntilNextChange = Math.floor(Math.random() * (maxPlatformsInSequence - minPlatformsInSequence + 1)) + minPlatformsInSequence; // Make ground sequences longer if (currentPlatformHeight === lowPlatformHeight) { platformsUntilNextChange += 5; } } // Spawn a single platform in the sequence var platform = new Platform(); platform.x = lastPlatform.x + (platformWidth - platformOverlap); platform.y = currentPlatformHeight; platforms.push(platform); game.addChild(platform); // Decrement the counter for each platform added platformsUntilNextChange--; } // Update platforms for (var i = platforms.length - 1; i >= 0; i--) { platforms[i].update(); // Remove platforms that are destroyed if (platforms[i].destroyed) { platforms.splice(i, 1); } } jarSpawnCounter++; if (jarSpawnCounter >= jarSpawnInterval) { var availablePlatforms = platforms.filter(function (p) { return p.x > 2048 && p.x < 2048 + 300; }); if (availablePlatforms.length > 0 && Math.random() < 0.3) { var platform = availablePlatforms[Math.floor(Math.random() * availablePlatforms.length)]; // Only spawn if position is clear if (canSpawnAtPosition(platform.x)) { var jar = new Jar(); jar.x = platform.x; jar.y = platform.y - 130; jar.currentPlatform = platform; collectibles.push(jar); // Add to collectibles array instead of jars array game.addChild(jar); } } jarSpawnCounter = 0; } chestSpawnCounter++; if (chestSpawnCounter >= chestSpawnInterval) { var availablePlatforms = platforms.filter(function (p) { return p.x > 2048 && p.x < 2048 + 300; }); if (availablePlatforms.length > 0 && Math.random() < 0.15) { // 15% chance to spawn var platform = availablePlatforms[Math.floor(Math.random() * availablePlatforms.length)]; // Only spawn if position is clear if (canSpawnAtPosition(platform.x)) { var chest = new TreasureChest(); chest.x = platform.x; chest.y = platform.y - 130; chest.currentPlatform = platform; collectibles.push(chest); // Add to collectibles array game.addChild(chest); } } chestSpawnCounter = 0; } // Replace the existing jar update code with this: for (var i = collectibles.length - 1; i >= 0; i--) { var collectible = collectibles[i]; if (collectible.currentPlatform) { collectible.x = collectible.currentPlatform.x; } var attackBounds = player.getAttackBounds(); if (attackBounds) { var itemBounds = { left: collectible.x - 50, right: collectible.x + 50, top: collectible.y - 75, bottom: collectible.y + 75 }; if (attackBounds.left < itemBounds.right && attackBounds.right > itemBounds.left && attackBounds.top < itemBounds.bottom && attackBounds.bottom > itemBounds.top) { collectible["break"](); collectibles.splice(i, 1); continue; } } if (collectible.x < -50) { collectible.destroy(); collectibles.splice(i, 1); } } // Update coins for (var i = coins.length - 1; i >= 0; i--) { coins[i].update(); if (coins[i].destroyed) { coins.splice(i, 1); } } for (var i = game.children.length - 1; i >= 0; i--) { var child = game.children[i]; if (child instanceof ScorePopup) { child.update(); } } // Handle goblin spawning goblinSpawnCounter++; if (goblinSpawnCounter >= goblinSpawnInterval) { var availablePlatforms = platforms.filter(function (p) { return p.x > 2048 - 100 && p.x < 2048 + 300; }); if (availablePlatforms.length > 0) { var enemy = new Enemy('goblin'); var platform = availablePlatforms[Math.floor(Math.random() * availablePlatforms.length)]; enemy.x = platform.x; enemy.y = platform.y - ENEMY_PLATFORM_OFFSET; enemy.currentPlatform = platform; enemies.push(enemy); game.addChild(enemy); goblinSpawnInterval = Math.floor(Math.random() * 150) + 100; goblinSpawnCounter = 0; } else { // No valid platforms, just reset counter but don't spawn goblinSpawnCounter = Math.max(0, goblinSpawnCounter - 20); // Back up a bit to try again soon } } // Handle eyeball spawning eyeballSpawnCounter++; if (eyeballSpawnCounter >= eyeballSpawnInterval) { var enemy = new Enemy('eyeball'); var randomHeight = Math.random() * 400 + 200; enemy.x = 2048 + 100; enemy.y = highPlatformHeight - randomHeight; enemies.push(enemy); game.addChild(enemy); eyeballSpawnInterval = Math.floor(Math.random() * 300) + 150; eyeballSpawnCounter = 0; } // Update enemies for (var j = enemies.length - 1; j >= 0; j--) { enemies[j].update(); var playerBounds = player.getBounds(); var enemyBounds = enemies[j].getBounds(); var attackBounds = player.getAttackBounds(); // Add check if enemy is behind player if (enemies[j].x < player.x - 100) { // Added 100px buffer continue; // Skip collision checks for enemies behind player } // Check for attack collision first if (attackBounds && !enemies[j].isHit && !enemies[j].isDying) { if (enemies[j].x > player.x && attackBounds.left < enemyBounds.right && attackBounds.right > enemyBounds.left && attackBounds.top < enemyBounds.bottom && attackBounds.bottom > enemyBounds.top) { enemies[j].hit(); if (enemies[j].type === 'eyeball') { LK.getSound('eyeballhit').play(); } else { LK.getSound('enemyhit').play(); } continue; } } // Check for body collision second if (playerBounds.left < enemyBounds.right && playerBounds.right > enemyBounds.left && playerBounds.top < enemyBounds.bottom && playerBounds.bottom > enemyBounds.top) { if (!enemies[j].isHit && !enemies[j].isDying) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); } } } }; // Handle player jump game.down = function (x, y, obj) { touchStartX = x; touchStartY = y; }; game.up = function (x, y, obj) { if (!gameStarted) { var buttonBounds = { left: playButton.x - playButton.width / 2, right: playButton.x + playButton.width / 2, top: playButton.y - playButton.height / 2, bottom: playButton.y + playButton.height / 2 }; if (x >= buttonBounds.left && x <= buttonBounds.right && y >= buttonBounds.top && y <= buttonBounds.bottom) { // Start the game startGame(); } return; // Early return if game hasn't started } // Original game.up code for handling player actions touchEndX = x; touchEndY = y; // Calculate swipe var deltaY = touchStartY - touchEndY; var deltaX = Math.abs(touchStartX - touchEndX); // If vertical swipe (more vertical than horizontal movement) if (deltaY > 50 && deltaY > deltaX) { player.jump(); } else { // Regular tap/click triggers attack player.attack(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Coin = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'coin';
// Create sprite based on type
self.sprite = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFFFFFF // No tint for gems
});
self.velocityX = 0;
self.velocityY = 0;
self.collected = false;
self.bounceCount = 0;
self.maxBounces = 2;
// Get value based on type
self.getValue = function () {
switch (self.type) {
case 'diamond':
return 10;
case 'emerald':
return 5;
case 'ruby':
return 3;
default:
return 1;
}
};
// Rest of the existing Coin code...
// Make sure to use self.getValue() in the collect function
self.collect = function () {
if (!self.collected) {
self.collected = true;
var value = self.getValue();
scoreManager.addScore(value, self.x, self.y);
LK.getSound('coincollect').play();
self.destroy();
}
};
self.update = function () {
if (self.collected) {
return;
}
// Apply physics
self.velocityY += 0.5; // gravity
self.x += self.velocityX;
self.y += self.velocityY;
// Check for platform collision with bounce
// Only bounce if we're moving downward and hit a platform
if (self.velocityY > 0 && self.checkPlatformCollision()) {
if (self.bounceCount < self.maxBounces) {
LK.getSound('coinbounce').play();
var impactSpeed = Math.abs(self.velocityY);
self.velocityY = -(impactSpeed * 0.5); // Use half of impact speed
self.velocityX *= 0.8;
self.bounceCount++;
} else {
self.velocityY = 0;
self.velocityX = -5; // Match platform speed
}
}
// Check if off screen
if (self.x < -50 || self.x > 2048 + 50 || self.y > 2732) {
self.destroy();
}
// Player collection detection
var playerBounds = player.getBounds();
var coinBounds = {
left: self.x - 25,
right: self.x + 25,
top: self.y - 25,
bottom: self.y + 25
};
if (playerBounds.left < coinBounds.right && playerBounds.right > coinBounds.left && playerBounds.top < coinBounds.bottom && playerBounds.bottom > coinBounds.top) {
self.collect();
}
};
self.checkPlatformCollision = function () {
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (Math.abs(self.y - (platform.y - 80)) < 10 && self.x > platform.x - 500 && self.x < platform.x + 500) {
self.y = platform.y - 80;
return true;
}
}
return false;
};
return self;
});
var Enemy = Container.expand(function (type) {
var self = Container.call(this);
// Enemy properties
self.type = type || 'basic';
self.speed = 7;
self.isOnGround = true;
self.velocityY = 0;
self.currentPlatform = null;
self.groundY = 2732 / 1.5; // Same as player ground Y
self.hitAnimation = ['goblinhit1'];
self.dieAnimation = ['goblindie1', 'goblindie2', 'goblindie3', 'goblindie4'];
self.isHit = false;
self.isDying = false;
self.deathTimer = 0;
self.throwBackSpeed = 15; // Initial backwards throw speed
self.throwBackDistance = 0; // Track distance thrown
self.maxThrowBack = 200; // Maximum throw back distance
// Add bounding box properties
self.hitboxWidth = 200; // Smaller than the 150px sprite width
self.hitboxHeight = 260; // Adjusted for goblin height
// Animation properties for goblin
self.runAnimation = [];
self.runFrame = 0;
self.animationSpeed = 0.08;
self.animationCounter = 0;
self.sprites = [];
// Add eyeball-specific properties
self.isFlying = type === 'eyeball';
self.flyingHeight = 0;
self.verticalSpeed = 2; // Speed of vertical adjustment
self.maxVerticalSpeed = 4; // Maximum vertical speed
self.homingDelay = 80; // Wait 60 frames before homing
self.homingTimer = 0; // Track how long the eyeball has been alive
// Add eyeball animations
self.flyAnimation = ['eyefly1', 'eyefly2', 'eyefly3', 'eyefly4', 'eyefly5', 'eyefly6', 'eyefly7', 'eyefly8'];
self.flyFrame = 0;
// Initialize based on enemy type
if (self.type === 'eyeball') {
// Eyeball animations
self.flyAnimation = ['eyefly1', 'eyefly2', 'eyefly3', 'eyefly4', 'eyefly5', 'eyefly6', 'eyefly7', 'eyefly8'];
self.hitAnimation = ['eyedie1', 'eyedie2'];
self.dieAnimation = ['eyedie3', 'eyedie4', 'eyedie5'];
} else if (self.type === 'goblin') {
// Goblin animations
self.runAnimation = ['goblinrun1', 'goblinrun2', 'goblinrun3', 'goblinrun4', 'goblinrun5', 'goblinrun6', 'goblinrun7', 'goblinrun8'];
self.hitAnimation = ['goblinhit1'];
self.dieAnimation = ['goblindie1', 'goblindie2', 'goblindie3', 'goblindie4'];
}
// Initialize based on enemy type
if (self.type === 'goblin') {
// Setup all animations
self.runAnimation = ['goblinrun1', 'goblinrun2', 'goblinrun3', 'goblinrun4', 'goblinrun5', 'goblinrun6', 'goblinrun7', 'goblinrun8'];
// Pre-attach all animation frames
// Run animation
for (var i = 0; i < self.runAnimation.length; i++) {
var sprite = self.attachAsset(self.runAnimation[i], {
anchorX: 0.5,
anchorY: 0.5
});
sprite.alpha = i === 0 ? 1 : 0;
self.sprites.push(sprite);
}
// Hit animation
for (var i = 0; i < self.hitAnimation.length; i++) {
var sprite = self.attachAsset(self.hitAnimation[i], {
anchorX: 0.5,
anchorY: 0.5
});
sprite.alpha = 0;
self.sprites.push(sprite);
}
// Die animation
for (var i = 0; i < self.dieAnimation.length; i++) {
var sprite = self.attachAsset(self.dieAnimation[i], {
anchorX: 0.5,
anchorY: 0.5
});
sprite.alpha = 0;
self.sprites.push(sprite);
}
} else if (self.type === 'eyeball') {
// First add fly animations (8 frames)
for (var i = 0; i < self.flyAnimation.length; i++) {
var sprite = self.attachAsset(self.flyAnimation[i], {
anchorX: 0.5,
anchorY: 0.5
});
sprite.alpha = i === 0 ? 1 : 0;
self.sprites.push(sprite);
}
// Then hit animations (2 frames)
for (var i = 0; i < self.hitAnimation.length; i++) {
var sprite = self.attachAsset(self.hitAnimation[i], {
anchorX: 0.5,
anchorY: 0.5
});
sprite.alpha = 0;
self.sprites.push(sprite);
}
// Then die animations (3 frames)
for (var i = 0; i < self.dieAnimation.length; i++) {
var sprite = self.attachAsset(self.dieAnimation[i], {
anchorX: 0.5,
anchorY: 0.5
});
sprite.alpha = 0;
self.sprites.push(sprite);
}
// Adjust hitbox for eyeball
self.hitboxWidth = 200;
self.hitboxHeight = 90;
// Flying enemies don't use ground physics
self.isOnGround = false;
} else {
// Basic enemy (original version)
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5
});
}
self.checkPlatformCollision = function () {
var onAnyPlatform = false;
var platformHalfWidth = 500;
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var leftEdge = platform.x - platformHalfWidth;
var rightEdge = platform.x + platformHalfWidth;
// First check if we're on a platform (exact position check)
if (self.x >= leftEdge && self.x <= rightEdge) {
if (Math.abs(self.y - (platform.y - ENEMY_PLATFORM_OFFSET)) < 5) {
onAnyPlatform = true;
self.currentPlatform = platform;
self.y = platform.y - ENEMY_PLATFORM_OFFSET;
self.isOnGround = true;
self.velocityY = 0;
return true;
}
// NEW CODE: Check for passing through platform during fall
// This detects if the enemy will cross the platform in the next frame
if (self.velocityY > 0 &&
// Must be falling down
self.y < platform.y - ENEMY_PLATFORM_OFFSET && self.y + self.velocityY >= platform.y - ENEMY_PLATFORM_OFFSET) {
self.y = platform.y - ENEMY_PLATFORM_OFFSET;
self.velocityY = 0;
self.isOnGround = true;
self.currentPlatform = platform;
return true;
}
}
}
if (!onAnyPlatform) {
self.isOnGround = false;
self.currentPlatform = null;
}
return false;
};
// Update collision check method
self.getBounds = function () {
return {
left: self.x - self.hitboxWidth / 2,
right: self.x + self.hitboxWidth / 2,
top: self.y - self.hitboxHeight / 2,
bottom: self.y + self.hitboxHeight / 2
};
};
self.hit = function () {
if (!self.isHit && !self.isDying) {
self.isHit = true;
self.throwBackSpeed = 25; // Increased from 25 for more distance
self.throwBackDistance = 0;
self.hitTimer = 35; // Added hit timer for longer hit frame
// Add particle effect here
var particleOffset = self.type === 'eyeball' ? 175 : 250; // smaller offset for eyeballs
particleSystem.emitFromHit(self.x + particleOffset, self.y, player.x);
}
};
self.update = function () {
// Hide all sprites first
for (var i = 0; i < self.sprites.length; i++) {
self.sprites[i].alpha = 0;
}
if (self.type === 'eyeball' && (self.isHit || self.isDying)) {
// First handle the hit state
if (self.isHit) {
var hitOffset = self.flyAnimation.length;
self.throwBackDistance += Math.abs(self.throwBackSpeed);
self.x += self.throwBackSpeed;
self.throwBackSpeed *= 0.95;
// Show hit animation (eyedie1, eyedie2)
var hitFrame = Math.floor(self.hitTimer / 100) % 2;
self.sprites[hitOffset + hitFrame].alpha = 1;
self.hitTimer--;
if (self.hitTimer <= 0) {
self.isHit = false;
self.isDying = true;
self.deathTimer = 180; // 3 seconds for death sequence
self.deathFrame = 0; // Start at first death frame
}
}
// Then handle the dying state
else if (self.isDying) {
var dieOffset = self.flyAnimation.length + self.hitAnimation.length;
// Always check for ground collision during fall
if (!self.isOnGround) {
self.velocityY += 0.5;
self.y += self.velocityY;
}
//self.x -= 5; // Match platform speed
// Progress through death frames
if (self.deathTimer > 120) {
self.sprites[dieOffset].alpha = 1; // eyedie3
} else if (self.deathTimer > 60) {
self.sprites[dieOffset + 1].alpha = 1; // eyedie4
} else {
self.sprites[dieOffset + 2].alpha = 1; // eyedie5
}
self.deathTimer--;
if (self.deathTimer <= 0) {
self.alpha -= 0.05;
if (self.alpha <= 0) {
self.destroy();
}
}
}
return; // Skip regular animation updates
} else if (self.type === 'eyeball') {
self.x -= self.speed;
// Only start homing after delay
if (self.homingTimer >= self.homingDelay) {
// Home toward player
var deltaY = player.y - self.y;
self.velocityY += deltaY > 0 ? 0.2 : -0.2;
self.velocityY = Math.max(-self.maxVerticalSpeed, Math.min(self.maxVerticalSpeed, self.velocityY));
} else {
// Before homing, just maintain height with slight wave motion
self.velocityY = Math.sin(self.homingTimer * 0.05) * 2;
self.homingTimer++;
}
self.y += self.velocityY;
// Animate
self.animationCounter += self.animationSpeed;
if (self.animationCounter >= 1) {
self.animationCounter = 0;
self.flyFrame = (self.flyFrame + 1) % self.flyAnimation.length;
}
self.sprites[self.flyFrame].alpha = 1;
// Check if off screen
if (self.x < -50 || self.y > 2732) {
self.destroy();
}
} else {
if (self.isHit) {
// Handle throw back motion
self.x += self.throwBackSpeed;
self.throwBackDistance += Math.abs(self.throwBackSpeed);
self.throwBackSpeed *= 0.95; // Slower decay than 0.9
// Show hit animation
var hitOffset = self.runAnimation.length;
self.sprites[hitOffset].alpha = 1;
// Decrease hit timer
self.hitTimer--;
// Once hit timer expires, start death animation
if (self.hitTimer <= 0) {
self.isHit = false;
self.isDying = true;
self.deathTimer = 60; // Increased to 60 frames
self.deathFrame = 0; // Explicitly track which frame we're on
}
} else if (self.isDying) {
// Continue throw back during death
self.x += self.throwBackSpeed;
// After halfway through death animation, match platform speed
if (self.deathFrame >= 2) {
// Since we have 4 frames, 2 is halfway
self.x -= 5; // Platform speed is defined as 5
}
self.throwBackSpeed *= 0.95;
// Removed vertical movement code
// Handle death animation
var dieOffset = self.runAnimation.length + self.hitAnimation.length;
// Progress frame every 15 frames (60/4 frames = 15)
if (self.deathTimer % 15 === 0 && self.deathFrame < self.dieAnimation.length - 1) {
self.deathFrame++;
}
var dieOffset = self.runAnimation.length + self.hitAnimation.length;
self.sprites[dieOffset + self.deathFrame].alpha = 1;
// Count down death timer
self.deathTimer--;
// After timer expires, fade out
if (self.deathTimer <= 0) {
self.alpha -= 0.1;
if (self.alpha <= 0) {
self.destroy();
}
}
} else {
// Original movement and animation code
// Move left
self.x -= self.speed;
// Original platform and gravity code
if (!self.isOnGround) {
self.velocityY += 0.7;
self.y += self.velocityY;
if (!self.checkPlatformCollision()) {
// Let them fall if not on platform
}
}
if (self.currentPlatform) {
var platformHalfWidth = 500; // Match the existing platform width constant
var stillOnPlatform = self.x >= self.currentPlatform.x - platformHalfWidth && self.x <= self.currentPlatform.x + platformHalfWidth;
if (!stillOnPlatform) {
var foundAnotherPlatform = false;
// Check if there's another platform we might have moved to
for (var i = 0; i < platforms.length; i++) {
var otherPlatform = platforms[i];
if (otherPlatform === self.currentPlatform) {
continue;
}
if (self.x >= otherPlatform.x - platformHalfWidth && self.x <= otherPlatform.x + platformHalfWidth && Math.abs(self.y - (otherPlatform.y - ENEMY_PLATFORM_OFFSET)) < 5) {
// Found another platform at the same height
self.currentPlatform = otherPlatform;
foundAnotherPlatform = true;
break;
}
}
// If no other platform found, start falling
if (!foundAnotherPlatform) {
self.isOnGround = false;
self.currentPlatform = null;
// Start falling with initial velocity
if (self.velocityY === 0) {
self.velocityY = 0.1;
}
}
}
}
// Handle run animation
if (self.type === 'goblin') {
self.animationCounter += self.animationSpeed;
if (self.animationCounter >= 1) {
self.animationCounter = 0;
self.runFrame = (self.runFrame + 1) % self.runAnimation.length;
}
self.sprites[self.runFrame].alpha = 1;
}
}
// Destroy if off screen
if (self.x < -50 || self.y > 2732) {
self.destroy();
}
}
};
});
var Jar = Container.expand(function () {
var self = Container.call(this);
// Attach jar sprite
self.sprite = self.attachAsset('jar', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xC0C0C0 // Change tint to an even lighter grey
});
self.isBreaking = false;
self.currentPlatform = null;
self["break"] = function () {
if (self.isBreaking) {
return;
}
self.isBreaking = true;
// Spawn jar pieces (keep existing piece code)
for (var i = 1; i <= 4; i++) {
var piece = new JarPiece(i);
piece.x = self.x;
piece.y = self.y;
piece.velocityX = Math.random() * 10 - 5;
piece.velocityY = -(Math.random() * 10 + 5);
piece.rotationSpeed = Math.random() * 0.2 - 0.1;
game.addChild(piece);
}
// Modified coin spawning with more forward motion
var coinCount = Math.floor(Math.random() * 8) + 1;
for (var i = 0; i < coinCount; i++) {
var coin = new Coin();
coin.x = self.x;
coin.y = self.y;
// More forward motion and higher initial jump
coin.velocityX = Math.random() * 8 + 4; // Minimum 4, maximum 12 right velocity
coin.velocityY = -(Math.random() * 10 + 12); // Higher jump
game.addChild(coin);
coins.push(coin);
}
LK.getSound('jarbreak').play();
self.destroy();
};
return self;
});
var JarPiece = Container.expand(function (pieceNum) {
var self = Container.call(this);
self.sprite = self.attachAsset('jarpiece' + pieceNum, {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xC0C0C0 // Apply grey tint
});
self.velocityX = 0;
self.velocityY = 0;
self.rotationSpeed = 0;
self.fadeSpeed = 0.02;
self.bounceCount = 0;
self.maxBounces = 2; // Number of bounces before stopping
self.update = function () {
// Apply physics
self.velocityY += 0.5; // gravity
self.x += self.velocityX;
self.y += self.velocityY;
self.rotation += self.rotationSpeed;
// Check for platform collision with bounce
if (self.checkPlatformCollision()) {
if (self.bounceCount < self.maxBounces) {
// Bounce with reduced velocity
self.velocityY = -(self.velocityY * 0.4); // 40% of original velocity
self.velocityX *= 0.8; // Reduce horizontal speed
self.bounceCount++;
} else {
// Stop moving after max bounces
self.velocityY = 0;
self.velocityX = -5; // Match platform speed
// Start fading
self.alpha -= self.fadeSpeed;
if (self.alpha <= 0) {
self.destroy();
}
}
}
// Destroy if off screen
if (self.x < -50 || self.y > 2732) {
self.destroy();
}
};
self.checkPlatformCollision = function () {
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (Math.abs(self.y - (platform.y - 80)) < 10 && self.x > platform.x - 500 && self.x < platform.x + 500) {
self.y = platform.y - 80;
return true;
}
}
return false;
};
return self;
});
var ParticlePool = Container.expand(function (maxParticles) {
var self = Container.call(this);
self.particles = [];
self.activeParticles = [];
self.redTints = [0xff0000, 0xff3333, 0xcc0000];
for (var i = 0; i < maxParticles; i++) {
var particle = self.attachAsset('pixel', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2,
// 4% of original size (4px from 100px)
scaleY: 0.2 // 4% of original size (4px from 100px)
});
particle.alpha = 0;
particle.velocityX = 0;
particle.velocityY = 0;
particle.lifespan = 0;
particle.fadeSpeed = 0;
self.particles.push(particle);
}
self.emitFromHit = function (x, y, playerX) {
var directionX = x - playerX;
var directionSign = Math.sign(directionX);
for (var i = 0; i < 20; i++) {
if (self.particles.length === 0) {
break;
}
var particle = self.particles.pop();
self.activeParticles.push(particle);
particle.x = x;
particle.y = y;
particle.alpha = 1;
particle.tint = self.redTints[Math.floor(Math.random() * self.redTints.length)];
// Set scale instead of width/height
var particleSize = Math.random() * 0.2 + 0.2; // 2-4% of original size
particle.scaleX = particleSize;
particle.scaleY = particleSize;
var angle = Math.random() * Math.PI / 2 - Math.PI / 4;
var speed = Math.random() * 5 + 10;
particle.velocityX = Math.cos(angle) * speed * directionSign;
particle.velocityY = Math.sin(angle) * speed;
particle.lifespan = 100;
particle.fadeSpeed = 1 / 60;
}
};
self.update = function () {
for (var i = self.activeParticles.length - 1; i >= 0; i--) {
var particle = self.activeParticles[i];
particle.x += particle.velocityX;
particle.y += particle.velocityY;
particle.alpha -= particle.fadeSpeed;
particle.lifespan--;
if (particle.lifespan <= 0 || particle.alpha <= 0) {
particle.alpha = 0;
self.activeParticles.splice(i, 1);
self.particles.push(particle);
}
}
};
return self;
});
var Platform = Container.expand(function () {
var self = Container.call(this);
var platformGraphics = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.passed = false;
self.update = function () {
self.x -= self.speed;
if (self.x < -500) {
// Increased value to ensure platforms are fully off-screen
self.destroy();
}
};
});
//<Assets used in the game will automatically appear here>
var Player = Container.expand(function () {
var self = Container.call(this);
// Animation properties
self.runAnimation = ['playerrun1', 'playerrun2', 'playerrun3', 'playerrun4', 'playerrun5', 'playerrun6'];
self.jumpAnimation = ['playerjump1', 'playerjump2', 'playerjump3'];
self.attackAnimation = ['playerattack1', 'playerattack2', 'playerattack3', 'playerattack4', 'playerattack5'];
self.isAttacking = false;
self.attackFrame = 0;
self.runFrame = 0;
self.animationSpeed = 0.08;
self.attackAnimationSpeed = 0.15; // Higher number = faster animation
self.animationCounter = 0;
self.sprites = [];
self.groundY = 2732 * 0.9; // Move ground much lower to allow falling from all platforms
// Add bounding box properties
self.hitboxWidth = 150; // Smaller than the 600px animation frames
self.hitboxHeight = 300; // Adjusted for player height
self.attackHitboxWidth = 200; // Width of attack hitbox
self.attackHitboxHeight = 400; // Height of attack hitbox
self.attackHitboxOffset = 50; // How far in front of player the attack hitbox extends
// Platform collision properties
self.isOnGround = true;
self.currentPlatform = null;
// Pre-attach all animation frames but make only the first one visible
// First add run animation sprites
for (var i = 0; i < self.runAnimation.length; i++) {
var sprite = self.attachAsset(self.runAnimation[i], {
anchorX: 0.5,
anchorY: 0.5
});
// Set all frames except the first to be invisible
sprite.alpha = i === 0 ? 1 : 0;
self.sprites.push(sprite);
}
// Then add jump animation sprites
for (var i = 0; i < self.jumpAnimation.length; i++) {
var sprite = self.attachAsset(self.jumpAnimation[i], {
anchorX: 0.5,
anchorY: 0.5
});
// Set all jump frames to invisible initially
sprite.alpha = 0;
self.sprites.push(sprite);
}
for (var i = 0; i < self.attackAnimation.length; i++) {
var sprite = self.attachAsset(self.attackAnimation[i], {
anchorX: 0.5,
anchorY: 0.5
});
sprite.alpha = 0;
self.sprites.push(sprite);
}
// Movement properties
self.speed = 5;
self.jumpHeight = 40; // Keeping the original jump height
self.isJumping = false;
self.velocityY = 0;
self.jumpState = "none"; // Added to track jump animation phases
self.jumpStartTime = 0;
// Add method to get actual collision bounds
self.getBounds = function () {
return {
left: self.x - self.hitboxWidth / 2,
right: self.x + self.hitboxWidth / 2,
top: self.y - self.hitboxHeight / 2,
bottom: self.y + self.hitboxHeight / 2
};
};
self.update = function () {
// Hide all sprites first
for (var i = 0; i < self.sprites.length; i++) {
self.sprites[i].alpha = 0;
}
// Handle platform collision and falling physics first
if (!self.isOnGround && !self.isJumping) {
self.velocityY += 0.7;
self.y += self.velocityY;
self.checkPlatformCollision();
}
// Handle jumping physics
if (self.isJumping) {
self.y += self.velocityY;
self.velocityY += 0.7;
// Get jump frame index offset
var jumpOffset = self.runAnimation.length;
// Check for landing on platforms while falling during a jump
self.checkPlatformCollision();
// End jump if hitting the original ground (for backward compatibility)
if (self.y >= self.groundY && !self.currentPlatform) {
self.y = self.groundY;
self.isJumping = false;
self.velocityY = 0;
self.jumpState = "none";
self.isOnGround = true;
}
}
// IMPORTANT: Platform collision check - runs EVERY frame
var onAnyPlatform = false;
var platformHalfWidth = 500; // half of platform width (1000/2)
// First, check platform collisions
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var leftEdge = platform.x - platformHalfWidth;
var rightEdge = platform.x + platformHalfWidth;
// Check if player is within horizontal bounds of platform
if (self.x >= leftEdge && self.x <= rightEdge) {
// If we're at platform height and not jumping
if (Math.abs(self.y - (platform.y - 250)) < 5 && !self.isJumping) {
onAnyPlatform = true;
self.currentPlatform = platform;
self.y = platform.y - 250;
self.isOnGround = true;
self.velocityY = 0;
break;
}
}
}
// Handle falling state
if (!onAnyPlatform && !self.isJumping) {
self.isOnGround = false;
self.currentPlatform = null;
// Apply gravity
if (self.velocityY === 0) {
self.velocityY = 0.1;
}
self.velocityY += 0.1;
self.y += self.velocityY;
// Ground collision check comes AFTER falling movement
if (self.y >= self.groundY) {
// Reached the bottom of the screen - game over
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
// Now handle animations - attack takes priority if active
if (self.isAttacking) {
var attackOffset = self.runAnimation.length + self.jumpAnimation.length;
self.animationCounter += self.attackAnimationSpeed;
if (self.animationCounter >= 1) {
self.animationCounter = 0;
self.attackFrame++;
if (self.attackFrame >= self.attackAnimation.length) {
self.isAttacking = false;
self.attackFrame = 0;
}
}
self.sprites[attackOffset + self.attackFrame].alpha = 1;
}
// If not attacking, show jump or run animation
else if (self.isJumping || !self.isOnGround) {
var jumpOffset = self.runAnimation.length;
var currentTime = Date.now();
if (currentTime - self.jumpStartTime < 100) {
self.sprites[jumpOffset + 0].alpha = 1;
} else if (self.velocityY < 0) {
self.sprites[jumpOffset + 1].alpha = 1;
} else if (self.velocityY > 0) {
self.sprites[jumpOffset + 2].alpha = 1;
}
} else if (self.isOnGround) {
self.animationCounter += self.animationSpeed;
if (self.animationCounter >= 1) {
self.animationCounter = 0;
self.runFrame = (self.runFrame + 1) % self.runAnimation.length;
}
self.sprites[self.runFrame].alpha = 1;
}
// If on a platform, check if we're still above it
if (self.currentPlatform) {
var platformHalfWidth = platformWidth / 2; // Use platformWidth constant
var stillOnPlatform = self.x > self.currentPlatform.x - platformHalfWidth && self.x < self.currentPlatform.x + platformHalfWidth;
if (!stillOnPlatform) {
var foundAnotherPlatform = false;
for (var i = 0; i < platforms.length; i++) {
var otherPlatform = platforms[i];
if (otherPlatform === self.currentPlatform) {
continue;
}
var otherHalfWidth = platformWidth / 2;
if (self.x > otherPlatform.x - otherHalfWidth && self.x < otherPlatform.x + otherHalfWidth) {
// We found another platform directly below player
self.currentPlatform = otherPlatform;
foundAnotherPlatform = true;
break;
}
}
// Only fall if we didn't find another platform
if (!foundAnotherPlatform) {
self.isOnGround = false;
self.currentPlatform = null;
// Start falling with initial velocity
self.velocityY = 0.1;
}
}
}
// Check if player has fallen off the bottom of the screen
if (self.y > 2732) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
};
self.getAttackBounds = function () {
// Only return attack bounds when actually attacking
if (!self.isAttacking) {
return null;
}
// Create a forward-facing hitbox
return {
left: self.x + (self.attackHitboxOffset - self.attackHitboxWidth / 2),
right: self.x + (self.attackHitboxOffset + self.attackHitboxWidth / 2),
top: self.y - self.attackHitboxHeight / 2,
bottom: self.y + self.attackHitboxHeight / 2
};
};
self.jump = function () {
if (self.isOnGround) {
self.isJumping = true;
self.isOnGround = false;
self.velocityY = -self.jumpHeight;
self.jumpState = "start";
self.jumpStartTime = Date.now();
LK.getSound('playerjump').play();
self.currentPlatform = null;
} else if (self.isJumping && self.velocityY < 10) {
// Allow for a small double-jump to reach higher platforms
// Only if not falling too fast
self.velocityY = -self.jumpHeight * 0.7;
self.jumpStartTime = Date.now();
}
};
self.attack = function () {
if (!self.isAttacking) {
self.isAttacking = true;
self.attackFrame = 0;
self.animationCounter = 0;
LK.getSound('swordslash').play();
}
};
self.checkPlatformCollision = function () {
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
var platformHalfWidth = platform.width / 2;
// The offset should match exactly how the player aligns with the lower platform initially
var playerPlatformOffset = 250; // This is the exact offset between player.y and lowPlatformHeight
// Check if player is above the platform and falling
if (self.velocityY > 0 &&
// Must be falling down
self.y < platform.y - playerPlatformOffset && self.y + self.velocityY >= platform.y - playerPlatformOffset && self.x > platform.x - platformHalfWidth && self.x < platform.x + platformHalfWidth) {
// Land on the platform with the exact same positioning as on the low platform
self.y = platform.y - playerPlatformOffset;
self.velocityY = 0;
self.isJumping = false;
self.isOnGround = true;
self.currentPlatform = platform;
return;
}
}
};
});
// Add this to your existing classes
var ScorePopup = Container.expand(function (x, y, amount) {
var self = Container.call(this);
// Create the text with the actual score amount
self.text = new Text2('+' + amount, {
size: 80,
fill: 0xFFFFFF,
anchorX: 0.5,
anchorY: 0.5
});
self.addChild(self.text);
self.x = x;
self.y = y;
self.velocityY = -3;
self.lifespan = 45;
self.update = function () {
self.y += self.velocityY;
self.lifespan--;
if (self.lifespan < 15) {
self.alpha -= 0.07;
}
if (self.alpha <= 0 || self.lifespan <= 0) {
self.destroy();
}
};
return self;
});
var Torch = Container.expand(function () {
var self = Container.call(this);
// Create base torch sprite
self.base = self.attachAsset('torch', {
anchorX: 0.5,
anchorY: 1 // Anchor at bottom
});
// Create flame sprite
self.flame = self.attachAsset('torchflame', {
anchorX: 0.5,
anchorY: 1,
// Anchor at bottom to scale from base
y: -180 // Position at top of torch
});
// Create aura sprite
self.aura = self.attachAsset('torchaura', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3,
// Start with low opacity
y: -250 // Match flame position
});
// Animation properties
self.flameTime = Math.random() * Math.PI * 2; // Random start phase
self.auraTime = Math.random() * Math.PI * 2;
self.flameSpeed = 0.05;
self.auraSpeed = 0.03;
// Update animation
self.update = function () {
// Animate flame scale
self.flameTime += self.flameSpeed;
var flameScale = 1 + Math.sin(self.flameTime) * 0.2; // Scale between 0.8 and 1.2
self.flame.scaleY = flameScale;
// Random flip chance for flame
if (Math.random() < 0.02) {
// 2% chance per frame
self.flame.scaleX *= -1;
}
// Animate aura alpha
self.auraTime += self.auraSpeed;
var auraAlpha = 0.3 + Math.sin(self.auraTime) * 0.15; // Pulse between 0.15 and 0.45
self.aura.alpha = auraAlpha;
};
return self;
});
var TreasureChest = Container.expand(function () {
var self = Container.call(this);
// Attach chest sprite
self.sprite = self.attachAsset('treasurechest', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xC0C0C0 // Change tint to match jar's grey tint
});
self.isBreaking = false;
self.currentPlatform = null;
self["break"] = function () {
if (self.isBreaking) {
return;
}
self.isBreaking = true;
// Spawn chest pieces
for (var i = 1; i <= 4; i++) {
var piece = new TreasureChestPiece(i);
piece.x = self.x;
piece.y = self.y;
piece.velocityX = Math.random() * 12 - 6;
piece.velocityY = -(Math.random() * 12 + 6);
piece.rotationSpeed = Math.random() * 0.2 - 0.1;
game.addChild(piece);
}
// Spawn valuables
var totalItems = Math.floor(Math.random() * 6) + 3; // 3-8 items
for (var i = 0; i < totalItems; i++) {
// Random chance for different gems
var rand = Math.random();
var item;
if (rand < 0.05) {
// 5% diamond
item = new Coin('diamond');
} else if (rand < 0.15) {
// 10% emerald
item = new Coin('emerald');
} else if (rand < 0.30) {
// 15% ruby
item = new Coin('ruby');
} else {
// 70% gold coin
item = new Coin('coin');
}
item.x = self.x;
item.y = self.y;
item.velocityX = Math.random() * 10 + 2;
item.velocityY = -(Math.random() * 12 + 14);
game.addChild(item);
coins.push(item);
}
LK.getSound('woodbreak').play();
self.destroy();
};
return self;
});
var TreasureChestPiece = Container.expand(function (pieceNum) {
var self = Container.call(this);
self.sprite = self.attachAsset('treasurechestpiece' + pieceNum, {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xC0C0C0 // Change tint to match jar's grey tint
});
self.velocityX = 0;
self.velocityY = 0;
self.rotationSpeed = 0;
self.fadeSpeed = 0.02;
self.bounceCount = 0;
self.maxBounces = 2;
self.update = function () {
self.velocityY += 0.5; // gravity
self.x += self.velocityX;
self.y += self.velocityY;
self.rotation += self.rotationSpeed;
if (self.checkPlatformCollision()) {
if (self.bounceCount < self.maxBounces) {
self.velocityY = -(self.velocityY * 0.4);
self.velocityX *= 0.8;
self.bounceCount++;
} else {
self.velocityY = 0;
self.velocityX = -5;
self.alpha -= self.fadeSpeed;
if (self.alpha <= 0) {
self.destroy();
}
}
}
if (self.x < -50 || self.y > 2732) {
self.destroy();
}
};
self.checkPlatformCollision = function () {
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (Math.abs(self.y - (platform.y - 80)) < 10 && self.x > platform.x - 500 && self.x < platform.x + 500) {
self.y = platform.y - 80;
return true;
}
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000 // Black background
});
/****
* Game Code
****/
var ScoreManager = function ScoreManager() {
var self = {};
// Initialize score and UI
self.score = 0;
self.scoreText = new Text2('0', {
size: 160,
fill: 0xFFFFFF,
anchorX: 1,
anchorY: 0.5
});
self.coinIcon = LK.getAsset('coin', {
anchorX: 0,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
// Initialize container
self.container = new Container();
self.container.addChild(self.scoreText);
self.container.addChild(self.coinIcon);
// Position container
self.container.x = 2048 - 100;
self.container.y = 100;
// Position elements
self.scoreText.x = -100;
self.scoreText.y = -100;
self.coinIcon.x = 0;
self.coinIcon.y = 0;
// Getter and setter for score
self.getScore = function () {
return self.score;
};
self.setScore = function (newScore) {
self.score = newScore;
self.scoreText.setText(newScore);
// Adjust position based on digit count
if (newScore >= 10 && newScore < 100) {
self.scoreText.x = -200; // Adjust for 2 digits
} else if (newScore >= 100 && newScore < 1000) {
self.scoreText.x = -300; // Adjust for 3 digits
} else if (newScore >= 1000) {
self.scoreText.x = -400; // Adjust for 4+ digits
} else {
self.scoreText.x = -100; // Default for single digit
}
};
// Add score and display popup
self.addScore = function (amount, x, y) {
self.setScore(self.score + amount);
LK.setScore(self.score); // Update LK score
// Create score popup if position is provided
if (x !== undefined && y !== undefined) {
var popup = new ScorePopup(x, y - 30, amount);
game.addChild(popup);
}
};
return self;
};
var backgroundContainer = game.addChild(new Container());
var midgroundContainer = game.addChild(new Container());
var foregroundContainer = game.addChild(new Container());
var scoreManager = new ScoreManager();
game.addChild(scoreManager.container);
var scoreContainer = game.addChild(new Container());
var GAME_WIDTH = 2048;
var ENEMY_PLATFORM_OFFSET = 225; // Adjust this value
var gameStarted = false;
var titleScreen;
var playButton; // Define playButton in the global scope
var platforms = [];
var platformWidth = 1000; // Define platform width based on asset size
var platformSpawnInterval = 60;
var platformSpawnCounter = 0;
var platformOverlap = 50;
var platformSpeed = 5; // Define platform speed globally
var platformSpawnInterval = 190;
var chestSpawnInterval = 100; // Longer than jar interval
var chestSpawnCounter = 0;
// = (1000 - 50) / 5 = 190
// Define the two fixed platform heights
var lowPlatformHeight = 2732 / 1.5 + 250; // Regular height (player.y + 250)
var highPlatformHeight = lowPlatformHeight - 600; // High platform (600 pixels higher)
var minPlatformsInSequence = 2; // Minimum platforms in a sequence
var maxPlatformsInSequence = 5; // Maximum platforms in a sequence
var platformsUntilNextChange = 5; // Initial longer ground sequence
var currentPlatformHeight = lowPlatformHeight;
var lastPlatformHeight = lowPlatformHeight;
// Simple toggle for alternating platform heights
var useHighPlatform = false;
var platformGap = 200; // Gap between platforms
var lastPlatformX = 0; // Track the last platform position
var touchStartX = 0;
var touchStartY = 0;
var touchEndX = 0;
var touchEndY = 0;
var jars = [];
var coins = [];
var collectibles = [];
var jarSpawnCounter = 0;
var jarSpawnInterval = 20; // Adjust as needed
var player;
// Initialize enemies
var enemies = [];
var enemySpawnInterval = 100;
var enemySpawnCounter = 0;
var goblinSpawnInterval = 100;
var goblinSpawnCounter = 0;
var eyeballSpawnInterval = 500; // Longer interval for eyeballs
var eyeballSpawnCounter = 150;
var particleSystem;
// Background layer (slowest)
var bg1 = backgroundContainer.addChild(LK.getAsset('background', {
anchorX: 0,
anchorY: 1
}));
var bg2 = backgroundContainer.addChild(LK.getAsset('background', {
anchorX: 0,
anchorY: 1
}));
bg1.y = 2732; // Position at bottom of screen
bg2.y = 2732;
bg2.x = GAME_WIDTH;
// Midground layer
var mg1 = midgroundContainer.addChild(LK.getAsset('midground', {
anchorX: 0,
anchorY: 1
}));
var mg2 = midgroundContainer.addChild(LK.getAsset('midground', {
anchorX: 0,
anchorY: 1
}));
mg1.y = 2732;
mg2.y = 2732;
mg2.x = GAME_WIDTH;
// Foreground layer (fastest)
var fg1 = foregroundContainer.addChild(LK.getAsset('foreground', {
anchorX: 0,
anchorY: 1
}));
var fg2 = foregroundContainer.addChild(LK.getAsset('foreground', {
anchorX: 0,
anchorY: 1
}));
fg1.y = 2732 * 1.25;
fg2.y = 2732 * 1.25;
fg1.x = 0;
fg2.x = GAME_WIDTH;
function createTitleScreen() {
titleScreen = new Container();
game.addChild(titleScreen);
// Add title image
var titleImage = titleScreen.attachAsset('title', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0 // Start with alpha 0 for fade-in effect
});
titleImage.x = 2048 / 2;
titleImage.y = 2732 / 2.7;
// Add fade-in animation for titleImage
tween(titleImage, {
alpha: 1
}, {
duration: 1000,
// 1 second fade-in duration
easing: tween.easeIn
});
// Add play button
playButton = titleScreen.attachAsset('playbutton', {
anchorX: 0.5,
anchorY: 0.5
});
playButton.x = 2048 / 2;
playButton.y = 2732 / 1.3;
// Add flashing animation to playButton
function flashPlayButton() {
tween(playButton, {
alpha: 0
}, {
duration: 250,
easing: tween.linear,
onFinish: function onFinish() {
tween(playButton, {
alpha: 1
}, {
duration: 250,
easing: tween.linear
});
}
});
}
// Set interval to flash every 2 seconds
LK.setInterval(flashPlayButton, 2000);
initializeTorches();
}
function canSpawnAtPosition(x, safeDistance) {
safeDistance = safeDistance || 200; // Minimum distance between objects
for (var i = 0; i < collectibles.length; i++) {
var existingItem = collectibles[i];
if (Math.abs(existingItem.x - x) < safeDistance) {
return false;
}
}
return true;
}
function initializeTorches() {
// Calculate number of torches needed based on screen width
var torchSpacing = GAME_WIDTH; // One torch per background width
// Create two torches for the two background sections
var torch1 = new Torch();
torch1.x = 25;
torch1.y = 2732 * 0.7; // Adjust Y position as needed
midgroundContainer.addChild(torch1);
var torch2 = new Torch();
torch2.x = GAME_WIDTH + 25;
torch2.y = 2732 * 0.7;
midgroundContainer.addChild(torch2);
}
// Initialize the game with starting platforms
function initializeGame() {
// Initialize player
player = game.addChild(new Player());
player.x = 2048 / 4.5;
player.y = 2732 / 1.5;
// Create initial platforms at the low level
for (var i = 0; i < 5; i++) {
var platform = new Platform();
if (i === 0) {
// First platform centered on player
platform.x = player.x;
} else {
// Position with slight overlap
platform.x = lastPlatformX + platformWidth - platformOverlap;
}
platform.y = lowPlatformHeight;
platforms.push(platform);
game.addChild(platform);
lastPlatformX = platform.x;
}
lastPlatformHeight = lowPlatformHeight;
player.isOnGround = true;
player.currentPlatform = platforms[0];
}
function startGame() {
gameStarted = true;
// Remove title screen
titleScreen.destroy();
// Initialize game elements
initializeGame();
// Initialize particle system
particleSystem = new ParticlePool(100);
game.addChild(particleSystem);
// Play background music
LK.playMusic('backgroundmusic1', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
}
createTitleScreen();
// Handle game updates
game.update = function () {
// Always scroll backgrounds for visual effect even on title screen
bg1.x -= platformSpeed * 0.3;
bg2.x -= platformSpeed * 0.3;
if (bg1.x <= -GAME_WIDTH) {
bg1.x = bg2.x + GAME_WIDTH;
}
if (bg2.x <= -GAME_WIDTH) {
bg2.x = bg1.x + GAME_WIDTH;
}
mg1.x -= platformSpeed * 0.6;
mg2.x -= platformSpeed * 0.6;
if (mg1.x <= -GAME_WIDTH) {
mg1.x = mg2.x + GAME_WIDTH;
}
if (mg2.x <= -GAME_WIDTH) {
mg2.x = mg1.x + GAME_WIDTH;
}
// Also scroll foreground on title screen
fg1.x -= platformSpeed;
fg2.x -= platformSpeed;
if (fg1.x <= -GAME_WIDTH) {
fg1.x = fg2.x + GAME_WIDTH;
}
if (fg2.x <= -GAME_WIDTH) {
fg2.x = fg1.x + GAME_WIDTH;
}
for (var i = 0; i < midgroundContainer.children.length; i++) {
var child = midgroundContainer.children[i];
if (child instanceof Torch) {
child.update();
// Move torch with midground
child.x -= platformSpeed * 0.6;
// Reset torch position when it goes off screen
if (child.x <= -GAME_WIDTH) {
child.x = child.x + GAME_WIDTH * 2;
}
}
}
if (!gameStarted) {
return;
}
player.update();
if (particleSystem) {
particleSystem.update();
}
// Check if we need to spawn a new sequence of platforms
var lastPlatform = platforms[platforms.length - 1];
if (lastPlatform && lastPlatform.x < GAME_WIDTH + 500) {
// Spawn further off-screen to prevent pop-in
// Time to spawn a new sequence
if (platformsUntilNextChange <= 0) {
// Switch height
currentPlatformHeight = currentPlatformHeight === lowPlatformHeight ? highPlatformHeight : lowPlatformHeight;
// Generate new random sequence length
platformsUntilNextChange = Math.floor(Math.random() * (maxPlatformsInSequence - minPlatformsInSequence + 1)) + minPlatformsInSequence;
// Make ground sequences longer
if (currentPlatformHeight === lowPlatformHeight) {
platformsUntilNextChange += 5;
}
}
// Spawn a single platform in the sequence
var platform = new Platform();
platform.x = lastPlatform.x + (platformWidth - platformOverlap);
platform.y = currentPlatformHeight;
platforms.push(platform);
game.addChild(platform);
// Decrement the counter for each platform added
platformsUntilNextChange--;
}
// Update platforms
for (var i = platforms.length - 1; i >= 0; i--) {
platforms[i].update();
// Remove platforms that are destroyed
if (platforms[i].destroyed) {
platforms.splice(i, 1);
}
}
jarSpawnCounter++;
if (jarSpawnCounter >= jarSpawnInterval) {
var availablePlatforms = platforms.filter(function (p) {
return p.x > 2048 && p.x < 2048 + 300;
});
if (availablePlatforms.length > 0 && Math.random() < 0.3) {
var platform = availablePlatforms[Math.floor(Math.random() * availablePlatforms.length)];
// Only spawn if position is clear
if (canSpawnAtPosition(platform.x)) {
var jar = new Jar();
jar.x = platform.x;
jar.y = platform.y - 130;
jar.currentPlatform = platform;
collectibles.push(jar); // Add to collectibles array instead of jars array
game.addChild(jar);
}
}
jarSpawnCounter = 0;
}
chestSpawnCounter++;
if (chestSpawnCounter >= chestSpawnInterval) {
var availablePlatforms = platforms.filter(function (p) {
return p.x > 2048 && p.x < 2048 + 300;
});
if (availablePlatforms.length > 0 && Math.random() < 0.15) {
// 15% chance to spawn
var platform = availablePlatforms[Math.floor(Math.random() * availablePlatforms.length)];
// Only spawn if position is clear
if (canSpawnAtPosition(platform.x)) {
var chest = new TreasureChest();
chest.x = platform.x;
chest.y = platform.y - 130;
chest.currentPlatform = platform;
collectibles.push(chest); // Add to collectibles array
game.addChild(chest);
}
}
chestSpawnCounter = 0;
}
// Replace the existing jar update code with this:
for (var i = collectibles.length - 1; i >= 0; i--) {
var collectible = collectibles[i];
if (collectible.currentPlatform) {
collectible.x = collectible.currentPlatform.x;
}
var attackBounds = player.getAttackBounds();
if (attackBounds) {
var itemBounds = {
left: collectible.x - 50,
right: collectible.x + 50,
top: collectible.y - 75,
bottom: collectible.y + 75
};
if (attackBounds.left < itemBounds.right && attackBounds.right > itemBounds.left && attackBounds.top < itemBounds.bottom && attackBounds.bottom > itemBounds.top) {
collectible["break"]();
collectibles.splice(i, 1);
continue;
}
}
if (collectible.x < -50) {
collectible.destroy();
collectibles.splice(i, 1);
}
}
// Update coins
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].update();
if (coins[i].destroyed) {
coins.splice(i, 1);
}
}
for (var i = game.children.length - 1; i >= 0; i--) {
var child = game.children[i];
if (child instanceof ScorePopup) {
child.update();
}
}
// Handle goblin spawning
goblinSpawnCounter++;
if (goblinSpawnCounter >= goblinSpawnInterval) {
var availablePlatforms = platforms.filter(function (p) {
return p.x > 2048 - 100 && p.x < 2048 + 300;
});
if (availablePlatforms.length > 0) {
var enemy = new Enemy('goblin');
var platform = availablePlatforms[Math.floor(Math.random() * availablePlatforms.length)];
enemy.x = platform.x;
enemy.y = platform.y - ENEMY_PLATFORM_OFFSET;
enemy.currentPlatform = platform;
enemies.push(enemy);
game.addChild(enemy);
goblinSpawnInterval = Math.floor(Math.random() * 150) + 100;
goblinSpawnCounter = 0;
} else {
// No valid platforms, just reset counter but don't spawn
goblinSpawnCounter = Math.max(0, goblinSpawnCounter - 20); // Back up a bit to try again soon
}
}
// Handle eyeball spawning
eyeballSpawnCounter++;
if (eyeballSpawnCounter >= eyeballSpawnInterval) {
var enemy = new Enemy('eyeball');
var randomHeight = Math.random() * 400 + 200;
enemy.x = 2048 + 100;
enemy.y = highPlatformHeight - randomHeight;
enemies.push(enemy);
game.addChild(enemy);
eyeballSpawnInterval = Math.floor(Math.random() * 300) + 150;
eyeballSpawnCounter = 0;
}
// Update enemies
for (var j = enemies.length - 1; j >= 0; j--) {
enemies[j].update();
var playerBounds = player.getBounds();
var enemyBounds = enemies[j].getBounds();
var attackBounds = player.getAttackBounds();
// Add check if enemy is behind player
if (enemies[j].x < player.x - 100) {
// Added 100px buffer
continue; // Skip collision checks for enemies behind player
}
// Check for attack collision first
if (attackBounds && !enemies[j].isHit && !enemies[j].isDying) {
if (enemies[j].x > player.x && attackBounds.left < enemyBounds.right && attackBounds.right > enemyBounds.left && attackBounds.top < enemyBounds.bottom && attackBounds.bottom > enemyBounds.top) {
enemies[j].hit();
if (enemies[j].type === 'eyeball') {
LK.getSound('eyeballhit').play();
} else {
LK.getSound('enemyhit').play();
}
continue;
}
}
// Check for body collision second
if (playerBounds.left < enemyBounds.right && playerBounds.right > enemyBounds.left && playerBounds.top < enemyBounds.bottom && playerBounds.bottom > enemyBounds.top) {
if (!enemies[j].isHit && !enemies[j].isDying) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
}
}
};
// Handle player jump
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
};
game.up = function (x, y, obj) {
if (!gameStarted) {
var buttonBounds = {
left: playButton.x - playButton.width / 2,
right: playButton.x + playButton.width / 2,
top: playButton.y - playButton.height / 2,
bottom: playButton.y + playButton.height / 2
};
if (x >= buttonBounds.left && x <= buttonBounds.right && y >= buttonBounds.top && y <= buttonBounds.bottom) {
// Start the game
startGame();
}
return; // Early return if game hasn't started
}
// Original game.up code for handling player actions
touchEndX = x;
touchEndY = y;
// Calculate swipe
var deltaY = touchStartY - touchEndY;
var deltaX = Math.abs(touchStartX - touchEndX);
// If vertical swipe (more vertical than horizontal movement)
if (deltaY > 50 && deltaY > deltaX) {
player.jump();
} else {
// Regular tap/click triggers attack
player.attack();
}
};
2D Single Monster. In-Game asset. 2d. Blank background. High contrast. No shadows..
A gold coin. 8 bit pixel art. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Dark and moody dungeon background. Infinite repeatable texture. 8 bit pixel art.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A ruby. Pixel art.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows