User prompt
Clear memory to avoid lags
User prompt
And the loading of signals is too incomplete! I told you that you can't leave so much space between them that it can be easily jumped over!
User prompt
Please fix the bug: 'LRUCache is not defined' in or related to this line: 'var signalCache = new LRUCache({' Line Number: 779
User prompt
There are lot of lags with signals. Fix it and make the game running smooter
User prompt
Facilitate the loading of signals a little more to the center of the screen
User prompt
YOU PUT TOO MANY RED SIGNALS NEXT TO EACH OTHER, EVEN THOUGH I TOLD YOU THAT YOU CAN'T HAVE MORE THAN 5 RED SIGNALS NEXT TO EACH OTHER AT THE SAME TIME!!
User prompt
Avoid lags. Avoid signal overlap an other signal. Make game running smooter.
User prompt
Avoid lags. Avoid signal overlap an other signal. Make game running smooter.
User prompt
There is a mistake with the player. After a while, it grabs itself and disappears on the left edge of the screen. Prevent this! The player can only jump horizontally at a fixed point!
User prompt
Ensure the game start easier
User prompt
The layout of the signals too boring. Change the layout of the signals to be more realistic to better resemble the fluctuating look of the real stock market.
User prompt
Change the layout of the signals to be more realistic to better resemble the fluctuating look of the real stock market
User prompt
The sharks only push up every second signal to make the game more varied
User prompt
The sharks only push up every third signal to make the game more varied
User prompt
The sharks only push up every second signal to make the game more varied
User prompt
Sharks move signals too high. Refine it with less
User prompt
The layout of the signals should have a cascading appearance.
User prompt
The layout of the signals should have a cascading appearance.
User prompt
The layout of the signals should have a cascading appearance.
User prompt
The layout of the signals should have a cascading appearance. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
The arrangement of the signals should look like an equalizer. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
allow the double jumping by clicking again mid jump.
User prompt
You set the top signals too high. Move them down by 444 units!
User prompt
You set the top signals too high. Put them down 444 units
User prompt
It is impossible to jump the signals. Fix it
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var BonusText = Container.expand(function (amount, type) { var self = Container.call(this); // Create bonus text display var bonusAmount = amount || 100; // Filter out 'glaud' from type if present if (type && type.toLowerCase().includes('glaud')) { type = 'BONUS'; // Replace with generic text } // Create text with filtered content var displayText = type ? '+' + bonusAmount + ' ' + type : '+' + bonusAmount + ' BONUS'; var bonusText = new Text2(displayText, { size: 100, fill: 0xFFD700 // Gold color }); bonusText.anchor.set(0.5, 0.5); self.addChild(bonusText); // Start animation self.animate = function () { // Initial state self.alpha = 0; self.scale.set(0.5); // Animation sequence - fade in with scale up (with memory optimizations) // Store tween reference so it can be cancelled if needed self.currentTween = tween(self, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Pulse effect self.currentTween = tween(bonusText, { tint: 0xFFFFFF // Flash to white }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { self.currentTween = tween(bonusText, { tint: 0xFFD700 // Back to gold }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { // Fade out with float up self.currentTween = tween(self, { alpha: 0, y: self.y - 100 }, { duration: 800, easing: tween.linear, onFinish: function onFinish() { self.active = false; } }); } }); } }); } }); }; self.active = true; // Add cleanup method to properly release memory when destroyed self.cleanup = function () { // Cancel any active tweens tween.cancel(self); tween.cancel(bonusText); // Clear references bonusText = null; self.removeChildren(); }; return self; }); var Memecoin = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'regular'; // Filter out 'glaud' content if (self.type === 'glaud') { self.type = 'regular'; // Replace with default type } var assetId; if (self.type === 'dogmeme') { assetId = 'dogmeme'; } else if (self.type === 'shib') { assetId = 'shib'; } else if (self.type === 'pepe') { assetId = 'pepe'; } else if (self.type === 'loki') { assetId = 'loki'; } else if (self.type === 'volt') { assetId = 'volt'; } else if (self.type === 'cat') { assetId = 'cat'; } else if (self.type === 'president') { assetId = 'president'; } else { assetId = 'memecoin'; } var coinGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); self.speed = 6; self.active = true; self.collected = false; self.value = self.type === 'dogmeme' ? 100 : self.type === 'shib' ? 150 : self.type === 'pepe' ? 200 : self.type === 'loki' ? 250 : self.type === 'volt' ? 300 : self.type === 'cat' ? 350 : self.type === 'president' ? 400 : 50; // President worth more points than cat self.update = function () { if (!self.active) { return; } self.x -= self.speed; // Rotate coin counterclockwise (negative value for opposite direction) coinGraphics.rotation -= 0.03; // Remove when off screen if (self.x < -100) { self.active = false; } }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.vx = 0; self.vy = 0; self.gravity = 0.5; self.jumpPower = -25; // Increased jump power from -15 to -25 self.isJumping = false; self.isDead = false; self.lastWasIntersecting = false; self.isSomersaulting = false; self.lastClickTime = 0; self.clickCount = 0; self.somersault = function () { if (self.isSomersaulting) { return; } self.isSomersaulting = true; self.vy = self.jumpPower * 1.2; // Higher jump for somersault self.isJumping = true; LK.getSound('jump').play(); // Reset rotation to avoid compounding rotations playerGraphics.rotation = 0; // First tween: slow start of rotation (0 to 90 degrees) tween(playerGraphics, { rotation: Math.PI / 2 // 90 degrees }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { // Second tween: fast middle rotation (90 to 270 degrees) tween(playerGraphics, { rotation: Math.PI * 1.5 // 270 degrees }, { duration: 400, easing: tween.linear, onFinish: function onFinish() { // Third tween: slow end of rotation (270 to 360 degrees) tween(playerGraphics, { rotation: Math.PI * 2 // 360 degrees }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { self.isSomersaulting = false; playerGraphics.rotation = 0; // Reset rotation after completing } }); } }); } }); }; self.jump = function (x, y) { // Check if the click was in the upper half of the screen var isUpperScreen = y < 2732 / 2; // Check for double click (tap) for somersault var currentTime = Date.now(); // Find if player is standing on a green signal with more precise detection var standingOnGreenSignal = signals.some(function (s) { return player && s.type === 'green' && player.intersects(s) && Math.abs(player.y - (s.y - 275)) < 20; }); // If clicked in upper half and player is on ground or signal, do somersault if (isUpperScreen && (self.vy === 0 || standingOnGreenSignal)) { // Add visual feedback with slight bounce effect tween(playerGraphics, { scaleX: 0.85, scaleY: 1.15 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(playerGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeIn }); self.somersault(); } }); return; } // Regular jump if in lower half of screen // Improved double-tap detection with more forgiving timing var timeDiff = currentTime - self.lastClickTime; if (timeDiff < 300 && timeDiff > 50 && (self.vy === 0 || standingOnGreenSignal)) { // Increased window from 250ms to 300ms for more reliable double-tap detection // Added minimum time of 50ms to prevent accidental double-tap from single long press self.clickCount++; if (self.clickCount === 2) { // Add visual feedback with slight bounce effect tween(playerGraphics, { scaleX: 0.85, scaleY: 1.15 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(playerGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeIn }); self.somersault(); } }); self.clickCount = 0; return; } } else if (timeDiff >= 300) { // Only reset click count if enough time has passed self.clickCount = 1; } self.lastClickTime = currentTime; // Regular jump logic if (!self.isDead && (self.vy === 0 || standingOnGreenSignal)) { self.vy = self.jumpPower; self.isJumping = true; LK.getSound('jump').play(); LK.getSound('jump').play(); } }; self.update = function () { if (self.isDead) { return; } // Store last position for collision detection self.lastY = self.y; // Apply gravity with smoothing for somersault if (self.isSomersaulting) { // Reduced gravity during somersault for a floatier feel self.vy += self.gravity * 0.8; // Add slight horizontal movement during somersault for more dynamic movement if (!self.somersaultDirection) { // Set random direction for horizontal drift during somersault self.somersaultDirection = Math.random() > 0.5 ? 1 : -1; } // Apply horizontal drift during somersault self.x += self.somersaultDirection * 1.5; } else { // Regular gravity self.vy += self.gravity; // Reset somersault direction self.somersaultDirection = null; } // Apply movement with smoothing self.y += self.vy; // Keep player at a fixed horizontal position self.x = 400; // Track if player is jumping or falling self.isJumping = self.vy !== 0; // Ground collision detection if (self.y > 2732 - playerGraphics.height / 2) { // Bottom of screen self.y = 2732 - playerGraphics.height / 2; self.vy = 0; self.isJumping = false; } }; return self; }); var Shark = Container.expand(function () { var self = Container.call(this); var sharkGraphics = self.attachAsset('shark', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.direction = 1; self.centerY = 2732 - sharkGraphics.height / 2 + 123; // Move sharks down by 123 units self.update = function () { // If sharks are orbiting, follow orbit pattern instead of normal movement if (orbiting) { // Keep track of which shark this is (1 or 2) var sharkIndex = this === shark2 ? 1 : 0; var offsetAngle = sharkIndex * Math.PI; // 180 degrees offset for second shark // Calculate position based on orbit angle var orbitRadius = 150; // Reduced radius of orbit from 200 to 150 for tighter movement // Increase orbit speed during tornado effect var orbitSpeed = 2.5; // Increased orbit speed factor self.x = orbitCenterX + Math.cos(orbitAngle * orbitSpeed + offsetAngle) * orbitRadius; self.y = orbitCenterY + Math.sin(orbitAngle * orbitSpeed + offsetAngle) * orbitRadius / 2; // More compressed elliptical orbit // Set shark orientation based on movement direction var movingRight = Math.cos(orbitAngle * orbitSpeed + offsetAngle + Math.PI / 2) > 0; sharkGraphics.scale.x = movingRight ? 1 : -1; return; // Skip normal movement logic when orbiting } // Normal movement when not orbiting // Keep shark at constant y position self.y = self.centerY; // Check if player exists and has fallen to shark's height level if (player && player.y > 2732 - 350) { // Shark hunts player - move toward player position self.direction = player.x > self.x ? 1 : -1; self.speed = 8; // Increase speed when hunting // Set correct shark orientation based on direction sharkGraphics.scale.x = self.direction; } else { // Normal back-and-forth movement when player isn't at shark level self.speed = 5; // Check if this is the second shark (compare to the global shark2 reference) if (this === shark2) { // Second shark moves in opposite pattern to first shark (alternating pattern) // Start swimming from right to left if (self.x <= 200 && self.direction === -1) { self.direction = 1; sharkGraphics.scale.x = 1; } else if (self.x >= 1900 && self.direction === 1) { self.direction = -1; sharkGraphics.scale.x = -1; } } else { // First shark patrols from left to right first if (self.x >= 1800 && self.direction === 1) { self.direction = -1; sharkGraphics.scale.x = -1; } else if (self.x <= 200 && self.direction === -1) { self.direction = 1; sharkGraphics.scale.x = 1; } } } // Apply movement self.x += self.speed * self.direction; }; return self; }); var Signal = Container.expand(function (type) { var self = Container.call(this); self.type = type || 'green'; var assetId = self.type === 'green' ? 'greenSignal' : 'redSignal'; // Generate random width variation factor between 0.6 and 1.4 for more dramatic variation var widthVariation = 0.6 + Math.random() * 0.8; var signalGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5, scaleX: 1 / 1.2 * widthVariation, scaleY: 1 / 1.2 }); // Rotate signal by 90 degrees to the left signalGraphics.rotation = -Math.PI / 2; // -90 degrees in radians self.speed = 3.5; self.active = true; self.shineTimer = 0; self.isShining = false; // Store the width variation for calculations self.widthVariation = widthVariation; self.changeType = function (newType) { // If type is already correct and graphics likely match, no change needed. // This check is simplified; perfect asset matching is hard without direct assetId on graphics. if (self.type === newType) { return; } var oldGraphics = self.children.length > 0 ? self.children[0] : null; // Get properties from old graphics if available. // self.widthVariation is set in the constructor and should be reliable. var oldRotation = oldGraphics ? oldGraphics.rotation : -Math.PI / 2; // Default rotation var oldScaleX = oldGraphics ? oldGraphics.scale.x : 1 / 1.2 * self.widthVariation; var oldScaleY = oldGraphics ? oldGraphics.scale.y : 1 / 1.2; if (oldGraphics) { self.removeChild(oldGraphics); } self.type = newType; // Set type before attaching asset, as assetId depends on it. var assetId = self.type === 'green' ? 'greenSignal' : 'redSignal'; var newSignalGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5, scaleX: oldScaleX, scaleY: oldScaleY }); newSignalGraphics.rotation = oldRotation; // Reset states that might be type-specific or visual self.isGolden = false; // Changing type removes golden status if (self.shimmerAnimationActive) { self.shimmerAnimationActive = false; if (newSignalGraphics) newSignalGraphics.tint = 0xFFFFFF; // Reset tint of new graphics } // self.flashedRed might need reset if applicable, but currently used for falling. }; // Create shine effect self.startShine = function () { if (!self.isShining) { self.isShining = true; var baseColor = self.type === 'green' ? 0xFFFFFF : 0xFFFFFF; // Shine effect with tween tween(signalGraphics, { alpha: 0.8 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { tween(signalGraphics, { alpha: 1 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { self.isShining = false; } }); } }); } }; // Turn green signal golden when touched by player // Create shimmer animation with color tint alternation self.startShimmerAnimation = function (targetGraphics) { self.shimmerAnimationActive = true; // Golden to bright white shimmer function shimmerCycle() { if (!self.shimmerAnimationActive) { return; } // Shimmer to bright white tween(targetGraphics, { tint: 0xFFFFFF // Bright white }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { if (!self.shimmerAnimationActive) { return; } // Return to gold tween(targetGraphics, { tint: 0xFFD700 // Gold color }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { if (self.shimmerAnimationActive) { // Continue animation cycle shimmerCycle(); } } }); } }); } // Start shimmer cycle shimmerCycle(); }; self.turnGolden = function () { if (self.type === 'green' && !self.isGolden) { self.isGolden = true; var goldenSignalGraphics = LK.getAsset('goldenSignal', { anchorX: 0.5, anchorY: 0.5, scaleX: 1 / 1.2, scaleY: 1 / 1.2 }); // Match the rotation of the current signal goldenSignalGraphics.rotation = signalGraphics.rotation; // Animation sequence for golden transformation tween(signalGraphics, { alpha: 0 }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { // Replace the green signal with golden one self.removeChild(signalGraphics); self.addChild(goldenSignalGraphics); // Start with small scale and expand goldenSignalGraphics.scale.set(0.5, 0.5); goldenSignalGraphics.alpha = 0.7; // Grow and fade in tween(goldenSignalGraphics, { scaleX: 1 / 1.2, scaleY: 1 / 1.2, alpha: 1 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { // Start shimmer animation after the initial grow animation self.startShimmerAnimation(goldenSignalGraphics); } }); } }); } }; self.falling = false; self.fallSpeed = 0; self.update = function () { if (!self.active) { // Clean up shimmer animation if it's running if (self.shimmerAnimationActive) { self.shimmerAnimationActive = false; } return; } // Handle falling behavior for red signals if (self.falling) { self.fallSpeed += 0.5; // Gravity effect self.y += self.fallSpeed; // Rotate while falling self.children[0].rotation += 0.05; // Apply red flash effect when signal starts falling (if it hasn't been flashed already) if (!self.flashedRed && self.fallSpeed < 3) { self.flashedRed = true; LK.effects.flashObject(self, 0xff4500, 500); // Flash red } // Deactivate when off bottom of screen if (self.y > 2732 + 100) { self.active = false; } return; // Skip normal behavior when falling } self.x -= self.speed; // Add random shine effect occasionally self.shineTimer++; if (self.shineTimer > 60 && Math.random() < 0.05) { self.startShine(); self.shineTimer = 0; } // Check if red signal is touching a shark if (self.type === 'red' && (shark && self.intersects(shark) || shark2 && self.intersects(shark2))) { // Check if this signal is the lowest red signal touching the shark var lowestRedSignal = true; var currentShark = shark && self.intersects(shark) ? shark : shark2; // Check if there are any other red signals lower than this one also touching the shark for (var i = 0; i < signals.length; i++) { var otherSignal = signals[i]; if (otherSignal !== self && otherSignal.active && otherSignal.type === 'red' && otherSignal.y > self.y && otherSignal.intersects(currentShark)) { lowestRedSignal = false; break; } } // Only affect this signal if it's the lowest red signal touching the shark and if it's every second signal if (lowestRedSignal && signals.indexOf(self) % 2 !== 0) { // Check if this is every second signal // Save the original y position before moving var startY = self.y; // Calculate target position with less variation (random amount between 100 and 500 upward) var moveAmount = 100 + Math.random() * 400; // Reduced maximum upward movement from 1800 to 500 var targetY = startY - moveAmount; // Change signal type to green using the new method self.changeType('green'); // Make the signal shine to highlight the change self.startShine(); // Use tween for smooth upward movement with reduced duration for a more controlled effect tween(self, { y: targetY }, { duration: 800, // Reduced duration for a more controlled effect easing: tween.easeOutQuad // Smoother deceleration for continuous movement }); } } // Check for signals getting too close to sharks // Shark is positioned close to bottom of screen (around 2732 - 100) var sharkYPosition = 2732 - 400; // Position above shark's height if (self.y > sharkYPosition) { // Move signal upward to avoid sharks self.y = sharkYPosition - Math.random() * 100; self.startShine(); // Visual indicator that signal moved } // Check for overlapping signals (only for active signals on screen) for (var i = 0; i < signals.length; i++) { var otherSignal = signals[i]; // Skip self and inactive signals if (otherSignal !== self && otherSignal.active) { // Check if signals are close to each other var xDistance = Math.abs(self.x - otherSignal.x); var yDistance = Math.abs(self.y - otherSignal.y); // If signals are overlapping or very close (within 20px) if (xDistance < 20 && yDistance < 20) { // Move this signal to avoid overlap if (self.type === 'green') { self.y -= 30; // Move green signals upward } else { self.y += 30; // Move red signals downward } // Trigger shine effect to show adjustment self.startShine(); } } } // Remove when off screen only if player is not jumping/falling // Make sure we keep signals visible while player is falling if (self.x < -200) { // Only deactivate if player doesn't exist or if player is not jumping/falling if (!player || !player.isJumping && player.vy <= 0) { self.active = false; } } }; return self; }); var Tornado = Container.expand(function () { var self = Container.call(this); // Create tornado graphics - optimize by reducing particle count self.particles = []; var numParticles = 20; // Reduced from 30 to 20 for better performance var colors = [0x87CEEB, 0x00BFFF, 0x1E90FF, 0x4682B4]; // Create particles that make up the tornado for (var i = 0; i < numParticles; i++) { var particle = new Container(); var size = 30 + Math.random() * 70; var shape = particle.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: size / 100, scaleY: size / 100, tint: colors[Math.floor(Math.random() * colors.length)] }); // Initial position particle.radius = 50 + i * 5; particle.angle = Math.random() * Math.PI * 2; particle.rotationSpeed = (0.03 + Math.random() * 0.05) * (Math.random() > 0.5 ? 1 : -1); particle.alpha = 0.5 + Math.random() * 0.5; // Set initial positions particle.x = Math.cos(particle.angle) * particle.radius; particle.y = Math.sin(particle.angle) * particle.radius; self.particles.push(particle); self.addChild(particle); } self.tornadoHeight = 0; // Current height of the tornado self.tornadoSpeed = 10; // How fast the tornado rises self.isActive = true; self.startY = 2732 - 400; // Start near the sharks self.topWidth = 50; // Width at top (narrow) self.bottomWidth = 500; // Width at bottom (wide) self.signalLimit = 3; // Fixed limit of exactly 3 signals self.signalsDestroyed = 0; // Counter for how many signals destroyed self.startTime = Date.now(); // Track when tornado started self.duration = 3000; // Duration in milliseconds (3 seconds) self.isSilent = false; // Track if tornado is in silent mode self.update = function () { if (!self.isActive) { return; } // Rise up self.tornadoHeight += self.tornadoSpeed; // Update all particles for (var i = 0; i < self.particles.length; i++) { var p = self.particles[i]; // Calculate relative height position (0-1) var relativeHeight = i / self.particles.length; // Width decreases as we go up var currentWidth = self.bottomWidth - (self.bottomWidth - self.topWidth) * relativeHeight; // Update angle for rotation - increase rotation speed by 2x p.angle += p.rotationSpeed * 2; // Position - wider at bottom, narrower at top p.x = Math.cos(p.angle) * (p.radius * (currentWidth / self.bottomWidth)); p.y = Math.sin(p.angle) * (p.radius * (currentWidth / self.bottomWidth)); // Adjust vertical position based on tornado height p.y -= self.tornadoHeight * relativeHeight; } // Check for signal collisions if (tornadoActive && self.signalsDestroyed < self.signalLimit) { for (var i = 0; i < signals.length; i++) { var signal = signals[i]; if (signal.active && !signal.falling && !tornadoSignals.includes(signal)) { // Check if signal is near the tornado var dx = signal.x - self.x; var dy = signal.y - (self.y - self.tornadoHeight / 2); var distance = Math.sqrt(dx * dx + dy * dy); // If signal is within tornado's effect range and we haven't hit the limit if (distance < 300 && self.signalsDestroyed < self.signalLimit) { // Add to affected signals tornadoSignals.push(signal); // Make it fall signal.falling = true; signal.fallSpeed = 2; signal.startShine(); // Add some sideways momentum based on tornado rotation signal.sideSpeed = Math.random() * 10 - 5; // Increment the counter self.signalsDestroyed++; } } } } }; return self; }); /**** * Initialize Game ****/ // Golden letter shimmer animation var game = new LK.Game({ backgroundColor: 0x00142A }); /**** * Game Code ****/ // Game variables // Golden letter shimmer animation var LetterShimmerEffect = function LetterShimmerEffect(letterText) { // Create shimmer animation cycle function startShimmer() { // Shimmer to bright white tween(letterText, { tint: 0xFFFFFF // Bright white }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { // Return to gold tween(letterText, { tint: 0xFFD700 // Gold color }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { // Continue animation cycle startShimmer(); } }); } }); } // Set initial state and start shimmer letterText.tint = 0xFFD700; // Gold color startShimmer(); }; var player; var signals = []; var memecoins = []; var shark; var shark2; var isGameActive = true; var gameSpeed = 1; var lastSignalTime = 0; var lastCoinTime = 0; var score = 0; var scoreIncrement = 0.1; var distanceTraveled = 0; var memecoinLetters = []; // Reference to MEMECOIN letters var nextLetterIndex = 0; // Track which letter to illuminate next var tornadoActive = false; var tornadoSignals = []; // Signals caught in tornado var lastOrbitTime = 0; // Track when sharks last started orbiting var orbiting = false; // Track if sharks are currently orbiting var orbitAngle = 0; // Current orbit angle var orbitCenterX = 0; // X center of orbit var orbitCenterY = 0; // Y center of orbit var tornadoY = 0; // Current Y position of tornado var coinRound = { regular: false, dogmeme: false, shib: false, pepe: false, loki: false, volt: false, cat: false, president: false }; // UI elements var scoreTxt; var highScoreTxt; // Initialize UI function initUI() { // Add watermark text var watermarkText = new Text2('@jzubora', { size: 18, fill: 0x808080 // Grey color }); watermarkText.anchor.set(1, 0); // Anchor to the top right corner LK.gui.topRight.addChild(watermarkText); // Add flashing effect to watermark function flashWatermark() { tween(watermarkText, { alpha: 0.5 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(watermarkText, { alpha: 1 }, { duration: 800, easing: tween.easeInOut, onFinish: flashWatermark }); } }); } flashWatermark(); // High score text var highScore = storage.highScore || 0; highScoreTxt = new Text2('HIGH SCORE: ' + Math.floor(highScore), { size: 50, fill: 0xFFD700 }); highScoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(highScoreTxt); highScoreTxt.y = 0; // Score text scoreTxt = new Text2('SCORE: 0', { size: 70, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.y = 60; // MEMECOIN letters container var memeLettersContainer = new Container(); memeLettersContainer.x = 0; memeLettersContainer.y = 140; // Move down by 10 units LK.gui.top.addChild(memeLettersContainer); // Initialize empty letter display memecoinLetters = []; // Use global variable to store letters var memecoinWord = "MEMECOIN"; // Ensure we never display 'glaud' if (memecoinWord.toLowerCase().includes('glaud')) { memecoinWord = "MEMECOIN"; // Force back to default } for (var i = 0; i < memecoinWord.length; i++) { var letterText = new Text2(memecoinWord[i], { size: 60, fill: 0xAAAAAA // Lighter gray (not collected) }); letterText.anchor.set(0.5, 0); letterText.x = (i - memecoinWord.length / 2 + 0.5) * 60 + 5; // Center the letters letterText.collected = false; memecoinLetters.push(letterText); memeLettersContainer.addChild(letterText); } } // Initialize game world function initGame() { isGameActive = true; score = 0; distanceTraveled = 0; gameSpeed = 1; // Reset coin round tracking coinRound = { regular: false, dogmeme: false, shib: false, pepe: false, loki: false, volt: false, cat: false, president: false }; // Reset MEMECOIN letters nextLetterIndex = 0; if (memecoinLetters && memecoinLetters.length > 0) { for (var i = 0; i < memecoinLetters.length; i++) { memecoinLetters[i].tint = 0x444444; // Reset to dark gray memecoinLetters[i].collected = false; } } // Create player at top left, ready to fall player = new Player(); player.x = 400; // Moved right by 200 units (from 200 to 400) player.y = 100; player.vy = 5; // Start with downward velocity game.addChild(player); // Create sharks shark = new Shark(); shark.y = 2732 - 100; game.addChild(shark); // Create second shark with opposite direction compared to first shark shark2 = new Shark(); shark2.x = 1500; // Position second shark on the right side shark2.y = 2732 - 100; shark2.direction = -1; // Start with opposite direction to make sharks swim alternately // Set correct orientation based on direction shark2.children[0].scale.x = -1; game.addChild(shark2); // Clear signals and coins clearEntities(); // Create initial signals that have already reached the left side var recentHeights = []; var heightThreshold = 150; // Further increased threshold to force more staggering for (var i = 0; i < 44; i++) { var signalType = Math.random() < 0.2 ? 'green' : 'red'; // Further decreased green signal probability from 30% to 20% // For signals that are lower than the previous, make them red // For signals that are higher than the previous, make them green var lastY = 1500; if (signals.length > 0) { lastY = signals[signals.length - 1].y; } var newY; var willBeHigher = Math.random() < 0.5; if (willBeHigher) { // More pronounced ascent with increased height differences var heightDiff = 80 + Math.random() * 120; // Reduced height difference for more regular cascading newY = lastY - heightDiff; signalType = 'green'; } else { // More pronounced descent with increased height differences var heightDiff = 150 + Math.random() * 180; newY = lastY + heightDiff; signalType = 'red'; } // Check if this height is too similar to recent heights var isTooSimilar = recentHeights.length > 0 && recentHeights.some(function (height) { return Math.abs(newY - height) < heightThreshold; }); // If too similar, adjust the height with larger offsets for more staggering if (isTooSimilar) { if (signalType === 'green') { newY -= 80 + Math.random() * 50; // Reduced offset for more regular staggering } else { newY += 120 + Math.random() * 80; // Increased offset for more staggering } } // Ensure signal stays within playable area and away from sharks // Keep signals at least 600px above sharks (which are at 2732 - 100) newY = Math.max(800, Math.min(2000, newY)); // Store this height for future comparison recentHeights.push(newY); if (recentHeights.length > 10) { recentHeights.shift(); // Keep only last 10 heights } var signal = new Signal(signalType); // Position signals already at the left side of the screen with horizontal variation var xOffset = Math.random() * 30 - 15; // Random horizontal offset between -15 and +15 signal.x = -150 + i * 50 + xOffset; // Distribute signals across the left edge with variations signal.y = newY - 100; // Move signals up by 100 units signals.push(signal); // Make sure signals are placed behind the player if (player) { var playerIndex = game.getChildIndex(player); game.addChildAt(signal, playerIndex); } else { game.addChild(signal); } } // Start game music in a loop (loop is true by default, but explicitly set for clarity) LK.playMusic('gameMusic', { loop: true }); } // Clear signals and coins - optimize by reusing objects when possible var recycledSignals = []; var recycledCoins = []; function clearEntities() { for (var i = signals.length - 1; i >= 0; i--) { // Store a limited number of signals for future reuse instead of destroying if (recycledSignals.length < 20) { signals[i].active = false; recycledSignals.push(signals[i]); } else { signals[i].destroy(); } signals.splice(i, 1); } for (var i = memecoins.length - 1; i >= 0; i--) { // Store a limited number of coins for future reuse if (recycledCoins.length < 10) { memecoins[i].active = false; recycledCoins.push(memecoins[i]); } else { memecoins[i].destroy(); } memecoins.splice(i, 1); } } // Spawn signals function spawnSignal() { var currentTime = Date.now(); // Spawn signals at intervals that maintain consistent spacing regardless of score // At higher scores (1000+), we need to keep a minimum time between signals var baseInterval = 300; var minInterval = 150; var adjustedInterval = score > 1000 ? Math.max(minInterval, baseInterval / gameSpeed) : baseInterval / gameSpeed; if (currentTime - lastSignalTime > adjustedInterval) { // This ensures spacing remains consistent even at high scores var signal; var lastSignalY = 1500; // Default Y position if no signals exist // Get the Y position of the last signal to compare with if (signals.length > 0) { var lastSignal = signals[signals.length - 1]; lastSignalY = lastSignal.y; } // Calculate a new Y position var newY; var willBeHigher = Math.random() < 0.1; // 10% chance to go higher, 90% chance for red signals // Count consecutive red signals var redSignalCount = 0; // Find the last signal of each type for height comparison var lastGreenY = null; var lastRedY = null; // Track recent signal heights to prevent repetition var recentHeights = []; var heightThreshold = 100; // Further increased threshold to force more staggering // Collect the last few signal heights for comparison for (var i = signals.length - 1; i >= Math.max(0, signals.length - 15); i--) { recentHeights.push(signals[i].y); } // Find the last green and red signal Y positions for (var i = signals.length - 1; i >= 0; i--) { if (signals[i].type === 'green' && lastGreenY === null) { lastGreenY = signals[i].y; } if (signals[i].type === 'red' && lastRedY === null) { lastRedY = signals[i].y; } if (lastGreenY !== null && lastRedY !== null) { break; } } for (var i = signals.length - 1; i >= Math.max(0, signals.length - 5); i--) { if (signals[i] && signals[i].type === 'red') { redSignalCount++; } else { break; } } // Count consecutive green signals at similar height var greenSignalCount = 0; var heightThresholdForSameLevel = 25; // Consider signals at same height if within 25 units for (var i = signals.length - 1; i >= Math.max(0, signals.length - 5); i--) { if (signals[i].type === 'green' && Math.abs(signals[i].y - lastSignalY) < heightThresholdForSameLevel) { greenSignalCount++; } else { break; } } // Force green signal if we've had 12 reds in a row (increased from 8) if (redSignalCount >= 12) { // Force green signal (must be higher) but with more gradual ascent newY = lastSignalY - (60 + Math.random() * 80); // Try to reuse an existing signal if available if (recycledSignals.length > 0) { signal = recycledSignals.pop(); signal.active = true; signal.changeType('green'); } else { signal = new Signal('green'); } } else if (willBeHigher && greenSignalCount < 5) { // This signal will be higher (ascending) // More pronounced height difference for green signals var heightDiff = 60 + Math.random() * 80; // Reduced for more regular staggering if (lastGreenY !== null && Math.abs(lastSignalY - heightDiff - lastGreenY) > 150) { // Reduced maximum height change between signals of same color heightDiff = Math.min(heightDiff, 150); } newY = lastSignalY - heightDiff; // Higher signals must be green signal = new Signal('green'); } else if (willBeHigher && greenSignalCount >= 5) { // If we already have 5 green signals at similar height, force a red signal instead var heightDiff = 80 + Math.random() * 120; newY = lastSignalY + heightDiff; // Move downward for red signal signal = new Signal('red'); } else { // This signal will be lower (descending) // More pronounced height difference for red signals var heightDiff = 80 + Math.random() * 120; // Increased for more staggering if (lastRedY !== null && Math.abs(lastSignalY + heightDiff - lastRedY) > 200) { // Increased maximum height change between signals of same color heightDiff = Math.min(heightDiff, 200); } newY = lastSignalY + heightDiff; // Check if we would have too many consecutive red signals var wouldBeConsecutiveReds = redSignalCount + 1; if (wouldBeConsecutiveReds >= 12) { // Increased from 8 to 12 // Force this to be a green signal instead with gradual ascent newY = lastSignalY - (60 + Math.random() * 80); signal = new Signal('green'); } else { // Lower signals must be red signal = new Signal('red'); } } // Ensure signal stays within playable area and away from sharks // Sharks are positioned at bottom (2732 - 100), keep signals at least 600px above sharks // Ensure signal stays within playable area and away from sharks // Sharks are positioned at bottom (2732 - 100), keep signals at least 600px above sharks // Limit green signals to maximum at 3/4 of screen height instead of middle if (signal.type === 'green') { newY = Math.min(2732 * 0.75, newY); // Allow green signals to appear up to 3/4 of screen height } newY = Math.max(800, Math.min(2200, newY)); // Lower maximum to keep away from sharks // Additional check for signals that might be about to overlap (within 25px) var potentialOverlap = signals.filter(function (s) { // Only check signals that are still on screen or about to enter return s.active && s.x > -200 && s.x < 2300 && Math.abs(s.y - newY) < 25; }); // If there's potential overlap, adjust the Y position with smaller offsets if (potentialOverlap.length > 0) { if (signal.type === 'green') { newY -= 40 + Math.random() * 20; // Reduced offset for more regular staggering } else { newY += 60 + Math.random() * 30; // Move red signals lower with smaller offset } // Re-check playable area boundaries newY = Math.max(800, Math.min(2200, newY)); } // Add height variation to signals and prevent consecutive similar heights var baseVerticalStep = 60; // Base step for cascading effect var randomVerticalVariation = Math.random() * 40 - 20; // Variation of +/- 20 from base step if (signal.type === 'green') { // Green signals with cascading heights - more controlled variations var greenOffset = 30 + Math.random() * 30; // Smaller, more regular offset for ascent newY -= greenOffset; // Green signals move upwards // If this green signal is lower than the last signal, change it to red and move down if (lastSignalY !== 1500 && newY > lastSignalY) { signal.changeType('red'); // Use changeType to update graphics newY = lastSignalY + (30 + Math.random() * 30); // Move down a bit more and ensure it's lower than the previous } } else if (signal.type === 'red') { // Red signals with cascading heights - more controlled variations var redOffset = 40 + Math.random() * 40; // Smaller, more regular offset for descent newY += redOffset; // Red signals move downwards // If this red signal is higher than the last signal, adjust its position to be lower or the same as the last red signal if (lastSignalY !== 1500 && newY < lastSignalY) { // If there was a previous red signal, try to match or go slightly lower if (lastRedY !== null) { newY = lastRedY + (20 + Math.random() * 20); // Position slightly lower than the last red signal } else { // If no previous red signal, just move it down a bit from the last signal newY = lastSignalY + 40 + Math.random() * 40; } // Re-check bounds after adjustment newY = Math.max(800, Math.min(2200, newY)); } } // Add horizontal variation for more staggered appearance var horizontalVariation = Math.random() * 60 - 30; // Range of -30 to +30 signal.x = 2048 + 150 + horizontalVariation; signal.y = newY; signals.push(signal); // Add signal behind the player to ensure correct display order if (player) { var playerIndex = game.getChildIndex(player); game.addChildAt(signal, playerIndex); } else { game.addChild(signal); } lastSignalTime = currentTime; } } // Spawn memecoins function spawnMemecoin() { var currentTime = Date.now(); // Spawn coins less frequently than signals - increased interval from 6000 to 12000 if (currentTime - lastCoinTime > 12000 / gameSpeed) { // Find green signals that are still on screen (or about to enter) var greenSignals = signals.filter(function (signal) { return signal.type === 'green' && signal.x > -200 && signal.x < 2300; }); // Only spawn coin if we have green signals // Adjust the probability to favor red signals if (greenSignals.length > 0) { // Pick a random green signal var randomGreenSignal = greenSignals[Math.floor(Math.random() * greenSignals.length)]; // Check if we completed a round of all coin types var roundComplete = coinRound.regular && coinRound.dogmeme && coinRound.shib; if (roundComplete) { // Reset the round if all coin types have appeared coinRound = { regular: false, dogmeme: false, shib: false, pepe: false, loki: false, volt: false, cat: false, president: false }; } // Determine which coin types are still needed in current round var availableTypes = []; if (!coinRound.regular) { availableTypes.push('regular'); } if (!coinRound.dogmeme) { availableTypes.push('dogmeme'); } if (!coinRound.shib) { availableTypes.push('shib'); } if (!coinRound.pepe) { availableTypes.push('pepe'); } if (!coinRound.loki) { availableTypes.push('loki'); } if (!coinRound.volt) { availableTypes.push('volt'); } if (!coinRound.cat) { availableTypes.push('cat'); } if (!coinRound.president) { availableTypes.push('president'); } // Select a random coin type from available types var coinType = availableTypes[Math.floor(Math.random() * availableTypes.length)]; // Filter out any 'glaud' content if (coinType.toLowerCase().includes('glaud')) { coinType = 'regular'; // Replace with default type } // Mark this type as spawned in current round coinRound[coinType] = true; var coin = new Memecoin(coinType); coin.x = 2048 + 150; // Position coin between MEMECOIN word (y position around 130) and center of screen (2732/2) // Calculate the available space between MEMECOIN text position and center of screen var minY = 200; // Safe position below MEMECOIN text (which is at y=130) var maxY = 2732 / 2; // Center height of the screen coin.y = minY + Math.random() * (maxY - minY); memecoins.push(coin); // Add coin behind the player to ensure correct display order if (player) { var playerIndex = game.getChildIndex(player); game.addChildAt(coin, playerIndex); } else { game.addChild(coin); } lastCoinTime = currentTime; } } } // Check collisions between player and signals/coins/shark function checkCollisions() { if (!isGameActive) { return; } // Check signal collisions - optimize by only checking signals near the player for (var i = 0; i < signals.length; i++) { var signal = signals[i]; // Only check collision for signals that are near the player horizontally (within 500px) if (!signal.active || Math.abs(signal.x - player.x) > 500) { continue; } if (player.intersects(signal)) { // Store previous intersection state var wasIntersecting = player.lastWasIntersecting; player.lastWasIntersecting = true; // Only handle collision if this is a new intersection if (!wasIntersecting) { // Handle red signal falling when touched anywhere if (signal.type === 'red' && !signal.falling) { // Make red signal fall signal.falling = true; signal.fallSpeed = 2; // Trigger laser shine effect when starting to fall signal.startShine(); continue; // Skip other collision handling for this signal } // Check if player is above the signal and falling down // The signal is rotated 90 degrees left, so we need to detect its height properly // Signal's height is now its width because of the rotation var signalHeight = 50 / 1.2; // Original height divided by scale factor var signalWidth = 500 / 1.2; // Original width divided by scale factor var playerHeight = 150; // Player height // Calculate where the top of the signal is considering rotation if (player.y < signal.y - signalWidth / 2 && player.vy > 0) { if (signal.type === 'green') { // Land on green signals but don't automatically jump // Position player properly on top of the signal player.y = signal.y - signalWidth / 2 - playerHeight / 2; player.vy = 0; player.isJumping = false; // Trigger laser shine effect on green signal when landing signal.startShine(); // Turn the green signal golden when touched signal.turnGolden(); } else if (signal.type === 'red') { // Pass through red signals, ignore collision // Don't land on red signals, continue falling player.vy += player.gravity; player.isJumping = true; // Trigger laser shine effect on red signal when passing through signal.startShine(); } } } } else if (signal.active) { // If not intersecting this signal, reset lastWasIntersecting player.lastWasIntersecting = false; } } // Check memecoin collisions for (var i = 0; i < memecoins.length; i++) { var coin = memecoins[i]; // Track previous intersection state to prevent multiple collections in one frame if (!coin.lastWasIntersecting) { coin.lastWasIntersecting = false; } // Find the highest green signal var highestGreenSignal = null; var highestY = Infinity; for (var j = 0; j < signals.length; j++) { if (signals[j].active && signals[j].type === 'green' && signals[j].y < highestY) { highestY = signals[j].y; highestGreenSignal = signals[j]; } } // Check if coin intersects with the highest green signal if (coin.active && !coin.collected && highestGreenSignal && coin.intersects(highestGreenSignal)) { // Turn the green signal red using the new method highestGreenSignal.changeType('red'); // Move signal down by 100-200 units var moveDownAmount = 100 + Math.random() * 100; // Use tween for smooth downward movement tween(highestGreenSignal, { y: highestGreenSignal.y + moveDownAmount }, { duration: 800, easing: tween.easeOutQuad }); // Flash the signal to indicate it's changed LK.effects.flashObject(highestGreenSignal, 0xff4500, 500); // Flash red // Collect the coin coin.collected = true; tween(coin, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 300, onFinish: function onFinish() { coin.active = false; } }); } // Only collect if active, not already collected, and this is a new intersection if (coin.active && !coin.collected && player.intersects(coin) && !coin.lastWasIntersecting) { // Collect coin coin.collected = true; coin.lastWasIntersecting = true; // Add points based on coin type score += coin.value; scoreTxt.setText('SCORE: ' + Math.floor(score)); // Illuminate next MEMECOIN letter if we haven't illuminated all if (memecoinLetters && memecoinLetters.length > 0 && nextLetterIndex < memecoinLetters.length) { var letterToIlluminate = memecoinLetters[nextLetterIndex]; if (!letterToIlluminate.collected) { letterToIlluminate.collected = true; // Change the color to gold without the shimmer effect letterToIlluminate.tint = 0xFFD700; // Gold color nextLetterIndex++; // Check if all letters are now collected if (nextLetterIndex === memecoinLetters.length) { // Apply the shimmer effect to all letters now that they're all collected for (var j = 0; j < memecoinLetters.length; j++) { LetterShimmerEffect(memecoinLetters[j]); } // All letters collected - show bonus score += 500; scoreTxt.setText('SCORE: ' + Math.floor(score)); // Create bonus text for completing MEMECOIN var bonusText = new BonusText(500, 'MEMECOIN'); bonusText.x = 2048 / 2; bonusText.y = 2732 / 3; game.addChild(bonusText); bonusText.animate(); // Show "you win" after a short delay when all MEMECOIN letters collected LK.setTimeout(function () { LK.showYouWin(); }, 1500); } } } // Flash coin with different colors based on type var flashColor; if (coin.type === 'dogmeme') { flashColor = 0xFFA500; // Orange } else if (coin.type === 'shib') { flashColor = 0x00FF00; // Green } else if (coin.type === 'pepe') { flashColor = 0x00FF80; // Mint Green } else if (coin.type === 'loki') { flashColor = 0x00FFFF; // Cyan } else if (coin.type === 'volt') { flashColor = 0xFFFF00; // Yellow } else if (coin.type === 'cat') { flashColor = 0xFF00FF; // Magenta } else if (coin.type === 'president') { flashColor = 0x0000FF; // Blue } else { flashColor = 0xFFFFFF; // White } LK.effects.flashObject(coin, flashColor, 300); LK.getSound('coinCollect').play(); // Show bonus text for memecoin pickup (+100 BONUS) if (coin.type === 'memecoin') { // Create bonus text in top third of screen var bonusText = new BonusText(100); bonusText.x = 2048 / 2; bonusText.y = 2732 / 3; game.addChild(bonusText); bonusText.animate(); // Add extra 100 points for memecoin score += 100; scoreTxt.setText('SCORE: ' + Math.floor(score)); } tween(coin, { alpha: 0, scaleX: coin.type === 'president' ? 8 : coin.type === 'cat' ? 7 : coin.type === 'volt' ? 6 : coin.type === 'loki' ? 5 : coin.type === 'pepe' ? 4 : coin.type === 'shib' ? 3 : 2, // Biggest effect for president, then cat, then volt, then loki, then pepe, then shib scaleY: coin.type === 'president' ? 8 : coin.type === 'cat' ? 7 : coin.type === 'volt' ? 6 : coin.type === 'loki' ? 5 : coin.type === 'pepe' ? 4 : coin.type === 'shib' ? 3 : 2 // Biggest effect for president, then cat, then volt, then loki, then pepe, then shib }, { duration: coin.type === 'president' ? 1000 : coin.type === 'cat' ? 900 : coin.type === 'volt' ? 800 : coin.type === 'loki' ? 700 : coin.type === 'pepe' ? 600 : coin.type === 'shib' ? 500 : 300, // Longest animation for president, then cat, then volt, then loki, then pepe, then shib onFinish: function onFinish() { coin.active = false; } }); } else if (!player.intersects(coin)) { // Reset intersection state when player is no longer intersecting the coin coin.lastWasIntersecting = false; } } // Check shark collisions if (player.y > 2732 - player.height && player.intersects(shark) || player.y > 2732 - player.height && player.intersects(shark2)) { // Game over if player touches either shark gameOver(); } } // Clean up inactive entities function cleanupEntities() { // Remove inactive signals for (var i = signals.length - 1; i >= 0; i--) { // Only remove signals if player is not jumping or falling if (!signals[i].active) { // Add extra conditions to ensure we don't remove signals that player might need to land on if (!player || !player.isJumping && player.vy <= 0) { signals[i].destroy(); signals.splice(i, 1); } } } // Remove inactive coins for (var i = memecoins.length - 1; i >= 0; i--) { if (!memecoins[i].active) { memecoins[i].destroy(); memecoins.splice(i, 1); } } // Remove inactive bonus texts - add explicit variable to avoid repeated property access for (var i = game.children.length - 1; i >= 0; i--) { var child = game.children[i]; if (child instanceof BonusText && !child.active) { if (child.cleanup) { child.cleanup(); // Call cleanup method if it exists } child.destroy(); } } } // Game over function gameOver() { isGameActive = false; player.isDead = true; // Play crash sound LK.getSound('crash').play(); // Flash screen red LK.effects.flashScreen(0xFF0000, 500); // Update high score var highScore = storage.highScore || 0; if (score > highScore) { storage.highScore = score; highScoreTxt.setText('HIGH SCORE: ' + Math.floor(score)); } // Show game over after a short delay LK.setTimeout(function () { LK.showGameOver(); }, 800); } // Input handling game.down = function (x, y, obj) { // Jump when tapping/clicking, passing click position player.jump(x, y); }; // Cache values that are frequently accessed for better performance var flooredScore = 0; // Main game update loop game.update = function () { if (!isGameActive) { return; } // Update score based on distance distanceTraveled += gameSpeed; score += scoreIncrement * gameSpeed; // Update score display occasionally to avoid text updates every frame // Cache the floored score to avoid recalculating it var newFlooredScore = Math.floor(score); if (newFlooredScore % 5 === 0 && newFlooredScore !== flooredScore) { flooredScore = newFlooredScore; scoreTxt.setText('SCORE: ' + flooredScore); } // Increase game speed gradually gameSpeed = 1 + distanceTraveled / 10000; // Check if sharks should start orbiting (every 10-20 seconds) var currentTime = Date.now(); // Tornado effect is turned off // Record the time to prevent other tornado-related code from running lastOrbitTime = currentTime; // Update orbit motion if active if (orbiting) { // Increase orbit angle orbitAngle += 0.02; // After 3 complete rotations (6*PI), start tornado and stop orbiting if (orbitAngle > Math.PI * 6) { orbiting = false; } } // Check tornado duration if (tornadoActive) { var tornado = game.children.find(function (child) { return child instanceof Tornado; }); if (tornado) { var currentTime = Date.now(); var elapsedTime = currentTime - tornado.startTime; // After 3 seconds, set to silent mode but keep tornado active if (elapsedTime >= tornado.duration && !tornado.isSilent) { tornado.isSilent = true; // Make particles semi-transparent in silent mode for (var i = 0; i < tornado.particles.length; i++) { tween(tornado.particles[i], { alpha: 0.3 }, { duration: 500, easing: tween.easeInOut }); } } } } // Update all tornado affected signals for (var i = 0; i < tornadoSignals.length; i++) { var signal = tornadoSignals[i]; if (signal.active && signal.falling) { // Add side-to-side motion to falling signals if (signal.sideSpeed !== undefined) { signal.x += signal.sideSpeed; // Gradually reduce side speed signal.sideSpeed *= 0.98; } } } // Spawn entities spawnSignal(); spawnMemecoin(); // Check collisions checkCollisions(); // Remove inactive entities cleanupEntities(); // Check if player fell off screen if (player.y > 2732 + 200) { gameOver(); } }; // Initialize UI and game initUI(); initGame(); // Track signal status globally game.onEntityDestroyed = function (entity) { // Keep track of destroyed entities if needed if (entity instanceof Signal && player) { // Keep signals around longer if player is falling or jumping if (player.isJumping || player.vy > 0) { // Return false to prevent deletion when player might need to land return false; } } return true; };
===================================================================
--- original.js
+++ change.js
@@ -27,32 +27,33 @@
self.animate = function () {
// Initial state
self.alpha = 0;
self.scale.set(0.5);
- // Animation sequence - fade in with scale up
- tween(self, {
+ // Animation sequence - fade in with scale up (with memory optimizations)
+ // Store tween reference so it can be cancelled if needed
+ self.currentTween = tween(self, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Pulse effect
- tween(bonusText, {
+ self.currentTween = tween(bonusText, {
tint: 0xFFFFFF // Flash to white
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
- tween(bonusText, {
+ self.currentTween = tween(bonusText, {
tint: 0xFFD700 // Back to gold
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Fade out with float up
- tween(self, {
+ self.currentTween = tween(self, {
alpha: 0,
y: self.y - 100
}, {
duration: 800,
@@ -68,8 +69,17 @@
}
});
};
self.active = true;
+ // Add cleanup method to properly release memory when destroyed
+ self.cleanup = function () {
+ // Cancel any active tweens
+ tween.cancel(self);
+ tween.cancel(bonusText);
+ // Clear references
+ bonusText = null;
+ self.removeChildren();
+ };
return self;
});
var Memecoin = Container.expand(function (type) {
var self = Container.call(this);
@@ -618,11 +628,11 @@
return self;
});
var Tornado = Container.expand(function () {
var self = Container.call(this);
- // Create tornado graphics
+ // Create tornado graphics - optimize by reducing particle count
self.particles = [];
- var numParticles = 30;
+ var numParticles = 20; // Reduced from 30 to 20 for better performance
var colors = [0x87CEEB, 0x00BFFF, 0x1E90FF, 0x4682B4];
// Create particles that make up the tornado
for (var i = 0; i < numParticles; i++) {
var particle = new Container();
@@ -718,46 +728,8 @@
* Game Code
****/
// Game variables
// Golden letter shimmer animation
-var LRUCache = function LRUCache(options) {
- var self = this;
- self.max = options.max || 10; // Default max size
- self.cache = {};
- self.order = [];
- self.get = function (key) {
- if (self.cache[key]) {
- // Move to the end (most recently used)
- var index = self.order.indexOf(key);
- if (index > -1) {
- self.order.splice(index, 1);
- self.order.push(key);
- }
- return self.cache[key];
- }
- return undefined;
- };
- self.set = function (key, value) {
- if (self.cache[key]) {
- // Update value and move to the end
- self.cache[key] = value;
- var index = self.order.indexOf(key);
- if (index > -1) {
- self.order.splice(index, 1);
- }
- self.order.push(key);
- } else {
- // Add new item
- if (self.order.length >= self.max) {
- // Remove least recently used item
- var oldestKey = self.order.shift();
- delete self.cache[oldestKey];
- }
- self.cache[key] = value;
- self.order.push(key);
- }
- };
-};
var LetterShimmerEffect = function LetterShimmerEffect(letterText) {
// Create shimmer animation cycle
function startShimmer() {
// Shimmer to bright white
@@ -787,17 +759,8 @@
};
var player;
var signals = [];
var memecoins = [];
-// Create an LRUCache for Signal objects with a max size
-var signalCache = new LRUCache({
- max: 100 // Cache up to 100 Signal objects
-});
-// Create an LRUCache for Memecoin objects with a max size
-var memecoinCache = new LRUCache({
- max: 50 // Cache up to 50 Memecoin objects
-});
-// Create an LRUCache for Signal objects with a max size
var shark;
var shark2;
var isGameActive = true;
var gameSpeed = 1;
@@ -944,9 +907,9 @@
// Clear signals and coins
clearEntities();
// Create initial signals that have already reached the left side
var recentHeights = [];
- var heightThreshold = 80; // Reduced threshold for staggering to create tighter packing
+ var heightThreshold = 150; // Further increased threshold to force more staggering
for (var i = 0; i < 44; i++) {
var signalType = Math.random() < 0.2 ? 'green' : 'red'; // Further decreased green signal probability from 30% to 20%
// For signals that are lower than the previous, make them red
// For signals that are higher than the previous, make them green
@@ -957,27 +920,27 @@
var newY;
var willBeHigher = Math.random() < 0.5;
if (willBeHigher) {
// More pronounced ascent with increased height differences
- var heightDiff = 40 + Math.random() * 60; // Reduced height difference for tighter packing
+ var heightDiff = 80 + Math.random() * 120; // Reduced height difference for more regular cascading
newY = lastY - heightDiff;
signalType = 'green';
} else {
// More pronounced descent with increased height differences
- var heightDiff = 60 + Math.random() * 80; // Reduced height difference for tighter packing
+ var heightDiff = 150 + Math.random() * 180;
newY = lastY + heightDiff;
signalType = 'red';
}
// Check if this height is too similar to recent heights
var isTooSimilar = recentHeights.length > 0 && recentHeights.some(function (height) {
return Math.abs(newY - height) < heightThreshold;
});
- // If too similar, adjust the height with smaller offsets for tighter packing
+ // If too similar, adjust the height with larger offsets for more staggering
if (isTooSimilar) {
if (signalType === 'green') {
- newY -= 30 + Math.random() * 20; // Reduced offset for tighter packing
+ newY -= 80 + Math.random() * 50; // Reduced offset for more regular staggering
} else {
- newY += 40 + Math.random() * 30; // Reduced offset for tighter packing
+ newY += 120 + Math.random() * 80; // Increased offset for more staggering
}
}
// Ensure signal stays within playable area and away from sharks
// Keep signals at least 600px above sharks (which are at 2732 - 100)
@@ -986,23 +949,9 @@
recentHeights.push(newY);
if (recentHeights.length > 10) {
recentHeights.shift(); // Keep only last 10 heights
}
- var signal = signalCache.get(signalType) || new Signal(signalType); // Reuse or create new Signal
- // Reset properties for reuse
- signal.active = true;
- signal.falling = false;
- signal.fallSpeed = 0;
- signal.shimmerAnimationActive = false;
- signal.flashedRed = false;
- signal.isGolden = false;
- signal.isShining = false;
- signal.shineTimer = 0;
- if (signal.children.length > 0) {
- signal.children[0].tint = 0xFFFFFF; // Reset tint
- signal.children[0].alpha = 1; // Reset alpha
- signal.children[0].rotation = -Math.PI / 2; // Reset rotation
- }
+ var signal = new Signal(signalType);
// Position signals already at the left side of the screen with horizontal variation
var xOffset = Math.random() * 30 - 15; // Random horizontal offset between -15 and +15
signal.x = -150 + i * 50 + xOffset; // Distribute signals across the left edge with variations
signal.y = newY - 100; // Move signals up by 100 units
@@ -1019,16 +968,30 @@
LK.playMusic('gameMusic', {
loop: true
});
}
-// Clear all entities
+// Clear signals and coins - optimize by reusing objects when possible
+var recycledSignals = [];
+var recycledCoins = [];
function clearEntities() {
for (var i = signals.length - 1; i >= 0; i--) {
- signals[i].destroy();
+ // Store a limited number of signals for future reuse instead of destroying
+ if (recycledSignals.length < 20) {
+ signals[i].active = false;
+ recycledSignals.push(signals[i]);
+ } else {
+ signals[i].destroy();
+ }
signals.splice(i, 1);
}
for (var i = memecoins.length - 1; i >= 0; i--) {
- memecoins[i].destroy();
+ // Store a limited number of coins for future reuse
+ if (recycledCoins.length < 10) {
+ memecoins[i].active = false;
+ recycledCoins.push(memecoins[i]);
+ } else {
+ memecoins[i].destroy();
+ }
memecoins.splice(i, 1);
}
}
// Spawn signals
@@ -1094,115 +1057,52 @@
}
// Force green signal if we've had 12 reds in a row (increased from 8)
if (redSignalCount >= 12) {
// Force green signal (must be higher) but with more gradual ascent
- newY = lastSignalY - (40 + Math.random() * 60); // Reduced ascent for tighter green signal spacing
- signal = signalCache.get('green') || new Signal('green'); // Reuse or create new Signal
- // Reset properties for reuse
- signal.active = true;
- signal.falling = false;
- signal.fallSpeed = 0;
- signal.shimmerAnimationActive = false;
- signal.flashedRed = false;
- signal.isGolden = false;
- signal.isShining = false;
- signal.shineTimer = 0;
- if (signal.children.length > 0) {
- signal.children[0].tint = 0xFFFFFF; // Reset tint
- signal.children[0].alpha = 1; // Reset alpha
- signal.children[0].rotation = -Math.PI / 2; // Reset rotation
+ newY = lastSignalY - (60 + Math.random() * 80);
+ // Try to reuse an existing signal if available
+ if (recycledSignals.length > 0) {
+ signal = recycledSignals.pop();
+ signal.active = true;
+ signal.changeType('green');
+ } else {
+ signal = new Signal('green');
}
} else if (willBeHigher && greenSignalCount < 5) {
// This signal will be higher (ascending)
// More pronounced height difference for green signals
- var heightDiff = 40 + Math.random() * 60; // Reduced for tighter green signal spacing
- if (lastGreenY !== null && Math.abs(lastSignalY - heightDiff - lastGreenY) > 100) {
- // Reduced maximum height change between signals of same color for tighter spacing
- heightDiff = Math.min(heightDiff, 100);
+ var heightDiff = 60 + Math.random() * 80; // Reduced for more regular staggering
+ if (lastGreenY !== null && Math.abs(lastSignalY - heightDiff - lastGreenY) > 150) {
+ // Reduced maximum height change between signals of same color
+ heightDiff = Math.min(heightDiff, 150);
}
newY = lastSignalY - heightDiff;
// Higher signals must be green
- signal = signalCache.get('green') || new Signal('green'); // Reuse or create new Signal
- // Reset properties for reuse
- signal.active = true;
- signal.falling = false;
- signal.fallSpeed = 0;
- signal.shimmerAnimationActive = false;
- signal.flashedRed = false;
- signal.isGolden = false;
- signal.isShining = false;
- signal.shineTimer = 0;
- if (signal.children.length > 0) {
- signal.children[0].tint = 0xFFFFFF; // Reset tint
- signal.children[0].alpha = 1; // Reset alpha
- signal.children[0].rotation = -Math.PI / 2; // Reset rotation
- }
+ signal = new Signal('green');
} else if (willBeHigher && greenSignalCount >= 5) {
// If we already have 5 green signals at similar height, force a red signal instead
- var heightDiff = 60 + Math.random() * 80; // Reduced for tighter red signal spacing
+ var heightDiff = 80 + Math.random() * 120;
newY = lastSignalY + heightDiff; // Move downward for red signal
- signal = signalCache.get('red') || new Signal('red'); // Reuse or create new Signal
- // Reset properties for reuse
- signal.active = true;
- signal.falling = false;
- signal.fallSpeed = 0;
- signal.shimmerAnimationActive = false;
- signal.flashedRed = false;
- signal.isGolden = false;
- signal.isShining = false;
- signal.shineTimer = 0;
- if (signal.children.length > 0) {
- signal.children[0].tint = 0xFFFFFF; // Reset tint
- signal.children[0].alpha = 1; // Reset alpha
- signal.children[0].rotation = -Math.PI / 2; // Reset rotation
- }
+ signal = new Signal('red');
} else {
// This signal will be lower (descending)
// More pronounced height difference for red signals
- var heightDiff = 60 + Math.random() * 80; // Reduced for tighter red signal spacing
- if (lastRedY !== null && Math.abs(lastSignalY + heightDiff - lastRedY) > 150) {
- // Reduced maximum height change between signals of same color for tighter spacing
- heightDiff = Math.min(heightDiff, 150);
+ var heightDiff = 80 + Math.random() * 120; // Increased for more staggering
+ if (lastRedY !== null && Math.abs(lastSignalY + heightDiff - lastRedY) > 200) {
+ // Increased maximum height change between signals of same color
+ heightDiff = Math.min(heightDiff, 200);
}
newY = lastSignalY + heightDiff;
// Check if we would have too many consecutive red signals
var wouldBeConsecutiveReds = redSignalCount + 1;
if (wouldBeConsecutiveReds >= 12) {
// Increased from 8 to 12
// Force this to be a green signal instead with gradual ascent
- newY = lastSignalY - (40 + Math.random() * 60); // Reduced ascent for tighter green signal spacing
- signal = signalCache.get('green') || new Signal('green'); // Reuse or create new Signal
- // Reset properties for reuse
- signal.active = true;
- signal.falling = false;
- signal.fallSpeed = 0;
- signal.shimmerAnimationActive = false;
- signal.flashedRed = false;
- signal.isGolden = false;
- signal.isShining = false;
- signal.shineTimer = 0;
- if (signal.children.length > 0) {
- signal.children[0].tint = 0xFFFFFF; // Reset tint
- signal.children[0].alpha = 1; // Reset alpha
- signal.children[0].rotation = -Math.PI / 2; // Reset rotation
- }
+ newY = lastSignalY - (60 + Math.random() * 80);
+ signal = new Signal('green');
} else {
// Lower signals must be red
- signal = signalCache.get('red') || new Signal('red'); // Reuse or create new Signal
- // Reset properties for reuse
- signal.active = true;
- signal.falling = false;
- signal.fallSpeed = 0;
- signal.shimmerAnimationActive = false;
- signal.flashedRed = false;
- signal.isGolden = false;
- signal.isShining = false;
- signal.shineTimer = 0;
- if (signal.children.length > 0) {
- signal.children[0].tint = 0xFFFFFF; // Reset tint
- signal.children[0].alpha = 1; // Reset alpha
- signal.children[0].rotation = -Math.PI / 2; // Reset rotation
- }
+ signal = new Signal('red');
}
}
// Ensure signal stays within playable area and away from sharks
// Sharks are positioned at bottom (2732 - 100), keep signals at least 600px above sharks
@@ -1220,46 +1120,46 @@
});
// If there's potential overlap, adjust the Y position with smaller offsets
if (potentialOverlap.length > 0) {
if (signal.type === 'green') {
- newY -= 20 + Math.random() * 10; // Reduced offset for tighter spacing
+ newY -= 40 + Math.random() * 20; // Reduced offset for more regular staggering
} else {
- newY += 30 + Math.random() * 20; // Reduced offset for tighter spacing
+ newY += 60 + Math.random() * 30; // Move red signals lower with smaller offset
}
// Re-check playable area boundaries
newY = Math.max(800, Math.min(2200, newY));
}
// Add height variation to signals and prevent consecutive similar heights
- var baseVerticalStep = 40; // Reduced base step for tighter cascading effect
- var randomVerticalVariation = Math.random() * 30 - 15; // Reduced variation
+ var baseVerticalStep = 60; // Base step for cascading effect
+ var randomVerticalVariation = Math.random() * 40 - 20; // Variation of +/- 20 from base step
if (signal.type === 'green') {
// Green signals with cascading heights - more controlled variations
- var greenOffset = 20 + Math.random() * 20; // Smaller, more regular offset for ascent
+ var greenOffset = 30 + Math.random() * 30; // Smaller, more regular offset for ascent
newY -= greenOffset; // Green signals move upwards
// If this green signal is lower than the last signal, change it to red and move down
if (lastSignalY !== 1500 && newY > lastSignalY) {
signal.changeType('red'); // Use changeType to update graphics
- newY = lastSignalY + (20 + Math.random() * 20); // Move down a bit more and ensure it's lower than the previous
+ newY = lastSignalY + (30 + Math.random() * 30); // Move down a bit more and ensure it's lower than the previous
}
} else if (signal.type === 'red') {
// Red signals with cascading heights - more controlled variations
- var redOffset = 30 + Math.random() * 30; // Smaller, more regular offset for descent
+ var redOffset = 40 + Math.random() * 40; // Smaller, more regular offset for descent
newY += redOffset; // Red signals move downwards
// If this red signal is higher than the last signal, adjust its position to be lower or the same as the last red signal
if (lastSignalY !== 1500 && newY < lastSignalY) {
// If there was a previous red signal, try to match or go slightly lower
if (lastRedY !== null) {
- newY = lastRedY + (10 + Math.random() * 10); // Position slightly lower than the last red signal
+ newY = lastRedY + (20 + Math.random() * 20); // Position slightly lower than the last red signal
} else {
// If no previous red signal, just move it down a bit from the last signal
- newY = lastSignalY + 30 + Math.random() * 30;
+ newY = lastSignalY + 40 + Math.random() * 40;
}
// Re-check bounds after adjustment
newY = Math.max(800, Math.min(2200, newY));
}
}
// Add horizontal variation for more staggered appearance
- var horizontalVariation = Math.random() * 40 - 20; // Reduced range
+ var horizontalVariation = Math.random() * 60 - 30; // Range of -30 to +30
signal.x = 2048 + 150 + horizontalVariation;
signal.y = newY;
signals.push(signal);
// Add signal behind the player to ensure correct display order
@@ -1334,16 +1234,9 @@
coinType = 'regular'; // Replace with default type
}
// Mark this type as spawned in current round
coinRound[coinType] = true;
- var coin = memecoinCache.get(coinType) || new Memecoin(coinType); // Reuse or create new Memecoin
- // Reset properties for reuse
- coin.active = true;
- coin.collected = false;
- if (coin.children.length > 0) {
- coin.children[0].alpha = 1; // Reset alpha
- coin.children[0].scale.set(1); // Reset scale
- }
+ var coin = new Memecoin(coinType);
coin.x = 2048 + 150;
// Position coin between MEMECOIN word (y position around 130) and center of screen (2732/2)
// Calculate the available space between MEMECOIN text position and center of screen
var minY = 200; // Safe position below MEMECOIN text (which is at y=130)
@@ -1365,12 +1258,16 @@
function checkCollisions() {
if (!isGameActive) {
return;
}
- // Check signal collisions
+ // Check signal collisions - optimize by only checking signals near the player
for (var i = 0; i < signals.length; i++) {
var signal = signals[i];
- if (signal.active && player.intersects(signal)) {
+ // Only check collision for signals that are near the player horizontally (within 500px)
+ if (!signal.active || Math.abs(signal.x - player.x) > 500) {
+ continue;
+ }
+ if (player.intersects(signal)) {
// Store previous intersection state
var wasIntersecting = player.lastWasIntersecting;
player.lastWasIntersecting = true;
// Only handle collision if this is a new intersection
@@ -1562,30 +1459,28 @@
// Only remove signals if player is not jumping or falling
if (!signals[i].active) {
// Add extra conditions to ensure we don't remove signals that player might need to land on
if (!player || !player.isJumping && player.vy <= 0) {
- // Add signal to cache for reuse
- signalCache.set(signals[i].type, signals[i]);
- // Remove from game world
- game.removeChild(signals[i]);
+ signals[i].destroy();
signals.splice(i, 1);
}
}
}
// Remove inactive coins
for (var i = memecoins.length - 1; i >= 0; i--) {
if (!memecoins[i].active) {
- // Add coin to cache for reuse
- memecoinCache.set(memecoins[i].type, memecoins[i]);
- // Remove from game world
- game.removeChild(memecoins[i]);
+ memecoins[i].destroy();
memecoins.splice(i, 1);
}
}
- // Remove inactive bonus texts
+ // Remove inactive bonus texts - add explicit variable to avoid repeated property access
for (var i = game.children.length - 1; i >= 0; i--) {
- if (game.children[i] instanceof BonusText && !game.children[i].active) {
- game.children[i].destroy();
+ var child = game.children[i];
+ if (child instanceof BonusText && !child.active) {
+ if (child.cleanup) {
+ child.cleanup(); // Call cleanup method if it exists
+ }
+ child.destroy();
}
}
}
// Game over
@@ -1611,8 +1506,10 @@
game.down = function (x, y, obj) {
// Jump when tapping/clicking, passing click position
player.jump(x, y);
};
+// Cache values that are frequently accessed for better performance
+var flooredScore = 0;
// Main game update loop
game.update = function () {
if (!isGameActive) {
return;
@@ -1620,10 +1517,13 @@
// Update score based on distance
distanceTraveled += gameSpeed;
score += scoreIncrement * gameSpeed;
// Update score display occasionally to avoid text updates every frame
- if (Math.floor(score) % 5 === 0) {
- scoreTxt.setText('SCORE: ' + Math.floor(score));
+ // Cache the floored score to avoid recalculating it
+ var newFlooredScore = Math.floor(score);
+ if (newFlooredScore % 5 === 0 && newFlooredScore !== flooredScore) {
+ flooredScore = newFlooredScore;
+ scoreTxt.setText('SCORE: ' + flooredScore);
}
// Increase game speed gradually
gameSpeed = 1 + distanceTraveled / 10000;
// Check if sharks should start orbiting (every 10-20 seconds)
@@ -1699,10 +1599,6 @@
// Return false to prevent deletion when player might need to land
return false;
}
}
- // If it's a Signal or Memecoin, don't destroy it as it's managed by the cache
- if (entity instanceof Signal || entity instanceof Memecoin) {
- return false;
- }
return true;
};
\ No newline at end of file
Grey shark, sideview. In-Game asset. 2d. High contrast. No shadows
Golden Dogecoin
Golden memecoin with sunglasses
shiba inu golden memecoin
Golden memecoin with Pepe
Golden coin with Floki
Golden coin with volt
Golden coin with cute catface
Golden coin with Trump and 'WILL FIX IT' Text
Lightning line. In-Game asset. 2d. High contrast. No shadows