/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bullet class for weapon projectiles var Bullet = Container.expand(function () { var self = Container.call(this); // Create bullet visual (small circle) var bulletAsset = self.attachAsset('manCircle', { anchorX: 0.5, anchorY: 0.5 }); bulletAsset.width = 20; bulletAsset.height = 20; bulletAsset.tint = 0xFFFF00; // Yellow color for bullet self.speed = 12; self.targetX = 0; self.targetY = 0; // Update method for bullet movement towards target self.update = function () { // Move towards target var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } // Remove bullet if it reaches target or goes off screen if (distance < 30 || self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) { if (self.parent) { self.parent.removeChild(self); } var index = bullets.indexOf(self); if (index !== -1) { bullets.splice(index, 1); } } }; return self; }); // Car class var Car = Container.expand(function () { var self = Container.call(this); // Attach car asset (red box, 200x120) var carAsset = self.attachAsset('car', { anchorX: 0.5, anchorY: 0.5 }); // Set size for car asset carAsset.width = 200; carAsset.height = 120; // For touch feedback self.flash = function () { tween(self, { alpha: 0.5 }, { duration: 80, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 120 }); } }); }; return self; }); // DeadlyTree class for special scene var DeadlyTree = Container.expand(function () { var self = Container.call(this); // Attach tree asset (red tinted, 100x100) var treeAsset = self.attachAsset('tree', { anchorX: 0.5, anchorY: 0.5 }); treeAsset.width = 100; treeAsset.height = 100; treeAsset.tint = 0xFF0000; // Red tint for deadly trees self.speed = 24; // Falling speed (3x faster) self.isFollowing = false; self.followSpeed = 8; // Speed when following player // Start following the player self.startFollowing = function () { self.isFollowing = true; }; // Stop following and disappear with tween self.stopFollowing = function () { self.isFollowing = false; tween(self, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { if (self.parent) { self.parent.removeChild(self); } } }); }; // Update method for falling motion or following self.update = function () { if (self.isFollowing && car) { // Move towards car position var dx = car.x - self.x; var dy = car.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.followSpeed; self.y += dy / distance * self.followSpeed; } } else { self.y += self.speed; } }; return self; }); // GoldenTree class var GoldenTree = Container.expand(function () { var self = Container.call(this); // Attach tree asset (golden, 140x140 - slightly bigger) var treeAsset = self.attachAsset('tree', { anchorX: 0.5, anchorY: 0.5 }); treeAsset.width = 140; treeAsset.height = 140; treeAsset.tint = 0xFFD700; // Golden tint color self.pointValue = 10; // Golden tree gives 10 points // Add golden glow effect self.glowEffect = function () { tween(self, { alpha: 0.7 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { self.glowEffect(); // Loop the glow effect } }); } }); }; // Start glow effect immediately self.glowEffect(); // Special golden hit animation self.hitAnim = function () { tween(self, { scaleX: 1.5, scaleY: 1.5 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 150, easing: tween.easeIn }); } }); }; return self; }); // MultiSkeleton class for fourth scene var MultiSkeleton = Container.expand(function () { var self = Container.call(this); // Create circular shape for the skeleton var skeletonAsset = self.attachAsset('manCircle', { anchorX: 0.5, anchorY: 0.5 }); skeletonAsset.tint = 0x800080; // Purple tint for skeletons self.throwTimer = 0; self.throwInterval = 60; // Fixed 1 second interval (60 ticks) // Update method for throwing trees self.update = function () { self.throwTimer++; if (self.throwTimer >= self.throwInterval) { // Throw either deadly tree or point tree randomly var isDeadly = Math.random() < 0.5; // 50% chance for deadly tree var thrownTree; if (isDeadly) { thrownTree = new DeadlyTree(); } else { thrownTree = new Tree(); } // Find valid position that doesn't overlap with existing trees var validPosition = false; var tries = 0; var targetX, targetY; do { targetX = self.x + (Math.random() - 0.5) * 400; // Random position around skeleton targetY = self.y + 50 + Math.random() * 200; validPosition = true; tries++; // Check distance from all existing fourth scene trees for (var ft = 0; ft < fourthSceneTrees.length; ft++) { var existingTree = fourthSceneTrees[ft]; var dx = targetX - existingTree.x; var dy = targetY - existingTree.y; var distanceToTree = Math.sqrt(dx * dx + dy * dy); if (distanceToTree < 150) { // Minimum distance of 150 pixels validPosition = false; break; } } } while (!validPosition && tries < 10); thrownTree.x = self.x; thrownTree.y = self.y + 50; // Set target towards calculated position thrownTree.targetX = targetX; thrownTree.targetY = targetY; thrownTree.speed = 8; thrownTree.isThrown = true; // Override update to move towards target thrownTree.update = function () { if (thrownTree.isThrown) { var dx = thrownTree.targetX - thrownTree.x; var dy = thrownTree.targetY - thrownTree.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { thrownTree.x += dx / distance * thrownTree.speed; thrownTree.y += dy / distance * thrownTree.speed; } // Remove if goes off screen if (thrownTree.x < -100 || thrownTree.x > 2148 || thrownTree.y < -100 || thrownTree.y > 2832) { if (thrownTree.parent) { thrownTree.parent.removeChild(thrownTree); } var index = fourthSceneTrees.indexOf(thrownTree); if (index !== -1) { fourthSceneTrees.splice(index, 1); lastIntersectingFourthTrees.splice(index, 1); } } } }; fourthSceneTrees.push(thrownTree); lastIntersectingFourthTrees.push(false); game.addChild(thrownTree); self.throwTimer = 0; self.throwInterval = 60; // Reset to 1 second interval } }; return self; }); // Pole class var Pole = Container.expand(function () { var self = Container.call(this); // Attach pole asset (thin metal pole, 30x300) var poleAsset = self.attachAsset('pole', { anchorX: 0.5, anchorY: 0.5 }); self.pointValue = -10; // Pole reduces 10 points // Animate on hit (shake effect) self.hitAnim = function () { tween(self, { rotation: 0.2 }, { duration: 80, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { rotation: -0.2 }, { duration: 80, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { rotation: 0 }, { duration: 80, easing: tween.easeIn }); } }); } }); }; return self; }); // PurpleTree class var PurpleTree = Container.expand(function () { var self = Container.call(this); // Attach tree asset (purple, 140x140 - slightly bigger) var treeAsset = self.attachAsset('tree', { anchorX: 0.5, anchorY: 0.5 }); treeAsset.width = 140; treeAsset.height = 140; treeAsset.tint = 0x8A2BE2; // Purple tint color self.pointValue = 30; // Purple tree gives 30 points // Add purple glow effect self.glowEffect = function () { tween(self, { alpha: 0.6 }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { self.glowEffect(); // Loop the glow effect } }); } }); }; // Start glow effect immediately self.glowEffect(); // Special purple hit animation self.hitAnim = function () { tween(self, { scaleX: 1.6, scaleY: 1.6 }, { duration: 180, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 180, easing: tween.easeIn }); } }); }; return self; }); // ThrowingMan class for special scene var ThrowingMan = Container.expand(function () { var self = Container.call(this); // Create circular shape for the man var manAsset = self.attachAsset('manCircle', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // Tree class var Tree = Container.expand(function () { var self = Container.call(this); // Attach tree asset (green ellipse, 120x120) var treeAsset = self.attachAsset('tree', { anchorX: 0.5, anchorY: 0.5 }); treeAsset.width = 120; treeAsset.height = 120; treeAsset.tint = 0x228B22; self.pointValue = 1; // Normal tree gives 1 point // Animate on hit self.hitAnim = function () { tween(self, { scaleX: 1.3, scaleY: 1.3 }, { duration: 120, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 120, easing: tween.easeIn }); } }); }; return self; }); // Weapon class for special scene var Weapon = Container.expand(function () { var self = Container.call(this); // Create weapon visual using weapon image asset var weaponAsset = self.attachAsset('weapon', { anchorX: 0.5, anchorY: 0.5 }); weaponAsset.rotation = Math.PI / 4; // 45 degree rotation return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87ceeb // Sky blue }); /**** * Game Code ****/ // --- Game constants --- var CAR_START_X = 2048 / 2; var CAR_START_Y = 2732 - 350; var TREE_MIN_Y = 350; var TREE_MAX_Y = 2732 - 350; var TREE_MIN_X = 150; var TREE_MAX_X = 2048 - 150; var WIN_SCORE = 100000000; // --- Game state --- var car = null; var trees = []; var poles = []; var score = 0; var scoreTxt = null; var dragNode = null; var lastIntersecting = []; var lastIntersectingPoles = []; var goldenTreeSpawned = false; var treesHitThisRound = 0; var purpleTreeCounter = 0; var polesSpawnedThisRound = 0; var countdownTimer = 10; var countdownTxt = null; var lastCarX = 0; var lastCarY = 0; var lastScore = 0; var upwardCounter = 1; var upwardCounterTxt = null; var specialScene = false; var specialSceneInitialized = false; var throwingMan = null; var deadlyTrees = []; var lastIntersectingDeadly = []; var throwTimer = 0; var followingStartTime = null; var followingDuration = 10000; // 10 seconds in milliseconds var allFollowingTreesGone = false; // Flag to track if all following trees have disappeared var bottomLeftCounter = 150; var bottomLeftCounterTxt = null; var weapon = null; var weaponSpawned = false; var bullets = []; var lastIntersectingWeapon = false; var skeletonHealth = 1000; var skeletonHealthTxt = null; var fourthScene = false; var fourthSceneInitialized = false; var multiSkeletons = []; var fourthSceneTrees = []; var lastIntersectingFourthTrees = []; // --- Create and add car --- car = new Car(); car.x = CAR_START_X; car.y = CAR_START_Y; game.addChild(car); // --- Create and add trees --- for (var i = 0; i < 5; i++) { var tree = new Tree(); tree.x = getRandomTreeX(); tree.y = getRandomTreeY(); trees.push(tree); lastIntersecting.push(false); game.addChild(tree); } // --- Create and add poles --- for (var i = 0; i < 5; i++) { var pole = new Pole(); var tries = 0; var validPosition = false; do { pole.x = getRandomTreeX(); pole.y = getRandomTreeY(); tries++; validPosition = true; // Check distance from car if (distance(car.x, car.y, pole.x, pole.y) < 300) { validPosition = false; } // Check distance from all existing trees for (var t = 0; t < trees.length; t++) { if (distance(pole.x, pole.y, trees[t].x, trees[t].y) < 200) { validPosition = false; break; } } // Check distance from all existing poles for (var p = 0; p < poles.length; p++) { if (distance(pole.x, pole.y, poles[p].x, poles[p].y) < 200) { validPosition = false; break; } } } while (!validPosition && tries < 20); poles.push(pole); lastIntersectingPoles.push(false); game.addChild(pole); } // --- Score text --- scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // --- Countdown timer text --- countdownTxt = new Text2('10', { size: 100, fill: 0xFF0000 }); countdownTxt.anchor.set(1, 1); LK.gui.bottomRight.addChild(countdownTxt); // --- Upward counter text --- upwardCounterTxt = new Text2('1', { size: 100, fill: 0x006400 }); upwardCounterTxt.anchor.set(1, 0); LK.gui.topRight.addChild(upwardCounterTxt); // --- Bottom-left counter text --- bottomLeftCounterTxt = new Text2('150', { size: 100, fill: 0x8B4513 }); bottomLeftCounterTxt.anchor.set(0, 1); LK.gui.bottomLeft.addChild(bottomLeftCounterTxt); // --- Skeleton health bar text --- skeletonHealthTxt = new Text2('ENES BATUR: 1000', { size: 80, fill: 0xFF0000 }); skeletonHealthTxt.anchor.set(0, 0.5); skeletonHealthTxt.visible = false; // Initially hidden until special scene game.addChild(skeletonHealthTxt); // --- Helper functions --- function getRandomTreeX() { return TREE_MIN_X + Math.floor(Math.random() * (TREE_MAX_X - TREE_MIN_X)); } function getRandomTreeY() { return TREE_MIN_Y + Math.floor(Math.random() * (TREE_MAX_Y - TREE_MIN_Y)); } function updateScoreText() { scoreTxt.setText(score); } function updateCountdownText() { countdownTxt.setText(countdownTimer); } function updateUpwardCounterText() { upwardCounterTxt.setText(upwardCounter); } function updateBottomLeftCounterText() { bottomLeftCounterTxt.setText(bottomLeftCounter); } function updateSkeletonHealthText() { skeletonHealthTxt.setText('ENES BATUR: ' + skeletonHealth); } function spawnNewTree() { var newTree; // Spawn purple tree every 40 normal trees (1 in 40 chance) purpleTreeCounter++; if (purpleTreeCounter >= 40) { newTree = new PurpleTree(); purpleTreeCounter = 0; // Reset counter } else if (treesHitThisRound % 5 === 0 && !goldenTreeSpawned) { // Spawn golden tree once every 5 hits if not already spawned this round newTree = new GoldenTree(); goldenTreeSpawned = true; } else { newTree = new Tree(); // Reset golden tree availability after 10 hits if (treesHitThisRound >= 10) { goldenTreeSpawned = false; treesHitThisRound = 0; } } // Position new tree randomly (avoid placing too close to car and existing poles) var tries = 0; var validPosition = false; do { newTree.x = getRandomTreeX(); newTree.y = getRandomTreeY(); tries++; validPosition = true; // Check distance from car if (distance(car.x, car.y, newTree.x, newTree.y) < 300) { validPosition = false; } // Check distance from all existing poles for (var p = 0; p < poles.length; p++) { if (distance(newTree.x, newTree.y, poles[p].x, poles[p].y) < 200) { validPosition = false; break; } } // Check distance from all existing trees for (var t = 0; t < trees.length; t++) { if (distance(newTree.x, newTree.y, trees[t].x, trees[t].y) < 200) { validPosition = false; break; } } } while (!validPosition && tries < 20); trees.push(newTree); lastIntersecting.push(false); game.addChild(newTree); // Calculate current round based on score (every 50 points is a new round) var currentRound = Math.floor(score / 50); var polesPerRound = Math.max(1, 5 - currentRound); // Start with 5, decrease by 1 each round, minimum 1 // Spawn poles (decreasing each round) if (polesSpawnedThisRound < polesPerRound) { var newPole = new Pole(); var tries = 0; var validPolePosition = false; do { newPole.x = getRandomTreeX(); newPole.y = getRandomTreeY(); tries++; validPolePosition = true; // Check distance from car if (distance(car.x, car.y, newPole.x, newPole.y) < 300) { validPolePosition = false; } // Check distance from all existing trees for (var t = 0; t < trees.length; t++) { if (distance(newPole.x, newPole.y, trees[t].x, trees[t].y) < 200) { validPolePosition = false; break; } } // Check distance from all existing poles for (var p = 0; p < poles.length; p++) { if (distance(newPole.x, newPole.y, poles[p].x, poles[p].y) < 200) { validPolePosition = false; break; } } } while (!validPolePosition && tries < 20); poles.push(newPole); lastIntersectingPoles.push(false); game.addChild(newPole); polesSpawnedThisRound++; } // Reset pole counter when round is complete if (polesSpawnedThisRound >= polesPerRound && treesHitThisRound >= 10) { polesSpawnedThisRound = 0; } } // --- Move handler for dragging car --- function handleMove(x, y, obj) { if (dragNode) { var newX = x; var newY = Math.max(200, Math.min(2732 - 100, y)); // Screen wrapping for X axis if (newX > 2048) { newX = 0; // Car exits right, appears on left } else if (newX < 0) { newX = 2048; // Car exits left, appears on right } dragNode.x = newX; dragNode.y = newY; } // Collision detection for all trees for (var i = 0; i < trees.length; i++) { var tree = trees[i]; var currentIntersecting = car.intersects(tree); if (!lastIntersecting[i] && currentIntersecting) { // Car just hit tree score += tree.pointValue; treesHitThisRound++; updateScoreText(); // Update bottom-left counter bottomLeftCounter -= tree.pointValue; if (bottomLeftCounter <= 0) { bottomLeftCounter = 0; bottomLeftCounterTxt.visible = false; } updateBottomLeftCounterText(); // Animate car and tree car.flash(); tree.hitAnim(); // Remove the hit tree game.removeChild(tree); trees.splice(i, 1); lastIntersecting.splice(i, 1); i--; // Adjust index since we removed an element // Spawn new tree (normal or golden based on conditions) spawnNewTree(); // Win condition if (score >= WIN_SCORE) { LK.showYouWin(); } } if (i >= 0 && i < lastIntersecting.length) { lastIntersecting[i] = currentIntersecting; } } // Collision detection for all poles for (var j = 0; j < poles.length; j++) { var pole = poles[j]; var currentIntersectingPole = car.intersects(pole); if (!lastIntersectingPoles[j] && currentIntersectingPole) { // Car just hit pole score += pole.pointValue; // This will subtract 10 points updateScoreText(); // Update bottom-left counter (increase by the amount of points lost) bottomLeftCounter += Math.abs(pole.pointValue); updateBottomLeftCounterText(); // Animate car and pole car.flash(); pole.hitAnim(); // Remove the hit pole game.removeChild(pole); poles.splice(j, 1); lastIntersectingPoles.splice(j, 1); j--; // Adjust index since we removed an element // Check for game over (negative score) if (score < 0) { // Show "eziksin" message for losing with negative score var loserText = new Text2('eziksin', { size: 300, fill: 0x000000 // Black color }); loserText.anchor.set(0.5, 0.5); loserText.x = 2048 / 2; loserText.y = 2732 / 2; game.addChild(loserText); // Show message for 2 seconds before game over LK.setTimeout(function () { LK.showGameOver(); }, 2000); } } if (j >= 0 && j < lastIntersectingPoles.length) { lastIntersectingPoles[j] = currentIntersectingPole; } } } // --- Utility: distance between two points --- function distance(x1, y1, x2, y2) { var dx = x1 - x2; var dy = y1 - y2; return Math.sqrt(dx * dx + dy * dy); } // --- Touch/drag events --- game.down = function (x, y, obj) { // Only start drag if touch is on car (within 120px radius) var dx = x - car.x; var dy = y - car.y; if (dx * dx + dy * dy < 120 * 120) { dragNode = car; handleMove(x, y, obj); } }; game.move = handleMove; game.up = function (x, y, obj) { dragNode = null; }; // --- Game update loop (not needed for movement, but for future extensibility) --- game.update = function () { // Check for special scene transition (150+ score) if (score >= 150 && !specialScene) { specialScene = true; // Clear existing game elements for (var i = trees.length - 1; i >= 0; i--) { game.removeChild(trees[i]); } trees = []; lastIntersecting = []; for (var j = poles.length - 1; j >= 0; j--) { game.removeChild(poles[j]); } poles = []; lastIntersectingPoles = []; // Change background to darker for special scene game.setBackgroundColor(0x2F4F4F); // Dark gray } // Handle special scene logic if (specialScene && !specialSceneInitialized) { // Initialize special scene throwingMan = new ThrowingMan(); throwingMan.x = 2048 / 2; throwingMan.y = 200; game.addChild(throwingMan); // Show and position skeleton health bar skeletonHealthTxt.visible = true; skeletonHealthTxt.x = throwingMan.x + 100; // Position to the right of skeleton skeletonHealthTxt.y = throwingMan.y; skeletonHealth = 1000; // Reset health updateSkeletonHealthText(); // Spawn weapon immediately in special scene if (!weaponSpawned) { weapon = new Weapon(); weapon.x = Math.random() * (2048 - 200) + 100; // Random X within game bounds weapon.y = Math.random() * (2732 - 400) + 200; // Random Y within game bounds game.addChild(weapon); weaponSpawned = true; } specialSceneInitialized = true; } if (specialScene) { // Initialize following start time when first entering special scene if (followingStartTime === null) { followingStartTime = Date.now(); } // Spawn deadly trees that follow player for 10 seconds, then disappear if (LK.ticks % 120 === 0 && deadlyTrees.length < 10 && !allFollowingTreesGone) { var newDeadlyTree = new DeadlyTree(); newDeadlyTree.x = Math.random() * 2048; newDeadlyTree.y = -100; // Start above screen newDeadlyTree.spawnTime = Date.now(); newDeadlyTree.startFollowing(); deadlyTrees.push(newDeadlyTree); lastIntersectingDeadly.push(false); game.addChild(newDeadlyTree); // Set timer to make tree disappear after 10 seconds LK.setTimeout(function () { if (newDeadlyTree.parent) { newDeadlyTree.stopFollowing(); var index = deadlyTrees.indexOf(newDeadlyTree); if (index !== -1) { deadlyTrees.splice(index, 1); lastIntersectingDeadly.splice(index, 1); } // Check if all deadly trees are gone if (deadlyTrees.length === 0 && !allFollowingTreesGone) { allFollowingTreesGone = true; // Show message near the throwing man var messageText = new Text2('O zaman bunu al', { size: 80, fill: 0xFFFFFF }); messageText.anchor.set(0.5, 0.5); messageText.x = throwingMan.x; messageText.y = throwingMan.y - 100; game.addChild(messageText); // Spawn weapon at random location if (!weaponSpawned) { weapon = new Weapon(); weapon.x = Math.random() * (2048 - 200) + 100; // Random X within game bounds weapon.y = Math.random() * (2732 - 400) + 200; // Random Y within game bounds game.addChild(weapon); weaponSpawned = true; } } } }, 10000); } // Check collision with deadly trees for (var k = deadlyTrees.length - 1; k >= 0; k--) { var deadlyTree = deadlyTrees[k]; var currentIntersectingDeadly = car.intersects(deadlyTree); // Check if tree has been alive for 10 seconds if (deadlyTree.spawnTime && Date.now() - deadlyTree.spawnTime >= 10000) { deadlyTree.stopFollowing(); deadlyTrees.splice(k, 1); lastIntersectingDeadly.splice(k, 1); // Check if all deadly trees are gone if (deadlyTrees.length === 0 && !allFollowingTreesGone) { allFollowingTreesGone = true; // Show message near the throwing man var messageText = new Text2('O zaman bunu al', { size: 80, fill: 0xFFFFFF }); messageText.anchor.set(0.5, 0.5); messageText.x = throwingMan.x; messageText.y = throwingMan.y - 100; // Position above the throwing man game.addChild(messageText); // Spawn weapon at random location if (!weaponSpawned) { weapon = new Weapon(); weapon.x = Math.random() * (2048 - 200) + 100; // Random X within game bounds weapon.y = Math.random() * (2732 - 400) + 200; // Random Y within game bounds game.addChild(weapon); weaponSpawned = true; } } continue; } // Check if tree went off screen (only for non-following trees) if (!deadlyTree.isFollowing && deadlyTree.y > 2732 + 100) { game.removeChild(deadlyTree); deadlyTrees.splice(k, 1); lastIntersectingDeadly.splice(k, 1); continue; } // Check collision - instant death if (!lastIntersectingDeadly[k] && currentIntersectingDeadly) { // Show death message var deathText = new Text2('ÖLDÜN!', { size: 300, fill: 0xFF0000 }); deathText.anchor.set(0.5, 0.5); deathText.x = 2048 / 2; deathText.y = 2732 / 2; game.addChild(deathText); // Show message for 2 seconds before game over LK.setTimeout(function () { LK.showGameOver(); }, 2000); return; } if (k < lastIntersectingDeadly.length) { lastIntersectingDeadly[k] = currentIntersectingDeadly; } } // Check weapon collision and bullet firing if (weapon && throwingMan) { var currentIntersectingWeapon = car.intersects(weapon); if (!lastIntersectingWeapon && currentIntersectingWeapon) { // Car touched weapon, make weapon follow car weapon.isFollowingCar = true; // Fire bullet at skeleton var newBullet = new Bullet(); newBullet.x = car.x; newBullet.y = car.y; newBullet.targetX = throwingMan.x; newBullet.targetY = throwingMan.y; bullets.push(newBullet); game.addChild(newBullet); } lastIntersectingWeapon = currentIntersectingWeapon; // Make weapon follow car if attached if (weapon.isFollowingCar) { weapon.x = car.x + 60; // Offset to the right of car weapon.y = car.y; } } // Check bullet collisions with skeleton for (var b = bullets.length - 1; b >= 0; b--) { var bullet = bullets[b]; if (throwingMan && bullet.intersects && bullet.intersects(throwingMan)) { // Bullet hit skeleton - reduce health skeletonHealth -= 5; updateSkeletonHealthText(); // Remove bullet game.removeChild(bullet); bullets.splice(b, 1); // Flash skeleton red when hit tween(throwingMan, { tint: 0xFF0000 }, { duration: 200, onFinish: function onFinish() { tween(throwingMan, { tint: 0xFFFFFF }, { duration: 200 }); } }); // Check if skeleton is defeated if (skeletonHealth <= 0) { // Hide health bar skeletonHealthTxt.visible = false; // Show victory message var victoryText = new Text2('Enes batur yenildi', { size: 200, fill: 0x00FF00 }); victoryText.anchor.set(0.5, 0.5); victoryText.x = 2048 / 2; victoryText.y = 2732 / 2; game.addChild(victoryText); // Show victory for 3 seconds then transition to fourth scene LK.setTimeout(function () { // Clear special scene elements game.removeChild(victoryText); if (throwingMan) { game.removeChild(throwingMan); throwingMan = null; } if (weapon) { game.removeChild(weapon); weapon = null; weaponSpawned = false; } // Clear bullets for (var b = bullets.length - 1; b >= 0; b--) { game.removeChild(bullets[b]); } bullets = []; // Clear deadly trees for (var d = deadlyTrees.length - 1; d >= 0; d--) { game.removeChild(deadlyTrees[d]); } deadlyTrees = []; lastIntersectingDeadly = []; // Transition to fourth scene with 6 skeletons specialScene = false; specialSceneInitialized = false; fourthScene = true; fourthSceneInitialized = false; game.setBackgroundColor(0x4B0082); // Dark purple background for fourth scene }, 3000); } } } } // Only run countdown timer logic if not in special scene if (!specialScene) { // Check if player hit something (score changed) var scoreChanged = score !== lastScore; if (scoreChanged) { // Player hit something, reset countdown countdownTimer = 10; updateCountdownText(); } else { // Player didn't hit anything, countdown every second (60 ticks = 1 second) if (LK.ticks % 60 === 0) { countdownTimer--; updateCountdownText(); if (countdownTimer <= 0) { if (score < 10) { // Show F- grade for low score var gradeText = new Text2('F-', { size: 300, fill: 0xFF0000 }); gradeText.anchor.set(0.5, 0.5); gradeText.x = 2048 / 2; gradeText.y = 2732 / 2; game.addChild(gradeText); // Show grade for 2 seconds before game over LK.setTimeout(function () { LK.showGameOver(); }, 2000); } else if (score >= 10 && score <= 30) { // Show F+ grade for score between 10 and 30 var gradeText = new Text2('F+', { size: 300, fill: 0xFFA500 }); gradeText.anchor.set(0.5, 0.5); gradeText.x = 2048 / 2; gradeText.y = 2732 / 2; game.addChild(gradeText); // Show grade for 2 seconds before game over LK.setTimeout(function () { LK.showGameOver(); }, 2000); } else if (score >= 30 && score <= 50) { // Show D- grade for score between 30 and 50 var gradeText = new Text2('D-', { size: 300, fill: 0x800080 }); gradeText.anchor.set(0.5, 0.5); gradeText.x = 2048 / 2; gradeText.y = 2732 / 2; game.addChild(gradeText); // Show grade for 2 seconds before game over LK.setTimeout(function () { LK.showGameOver(); }, 2000); } else { LK.showGameOver(); } } } } } // Only run upward counter logic if not in special scene if (!specialScene) { // Upward counter increments every second (60 ticks = 1 second) if (LK.ticks % 60 === 0) { upwardCounter++; updateUpwardCounterText(); if (upwardCounter >= 90) { if (score < 10) { // Show F- grade for low score var gradeText = new Text2('F-', { size: 300, fill: 0xFF0000 }); gradeText.anchor.set(0.5, 0.5); gradeText.x = 2048 / 2; gradeText.y = 2732 / 2; game.addChild(gradeText); // Show grade for 2 seconds before game over LK.setTimeout(function () { LK.showGameOver(); }, 2000); } else if (score >= 10 && score <= 30) { // Show F+ grade for score between 10 and 30 var gradeText = new Text2('F+', { size: 300, fill: 0xFFA500 }); gradeText.anchor.set(0.5, 0.5); gradeText.x = 2048 / 2; gradeText.y = 2732 / 2; game.addChild(gradeText); // Show grade for 2 seconds before game over LK.setTimeout(function () { LK.showGameOver(); }, 2000); } else if (score >= 30 && score <= 50) { // Show D- grade for score between 30 and 50 var gradeText = new Text2('D-', { size: 300, fill: 0x800080 }); gradeText.anchor.set(0.5, 0.5); gradeText.x = 2048 / 2; gradeText.y = 2732 / 2; game.addChild(gradeText); // Show grade for 2 seconds before game over LK.setTimeout(function () { LK.showGameOver(); }, 2000); } else { LK.showGameOver(); } } } } // Handle fourth scene logic if (fourthScene && !fourthSceneInitialized) { // Initialize fourth scene with 6 skeletons for (var s = 0; s < 6; s++) { var skeleton = new MultiSkeleton(); // Position skeletons in two rows if (s < 3) { skeleton.x = (s + 1) * (2048 / 4); skeleton.y = 200; } else { skeleton.x = (s - 2) * (2048 / 4); skeleton.y = 400; } multiSkeletons.push(skeleton); game.addChild(skeleton); } fourthSceneInitialized = true; } if (fourthScene) { // Check collisions with thrown trees for (var ft = fourthSceneTrees.length - 1; ft >= 0; ft--) { var thrownTree = fourthSceneTrees[ft]; var currentIntersectingFourth = car.intersects(thrownTree); if (!lastIntersectingFourthTrees[ft] && currentIntersectingFourth) { // Check if it's a deadly tree or point tree if (thrownTree.tint === 0xFF0000) { // Deadly tree - instant death var deathText = new Text2('ÖLDÜN!', { size: 300, fill: 0xFF0000 }); deathText.anchor.set(0.5, 0.5); deathText.x = 2048 / 2; deathText.y = 2732 / 2; game.addChild(deathText); // Show message for 2 seconds before game over LK.setTimeout(function () { LK.showGameOver(); }, 2000); return; } else { // Point tree - add points score += thrownTree.pointValue || 1; updateScoreText(); car.flash(); thrownTree.hitAnim(); // Remove the hit tree game.removeChild(thrownTree); fourthSceneTrees.splice(ft, 1); lastIntersectingFourthTrees.splice(ft, 1); // Check win condition for fourth scene if (score >= 400) { LK.showYouWin(); return; } } } if (ft < lastIntersectingFourthTrees.length) { lastIntersectingFourthTrees[ft] = currentIntersectingFourth; } } } // Update tracking variables lastCarX = car.x; lastCarY = car.y; lastScore = score; }; // --- Initialize score --- score = 0; updateScoreText(); // --- Initialize upward counter --- upwardCounter = 1; updateUpwardCounterText(); // --- Initialize bottom-left counter --- bottomLeftCounter = 150; updateBottomLeftCounterText(); // --- Initialize tracking variables --- lastCarX = car.x; lastCarY = car.y; lastScore = score;
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet class for weapon projectiles
var Bullet = Container.expand(function () {
var self = Container.call(this);
// Create bullet visual (small circle)
var bulletAsset = self.attachAsset('manCircle', {
anchorX: 0.5,
anchorY: 0.5
});
bulletAsset.width = 20;
bulletAsset.height = 20;
bulletAsset.tint = 0xFFFF00; // Yellow color for bullet
self.speed = 12;
self.targetX = 0;
self.targetY = 0;
// Update method for bullet movement towards target
self.update = function () {
// Move towards target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
// Remove bullet if it reaches target or goes off screen
if (distance < 30 || self.x < -100 || self.x > 2148 || self.y < -100 || self.y > 2832) {
if (self.parent) {
self.parent.removeChild(self);
}
var index = bullets.indexOf(self);
if (index !== -1) {
bullets.splice(index, 1);
}
}
};
return self;
});
// Car class
var Car = Container.expand(function () {
var self = Container.call(this);
// Attach car asset (red box, 200x120)
var carAsset = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 0.5
});
// Set size for car asset
carAsset.width = 200;
carAsset.height = 120;
// For touch feedback
self.flash = function () {
tween(self, {
alpha: 0.5
}, {
duration: 80,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: 120
});
}
});
};
return self;
});
// DeadlyTree class for special scene
var DeadlyTree = Container.expand(function () {
var self = Container.call(this);
// Attach tree asset (red tinted, 100x100)
var treeAsset = self.attachAsset('tree', {
anchorX: 0.5,
anchorY: 0.5
});
treeAsset.width = 100;
treeAsset.height = 100;
treeAsset.tint = 0xFF0000; // Red tint for deadly trees
self.speed = 24; // Falling speed (3x faster)
self.isFollowing = false;
self.followSpeed = 8; // Speed when following player
// Start following the player
self.startFollowing = function () {
self.isFollowing = true;
};
// Stop following and disappear with tween
self.stopFollowing = function () {
self.isFollowing = false;
tween(self, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
}
}
});
};
// Update method for falling motion or following
self.update = function () {
if (self.isFollowing && car) {
// Move towards car position
var dx = car.x - self.x;
var dy = car.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
self.x += dx / distance * self.followSpeed;
self.y += dy / distance * self.followSpeed;
}
} else {
self.y += self.speed;
}
};
return self;
});
// GoldenTree class
var GoldenTree = Container.expand(function () {
var self = Container.call(this);
// Attach tree asset (golden, 140x140 - slightly bigger)
var treeAsset = self.attachAsset('tree', {
anchorX: 0.5,
anchorY: 0.5
});
treeAsset.width = 140;
treeAsset.height = 140;
treeAsset.tint = 0xFFD700; // Golden tint color
self.pointValue = 10; // Golden tree gives 10 points
// Add golden glow effect
self.glowEffect = function () {
tween(self, {
alpha: 0.7
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.glowEffect(); // Loop the glow effect
}
});
}
});
};
// Start glow effect immediately
self.glowEffect();
// Special golden hit animation
self.hitAnim = function () {
tween(self, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeIn
});
}
});
};
return self;
});
// MultiSkeleton class for fourth scene
var MultiSkeleton = Container.expand(function () {
var self = Container.call(this);
// Create circular shape for the skeleton
var skeletonAsset = self.attachAsset('manCircle', {
anchorX: 0.5,
anchorY: 0.5
});
skeletonAsset.tint = 0x800080; // Purple tint for skeletons
self.throwTimer = 0;
self.throwInterval = 60; // Fixed 1 second interval (60 ticks)
// Update method for throwing trees
self.update = function () {
self.throwTimer++;
if (self.throwTimer >= self.throwInterval) {
// Throw either deadly tree or point tree randomly
var isDeadly = Math.random() < 0.5; // 50% chance for deadly tree
var thrownTree;
if (isDeadly) {
thrownTree = new DeadlyTree();
} else {
thrownTree = new Tree();
}
// Find valid position that doesn't overlap with existing trees
var validPosition = false;
var tries = 0;
var targetX, targetY;
do {
targetX = self.x + (Math.random() - 0.5) * 400; // Random position around skeleton
targetY = self.y + 50 + Math.random() * 200;
validPosition = true;
tries++;
// Check distance from all existing fourth scene trees
for (var ft = 0; ft < fourthSceneTrees.length; ft++) {
var existingTree = fourthSceneTrees[ft];
var dx = targetX - existingTree.x;
var dy = targetY - existingTree.y;
var distanceToTree = Math.sqrt(dx * dx + dy * dy);
if (distanceToTree < 150) {
// Minimum distance of 150 pixels
validPosition = false;
break;
}
}
} while (!validPosition && tries < 10);
thrownTree.x = self.x;
thrownTree.y = self.y + 50;
// Set target towards calculated position
thrownTree.targetX = targetX;
thrownTree.targetY = targetY;
thrownTree.speed = 8;
thrownTree.isThrown = true;
// Override update to move towards target
thrownTree.update = function () {
if (thrownTree.isThrown) {
var dx = thrownTree.targetX - thrownTree.x;
var dy = thrownTree.targetY - thrownTree.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
thrownTree.x += dx / distance * thrownTree.speed;
thrownTree.y += dy / distance * thrownTree.speed;
}
// Remove if goes off screen
if (thrownTree.x < -100 || thrownTree.x > 2148 || thrownTree.y < -100 || thrownTree.y > 2832) {
if (thrownTree.parent) {
thrownTree.parent.removeChild(thrownTree);
}
var index = fourthSceneTrees.indexOf(thrownTree);
if (index !== -1) {
fourthSceneTrees.splice(index, 1);
lastIntersectingFourthTrees.splice(index, 1);
}
}
}
};
fourthSceneTrees.push(thrownTree);
lastIntersectingFourthTrees.push(false);
game.addChild(thrownTree);
self.throwTimer = 0;
self.throwInterval = 60; // Reset to 1 second interval
}
};
return self;
});
// Pole class
var Pole = Container.expand(function () {
var self = Container.call(this);
// Attach pole asset (thin metal pole, 30x300)
var poleAsset = self.attachAsset('pole', {
anchorX: 0.5,
anchorY: 0.5
});
self.pointValue = -10; // Pole reduces 10 points
// Animate on hit (shake effect)
self.hitAnim = function () {
tween(self, {
rotation: 0.2
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
rotation: -0.2
}, {
duration: 80,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
rotation: 0
}, {
duration: 80,
easing: tween.easeIn
});
}
});
}
});
};
return self;
});
// PurpleTree class
var PurpleTree = Container.expand(function () {
var self = Container.call(this);
// Attach tree asset (purple, 140x140 - slightly bigger)
var treeAsset = self.attachAsset('tree', {
anchorX: 0.5,
anchorY: 0.5
});
treeAsset.width = 140;
treeAsset.height = 140;
treeAsset.tint = 0x8A2BE2; // Purple tint color
self.pointValue = 30; // Purple tree gives 30 points
// Add purple glow effect
self.glowEffect = function () {
tween(self, {
alpha: 0.6
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.glowEffect(); // Loop the glow effect
}
});
}
});
};
// Start glow effect immediately
self.glowEffect();
// Special purple hit animation
self.hitAnim = function () {
tween(self, {
scaleX: 1.6,
scaleY: 1.6
}, {
duration: 180,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 180,
easing: tween.easeIn
});
}
});
};
return self;
});
// ThrowingMan class for special scene
var ThrowingMan = Container.expand(function () {
var self = Container.call(this);
// Create circular shape for the man
var manAsset = self.attachAsset('manCircle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Tree class
var Tree = Container.expand(function () {
var self = Container.call(this);
// Attach tree asset (green ellipse, 120x120)
var treeAsset = self.attachAsset('tree', {
anchorX: 0.5,
anchorY: 0.5
});
treeAsset.width = 120;
treeAsset.height = 120;
treeAsset.tint = 0x228B22;
self.pointValue = 1; // Normal tree gives 1 point
// Animate on hit
self.hitAnim = function () {
tween(self, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 120,
easing: tween.easeIn
});
}
});
};
return self;
});
// Weapon class for special scene
var Weapon = Container.expand(function () {
var self = Container.call(this);
// Create weapon visual using weapon image asset
var weaponAsset = self.attachAsset('weapon', {
anchorX: 0.5,
anchorY: 0.5
});
weaponAsset.rotation = Math.PI / 4; // 45 degree rotation
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// --- Game constants ---
var CAR_START_X = 2048 / 2;
var CAR_START_Y = 2732 - 350;
var TREE_MIN_Y = 350;
var TREE_MAX_Y = 2732 - 350;
var TREE_MIN_X = 150;
var TREE_MAX_X = 2048 - 150;
var WIN_SCORE = 100000000;
// --- Game state ---
var car = null;
var trees = [];
var poles = [];
var score = 0;
var scoreTxt = null;
var dragNode = null;
var lastIntersecting = [];
var lastIntersectingPoles = [];
var goldenTreeSpawned = false;
var treesHitThisRound = 0;
var purpleTreeCounter = 0;
var polesSpawnedThisRound = 0;
var countdownTimer = 10;
var countdownTxt = null;
var lastCarX = 0;
var lastCarY = 0;
var lastScore = 0;
var upwardCounter = 1;
var upwardCounterTxt = null;
var specialScene = false;
var specialSceneInitialized = false;
var throwingMan = null;
var deadlyTrees = [];
var lastIntersectingDeadly = [];
var throwTimer = 0;
var followingStartTime = null;
var followingDuration = 10000; // 10 seconds in milliseconds
var allFollowingTreesGone = false; // Flag to track if all following trees have disappeared
var bottomLeftCounter = 150;
var bottomLeftCounterTxt = null;
var weapon = null;
var weaponSpawned = false;
var bullets = [];
var lastIntersectingWeapon = false;
var skeletonHealth = 1000;
var skeletonHealthTxt = null;
var fourthScene = false;
var fourthSceneInitialized = false;
var multiSkeletons = [];
var fourthSceneTrees = [];
var lastIntersectingFourthTrees = [];
// --- Create and add car ---
car = new Car();
car.x = CAR_START_X;
car.y = CAR_START_Y;
game.addChild(car);
// --- Create and add trees ---
for (var i = 0; i < 5; i++) {
var tree = new Tree();
tree.x = getRandomTreeX();
tree.y = getRandomTreeY();
trees.push(tree);
lastIntersecting.push(false);
game.addChild(tree);
}
// --- Create and add poles ---
for (var i = 0; i < 5; i++) {
var pole = new Pole();
var tries = 0;
var validPosition = false;
do {
pole.x = getRandomTreeX();
pole.y = getRandomTreeY();
tries++;
validPosition = true;
// Check distance from car
if (distance(car.x, car.y, pole.x, pole.y) < 300) {
validPosition = false;
}
// Check distance from all existing trees
for (var t = 0; t < trees.length; t++) {
if (distance(pole.x, pole.y, trees[t].x, trees[t].y) < 200) {
validPosition = false;
break;
}
}
// Check distance from all existing poles
for (var p = 0; p < poles.length; p++) {
if (distance(pole.x, pole.y, poles[p].x, poles[p].y) < 200) {
validPosition = false;
break;
}
}
} while (!validPosition && tries < 20);
poles.push(pole);
lastIntersectingPoles.push(false);
game.addChild(pole);
}
// --- Score text ---
scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// --- Countdown timer text ---
countdownTxt = new Text2('10', {
size: 100,
fill: 0xFF0000
});
countdownTxt.anchor.set(1, 1);
LK.gui.bottomRight.addChild(countdownTxt);
// --- Upward counter text ---
upwardCounterTxt = new Text2('1', {
size: 100,
fill: 0x006400
});
upwardCounterTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(upwardCounterTxt);
// --- Bottom-left counter text ---
bottomLeftCounterTxt = new Text2('150', {
size: 100,
fill: 0x8B4513
});
bottomLeftCounterTxt.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(bottomLeftCounterTxt);
// --- Skeleton health bar text ---
skeletonHealthTxt = new Text2('ENES BATUR: 1000', {
size: 80,
fill: 0xFF0000
});
skeletonHealthTxt.anchor.set(0, 0.5);
skeletonHealthTxt.visible = false; // Initially hidden until special scene
game.addChild(skeletonHealthTxt);
// --- Helper functions ---
function getRandomTreeX() {
return TREE_MIN_X + Math.floor(Math.random() * (TREE_MAX_X - TREE_MIN_X));
}
function getRandomTreeY() {
return TREE_MIN_Y + Math.floor(Math.random() * (TREE_MAX_Y - TREE_MIN_Y));
}
function updateScoreText() {
scoreTxt.setText(score);
}
function updateCountdownText() {
countdownTxt.setText(countdownTimer);
}
function updateUpwardCounterText() {
upwardCounterTxt.setText(upwardCounter);
}
function updateBottomLeftCounterText() {
bottomLeftCounterTxt.setText(bottomLeftCounter);
}
function updateSkeletonHealthText() {
skeletonHealthTxt.setText('ENES BATUR: ' + skeletonHealth);
}
function spawnNewTree() {
var newTree;
// Spawn purple tree every 40 normal trees (1 in 40 chance)
purpleTreeCounter++;
if (purpleTreeCounter >= 40) {
newTree = new PurpleTree();
purpleTreeCounter = 0; // Reset counter
} else if (treesHitThisRound % 5 === 0 && !goldenTreeSpawned) {
// Spawn golden tree once every 5 hits if not already spawned this round
newTree = new GoldenTree();
goldenTreeSpawned = true;
} else {
newTree = new Tree();
// Reset golden tree availability after 10 hits
if (treesHitThisRound >= 10) {
goldenTreeSpawned = false;
treesHitThisRound = 0;
}
}
// Position new tree randomly (avoid placing too close to car and existing poles)
var tries = 0;
var validPosition = false;
do {
newTree.x = getRandomTreeX();
newTree.y = getRandomTreeY();
tries++;
validPosition = true;
// Check distance from car
if (distance(car.x, car.y, newTree.x, newTree.y) < 300) {
validPosition = false;
}
// Check distance from all existing poles
for (var p = 0; p < poles.length; p++) {
if (distance(newTree.x, newTree.y, poles[p].x, poles[p].y) < 200) {
validPosition = false;
break;
}
}
// Check distance from all existing trees
for (var t = 0; t < trees.length; t++) {
if (distance(newTree.x, newTree.y, trees[t].x, trees[t].y) < 200) {
validPosition = false;
break;
}
}
} while (!validPosition && tries < 20);
trees.push(newTree);
lastIntersecting.push(false);
game.addChild(newTree);
// Calculate current round based on score (every 50 points is a new round)
var currentRound = Math.floor(score / 50);
var polesPerRound = Math.max(1, 5 - currentRound); // Start with 5, decrease by 1 each round, minimum 1
// Spawn poles (decreasing each round)
if (polesSpawnedThisRound < polesPerRound) {
var newPole = new Pole();
var tries = 0;
var validPolePosition = false;
do {
newPole.x = getRandomTreeX();
newPole.y = getRandomTreeY();
tries++;
validPolePosition = true;
// Check distance from car
if (distance(car.x, car.y, newPole.x, newPole.y) < 300) {
validPolePosition = false;
}
// Check distance from all existing trees
for (var t = 0; t < trees.length; t++) {
if (distance(newPole.x, newPole.y, trees[t].x, trees[t].y) < 200) {
validPolePosition = false;
break;
}
}
// Check distance from all existing poles
for (var p = 0; p < poles.length; p++) {
if (distance(newPole.x, newPole.y, poles[p].x, poles[p].y) < 200) {
validPolePosition = false;
break;
}
}
} while (!validPolePosition && tries < 20);
poles.push(newPole);
lastIntersectingPoles.push(false);
game.addChild(newPole);
polesSpawnedThisRound++;
}
// Reset pole counter when round is complete
if (polesSpawnedThisRound >= polesPerRound && treesHitThisRound >= 10) {
polesSpawnedThisRound = 0;
}
}
// --- Move handler for dragging car ---
function handleMove(x, y, obj) {
if (dragNode) {
var newX = x;
var newY = Math.max(200, Math.min(2732 - 100, y));
// Screen wrapping for X axis
if (newX > 2048) {
newX = 0; // Car exits right, appears on left
} else if (newX < 0) {
newX = 2048; // Car exits left, appears on right
}
dragNode.x = newX;
dragNode.y = newY;
}
// Collision detection for all trees
for (var i = 0; i < trees.length; i++) {
var tree = trees[i];
var currentIntersecting = car.intersects(tree);
if (!lastIntersecting[i] && currentIntersecting) {
// Car just hit tree
score += tree.pointValue;
treesHitThisRound++;
updateScoreText();
// Update bottom-left counter
bottomLeftCounter -= tree.pointValue;
if (bottomLeftCounter <= 0) {
bottomLeftCounter = 0;
bottomLeftCounterTxt.visible = false;
}
updateBottomLeftCounterText();
// Animate car and tree
car.flash();
tree.hitAnim();
// Remove the hit tree
game.removeChild(tree);
trees.splice(i, 1);
lastIntersecting.splice(i, 1);
i--; // Adjust index since we removed an element
// Spawn new tree (normal or golden based on conditions)
spawnNewTree();
// Win condition
if (score >= WIN_SCORE) {
LK.showYouWin();
}
}
if (i >= 0 && i < lastIntersecting.length) {
lastIntersecting[i] = currentIntersecting;
}
}
// Collision detection for all poles
for (var j = 0; j < poles.length; j++) {
var pole = poles[j];
var currentIntersectingPole = car.intersects(pole);
if (!lastIntersectingPoles[j] && currentIntersectingPole) {
// Car just hit pole
score += pole.pointValue; // This will subtract 10 points
updateScoreText();
// Update bottom-left counter (increase by the amount of points lost)
bottomLeftCounter += Math.abs(pole.pointValue);
updateBottomLeftCounterText();
// Animate car and pole
car.flash();
pole.hitAnim();
// Remove the hit pole
game.removeChild(pole);
poles.splice(j, 1);
lastIntersectingPoles.splice(j, 1);
j--; // Adjust index since we removed an element
// Check for game over (negative score)
if (score < 0) {
// Show "eziksin" message for losing with negative score
var loserText = new Text2('eziksin', {
size: 300,
fill: 0x000000 // Black color
});
loserText.anchor.set(0.5, 0.5);
loserText.x = 2048 / 2;
loserText.y = 2732 / 2;
game.addChild(loserText);
// Show message for 2 seconds before game over
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
}
}
if (j >= 0 && j < lastIntersectingPoles.length) {
lastIntersectingPoles[j] = currentIntersectingPole;
}
}
}
// --- Utility: distance between two points ---
function distance(x1, y1, x2, y2) {
var dx = x1 - x2;
var dy = y1 - y2;
return Math.sqrt(dx * dx + dy * dy);
}
// --- Touch/drag events ---
game.down = function (x, y, obj) {
// Only start drag if touch is on car (within 120px radius)
var dx = x - car.x;
var dy = y - car.y;
if (dx * dx + dy * dy < 120 * 120) {
dragNode = car;
handleMove(x, y, obj);
}
};
game.move = handleMove;
game.up = function (x, y, obj) {
dragNode = null;
};
// --- Game update loop (not needed for movement, but for future extensibility) ---
game.update = function () {
// Check for special scene transition (150+ score)
if (score >= 150 && !specialScene) {
specialScene = true;
// Clear existing game elements
for (var i = trees.length - 1; i >= 0; i--) {
game.removeChild(trees[i]);
}
trees = [];
lastIntersecting = [];
for (var j = poles.length - 1; j >= 0; j--) {
game.removeChild(poles[j]);
}
poles = [];
lastIntersectingPoles = [];
// Change background to darker for special scene
game.setBackgroundColor(0x2F4F4F); // Dark gray
}
// Handle special scene logic
if (specialScene && !specialSceneInitialized) {
// Initialize special scene
throwingMan = new ThrowingMan();
throwingMan.x = 2048 / 2;
throwingMan.y = 200;
game.addChild(throwingMan);
// Show and position skeleton health bar
skeletonHealthTxt.visible = true;
skeletonHealthTxt.x = throwingMan.x + 100; // Position to the right of skeleton
skeletonHealthTxt.y = throwingMan.y;
skeletonHealth = 1000; // Reset health
updateSkeletonHealthText();
// Spawn weapon immediately in special scene
if (!weaponSpawned) {
weapon = new Weapon();
weapon.x = Math.random() * (2048 - 200) + 100; // Random X within game bounds
weapon.y = Math.random() * (2732 - 400) + 200; // Random Y within game bounds
game.addChild(weapon);
weaponSpawned = true;
}
specialSceneInitialized = true;
}
if (specialScene) {
// Initialize following start time when first entering special scene
if (followingStartTime === null) {
followingStartTime = Date.now();
}
// Spawn deadly trees that follow player for 10 seconds, then disappear
if (LK.ticks % 120 === 0 && deadlyTrees.length < 10 && !allFollowingTreesGone) {
var newDeadlyTree = new DeadlyTree();
newDeadlyTree.x = Math.random() * 2048;
newDeadlyTree.y = -100; // Start above screen
newDeadlyTree.spawnTime = Date.now();
newDeadlyTree.startFollowing();
deadlyTrees.push(newDeadlyTree);
lastIntersectingDeadly.push(false);
game.addChild(newDeadlyTree);
// Set timer to make tree disappear after 10 seconds
LK.setTimeout(function () {
if (newDeadlyTree.parent) {
newDeadlyTree.stopFollowing();
var index = deadlyTrees.indexOf(newDeadlyTree);
if (index !== -1) {
deadlyTrees.splice(index, 1);
lastIntersectingDeadly.splice(index, 1);
}
// Check if all deadly trees are gone
if (deadlyTrees.length === 0 && !allFollowingTreesGone) {
allFollowingTreesGone = true;
// Show message near the throwing man
var messageText = new Text2('O zaman bunu al', {
size: 80,
fill: 0xFFFFFF
});
messageText.anchor.set(0.5, 0.5);
messageText.x = throwingMan.x;
messageText.y = throwingMan.y - 100;
game.addChild(messageText);
// Spawn weapon at random location
if (!weaponSpawned) {
weapon = new Weapon();
weapon.x = Math.random() * (2048 - 200) + 100; // Random X within game bounds
weapon.y = Math.random() * (2732 - 400) + 200; // Random Y within game bounds
game.addChild(weapon);
weaponSpawned = true;
}
}
}
}, 10000);
}
// Check collision with deadly trees
for (var k = deadlyTrees.length - 1; k >= 0; k--) {
var deadlyTree = deadlyTrees[k];
var currentIntersectingDeadly = car.intersects(deadlyTree);
// Check if tree has been alive for 10 seconds
if (deadlyTree.spawnTime && Date.now() - deadlyTree.spawnTime >= 10000) {
deadlyTree.stopFollowing();
deadlyTrees.splice(k, 1);
lastIntersectingDeadly.splice(k, 1);
// Check if all deadly trees are gone
if (deadlyTrees.length === 0 && !allFollowingTreesGone) {
allFollowingTreesGone = true;
// Show message near the throwing man
var messageText = new Text2('O zaman bunu al', {
size: 80,
fill: 0xFFFFFF
});
messageText.anchor.set(0.5, 0.5);
messageText.x = throwingMan.x;
messageText.y = throwingMan.y - 100; // Position above the throwing man
game.addChild(messageText);
// Spawn weapon at random location
if (!weaponSpawned) {
weapon = new Weapon();
weapon.x = Math.random() * (2048 - 200) + 100; // Random X within game bounds
weapon.y = Math.random() * (2732 - 400) + 200; // Random Y within game bounds
game.addChild(weapon);
weaponSpawned = true;
}
}
continue;
}
// Check if tree went off screen (only for non-following trees)
if (!deadlyTree.isFollowing && deadlyTree.y > 2732 + 100) {
game.removeChild(deadlyTree);
deadlyTrees.splice(k, 1);
lastIntersectingDeadly.splice(k, 1);
continue;
}
// Check collision - instant death
if (!lastIntersectingDeadly[k] && currentIntersectingDeadly) {
// Show death message
var deathText = new Text2('ÖLDÜN!', {
size: 300,
fill: 0xFF0000
});
deathText.anchor.set(0.5, 0.5);
deathText.x = 2048 / 2;
deathText.y = 2732 / 2;
game.addChild(deathText);
// Show message for 2 seconds before game over
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
return;
}
if (k < lastIntersectingDeadly.length) {
lastIntersectingDeadly[k] = currentIntersectingDeadly;
}
}
// Check weapon collision and bullet firing
if (weapon && throwingMan) {
var currentIntersectingWeapon = car.intersects(weapon);
if (!lastIntersectingWeapon && currentIntersectingWeapon) {
// Car touched weapon, make weapon follow car
weapon.isFollowingCar = true;
// Fire bullet at skeleton
var newBullet = new Bullet();
newBullet.x = car.x;
newBullet.y = car.y;
newBullet.targetX = throwingMan.x;
newBullet.targetY = throwingMan.y;
bullets.push(newBullet);
game.addChild(newBullet);
}
lastIntersectingWeapon = currentIntersectingWeapon;
// Make weapon follow car if attached
if (weapon.isFollowingCar) {
weapon.x = car.x + 60; // Offset to the right of car
weapon.y = car.y;
}
}
// Check bullet collisions with skeleton
for (var b = bullets.length - 1; b >= 0; b--) {
var bullet = bullets[b];
if (throwingMan && bullet.intersects && bullet.intersects(throwingMan)) {
// Bullet hit skeleton - reduce health
skeletonHealth -= 5;
updateSkeletonHealthText();
// Remove bullet
game.removeChild(bullet);
bullets.splice(b, 1);
// Flash skeleton red when hit
tween(throwingMan, {
tint: 0xFF0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(throwingMan, {
tint: 0xFFFFFF
}, {
duration: 200
});
}
});
// Check if skeleton is defeated
if (skeletonHealth <= 0) {
// Hide health bar
skeletonHealthTxt.visible = false;
// Show victory message
var victoryText = new Text2('Enes batur yenildi', {
size: 200,
fill: 0x00FF00
});
victoryText.anchor.set(0.5, 0.5);
victoryText.x = 2048 / 2;
victoryText.y = 2732 / 2;
game.addChild(victoryText);
// Show victory for 3 seconds then transition to fourth scene
LK.setTimeout(function () {
// Clear special scene elements
game.removeChild(victoryText);
if (throwingMan) {
game.removeChild(throwingMan);
throwingMan = null;
}
if (weapon) {
game.removeChild(weapon);
weapon = null;
weaponSpawned = false;
}
// Clear bullets
for (var b = bullets.length - 1; b >= 0; b--) {
game.removeChild(bullets[b]);
}
bullets = [];
// Clear deadly trees
for (var d = deadlyTrees.length - 1; d >= 0; d--) {
game.removeChild(deadlyTrees[d]);
}
deadlyTrees = [];
lastIntersectingDeadly = [];
// Transition to fourth scene with 6 skeletons
specialScene = false;
specialSceneInitialized = false;
fourthScene = true;
fourthSceneInitialized = false;
game.setBackgroundColor(0x4B0082); // Dark purple background for fourth scene
}, 3000);
}
}
}
}
// Only run countdown timer logic if not in special scene
if (!specialScene) {
// Check if player hit something (score changed)
var scoreChanged = score !== lastScore;
if (scoreChanged) {
// Player hit something, reset countdown
countdownTimer = 10;
updateCountdownText();
} else {
// Player didn't hit anything, countdown every second (60 ticks = 1 second)
if (LK.ticks % 60 === 0) {
countdownTimer--;
updateCountdownText();
if (countdownTimer <= 0) {
if (score < 10) {
// Show F- grade for low score
var gradeText = new Text2('F-', {
size: 300,
fill: 0xFF0000
});
gradeText.anchor.set(0.5, 0.5);
gradeText.x = 2048 / 2;
gradeText.y = 2732 / 2;
game.addChild(gradeText);
// Show grade for 2 seconds before game over
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
} else if (score >= 10 && score <= 30) {
// Show F+ grade for score between 10 and 30
var gradeText = new Text2('F+', {
size: 300,
fill: 0xFFA500
});
gradeText.anchor.set(0.5, 0.5);
gradeText.x = 2048 / 2;
gradeText.y = 2732 / 2;
game.addChild(gradeText);
// Show grade for 2 seconds before game over
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
} else if (score >= 30 && score <= 50) {
// Show D- grade for score between 30 and 50
var gradeText = new Text2('D-', {
size: 300,
fill: 0x800080
});
gradeText.anchor.set(0.5, 0.5);
gradeText.x = 2048 / 2;
gradeText.y = 2732 / 2;
game.addChild(gradeText);
// Show grade for 2 seconds before game over
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
} else {
LK.showGameOver();
}
}
}
}
}
// Only run upward counter logic if not in special scene
if (!specialScene) {
// Upward counter increments every second (60 ticks = 1 second)
if (LK.ticks % 60 === 0) {
upwardCounter++;
updateUpwardCounterText();
if (upwardCounter >= 90) {
if (score < 10) {
// Show F- grade for low score
var gradeText = new Text2('F-', {
size: 300,
fill: 0xFF0000
});
gradeText.anchor.set(0.5, 0.5);
gradeText.x = 2048 / 2;
gradeText.y = 2732 / 2;
game.addChild(gradeText);
// Show grade for 2 seconds before game over
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
} else if (score >= 10 && score <= 30) {
// Show F+ grade for score between 10 and 30
var gradeText = new Text2('F+', {
size: 300,
fill: 0xFFA500
});
gradeText.anchor.set(0.5, 0.5);
gradeText.x = 2048 / 2;
gradeText.y = 2732 / 2;
game.addChild(gradeText);
// Show grade for 2 seconds before game over
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
} else if (score >= 30 && score <= 50) {
// Show D- grade for score between 30 and 50
var gradeText = new Text2('D-', {
size: 300,
fill: 0x800080
});
gradeText.anchor.set(0.5, 0.5);
gradeText.x = 2048 / 2;
gradeText.y = 2732 / 2;
game.addChild(gradeText);
// Show grade for 2 seconds before game over
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
} else {
LK.showGameOver();
}
}
}
}
// Handle fourth scene logic
if (fourthScene && !fourthSceneInitialized) {
// Initialize fourth scene with 6 skeletons
for (var s = 0; s < 6; s++) {
var skeleton = new MultiSkeleton();
// Position skeletons in two rows
if (s < 3) {
skeleton.x = (s + 1) * (2048 / 4);
skeleton.y = 200;
} else {
skeleton.x = (s - 2) * (2048 / 4);
skeleton.y = 400;
}
multiSkeletons.push(skeleton);
game.addChild(skeleton);
}
fourthSceneInitialized = true;
}
if (fourthScene) {
// Check collisions with thrown trees
for (var ft = fourthSceneTrees.length - 1; ft >= 0; ft--) {
var thrownTree = fourthSceneTrees[ft];
var currentIntersectingFourth = car.intersects(thrownTree);
if (!lastIntersectingFourthTrees[ft] && currentIntersectingFourth) {
// Check if it's a deadly tree or point tree
if (thrownTree.tint === 0xFF0000) {
// Deadly tree - instant death
var deathText = new Text2('ÖLDÜN!', {
size: 300,
fill: 0xFF0000
});
deathText.anchor.set(0.5, 0.5);
deathText.x = 2048 / 2;
deathText.y = 2732 / 2;
game.addChild(deathText);
// Show message for 2 seconds before game over
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
return;
} else {
// Point tree - add points
score += thrownTree.pointValue || 1;
updateScoreText();
car.flash();
thrownTree.hitAnim();
// Remove the hit tree
game.removeChild(thrownTree);
fourthSceneTrees.splice(ft, 1);
lastIntersectingFourthTrees.splice(ft, 1);
// Check win condition for fourth scene
if (score >= 400) {
LK.showYouWin();
return;
}
}
}
if (ft < lastIntersectingFourthTrees.length) {
lastIntersectingFourthTrees[ft] = currentIntersectingFourth;
}
}
}
// Update tracking variables
lastCarX = car.x;
lastCarY = car.y;
lastScore = score;
};
// --- Initialize score ---
score = 0;
updateScoreText();
// --- Initialize upward counter ---
upwardCounter = 1;
updateUpwardCounterText();
// --- Initialize bottom-left counter ---
bottomLeftCounter = 150;
updateBottomLeftCounterText();
// --- Initialize tracking variables ---
lastCarX = car.x;
lastCarY = car.y;
lastScore = score;