/****
* 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;