Code edit (1 edits merged)
Please save this source code
User prompt
add more variance
User prompt
add a bit of variance to defeat particle scale
User prompt
reduce their velocity a little bit
User prompt
increas the velocity of defeat particles
User prompt
increase the life time of defeat particles
User prompt
increase the amount of defeat particles spawned when enemy or enemytwo is defeated
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
User prompt
update enemy two class as needed with: self.update = function() { if (!self.visible) return; switch(self.state) { case 'approaching': // existing approaching code... break; case 'holding': // existing holding code... break; case 'falling': self.rotation += self.rotationSpeed; self.fallSpeed += self.acceleration; self.y += self.fallSpeed; // Check for ground collision if (self.y >= dragonShadow.y && !self.hasExploded) { self.hasExploded = true; for (var i = 0; i < 20; i++) { defeatParticlePool.spawn(self.x, self.y, 0xff0000); } enemyTwoPool.recycle(self); } break; } if (self.shadow) { self.shadow.update(self); } };
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (6 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: enemy is undefined' in or related to this line: 'if (!enemy.visible) {' Line Number: 609
User prompt
Please fix the bug: 'TypeError: enemy is undefined' in or related to this line: 'if (!enemy.visible) {' Line Number: 609
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (2 edits merged)
Please save this source code
User prompt
triple the lifespan of defeat particles
Code edit (2 edits merged)
Please save this source code
User prompt
Update as needed with: var Enemy = Container.expand(function () { // Existing code... self.hasExploded = false; // Add this flag self.activate = function (x, y) { // Existing activation code... self.hasExploded = false; // Reset explosion flag }; self.update = function () { switch (self.state) { // Other cases... case FALLING: self.rotation += self.rotationSpeed; self.fallSpeed += self.acceleration; self.y += self.fallSpeed; // Modified check with explosion flag if (self.y >= dragonShadow.y && !self.hasExploded) { self.hasExploded = true; // Set flag first // Create explosion effect for (var i = 0; i < 20; i++) { defeatParticlePool.spawn(self.x, self.y); } enemyPool.recycle(self); } break; } }; // Rest of the enemy class... });
Code edit (1 edits merged)
Please save this source code
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: shadow is not defined' in or related to this line: 'shadow.scaleX += (targetScaleX - shadow.scaleX) * scaleSmoothing;' Line Number: 273
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); var facekit = LK.import("@upit/facekit.v1"); /**** * Classes ****/ var Cloud = Container.expand(function () { var self = Container.call(this); var cloud = self.attachAsset('cloudShape', { anchorX: 0.5, anchorY: 0.5 }); self.activate = function (x, y, scale, alpha) { self.x = x; self.y = y; self.visible = true; self.speedY = 1 + Math.random() * 2; self.speedX = (Math.random() - 0.5) * 1.5; self.targetY = self.horizonY; cloud.scaleX = scale; cloud.scaleY = scale * 0.8; cloud.alpha = alpha || 0.8; }; self.deactivate = function () { self.visible = false; }; return self; }); var DefeatParticle = Container.expand(function () { var self = Container.call(this); var particle = self.attachAsset('particle', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.15, scaleY: 0.15 }); self.activate = function (x, y, tint) { self.x = x + (Math.random() * 40 - 20); // Wider initial spread self.y = y + (Math.random() * 40 - 20); // Wider initial spread self.visible = true; self.age = 0; self.lifespan = 75; // Tripled lifespan for longer visual impact // More dramatic explosion velocities var angle = Math.PI * 2 * Math.random(); var speed = 18 + Math.random() * 20; // Much higher speed for bigger burst self.vx = Math.cos(angle) * speed; self.vy = Math.sin(angle) * speed; self.rotation = Math.random() * Math.PI * 2; particle.alpha = 1; // Larger, more varied particle sizes particle.scaleX = 0.4 + Math.random() * 0.4; particle.scaleY = 0.4 + Math.random() * 0.4; // Apply tint if provided if (tint !== undefined) { particle.tint = tint; } else { particle.tint = 0xffffff; // Default white } }; self.update = function () { // Check bounds first if (self.y < -50 || self.y > 2732 || self.x < -50 || self.x > 2048) { defeatParticlePool.recycle(self); return; } self.x += self.vx; self.y += self.vy; self.age++; // Keep strong deceleration self.vx *= 0.87; self.vy *= 0.87; var lifePercent = self.age / self.lifespan; // Fade out curve particle.alpha = Math.max(0, 1 - lifePercent * 1.7); // More dramatic shrink effect as particles fade var scale = (0.5 - 0.3 * lifePercent) * (1 - lifePercent * 0.5); particle.scaleX = scale; particle.scaleY = scale; if (lifePercent >= 1) { defeatParticlePool.recycle(self); } }; self.deactivate = function () { self.visible = false; // Reset tint when deactivated particle.tint = 0xffffff; }; return self; }); var DragonHead = Container.expand(function () { var self = Container.call(this); // Dragon sprites var body = self.attachAsset('dragonBody', { anchorX: 0.5, anchorY: 0.75, scaleX: 2, scaleY: 2 }); var head = self.attachAsset('dragonHead', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2 }); var headOpen = self.attachAsset('dragonHeadOpen', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2, alpha: 0 }); var lookLeft = self.attachAsset('dragonLook', { anchorX: 0.5, anchorY: 0.5, scaleX: -2, // Mirror for left direction scaleY: 2, alpha: 0 }); var lookRight = self.attachAsset('dragonLook', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2, alpha: 0 }); var lookLeftOpen = self.attachAsset('dragonLookOpen', { anchorX: 0.5, anchorY: 0.5, scaleX: -2, // Mirror for left direction scaleY: 2, alpha: 0 }); var lookRightOpen = self.attachAsset('dragonLookOpen', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2, alpha: 0 }); self.currentScale = 2; // Starting scale var horizontalSpeed = 0; // Position tracking variables var targetX = 2048 / 2; var targetY = 2732 * 0.2; var smoothingFactor = 0.12; var prevX = null; var prevY = null; // Rotation variables var targetTilt = 0; var tiltSmoothingFactor = 0.11; var tiltScaleFactor = 0.09; // Scale tracking var scaleHistory = new Array(5).fill(2); // Start with default scale of 2 var scaleIndex = 0; self.update = function () { // Position tracking if (facekit.noseTip) { targetX = facekit.noseTip.x; targetY = facekit.noseTip.y - 400; // Initialize previous positions if not set if (prevX === null) { prevX = targetX; prevY = targetY; } // Weighted average between previous and target position var newX = prevX * (1 - smoothingFactor) + targetX * smoothingFactor; var newY = prevY * (1 - smoothingFactor) + targetY * smoothingFactor; self.x = newX; self.y = newY; if (prevX !== null) { horizontalSpeed = Math.abs(self.x - prevX); } self.currentShakeSpeed = horizontalSpeed; // Update previous positions prevX = newX; prevY = newY; } // Rotation tracking - CORRECTED VERSION if (facekit.leftEye && facekit.rightEye) { targetTilt = calculateFaceTilt() * tiltScaleFactor; // Limit rotation to ±15 degrees - DON'T convert to radians here targetTilt = Math.max(-15, Math.min(15, targetTilt)); self.rotation += (targetTilt - self.rotation) * tiltSmoothingFactor; } if (facekit.leftEye && facekit.rightEye && facekit.noseTip) { // Calculate face direction by comparing horizontal positions var faceCenter = (facekit.leftEye.x + facekit.rightEye.x) / 2; var noseDiff = facekit.noseTip.x - faceCenter; // Calculate eye alignment for head rotation var eyeYDiff = facekit.rightEye.y - facekit.leftEye.y; // Reset all direction indicators lookLeft.alpha = 0; lookRight.alpha = 0; lookLeftOpen.alpha = 0; lookRightOpen.alpha = 0; // Combined detection logic var showingTurnedHead = false; if (noseDiff < -120 && Math.abs(eyeYDiff) < 30 || eyeYDiff > 40) { // Looking left (nose to left OR right eye lower) if (facekit.mouthOpen) { lookLeftOpen.alpha = 1; } else { lookLeft.alpha = 1; } showingTurnedHead = true; } else if (noseDiff > 120 && Math.abs(eyeYDiff) < 30 || eyeYDiff < -40) { // Looking right (nose to right OR left eye lower) if (facekit.mouthOpen) { lookRightOpen.alpha = 1; } else { lookRight.alpha = 1; } showingTurnedHead = true; } // Set original head visibility based on whether a turned head is showing if (showingTurnedHead) { head.alpha = 0; headOpen.alpha = 0; } else { // Only then handle regular head visibility based on mouth state if (facekit && facekit.mouthOpen) { head.alpha = 0; headOpen.alpha = 1; } else { head.alpha = 1; headOpen.alpha = 0; } } } // Scale adjustment based on face size if (facekit.leftEye && facekit.rightEye) { var eyeDistance = Math.abs(facekit.rightEye.x - facekit.leftEye.x); var newScale = eyeDistance / 250; // Adjusted divisor for dragon head // Update rolling average scaleHistory[scaleIndex] = newScale; scaleIndex = (scaleIndex + 1) % scaleHistory.length; // Calculate average scale var avgScale = scaleHistory.reduce(function (a, b) { return a + b; }, 0) / scaleHistory.length; // Apply with gentle smoothing (limited range) var targetScale = Math.max(1.5, Math.min(2.5, avgScale)); head.scaleX = head.scaleX * 0.85 + targetScale * 0.15; self.currentScale = head.scaleX; // Track the current scale head.scaleY = head.scaleY * 0.85 + targetScale * 0.15; headOpen.scaleX = headOpen.scaleX * 0.85 + targetScale * 0.15; headOpen.scaleY = headOpen.scaleY * 0.85 + targetScale * 0.15; body.scaleX = body.scaleX * 0.85 + targetScale * 0.15; body.scaleY = body.scaleY * 0.85 + targetScale * 0.15; lookLeft.scaleX = lookLeft.scaleX * 0.85 - targetScale * 0.15; lookLeft.scaleY = lookLeft.scaleY * 0.85 + targetScale * 0.15; lookRight.scaleX = lookRight.scaleX * 0.85 + targetScale * 0.15; lookRight.scaleY = lookRight.scaleY * 0.85 + targetScale * 0.15; lookLeftOpen.scaleX = lookLeftOpen.scaleX * 0.85 - targetScale * 0.15; lookLeftOpen.scaleY = lookLeftOpen.scaleY * 0.85 + targetScale * 0.15; lookRightOpen.scaleX = lookRightOpen.scaleX * 0.85 + targetScale * 0.15; lookRightOpen.scaleY = lookRightOpen.scaleY * 0.85 + targetScale * 0.15; } }; function calculateFaceTilt() { if (facekit.leftEye && facekit.rightEye && facekit.mouthCenter) { // Calculate midpoint between eyes var eyeMidX = (facekit.leftEye.x + facekit.rightEye.x) / 2; var eyeMidY = (facekit.leftEye.y + facekit.rightEye.y) / 2; // Calculate angle between eye midpoint and mouth, negated to fix direction var dx = facekit.mouthCenter.x - eyeMidX; var dy = facekit.mouthCenter.y - eyeMidY; var angle = -(Math.atan2(dx, dy) * (180 / Math.PI)); // Reduced angle impact return Math.max(-15, Math.min(15, angle * 0.15)); } return 0; // Default to straight when face points aren't available } return self; }); var DragonShadow = Container.expand(function () { var self = Container.call(this); var shadow = self.attachAsset('dragonShadow', { anchorX: 0.5, anchorY: 0.5, alpha: 0.5, scaleX: 1, scaleY: 0.3 }); var positionSmoothing = 0.12; var scaleSmoothing = 0.08; self.update = function (dragonX, dragonY, dragonScale) { if (dragonX !== undefined && dragonY !== undefined && dragonScale !== undefined) { // X position follow self.x += (dragonX - self.x) * positionSmoothing; // Y position based on scale (Z-depth) var baseY = 2732 * 0.6; var scaleOffset = (dragonScale - 1) * 300; var targetY = baseY + scaleOffset; self.y += (targetY - self.y) * positionSmoothing; // Scale calculation based on dragon's Y position var heightRatio = dragonY / 2732; var scaleMultiplier = 0.2 + heightRatio * 1.5; // Add Y-position based size adjustment (0-20% increase based on Y position) var yPositionScale = 1 + self.y / 2732 * 0.2; var targetScaleX = scaleMultiplier * yPositionScale; var targetScaleY = scaleMultiplier * 0.3 * yPositionScale; var shadow = self.getChildAt(0); // Get the shadow sprite shadow.scaleX += (targetScaleX - shadow.scaleX) * scaleSmoothing; shadow.scaleY += (targetScaleY - shadow.scaleY) * scaleSmoothing; shadow.alpha = 0.3 + heightRatio * 0.2; } }; return self; }); var DustParticle = Container.expand(function () { var self = Container.call(this); var dust = self.attachAsset('dust', { anchorX: 0.5, anchorY: 0.5 }); self.activate = function (x, y) { self.x = x + (Math.random() * 20 - 10); self.y = y; self.visible = true; self.age = 0; self.lifespan = 60; // Fixed lifespan for consistency dust.alpha = 0.9; // Vertical velocity - move upward self.vy = -1.5; // Faster upward movement self.vx = (Math.random() - 0.5) * 5; // Slightly more horizontal movement // Add rotation for visual interest self.rotation = Math.random() * Math.PI * 2; }; self.update = function () { // Update position self.x += self.vx; self.y += self.vy; self.age++; // Calculate life percentage var lifePercent = self.age / self.lifespan; // Fade out dust.alpha = 0.8 * (1 - lifePercent); // Grow slightly as it rises var scale = 1 + lifePercent * 0.2; // Linear growth from 0.2 to 0.3 dust.scaleX = scale; dust.scaleY = scale; // Recycle when lifetime is over if (lifePercent >= 1) { dustParticlePool.recycle(self); } }; self.deactivate = function () { self.visible = false; }; return self; }); var Enemy = Container.expand(function () { var self = Container.call(this); // States var RUNNING = 'running'; var LEAPING = 'leaping'; var ATTACHED = 'attached'; var FALLING = 'falling'; // Running enemy sprites var runSprite = self.attachAsset('enemy1', { anchorX: 0.5, anchorY: 0.5, alpha: 1 }); var runSpriteMirrored = self.attachAsset('enemy1', { anchorX: 0.5, anchorY: 0.5, scaleX: -1, alpha: 0 }); // Properties self.health = 1; self.rotationSpeed = 0; self.animTick = 0; self.animRate = 30; self.state = RUNNING; self.leapSpeed = 10; self.targetX = 0; self.targetY = 0; self.hasExploded = false; // Add this flag self.activate = function (x, y) { self.visible = true; self.x = x; self.y = y; self.state = RUNNING; self.rotation = 0; // Reset rotation self.health = 1; self.rotationSpeed = 0; self.fallSpeed = 0; self.acceleration = 0; self.leapDuration = 0; self.shadow = enemyShadowPool.spawn(x, y, self.scaleX); self.isPulsedOut = false; self.hasExploded = false; // Reset explosion flag // If there was a tween running, stop it if (self.currentTween) { self.currentTween.stop(); self.currentTween = null; } // Reset animation state self.animTick = 0; runSprite.alpha = 1; runSpriteMirrored.alpha = 0; // Set initial scale based on distance from horizon var progress = Math.max(0, self.y - flyingBackground.horizonY) / (2732 - flyingBackground.horizonY); var scale = 0.5 + progress; self.scaleX = scale; self.scaleY = scale; }; function checkLeapDistance() { // Get distance on Y-axis only var dy = Math.abs(self.y - dragonShadow.y); // Get relative scales as depth indicators var enemyDepth = self.scaleX; var shadowDepth = dragonShadow.scaleX; // Leap when on same Y-plane regardless of X position var depthDiff = Math.abs(enemyDepth - shadowDepth); var yThreshold = 10; // Close on the Y-axis // If the enemy is on screen and at the right Y position if (dy < yThreshold && depthDiff < 0.3 && self.x > 0 && self.x < 2048) { startLeap(); return true; } return false; } function startLeap() { self.state = LEAPING; // Store where the dragon was when leap started self.leapTargetX = dragon.x; self.leapTargetY = dragon.y; var dx = self.leapTargetX - self.x; var dy = self.leapTargetY - self.y; self.initialLeapDistance = Math.sqrt(dx * dx + dy * dy); self.initialScale = self.scaleX; self.isPulsedOut = false; runSprite.alpha = 1; runSpriteMirrored.alpha = 0; } self.update = function () { if (!self.visible) { return; } switch (self.state) { case RUNNING: // Existing running code var progress = Math.max(0, self.y - flyingBackground.horizonY) / (2732 - flyingBackground.horizonY); var speed = (flyingBackground.scrollSpeed * 0.05 + flyingBackground.scrollSpeed * (progress * 2.5)) * 0.8; self.y -= speed; // Update scale based on distance var scale = 0.5 + progress; self.scaleX = scale; self.scaleY = scale; // Running animation self.animTick++; if (self.animTick >= self.animRate) { self.animTick = 0; runSprite.alpha = runSprite.alpha === 0 ? 1 : 0; runSpriteMirrored.alpha = runSpriteMirrored.alpha === 0 ? 1 : 0; } // In the Enemy class RUNNING state section, replace the dust spawning code with: if (LK.ticks % 10 === 0 && self.y < 2732) { // More frequent spawning (every 10 ticks) var footY = self.y + 50 * self.scaleY; dustParticlePool.spawn(self.x, footY); } // Check for leap checkLeapDistance(); break; case LEAPING: // Calculate progress towards original leap target var dx = self.leapTargetX - self.x; var dy = self.leapTargetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Check if we've reached or passed the target Y position OR if we're very close to the peak of the leap if (self.y <= self.leapTargetY || distance < 50 || self.leapDuration > 100) { // Added timeout condition var dragonDx = dragon.x - self.x; var dragonDy = dragon.y - self.y; var dragonDistance = Math.sqrt(dragonDx * dragonDx + dragonDy * dragonDy); if (dragonDistance > 300) { self.state = FALLING; self.rotationSpeed = (Math.random() * 0.1 + 0.05) * (Math.random() < 0.5 ? 1 : -1); self.fallSpeed = 2; self.acceleration = 0.2; } else { self.state = ATTACHED; } break; } // Continue leap motion if (distance > 10) { var dirX = dx / distance; var dirY = dy / distance; var speedMultiplier = Math.min(1.5, distance / 100); self.x += dirX * self.leapSpeed * speedMultiplier; self.y += dirY * self.leapSpeed * speedMultiplier; self.scaleX = self.initialScale * 0.75; self.scaleY = self.initialScale * 0.75; } // Increment leap duration for safety timeout self.leapDuration = (self.leapDuration || 0) + 1; break; case ATTACHED: // Stick to dragon position self.x = dragon.x; self.y = dragon.y; // Check for shake-off if (dragon.currentShakeSpeed > 25) { // Threshold for shake-off self.state = FALLING; self.rotationSpeed = (Math.random() * 0.1 + 0.05) * (Math.random() < 0.5 ? 1 : -1); self.fallSpeed = 2; self.acceleration = 0.2; score += self.type * 5; // Bonus points for shake-off scoreTxt.setText(score); LK.setScore(score); break; } // Pulsing animation self.animTick++; if (self.animTick >= self.animRate) { self.animTick = 0; // Pulse between 0.7 and 0.8 scale tween(self, { scaleX: self.initialScale * (self.isPulsedOut ? 0.7 : 0.8), scaleY: self.initialScale * (self.isPulsedOut ? 0.7 : 0.8) }, { duration: 200, easing: tween.easeOut }); self.isPulsedOut = !self.isPulsedOut; } break; case FALLING: self.rotation += self.rotationSpeed; self.fallSpeed += self.acceleration; self.y += self.fallSpeed; // Check for shadow collision with explosion flag if (self.y >= dragonShadow.y && !self.hasExploded) { self.hasExploded = true; // Create MUCH bigger explosion with red tint for (var i = 0; i < 20; i++) { defeatParticlePool.spawn(self.x, self.y, 0xff0000); // Red tint (0xff0000) } enemyPool.recycle(self); } break; } if (self.shadow) { self.shadow.update(self); } }; self.hit = function () { self.health--; if (self.health <= 0) { if (self.state !== FALLING) { self.state = FALLING; self.rotationSpeed = (Math.random() * 0.1 + 0.05) * (Math.random() < 0.5 ? 1 : -1); self.fallSpeed = 2; self.acceleration = 0.2; return true; } } return false; }; self.deactivate = function () { self.visible = false; runSprite.alpha = 1; runSpriteMirrored.alpha = 0; if (self.shadow) { enemyShadowPool.recycle(self.shadow); self.shadow = null; } }; return self; }); var EnemyArrow = Container.expand(function () { var self = Container.call(this); var arrow = self.attachAsset('enemyArrow', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); self.speed = 8; self.update = function () { if (!self.active) { return; } self.x += self.vx; self.y += self.vy; // Point arrow in direction of travel self.rotation = Math.atan2(self.vy, self.vx) + Math.PI / 2; if (self.y < 0 || self.y > 2732 || self.x < 0 || self.x > 2048) { enemyArrowPool.recycle(self); } }; self.activate = function (x, y, targetX, targetY) { self.x = x; self.y = y; self.visible = true; self.active = true; // Calculate direction to target var dx = targetX - x; var dy = targetY - y; var dist = Math.sqrt(dx * dx + dy * dy); self.vx = dx / dist * self.speed; self.vy = dy / dist * self.speed; }; self.deactivate = function () { self.visible = false; self.active = false; }; return self; }); var EnemyShadow = Container.expand(function () { var self = Container.call(this); var shadow = self.attachAsset('enemyShadow', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3, scaleX: 1, scaleY: 0.3 }); // In the EnemyShadow class, update method (around line 1018) self.update = function (enemy) { if (!enemy || !enemy.visible || enemy.hasExploded) { self.visible = false; return; } self.visible = true; // Always follow enemy's X position self.x = enemy.x; // For running enemies, shadow is slightly below them if (enemy.state === 'running') { self.y = enemy.y + 200; // Shadow slightly below enemy } // For leaping enemies, shadow moves to dragon shadow position else if (enemy.state === 'leaping') { self.y = dragonShadow.y + 50; // Position just below dragon shadow } // For attached enemies, follow dragon shadow else if (enemy.state === 'attached') { self.y = dragonShadow.y + 50; // Keep following dragon shadow } // For falling enemies, shadow holds last position else if (enemy.state === 'falling') { // Y position stays the same } // Special case for EnemyTwo type else if (enemy.type === 2) { self.y = enemy.y + 600; // Position higher for enemy type 2 } // Scale shadow based on enemy's scale shadow.scaleX = enemy.scaleX * 1.2; shadow.scaleY = enemy.scaleX * 0.3; }; self.activate = function (x, y, enemyScale) { self.x = x; self.y = y + 200; // Initially position shadow slightly below enemy self.visible = true; shadow.scaleX = (enemyScale || 1) * 1.2; shadow.scaleY = (enemyScale || 1) * 0.3; }; self.deactivate = function () { self.visible = false; }; return self; }); var EnemyTwo = Container.expand(function () { var self = Container.call(this); var sprite = self.attachAsset('enemy2', { anchorX: 0.5, anchorY: 0.5 }); // Properties self.health = 1; self.type = 2; // For scoring self.state = 'approaching'; // approaching, holding self.holdDistance = 800; self.bobOffset = 0; self.bobSpeed = 0.05; self.lastShotTime = 0; self.shotInterval = 2000; // 2 seconds self.activate = function (x, y) { self.visible = true; self.x = x; self.y = y; self.state = 'approaching'; self.health = 1; self.rotation = 0; self.hasExploded = false; // Make sure this flag is set // Ensure shadow is created and stored if (!self.shadow) { self.shadow = enemyShadowPool.spawn(x, y, self.scaleX); } // Moving direction self.moveRight = x < 1024; // If spawned on left side, move right // Initial scale based on distance from horizon var progress = Math.max(0, self.y - flyingBackground.horizonY) / (2732 - flyingBackground.horizonY); self.scaleX = 0.5 + progress; self.scaleY = 0.5 + progress; }; self.update = function () { if (!self.visible) { return; } switch (self.state) { case 'approaching': // Bobbing motion self.bobOffset = Math.sin(LK.ticks * self.bobSpeed) * 50; // Move towards dragon var dx = dragon.x - self.x; var dy = dragon.y - self.y + self.bobOffset; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > self.holdDistance) { self.x += dx * 0.01; // Reduced from 0.02 self.y += dy * 0.01; // Reduced from 0.02 // Modified scale calculation to maintain larger size var progress = Math.max(0, self.y - flyingBackground.horizonY) / (2732 - flyingBackground.horizonY); self.scaleX = 0.7 + progress * 0.5; // Modified from 0.5 + progress self.scaleY = 0.7 + progress * 0.5; // Modified from 0.5 + progress } else { self.state = 'holding'; } break; case 'holding': // Maintain position relative to dragon var dx = dragon.x - self.x; var targetX = self.x + dx * 0.01; // Keep on screen targetX = Math.max(100, Math.min(1948, targetX)); self.x = targetX; // Stay below dragon with offset var targetY = dragon.y + 800; // Stay 200 pixels below dragon var currentY = self.y - self.bobOffset; // Remove bobbing to get true position self.y = currentY + (targetY - currentY) * 0.1; // Smooth movement to target // Apply bobbing to final position self.y += self.bobOffset; // Shoot at intervals var now = Date.now(); if (now - self.lastShotTime >= self.shotInterval) { self.shoot(); self.lastShotTime = now; } break; case 'falling': self.rotation += self.rotationSpeed; self.fallSpeed += self.acceleration; self.y += self.fallSpeed; // Check for ground collision if (self.shadow && self.y >= self.shadow.y && !self.hasExploded) { self.hasExploded = true; for (var i = 0; i < 20; i++) { defeatParticlePool.spawn(self.x, self.y, 0xff0000); } enemyTwoPool.recycle(self); } break; } if (self.shadow) { self.shadow.update(self); } }; self.shoot = function () { var arrow = enemyArrowPool.spawn(self.x, self.y); if (arrow) { arrow.activate(self.x, self.y, dragon.x, dragon.y); } }; self.hit = function () { self.health--; if (self.health <= 0) { if (Math.random() < 0.5) { // Mid-air explosion for (var i = 0; i < 20; i++) { defeatParticlePool.spawn(self.x, self.y, 0xff0000); } enemyTwoPool.recycle(self); } else { // Fall and explode self.state = 'falling'; self.rotationSpeed = (Math.random() * 0.1 + 0.05) * (Math.random() < 0.5 ? 1 : -1); self.fallSpeed = 2; self.acceleration = 0.2; } return true; } return false; }; self.deactivate = function () { self.visible = false; if (self.shadow) { enemyShadowPool.recycle(self.shadow); self.shadow = null; } }; return self; }); var FieldElement = Container.expand(function () { var self = Container.call(this); var element = self.attachAsset('fieldElement', { anchorX: 0.5, anchorY: 0.5 }); self.activate = function (x, y, scale, alpha) { self.x = x; self.y = y; self.visible = true; self.speedY = 2 + Math.random() * 3; self.initialX = x; element.scaleX = scale; element.scaleY = scale * 0.8; element.alpha = alpha || 0.9; }; self.deactivate = function () { self.visible = false; }; return self; }); var FireParticle = Container.expand(function () { var self = Container.call(this); var particle = self.attachAsset('fireParticle', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { self.x += self.vx; self.y += self.vy; self.age++; // Update alpha var lifePercent = self.age / self.lifespan; particle.alpha = 1 - lifePercent; // Recycle if lifetime is over OR particle is off screen if (lifePercent >= 1 || self.y < 0 || self.y > 2732 || // Screen height self.x < 0 || self.x > 2048) { // Screen width particlePool.recycle(self); } }; self.activate = function (x, y) { self.x = x; self.y = y; self.visible = true; self.vx = Math.random() * 4 - 2; self.vy = Math.random() * 2 + 1; self.lifespan = 20 + Math.random() * 20; self.age = 0; particle.alpha = 1; }; self.deactivate = function () { self.visible = false; }; return self; }); // In the Fireball class, update the properties and update method var Fireball = Container.expand(function () { var self = Container.call(this); var fireballGraphic = self.attachAsset('fireball', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 15; self.vx = 0; // Add horizontal velocity self.update = function () { if (!self.active) { return; } // Update position with both vertical and horizontal components self.y += self.speed; self.x += self.vx; // Calculate rotation based on direction of travel // For correct orientation: Math.atan2(dy, dx) - Math.PI/2 // We're subtracting 90 degrees (PI/2) to adjust for the sprite's default orientation var angle = Math.atan2(self.speed, self.vx) - Math.PI / 2; self.rotation = angle; // Create fire trail particles if (Math.random() < 0.3) { particlePool.spawn(self.x + (Math.random() * 40 - 20), self.y + 20); } // Recycle when off screen (bottom or sides) if (self.y > 2732 || self.x < -100 || self.x > 2148) { fireballPool.recycle(self); } }; self.activate = function (x, y) { self.x = x; self.y = y; self.visible = true; self.active = true; self.vx = 0; self.rotation = 0; fireballGraphic.alpha = 1; }; self.deactivate = function () { self.visible = false; self.active = false; // Clear any references that might cause memory leaks self.currentTween = null; }; return self; }); var FlyingBackground = Container.expand(function () { var self = Container.call(this); // Create bottom container self.bottomContainer = new Container(); self.addChild(self.bottomContainer); // Store the horizon line self.horizonY = 2732 / 2; self.totalHeight = 2732 - self.horizonY; self.fieldStripes = []; // Create field stripes (keep this the same as original) var nbStripes = 30; var lastY = self.horizonY + 10; var stripe = self.bottomContainer.attachAsset('fieldStripes', { anchorX: 0.5, anchorY: 0, x: 2048 / 2, y: lastY }); var progress = Math.max(0, lastY - self.horizonY) / self.totalHeight; stripe.height = 1 + 400 * progress; self.fieldStripes.push({ sprite: stripe, progress: progress }); for (var i = 1; i < nbStripes; i++) { var spacing = 400 * (lastY - self.horizonY) / self.totalHeight; var y = lastY + spacing; var stripe = self.bottomContainer.attachAsset('fieldStripes', { anchorX: 0.5, anchorY: 0, x: 2048 / 2, y: y }); var progress = Math.max(0, y - self.horizonY) / self.totalHeight; stripe.height = 1 + 400 * progress; self.fieldStripes.push({ sprite: stripe, progress: progress }); lastY = y; } // Create top container self.topContainer = new Container(); self.addChild(self.topContainer); // Create sky background in top container var sky = self.topContainer.attachAsset('skyBackground', { anchorX: 0.5, anchorY: 1.0, x: 2048 / 2, y: self.horizonY + 10 }); // Field scroll speed self.scrollSpeed = 4; // Create object pools self.cloudPool = new ObjectPool(Cloud, 15); self.fieldElementPool = new ObjectPool(FieldElement, 20); // Add pools to containers self.topContainer.addChild(self.cloudPool); self.bottomContainer.addChild(self.fieldElementPool); // Initialize clouds for (var i = 0; i < 8; i++) { var startY = self.horizonY - 400 - Math.random() * 600; var distanceFromHorizon = Math.abs(startY - self.horizonY); var startScale = 0.5 + distanceFromHorizon / 800; var cloud = self.cloudPool.spawn(Math.random() * 2048, startY, startScale, 0.8); if (cloud) { cloud.horizonY = self.horizonY; } } // Initialize field elements for (var j = 0; j < 12; j++) { var fieldStartY = self.horizonY + Math.random() * (2732 - self.horizonY); var fieldDistanceFromHorizon = Math.abs(fieldStartY - self.horizonY); var fieldStartScale = 0.5 + fieldDistanceFromHorizon / 1000; var fieldElement = self.fieldElementPool.spawn(Math.random() * 2048, fieldStartY, fieldStartScale, 0.9); if (fieldElement) { fieldElement.horizonY = self.horizonY; } } self.update = function () { // Update field stripes (keep original code) for (var i = 0; i < self.fieldStripes.length; i++) { var stripe = self.fieldStripes[i]; stripe.progress = Math.max(0, stripe.sprite.y - self.horizonY) / self.totalHeight; var tempSpeed = self.scrollSpeed * 0.05 + self.scrollSpeed * (stripe.progress * 3); stripe.sprite.y -= tempSpeed; } // Sort stripes by Y position self.fieldStripes.sort(function (a, b) { return a.sprite.y - b.sprite.y; }); // Reset stripes that moved above horizon for (var i = 0; i < self.fieldStripes.length; i++) { if (self.fieldStripes[i].sprite.y < self.horizonY) { var lowestStripe = self.fieldStripes[self.fieldStripes.length - 1]; self.fieldStripes[i].sprite.y = lowestStripe.sprite.y + 400 * (lowestStripe.sprite.y - self.horizonY) / self.totalHeight; self.fieldStripes[i].progress = Math.max(0, self.fieldStripes[i].sprite.y - self.horizonY) / self.totalHeight; } } // Re-sort after repositioning self.fieldStripes.sort(function (a, b) { return a.sprite.y - b.sprite.y; }); // Adjust stripe heights for (var i = 0; i < self.fieldStripes.length - 1; i++) { var currentStripe = self.fieldStripes[i]; var nextStripe = self.fieldStripes[i + 1]; currentStripe.sprite.height = nextStripe.sprite.y - currentStripe.sprite.y; } // Handle last stripe var lastStripe = self.fieldStripes[self.fieldStripes.length - 1]; lastStripe.sprite.height = Math.max(1 + 400 * lastStripe.progress, self.horizonY + self.totalHeight - lastStripe.sprite.y + 100); // Update clouds and field elements updateCloudPool(); updateFieldElementPool(); }; function updateCloudPool() { var activeObjects = self.cloudPool.getActiveObjects(); for (var i = 0; i < activeObjects.length; i++) { var cloud = activeObjects[i]; // Move cloud toward horizon cloud.y += cloud.speedY; cloud.x += cloud.speedX; // Get the cloud's sprite var sprite = cloud.getChildAt(0); // Calculate scale based on distance from horizon var distanceFactor = Math.max(0.05, (cloud.y - self.horizonY) / -500); sprite.scaleX = distanceFactor; sprite.scaleY = distanceFactor * 0.8; // Adjust alpha for fade effect near horizon sprite.alpha = Math.min(0.9, distanceFactor); // Reset cloud if it reaches horizon or gets too small if (cloud.y >= self.horizonY - 10 || sprite.scaleX < 0.1) { // Recycle and spawn new cloud self.cloudPool.recycle(cloud); var newCloud = self.cloudPool.spawn(Math.random() * 2048, self.horizonY - 800 - Math.random() * 400, (self.horizonY - 800 - Math.random() * 400 - self.horizonY) / -500, 0.8); if (newCloud) { newCloud.horizonY = self.horizonY; } } } } function updateFieldElementPool() { var activeObjects = self.fieldElementPool.getActiveObjects(); for (var j = 0; j < activeObjects.length; j++) { var element = activeObjects[j]; // Calculate progress based on distance from horizon var progress = Math.max(0, element.y - self.horizonY) / self.totalHeight; // Calculate speed using same logic as stripes var tempSpeed = self.scrollSpeed * 0.05 + self.scrollSpeed * (progress * 3); // Move element toward horizon element.y -= tempSpeed; // Get the element's sprite var sprite = element.getChildAt(0); // Calculate scale based on distance from horizon var fieldDistanceFactor = Math.max(0.05, (element.y - self.horizonY) / 300); sprite.scaleX = fieldDistanceFactor * 1.2; sprite.scaleY = fieldDistanceFactor * 1.2; // Adjust alpha for fade effect //sprite.alpha = Math.min(0.9, fieldDistanceFactor); // Reset element if it reaches horizon if (element.y <= self.horizonY + 10 || sprite.scaleX < 0.1) { // Recycle and spawn new element self.fieldElementPool.recycle(element); // Calculate position for new element var section = Math.floor(Math.random() * 8); var sectionWidth = 2048 / 8; var newX = section * sectionWidth + Math.random() * sectionWidth; var newY = 2732 + Math.random() * 600; var newScale = (newY - self.horizonY) / 300; var newElement = self.fieldElementPool.spawn(newX, newY, newScale, 0.9); if (newElement) { newElement.horizonY = self.horizonY; newElement.initialX = newX; } } element.zIndex = element.y; } // After updating all elements, sort them by z-index activeObjects.sort(function (a, b) { return a.y - b.y; // Sort by y position (smaller y values first) }); // Remove and re-add in the sorted order for (var k = 0; k < activeObjects.length; k++) { var element = activeObjects[k]; self.bottomContainer.removeChild(element); self.bottomContainer.addChild(element); } } return self; }); var ObjectPool = Container.expand(function (ObjectClass, size) { var self = Container.call(this); var objects = []; var activeCount = 0; for (var i = 0; i < size; i++) { var obj = new ObjectClass(); if (typeof obj.update !== 'function') { obj.update = function () {}; // Provide a default update method if not defined } obj.visible = false; obj._poolIndex = i; objects.push(obj); self.addChild(obj); } self.spawn = function (x, y, params) { if (activeCount >= objects.length) { return null; } var obj = objects[activeCount]; activeCount++; // Increment AFTER getting object obj.visible = true; obj.activate(x, y, params); return obj; }; self.recycle = function (obj) { if (!obj || typeof obj._poolIndex !== 'number' || obj._poolIndex >= activeCount) { return; } activeCount--; // Decrement count // Swap with last active object if needed if (obj._poolIndex < activeCount) { var temp = objects[activeCount]; objects[activeCount] = obj; objects[obj._poolIndex] = temp; // Update indices temp._poolIndex = obj._poolIndex; obj._poolIndex = activeCount; } obj.deactivate(); obj.visible = false; }; self.recycleAll = function () { while (activeCount > 0) { self.recycle(objects[0]); } }; self.update = function () { for (var i = 0; i < activeCount; i++) { objects[i].update(); } }; self.getActiveObjects = function () { return objects.slice(0, activeCount); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ function processCollisions() { var fireballs = fireballPool.getActiveObjects(); var enemies = enemyPool.getActiveObjects(); var enemiesTwo = enemyTwoPool.getActiveObjects(); // Process enemy arrows first var arrows = enemyArrowPool.getActiveObjects(); for (var i = arrows.length - 1; i >= 0; i--) { var arrow = arrows[i]; var dx = arrow.x - dragon.x; var dy = arrow.y - dragon.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 75) { enemyArrowPool.recycle(arrow); // Flash dragon red var dragonSprites = [dragon.getChildAt(0)]; dragonSprites.forEach(function (sprite) { sprite.tint = 0xFF0000; LK.setTimeout(function () { sprite.tint = 0xFFFFFF; }, 10); }); break; } } // Process fireballs against both enemy types for (var i = fireballs.length - 1; i >= 0; i--) { var fireball = fireballs[i]; // Check against type 1 enemies for (var j = enemies.length - 1; j >= 0; j--) { var enemy = enemies[j]; var dx = fireball.x - enemy.x; var dy = fireball.y - enemy.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 100 * enemy.scaleX) { if (enemy.hit()) { score += enemy.type * 10; scoreTxt.setText(score); LK.setScore(score); LK.getSound('enemyDefeat').play(); } fireballPool.recycle(fireball); break; } } // Check against type 2 enemies for (var j = enemiesTwo.length - 1; j >= 0; j--) { var enemy = enemiesTwo[j]; var dx = fireball.x - enemy.x; var dy = fireball.y - enemy.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150 * enemy.scaleX) { if (enemy.hit()) { score += enemy.type * 10; scoreTxt.setText(score); LK.setScore(score); LK.getSound('enemyDefeat').play(); } fireballPool.recycle(fireball); break; } } } } // Set dark blue background for sky effect game.setBackgroundColor(0x2c3e50); // Game state variables var score = 0; var fireballPool = new ObjectPool(Fireball, 100); var particlePool = new ObjectPool(FireParticle, 400); var enemyPool = new ObjectPool(Enemy, 25); var defeatParticlePool = new ObjectPool(DefeatParticle, 200); var dustParticlePool = new ObjectPool(DustParticle, 100); var enemyShadowPool = new ObjectPool(EnemyShadow, 50); var enemyArrowPool = new ObjectPool(EnemyArrow, 50); var enemyTwoPool = new ObjectPool(EnemyTwo, 25); var gameActive = true; var isFiring = false; var lastFireTime = 0; var fireRate = 250; // ms between fireballs var enemySpawnRate = 120; // Frames between enemy spawns var difficultyScaling = 0; var flyingBackground = new FlyingBackground(); game.addChild(flyingBackground); // Create dragon head (player character) var dragon = game.addChild(new DragonHead()); dragon.x = 2048 / 2; dragon.y = 2732 * 0.2; // Place dragon at top fifth of screen var dragonShadow = new DragonShadow(); game.addChild(dragonShadow); game.addChild(enemyShadowPool); game.addChild(fireballPool); game.addChild(particlePool); game.addChild(enemyPool); game.addChild(enemyTwoPool); game.addChild(defeatParticlePool); game.addChild(dustParticlePool); game.addChild(enemyArrowPool); game.cleanupPools = function () { fireballPool.recycleAll(); particlePool.recycleAll(); enemyPool.recycleAll(); defeatParticlePool.recycleAll(); dustParticlePool.recycleAll(); enemyShadowPool.recycleAll(); enemyArrowPool.recycleAll(); }; // Score display var scoreTxt = new Text2('0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); scoreTxt.y = 50; LK.gui.top.addChild(scoreTxt); // Create a function to add fire particles function createFireParticle(x, y) { particlePool.spawn(x, y); } // Function to spawn a fireball // Update the spawnFireball function function spawnFireball() { if (!gameActive) { return; } var now = Date.now(); if (now - lastFireTime < fireRate) { return; } lastFireTime = now; // Initialize horizontal velocity components var angleOffset = 0; // Get direction from dragon head facing - match thresholds with DragonHead class if (facekit.leftEye && facekit.rightEye && facekit.noseTip) { var faceCenter = (facekit.leftEye.x + facekit.rightEye.x) / 2; var noseDiff = facekit.noseTip.x - faceCenter; var eyeYDiff = facekit.rightEye.y - facekit.leftEye.y; // Keep the original thresholds but require more pronounced movement // to trigger the sideways shots (higher threshold values) if (noseDiff < -120 && Math.abs(eyeYDiff) < 30 || eyeYDiff > 40) { // Facing left - fireballs go left (maintain strong angle) angleOffset = -8; // Original value for strong effect } else if (noseDiff > 120 && Math.abs(eyeYDiff) < 30 || eyeYDiff < -40) { // Facing right - fireballs go right (maintain strong angle) angleOffset = 8; // Original value for strong effect } } // Keep the original tilt impact for consistent feel if (dragon.rotation) { angleOffset += dragon.rotation * 5; // Original value } // Use the new pool's spawn method var fireball = fireballPool.spawn(dragon.x, dragon.y + 50); // Set horizontal velocity if fireball was created if (fireball) { fireball.vx = angleOffset; } // Play sound LK.getSound('firebreathSound').play(); } // Function to spawn enemies function spawnEnemy() { if (!gameActive) { return; } var isTypeTwo = Math.random() < 0.4; // 40% chance for EnemyTwo if (isTypeTwo) { // Spawn from sides, about 500px from bottom var spawnX = Math.random() < 0.5 ? -50 : 2098; var enemy = enemyTwoPool.spawn(spawnX, 2732 - 500); if (enemy) { enemy.visible = true; } } else { var enemy = enemyPool.spawn(Math.random() * (2048 - 200) + 100, 2732 + 100); if (enemy) { enemy.visible = true; } } } // Game update logic game.update = function () { if (!gameActive) { return; } // Check if mouth is open for fire breathing if (facekit && facekit.mouthOpen) { isFiring = true; spawnFireball(); } else { isFiring = false; } // Spawn enemies at a constant rate if (LK.ticks % enemySpawnRate === 0) { spawnEnemy(); } dragonShadow.update(dragon.x, dragon.y, dragon.currentScale); // Update all pools fireballPool.update(); enemyPool.update(); particlePool.update(); defeatParticlePool.update(); dustParticlePool.update(); // Process collisions processCollisions(); }; // Start background music LK.playMusic('gameMusic', { fade: { start: 0, end: 0.8, duration: 1000 } });
===================================================================
--- original.js
+++ change.js
@@ -143,8 +143,9 @@
scaleY: 2,
alpha: 0
});
self.currentScale = 2; // Starting scale
+ var horizontalSpeed = 0;
// Position tracking variables
var targetX = 2048 / 2;
var targetY = 2732 * 0.2;
var smoothingFactor = 0.12;
@@ -171,8 +172,12 @@
var newX = prevX * (1 - smoothingFactor) + targetX * smoothingFactor;
var newY = prevY * (1 - smoothingFactor) + targetY * smoothingFactor;
self.x = newX;
self.y = newY;
+ if (prevX !== null) {
+ horizontalSpeed = Math.abs(self.x - prevX);
+ }
+ self.currentShakeSpeed = horizontalSpeed;
// Update previous positions
prevX = newX;
prevY = newY;
}
@@ -290,9 +295,9 @@
// X position follow
self.x += (dragonX - self.x) * positionSmoothing;
// Y position based on scale (Z-depth)
var baseY = 2732 * 0.6;
- var scaleOffset = (dragonScale - 1) * 500;
+ var scaleOffset = (dragonScale - 1) * 300;
var targetY = baseY + scaleOffset;
self.y += (targetY - self.y) * positionSmoothing;
// Scale calculation based on dragon's Y position
var heightRatio = dragonY / 2732;
@@ -505,8 +510,20 @@
case ATTACHED:
// Stick to dragon position
self.x = dragon.x;
self.y = dragon.y;
+ // Check for shake-off
+ if (dragon.currentShakeSpeed > 25) {
+ // Threshold for shake-off
+ self.state = FALLING;
+ self.rotationSpeed = (Math.random() * 0.1 + 0.05) * (Math.random() < 0.5 ? 1 : -1);
+ self.fallSpeed = 2;
+ self.acceleration = 0.2;
+ score += self.type * 5; // Bonus points for shake-off
+ scoreTxt.setText(score);
+ LK.setScore(score);
+ break;
+ }
// Pulsing animation
self.animTick++;
if (self.animTick >= self.animRate) {
self.animTick = 0;
@@ -579,9 +596,9 @@
}
self.x += self.vx;
self.y += self.vy;
// Point arrow in direction of travel
- self.rotation = Math.atan2(self.vy, self.vx);
+ self.rotation = Math.atan2(self.vy, self.vx) + Math.PI / 2;
if (self.y < 0 || self.y > 2732 || self.x < 0 || self.x > 2048) {
enemyArrowPool.recycle(self);
}
};
@@ -611,8 +628,9 @@
alpha: 0.3,
scaleX: 1,
scaleY: 0.3
});
+ // In the EnemyShadow class, update method (around line 1018)
self.update = function (enemy) {
if (!enemy || !enemy.visible || enemy.hasExploded) {
self.visible = false;
return;
@@ -635,8 +653,12 @@
// For falling enemies, shadow holds last position
else if (enemy.state === 'falling') {
// Y position stays the same
}
+ // Special case for EnemyTwo type
+ else if (enemy.type === 2) {
+ self.y = enemy.y + 600; // Position higher for enemy type 2
+ }
// Scale shadow based on enemy's scale
shadow.scaleX = enemy.scaleX * 1.2;
shadow.scaleY = enemy.scaleX * 0.3;
};
@@ -658,12 +680,12 @@
anchorX: 0.5,
anchorY: 0.5
});
// Properties
- self.health = 2;
+ self.health = 1;
self.type = 2; // For scoring
self.state = 'approaching'; // approaching, holding
- self.holdDistance = 400;
+ self.holdDistance = 800;
self.bobOffset = 0;
self.bobSpeed = 0.05;
self.lastShotTime = 0;
self.shotInterval = 2000; // 2 seconds
@@ -671,11 +693,15 @@
self.visible = true;
self.x = x;
self.y = y;
self.state = 'approaching';
- self.health = 2;
+ self.health = 1;
self.rotation = 0;
- self.shadow = enemyShadowPool.spawn(x, y, self.scaleX);
+ self.hasExploded = false; // Make sure this flag is set
+ // Ensure shadow is created and stored
+ if (!self.shadow) {
+ self.shadow = enemyShadowPool.spawn(x, y, self.scaleX);
+ }
// Moving direction
self.moveRight = x < 1024; // If spawned on left side, move right
// Initial scale based on distance from horizon
var progress = Math.max(0, self.y - flyingBackground.horizonY) / (2732 - flyingBackground.horizonY);
@@ -694,14 +720,14 @@
var dx = dragon.x - self.x;
var dy = dragon.y - self.y + self.bobOffset;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > self.holdDistance) {
- self.x += dx * 0.02;
- self.y += dy * 0.02;
- // Update scale while approaching
+ self.x += dx * 0.01; // Reduced from 0.02
+ self.y += dy * 0.01; // Reduced from 0.02
+ // Modified scale calculation to maintain larger size
var progress = Math.max(0, self.y - flyingBackground.horizonY) / (2732 - flyingBackground.horizonY);
- self.scaleX = 0.5 + progress;
- self.scaleY = 0.5 + progress;
+ self.scaleX = 0.7 + progress * 0.5; // Modified from 0.5 + progress
+ self.scaleY = 0.7 + progress * 0.5; // Modified from 0.5 + progress
} else {
self.state = 'holding';
}
break;
@@ -712,9 +738,9 @@
// Keep on screen
targetX = Math.max(100, Math.min(1948, targetX));
self.x = targetX;
// Stay below dragon with offset
- var targetY = dragon.y + 600; // Stay 200 pixels below dragon
+ var targetY = dragon.y + 800; // Stay 200 pixels below dragon
var currentY = self.y - self.bobOffset; // Remove bobbing to get true position
self.y = currentY + (targetY - currentY) * 0.1; // Smooth movement to target
// Apply bobbing to final position
self.y += self.bobOffset;
@@ -729,9 +755,9 @@
self.rotation += self.rotationSpeed;
self.fallSpeed += self.acceleration;
self.y += self.fallSpeed;
// Check for ground collision
- if (self.y >= dragonShadow.y && !self.hasExploded) {
+ if (self.shadow && self.y >= self.shadow.y && !self.hasExploded) {
self.hasExploded = true;
for (var i = 0; i < 20; i++) {
defeatParticlePool.spawn(self.x, self.y, 0xff0000);
}
@@ -1189,9 +1215,9 @@
var enemy = enemiesTwo[j];
var dx = fireball.x - enemy.x;
var dy = fireball.y - enemy.y;
var distance = Math.sqrt(dx * dx + dy * dy);
- if (distance < 100 * enemy.scaleX) {
+ if (distance < 150 * enemy.scaleX) {
if (enemy.hit()) {
score += enemy.type * 10;
scoreTxt.setText(score);
LK.setScore(score);
A clear blue sky background with no clouds.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
a small bush. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
a wooden arrow with red feathers and a metal arrow head. Completely vertical orientation. Cartoon. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A small vertical flame. Cartoon. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
a black scorch mark on the ground left by a meteor impact. cartoon. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A bright spark. Cartoon. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
a red heart. cartoon. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
An SVG of the word **BOSS** in sharp red font.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
An SVG of the word “Start” written in fire. Cartoon.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows