Code edit (21 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: objects[i].update is not a function' in or related to this line: 'objects[i].update();' Line Number: 681
Code edit (1 edits merged)
Please save this source code
Code edit (11 edits merged)
Please save this source code
User prompt
update as needed with: 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 }); // Position tracking variables var baselineY = 2732 * 0.2; // Default position in top fifth var targetX = 2048 / 2; var targetY = baselineY; var maxY = 2732 * 0.4; // Only allow in top 40% of screen 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; // Limit how far down the dragon can go targetY = Math.min(facekit.noseTip.y, maxY); // 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; // Update previous positions prevX = newX; prevY = newY; } else { // Return to baseline position gradually if no face detected if (prevX === null) { prevX = 2048 / 2; prevY = baselineY; } var newX = prevX * (1 - smoothingFactor) + (2048 / 2) * smoothingFactor; var newY = prevY * (1 - smoothingFactor) + baselineY * smoothingFactor; self.x = newX; self.y = newY; // Update previous positions prevX = newX; prevY = newY; } // Rest of the update method remains the same // 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; } // 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; head.scaleY = head.scaleY * 0.85 + targetScale * 0.15; headOpen.scaleX = head.scaleX; headOpen.scaleY = head.scaleY; } // Toggle dragon head assets based on mouth open state if (facekit && facekit.mouthOpen) { head.alpha = 0; headOpen.alpha = 1; } else { head.alpha = 1; headOpen.alpha = 0; } }; // Rest of the class remains the same function calculateFaceTilt() { // Existing code... } return self; });
Code edit (5 edits merged)
Please save this source code
User prompt
Add dragonBody asset to dragon head class. Initialize before dragonHead asset.
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 with: // 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; }
User prompt
Update with: var DragonHead = Container.expand(function () { var self = Container.call(this); // Dragon sprites 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 }); // 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; // 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; // Update previous positions prevX = newX; prevY = newY; } // Rotation tracking if (facekit.leftEye && facekit.rightEye) { targetTilt = calculateFaceTilt() * tiltScaleFactor; // Limit rotation to ±15 degrees (converting to radians) targetTilt = Math.max(-15, Math.min(15, targetTilt)) * (Math.PI / 180); self.rotation += (targetTilt - self.rotation) * tiltSmoothingFactor; } // 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; head.scaleY = head.scaleY * 0.85 + targetScale * 0.15; headOpen.scaleX = head.scaleX; headOpen.scaleY = head.scaleY; } // Toggle dragon head assets based on mouth open state if (facekit && facekit.mouthOpen) { head.alpha = 0; headOpen.alpha = 1; } else { head.alpha = 1; headOpen.alpha = 0; } }; 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; }); ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
Update as needed with: // First add these variables at the top of the DragonHead constructor: self.targetTilt = 0; self.tiltSmoothingFactor = 0.08; // Slightly slower than reference for extra stability self.tiltScaleFactor = 0.07; // Less extreme tilt // Then replace the existing rotation code in update() with: // Rotation tracking using eye-to-mouth relationship 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 var dx = facekit.mouthCenter.x - eyeMidX; var dy = facekit.mouthCenter.y - eyeMidY; var angle = -(Math.atan2(dx, dy)); // Convert to degrees for easier understanding, then scale down var angleDegrees = angle * (180 / Math.PI); self.targetTilt = (angleDegrees * self.tiltScaleFactor) * (Math.PI / 180); // Back to radians // Limit rotation (10 degrees = ~0.175 radians) self.targetTilt = Math.max(-0.175, Math.min(0.175, self.targetTilt)); // Apply rotation with smoothing self.rotation += (self.targetTilt - self.rotation) * self.tiltSmoothingFactor; } else { // Gradually return to vertical when face tracking is lost self.rotation += (0 - self.rotation) * 0.1; ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
Update with: // Completely revamped rotation handling if (facekit.leftEye && facekit.rightEye) { // Calculate angle between eyes var dx = facekit.rightEye.x - facekit.leftEye.x; var dy = facekit.rightEye.y - facekit.leftEye.y; // Get raw angle in radians var rawAngle = -Math.atan2(dy, dx); // Apply substantial deadzone - default to vertical var deadzone = 0.12; // About 7 degrees if (Math.abs(rawAngle) < deadzone) { self.targetRotation = 0; // Force vertical } else { // Apply non-linear scaling to reduce sensitivity while preserving direction var direction = Math.sign(rawAngle); var magnitude = Math.abs(rawAngle) - deadzone; var scaledMagnitude = magnitude * 0.3; // Very reduced sensitivity // Combined result with limits self.targetRotation = direction * Math.min(scaledMagnitude, 0.2); } // Apply very strong damping for stability self.rotationSmoothing = 0.05; // Slower response self.rotation += (self.targetRotation - self.rotation) * self.rotationSmoothing; } ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
Update with: // In the DragonHead class, replace the rotation calculation section with this: if (facekit.leftEye && facekit.rightEye) { // Calculate angle between eyes var dx = facekit.rightEye.x - facekit.leftEye.x; var dy = facekit.rightEye.y - facekit.leftEye.y; // Get angle in radians var rawAngle = -Math.atan2(dy, dx); // Apply deadzone for small movements (keep vertical by default) var deadzone = 0.05; // About 3 degrees if (Math.abs(rawAngle) < deadzone) { rawAngle = 0; } // Further reduce rotation sensitivity using a scale factor var scaleFactor = 0.5; // Reduce rotation amount rawAngle *= scaleFactor; // Limit rotation range self.targetRotation = Math.max(-0.25, Math.min(0.25, rawAngle)); // Apply stronger rotation damping for smoother transitions self.rotation += (self.targetRotation - self.rotation) * 0.08; } ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
Increase the speed of the field scroll by double
User prompt
Replace flyingbackground with: var FlyingBackground = Container.expand(function () { var self = Container.call(this); // Create a bottom container for field elements (will be rendered first/behind) self.bottomContainer = new Container(); self.addChild(self.bottomContainer); // Store the horizon line self.horizonY = 2732 / 2; // Create field background panels for scrolling self.fieldPanels = []; for (var i = 0; i < 3; i++) { var fieldPanel = self.bottomContainer.attachAsset('fieldBackground', { anchorX: 0.5, anchorY: 0, x: 2048 / 2, y: self.horizonY + (i * 1696) }); self.fieldPanels.push(fieldPanel); } // Create a top container (will be rendered last/in front) 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 }); // Field scroll speed self.scrollSpeed = 2; // Create clouds self.clouds = []; for (var i = 0; i < 8; i++) { // Start clouds with larger scale farther from horizon var startY = self.horizonY - 400 - Math.random() * 600; var distanceFromHorizon = Math.abs(startY - self.horizonY); var startScale = 0.5 + distanceFromHorizon / 800; var cloud = self.topContainer.attachAsset('cloudShape', { anchorX: 0.5, anchorY: 0.5, x: Math.random() * 2048, y: startY, alpha: 0.8, scaleX: startScale, scaleY: startScale * 0.8 }); // Store with motion properties self.clouds.push({ sprite: cloud, speedY: 1 + Math.random() * 2, speedX: (Math.random() - 0.5) * 1.5, // Slight side-to-side drift targetY: self.horizonY }); } // Create field elements self.fieldElements = []; for (var j = 0; j < 12; j++) { // Start field elements with larger scale farther from horizon var fieldStartY = self.horizonY + 400 + Math.random() * 800; var fieldDistanceFromHorizon = Math.abs(fieldStartY - self.horizonY); var fieldStartScale = 0.5 + fieldDistanceFromHorizon / 1000; var fieldElement = self.bottomContainer.attachAsset('fieldElement', { anchorX: 0.5, anchorY: 0.5, x: Math.random() * 2048, y: fieldStartY, scaleX: fieldStartScale, scaleY: fieldStartScale * 0.8 }); // Store with motion properties self.fieldElements.push({ sprite: fieldElement, speedY: 2 + Math.random() * 3, speedX: (Math.random() - 0.5) * 3, // More side-to-side movement for field elements targetY: self.horizonY }); } self.update = function () { // Scroll field panels for (var p = 0; p < self.fieldPanels.length; p++) { var panel = self.fieldPanels[p]; panel.y -= self.scrollSpeed; // If a panel scrolls completely above the horizon, reset it to the bottom if (panel.y + 1696 < self.horizonY) { // Find the lowest panel var lowestY = self.horizonY; for (var k = 0; k < self.fieldPanels.length; k++) { if (self.fieldPanels[k].y > lowestY) { lowestY = self.fieldPanels[k].y; } } // Place this panel below the lowest one panel.y = lowestY + 1696; } } // Update clouds for (var i = 0; i < self.clouds.length; i++) { var cloud = self.clouds[i]; // Move cloud toward horizon cloud.sprite.y += cloud.speedY; cloud.sprite.x += cloud.speedX; // Calculate scale based on distance from horizon var distanceFactor = Math.max(0.05, (cloud.sprite.y - self.horizonY) / -500); cloud.sprite.scaleX = distanceFactor; cloud.sprite.scaleY = distanceFactor * 0.8; // Adjust alpha for fade effect near horizon cloud.sprite.alpha = Math.min(0.9, distanceFactor); // Reset cloud if it reaches horizon or gets too small if (cloud.sprite.y >= self.horizonY - 10 || cloud.sprite.scaleX < 0.1) { cloud.sprite.y = self.horizonY - 800 - Math.random() * 400; cloud.sprite.x = Math.random() * 2048; var newDistanceFactor = (cloud.sprite.y - self.horizonY) / -500; cloud.sprite.scaleX = newDistanceFactor; cloud.sprite.scaleY = newDistanceFactor * 0.8; cloud.sprite.alpha = 0.8; } } // Update field elements for (var j = 0; j < self.fieldElements.length; j++) { var element = self.fieldElements[j]; // Move field element toward horizon element.sprite.y -= element.speedY; element.sprite.x += element.speedX; // Calculate scale based on distance from horizon var fieldDistanceFactor = Math.max(0.05, (element.sprite.y - self.horizonY) / 500); element.sprite.scaleX = fieldDistanceFactor; element.sprite.scaleY = fieldDistanceFactor * 0.8; // Adjust alpha for fade effect near horizon element.sprite.alpha = Math.min(0.9, fieldDistanceFactor); // Reset field element if it reaches horizon or goes off screen if (element.sprite.y <= self.horizonY + 10 || element.sprite.scaleX < 0.1 || element.sprite.x < -50 || element.sprite.x > 2048 + 50) { element.sprite.y = self.horizonY + 800 + Math.random() * 400; element.sprite.x = Math.random() * 2048; var newFieldDistanceFactor = (element.sprite.y - self.horizonY) / 500; element.sprite.scaleX = newFieldDistanceFactor; element.sprite.scaleY = newFieldDistanceFactor * 0.8; element.sprite.alpha = 0.9; } } }; return self; });
User prompt
Update the existing flyingbackground class as needed with: var FlyingBackground = Container.expand(function () { var self = Container.call(this); // Create a bottom container for field elements (will be rendered first/behind) self.bottomContainer = new Container(); self.addChild(self.bottomContainer); // Store the horizon line self.horizonY = 2732 / 2; // Create field background panels for scrolling self.fieldPanels = []; for (var i = 0; i < 3; i++) { var fieldPanel = self.bottomContainer.attachAsset('fieldBackground', { anchorX: 0.5, anchorY: 0, x: 2048 / 2, y: self.horizonY + (i * 1696) }); self.fieldPanels.push(fieldPanel); } // Create a top container (will be rendered last/in front) 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 }); // Field scroll speed self.scrollSpeed = 2; // [Rest of implementation for clouds and field elements...] self.update = function () { // Scroll field panels for (var p = 0; p < self.fieldPanels.length; p++) { var panel = self.fieldPanels[p]; panel.y -= self.scrollSpeed; // If a panel scrolls completely above the horizon, reset it to the bottom if (panel.y + 1696 < self.horizonY) { // Find the lowest panel var lowestY = self.horizonY; for (var k = 0; k < self.fieldPanels.length; k++) { if (self.fieldPanels[k].y > lowestY) { lowestY = self.fieldPanels[k].y; } } // Place this panel below the lowest one panel.y = lowestY + 1696; } } // [Rest of update code for clouds and field elements...] }; return self; });
User prompt
Update with: // In Enemy class, modify the activate function: self.activate = function (x, y, type) { self.type = type || 1; self.visible = true; self.toDestroy = false; // Set position from parameters self.x = x; self.y = y; // Reset scale to maximum when activated self.scaleX = 2.0; // Match maxScale from update method self.scaleY = 2.0; // Update the enemy graphic based on type var assetId = 'enemy1'; if (self.type === 2) { assetId = 'enemy2'; } else if (self.type === 3) { assetId = 'enemy3'; } // Update the existing enemy graphic or create a new one if (enemyGraphic) { enemyGraphic.destroy(); } enemyGraphic = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); // Set type-specific properties switch (self.type) { case 1: self.speed = 2; self.health = 1; break; case 2: self.speed = 1.5; self.health = 2; break; case 3: self.speed = 3; self.health = 1; break; } };
User prompt
Update with: // In the Fireball class, modify the update method: self.update = function () { if (!self.active) { return; } self.y += self.speed; // Create fire trail particles if (Math.random() < 0.3) { particlePool.spawn(self.x + (Math.random() * 40 - 20), self.y + 20); } // NEW CODE: Recycle when off screen if (self.y > 2732) { // Screen height fireballPool.recycle(self); } };
User prompt
Remove firepower and allow player to continually create fireballs
User prompt
Please fix the bug: 'ReferenceError: Can't find variable: firepower' in or related to this line: 'if (!gameActive || firepower < 10) {' Line Number: 523
User prompt
Remove the power bar and associated logic
User prompt
Update with: self.activate = function (x, y, type) { self.type = type || 1; self.visible = true; self.toDestroy = false; // Set position from parameters self.x = x; self.y = y; // Update the enemy graphic based on type var assetId = 'enemy1'; if (self.type === 2) { assetId = 'enemy2'; } else if (self.type === 3) { assetId = 'enemy3'; } // Update the existing enemy graphic or create a new one if (enemyGraphic) { enemyGraphic.destroy(); } enemyGraphic = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); // Set type-specific properties switch (self.type) { case 1: self.speed = 2; self.health = 1; break; case 2: self.speed = 1.5; self.health = 2; break; case 3: self.speed = 3; self.health = 1; break; } };
User prompt
Please fix the bug: 'TypeError: target is not an Object. (evaluating 'key in target')' in or related to this line: 'tween(enemyGraphic, {' Line Number: 195
/**** * 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 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 }); // 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; // 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 < -80 && Math.abs(eyeYDiff) < 30 || eyeYDiff > 30) { // Looking left (nose to left OR right eye lower) if (facekit.mouthOpen) { lookLeftOpen.alpha = 1; } else { lookLeft.alpha = 1; } showingTurnedHead = true; } else if (noseDiff > 80 && Math.abs(eyeYDiff) < 30 || eyeYDiff < -30) { // 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; head.scaleY = head.scaleY * 0.85 + targetScale * 0.15; headOpen.scaleX = head.scaleX; headOpen.scaleY = head.scaleY; } }; 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 Enemy = Container.expand(function (type) { var self = Container.call(this); var assetId = 'enemy1'; if (type === 2) { assetId = 'enemy2'; } if (type === 3) { assetId = 'enemy3'; } self.type = type || 1; var enemyGraphic = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); // Different enemy types have different speeds and health switch (self.type) { case 1: self.speed = 2; self.health = 1; break; case 2: self.speed = 1.5; self.health = 2; break; case 3: self.speed = 3; self.health = 1; break; } self.activate = function (x, y, type) { self.type = type || 1; self.visible = true; self.toDestroy = false; // Set position from parameters self.x = x; self.y = y; // Reset scale to maximum when activated self.scaleX = 2.0; // Match maxScale from update method self.scaleY = 2.0; // Update the enemy graphic based on type var assetId = 'enemy1'; if (self.type === 2) { assetId = 'enemy2'; } else if (self.type === 3) { assetId = 'enemy3'; } // Update the existing enemy graphic or create a new one if (enemyGraphic) { enemyGraphic.destroy(); } enemyGraphic = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); // Set type-specific properties switch (self.type) { case 1: self.speed = 2; self.health = 1; break; case 2: self.speed = 1.5; self.health = 2; break; case 3: self.speed = 3; self.health = 1; break; } }; self.update = function () { self.y -= self.speed; // Enemies move up the screen toward the player // Only start scaling when actually on screen var maxDistance = 2732; // Screen height var minScale = 0.3; // Smallest size var maxScale = 2.0; // Largest size // Keep full scale until enemy is actually on screen if (self.y <= maxDistance) { var distancePercent = self.y / maxDistance; var newScale = Math.max(0.3, minScale + distancePercent * (maxScale - minScale)); // Ensure minimum scale // Apply scaling self.scaleX = newScale; self.scaleY = newScale; } else { // Keep maximum scale while off-screen self.scaleX = maxScale; self.scaleY = maxScale; } // Also ensure visibility is maintained self.visible = true; }; self.hit = function () { self.health--; if (self.health <= 0) { // Immediate visual feedback LK.effects.flashObject(enemyGraphic, 0xff0000, 200); // Play death effect and IMMEDIATELY recycle if (self.type === 1) { tween(enemyGraphic, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 500, easing: tween.easeOut }); } else if (self.type === 2) { tween(enemyGraphic, { rotation: Math.PI * 4, y: self.y + 300 }, { duration: 700, easing: tween.easeIn }); } else if (self.type === 3) { tween(enemyGraphic, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 300, easing: tween.easeOut }); } // Immediately recycle - no waiting for animation enemyPool.recycle(self); return true; } return false; }; self.deactivate = function () { self.visible = false; self.toDestroy = false; }; 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; // 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; // Reset horizontal velocity on activation }; self.deactivate = function () { self.visible = false; self.active = false; }; 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 }); // 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; sprite.scaleY = fieldDistanceFactor * 0.8; // 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; } } } } 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 || obj._poolIndex >= activeCount) { return; } // Already recycled 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.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(); for (var i = 0; i < fireballs.length; i++) { var fireball = fireballs[i]; for (var j = 0; j < enemies.length; 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) { // Adjusted collision radius 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, 50); var gameActive = true; var isFiring = false; var lastFireTime = 0; var fireRate = 150; // ms between fireballs var enemySpawnRate = 60; // 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 game.addChild(fireballPool); game.addChild(particlePool); game.addChild(enemyPool); // 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 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; // Add strong sideways component when head is turned if (noseDiff < -80 && Math.abs(eyeYDiff) < 15 || eyeYDiff > 15) { // Facing left - fireballs go left angleOffset = -8; } else if (noseDiff > 80 && Math.abs(eyeYDiff) < 15 || eyeYDiff < -15) { // Facing right - fireballs go right angleOffset = 8; } } // Add additional angle from dragon tilt (subtle effect on top of head direction) if (dragon.rotation) { angleOffset += dragon.rotation * 5; // Reduced from 10 to make this a secondary effect } // 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 type = Math.floor(Math.random() * 3) + 1; var enemy = enemyPool.spawn(Math.random() * (2048 - 200) + 100, 2732 + 100, type); if (enemy) { enemy.activate(enemy.x, enemy.y, type); // Ensure enemy is activated with correct parameters enemy.visible = true; // Force visibility } } // 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(); } // Update all pools fireballPool.update(); enemyPool.update(); particlePool.update(); // Process collisions processCollisions(); }; // Start background music LK.playMusic('gameMusic', { fade: { start: 0, end: 0.3, duration: 1000 } });
===================================================================
--- original.js
+++ change.js
@@ -7,8 +7,30 @@
/****
* 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 DragonHead = Container.expand(function () {
var self = Container.call(this);
// Dragon sprites
var body = self.attachAsset('dragonBody', {
@@ -102,29 +124,48 @@
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;
- // Check direction and mouth state
- if (noseDiff < -80) {
- // Looking left
+ // Combined detection logic
+ var showingTurnedHead = false;
+ if (noseDiff < -80 && Math.abs(eyeYDiff) < 30 || eyeYDiff > 30) {
+ // Looking left (nose to left OR right eye lower)
if (facekit.mouthOpen) {
lookLeftOpen.alpha = 1;
} else {
lookLeft.alpha = 1;
}
- } else if (noseDiff > 80) {
- // Looking right
+ showingTurnedHead = true;
+ } else if (noseDiff > 80 && Math.abs(eyeYDiff) < 30 || eyeYDiff < -30) {
+ // 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);
@@ -142,16 +183,8 @@
head.scaleY = head.scaleY * 0.85 + targetScale * 0.15;
headOpen.scaleX = head.scaleX;
headOpen.scaleY = head.scaleY;
}
- // Toggle dragon head assets based on mouth open state
- if (facekit && facekit.mouthOpen) {
- head.alpha = 0;
- headOpen.alpha = 1;
- } else {
- head.alpha = 1;
- headOpen.alpha = 0;
- }
};
function calculateFaceTilt() {
if (facekit.leftEye && facekit.rightEye && facekit.mouthCenter) {
// Calculate midpoint between eyes
@@ -303,8 +336,29 @@
self.toDestroy = false;
};
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,
@@ -339,54 +393,57 @@
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;
// Create fire trail particles
if (Math.random() < 0.3) {
particlePool.spawn(self.x + (Math.random() * 40 - 20), self.y + 20);
}
- // NEW CODE: Recycle when off screen
- if (self.y > 2732) {
- // Screen height
+ // 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; // Reset horizontal velocity on activation
};
self.deactivate = function () {
self.visible = false;
self.active = false;
- // Remove array manipulation from here
};
return self;
});
var FlyingBackground = Container.expand(function () {
var self = Container.call(this);
- // Create a bottom container for field elements (will be rendered first/behind)
+ // 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;
- // Place first stripe slightly below horizon
var lastY = self.horizonY + 10;
var stripe = self.bottomContainer.attachAsset('fieldStripes', {
anchorX: 0.5,
anchorY: 0,
@@ -398,9 +455,8 @@
self.fieldStripes.push({
sprite: stripe,
progress: progress
});
- // Place each subsequent stripe using same logic
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', {
@@ -416,9 +472,9 @@
progress: progress
});
lastY = y;
}
- // Create a top container (will be rendered last/in front)
+ // Create top container
self.topContainer = new Container();
self.addChild(self.topContainer);
// Create sky background in top container
var sky = self.topContainer.attachAsset('skyBackground', {
@@ -428,153 +484,144 @@
y: self.horizonY
});
// Field scroll speed
self.scrollSpeed = 4;
- // Create clouds
- self.clouds = [];
+ // 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++) {
- // Start clouds with larger scale farther from horizon
var startY = self.horizonY - 400 - Math.random() * 600;
var distanceFromHorizon = Math.abs(startY - self.horizonY);
var startScale = 0.5 + distanceFromHorizon / 800;
- var cloud = self.topContainer.attachAsset('cloudShape', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: Math.random() * 2048,
- y: startY,
- alpha: 0.8,
- scaleX: startScale,
- scaleY: startScale * 0.8
- });
- // Store with motion properties
- self.clouds.push({
- sprite: cloud,
- speedY: 1 + Math.random() * 2,
- speedX: (Math.random() - 0.5) * 1.5,
- // Slight side-to-side drift
- targetY: self.horizonY
- });
+ var cloud = self.cloudPool.spawn(Math.random() * 2048, startY, startScale, 0.8);
+ if (cloud) {
+ cloud.horizonY = self.horizonY;
+ }
}
- // Create field elements
- self.fieldElements = [];
- // Create initial field elements properly distributed
+ // Initialize field elements
for (var j = 0; j < 12; j++) {
- // Start with elements throughout the lower half of screen
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.bottomContainer.attachAsset('fieldElement', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: Math.random() * 2048,
- y: fieldStartY,
- scaleX: fieldStartScale,
- scaleY: fieldStartScale * 0.8
- });
- // Store with fixed X position and Y-only movement
- self.fieldElements.push({
- sprite: fieldElement,
- speedY: 2 + Math.random() * 3,
- initialX: fieldElement.x,
- targetY: self.horizonY
- });
+ 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 (lowest Y value - closest to top of screen - first)
+ // Sort stripes by Y position
self.fieldStripes.sort(function (a, b) {
return a.sprite.y - b.sprite.y;
});
- // Reset any stripes that have moved above horizon
+ // Reset stripes that moved above horizon
for (var i = 0; i < self.fieldStripes.length; i++) {
if (self.fieldStripes[i].sprite.y < self.horizonY) {
- // Find the lowest stripe
var lowestStripe = self.fieldStripes[self.fieldStripes.length - 1];
- // Position this stripe below the lowest one
self.fieldStripes[i].sprite.y = lowestStripe.sprite.y + 400 * (lowestStripe.sprite.y - self.horizonY) / self.totalHeight;
- // Recalculate progress
self.fieldStripes[i].progress = Math.max(0, self.fieldStripes[i].sprite.y - self.horizonY) / self.totalHeight;
}
}
- // Re-sort after any repositioning
+ // Re-sort after repositioning
self.fieldStripes.sort(function (a, b) {
return a.sprite.y - b.sprite.y;
});
- // Adjust heights to ensure stripes connect perfectly
+ // Adjust stripe heights
for (var i = 0; i < self.fieldStripes.length - 1; i++) {
var currentStripe = self.fieldStripes[i];
var nextStripe = self.fieldStripes[i + 1];
- // Set height to exactly reach the next stripe
currentStripe.sprite.height = nextStripe.sprite.y - currentStripe.sprite.y;
}
- // Special case for the last stripe - extend it far enough
+ // 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 // Add some buffer
- );
- // Update clouds
- for (var i = 0; i < self.clouds.length; i++) {
- var cloud = self.clouds[i];
+ 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.sprite.y += cloud.speedY;
- cloud.sprite.x += cloud.speedX;
+ 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.sprite.y - self.horizonY) / -500);
- cloud.sprite.scaleX = distanceFactor;
- cloud.sprite.scaleY = distanceFactor * 0.8;
+ 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
- cloud.sprite.alpha = Math.min(0.9, distanceFactor);
+ sprite.alpha = Math.min(0.9, distanceFactor);
// Reset cloud if it reaches horizon or gets too small
- if (cloud.sprite.y >= self.horizonY - 10 || cloud.sprite.scaleX < 0.1) {
- cloud.sprite.y = self.horizonY - 800 - Math.random() * 400;
- cloud.sprite.x = Math.random() * 2048;
- var newDistanceFactor = (cloud.sprite.y - self.horizonY) / -500;
- cloud.sprite.scaleX = newDistanceFactor;
- cloud.sprite.scaleY = newDistanceFactor * 0.8;
- cloud.sprite.alpha = 0.8;
+ 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;
+ }
}
}
- // Update field elements
- for (var j = 0; j < self.fieldElements.length; j++) {
- var element = self.fieldElements[j];
+ }
+ 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.sprite.y - self.horizonY) / self.totalHeight;
- // Use the same scrolling speed calculation as the stripes
+ 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 field element toward horizon on Y axis only
- element.sprite.y -= tempSpeed;
+ // 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.sprite.y - self.horizonY) / 500);
- element.sprite.scaleX = fieldDistanceFactor;
- element.sprite.scaleY = fieldDistanceFactor * 0.8;
- // Adjust alpha for fade effect near horizon
- element.sprite.alpha = Math.min(0.9, fieldDistanceFactor);
- // Reset field element if it reaches horizon
- if (element.sprite.y <= self.horizonY + 10 || element.sprite.scaleX < 0.1) {
- // Spawn from bottom of screen
- element.sprite.y = 2732 + Math.random() * 200;
- // Randomize X position only on respawn
- element.initialX = Math.random() * 2048;
- element.sprite.x = element.initialX;
- var newFieldDistanceFactor = (element.sprite.y - self.horizonY) / 500;
- element.sprite.scaleX = newFieldDistanceFactor;
- element.sprite.scaleY = newFieldDistanceFactor * 0.8;
- element.sprite.alpha = 0.9;
+ var fieldDistanceFactor = Math.max(0.05, (element.y - self.horizonY) / 300);
+ sprite.scaleX = fieldDistanceFactor;
+ sprite.scaleY = fieldDistanceFactor * 0.8;
+ // 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;
+ }
}
}
- };
+ }
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);
@@ -685,8 +732,9 @@
function createFireParticle(x, y) {
particlePool.spawn(x, y);
}
// Function to spawn a fireball
+// Update the spawnFireball function
function spawnFireball() {
if (!gameActive) {
return;
}
@@ -694,10 +742,34 @@
if (now - lastFireTime < fireRate) {
return;
}
lastFireTime = now;
+ // Initialize horizontal velocity components
+ var angleOffset = 0;
+ // Get direction from dragon head facing
+ 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;
+ // Add strong sideways component when head is turned
+ if (noseDiff < -80 && Math.abs(eyeYDiff) < 15 || eyeYDiff > 15) {
+ // Facing left - fireballs go left
+ angleOffset = -8;
+ } else if (noseDiff > 80 && Math.abs(eyeYDiff) < 15 || eyeYDiff < -15) {
+ // Facing right - fireballs go right
+ angleOffset = 8;
+ }
+ }
+ // Add additional angle from dragon tilt (subtle effect on top of head direction)
+ if (dragon.rotation) {
+ angleOffset += dragon.rotation * 5; // Reduced from 10 to make this a secondary effect
+ }
// 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
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