/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { currentLevel: 1, unlockedLevels: 1, totalScore: 0, levelScore: 0, mouseTrackingEnabled: true, fireToggleEnabled: true, checkpointEnabled: true, longPressEnabled: true }); /**** * Classes ****/ var BackgroundShape = Container.expand(function () { var self = Container.call(this); var shapeTypes = ['bgCircle', 'bgSquare', 'bgTriangle', 'bgPentagon', 'bgHexagon', 'bgHeptagon', 'bgOctagon']; var randomType = shapeTypes[Math.floor(Math.random() * shapeTypes.length)]; var shapeGraphics = self.attachAsset(randomType, { anchorX: 0.5, anchorY: 0.5 }); self.speed = -1 - Math.random() * 2; // Random speed between -1 and -3 self.rotationSpeed = (Math.random() - 0.5) * 0.02; // Random rotation self.pulseScale = 1; self.pulseDirection = 1; self.alpha = 0.3 + Math.random() * 0.4; // Random transparency between 0.3-0.7 shapeGraphics.alpha = self.alpha; self.update = function () { self.x += self.speed; // Add rotation shapeGraphics.rotation += self.rotationSpeed; // Add subtle pulsing self.pulseScale += 0.003 * self.pulseDirection; if (self.pulseScale > 1.1) self.pulseDirection = -1; if (self.pulseScale < 0.9) self.pulseDirection = 1; shapeGraphics.scaleX = self.pulseScale; shapeGraphics.scaleY = self.pulseScale; }; return self; }); var Bird = Container.expand(function () { var self = Container.call(this); var birdGraphics = self.attachAsset('bird', { anchorX: 0.5, anchorY: 0.5 }); // Ensure bird is visible birdGraphics.alpha = 1.0; birdGraphics.visible = true; self.velocityY = 0; self.gravity = 0.8; self.flapPower = -12; self.rotation = 0; self.rotationVelocity = 0; self.isFlipping = false; self.completedFlips = 0; self.lastUpright = true; self.flap = function () { self.velocityY = self.flapPower; LK.getSound('flap').play(); // No score bonus for flapping - score only from obstacles }; self.update = function () { // Check for long press - apply continuous upward force only if enabled if (longPressEnabled && isPressing && gameStarted) { var pressDuration = Date.now() - pressStartTime; if (pressDuration >= longPressThreshold) { // Apply strong upward force for long press self.velocityY = -15; // Strong upward velocity } } // Make bird follow mouse cursor when mouse position is available and tracking is enabled if (mouseTrackingEnabled && game.mouseX !== undefined && game.mouseY !== undefined) { // Calculate direction towards cursor var directionX = game.mouseX - self.x; var directionY = game.mouseY - self.y; var distance = Math.sqrt(directionX * directionX + directionY * directionY); // Move bird towards cursor with smooth following if (distance > 5) { // Only move if not too close to avoid jittering var followSpeed = 4; // Speed of following var normalX = directionX / distance; var normalY = directionY / distance; self.x += normalX * followSpeed; self.y += normalY * followSpeed; self.velocityY = 0; // Reset gravity when following cursor } else { // When very close to cursor, stop moving to avoid jittering self.velocityY = 0; } } else { // Normal bird physics when mouse tracking disabled or no mouse position available self.velocityY += self.gravity; self.y += self.velocityY; } // Keep bird in bounds horizontally if (self.x < 40) self.x = 40; if (self.x > 2008) self.x = 2008; // Keep bird in bounds vertically if (self.y < 40) self.y = 40; if (self.y > 2600) self.y = 2600; }; self.isUpright = function () { var normalizedRotation = self.rotation % (Math.PI * 2); return normalizedRotation < 0.3 || normalizedRotation > Math.PI * 2 - 0.3; }; return self; }); var Block = Container.expand(function () { var self = Container.call(this); var blockGraphics = self.attachAsset('checkpointblou1', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); self.speed = -3; self.collected = false; self.pulseScale = 1; self.pulseDirection = 1; self.rotationSpeed = 0.02; // Add pulsing animation only (no rotation) self.update = function () { self.x += self.speed; // Pulsing effect self.pulseScale += 0.008 * self.pulseDirection; if (self.pulseScale > 1.15) self.pulseDirection = -1; if (self.pulseScale < 0.85) self.pulseDirection = 1; blockGraphics.scaleX = self.pulseScale * 1.5; blockGraphics.scaleY = self.pulseScale * 1.5; // Rotation effect removed }; return self; }); var Bomb = Container.expand(function () { var self = Container.call(this); var bombGraphics = self.attachAsset('bomb', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -2; self.passed = false; self.collected = false; self.isBomb = true; self.pulseScale = 1; self.pulseDirection = 1; self.rotationSpeed = 0.05; self.update = function () { self.x += self.speed; // Pulsing effect for bombs self.pulseScale += 0.015 * self.pulseDirection; if (self.pulseScale > 1.3) self.pulseDirection = -1; if (self.pulseScale < 0.8) self.pulseDirection = 1; bombGraphics.scaleX = self.pulseScale; bombGraphics.scaleY = self.pulseScale; }; return self; }); var Character = Container.expand(function () { var self = Container.call(this); var characterGraphics = self.attachAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -1.5; self.passed = false; self.collected = false; self.isCharacter = true; self.isDead = false; self.pulseScale = 1; self.pulseDirection = 1; // Character visual effects characterGraphics.tint = 0x00FF00; // Green color to distinguish from other elements self.update = function () { if (!self.isDead) { self.x += self.speed; // Pulsing effect for character self.pulseScale += 0.008 * self.pulseDirection; if (self.pulseScale > 1.1) self.pulseDirection = -1; if (self.pulseScale < 0.9) self.pulseDirection = 1; characterGraphics.scaleX = self.pulseScale; characterGraphics.scaleY = self.pulseScale; } }; return self; }); var Fire = Container.expand(function () { var self = Container.call(this); var fireGraphics = self.attachAsset('fire', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -2.5; self.passed = false; self.collected = false; self.isFire = true; self.pulseScale = 1; self.pulseDirection = 1; self.rotationSpeed = 0.03; self.flickerIntensity = 0; // Fire visual effects - orange/red color with flickering fireGraphics.tint = 0xff4400; self.update = function () { self.x += self.speed; // Intense pulsing effect for fire self.pulseScale += 0.02 * self.pulseDirection; if (self.pulseScale > 1.4) self.pulseDirection = -1; if (self.pulseScale < 0.7) self.pulseDirection = 1; fireGraphics.scaleX = self.pulseScale; fireGraphics.scaleY = self.pulseScale; // Fire rotation removed - fire no longer rotates // Flickering effect by changing tint between orange and red self.flickerIntensity += 0.1; var flicker = Math.sin(self.flickerIntensity); if (flicker > 0) { fireGraphics.tint = 0xff6600; // Brighter orange } else { fireGraphics.tint = 0xff2200; // Darker red } }; return self; }); var Heart = Container.expand(function () { var self = Container.call(this); var heartGraphics = self.attachAsset('heart', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2 }); self.speed = -3; self.collected = false; self.pulseScale = 1; self.pulseDirection = 1; self.floatOffset = 0; // Add pulsing and floating animation self.update = function () { self.x += self.speed; // Pulsing effect self.pulseScale += 0.01 * self.pulseDirection; if (self.pulseScale > 1.2) self.pulseDirection = -1; if (self.pulseScale < 0.8) self.pulseDirection = 1; heartGraphics.scaleX = self.pulseScale; heartGraphics.scaleY = self.pulseScale; // Floating effect self.floatOffset += 0.05; heartGraphics.y = Math.sin(self.floatOffset) * 10; }; return self; }); var Ice = Container.expand(function () { var self = Container.call(this); var iceGraphics = self.attachAsset('ice', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = 8; // Horizontal velocity self.velocityY = 0; self.isIce = true; self.collected = false; // Ice visual effects - light blue color iceGraphics.tint = 0x87ceeb; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; // Add slight rotation for visual effect iceGraphics.rotation += 0.1; }; return self; }); var Laser = Container.expand(function () { var self = Container.call(this); var laserGraphics = self.attachAsset('laser', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -24; self.passed = false; self.collected = false; self.isLaser = true; self.pulseScale = 1; self.pulseDirection = 1; self.horizontalSpeed = 6; self.horizontalDirection = 1; self.maxHorizontalRange = 300; self.startX = 0; // Laser visual effects - bright red pulsing laserGraphics.tint = 0xff0000; self.update = function () { self.x -= self.speed; // Changed to move in opposite direction (positive X, away from bird) // Horizontal oscillation movement self.x += self.horizontalSpeed * self.horizontalDirection; // Reverse direction if reached maximum range if (Math.abs(self.x - self.startX) > self.maxHorizontalRange) { self.horizontalDirection *= -1; } // Intense pulsing effect for laser self.pulseScale += 0.02 * self.pulseDirection; if (self.pulseScale > 1.4) self.pulseDirection = -1; if (self.pulseScale < 0.7) self.pulseDirection = 1; laserGraphics.scaleX = self.pulseScale; laserGraphics.scaleY = self.pulseScale; // Add rotation for visual effect laserGraphics.rotation += 0.03; }; return self; }); var Obstacle = Container.expand(function () { var self = Container.call(this); // Choose obstacle type from level-specific sequence var randomType = 'block'; // Default fallback if (levelObstacleTypes.length > 0) { var typeIndex = obstacleCounter % levelObstacleTypes.length; randomType = levelObstacleTypes[typeIndex]; } var obstacleGraphics = self.attachAsset(randomType, { anchorX: 0.5, anchorY: 0.5 }); self.speed = -3; self.passed = false; self.obstacleType = randomType; // Add visual effects for Geometry Dash style self.pulseScale = 1; self.pulseDirection = 1; self.rotationSpeed = 0; self.isStationary = false; // Set rotation speed for certain types if (randomType === 'spike' || randomType === 'block') { self.rotationSpeed = 0.02; } // Set rest platform specific properties if (randomType === 'restPlatform') { self.speed = 0; // Rest platforms don't move horizontally self.isStationary = true; self.isSafe = true; // Mark as safe platform } // Set door specific properties if (randomType === 'door') { self.speed = -1; // Doors move slower self.isDoor = true; // Mark as door for special collision handling self.pulseScale = 1.1; // Start with larger pulse for visibility } self.update = function () { // Only move if not stationary if (!self.isStationary) { self.x += self.speed; } // Add pulsing effect only for non-rest platform obstacles if (self.obstacleType !== 'restPlatform') { self.pulseScale += 0.005 * self.pulseDirection; if (self.pulseScale > 1.05) self.pulseDirection = -1; if (self.pulseScale < 0.98) self.pulseDirection = 1; obstacleGraphics.scaleX = self.pulseScale; obstacleGraphics.scaleY = self.pulseScale; } // Add rotation for certain obstacles if (self.rotationSpeed > 0) { obstacleGraphics.rotation += self.rotationSpeed; } }; return self; }); var Portal = Container.expand(function () { var self = Container.call(this); var portalGraphics = self.attachAsset('door', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); self.speed = -2; self.passed = false; self.isPortal = true; self.pulseScale = 1; self.pulseDirection = 1; self.rotationSpeed = 0.01; // Portal specific visual effects portalGraphics.tint = 0x9966ff; // Purple tint for portal self.update = function () { self.x += self.speed; // Enhanced pulsing effect for portal self.pulseScale += 0.008 * self.pulseDirection; if (self.pulseScale > 1.3) self.pulseDirection = -1; if (self.pulseScale < 0.8) self.pulseDirection = 1; portalGraphics.scaleX = self.pulseScale * 1.5; portalGraphics.scaleY = self.pulseScale * 1.5; // Portal rotation removed - portal no longer spins }; return self; }); var Spike = Container.expand(function () { var self = Container.call(this); var spikeGraphics = self.attachAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -2; self.passed = false; self.collected = false; self.isSpike = true; self.pulseScale = 1; self.pulseDirection = 1; self.rotationSpeed = 0; // Spike visual effects - look like hearts (no tint) self.update = function () { self.x += self.speed; // Pulsing effect for spikes self.pulseScale += 0.01 * self.pulseDirection; if (self.pulseScale > 1.15) self.pulseDirection = -1; if (self.pulseScale < 0.9) self.pulseDirection = 1; spikeGraphics.scaleX = self.pulseScale; spikeGraphics.scaleY = self.pulseScale; // No rotation for spikes }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ var bird; var obstacles = []; var hearts = []; var blocks = []; var backgroundShapes = []; var portals = []; var spikes = []; var bombs = []; var lasers = []; var characters = []; var fires = []; var ices = []; var ground; var gameStarted = false; var lastObstacle = 0; var obstacleSpacing = 400; var currentLevel = 1; var unlockedLevels = 999; // All levels unlocked for everyone var totalScore = 0; var levelScoreThreshold = 10; // Base score needed to unlock next level // Load persistent scores from storage totalScore = storage.totalScore || 0; var levelScore = storage.levelScore || 0; LK.setScore(levelScore); var obstacleCounter = 0; // Counter for obstacle generation var levelObstacleTypes = []; // Array to store shuffled obstacle types for current level var playerHealth = 3; // Player starts with 3 lives var lastBackgroundShape = 0; var backgroundShapeSpacing = 400; // Spacing between background shapes - increased for more space between shapes var missedHearts = 0; // Track how many hearts were missed var missedBlocks = 0; // Track how many blocks were missed var missedCheckpointBlocks = 0; // Track how many checkpointblou1 blocks were missed var checkpointCounter = 0; // Track collected checkpoint blocks var totalCollectedBackupLives = 0; // Track total backup lives collected across the game var lastCheckpointX = 300; // Last checkpoint X position var lastCheckpointY = 800; // Last checkpoint Y position var portalSpawned = false; // Track if portal has been spawned for current level var currentObstacleArrayPassed = false; // Track if current obstacle array has been passed var lastObstacleArrayX = 0; // Track the X position of the last obstacle array // Death music is already implemented in the following scenarios: // 1. Ground collision - line 43: LK.getSound('death').play(); // 2. Spike collision - line 5F: LK.getSound('death').play(); // 3. Bomb collision when health is 1 - line 5S: LK.getSound('death').play(); // 4. When health reaches 0 in takeDamage - line 36: LK.getSound('death').play(); LK.setScore(0); // Create score display var scoreTxt = new Text2('0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.y = 100; // Reset storage values to initial state - make all levels unlocked for everyone storage.currentLevel = 1; storage.unlockedLevels = 999; // Unlock all levels for everyone storage.totalScore = 0; // Create level display var levelTxt = new Text2('Seviye ' + currentLevel, { size: 70, fill: 0xFFD700 }); levelTxt.anchor.set(0.5, 0); LK.gui.top.addChild(levelTxt); levelTxt.y = 180; // Create level progress display var progressTxt = new Text2('İlerleme: 0/' + levelScoreThreshold, { size: 40, fill: 0xFFFFFF }); progressTxt.anchor.set(0.5, 0); LK.gui.top.addChild(progressTxt); progressTxt.y = 280; // Create health display var healthTxt = new Text2('Can: ' + playerHealth, { size: 50, fill: 0xff0000 }); healthTxt.anchor.set(0.5, 0); LK.gui.top.addChild(healthTxt); healthTxt.y = 340; // Create checkpoint counter display var checkpointTxt = new Text2('Yedek Can: 0', { size: 50, fill: 0x00FFFF }); checkpointTxt.anchor.set(0.5, 0); LK.gui.top.addChild(checkpointTxt); checkpointTxt.y = 400; // Set initial visibility based on loaded checkpoint setting checkpointTxt.visible = checkpointEnabled; // Create additional checkpoint counter in a more prominent position var checkpointCounterTxt = new Text2('Yedek Can: 0', { size: 60, fill: 0x00FFFF }); checkpointCounterTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(checkpointCounterTxt); checkpointCounterTxt.x = 120; // Position away from menu icon checkpointCounterTxt.y = 20; // Set initial visibility based on loaded checkpoint setting checkpointCounterTxt.visible = checkpointEnabled; // Create backup lives counter display in prominent position var backupLivesTxt = new Text2('Yedek Can: 0', { size: 70, fill: 0x00FFFF }); backupLivesTxt.anchor.set(0.5, 0); LK.gui.top.addChild(backupLivesTxt); backupLivesTxt.y = 460; // Set initial visibility based on checkpoint setting backupLivesTxt.visible = checkpointEnabled; // Create main backup lives counter display var mainBackupLivesTxt = new Text2('Yedek Can: 0', { size: 80, fill: 0x00FFFF }); mainBackupLivesTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(mainBackupLivesTxt); mainBackupLivesTxt.x = 120; // Position away from menu icon mainBackupLivesTxt.y = 100; // Set initial visibility based on checkpoint setting mainBackupLivesTxt.visible = checkpointEnabled; // Create missed checkpoint blocks counter display var missedCheckpointTxt = new Text2('Kaçırılan Yedek Can: 0', { size: 60, fill: 0xff0066 }); missedCheckpointTxt.anchor.set(0.5, 0); LK.gui.top.addChild(missedCheckpointTxt); missedCheckpointTxt.y = 540; // Set initial visibility based on checkpoint setting missedCheckpointTxt.visible = checkpointEnabled; // Create backup lives collected counter display var collectedBackupLivesTxt = new Text2('Toplanan Yedek Can: 0', { size: 60, fill: 0x00ff00 }); collectedBackupLivesTxt.anchor.set(0.5, 0); LK.gui.top.addChild(collectedBackupLivesTxt); collectedBackupLivesTxt.y = 600; // Set initial visibility based on checkpoint setting collectedBackupLivesTxt.visible = checkpointEnabled; // Create destroyed fires counter display var destroyedFiresTxt = new Text2('Yok Edilen Ateş: 0', { size: 50, fill: 0xff6600 }); destroyedFiresTxt.anchor.set(0.5, 0); LK.gui.top.addChild(destroyedFiresTxt); destroyedFiresTxt.y = 520; // Set initial visibility based on fire toggle setting destroyedFiresTxt.visible = fireToggleEnabled; // Initialize destroyed fires counter var destroyedFiresCount = 0; // Create death reason display var deathReasonTxt = new Text2('', { size: 150, fill: 0x000000 }); deathReasonTxt.anchor.set(0.5, 0.5); deathReasonTxt.visible = false; game.addChild(deathReasonTxt); deathReasonTxt.x = 1024; deathReasonTxt.y = 1366; // Death reason variable var lastDeathReason = ''; var isPressing = false; // Track if user is currently pressing var pressStartTime = 0; // Track when press started var longPressThreshold = 150; // Milliseconds to consider a long press // Load mouse tracking setting from storage and apply it var mouseTrackingEnabled = storage.mouseTrackingEnabled; var mouseTrackingBtn = new Text2(mouseTrackingEnabled ? 'Fare Takip: AÇIK' : 'Fare Takip: KAPALI', { size: 60, fill: 0x000000 }); mouseTrackingBtn.anchor.set(1, 0); LK.gui.topRight.addChild(mouseTrackingBtn); mouseTrackingBtn.x = -20; mouseTrackingBtn.y = 100; // Load fire toggle setting from storage and apply it var fireToggleEnabled = storage.fireToggleEnabled; var fireToggleBtn = new Text2(fireToggleEnabled ? 'Ateş: AÇIK' : 'Ateş: KAPALI', { size: 60, fill: 0x000000 }); fireToggleBtn.anchor.set(1, 0); LK.gui.topRight.addChild(fireToggleBtn); fireToggleBtn.x = -20; fireToggleBtn.y = 180; // Load checkpoint setting from storage and apply it var checkpointEnabled = storage.checkpointEnabled; // Create checkpoint toggle button with correct initial text based on loaded setting var checkpointToggleBtn = new Text2(checkpointEnabled ? 'Yedek Can: AÇIK' : 'Yedek Can: KAPALI', { size: 60, fill: 0x000000 }); checkpointToggleBtn.anchor.set(1, 0); LK.gui.topRight.addChild(checkpointToggleBtn); checkpointToggleBtn.x = -20; checkpointToggleBtn.y = 20; // Load long press setting from storage var longPressEnabled = storage.longPressEnabled; // Create long press toggle button with correct initial text based on loaded setting var longPressToggleBtn = new Text2(longPressEnabled ? 'Uzun Basma: AÇIK' : 'Uzun Basma: KAPALI', { size: 60, fill: 0x000000 }); longPressToggleBtn.anchor.set(1, 0); LK.gui.topRight.addChild(longPressToggleBtn); longPressToggleBtn.x = -20; longPressToggleBtn.y = 260; // Add touch event to mouse tracking toggle button mouseTrackingBtn.down = function (x, y, obj) { mouseTrackingEnabled = !mouseTrackingEnabled; storage.mouseTrackingEnabled = mouseTrackingEnabled; if (mouseTrackingEnabled) { mouseTrackingBtn.setText('Fare Takip: AÇIK'); mouseTrackingBtn.fill = 0x000000; // Black } else { mouseTrackingBtn.setText('Fare Takip: KAPALI'); mouseTrackingBtn.fill = 0x000000; // Black } }; // Add touch event to toggle button checkpointToggleBtn.down = function (x, y, obj) { checkpointEnabled = !checkpointEnabled; storage.checkpointEnabled = checkpointEnabled; if (checkpointEnabled) { checkpointToggleBtn.setText('Yedek Can: AÇIK'); checkpointToggleBtn.fill = 0x000000; // Black checkpointTxt.visible = true; // Show checkpoint counter checkpointCounterTxt.visible = true; // Show prominent checkpoint counter backupLivesTxt.visible = true; // Show backup lives counter mainBackupLivesTxt.visible = true; // Show main backup lives counter missedCheckpointTxt.visible = true; // Show missed checkpoint counter collectedBackupLivesTxt.visible = true; // Show collected backup lives counter // Show all checkpoint blocks for (var bl = 0; bl < blocks.length; bl++) { if (blocks[bl]) { blocks[bl].visible = true; } } } else { checkpointToggleBtn.setText('Yedek Can: KAPALI'); checkpointToggleBtn.fill = 0x000000; // Black checkpointTxt.visible = false; // Hide checkpoint counter checkpointCounterTxt.visible = false; // Hide prominent checkpoint counter backupLivesTxt.visible = false; // Hide backup lives counter mainBackupLivesTxt.visible = false; // Hide main backup lives counter missedCheckpointTxt.visible = false; // Hide missed checkpoint counter collectedBackupLivesTxt.visible = false; // Hide collected backup lives counter // Hide all checkpoint blocks for (var bl = 0; bl < blocks.length; bl++) { if (blocks[bl]) { blocks[bl].visible = false; } } } }; // Add touch event to fire toggle button fireToggleBtn.down = function (x, y, obj) { fireToggleEnabled = !fireToggleEnabled; storage.fireToggleEnabled = fireToggleEnabled; if (fireToggleEnabled) { fireToggleBtn.setText('Ateş: AÇIK'); fireToggleBtn.fill = 0x000000; // Black // Show all fires for (var f = 0; f < fires.length; f++) { if (fires[f]) { fires[f].visible = true; } } // Show destroyed fires counter when fire toggle is enabled destroyedFiresTxt.visible = true; } else { fireToggleBtn.setText('Ateş: KAPALI'); fireToggleBtn.fill = 0x000000; // Black // Hide all fires for (var f = 0; f < fires.length; f++) { if (fires[f]) { fires[f].visible = false; } } // Hide destroyed fires counter when fire toggle is disabled destroyedFiresTxt.visible = false; } }; // Add touch event to long press toggle button longPressToggleBtn.down = function (x, y, obj) { longPressEnabled = !longPressEnabled; storage.longPressEnabled = longPressEnabled; if (longPressEnabled) { longPressToggleBtn.setText('Uzun Basma: AÇIK'); longPressToggleBtn.fill = 0x000000; // Black } else { longPressToggleBtn.setText('Uzun Basma: KAPALI'); longPressToggleBtn.fill = 0x000000; // Black } }; // Create instructions var instructionTxt = new Text2('DOKUN VE UÇ\nENGELLERDEN ZİPLA!', { size: 60, fill: 0xFFFFFF }); instructionTxt.anchor.set(0.5, 0.5); game.addChild(instructionTxt); instructionTxt.x = 1024; instructionTxt.y = 1000; // Create ground ground = game.addChild(LK.getAsset('ground', { anchorX: 0, anchorY: 0 })); ground.x = 0; ground.y = 2632; // Solid blue background (camera background removed) game.setBackgroundColor(0x0066ff); // Create bird bird = game.addChild(new Bird()); bird.x = 300; bird.y = 800; // Generate initial obstacle sequence for current level generateLevelObstacleSequence(); // Create initial obstacles at game start createObstacle(); // Create initial background shapes for (var i = 0; i < 15; i++) { createBackgroundShape(); } function generateLevelObstacleSequence() { levelObstacleTypes = []; var baseTypes = ['spike', 'block', 'tallBlock', 'platform', 'restPlatform', 'restPlatform', 'restPlatform', 'laser']; // Door obstacle removed completely var sequenceLength = 50; // Generate enough types for a full level var seed = 3726928364; // Fixed seed value for (var i = 0; i < sequenceLength; i++) { seed = (seed * 9301 + 49297) % 233280; var randomIndex = Math.floor(seed / 233280 * baseTypes.length); levelObstacleTypes.push(baseTypes[randomIndex]); } } function updateLevelProgress() { var levelProgress = LK.getScore(); var progressNeeded = levelScoreThreshold + (currentLevel - 1) * 10; // Update progress display progressTxt.setText('İlerleme: ' + levelProgress + '/' + progressNeeded); } function updateDifficultyForLevel() { // Each level increases difficulty significantly var difficultyMultiplier = 1 + (currentLevel - 1) * 0.4; // Adjust obstacle spacing based on level - gets much tighter obstacleSpacing = Math.max(150, 400 - (currentLevel - 1) * 30); // Adjust bird physics progressively for higher levels if (currentLevel > 2) { bird.gravity = 0.8 + (currentLevel - 2) * 0.15; // Stronger gravity earlier } // Increase bird flap power requirement for higher levels if (currentLevel > 3) { bird.flapPower = Math.max(-18, -12 - (currentLevel - 3) * 1.5); // Stronger flap needed } // Adjust obstacle speed for higher levels var obstacleSpeedMultiplier = 1 + (currentLevel - 1) * 0.2; // Apply speed multiplier to all moving obstacles for (var i = 0; i < obstacles.length; i++) { if (obstacles[i] && !obstacles[i].isStationary) { obstacles[i].speed = -3 * obstacleSpeedMultiplier; } } for (var h = 0; h < hearts.length; h++) { if (hearts[h]) { hearts[h].speed = -3 * obstacleSpeedMultiplier; } } for (var bl = 0; bl < blocks.length; bl++) { if (blocks[bl]) { blocks[bl].speed = -3 * obstacleSpeedMultiplier; } } for (var s = 0; s < spikes.length; s++) { if (spikes[s]) { spikes[s].speed = -2 * obstacleSpeedMultiplier; } } for (var b = 0; b < bombs.length; b++) { if (bombs[b]) { bombs[b].speed = -2 * obstacleSpeedMultiplier; } } for (var l = 0; l < lasers.length; l++) { if (lasers[l]) { lasers[l].speed = -24 * obstacleSpeedMultiplier; } } } function clearAllGameObjects() { // Clear all obstacles for (var i = obstacles.length - 1; i >= 0; i--) { obstacles[i].destroy(); obstacles.splice(i, 1); } // Clear all hearts for (var h = hearts.length - 1; h >= 0; h--) { hearts[h].destroy(); hearts.splice(h, 1); } // Clear all blocks for (var bl = blocks.length - 1; bl >= 0; bl--) { blocks[bl].destroy(); blocks.splice(bl, 1); } // Clear all portals for (var p = portals.length - 1; p >= 0; p--) { portals[p].destroy(); portals.splice(p, 1); } // Clear all spikes for (var s = spikes.length - 1; s >= 0; s--) { spikes[s].destroy(); spikes.splice(s, 1); } // Clear all bombs for (var b = bombs.length - 1; b >= 0; b--) { bombs[b].destroy(); bombs.splice(b, 1); } // Clear all lasers for (var l = lasers.length - 1; l >= 0; l--) { lasers[l].destroy(); lasers.splice(l, 1); } // Clear all characters for (var c = characters.length - 1; c >= 0; c--) { characters[c].destroy(); characters.splice(c, 1); } // Clear all fires for (var f = fires.length - 1; f >= 0; f--) { fires[f].destroy(); fires.splice(f, 1); } // Clear all ice projectiles for (var ic = ices.length - 1; ic >= 0; ic--) { ices[ic].destroy(); ices.splice(ic, 1); } // Clear all background shapes for (var bg = backgroundShapes.length - 1; bg >= 0; bg--) { backgroundShapes[bg].destroy(); backgroundShapes.splice(bg, 1); } // Reset counters obstacleCounter = 0; missedHearts = 0; missedBlocks = 0; checkpointCounter = 0; portalSpawned = false; currentObstacleArrayPassed = false; lastObstacleArrayX = 0; } function resetToLevelStart() { // Reset to level 1 when game over occurs currentLevel = 1; storage.currentLevel = 1; levelTxt.setText('Seviye ' + currentLevel); // Reset score to level start LK.setScore(0); scoreTxt.setText(0); // Reset health playerHealth = 3; healthTxt.setText('Can: ' + playerHealth); // Update checkpoint counter display checkpointTxt.setText('Yedek Can: ' + checkpointCounter); checkpointCounterTxt.setText('Yedek Can: ' + checkpointCounter); // Restart music when game resets LK.playMusic('hfu2'); // Clear all obstacles for (var i = obstacles.length - 1; i >= 0; i--) { obstacles[i].destroy(); obstacles.splice(i, 1); } // Clear all background shapes for (var j = backgroundShapes.length - 1; j >= 0; j--) { backgroundShapes[j].destroy(); backgroundShapes.splice(j, 1); } // Clear all hearts for (var k = hearts.length - 1; k >= 0; k--) { hearts[k].destroy(); hearts.splice(k, 1); } // Clear all blocks for (var bl = blocks.length - 1; bl >= 0; bl--) { blocks[bl].destroy(); blocks.splice(bl, 1); } // Clear all portals for (var p = portals.length - 1; p >= 0; p--) { portals[p].destroy(); portals.splice(p, 1); } // Clear all spikes for (var s = spikes.length - 1; s >= 0; s--) { spikes[s].destroy(); spikes.splice(s, 1); } // Clear all bombs for (var b = bombs.length - 1; b >= 0; b--) { bombs[b].destroy(); bombs.splice(b, 1); } // Clear all lasers for (var l = lasers.length - 1; l >= 0; l--) { lasers[l].destroy(); lasers.splice(l, 1); } // Clear all characters for (var ch = characters.length - 1; ch >= 0; ch--) { characters[ch].destroy(); characters.splice(ch, 1); } // Clear all fires for (var fi = fires.length - 1; fi >= 0; fi--) { fires[fi].destroy(); fires.splice(fi, 1); } // Clear all ice projectiles for (var ic = ices.length - 1; ic >= 0; ic--) { ices[ic].destroy(); ices.splice(ic, 1); } // Reset obstacle counter obstacleCounter = 0; // Reset missed hearts counter missedHearts = 0; // Reset missed blocks counter missedBlocks = 0; // Reset missed checkpoint blocks counter missedCheckpointBlocks = 0; missedCheckpointTxt.setText('Kaçırılan Yedek Can: ' + missedCheckpointBlocks); // Reset checkpoint counter checkpointCounter = 0; // Update checkpoint counter displays checkpointTxt.setText('Yedek Can: ' + checkpointCounter); checkpointCounterTxt.setText('Yedek Can: ' + checkpointCounter); backupLivesTxt.setText('Yedek Can: ' + checkpointCounter); mainBackupLivesTxt.setText('Yedek Can: ' + checkpointCounter); // Reset destroyed fires counter destroyedFiresCount = 0; destroyedFiresTxt.setText('Yok Edilen Ateş: ' + destroyedFiresCount); // Reset total collected backup lives counter totalCollectedBackupLives = 0; collectedBackupLivesTxt.setText('Toplanan Yedek Can: ' + totalCollectedBackupLives); // Reset portal spawned flag portalSpawned = false; // Reset obstacle array tracking currentObstacleArrayPassed = false; lastObstacleArrayX = 0; // Reset checkpoint position to start lastCheckpointX = 300; lastCheckpointY = 800; // Reset bird position bird.x = 300; bird.y = 800; bird.velocityY = 0; bird.completedFlips = 0; // Regenerate obstacle sequence for current level generateLevelObstacleSequence(); // Update displays updateLevelProgress(); // Update difficulty for level 1 updateDifficultyForLevel(); // Create initial obstacle createObstacle(); } function takeDamage() { // Check if we have checkpoints available and checkpoint system is enabled if (checkpointEnabled && checkpointCounter > 0) { // Use checkpoint instead of losing health checkpointCounter--; checkpointTxt.setText('Yedek Can: ' + checkpointCounter); checkpointCounterTxt.setText('Yedek Can: ' + checkpointCounter); backupLivesTxt.setText('Yedek Can: ' + checkpointCounter); mainBackupLivesTxt.setText('Yedek Can: ' + checkpointCounter); // Reset bird to last checkpoint position bird.x = lastCheckpointX; bird.y = lastCheckpointY; bird.velocityY = 0; // Flash screen yellow to indicate checkpoint usage tween(game, { tint: 0xffff44 }, { duration: 200, onFinish: function onFinish() { tween(game, { tint: 0xffffff }, { duration: 200 }); } }); // Play death music LK.getSound('death').play(); // Play death sound LK.getSound('deathSound').play(); return; // Don't lose health, checkpoint consumed instead } else { // No checkpoints available, lose health normally playerHealth--; healthTxt.setText('Can: ' + playerHealth); // Play warning sound when health decreases LK.getSound('healthWarning').play(); // Flash screen red when taking damage tween(game, { tint: 0xff4444 }, { duration: 200, onFinish: function onFinish() { tween(game, { tint: 0xffffff }, { duration: 200 }); } }); // Check if game over if (playerHealth <= 0) { showDeathReason('CANINIZ BİTTİ!'); // Show standard game over when no checkpoints available resetToLevelStart(); LK.showGameOver(); return; } } } function resetHealth() { playerHealth = 3; healthTxt.setText('Can: ' + playerHealth); } function startGame() { if (!gameStarted) { gameStarted = true; game.removeChild(instructionTxt); // Start playing music when game begins - restart music for new game LK.playMusic('hfu2'); // Reset obstacle counter for consistent level maps obstacleCounter = 0; // Generate obstacle sequence for current level generateLevelObstacleSequence(); resetHealth(); // Reset health when starting game updateDifficultyForLevel(); updateLevelProgress(); } } function createBackgroundShape() { var bgShape = new BackgroundShape(); bgShape.x = 2200 + Math.random() * 200; // Start off-screen right bgShape.y = 200 + Math.random() * 2300; // Random Y position // Scale background shapes to 3 times their original size bgShape.scaleX = 3; bgShape.scaleY = 3; // Check distance from existing background shapes to ensure spacing var minDistance = 400; // Minimum distance between shapes var validPosition = true; for (var i = 0; i < backgroundShapes.length; i++) { var existingShape = backgroundShapes[i]; var distanceX = bgShape.x - existingShape.x; var distanceY = bgShape.y - existingShape.y; var distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY); if (distance < minDistance) { validPosition = false; break; } } // Only add the shape if it has enough spacing if (validPosition) { backgroundShapes.push(bgShape); game.addChild(bgShape); } else { // Destroy the shape if position is invalid bgShape.destroy(); } } function createHeart() { var heart = new Heart(); heart.x = 2200; // Start off-screen right heart.y = bird.y - 400 + Math.random() * 800; // Random Y position around bird's flight path hearts.push(heart); game.addChild(heart); } function createSpike() { // Use seed based on current level and time for randomness var spikeSeed = (currentLevel * 7777 + LK.ticks + Date.now()) % 99991; var spikeRandom = (spikeSeed * 9301 + 49297) % 233280 / 233280; // Only create spike if random chance is met (roughly 15% chance increased by 50x to 100%) if (spikeRandom < 1.0) { var spike = new Spike(); spike.x = 2200 + Math.random() * 100; // Start off-screen right spike.y = 300 + spikeRandom * 2000; // Random Y position spikes.push(spike); game.addChild(spike); } } function createObstacle() { // Create walls that cover full screen with a gap for the bird var baseX = 2148; var gapSize = 600; // Size of the gap for bird to pass through // Progressive gap size reduction per level for increased difficulty if (currentLevel === 1) { gapSize = 650; // Easier start for level 1 } else if (currentLevel === 2) { gapSize = 580; // Slightly smaller for level 2 } else if (currentLevel === 3) { gapSize = 520; // Even smaller for level 3 } else if (currentLevel >= 4) { // Much more challenging gaps for level 4+ var baseLevelGap = Math.max(350, 500 - (currentLevel - 4) * 25); // Starts at 500, reduces by 25 per level, minimum 350 var obstacleReduction = Math.max(0, obstacleCounter * 3); // Reduce by 3 per obstacle within level gapSize = Math.max(300, baseLevelGap - obstacleReduction); // Minimum gap of 300 } // Use seeded random based on current level and obstacle counter only var seed = (currentLevel * 1000 + obstacleCounter) % 9973; // Use prime number for better distribution var seededRandom = (seed * 9301 + 49297) % 233280 / 233280; // Linear congruential generator var gapPosition = seededRandom * (2200 - gapSize) + 300; // Seeded gap position between 300-2200 var obstacleHeight = 320; // Height of each obstacle segment (reduced from 400) // Reduce obstacle height for Level 4 to create more segments and fill gaps if (currentLevel >= 4) { obstacleHeight = 240; // Smaller segments create more obstacles (reduced from 300) } var numSegments = Math.ceil(2732 / obstacleHeight); // Number of segments to cover full height for (var i = 0; i < numSegments; i++) { var segmentY = i * obstacleHeight + obstacleHeight / 2; // Skip creating obstacles in the gap area if (segmentY + obstacleHeight / 2 > gapPosition && segmentY - obstacleHeight / 2 < gapPosition + gapSize) { continue; } var obstacle = new Obstacle(); obstacle.x = baseX; obstacle.y = segmentY; obstacles.push(obstacle); game.addChild(obstacle); } // Add extra obstacles to fill empty spaces - more for higher levels var extraObstacles = Math.min(15, 4 + currentLevel + Math.floor(seededRandom * (2 + currentLevel))); // Scales with level: 5-7 for level 1, up to 15 for high levels for (var j = 0; j < extraObstacles; j++) { var extraSeed = (seed + j * 777) % 9973; var extraRandom = (extraSeed * 9301 + 49297) % 233280 / 233280; var obstacleX = baseX + 100 + extraRandom * (400 + currentLevel * 50); // Wider spread for higher levels var obstacleY = 150 + extraRandom * 2300; // Cover more vertical space // Make sure it's not in the main gap area - tighter constraints for higher levels var gapBuffer = Math.max(30, 80 - currentLevel * 5); // Smaller buffer for higher levels if (obstacleY < gapPosition - gapBuffer || obstacleY > gapPosition + gapSize + gapBuffer) { var extraObstacle = new Obstacle(); extraObstacle.x = obstacleX; extraObstacle.y = obstacleY; obstacles.push(extraObstacle); game.addChild(extraObstacle); } } // Add obstacles in the middle area - much more for higher levels var middleObstacles = Math.min(12, 3 + currentLevel * 2 + Math.floor(seededRandom * currentLevel)); // Scales dramatically: 4-6 for level 1, up to 12 for high levels for (var m = 0; m < middleObstacles; m++) { var middleSeed = (seed + m * 333 + 111) % 9973; var middleRandom = (middleSeed * 9301 + 49297) % 233280 / 233280; var middleX = baseX - 300 - middleRandom * (600 + currentLevel * 100); // Wider area coverage for higher levels var middleY = 250 + middleRandom * 2100; // Random Y position // Ensure obstacles are within screen bounds - tighter placement for higher levels var minX = Math.max(400, 600 - currentLevel * 20); // Allow closer placement for higher levels if (middleX > minX && middleY > 150 && middleY < 2500) { var middleObstacle = new Obstacle(); middleObstacle.x = middleX; middleObstacle.y = middleY; obstacles.push(middleObstacle); game.addChild(middleObstacle); } } // Add additional scattered obstacles for Level 4, but fewer at the beginning if (currentLevel >= 4 && obstacleCounter > 3) { // Create 2-3 additional obstacles in random positions, but only after first few obstacles var additionalObstacles = 2 + Math.floor(seededRandom * 2); // 2-3 obstacles for (var j = 0; j < additionalObstacles; j++) { var additionalSeed = (seed + j * 1000) % 9973; var additionalRandom = (additionalSeed * 9301 + 49297) % 233280 / 233280; var obstacleX = baseX + 200 + additionalRandom * 400; // Spread them out var obstacleY = 400 + additionalRandom * 1800; // Random Y position // Make sure it's not in the main gap area if (obstacleY < gapPosition || obstacleY > gapPosition + gapSize) { var additionalObstacle = new Obstacle(); additionalObstacle.x = obstacleX; additionalObstacle.y = obstacleY; obstacles.push(additionalObstacle); game.addChild(additionalObstacle); } } // Add obstacles specifically in character's current area for Level 4, but fewer at the beginning var characterAreaObstacles = obstacleCounter > 2 ? 3 + Math.floor(seededRandom * 2) : 1 + Math.floor(seededRandom * 1); // Start with 1-2 obstacles, then 3-4 for (var k = 0; k < characterAreaObstacles; k++) { var charAreaSeed = (seed + k * 2000 + 500) % 9973; var charAreaRandom = (charAreaSeed * 9301 + 49297) % 233280 / 233280; // Place obstacles in character's vicinity (around x=300, y=800) var charObstacleX = baseX + 100 + charAreaRandom * 300; // Close to current obstacles var charObstacleY = bird.y - 400 + charAreaRandom * 800; // Around character's Y position // Ensure obstacles are within screen bounds and not in gap if (charObstacleY > 100 && charObstacleY < 2500 && (charObstacleY < gapPosition || charObstacleY > gapPosition + gapSize)) { var charAreaObstacle = new Obstacle(); charAreaObstacle.x = charObstacleX; charAreaObstacle.y = charObstacleY; obstacles.push(charAreaObstacle); game.addChild(charAreaObstacle); } } } obstacleCounter++; lastObstacle = LK.ticks; // Update the last obstacle array position and reset completion flag lastObstacleArrayX = baseX; currentObstacleArrayPassed = false; // Create rest platform every 2 obstacles if (obstacleCounter % 2 === 0) { var restPlatform = new Obstacle(); restPlatform.obstacleType = 'restPlatform'; restPlatform.speed = 0; restPlatform.isStationary = true; restPlatform.isSafe = true; restPlatform.x = baseX + 300; // Position rest platform after obstacles restPlatform.y = gapPosition + gapSize / 2; // Center in gap area obstacles.push(restPlatform); game.addChild(restPlatform); } // Create hearts based on missed hearts count (minimum 1, add 1 for each missed) var heartsToCreate = 1 + missedHearts; for (var heartIndex = 0; heartIndex < heartsToCreate; heartIndex++) { var heart = new Heart(); heart.x = baseX + 30; // Position heart 30 pixels ahead of obstacle // Spread multiple hearts vertically in the gap area if (heartsToCreate === 1) { heart.y = bird.y - 400 + Math.random() * 800; // Position single heart near bird's flight path } else { // Distribute multiple hearts evenly across the gap var heartSpacing = gapSize / (heartsToCreate + 1); heart.y = gapPosition + heartSpacing * (heartIndex + 1); } hearts.push(heart); game.addChild(heart); } // Create blocks based on missed blocks count (minimum 1, add 1 for each missed) var blocksToCreate = 1 + missedBlocks; for (var blockIndex = 0; blockIndex < blocksToCreate; blockIndex++) { var block = new Block(); block.x = baseX + 130; // Position block 100 pixels ahead of hearts (30 + 100) // Spread multiple blocks vertically in the gap area if (blocksToCreate === 1) { block.y = gapPosition + gapSize / 2 + 60; // Position single block offset from heart } else { // Distribute multiple blocks evenly across the gap var blockSpacing = gapSize / (blocksToCreate + 1); block.y = gapPosition + blockSpacing * (blockIndex + 1) + 60; } // Hide block if checkpoint system is disabled if (!checkpointEnabled) { block.visible = false; } blocks.push(block); game.addChild(block); } // Create spikes based on level - more spikes for higher levels with strategic positioning var spikesToCreate = Math.min(5, Math.floor(currentLevel / 2) + 1); // 1 spike for levels 1-2, up to 5 for high levels for (var spikeIndex = 0; spikeIndex < spikesToCreate; spikeIndex++) { var spike = new Spike(); spike.x = baseX + 40 + spikeIndex * 25; // Position spikes closer together // Strategic spike positioning for higher levels if (spikesToCreate === 1) { spike.y = gapPosition + gapSize / 2 + 120; // Single spike offset from heart position } else if (currentLevel >= 3) { // For level 3+: place spikes to create challenging patterns if (spikeIndex === 0) { spike.y = gapPosition - 50; // Above gap } else if (spikeIndex === 1) { spike.y = gapPosition + gapSize + 50; // Below gap } else { // Additional spikes within gap area for extreme difficulty var innerSpacing = gapSize / (spikesToCreate - 1); spike.y = gapPosition + innerSpacing * (spikeIndex - 2); } } else { // For levels 1-2: distribute spikes more safely var spikeSpacing = (gapSize + 200) / spikesToCreate; spike.y = gapPosition - 50 + spikeSpacing * spikeIndex; } spikes.push(spike); game.addChild(spike); } // Add 70 spikes scattered at the end of each obstacle for (var endSpikeIndex = 0; endSpikeIndex < 70; endSpikeIndex++) { var endSpike = new Spike(); // Scatter spikes randomly across a wide area at the end of obstacle var scatterSeed = (currentLevel * 1000 + obstacleCounter * 100 + endSpikeIndex) % 9973; var scatterRandomX = (scatterSeed * 9301 + 49297) % 233280 / 233280; var scatterRandomY = ((scatterSeed + 1000) * 9301 + 49297) % 233280 / 233280; endSpike.x = baseX + 500 + scatterRandomX * 400; // Scatter across 400px width endSpike.y = 150 + scatterRandomY * 2300; // Scatter across full height spikes.push(endSpike); game.addChild(endSpike); } // Create bombs based on level - much more frequent and challenging for higher levels var bombFrequency = Math.max(1, 3 - currentLevel); // Level 1: every 2 obstacles, Level 2: every obstacle, Level 3+: every obstacle if (obstacleCounter % bombFrequency === 0) { // Create multiple bombs for higher levels var bombCount = Math.min(5, Math.floor(currentLevel / 2) + 2); // 2 bombs for levels 1-2, 3 for 3-4, 4 for 5-6, 5 for 7+ for (var bombIndex = 0; bombIndex < bombCount; bombIndex++) { var bomb = new Bomb(); bomb.x = baseX + 50 + bombIndex * 40; // Spread bombs horizontally // Position bombs at different heights for higher levels if (bombCount === 1) { bomb.y = gapPosition + gapSize / 2 - 100; // Single bomb position } else { // Distribute multiple bombs vertically in and around the gap var bombSpacing = (gapSize + 200) / bombCount; bomb.y = gapPosition - 100 + bombSpacing * bombIndex; } bombs.push(bomb); game.addChild(bomb); } } // Create exactly 6 lasers with each obstacle if (currentLevel >= 1) { var laserCount = 6; // Always create exactly 6 lasers for (var laserIndex = 0; laserIndex < laserCount; laserIndex++) { var laser = new Laser(); laser.x = baseX + 100 + laserIndex * 40; // Spread lasers horizontally with closer spacing laser.startX = laser.x; // Set starting position for oscillation // Distribute 6 lasers vertically around the gap var laserSpacing = (gapSize + 300) / laserCount; laser.y = gapPosition - 150 + laserSpacing * laserIndex; lasers.push(laser); game.addChild(laser); } } // Create characters based on level var charactersToCreate = Math.min(3, 1 + Math.floor(currentLevel / 3)); // 1-2 characters for early levels, up to 3 for higher levels for (var charIndex = 0; charIndex < charactersToCreate; charIndex++) { var character = new Character(); character.x = baseX + 200 + charIndex * 60; // Position characters horizontally // Distribute characters vertically in and around the gap var characterSpacing = (gapSize + 200) / charactersToCreate; character.y = gapPosition - 100 + characterSpacing * charIndex; characters.push(character); game.addChild(character); } // Create fires frequently - 2-4 fires per obstacle var firesToCreate = 2 + Math.floor(Math.random() * 3); // 2-4 fires for (var fireIndex = 0; fireIndex < firesToCreate; fireIndex++) { var fire = new Fire(); fire.x = baseX + 80 + fireIndex * 50; // Position fires horizontally // Distribute fires vertically across the screen var fireSpacing = 2400 / firesToCreate; fire.y = 200 + fireSpacing * fireIndex; // Set fire visibility based on toggle state fire.visible = fireToggleEnabled; fires.push(fire); game.addChild(fire); } // Create rest platforms above and below the gap (door area) var topRestPlatform = new Obstacle(); topRestPlatform.obstacleType = 'restPlatform'; topRestPlatform.speed = 0; topRestPlatform.isStationary = true; topRestPlatform.isSafe = true; topRestPlatform.x = baseX; topRestPlatform.y = gapPosition - 100; // Position above the gap obstacles.push(topRestPlatform); game.addChild(topRestPlatform); var bottomRestPlatform = new Obstacle(); bottomRestPlatform.obstacleType = 'restPlatform'; bottomRestPlatform.speed = 0; bottomRestPlatform.isStationary = true; bottomRestPlatform.isSafe = true; bottomRestPlatform.x = baseX; bottomRestPlatform.y = gapPosition + gapSize + 100; // Position below the gap obstacles.push(bottomRestPlatform); game.addChild(bottomRestPlatform); } function checkCollisions() { // Check ground collision - respawn at checkpoint when bird touches ground if (bird.y + 60 >= ground.y) { showDeathReason('YERE ÇARPTIN!'); if (checkpointEnabled) { // Reset bird to last checkpoint position bird.x = lastCheckpointX; bird.y = lastCheckpointY; bird.velocityY = 0; } else { // Reset to start position when checkpoint disabled bird.x = 300; bird.y = 800; bird.velocityY = 0; } // Take damage takeDamage(); // Play death music LK.getSound('death').play(); // Play death sound LK.getSound('deathSound').play(); return; } // Check obstacle collisions - bounce off obstacles for (var i = obstacles.length - 1; i >= 0; i--) { var obstacle = obstacles[i]; // Skip if obstacle is undefined if (!obstacle) { obstacles.splice(i, 1); continue; } if (bird.intersects(obstacle)) { // Check if it's a rest platform - safe area if (obstacle.obstacleType === 'restPlatform') { // Safe collision - just bounce without damage var distanceX = bird.x - obstacle.x; var distanceY = bird.y - obstacle.y; var totalDistance = Math.sqrt(distanceX * distanceX + distanceY * distanceY); if (totalDistance > 0) { var normalX = distanceX / totalDistance; var normalY = distanceY / totalDistance; // Gentle push away from platform var pushForce = 3; bird.x += normalX * pushForce; bird.y += normalY * pushForce; // Apply gentle bounce velocity bird.velocityY = normalY * 3; // Visual feedback for landing on safe platform LK.effects.flashObject(obstacle, 0x00ff88, 300); } continue; // Skip damage dealing } // Only take damage if not already damaged from this obstacle if (!obstacle.damagedBird) { takeDamage(); obstacle.damagedBird = true; // Mark this obstacle as having caused damage } // Calculate collision direction var distanceX = bird.x - obstacle.x; var distanceY = bird.y - obstacle.y; var totalDistance = Math.sqrt(distanceX * distanceX + distanceY * distanceY); // Normalize collision direction if (totalDistance > 0) { var normalX = distanceX / totalDistance; var normalY = distanceY / totalDistance; // Push bird away from obstacle var pushForce = 8; bird.x += normalX * pushForce; bird.y += normalY * pushForce; // Apply bounce velocity var bounceForce = 5; bird.velocityY = normalY * bounceForce; // Play flap sound for bounce feedback LK.getSound('flap').play(); } } // Check if bird passed obstacle (mark individual obstacles as passed but don't award points yet) if (!obstacle.passed && obstacle.x + 100 < bird.x) { obstacle.passed = true; } ; // Remove off-screen obstacles (but keep stationary gears and rest platforms) if (obstacle.x < -100 && !obstacle.isStationary) { // Add flash effect when obstacle disappears LK.effects.flashObject(obstacle, 0xffffff, 200); obstacle.destroy(); obstacles.splice(i, 1); } } // Check heart collections for (var h = hearts.length - 1; h >= 0; h--) { var heart = hearts[h]; // Skip if heart is undefined if (!heart) { hearts.splice(h, 1); continue; } // Check if bird collected the heart if (bird.intersects(heart) && !heart.collected) { heart.collected = true; // Reset missed hearts counter when collecting a heart missedHearts = 0; // Always increase health (no maximum limit) playerHealth++; healthTxt.setText('Can: ' + playerHealth); // Increase score by 2 when collecting heart LK.setScore(LK.getScore() + 2); storage.levelScore = LK.getScore(); // Save to storage scoreTxt.setText(LK.getScore()); updateLevelProgress(); // Visual feedback for collecting heart tween(heart, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { heart.destroy(); } }); // Flash screen green briefly LK.effects.flashScreen(0x00ff00, 200); // Play score sound as feedback LK.getSound('score').play(); hearts.splice(h, 1); continue; } // Remove off-screen hearts if (heart.x < -100) { // Track that this heart was missed missedHearts++; heart.destroy(); hearts.splice(h, 1); } } // Check block collections for (var bl = blocks.length - 1; bl >= 0; bl--) { var block = blocks[bl]; // Skip if block is undefined if (!block) { blocks.splice(bl, 1); continue; } // Check if bird collected the block if (bird.intersects(block) && !block.collected) { block.collected = true; // Reset missed blocks counter when collecting a block missedBlocks = 0; // Only save checkpoint if system is enabled if (checkpointEnabled) { // Increment checkpoint counter checkpointCounter++; checkpointTxt.setText('Yedek Can: ' + checkpointCounter); checkpointCounterTxt.setText('Yedek Can: ' + checkpointCounter); backupLivesTxt.setText('Yedek Can: ' + checkpointCounter); mainBackupLivesTxt.setText('Yedek Can: ' + checkpointCounter); // Save checkpoint position lastCheckpointX = block.x; lastCheckpointY = block.y; } // Always increment total collected backup lives counter regardless of checkpoint enabled state totalCollectedBackupLives++; collectedBackupLivesTxt.setText('Toplanan Yedek Can: ' + totalCollectedBackupLives); // Increase score by 0.5 when collecting checkpoint LK.setScore(LK.getScore() + 0.5); storage.levelScore = LK.getScore(); // Save to storage scoreTxt.setText(LK.getScore()); updateLevelProgress(); // Increase health by 0 when collecting block (no health change) playerHealth += 0; healthTxt.setText('Can: ' + playerHealth); // Visual feedback for collecting block tween(block, { scaleX: 2.5, scaleY: 2.5, alpha: 0, rotation: Math.PI * 2 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { block.destroy(); } }); // Flash screen blue briefly LK.effects.flashScreen(0x4169E1, 300); // Play score sound as feedback LK.getSound('score').play(); blocks.splice(bl, 1); continue; } // Remove off-screen blocks if (block.x < -100) { // Track that this block was missed missedBlocks++; // Track missed checkpoint blocks specifically missedCheckpointBlocks++; missedCheckpointTxt.setText('Kaçırılan Yedek Can: ' + missedCheckpointBlocks); block.destroy(); blocks.splice(bl, 1); } } // Check spike collisions - instant death for (var s = spikes.length - 1; s >= 0; s--) { var spike = spikes[s]; // Skip if spike is undefined if (!spike) { spikes.splice(s, 1); continue; } // Check if bird touched the spike - respawn at checkpoint if (bird.intersects(spike)) { showDeathReason('DİKENE ÇARPTIN!'); if (checkpointEnabled) { // Reset bird to last checkpoint position bird.x = lastCheckpointX; bird.y = lastCheckpointY; bird.velocityY = 0; } else { // Reset to start position when checkpoint disabled bird.x = 300; bird.y = 800; bird.velocityY = 0; } // Take damage takeDamage(); // Play death music LK.getSound('death').play(); // Play death sound LK.getSound('deathSound').play(); // Flash screen red to indicate death LK.effects.flashScreen(0xff0000, 500); return; // Exit collision check immediately } // Remove off-screen spikes if (spike.x < -150) { spike.destroy(); spikes.splice(s, 1); } } // Check bomb collisions - reduce health to 1 and remove all hearts for (var b = bombs.length - 1; b >= 0; b--) { var bomb = bombs[b]; // Skip if bomb is undefined if (!bomb) { bombs.splice(b, 1); continue; } // Check if bird touched the bomb if (bird.intersects(bomb) && !bomb.collected) { bomb.collected = true; // Play bomb explosion sound LK.getSound('bombExplosion').play(); // Create explosion effect - scale up and fade out tween(bomb, { scaleX: 3, scaleY: 3, alpha: 0, rotation: Math.PI * 2 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { bomb.destroy(); } }); // Hide all hearts when bomb explodes for (var hHide = 0; hHide < hearts.length; hHide++) { if (hearts[hHide]) { hearts[hHide].visible = false; } } // Check if player already had 1 health (would die from bomb) if (playerHealth <= 1) { showDeathReason('BOMBA PATLADI!'); if (checkpointEnabled) { // Reset bird to last checkpoint position bird.x = lastCheckpointX; bird.y = lastCheckpointY; bird.velocityY = 0; } else { // Reset to start position when checkpoint disabled bird.x = 300; bird.y = 800; bird.velocityY = 0; } // Reset health to 3 playerHealth = 3; healthTxt.setText('Can: ' + playerHealth); // Play death music LK.getSound('death').play(); // Play death sound LK.getSound('deathSound').play(); return; // Exit collision check immediately } // Reduce health to 1 playerHealth = 1; healthTxt.setText('Can: ' + playerHealth); // Flash screen red to indicate bomb effect LK.effects.flashScreen(0xff4444, 800); // Remove the bomb from array but don't destroy immediately (explosion handles destruction) bombs.splice(b, 1); continue; } // Remove off-screen bombs if (bomb.x < -150) { bomb.destroy(); bombs.splice(b, 1); } } // Check laser collisions - damage player and apply knockback for (var l = lasers.length - 1; l >= 0; l--) { var laser = lasers[l]; // Skip if laser is undefined if (!laser) { lasers.splice(l, 1); continue; } // Check if bird touched the laser if (bird.intersects(laser) && !laser.collected) { laser.collected = true; // Play laser sound LK.getSound('laserSound').play(); // Take damage takeDamage(); // Apply knockback effect var knockbackForce = 15; var distanceX = bird.x - laser.x; var distanceY = bird.y - laser.y; var totalDistance = Math.sqrt(distanceX * distanceX + distanceY * distanceY); if (totalDistance > 0) { var normalX = distanceX / totalDistance; var normalY = distanceY / totalDistance; // Push bird away from laser bird.x += normalX * knockbackForce; bird.y += normalY * knockbackForce; // Apply strong bounce velocity bird.velocityY = normalY * 8; } // Flash screen red to indicate laser hit LK.effects.flashScreen(0xff0000, 400); // Create destruction effect for laser tween(laser, { scaleX: 0, scaleY: 0, alpha: 0, rotation: Math.PI * 4 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { laser.destroy(); } }); lasers.splice(l, 1); continue; } // Remove off-screen lasers (now check right side since they move right) if (laser.x > 2300) { laser.destroy(); lasers.splice(l, 1); } } // Check character collisions - character dies when touched by bird for (var c = characters.length - 1; c >= 0; c--) { var character = characters[c]; // Skip if character is undefined if (!character) { characters.splice(c, 1); continue; } // Check if bird touched the character if (bird.intersects(character) && !character.isDead) { character.isDead = true; // Visual feedback for character death tween(character, { scaleX: 0.1, scaleY: 0.1, alpha: 0, rotation: Math.PI * 3 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { character.destroy(); } }); // Flash screen briefly to indicate character death LK.effects.flashScreen(0xFFFF00, 200); // Play score sound as feedback LK.getSound('score').play(); characters.splice(c, 1); continue; } // Remove off-screen characters if (character.x < -150) { character.destroy(); characters.splice(c, 1); } } // Check fire collisions - instant death that completely ignores checkpoint system for (var f = fires.length - 1; f >= 0; f--) { var fire = fires[f]; // Skip if fire is undefined if (!fire) { fires.splice(f, 1); continue; } // Check if bird touched the fire if (bird.intersects(fire) && !fire.collected) { fire.collected = true; showDeathReason('ATEŞE DOKUNDIN!'); // Fire causes instant death - completely bypass checkpoint system and kill bird immediately // Reset to start position regardless of any checkpoint settings bird.x = 300; bird.y = 800; bird.velocityY = 0; // Reset checkpoint counter to 0 when touching fire checkpointCounter = 0; checkpointTxt.setText('Yedek Can: ' + checkpointCounter); checkpointCounterTxt.setText('Yedek Can: ' + checkpointCounter); backupLivesTxt.setText('Yedek Can: ' + checkpointCounter); mainBackupLivesTxt.setText('Yedek Can: ' + checkpointCounter); // Show game over immediately - fire kills bird instantly resetToLevelStart(); LK.showGameOver(); // Play death music LK.getSound('death').play(); // Play death sound LK.getSound('deathSound').play(); // Create fire destruction effect tween(fire, { scaleX: 2, scaleY: 2, alpha: 0, rotation: Math.PI * 2 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { fire.destroy(); } }); // Flash screen orange to indicate fire damage LK.effects.flashScreen(0xff4400, 300); fires.splice(f, 1); return; // Exit collision check immediately after fire death } // Remove off-screen fires if (fire.x < -150) { fire.destroy(); fires.splice(f, 1); } } // Check portal collisions for (var p = portals.length - 1; p >= 0; p--) { var portal = portals[p]; // Skip if portal is undefined if (!portal) { portals.splice(p, 1); continue; } if (bird.intersects(portal)) { // Flash screen purple to indicate portal entry LK.effects.flashScreen(0x9966ff, 800); // Add current level score to total and preserve it totalScore += LK.getScore(); storage.totalScore = totalScore; storage.levelScore = LK.getScore(); // Save current level score // All levels are already unlocked for everyone - no need to unlock unlockedLevels = 999; // Keep all levels unlocked storage.unlockedLevels = unlockedLevels; // Advance to next level currentLevel++; storage.currentLevel = currentLevel; levelTxt.setText('Seviye ' + currentLevel); // Keep current score when advancing levels (don't reset to 0) // Score persists to next level scoreTxt.setText(LK.getScore()); // Reset obstacle counter for consistent level maps obstacleCounter = 0; // Clear all obstacles for (var j = obstacles.length - 1; j >= 0; j--) { obstacles[j].destroy(); obstacles.splice(j, 1); } // Clear all portals for (var pt = portals.length - 1; pt >= 0; pt--) { portals[pt].destroy(); portals.splice(pt, 1); } // Generate new obstacle sequence for the new level generateLevelObstacleSequence(); updateLevelProgress(); // Increase difficulty for new level updateDifficultyForLevel(); // Reset bird position bird.x = 300; bird.y = 800; bird.velocityY = 0; bird.completedFlips = 0; // Reset health resetHealth(); // Reset portal spawned flag portalSpawned = false; // Create initial obstacle for new level createObstacle(); return; // Exit collision check to avoid other collision handling } // Remove off-screen portals if (portal.x < -200) { portal.destroy(); portals.splice(p, 1); } } // Check ceiling collision if (bird.y < 50) { bird.y = 50; bird.velocityY = 0; } } game.down = function (x, y, obj) { // Check if right mouse button (button 2) or secondary touch if (obj.event && (obj.event.button === 2 || obj.event.which === 3)) { // Right click - only throw ice if cursor is over a fire and fire toggle is enabled if (gameStarted && fireToggleEnabled) { // Check if cursor position is over any fire object var cursorOverFire = false; for (var f = 0; f < fires.length; f++) { var fire = fires[f]; if (fire && !fire.collected) { // Check if cursor position is within fire bounds var fireLeft = fire.x - 50; // Half of fire width (100/2) var fireRight = fire.x + 50; var fireTop = fire.y - 50; // Half of fire height (100/2) var fireBottom = fire.y + 50; if (x >= fireLeft && x <= fireRight && y >= fireTop && y <= fireBottom) { cursorOverFire = true; break; } } } // Only throw ice if cursor is over a fire if (cursorOverFire) { var ice = new Ice(); ice.x = bird.x; ice.y = bird.y; // Calculate direction towards cursor var directionX = x - bird.x; var directionY = y - bird.y; var distance = Math.sqrt(directionX * directionX + directionY * directionY); // Normalize direction and set ice velocity if (distance > 0) { ice.velocityX = directionX / distance * 8; ice.velocityY = directionY / distance * 8; } else { ice.velocityX = 8; ice.velocityY = 0; } ices.push(ice); game.addChild(ice); } } return; } // Check if left mouse button or primary touch AND cursor is over fire if (gameStarted && fireToggleEnabled) { // Check if cursor position is over any fire object var cursorOverFire = false; for (var f = 0; f < fires.length; f++) { var fire = fires[f]; if (fire && !fire.collected) { // Check if cursor position is within fire bounds var fireLeft = fire.x - 50; // Half of fire width (100/2) var fireRight = fire.x + 50; var fireTop = fire.y - 50; // Half of fire height (100/2) var fireBottom = fire.y + 50; if (x >= fireLeft && x <= fireRight && y >= fireTop && y <= fireBottom) { cursorOverFire = true; break; } } } // If cursor is over fire, throw ice instead of flapping if (cursorOverFire) { var ice = new Ice(); ice.x = bird.x; ice.y = bird.y; // Calculate direction towards cursor var directionX = x - bird.x; var directionY = y - bird.y; var distance = Math.sqrt(directionX * directionX + directionY * directionY); // Normalize direction and set ice velocity if (distance > 0) { ice.velocityX = directionX / distance * 8; ice.velocityY = directionY / distance * 8; } else { ice.velocityX = 8; ice.velocityY = 0; } ices.push(ice); game.addChild(ice); return; // Don't flap when throwing ice } } if (!gameStarted) { startGame(); return; } // Start tracking press for long press detection isPressing = true; pressStartTime = Date.now(); }; game.up = function (x, y, obj) { if (!gameStarted) return; // Calculate press duration var pressDuration = Date.now() - pressStartTime; isPressing = false; // If it was a short press (less than threshold), perform a flap if (pressDuration < longPressThreshold) { bird.flap(); } }; game.update = function () { if (!gameStarted) return; // Create obstacles if (LK.ticks - lastObstacle > obstacleSpacing) { createObstacle(); } // Create background shapes if (LK.ticks - lastBackgroundShape > backgroundShapeSpacing) { createBackgroundShape(); lastBackgroundShape = LK.ticks; } // Spikes are now created after obstacles, no random creation needed // Hearts are now created after each obstacle, so no timer-based spawning needed // Update bird physics bird.update(); // Update obstacles for (var i = 0; i < obstacles.length; i++) { obstacles[i].update(); } // Update hearts for (var h = 0; h < hearts.length; h++) { hearts[h].update(); } // Update blocks for (var bl = 0; bl < blocks.length; bl++) { blocks[bl].update(); } // Update portals for (var p = 0; p < portals.length; p++) { portals[p].update(); } // Update spikes for (var s = 0; s < spikes.length; s++) { spikes[s].update(); } // Update bombs for (var b = 0; b < bombs.length; b++) { bombs[b].update(); } // Update lasers for (var l = 0; l < lasers.length; l++) { lasers[l].update(); } // Update characters for (var c = 0; c < characters.length; c++) { if (characters[c]) { characters[c].update(); } } // Update fires for (var f = 0; f < fires.length; f++) { if (fires[f]) { fires[f].update(); } } // Update ice projectiles for (var ic = ices.length - 1; ic >= 0; ic--) { var ice = ices[ic]; if (ice) { ice.update(); // Remove off-screen ice if (ice.x > 2300 || ice.y < 0 || ice.y > 2732) { ice.destroy(); ices.splice(ic, 1); continue; } // Check ice-fire collision for (var f = fires.length - 1; f >= 0; f--) { var fire = fires[f]; if (fire && ice.intersects(fire) && !ice.collected && !fire.collected) { ice.collected = true; fire.collected = true; // Increment score by 1 when destroying fire LK.setScore(LK.getScore() + 1); storage.levelScore = LK.getScore(); // Save to storage scoreTxt.setText(LK.getScore()); updateLevelProgress(); // Increment destroyed fires counter destroyedFiresCount++; destroyedFiresTxt.setText('Yok Edilen Ateş: ' + destroyedFiresCount); // Destroy both ice and fire tween(ice, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 300, onFinish: function onFinish() { ice.destroy(); } }); tween(fire, { scaleX: 0.1, scaleY: 0.1, alpha: 0 }, { duration: 300, onFinish: function onFinish() { fire.destroy(); } }); // Flash screen white briefly LK.effects.flashScreen(0xffffff, 200); // Play score sound LK.getSound('score').play(); // Remove from arrays ices.splice(ic, 1); fires.splice(f, 1); break; } } } } // Update background shapes for (var j = backgroundShapes.length - 1; j >= 0; j--) { var bgShape = backgroundShapes[j]; bgShape.update(); // Remove off-screen background shapes if (bgShape.x < -200) { bgShape.destroy(); backgroundShapes.splice(j, 1); } } // Check collisions checkCollisions(); // Check individual obstacle passing for score increment for (var i = 0; i < obstacles.length; i++) { var obstacle = obstacles[i]; // Check if bird passed obstacle and hasn't scored from it yet if (!obstacle.passed && !obstacle.scoredFrom && obstacle.x + 100 < bird.x) { obstacle.passed = true; obstacle.scoredFrom = true; // Mark as scored to prevent duplicate scoring LK.setScore(LK.getScore() + 1); storage.levelScore = LK.getScore(); // Save to storage scoreTxt.setText(LK.getScore()); LK.getSound('score').play(); updateLevelProgress(); } } // Create portal when score reaches level threshold (10 + (level-1)*10) var currentLevelThreshold = levelScoreThreshold + (currentLevel - 1) * 10; if (LK.getScore() >= currentLevelThreshold && !portalSpawned) { var portal = new Portal(); portal.x = 2200; // Start off-screen right portal.y = 1366; // Center of screen vertically portals.push(portal); game.addChild(portal); // Hide all existing obstacles when portal is created for (var hideIndex = 0; hideIndex < obstacles.length; hideIndex++) { obstacles[hideIndex].visible = false; } // Hide all hearts when portal is created for (var heartHideIndex = 0; heartHideIndex < hearts.length; heartHideIndex++) { hearts[heartHideIndex].visible = false; } // Hide all blocks when portal is created for (var blockHideIndex = 0; blockHideIndex < blocks.length; blockHideIndex++) { blocks[blockHideIndex].visible = false; } // Hide all spikes when portal is created for (var spikeHideIndex = 0; spikeHideIndex < spikes.length; spikeHideIndex++) { spikes[spikeHideIndex].visible = false; } // Hide all bombs when portal is created for (var bombHideIndex = 0; bombHideIndex < bombs.length; bombHideIndex++) { bombs[bombHideIndex].visible = false; } // Hide all lasers when portal is created for (var laserHideIndex = 0; laserHideIndex < lasers.length; laserHideIndex++) { lasers[laserHideIndex].visible = false; } // Hide all characters when portal is created for (var characterHideIndex = 0; characterHideIndex < characters.length; characterHideIndex++) { characters[characterHideIndex].visible = false; } // Hide all fires when portal is created for (var fireHideIndex = 0; fireHideIndex < fires.length; fireHideIndex++) { fires[fireHideIndex].visible = false; } // Hide all ice projectiles when portal is created for (var iceHideIndex = 0; iceHideIndex < ices.length; iceHideIndex++) { ices[iceHideIndex].visible = false; } portalSpawned = true; } // No time-based score increment - score only from obstacles // Level-based difficulty progression var baseSpacing = 400 - (currentLevel - 1) * 20; var minSpacing = Math.max(200, 300 - (currentLevel - 1) * 10); var reductionRate = 1 + currentLevel; // Increase reduction rate with level var currentSpacing = baseSpacing - LK.getScore() * reductionRate; obstacleSpacing = Math.max(minSpacing, currentSpacing); }; function showContinueButton() { // Continue button functionality removed } function showDeathReason(reason) { lastDeathReason = reason; deathReasonTxt.setText(reason); deathReasonTxt.visible = true; deathReasonTxt.alpha = 1; deathReasonTxt.scaleX = 2; deathReasonTxt.scaleY = 2; // Animate the death reason text tween(deathReasonTxt, { scaleX: 1.0, scaleY: 1.0 }, { duration: 300, onFinish: function onFinish() { tween(deathReasonTxt, { alpha: 0 }, { duration: 2000, onFinish: function onFinish() { deathReasonTxt.visible = false; } }); } }); } function showGameOverWithLevelButton() { // Standard game over resetToLevelStart(); LK.showGameOver(); } ; // Track mouse position for cursor detection game.move = function (x, y, obj) { game.mouseX = x; game.mouseY = y; };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
currentLevel: 1,
unlockedLevels: 1,
totalScore: 0,
levelScore: 0,
mouseTrackingEnabled: true,
fireToggleEnabled: true,
checkpointEnabled: true,
longPressEnabled: true
});
/****
* Classes
****/
var BackgroundShape = Container.expand(function () {
var self = Container.call(this);
var shapeTypes = ['bgCircle', 'bgSquare', 'bgTriangle', 'bgPentagon', 'bgHexagon', 'bgHeptagon', 'bgOctagon'];
var randomType = shapeTypes[Math.floor(Math.random() * shapeTypes.length)];
var shapeGraphics = self.attachAsset(randomType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -1 - Math.random() * 2; // Random speed between -1 and -3
self.rotationSpeed = (Math.random() - 0.5) * 0.02; // Random rotation
self.pulseScale = 1;
self.pulseDirection = 1;
self.alpha = 0.3 + Math.random() * 0.4; // Random transparency between 0.3-0.7
shapeGraphics.alpha = self.alpha;
self.update = function () {
self.x += self.speed;
// Add rotation
shapeGraphics.rotation += self.rotationSpeed;
// Add subtle pulsing
self.pulseScale += 0.003 * self.pulseDirection;
if (self.pulseScale > 1.1) self.pulseDirection = -1;
if (self.pulseScale < 0.9) self.pulseDirection = 1;
shapeGraphics.scaleX = self.pulseScale;
shapeGraphics.scaleY = self.pulseScale;
};
return self;
});
var Bird = Container.expand(function () {
var self = Container.call(this);
var birdGraphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
// Ensure bird is visible
birdGraphics.alpha = 1.0;
birdGraphics.visible = true;
self.velocityY = 0;
self.gravity = 0.8;
self.flapPower = -12;
self.rotation = 0;
self.rotationVelocity = 0;
self.isFlipping = false;
self.completedFlips = 0;
self.lastUpright = true;
self.flap = function () {
self.velocityY = self.flapPower;
LK.getSound('flap').play();
// No score bonus for flapping - score only from obstacles
};
self.update = function () {
// Check for long press - apply continuous upward force only if enabled
if (longPressEnabled && isPressing && gameStarted) {
var pressDuration = Date.now() - pressStartTime;
if (pressDuration >= longPressThreshold) {
// Apply strong upward force for long press
self.velocityY = -15; // Strong upward velocity
}
}
// Make bird follow mouse cursor when mouse position is available and tracking is enabled
if (mouseTrackingEnabled && game.mouseX !== undefined && game.mouseY !== undefined) {
// Calculate direction towards cursor
var directionX = game.mouseX - self.x;
var directionY = game.mouseY - self.y;
var distance = Math.sqrt(directionX * directionX + directionY * directionY);
// Move bird towards cursor with smooth following
if (distance > 5) {
// Only move if not too close to avoid jittering
var followSpeed = 4; // Speed of following
var normalX = directionX / distance;
var normalY = directionY / distance;
self.x += normalX * followSpeed;
self.y += normalY * followSpeed;
self.velocityY = 0; // Reset gravity when following cursor
} else {
// When very close to cursor, stop moving to avoid jittering
self.velocityY = 0;
}
} else {
// Normal bird physics when mouse tracking disabled or no mouse position available
self.velocityY += self.gravity;
self.y += self.velocityY;
}
// Keep bird in bounds horizontally
if (self.x < 40) self.x = 40;
if (self.x > 2008) self.x = 2008;
// Keep bird in bounds vertically
if (self.y < 40) self.y = 40;
if (self.y > 2600) self.y = 2600;
};
self.isUpright = function () {
var normalizedRotation = self.rotation % (Math.PI * 2);
return normalizedRotation < 0.3 || normalizedRotation > Math.PI * 2 - 0.3;
};
return self;
});
var Block = Container.expand(function () {
var self = Container.call(this);
var blockGraphics = self.attachAsset('checkpointblou1', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.speed = -3;
self.collected = false;
self.pulseScale = 1;
self.pulseDirection = 1;
self.rotationSpeed = 0.02;
// Add pulsing animation only (no rotation)
self.update = function () {
self.x += self.speed;
// Pulsing effect
self.pulseScale += 0.008 * self.pulseDirection;
if (self.pulseScale > 1.15) self.pulseDirection = -1;
if (self.pulseScale < 0.85) self.pulseDirection = 1;
blockGraphics.scaleX = self.pulseScale * 1.5;
blockGraphics.scaleY = self.pulseScale * 1.5;
// Rotation effect removed
};
return self;
});
var Bomb = Container.expand(function () {
var self = Container.call(this);
var bombGraphics = self.attachAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -2;
self.passed = false;
self.collected = false;
self.isBomb = true;
self.pulseScale = 1;
self.pulseDirection = 1;
self.rotationSpeed = 0.05;
self.update = function () {
self.x += self.speed;
// Pulsing effect for bombs
self.pulseScale += 0.015 * self.pulseDirection;
if (self.pulseScale > 1.3) self.pulseDirection = -1;
if (self.pulseScale < 0.8) self.pulseDirection = 1;
bombGraphics.scaleX = self.pulseScale;
bombGraphics.scaleY = self.pulseScale;
};
return self;
});
var Character = Container.expand(function () {
var self = Container.call(this);
var characterGraphics = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -1.5;
self.passed = false;
self.collected = false;
self.isCharacter = true;
self.isDead = false;
self.pulseScale = 1;
self.pulseDirection = 1;
// Character visual effects
characterGraphics.tint = 0x00FF00; // Green color to distinguish from other elements
self.update = function () {
if (!self.isDead) {
self.x += self.speed;
// Pulsing effect for character
self.pulseScale += 0.008 * self.pulseDirection;
if (self.pulseScale > 1.1) self.pulseDirection = -1;
if (self.pulseScale < 0.9) self.pulseDirection = 1;
characterGraphics.scaleX = self.pulseScale;
characterGraphics.scaleY = self.pulseScale;
}
};
return self;
});
var Fire = Container.expand(function () {
var self = Container.call(this);
var fireGraphics = self.attachAsset('fire', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -2.5;
self.passed = false;
self.collected = false;
self.isFire = true;
self.pulseScale = 1;
self.pulseDirection = 1;
self.rotationSpeed = 0.03;
self.flickerIntensity = 0;
// Fire visual effects - orange/red color with flickering
fireGraphics.tint = 0xff4400;
self.update = function () {
self.x += self.speed;
// Intense pulsing effect for fire
self.pulseScale += 0.02 * self.pulseDirection;
if (self.pulseScale > 1.4) self.pulseDirection = -1;
if (self.pulseScale < 0.7) self.pulseDirection = 1;
fireGraphics.scaleX = self.pulseScale;
fireGraphics.scaleY = self.pulseScale;
// Fire rotation removed - fire no longer rotates
// Flickering effect by changing tint between orange and red
self.flickerIntensity += 0.1;
var flicker = Math.sin(self.flickerIntensity);
if (flicker > 0) {
fireGraphics.tint = 0xff6600; // Brighter orange
} else {
fireGraphics.tint = 0xff2200; // Darker red
}
};
return self;
});
var Heart = Container.expand(function () {
var self = Container.call(this);
var heartGraphics = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
self.speed = -3;
self.collected = false;
self.pulseScale = 1;
self.pulseDirection = 1;
self.floatOffset = 0;
// Add pulsing and floating animation
self.update = function () {
self.x += self.speed;
// Pulsing effect
self.pulseScale += 0.01 * self.pulseDirection;
if (self.pulseScale > 1.2) self.pulseDirection = -1;
if (self.pulseScale < 0.8) self.pulseDirection = 1;
heartGraphics.scaleX = self.pulseScale;
heartGraphics.scaleY = self.pulseScale;
// Floating effect
self.floatOffset += 0.05;
heartGraphics.y = Math.sin(self.floatOffset) * 10;
};
return self;
});
var Ice = Container.expand(function () {
var self = Container.call(this);
var iceGraphics = self.attachAsset('ice', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 8; // Horizontal velocity
self.velocityY = 0;
self.isIce = true;
self.collected = false;
// Ice visual effects - light blue color
iceGraphics.tint = 0x87ceeb;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
// Add slight rotation for visual effect
iceGraphics.rotation += 0.1;
};
return self;
});
var Laser = Container.expand(function () {
var self = Container.call(this);
var laserGraphics = self.attachAsset('laser', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -24;
self.passed = false;
self.collected = false;
self.isLaser = true;
self.pulseScale = 1;
self.pulseDirection = 1;
self.horizontalSpeed = 6;
self.horizontalDirection = 1;
self.maxHorizontalRange = 300;
self.startX = 0;
// Laser visual effects - bright red pulsing
laserGraphics.tint = 0xff0000;
self.update = function () {
self.x -= self.speed; // Changed to move in opposite direction (positive X, away from bird)
// Horizontal oscillation movement
self.x += self.horizontalSpeed * self.horizontalDirection;
// Reverse direction if reached maximum range
if (Math.abs(self.x - self.startX) > self.maxHorizontalRange) {
self.horizontalDirection *= -1;
}
// Intense pulsing effect for laser
self.pulseScale += 0.02 * self.pulseDirection;
if (self.pulseScale > 1.4) self.pulseDirection = -1;
if (self.pulseScale < 0.7) self.pulseDirection = 1;
laserGraphics.scaleX = self.pulseScale;
laserGraphics.scaleY = self.pulseScale;
// Add rotation for visual effect
laserGraphics.rotation += 0.03;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
// Choose obstacle type from level-specific sequence
var randomType = 'block'; // Default fallback
if (levelObstacleTypes.length > 0) {
var typeIndex = obstacleCounter % levelObstacleTypes.length;
randomType = levelObstacleTypes[typeIndex];
}
var obstacleGraphics = self.attachAsset(randomType, {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -3;
self.passed = false;
self.obstacleType = randomType;
// Add visual effects for Geometry Dash style
self.pulseScale = 1;
self.pulseDirection = 1;
self.rotationSpeed = 0;
self.isStationary = false;
// Set rotation speed for certain types
if (randomType === 'spike' || randomType === 'block') {
self.rotationSpeed = 0.02;
}
// Set rest platform specific properties
if (randomType === 'restPlatform') {
self.speed = 0; // Rest platforms don't move horizontally
self.isStationary = true;
self.isSafe = true; // Mark as safe platform
}
// Set door specific properties
if (randomType === 'door') {
self.speed = -1; // Doors move slower
self.isDoor = true; // Mark as door for special collision handling
self.pulseScale = 1.1; // Start with larger pulse for visibility
}
self.update = function () {
// Only move if not stationary
if (!self.isStationary) {
self.x += self.speed;
}
// Add pulsing effect only for non-rest platform obstacles
if (self.obstacleType !== 'restPlatform') {
self.pulseScale += 0.005 * self.pulseDirection;
if (self.pulseScale > 1.05) self.pulseDirection = -1;
if (self.pulseScale < 0.98) self.pulseDirection = 1;
obstacleGraphics.scaleX = self.pulseScale;
obstacleGraphics.scaleY = self.pulseScale;
}
// Add rotation for certain obstacles
if (self.rotationSpeed > 0) {
obstacleGraphics.rotation += self.rotationSpeed;
}
};
return self;
});
var Portal = Container.expand(function () {
var self = Container.call(this);
var portalGraphics = self.attachAsset('door', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.speed = -2;
self.passed = false;
self.isPortal = true;
self.pulseScale = 1;
self.pulseDirection = 1;
self.rotationSpeed = 0.01;
// Portal specific visual effects
portalGraphics.tint = 0x9966ff; // Purple tint for portal
self.update = function () {
self.x += self.speed;
// Enhanced pulsing effect for portal
self.pulseScale += 0.008 * self.pulseDirection;
if (self.pulseScale > 1.3) self.pulseDirection = -1;
if (self.pulseScale < 0.8) self.pulseDirection = 1;
portalGraphics.scaleX = self.pulseScale * 1.5;
portalGraphics.scaleY = self.pulseScale * 1.5;
// Portal rotation removed - portal no longer spins
};
return self;
});
var Spike = Container.expand(function () {
var self = Container.call(this);
var spikeGraphics = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -2;
self.passed = false;
self.collected = false;
self.isSpike = true;
self.pulseScale = 1;
self.pulseDirection = 1;
self.rotationSpeed = 0;
// Spike visual effects - look like hearts (no tint)
self.update = function () {
self.x += self.speed;
// Pulsing effect for spikes
self.pulseScale += 0.01 * self.pulseDirection;
if (self.pulseScale > 1.15) self.pulseDirection = -1;
if (self.pulseScale < 0.9) self.pulseDirection = 1;
spikeGraphics.scaleX = self.pulseScale;
spikeGraphics.scaleY = self.pulseScale;
// No rotation for spikes
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
var bird;
var obstacles = [];
var hearts = [];
var blocks = [];
var backgroundShapes = [];
var portals = [];
var spikes = [];
var bombs = [];
var lasers = [];
var characters = [];
var fires = [];
var ices = [];
var ground;
var gameStarted = false;
var lastObstacle = 0;
var obstacleSpacing = 400;
var currentLevel = 1;
var unlockedLevels = 999; // All levels unlocked for everyone
var totalScore = 0;
var levelScoreThreshold = 10; // Base score needed to unlock next level
// Load persistent scores from storage
totalScore = storage.totalScore || 0;
var levelScore = storage.levelScore || 0;
LK.setScore(levelScore);
var obstacleCounter = 0; // Counter for obstacle generation
var levelObstacleTypes = []; // Array to store shuffled obstacle types for current level
var playerHealth = 3; // Player starts with 3 lives
var lastBackgroundShape = 0;
var backgroundShapeSpacing = 400; // Spacing between background shapes - increased for more space between shapes
var missedHearts = 0; // Track how many hearts were missed
var missedBlocks = 0; // Track how many blocks were missed
var missedCheckpointBlocks = 0; // Track how many checkpointblou1 blocks were missed
var checkpointCounter = 0; // Track collected checkpoint blocks
var totalCollectedBackupLives = 0; // Track total backup lives collected across the game
var lastCheckpointX = 300; // Last checkpoint X position
var lastCheckpointY = 800; // Last checkpoint Y position
var portalSpawned = false; // Track if portal has been spawned for current level
var currentObstacleArrayPassed = false; // Track if current obstacle array has been passed
var lastObstacleArrayX = 0; // Track the X position of the last obstacle array
// Death music is already implemented in the following scenarios:
// 1. Ground collision - line 43: LK.getSound('death').play();
// 2. Spike collision - line 5F: LK.getSound('death').play();
// 3. Bomb collision when health is 1 - line 5S: LK.getSound('death').play();
// 4. When health reaches 0 in takeDamage - line 36: LK.getSound('death').play();
LK.setScore(0);
// Create score display
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 100;
// Reset storage values to initial state - make all levels unlocked for everyone
storage.currentLevel = 1;
storage.unlockedLevels = 999; // Unlock all levels for everyone
storage.totalScore = 0;
// Create level display
var levelTxt = new Text2('Seviye ' + currentLevel, {
size: 70,
fill: 0xFFD700
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 180;
// Create level progress display
var progressTxt = new Text2('İlerleme: 0/' + levelScoreThreshold, {
size: 40,
fill: 0xFFFFFF
});
progressTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(progressTxt);
progressTxt.y = 280;
// Create health display
var healthTxt = new Text2('Can: ' + playerHealth, {
size: 50,
fill: 0xff0000
});
healthTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(healthTxt);
healthTxt.y = 340;
// Create checkpoint counter display
var checkpointTxt = new Text2('Yedek Can: 0', {
size: 50,
fill: 0x00FFFF
});
checkpointTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(checkpointTxt);
checkpointTxt.y = 400;
// Set initial visibility based on loaded checkpoint setting
checkpointTxt.visible = checkpointEnabled;
// Create additional checkpoint counter in a more prominent position
var checkpointCounterTxt = new Text2('Yedek Can: 0', {
size: 60,
fill: 0x00FFFF
});
checkpointCounterTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(checkpointCounterTxt);
checkpointCounterTxt.x = 120; // Position away from menu icon
checkpointCounterTxt.y = 20;
// Set initial visibility based on loaded checkpoint setting
checkpointCounterTxt.visible = checkpointEnabled;
// Create backup lives counter display in prominent position
var backupLivesTxt = new Text2('Yedek Can: 0', {
size: 70,
fill: 0x00FFFF
});
backupLivesTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(backupLivesTxt);
backupLivesTxt.y = 460;
// Set initial visibility based on checkpoint setting
backupLivesTxt.visible = checkpointEnabled;
// Create main backup lives counter display
var mainBackupLivesTxt = new Text2('Yedek Can: 0', {
size: 80,
fill: 0x00FFFF
});
mainBackupLivesTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(mainBackupLivesTxt);
mainBackupLivesTxt.x = 120; // Position away from menu icon
mainBackupLivesTxt.y = 100;
// Set initial visibility based on checkpoint setting
mainBackupLivesTxt.visible = checkpointEnabled;
// Create missed checkpoint blocks counter display
var missedCheckpointTxt = new Text2('Kaçırılan Yedek Can: 0', {
size: 60,
fill: 0xff0066
});
missedCheckpointTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(missedCheckpointTxt);
missedCheckpointTxt.y = 540;
// Set initial visibility based on checkpoint setting
missedCheckpointTxt.visible = checkpointEnabled;
// Create backup lives collected counter display
var collectedBackupLivesTxt = new Text2('Toplanan Yedek Can: 0', {
size: 60,
fill: 0x00ff00
});
collectedBackupLivesTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(collectedBackupLivesTxt);
collectedBackupLivesTxt.y = 600;
// Set initial visibility based on checkpoint setting
collectedBackupLivesTxt.visible = checkpointEnabled;
// Create destroyed fires counter display
var destroyedFiresTxt = new Text2('Yok Edilen Ateş: 0', {
size: 50,
fill: 0xff6600
});
destroyedFiresTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(destroyedFiresTxt);
destroyedFiresTxt.y = 520;
// Set initial visibility based on fire toggle setting
destroyedFiresTxt.visible = fireToggleEnabled;
// Initialize destroyed fires counter
var destroyedFiresCount = 0;
// Create death reason display
var deathReasonTxt = new Text2('', {
size: 150,
fill: 0x000000
});
deathReasonTxt.anchor.set(0.5, 0.5);
deathReasonTxt.visible = false;
game.addChild(deathReasonTxt);
deathReasonTxt.x = 1024;
deathReasonTxt.y = 1366;
// Death reason variable
var lastDeathReason = '';
var isPressing = false; // Track if user is currently pressing
var pressStartTime = 0; // Track when press started
var longPressThreshold = 150; // Milliseconds to consider a long press
// Load mouse tracking setting from storage and apply it
var mouseTrackingEnabled = storage.mouseTrackingEnabled;
var mouseTrackingBtn = new Text2(mouseTrackingEnabled ? 'Fare Takip: AÇIK' : 'Fare Takip: KAPALI', {
size: 60,
fill: 0x000000
});
mouseTrackingBtn.anchor.set(1, 0);
LK.gui.topRight.addChild(mouseTrackingBtn);
mouseTrackingBtn.x = -20;
mouseTrackingBtn.y = 100;
// Load fire toggle setting from storage and apply it
var fireToggleEnabled = storage.fireToggleEnabled;
var fireToggleBtn = new Text2(fireToggleEnabled ? 'Ateş: AÇIK' : 'Ateş: KAPALI', {
size: 60,
fill: 0x000000
});
fireToggleBtn.anchor.set(1, 0);
LK.gui.topRight.addChild(fireToggleBtn);
fireToggleBtn.x = -20;
fireToggleBtn.y = 180;
// Load checkpoint setting from storage and apply it
var checkpointEnabled = storage.checkpointEnabled;
// Create checkpoint toggle button with correct initial text based on loaded setting
var checkpointToggleBtn = new Text2(checkpointEnabled ? 'Yedek Can: AÇIK' : 'Yedek Can: KAPALI', {
size: 60,
fill: 0x000000
});
checkpointToggleBtn.anchor.set(1, 0);
LK.gui.topRight.addChild(checkpointToggleBtn);
checkpointToggleBtn.x = -20;
checkpointToggleBtn.y = 20;
// Load long press setting from storage
var longPressEnabled = storage.longPressEnabled;
// Create long press toggle button with correct initial text based on loaded setting
var longPressToggleBtn = new Text2(longPressEnabled ? 'Uzun Basma: AÇIK' : 'Uzun Basma: KAPALI', {
size: 60,
fill: 0x000000
});
longPressToggleBtn.anchor.set(1, 0);
LK.gui.topRight.addChild(longPressToggleBtn);
longPressToggleBtn.x = -20;
longPressToggleBtn.y = 260;
// Add touch event to mouse tracking toggle button
mouseTrackingBtn.down = function (x, y, obj) {
mouseTrackingEnabled = !mouseTrackingEnabled;
storage.mouseTrackingEnabled = mouseTrackingEnabled;
if (mouseTrackingEnabled) {
mouseTrackingBtn.setText('Fare Takip: AÇIK');
mouseTrackingBtn.fill = 0x000000; // Black
} else {
mouseTrackingBtn.setText('Fare Takip: KAPALI');
mouseTrackingBtn.fill = 0x000000; // Black
}
};
// Add touch event to toggle button
checkpointToggleBtn.down = function (x, y, obj) {
checkpointEnabled = !checkpointEnabled;
storage.checkpointEnabled = checkpointEnabled;
if (checkpointEnabled) {
checkpointToggleBtn.setText('Yedek Can: AÇIK');
checkpointToggleBtn.fill = 0x000000; // Black
checkpointTxt.visible = true; // Show checkpoint counter
checkpointCounterTxt.visible = true; // Show prominent checkpoint counter
backupLivesTxt.visible = true; // Show backup lives counter
mainBackupLivesTxt.visible = true; // Show main backup lives counter
missedCheckpointTxt.visible = true; // Show missed checkpoint counter
collectedBackupLivesTxt.visible = true; // Show collected backup lives counter
// Show all checkpoint blocks
for (var bl = 0; bl < blocks.length; bl++) {
if (blocks[bl]) {
blocks[bl].visible = true;
}
}
} else {
checkpointToggleBtn.setText('Yedek Can: KAPALI');
checkpointToggleBtn.fill = 0x000000; // Black
checkpointTxt.visible = false; // Hide checkpoint counter
checkpointCounterTxt.visible = false; // Hide prominent checkpoint counter
backupLivesTxt.visible = false; // Hide backup lives counter
mainBackupLivesTxt.visible = false; // Hide main backup lives counter
missedCheckpointTxt.visible = false; // Hide missed checkpoint counter
collectedBackupLivesTxt.visible = false; // Hide collected backup lives counter
// Hide all checkpoint blocks
for (var bl = 0; bl < blocks.length; bl++) {
if (blocks[bl]) {
blocks[bl].visible = false;
}
}
}
};
// Add touch event to fire toggle button
fireToggleBtn.down = function (x, y, obj) {
fireToggleEnabled = !fireToggleEnabled;
storage.fireToggleEnabled = fireToggleEnabled;
if (fireToggleEnabled) {
fireToggleBtn.setText('Ateş: AÇIK');
fireToggleBtn.fill = 0x000000; // Black
// Show all fires
for (var f = 0; f < fires.length; f++) {
if (fires[f]) {
fires[f].visible = true;
}
}
// Show destroyed fires counter when fire toggle is enabled
destroyedFiresTxt.visible = true;
} else {
fireToggleBtn.setText('Ateş: KAPALI');
fireToggleBtn.fill = 0x000000; // Black
// Hide all fires
for (var f = 0; f < fires.length; f++) {
if (fires[f]) {
fires[f].visible = false;
}
}
// Hide destroyed fires counter when fire toggle is disabled
destroyedFiresTxt.visible = false;
}
};
// Add touch event to long press toggle button
longPressToggleBtn.down = function (x, y, obj) {
longPressEnabled = !longPressEnabled;
storage.longPressEnabled = longPressEnabled;
if (longPressEnabled) {
longPressToggleBtn.setText('Uzun Basma: AÇIK');
longPressToggleBtn.fill = 0x000000; // Black
} else {
longPressToggleBtn.setText('Uzun Basma: KAPALI');
longPressToggleBtn.fill = 0x000000; // Black
}
};
// Create instructions
var instructionTxt = new Text2('DOKUN VE UÇ\nENGELLERDEN ZİPLA!', {
size: 60,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 0.5);
game.addChild(instructionTxt);
instructionTxt.x = 1024;
instructionTxt.y = 1000;
// Create ground
ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0
}));
ground.x = 0;
ground.y = 2632;
// Solid blue background (camera background removed)
game.setBackgroundColor(0x0066ff);
// Create bird
bird = game.addChild(new Bird());
bird.x = 300;
bird.y = 800;
// Generate initial obstacle sequence for current level
generateLevelObstacleSequence();
// Create initial obstacles at game start
createObstacle();
// Create initial background shapes
for (var i = 0; i < 15; i++) {
createBackgroundShape();
}
function generateLevelObstacleSequence() {
levelObstacleTypes = [];
var baseTypes = ['spike', 'block', 'tallBlock', 'platform', 'restPlatform', 'restPlatform', 'restPlatform', 'laser']; // Door obstacle removed completely
var sequenceLength = 50; // Generate enough types for a full level
var seed = 3726928364; // Fixed seed value
for (var i = 0; i < sequenceLength; i++) {
seed = (seed * 9301 + 49297) % 233280;
var randomIndex = Math.floor(seed / 233280 * baseTypes.length);
levelObstacleTypes.push(baseTypes[randomIndex]);
}
}
function updateLevelProgress() {
var levelProgress = LK.getScore();
var progressNeeded = levelScoreThreshold + (currentLevel - 1) * 10;
// Update progress display
progressTxt.setText('İlerleme: ' + levelProgress + '/' + progressNeeded);
}
function updateDifficultyForLevel() {
// Each level increases difficulty significantly
var difficultyMultiplier = 1 + (currentLevel - 1) * 0.4;
// Adjust obstacle spacing based on level - gets much tighter
obstacleSpacing = Math.max(150, 400 - (currentLevel - 1) * 30);
// Adjust bird physics progressively for higher levels
if (currentLevel > 2) {
bird.gravity = 0.8 + (currentLevel - 2) * 0.15; // Stronger gravity earlier
}
// Increase bird flap power requirement for higher levels
if (currentLevel > 3) {
bird.flapPower = Math.max(-18, -12 - (currentLevel - 3) * 1.5); // Stronger flap needed
}
// Adjust obstacle speed for higher levels
var obstacleSpeedMultiplier = 1 + (currentLevel - 1) * 0.2;
// Apply speed multiplier to all moving obstacles
for (var i = 0; i < obstacles.length; i++) {
if (obstacles[i] && !obstacles[i].isStationary) {
obstacles[i].speed = -3 * obstacleSpeedMultiplier;
}
}
for (var h = 0; h < hearts.length; h++) {
if (hearts[h]) {
hearts[h].speed = -3 * obstacleSpeedMultiplier;
}
}
for (var bl = 0; bl < blocks.length; bl++) {
if (blocks[bl]) {
blocks[bl].speed = -3 * obstacleSpeedMultiplier;
}
}
for (var s = 0; s < spikes.length; s++) {
if (spikes[s]) {
spikes[s].speed = -2 * obstacleSpeedMultiplier;
}
}
for (var b = 0; b < bombs.length; b++) {
if (bombs[b]) {
bombs[b].speed = -2 * obstacleSpeedMultiplier;
}
}
for (var l = 0; l < lasers.length; l++) {
if (lasers[l]) {
lasers[l].speed = -24 * obstacleSpeedMultiplier;
}
}
}
function clearAllGameObjects() {
// Clear all obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
obstacles.splice(i, 1);
}
// Clear all hearts
for (var h = hearts.length - 1; h >= 0; h--) {
hearts[h].destroy();
hearts.splice(h, 1);
}
// Clear all blocks
for (var bl = blocks.length - 1; bl >= 0; bl--) {
blocks[bl].destroy();
blocks.splice(bl, 1);
}
// Clear all portals
for (var p = portals.length - 1; p >= 0; p--) {
portals[p].destroy();
portals.splice(p, 1);
}
// Clear all spikes
for (var s = spikes.length - 1; s >= 0; s--) {
spikes[s].destroy();
spikes.splice(s, 1);
}
// Clear all bombs
for (var b = bombs.length - 1; b >= 0; b--) {
bombs[b].destroy();
bombs.splice(b, 1);
}
// Clear all lasers
for (var l = lasers.length - 1; l >= 0; l--) {
lasers[l].destroy();
lasers.splice(l, 1);
}
// Clear all characters
for (var c = characters.length - 1; c >= 0; c--) {
characters[c].destroy();
characters.splice(c, 1);
}
// Clear all fires
for (var f = fires.length - 1; f >= 0; f--) {
fires[f].destroy();
fires.splice(f, 1);
}
// Clear all ice projectiles
for (var ic = ices.length - 1; ic >= 0; ic--) {
ices[ic].destroy();
ices.splice(ic, 1);
}
// Clear all background shapes
for (var bg = backgroundShapes.length - 1; bg >= 0; bg--) {
backgroundShapes[bg].destroy();
backgroundShapes.splice(bg, 1);
}
// Reset counters
obstacleCounter = 0;
missedHearts = 0;
missedBlocks = 0;
checkpointCounter = 0;
portalSpawned = false;
currentObstacleArrayPassed = false;
lastObstacleArrayX = 0;
}
function resetToLevelStart() {
// Reset to level 1 when game over occurs
currentLevel = 1;
storage.currentLevel = 1;
levelTxt.setText('Seviye ' + currentLevel);
// Reset score to level start
LK.setScore(0);
scoreTxt.setText(0);
// Reset health
playerHealth = 3;
healthTxt.setText('Can: ' + playerHealth);
// Update checkpoint counter display
checkpointTxt.setText('Yedek Can: ' + checkpointCounter);
checkpointCounterTxt.setText('Yedek Can: ' + checkpointCounter);
// Restart music when game resets
LK.playMusic('hfu2');
// Clear all obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
obstacles.splice(i, 1);
}
// Clear all background shapes
for (var j = backgroundShapes.length - 1; j >= 0; j--) {
backgroundShapes[j].destroy();
backgroundShapes.splice(j, 1);
}
// Clear all hearts
for (var k = hearts.length - 1; k >= 0; k--) {
hearts[k].destroy();
hearts.splice(k, 1);
}
// Clear all blocks
for (var bl = blocks.length - 1; bl >= 0; bl--) {
blocks[bl].destroy();
blocks.splice(bl, 1);
}
// Clear all portals
for (var p = portals.length - 1; p >= 0; p--) {
portals[p].destroy();
portals.splice(p, 1);
}
// Clear all spikes
for (var s = spikes.length - 1; s >= 0; s--) {
spikes[s].destroy();
spikes.splice(s, 1);
}
// Clear all bombs
for (var b = bombs.length - 1; b >= 0; b--) {
bombs[b].destroy();
bombs.splice(b, 1);
}
// Clear all lasers
for (var l = lasers.length - 1; l >= 0; l--) {
lasers[l].destroy();
lasers.splice(l, 1);
}
// Clear all characters
for (var ch = characters.length - 1; ch >= 0; ch--) {
characters[ch].destroy();
characters.splice(ch, 1);
}
// Clear all fires
for (var fi = fires.length - 1; fi >= 0; fi--) {
fires[fi].destroy();
fires.splice(fi, 1);
}
// Clear all ice projectiles
for (var ic = ices.length - 1; ic >= 0; ic--) {
ices[ic].destroy();
ices.splice(ic, 1);
}
// Reset obstacle counter
obstacleCounter = 0;
// Reset missed hearts counter
missedHearts = 0;
// Reset missed blocks counter
missedBlocks = 0;
// Reset missed checkpoint blocks counter
missedCheckpointBlocks = 0;
missedCheckpointTxt.setText('Kaçırılan Yedek Can: ' + missedCheckpointBlocks);
// Reset checkpoint counter
checkpointCounter = 0;
// Update checkpoint counter displays
checkpointTxt.setText('Yedek Can: ' + checkpointCounter);
checkpointCounterTxt.setText('Yedek Can: ' + checkpointCounter);
backupLivesTxt.setText('Yedek Can: ' + checkpointCounter);
mainBackupLivesTxt.setText('Yedek Can: ' + checkpointCounter);
// Reset destroyed fires counter
destroyedFiresCount = 0;
destroyedFiresTxt.setText('Yok Edilen Ateş: ' + destroyedFiresCount);
// Reset total collected backup lives counter
totalCollectedBackupLives = 0;
collectedBackupLivesTxt.setText('Toplanan Yedek Can: ' + totalCollectedBackupLives);
// Reset portal spawned flag
portalSpawned = false;
// Reset obstacle array tracking
currentObstacleArrayPassed = false;
lastObstacleArrayX = 0;
// Reset checkpoint position to start
lastCheckpointX = 300;
lastCheckpointY = 800;
// Reset bird position
bird.x = 300;
bird.y = 800;
bird.velocityY = 0;
bird.completedFlips = 0;
// Regenerate obstacle sequence for current level
generateLevelObstacleSequence();
// Update displays
updateLevelProgress();
// Update difficulty for level 1
updateDifficultyForLevel();
// Create initial obstacle
createObstacle();
}
function takeDamage() {
// Check if we have checkpoints available and checkpoint system is enabled
if (checkpointEnabled && checkpointCounter > 0) {
// Use checkpoint instead of losing health
checkpointCounter--;
checkpointTxt.setText('Yedek Can: ' + checkpointCounter);
checkpointCounterTxt.setText('Yedek Can: ' + checkpointCounter);
backupLivesTxt.setText('Yedek Can: ' + checkpointCounter);
mainBackupLivesTxt.setText('Yedek Can: ' + checkpointCounter);
// Reset bird to last checkpoint position
bird.x = lastCheckpointX;
bird.y = lastCheckpointY;
bird.velocityY = 0;
// Flash screen yellow to indicate checkpoint usage
tween(game, {
tint: 0xffff44
}, {
duration: 200,
onFinish: function onFinish() {
tween(game, {
tint: 0xffffff
}, {
duration: 200
});
}
});
// Play death music
LK.getSound('death').play();
// Play death sound
LK.getSound('deathSound').play();
return; // Don't lose health, checkpoint consumed instead
} else {
// No checkpoints available, lose health normally
playerHealth--;
healthTxt.setText('Can: ' + playerHealth);
// Play warning sound when health decreases
LK.getSound('healthWarning').play();
// Flash screen red when taking damage
tween(game, {
tint: 0xff4444
}, {
duration: 200,
onFinish: function onFinish() {
tween(game, {
tint: 0xffffff
}, {
duration: 200
});
}
});
// Check if game over
if (playerHealth <= 0) {
showDeathReason('CANINIZ BİTTİ!');
// Show standard game over when no checkpoints available
resetToLevelStart();
LK.showGameOver();
return;
}
}
}
function resetHealth() {
playerHealth = 3;
healthTxt.setText('Can: ' + playerHealth);
}
function startGame() {
if (!gameStarted) {
gameStarted = true;
game.removeChild(instructionTxt);
// Start playing music when game begins - restart music for new game
LK.playMusic('hfu2');
// Reset obstacle counter for consistent level maps
obstacleCounter = 0;
// Generate obstacle sequence for current level
generateLevelObstacleSequence();
resetHealth(); // Reset health when starting game
updateDifficultyForLevel();
updateLevelProgress();
}
}
function createBackgroundShape() {
var bgShape = new BackgroundShape();
bgShape.x = 2200 + Math.random() * 200; // Start off-screen right
bgShape.y = 200 + Math.random() * 2300; // Random Y position
// Scale background shapes to 3 times their original size
bgShape.scaleX = 3;
bgShape.scaleY = 3;
// Check distance from existing background shapes to ensure spacing
var minDistance = 400; // Minimum distance between shapes
var validPosition = true;
for (var i = 0; i < backgroundShapes.length; i++) {
var existingShape = backgroundShapes[i];
var distanceX = bgShape.x - existingShape.x;
var distanceY = bgShape.y - existingShape.y;
var distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
if (distance < minDistance) {
validPosition = false;
break;
}
}
// Only add the shape if it has enough spacing
if (validPosition) {
backgroundShapes.push(bgShape);
game.addChild(bgShape);
} else {
// Destroy the shape if position is invalid
bgShape.destroy();
}
}
function createHeart() {
var heart = new Heart();
heart.x = 2200; // Start off-screen right
heart.y = bird.y - 400 + Math.random() * 800; // Random Y position around bird's flight path
hearts.push(heart);
game.addChild(heart);
}
function createSpike() {
// Use seed based on current level and time for randomness
var spikeSeed = (currentLevel * 7777 + LK.ticks + Date.now()) % 99991;
var spikeRandom = (spikeSeed * 9301 + 49297) % 233280 / 233280;
// Only create spike if random chance is met (roughly 15% chance increased by 50x to 100%)
if (spikeRandom < 1.0) {
var spike = new Spike();
spike.x = 2200 + Math.random() * 100; // Start off-screen right
spike.y = 300 + spikeRandom * 2000; // Random Y position
spikes.push(spike);
game.addChild(spike);
}
}
function createObstacle() {
// Create walls that cover full screen with a gap for the bird
var baseX = 2148;
var gapSize = 600; // Size of the gap for bird to pass through
// Progressive gap size reduction per level for increased difficulty
if (currentLevel === 1) {
gapSize = 650; // Easier start for level 1
} else if (currentLevel === 2) {
gapSize = 580; // Slightly smaller for level 2
} else if (currentLevel === 3) {
gapSize = 520; // Even smaller for level 3
} else if (currentLevel >= 4) {
// Much more challenging gaps for level 4+
var baseLevelGap = Math.max(350, 500 - (currentLevel - 4) * 25); // Starts at 500, reduces by 25 per level, minimum 350
var obstacleReduction = Math.max(0, obstacleCounter * 3); // Reduce by 3 per obstacle within level
gapSize = Math.max(300, baseLevelGap - obstacleReduction); // Minimum gap of 300
}
// Use seeded random based on current level and obstacle counter only
var seed = (currentLevel * 1000 + obstacleCounter) % 9973; // Use prime number for better distribution
var seededRandom = (seed * 9301 + 49297) % 233280 / 233280; // Linear congruential generator
var gapPosition = seededRandom * (2200 - gapSize) + 300; // Seeded gap position between 300-2200
var obstacleHeight = 320; // Height of each obstacle segment (reduced from 400)
// Reduce obstacle height for Level 4 to create more segments and fill gaps
if (currentLevel >= 4) {
obstacleHeight = 240; // Smaller segments create more obstacles (reduced from 300)
}
var numSegments = Math.ceil(2732 / obstacleHeight); // Number of segments to cover full height
for (var i = 0; i < numSegments; i++) {
var segmentY = i * obstacleHeight + obstacleHeight / 2;
// Skip creating obstacles in the gap area
if (segmentY + obstacleHeight / 2 > gapPosition && segmentY - obstacleHeight / 2 < gapPosition + gapSize) {
continue;
}
var obstacle = new Obstacle();
obstacle.x = baseX;
obstacle.y = segmentY;
obstacles.push(obstacle);
game.addChild(obstacle);
}
// Add extra obstacles to fill empty spaces - more for higher levels
var extraObstacles = Math.min(15, 4 + currentLevel + Math.floor(seededRandom * (2 + currentLevel))); // Scales with level: 5-7 for level 1, up to 15 for high levels
for (var j = 0; j < extraObstacles; j++) {
var extraSeed = (seed + j * 777) % 9973;
var extraRandom = (extraSeed * 9301 + 49297) % 233280 / 233280;
var obstacleX = baseX + 100 + extraRandom * (400 + currentLevel * 50); // Wider spread for higher levels
var obstacleY = 150 + extraRandom * 2300; // Cover more vertical space
// Make sure it's not in the main gap area - tighter constraints for higher levels
var gapBuffer = Math.max(30, 80 - currentLevel * 5); // Smaller buffer for higher levels
if (obstacleY < gapPosition - gapBuffer || obstacleY > gapPosition + gapSize + gapBuffer) {
var extraObstacle = new Obstacle();
extraObstacle.x = obstacleX;
extraObstacle.y = obstacleY;
obstacles.push(extraObstacle);
game.addChild(extraObstacle);
}
}
// Add obstacles in the middle area - much more for higher levels
var middleObstacles = Math.min(12, 3 + currentLevel * 2 + Math.floor(seededRandom * currentLevel)); // Scales dramatically: 4-6 for level 1, up to 12 for high levels
for (var m = 0; m < middleObstacles; m++) {
var middleSeed = (seed + m * 333 + 111) % 9973;
var middleRandom = (middleSeed * 9301 + 49297) % 233280 / 233280;
var middleX = baseX - 300 - middleRandom * (600 + currentLevel * 100); // Wider area coverage for higher levels
var middleY = 250 + middleRandom * 2100; // Random Y position
// Ensure obstacles are within screen bounds - tighter placement for higher levels
var minX = Math.max(400, 600 - currentLevel * 20); // Allow closer placement for higher levels
if (middleX > minX && middleY > 150 && middleY < 2500) {
var middleObstacle = new Obstacle();
middleObstacle.x = middleX;
middleObstacle.y = middleY;
obstacles.push(middleObstacle);
game.addChild(middleObstacle);
}
}
// Add additional scattered obstacles for Level 4, but fewer at the beginning
if (currentLevel >= 4 && obstacleCounter > 3) {
// Create 2-3 additional obstacles in random positions, but only after first few obstacles
var additionalObstacles = 2 + Math.floor(seededRandom * 2); // 2-3 obstacles
for (var j = 0; j < additionalObstacles; j++) {
var additionalSeed = (seed + j * 1000) % 9973;
var additionalRandom = (additionalSeed * 9301 + 49297) % 233280 / 233280;
var obstacleX = baseX + 200 + additionalRandom * 400; // Spread them out
var obstacleY = 400 + additionalRandom * 1800; // Random Y position
// Make sure it's not in the main gap area
if (obstacleY < gapPosition || obstacleY > gapPosition + gapSize) {
var additionalObstacle = new Obstacle();
additionalObstacle.x = obstacleX;
additionalObstacle.y = obstacleY;
obstacles.push(additionalObstacle);
game.addChild(additionalObstacle);
}
}
// Add obstacles specifically in character's current area for Level 4, but fewer at the beginning
var characterAreaObstacles = obstacleCounter > 2 ? 3 + Math.floor(seededRandom * 2) : 1 + Math.floor(seededRandom * 1); // Start with 1-2 obstacles, then 3-4
for (var k = 0; k < characterAreaObstacles; k++) {
var charAreaSeed = (seed + k * 2000 + 500) % 9973;
var charAreaRandom = (charAreaSeed * 9301 + 49297) % 233280 / 233280;
// Place obstacles in character's vicinity (around x=300, y=800)
var charObstacleX = baseX + 100 + charAreaRandom * 300; // Close to current obstacles
var charObstacleY = bird.y - 400 + charAreaRandom * 800; // Around character's Y position
// Ensure obstacles are within screen bounds and not in gap
if (charObstacleY > 100 && charObstacleY < 2500 && (charObstacleY < gapPosition || charObstacleY > gapPosition + gapSize)) {
var charAreaObstacle = new Obstacle();
charAreaObstacle.x = charObstacleX;
charAreaObstacle.y = charObstacleY;
obstacles.push(charAreaObstacle);
game.addChild(charAreaObstacle);
}
}
}
obstacleCounter++;
lastObstacle = LK.ticks;
// Update the last obstacle array position and reset completion flag
lastObstacleArrayX = baseX;
currentObstacleArrayPassed = false;
// Create rest platform every 2 obstacles
if (obstacleCounter % 2 === 0) {
var restPlatform = new Obstacle();
restPlatform.obstacleType = 'restPlatform';
restPlatform.speed = 0;
restPlatform.isStationary = true;
restPlatform.isSafe = true;
restPlatform.x = baseX + 300; // Position rest platform after obstacles
restPlatform.y = gapPosition + gapSize / 2; // Center in gap area
obstacles.push(restPlatform);
game.addChild(restPlatform);
}
// Create hearts based on missed hearts count (minimum 1, add 1 for each missed)
var heartsToCreate = 1 + missedHearts;
for (var heartIndex = 0; heartIndex < heartsToCreate; heartIndex++) {
var heart = new Heart();
heart.x = baseX + 30; // Position heart 30 pixels ahead of obstacle
// Spread multiple hearts vertically in the gap area
if (heartsToCreate === 1) {
heart.y = bird.y - 400 + Math.random() * 800; // Position single heart near bird's flight path
} else {
// Distribute multiple hearts evenly across the gap
var heartSpacing = gapSize / (heartsToCreate + 1);
heart.y = gapPosition + heartSpacing * (heartIndex + 1);
}
hearts.push(heart);
game.addChild(heart);
}
// Create blocks based on missed blocks count (minimum 1, add 1 for each missed)
var blocksToCreate = 1 + missedBlocks;
for (var blockIndex = 0; blockIndex < blocksToCreate; blockIndex++) {
var block = new Block();
block.x = baseX + 130; // Position block 100 pixels ahead of hearts (30 + 100)
// Spread multiple blocks vertically in the gap area
if (blocksToCreate === 1) {
block.y = gapPosition + gapSize / 2 + 60; // Position single block offset from heart
} else {
// Distribute multiple blocks evenly across the gap
var blockSpacing = gapSize / (blocksToCreate + 1);
block.y = gapPosition + blockSpacing * (blockIndex + 1) + 60;
}
// Hide block if checkpoint system is disabled
if (!checkpointEnabled) {
block.visible = false;
}
blocks.push(block);
game.addChild(block);
}
// Create spikes based on level - more spikes for higher levels with strategic positioning
var spikesToCreate = Math.min(5, Math.floor(currentLevel / 2) + 1); // 1 spike for levels 1-2, up to 5 for high levels
for (var spikeIndex = 0; spikeIndex < spikesToCreate; spikeIndex++) {
var spike = new Spike();
spike.x = baseX + 40 + spikeIndex * 25; // Position spikes closer together
// Strategic spike positioning for higher levels
if (spikesToCreate === 1) {
spike.y = gapPosition + gapSize / 2 + 120; // Single spike offset from heart position
} else if (currentLevel >= 3) {
// For level 3+: place spikes to create challenging patterns
if (spikeIndex === 0) {
spike.y = gapPosition - 50; // Above gap
} else if (spikeIndex === 1) {
spike.y = gapPosition + gapSize + 50; // Below gap
} else {
// Additional spikes within gap area for extreme difficulty
var innerSpacing = gapSize / (spikesToCreate - 1);
spike.y = gapPosition + innerSpacing * (spikeIndex - 2);
}
} else {
// For levels 1-2: distribute spikes more safely
var spikeSpacing = (gapSize + 200) / spikesToCreate;
spike.y = gapPosition - 50 + spikeSpacing * spikeIndex;
}
spikes.push(spike);
game.addChild(spike);
}
// Add 70 spikes scattered at the end of each obstacle
for (var endSpikeIndex = 0; endSpikeIndex < 70; endSpikeIndex++) {
var endSpike = new Spike();
// Scatter spikes randomly across a wide area at the end of obstacle
var scatterSeed = (currentLevel * 1000 + obstacleCounter * 100 + endSpikeIndex) % 9973;
var scatterRandomX = (scatterSeed * 9301 + 49297) % 233280 / 233280;
var scatterRandomY = ((scatterSeed + 1000) * 9301 + 49297) % 233280 / 233280;
endSpike.x = baseX + 500 + scatterRandomX * 400; // Scatter across 400px width
endSpike.y = 150 + scatterRandomY * 2300; // Scatter across full height
spikes.push(endSpike);
game.addChild(endSpike);
}
// Create bombs based on level - much more frequent and challenging for higher levels
var bombFrequency = Math.max(1, 3 - currentLevel); // Level 1: every 2 obstacles, Level 2: every obstacle, Level 3+: every obstacle
if (obstacleCounter % bombFrequency === 0) {
// Create multiple bombs for higher levels
var bombCount = Math.min(5, Math.floor(currentLevel / 2) + 2); // 2 bombs for levels 1-2, 3 for 3-4, 4 for 5-6, 5 for 7+
for (var bombIndex = 0; bombIndex < bombCount; bombIndex++) {
var bomb = new Bomb();
bomb.x = baseX + 50 + bombIndex * 40; // Spread bombs horizontally
// Position bombs at different heights for higher levels
if (bombCount === 1) {
bomb.y = gapPosition + gapSize / 2 - 100; // Single bomb position
} else {
// Distribute multiple bombs vertically in and around the gap
var bombSpacing = (gapSize + 200) / bombCount;
bomb.y = gapPosition - 100 + bombSpacing * bombIndex;
}
bombs.push(bomb);
game.addChild(bomb);
}
}
// Create exactly 6 lasers with each obstacle
if (currentLevel >= 1) {
var laserCount = 6; // Always create exactly 6 lasers
for (var laserIndex = 0; laserIndex < laserCount; laserIndex++) {
var laser = new Laser();
laser.x = baseX + 100 + laserIndex * 40; // Spread lasers horizontally with closer spacing
laser.startX = laser.x; // Set starting position for oscillation
// Distribute 6 lasers vertically around the gap
var laserSpacing = (gapSize + 300) / laserCount;
laser.y = gapPosition - 150 + laserSpacing * laserIndex;
lasers.push(laser);
game.addChild(laser);
}
}
// Create characters based on level
var charactersToCreate = Math.min(3, 1 + Math.floor(currentLevel / 3)); // 1-2 characters for early levels, up to 3 for higher levels
for (var charIndex = 0; charIndex < charactersToCreate; charIndex++) {
var character = new Character();
character.x = baseX + 200 + charIndex * 60; // Position characters horizontally
// Distribute characters vertically in and around the gap
var characterSpacing = (gapSize + 200) / charactersToCreate;
character.y = gapPosition - 100 + characterSpacing * charIndex;
characters.push(character);
game.addChild(character);
}
// Create fires frequently - 2-4 fires per obstacle
var firesToCreate = 2 + Math.floor(Math.random() * 3); // 2-4 fires
for (var fireIndex = 0; fireIndex < firesToCreate; fireIndex++) {
var fire = new Fire();
fire.x = baseX + 80 + fireIndex * 50; // Position fires horizontally
// Distribute fires vertically across the screen
var fireSpacing = 2400 / firesToCreate;
fire.y = 200 + fireSpacing * fireIndex;
// Set fire visibility based on toggle state
fire.visible = fireToggleEnabled;
fires.push(fire);
game.addChild(fire);
}
// Create rest platforms above and below the gap (door area)
var topRestPlatform = new Obstacle();
topRestPlatform.obstacleType = 'restPlatform';
topRestPlatform.speed = 0;
topRestPlatform.isStationary = true;
topRestPlatform.isSafe = true;
topRestPlatform.x = baseX;
topRestPlatform.y = gapPosition - 100; // Position above the gap
obstacles.push(topRestPlatform);
game.addChild(topRestPlatform);
var bottomRestPlatform = new Obstacle();
bottomRestPlatform.obstacleType = 'restPlatform';
bottomRestPlatform.speed = 0;
bottomRestPlatform.isStationary = true;
bottomRestPlatform.isSafe = true;
bottomRestPlatform.x = baseX;
bottomRestPlatform.y = gapPosition + gapSize + 100; // Position below the gap
obstacles.push(bottomRestPlatform);
game.addChild(bottomRestPlatform);
}
function checkCollisions() {
// Check ground collision - respawn at checkpoint when bird touches ground
if (bird.y + 60 >= ground.y) {
showDeathReason('YERE ÇARPTIN!');
if (checkpointEnabled) {
// Reset bird to last checkpoint position
bird.x = lastCheckpointX;
bird.y = lastCheckpointY;
bird.velocityY = 0;
} else {
// Reset to start position when checkpoint disabled
bird.x = 300;
bird.y = 800;
bird.velocityY = 0;
}
// Take damage
takeDamage();
// Play death music
LK.getSound('death').play();
// Play death sound
LK.getSound('deathSound').play();
return;
}
// Check obstacle collisions - bounce off obstacles
for (var i = obstacles.length - 1; i >= 0; i--) {
var obstacle = obstacles[i];
// Skip if obstacle is undefined
if (!obstacle) {
obstacles.splice(i, 1);
continue;
}
if (bird.intersects(obstacle)) {
// Check if it's a rest platform - safe area
if (obstacle.obstacleType === 'restPlatform') {
// Safe collision - just bounce without damage
var distanceX = bird.x - obstacle.x;
var distanceY = bird.y - obstacle.y;
var totalDistance = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
if (totalDistance > 0) {
var normalX = distanceX / totalDistance;
var normalY = distanceY / totalDistance;
// Gentle push away from platform
var pushForce = 3;
bird.x += normalX * pushForce;
bird.y += normalY * pushForce;
// Apply gentle bounce velocity
bird.velocityY = normalY * 3;
// Visual feedback for landing on safe platform
LK.effects.flashObject(obstacle, 0x00ff88, 300);
}
continue; // Skip damage dealing
}
// Only take damage if not already damaged from this obstacle
if (!obstacle.damagedBird) {
takeDamage();
obstacle.damagedBird = true; // Mark this obstacle as having caused damage
}
// Calculate collision direction
var distanceX = bird.x - obstacle.x;
var distanceY = bird.y - obstacle.y;
var totalDistance = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
// Normalize collision direction
if (totalDistance > 0) {
var normalX = distanceX / totalDistance;
var normalY = distanceY / totalDistance;
// Push bird away from obstacle
var pushForce = 8;
bird.x += normalX * pushForce;
bird.y += normalY * pushForce;
// Apply bounce velocity
var bounceForce = 5;
bird.velocityY = normalY * bounceForce;
// Play flap sound for bounce feedback
LK.getSound('flap').play();
}
}
// Check if bird passed obstacle (mark individual obstacles as passed but don't award points yet)
if (!obstacle.passed && obstacle.x + 100 < bird.x) {
obstacle.passed = true;
}
;
// Remove off-screen obstacles (but keep stationary gears and rest platforms)
if (obstacle.x < -100 && !obstacle.isStationary) {
// Add flash effect when obstacle disappears
LK.effects.flashObject(obstacle, 0xffffff, 200);
obstacle.destroy();
obstacles.splice(i, 1);
}
}
// Check heart collections
for (var h = hearts.length - 1; h >= 0; h--) {
var heart = hearts[h];
// Skip if heart is undefined
if (!heart) {
hearts.splice(h, 1);
continue;
}
// Check if bird collected the heart
if (bird.intersects(heart) && !heart.collected) {
heart.collected = true;
// Reset missed hearts counter when collecting a heart
missedHearts = 0;
// Always increase health (no maximum limit)
playerHealth++;
healthTxt.setText('Can: ' + playerHealth);
// Increase score by 2 when collecting heart
LK.setScore(LK.getScore() + 2);
storage.levelScore = LK.getScore(); // Save to storage
scoreTxt.setText(LK.getScore());
updateLevelProgress();
// Visual feedback for collecting heart
tween(heart, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
heart.destroy();
}
});
// Flash screen green briefly
LK.effects.flashScreen(0x00ff00, 200);
// Play score sound as feedback
LK.getSound('score').play();
hearts.splice(h, 1);
continue;
}
// Remove off-screen hearts
if (heart.x < -100) {
// Track that this heart was missed
missedHearts++;
heart.destroy();
hearts.splice(h, 1);
}
}
// Check block collections
for (var bl = blocks.length - 1; bl >= 0; bl--) {
var block = blocks[bl];
// Skip if block is undefined
if (!block) {
blocks.splice(bl, 1);
continue;
}
// Check if bird collected the block
if (bird.intersects(block) && !block.collected) {
block.collected = true;
// Reset missed blocks counter when collecting a block
missedBlocks = 0;
// Only save checkpoint if system is enabled
if (checkpointEnabled) {
// Increment checkpoint counter
checkpointCounter++;
checkpointTxt.setText('Yedek Can: ' + checkpointCounter);
checkpointCounterTxt.setText('Yedek Can: ' + checkpointCounter);
backupLivesTxt.setText('Yedek Can: ' + checkpointCounter);
mainBackupLivesTxt.setText('Yedek Can: ' + checkpointCounter);
// Save checkpoint position
lastCheckpointX = block.x;
lastCheckpointY = block.y;
}
// Always increment total collected backup lives counter regardless of checkpoint enabled state
totalCollectedBackupLives++;
collectedBackupLivesTxt.setText('Toplanan Yedek Can: ' + totalCollectedBackupLives);
// Increase score by 0.5 when collecting checkpoint
LK.setScore(LK.getScore() + 0.5);
storage.levelScore = LK.getScore(); // Save to storage
scoreTxt.setText(LK.getScore());
updateLevelProgress();
// Increase health by 0 when collecting block (no health change)
playerHealth += 0;
healthTxt.setText('Can: ' + playerHealth);
// Visual feedback for collecting block
tween(block, {
scaleX: 2.5,
scaleY: 2.5,
alpha: 0,
rotation: Math.PI * 2
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
block.destroy();
}
});
// Flash screen blue briefly
LK.effects.flashScreen(0x4169E1, 300);
// Play score sound as feedback
LK.getSound('score').play();
blocks.splice(bl, 1);
continue;
}
// Remove off-screen blocks
if (block.x < -100) {
// Track that this block was missed
missedBlocks++;
// Track missed checkpoint blocks specifically
missedCheckpointBlocks++;
missedCheckpointTxt.setText('Kaçırılan Yedek Can: ' + missedCheckpointBlocks);
block.destroy();
blocks.splice(bl, 1);
}
}
// Check spike collisions - instant death
for (var s = spikes.length - 1; s >= 0; s--) {
var spike = spikes[s];
// Skip if spike is undefined
if (!spike) {
spikes.splice(s, 1);
continue;
}
// Check if bird touched the spike - respawn at checkpoint
if (bird.intersects(spike)) {
showDeathReason('DİKENE ÇARPTIN!');
if (checkpointEnabled) {
// Reset bird to last checkpoint position
bird.x = lastCheckpointX;
bird.y = lastCheckpointY;
bird.velocityY = 0;
} else {
// Reset to start position when checkpoint disabled
bird.x = 300;
bird.y = 800;
bird.velocityY = 0;
}
// Take damage
takeDamage();
// Play death music
LK.getSound('death').play();
// Play death sound
LK.getSound('deathSound').play();
// Flash screen red to indicate death
LK.effects.flashScreen(0xff0000, 500);
return; // Exit collision check immediately
}
// Remove off-screen spikes
if (spike.x < -150) {
spike.destroy();
spikes.splice(s, 1);
}
}
// Check bomb collisions - reduce health to 1 and remove all hearts
for (var b = bombs.length - 1; b >= 0; b--) {
var bomb = bombs[b];
// Skip if bomb is undefined
if (!bomb) {
bombs.splice(b, 1);
continue;
}
// Check if bird touched the bomb
if (bird.intersects(bomb) && !bomb.collected) {
bomb.collected = true;
// Play bomb explosion sound
LK.getSound('bombExplosion').play();
// Create explosion effect - scale up and fade out
tween(bomb, {
scaleX: 3,
scaleY: 3,
alpha: 0,
rotation: Math.PI * 2
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
bomb.destroy();
}
});
// Hide all hearts when bomb explodes
for (var hHide = 0; hHide < hearts.length; hHide++) {
if (hearts[hHide]) {
hearts[hHide].visible = false;
}
}
// Check if player already had 1 health (would die from bomb)
if (playerHealth <= 1) {
showDeathReason('BOMBA PATLADI!');
if (checkpointEnabled) {
// Reset bird to last checkpoint position
bird.x = lastCheckpointX;
bird.y = lastCheckpointY;
bird.velocityY = 0;
} else {
// Reset to start position when checkpoint disabled
bird.x = 300;
bird.y = 800;
bird.velocityY = 0;
}
// Reset health to 3
playerHealth = 3;
healthTxt.setText('Can: ' + playerHealth);
// Play death music
LK.getSound('death').play();
// Play death sound
LK.getSound('deathSound').play();
return; // Exit collision check immediately
}
// Reduce health to 1
playerHealth = 1;
healthTxt.setText('Can: ' + playerHealth);
// Flash screen red to indicate bomb effect
LK.effects.flashScreen(0xff4444, 800);
// Remove the bomb from array but don't destroy immediately (explosion handles destruction)
bombs.splice(b, 1);
continue;
}
// Remove off-screen bombs
if (bomb.x < -150) {
bomb.destroy();
bombs.splice(b, 1);
}
}
// Check laser collisions - damage player and apply knockback
for (var l = lasers.length - 1; l >= 0; l--) {
var laser = lasers[l];
// Skip if laser is undefined
if (!laser) {
lasers.splice(l, 1);
continue;
}
// Check if bird touched the laser
if (bird.intersects(laser) && !laser.collected) {
laser.collected = true;
// Play laser sound
LK.getSound('laserSound').play();
// Take damage
takeDamage();
// Apply knockback effect
var knockbackForce = 15;
var distanceX = bird.x - laser.x;
var distanceY = bird.y - laser.y;
var totalDistance = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
if (totalDistance > 0) {
var normalX = distanceX / totalDistance;
var normalY = distanceY / totalDistance;
// Push bird away from laser
bird.x += normalX * knockbackForce;
bird.y += normalY * knockbackForce;
// Apply strong bounce velocity
bird.velocityY = normalY * 8;
}
// Flash screen red to indicate laser hit
LK.effects.flashScreen(0xff0000, 400);
// Create destruction effect for laser
tween(laser, {
scaleX: 0,
scaleY: 0,
alpha: 0,
rotation: Math.PI * 4
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
laser.destroy();
}
});
lasers.splice(l, 1);
continue;
}
// Remove off-screen lasers (now check right side since they move right)
if (laser.x > 2300) {
laser.destroy();
lasers.splice(l, 1);
}
}
// Check character collisions - character dies when touched by bird
for (var c = characters.length - 1; c >= 0; c--) {
var character = characters[c];
// Skip if character is undefined
if (!character) {
characters.splice(c, 1);
continue;
}
// Check if bird touched the character
if (bird.intersects(character) && !character.isDead) {
character.isDead = true;
// Visual feedback for character death
tween(character, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0,
rotation: Math.PI * 3
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
character.destroy();
}
});
// Flash screen briefly to indicate character death
LK.effects.flashScreen(0xFFFF00, 200);
// Play score sound as feedback
LK.getSound('score').play();
characters.splice(c, 1);
continue;
}
// Remove off-screen characters
if (character.x < -150) {
character.destroy();
characters.splice(c, 1);
}
}
// Check fire collisions - instant death that completely ignores checkpoint system
for (var f = fires.length - 1; f >= 0; f--) {
var fire = fires[f];
// Skip if fire is undefined
if (!fire) {
fires.splice(f, 1);
continue;
}
// Check if bird touched the fire
if (bird.intersects(fire) && !fire.collected) {
fire.collected = true;
showDeathReason('ATEŞE DOKUNDIN!');
// Fire causes instant death - completely bypass checkpoint system and kill bird immediately
// Reset to start position regardless of any checkpoint settings
bird.x = 300;
bird.y = 800;
bird.velocityY = 0;
// Reset checkpoint counter to 0 when touching fire
checkpointCounter = 0;
checkpointTxt.setText('Yedek Can: ' + checkpointCounter);
checkpointCounterTxt.setText('Yedek Can: ' + checkpointCounter);
backupLivesTxt.setText('Yedek Can: ' + checkpointCounter);
mainBackupLivesTxt.setText('Yedek Can: ' + checkpointCounter);
// Show game over immediately - fire kills bird instantly
resetToLevelStart();
LK.showGameOver();
// Play death music
LK.getSound('death').play();
// Play death sound
LK.getSound('deathSound').play();
// Create fire destruction effect
tween(fire, {
scaleX: 2,
scaleY: 2,
alpha: 0,
rotation: Math.PI * 2
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
fire.destroy();
}
});
// Flash screen orange to indicate fire damage
LK.effects.flashScreen(0xff4400, 300);
fires.splice(f, 1);
return; // Exit collision check immediately after fire death
}
// Remove off-screen fires
if (fire.x < -150) {
fire.destroy();
fires.splice(f, 1);
}
}
// Check portal collisions
for (var p = portals.length - 1; p >= 0; p--) {
var portal = portals[p];
// Skip if portal is undefined
if (!portal) {
portals.splice(p, 1);
continue;
}
if (bird.intersects(portal)) {
// Flash screen purple to indicate portal entry
LK.effects.flashScreen(0x9966ff, 800);
// Add current level score to total and preserve it
totalScore += LK.getScore();
storage.totalScore = totalScore;
storage.levelScore = LK.getScore(); // Save current level score
// All levels are already unlocked for everyone - no need to unlock
unlockedLevels = 999; // Keep all levels unlocked
storage.unlockedLevels = unlockedLevels;
// Advance to next level
currentLevel++;
storage.currentLevel = currentLevel;
levelTxt.setText('Seviye ' + currentLevel);
// Keep current score when advancing levels (don't reset to 0)
// Score persists to next level
scoreTxt.setText(LK.getScore());
// Reset obstacle counter for consistent level maps
obstacleCounter = 0;
// Clear all obstacles
for (var j = obstacles.length - 1; j >= 0; j--) {
obstacles[j].destroy();
obstacles.splice(j, 1);
}
// Clear all portals
for (var pt = portals.length - 1; pt >= 0; pt--) {
portals[pt].destroy();
portals.splice(pt, 1);
}
// Generate new obstacle sequence for the new level
generateLevelObstacleSequence();
updateLevelProgress();
// Increase difficulty for new level
updateDifficultyForLevel();
// Reset bird position
bird.x = 300;
bird.y = 800;
bird.velocityY = 0;
bird.completedFlips = 0;
// Reset health
resetHealth();
// Reset portal spawned flag
portalSpawned = false;
// Create initial obstacle for new level
createObstacle();
return; // Exit collision check to avoid other collision handling
}
// Remove off-screen portals
if (portal.x < -200) {
portal.destroy();
portals.splice(p, 1);
}
}
// Check ceiling collision
if (bird.y < 50) {
bird.y = 50;
bird.velocityY = 0;
}
}
game.down = function (x, y, obj) {
// Check if right mouse button (button 2) or secondary touch
if (obj.event && (obj.event.button === 2 || obj.event.which === 3)) {
// Right click - only throw ice if cursor is over a fire and fire toggle is enabled
if (gameStarted && fireToggleEnabled) {
// Check if cursor position is over any fire object
var cursorOverFire = false;
for (var f = 0; f < fires.length; f++) {
var fire = fires[f];
if (fire && !fire.collected) {
// Check if cursor position is within fire bounds
var fireLeft = fire.x - 50; // Half of fire width (100/2)
var fireRight = fire.x + 50;
var fireTop = fire.y - 50; // Half of fire height (100/2)
var fireBottom = fire.y + 50;
if (x >= fireLeft && x <= fireRight && y >= fireTop && y <= fireBottom) {
cursorOverFire = true;
break;
}
}
}
// Only throw ice if cursor is over a fire
if (cursorOverFire) {
var ice = new Ice();
ice.x = bird.x;
ice.y = bird.y;
// Calculate direction towards cursor
var directionX = x - bird.x;
var directionY = y - bird.y;
var distance = Math.sqrt(directionX * directionX + directionY * directionY);
// Normalize direction and set ice velocity
if (distance > 0) {
ice.velocityX = directionX / distance * 8;
ice.velocityY = directionY / distance * 8;
} else {
ice.velocityX = 8;
ice.velocityY = 0;
}
ices.push(ice);
game.addChild(ice);
}
}
return;
}
// Check if left mouse button or primary touch AND cursor is over fire
if (gameStarted && fireToggleEnabled) {
// Check if cursor position is over any fire object
var cursorOverFire = false;
for (var f = 0; f < fires.length; f++) {
var fire = fires[f];
if (fire && !fire.collected) {
// Check if cursor position is within fire bounds
var fireLeft = fire.x - 50; // Half of fire width (100/2)
var fireRight = fire.x + 50;
var fireTop = fire.y - 50; // Half of fire height (100/2)
var fireBottom = fire.y + 50;
if (x >= fireLeft && x <= fireRight && y >= fireTop && y <= fireBottom) {
cursorOverFire = true;
break;
}
}
}
// If cursor is over fire, throw ice instead of flapping
if (cursorOverFire) {
var ice = new Ice();
ice.x = bird.x;
ice.y = bird.y;
// Calculate direction towards cursor
var directionX = x - bird.x;
var directionY = y - bird.y;
var distance = Math.sqrt(directionX * directionX + directionY * directionY);
// Normalize direction and set ice velocity
if (distance > 0) {
ice.velocityX = directionX / distance * 8;
ice.velocityY = directionY / distance * 8;
} else {
ice.velocityX = 8;
ice.velocityY = 0;
}
ices.push(ice);
game.addChild(ice);
return; // Don't flap when throwing ice
}
}
if (!gameStarted) {
startGame();
return;
}
// Start tracking press for long press detection
isPressing = true;
pressStartTime = Date.now();
};
game.up = function (x, y, obj) {
if (!gameStarted) return;
// Calculate press duration
var pressDuration = Date.now() - pressStartTime;
isPressing = false;
// If it was a short press (less than threshold), perform a flap
if (pressDuration < longPressThreshold) {
bird.flap();
}
};
game.update = function () {
if (!gameStarted) return;
// Create obstacles
if (LK.ticks - lastObstacle > obstacleSpacing) {
createObstacle();
}
// Create background shapes
if (LK.ticks - lastBackgroundShape > backgroundShapeSpacing) {
createBackgroundShape();
lastBackgroundShape = LK.ticks;
}
// Spikes are now created after obstacles, no random creation needed
// Hearts are now created after each obstacle, so no timer-based spawning needed
// Update bird physics
bird.update();
// Update obstacles
for (var i = 0; i < obstacles.length; i++) {
obstacles[i].update();
}
// Update hearts
for (var h = 0; h < hearts.length; h++) {
hearts[h].update();
}
// Update blocks
for (var bl = 0; bl < blocks.length; bl++) {
blocks[bl].update();
}
// Update portals
for (var p = 0; p < portals.length; p++) {
portals[p].update();
}
// Update spikes
for (var s = 0; s < spikes.length; s++) {
spikes[s].update();
}
// Update bombs
for (var b = 0; b < bombs.length; b++) {
bombs[b].update();
}
// Update lasers
for (var l = 0; l < lasers.length; l++) {
lasers[l].update();
}
// Update characters
for (var c = 0; c < characters.length; c++) {
if (characters[c]) {
characters[c].update();
}
}
// Update fires
for (var f = 0; f < fires.length; f++) {
if (fires[f]) {
fires[f].update();
}
}
// Update ice projectiles
for (var ic = ices.length - 1; ic >= 0; ic--) {
var ice = ices[ic];
if (ice) {
ice.update();
// Remove off-screen ice
if (ice.x > 2300 || ice.y < 0 || ice.y > 2732) {
ice.destroy();
ices.splice(ic, 1);
continue;
}
// Check ice-fire collision
for (var f = fires.length - 1; f >= 0; f--) {
var fire = fires[f];
if (fire && ice.intersects(fire) && !ice.collected && !fire.collected) {
ice.collected = true;
fire.collected = true;
// Increment score by 1 when destroying fire
LK.setScore(LK.getScore() + 1);
storage.levelScore = LK.getScore(); // Save to storage
scoreTxt.setText(LK.getScore());
updateLevelProgress();
// Increment destroyed fires counter
destroyedFiresCount++;
destroyedFiresTxt.setText('Yok Edilen Ateş: ' + destroyedFiresCount);
// Destroy both ice and fire
tween(ice, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
ice.destroy();
}
});
tween(fire, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
fire.destroy();
}
});
// Flash screen white briefly
LK.effects.flashScreen(0xffffff, 200);
// Play score sound
LK.getSound('score').play();
// Remove from arrays
ices.splice(ic, 1);
fires.splice(f, 1);
break;
}
}
}
}
// Update background shapes
for (var j = backgroundShapes.length - 1; j >= 0; j--) {
var bgShape = backgroundShapes[j];
bgShape.update();
// Remove off-screen background shapes
if (bgShape.x < -200) {
bgShape.destroy();
backgroundShapes.splice(j, 1);
}
}
// Check collisions
checkCollisions();
// Check individual obstacle passing for score increment
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
// Check if bird passed obstacle and hasn't scored from it yet
if (!obstacle.passed && !obstacle.scoredFrom && obstacle.x + 100 < bird.x) {
obstacle.passed = true;
obstacle.scoredFrom = true; // Mark as scored to prevent duplicate scoring
LK.setScore(LK.getScore() + 1);
storage.levelScore = LK.getScore(); // Save to storage
scoreTxt.setText(LK.getScore());
LK.getSound('score').play();
updateLevelProgress();
}
}
// Create portal when score reaches level threshold (10 + (level-1)*10)
var currentLevelThreshold = levelScoreThreshold + (currentLevel - 1) * 10;
if (LK.getScore() >= currentLevelThreshold && !portalSpawned) {
var portal = new Portal();
portal.x = 2200; // Start off-screen right
portal.y = 1366; // Center of screen vertically
portals.push(portal);
game.addChild(portal);
// Hide all existing obstacles when portal is created
for (var hideIndex = 0; hideIndex < obstacles.length; hideIndex++) {
obstacles[hideIndex].visible = false;
}
// Hide all hearts when portal is created
for (var heartHideIndex = 0; heartHideIndex < hearts.length; heartHideIndex++) {
hearts[heartHideIndex].visible = false;
}
// Hide all blocks when portal is created
for (var blockHideIndex = 0; blockHideIndex < blocks.length; blockHideIndex++) {
blocks[blockHideIndex].visible = false;
}
// Hide all spikes when portal is created
for (var spikeHideIndex = 0; spikeHideIndex < spikes.length; spikeHideIndex++) {
spikes[spikeHideIndex].visible = false;
}
// Hide all bombs when portal is created
for (var bombHideIndex = 0; bombHideIndex < bombs.length; bombHideIndex++) {
bombs[bombHideIndex].visible = false;
}
// Hide all lasers when portal is created
for (var laserHideIndex = 0; laserHideIndex < lasers.length; laserHideIndex++) {
lasers[laserHideIndex].visible = false;
}
// Hide all characters when portal is created
for (var characterHideIndex = 0; characterHideIndex < characters.length; characterHideIndex++) {
characters[characterHideIndex].visible = false;
}
// Hide all fires when portal is created
for (var fireHideIndex = 0; fireHideIndex < fires.length; fireHideIndex++) {
fires[fireHideIndex].visible = false;
}
// Hide all ice projectiles when portal is created
for (var iceHideIndex = 0; iceHideIndex < ices.length; iceHideIndex++) {
ices[iceHideIndex].visible = false;
}
portalSpawned = true;
}
// No time-based score increment - score only from obstacles
// Level-based difficulty progression
var baseSpacing = 400 - (currentLevel - 1) * 20;
var minSpacing = Math.max(200, 300 - (currentLevel - 1) * 10);
var reductionRate = 1 + currentLevel; // Increase reduction rate with level
var currentSpacing = baseSpacing - LK.getScore() * reductionRate;
obstacleSpacing = Math.max(minSpacing, currentSpacing);
};
function showContinueButton() {
// Continue button functionality removed
}
function showDeathReason(reason) {
lastDeathReason = reason;
deathReasonTxt.setText(reason);
deathReasonTxt.visible = true;
deathReasonTxt.alpha = 1;
deathReasonTxt.scaleX = 2;
deathReasonTxt.scaleY = 2;
// Animate the death reason text
tween(deathReasonTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
onFinish: function onFinish() {
tween(deathReasonTxt, {
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
deathReasonTxt.visible = false;
}
});
}
});
}
function showGameOverWithLevelButton() {
// Standard game over
resetToLevelStart();
LK.showGameOver();
}
;
// Track mouse position for cursor detection
game.move = function (x, y, obj) {
game.mouseX = x;
game.mouseY = y;
};
kırmızı bir kalp . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
portal. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
bomba. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
minecraft papağan. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
bayrak . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat