/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
// Apple (collectible)
var Apple = Container.expand(function () {
	var self = Container.call(this);
	var appleSprite = self.attachAsset('apple', {
		anchorX: 0.5,
		anchorY: 1
	});
	self.lane = 1;
	self.collected = false;
	self.update = function () {
		// Movement handled by game
	};
	return self;
});
// Fence (obstacle)
var Fence = Container.expand(function () {
	var self = Container.call(this);
	var fenceSprite = self.attachAsset('fence', {
		anchorX: 0.5,
		anchorY: 1
	});
	self.lane = 1;
	self.hit = false;
	self.update = function () {};
	return self;
});
// Horse (player) class
var Horse = Container.expand(function () {
	var self = Container.call(this);
	var horseSprite = self.attachAsset('horse', {
		anchorX: 0.5,
		anchorY: 1
	});
	self.lane = 1; // 0: left, 1: center, 2: right
	self.isJumping = false;
	self.jumpY = 0; // Offset for jump animation
	self.jumpTween = null;
	self.groundY = 0; // Set after adding to game
	self.jumpHeight = 320; // How high the horse jumps
	self.jumpDuration = 420; // ms
	// Start jump if not already jumping
	self.jump = function () {
		if (self.isJumping) return;
		self.isJumping = true;
		if (self.jumpTween) tween.stop(self, {
			jumpY: true
		});
		tween(self, {
			jumpY: -self.jumpHeight
		}, {
			duration: self.jumpDuration,
			easing: tween.cubicOut,
			onFinish: function onFinish() {
				tween(self, {
					jumpY: 0
				}, {
					duration: self.jumpDuration,
					easing: tween.cubicIn,
					onFinish: function onFinish() {
						self.isJumping = false;
					}
				});
			}
		});
	};
	// Move to lane (0,1,2)
	self.moveToLane = function (lane) {
		if (lane < 0) lane = 0;
		if (lane > 2) lane = 2;
		self.lane = lane;
		// Animate x to new lane
		var targetX = laneX(lane);
		tween(self, {
			x: targetX
		}, {
			duration: 120,
			easing: tween.cubicOut
		});
	};
	// Update position for jump
	self.update = function () {
		self.y = self.groundY + self.jumpY;
	};
	return self;
});
// Puddle (obstacle)
var Puddle = Container.expand(function () {
	var self = Container.call(this);
	var puddleSprite = self.attachAsset('puddle', {
		anchorX: 0.5,
		anchorY: 1
	});
	self.lane = 1;
	self.hit = false;
	self.update = function () {};
	return self;
});
// Rock (obstacle)
var Rock = Container.expand(function () {
	var self = Container.call(this);
	var rockSprite = self.attachAsset('rock', {
		anchorX: 0.5,
		anchorY: 1
	});
	self.lane = 1;
	self.hit = false;
	self.update = function () {};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0xA7D36C // Soft green field
});
/**** 
* Game Code
****/ 
// Lane marker (for visual lanes) - 8x2732, light gray box
// Puddle (obstacle) - 140x60, blue ellipse
// Fence (obstacle) - 160x40, tan box
// Rock (obstacle) - 120x80, gray ellipse
// Apple (collectible) - 100x100, red ellipse
// Horse (player) - 220x180, brown box
// Lane logic
var laneCount = 3;
var laneWidth = 480; // (2048 - 2*104) / 3 = ~613, but use 480 for margin
var laneMargin = 104; // left/right margin
function laneX(lane) {
	return laneMargin + lane * laneWidth + laneWidth / 2;
}
// Ground Y (where horse stands)
var groundY = 2200;
// Game speed (pixels per tick)
var baseSpeed = 16;
var speed = baseSpeed;
var speedIncrease = 0.0007; // per tick
var maxSpeed = 38;
// Arrays for obstacles and apples
var obstacles = [];
var apples = [];
// Score
var score = 0;
// Distance (for speed up)
var distance = 0;
// GUI
var scoreTxt = new Text2('0', {
	size: 120,
	fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Lane markers (visual only)
for (var i = 1; i < laneCount; i++) {
	var marker = LK.getAsset('laneMarker', {
		anchorX: 0.5,
		anchorY: 0,
		x: laneMargin + i * laneWidth,
		y: 0,
		scaleY: 1
	});
	game.addChild(marker);
}
// Create horse
var horse = new Horse();
horse.x = laneX(1);
horse.y = groundY;
horse.groundY = groundY;
game.addChild(horse);
// Touch/drag controls
var dragStartX = null;
var dragStartY = null;
var dragStartLane = null;
var dragStartTime = null;
var dragActive = false;
function getLaneFromX(x) {
	for (var i = 0; i < laneCount; i++) {
		var lx = laneX(i);
		if (x < lx + laneWidth / 2) return i;
	}
	return laneCount - 1;
}
// Touch down: record start
game.down = function (x, y, obj) {
	dragStartX = x;
	dragStartY = y;
	dragStartLane = horse.lane;
	dragStartTime = LK.ticks;
	dragActive = true;
};
// Touch move: if horizontal drag, change lane
game.move = function (x, y, obj) {
	if (!dragActive) return;
	var dx = x - dragStartX;
	var dy = y - dragStartY;
	if (Math.abs(dx) > 80 && Math.abs(dx) > Math.abs(dy)) {
		// Lane change
		if (dx > 0 && horse.lane < laneCount - 1) {
			horse.moveToLane(horse.lane + 1);
			dragStartX = x;
			dragStartLane = horse.lane;
		} else if (dx < 0 && horse.lane > 0) {
			horse.moveToLane(horse.lane - 1);
			dragStartX = x;
			dragStartLane = horse.lane;
		}
	}
};
// Touch up: if short tap or upward swipe, jump
game.up = function (x, y, obj) {
	if (!dragActive) return;
	var dt = LK.ticks - dragStartTime;
	var dx = x - dragStartX;
	var dy = y - dragStartY;
	if (dt < 30 && Math.abs(dx) < 60 && Math.abs(dy) < 60) {
		// Tap: jump
		horse.jump();
	} else if (dy < -100 && Math.abs(dy) > Math.abs(dx)) {
		// Upward swipe: jump
		horse.jump();
	}
	dragActive = false;
};
// Obstacle/Apple spawn logic
var lastObstacleY = 0;
var lastAppleY = 0;
var minObstacleGap = 520;
var minAppleGap = 340;
var obstacleTypes = ['rock', 'fence', 'puddle'];
// Helper: spawn obstacle at y, lane
function spawnObstacle(type, lane, y) {
	var obs;
	if (type === 'rock') obs = new Rock();else if (type === 'fence') obs = new Fence();else obs = new Puddle();
	obs.lane = lane;
	obs.x = laneX(lane);
	obs.y = y;
	game.addChild(obs);
	obstacles.push(obs);
}
// Helper: spawn apple at y, lane
function spawnApple(lane, y) {
	var apple = new Apple();
	apple.lane = lane;
	apple.x = laneX(lane);
	apple.y = y;
	game.addChild(apple);
	apples.push(apple);
}
// Main game update
game.update = function () {
	// Speed up over time
	if (speed < maxSpeed) speed += speedIncrease;
	distance += speed;
	// Move obstacles/apples down
	for (var i = obstacles.length - 1; i >= 0; i--) {
		var obs = obstacles[i];
		obs.y += speed;
		// Remove if off screen
		if (obs.y > 2800) {
			obs.destroy();
			obstacles.splice(i, 1);
			continue;
		}
		// Collision: only if in same lane and not already hit
		if (!obs.hit && obs.lane === horse.lane) {
			// Fence: must be jumped over
			if (obs instanceof Fence) {
				if (Math.abs(obs.y - horse.y) < 120 && horse.jumpY > -40) {
					// Not high enough: hit
					obs.hit = true;
					LK.effects.flashScreen(0xff0000, 800);
					LK.showGameOver();
					return;
				}
			} else {
				// Rock/Puddle: must be jumped or avoided
				if (Math.abs(obs.y - horse.y) < 100 && horse.jumpY > -40) {
					obs.hit = true;
					LK.effects.flashScreen(0xff0000, 800);
					LK.showGameOver();
					return;
				}
			}
		}
	}
	for (var i = apples.length - 1; i >= 0; i--) {
		var apple = apples[i];
		apple.y += speed;
		// Remove if off screen
		if (apple.y > 2800) {
			apple.destroy();
			apples.splice(i, 1);
			continue;
		}
		// Collect: same lane, close, not already collected, and not jumping over
		if (!apple.collected && apple.lane === horse.lane && Math.abs(apple.y - horse.y) < 120 && horse.jumpY > -120) {
			apple.collected = true;
			LK.setScore(LK.getScore() + 1);
			scoreTxt.setText(LK.getScore());
			// Animate apple
			tween(apple, {
				y: apple.y - 120,
				alpha: 0
			}, {
				duration: 320,
				easing: tween.cubicIn,
				onFinish: function onFinish() {
					apple.destroy();
				}
			});
			apples.splice(i, 1);
		}
	}
	// Spawn obstacles
	if (distance - lastObstacleY > minObstacleGap + Math.random() * 320) {
		var type = obstacleTypes[Math.floor(Math.random() * obstacleTypes.length)];
		var lane = Math.floor(Math.random() * laneCount);
		spawnObstacle(type, lane, -180);
		lastObstacleY = distance;
	}
	// Spawn apples
	if (distance - lastAppleY > minAppleGap + Math.random() * 220) {
		var lane = Math.floor(Math.random() * laneCount);
		spawnApple(lane, -120);
		lastAppleY = distance;
	}
};
// Reset score on game start
LK.setScore(0);
scoreTxt.setText('0'); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
// Apple (collectible)
var Apple = Container.expand(function () {
	var self = Container.call(this);
	var appleSprite = self.attachAsset('apple', {
		anchorX: 0.5,
		anchorY: 1
	});
	self.lane = 1;
	self.collected = false;
	self.update = function () {
		// Movement handled by game
	};
	return self;
});
// Fence (obstacle)
var Fence = Container.expand(function () {
	var self = Container.call(this);
	var fenceSprite = self.attachAsset('fence', {
		anchorX: 0.5,
		anchorY: 1
	});
	self.lane = 1;
	self.hit = false;
	self.update = function () {};
	return self;
});
// Horse (player) class
var Horse = Container.expand(function () {
	var self = Container.call(this);
	var horseSprite = self.attachAsset('horse', {
		anchorX: 0.5,
		anchorY: 1
	});
	self.lane = 1; // 0: left, 1: center, 2: right
	self.isJumping = false;
	self.jumpY = 0; // Offset for jump animation
	self.jumpTween = null;
	self.groundY = 0; // Set after adding to game
	self.jumpHeight = 320; // How high the horse jumps
	self.jumpDuration = 420; // ms
	// Start jump if not already jumping
	self.jump = function () {
		if (self.isJumping) return;
		self.isJumping = true;
		if (self.jumpTween) tween.stop(self, {
			jumpY: true
		});
		tween(self, {
			jumpY: -self.jumpHeight
		}, {
			duration: self.jumpDuration,
			easing: tween.cubicOut,
			onFinish: function onFinish() {
				tween(self, {
					jumpY: 0
				}, {
					duration: self.jumpDuration,
					easing: tween.cubicIn,
					onFinish: function onFinish() {
						self.isJumping = false;
					}
				});
			}
		});
	};
	// Move to lane (0,1,2)
	self.moveToLane = function (lane) {
		if (lane < 0) lane = 0;
		if (lane > 2) lane = 2;
		self.lane = lane;
		// Animate x to new lane
		var targetX = laneX(lane);
		tween(self, {
			x: targetX
		}, {
			duration: 120,
			easing: tween.cubicOut
		});
	};
	// Update position for jump
	self.update = function () {
		self.y = self.groundY + self.jumpY;
	};
	return self;
});
// Puddle (obstacle)
var Puddle = Container.expand(function () {
	var self = Container.call(this);
	var puddleSprite = self.attachAsset('puddle', {
		anchorX: 0.5,
		anchorY: 1
	});
	self.lane = 1;
	self.hit = false;
	self.update = function () {};
	return self;
});
// Rock (obstacle)
var Rock = Container.expand(function () {
	var self = Container.call(this);
	var rockSprite = self.attachAsset('rock', {
		anchorX: 0.5,
		anchorY: 1
	});
	self.lane = 1;
	self.hit = false;
	self.update = function () {};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0xA7D36C // Soft green field
});
/**** 
* Game Code
****/ 
// Lane marker (for visual lanes) - 8x2732, light gray box
// Puddle (obstacle) - 140x60, blue ellipse
// Fence (obstacle) - 160x40, tan box
// Rock (obstacle) - 120x80, gray ellipse
// Apple (collectible) - 100x100, red ellipse
// Horse (player) - 220x180, brown box
// Lane logic
var laneCount = 3;
var laneWidth = 480; // (2048 - 2*104) / 3 = ~613, but use 480 for margin
var laneMargin = 104; // left/right margin
function laneX(lane) {
	return laneMargin + lane * laneWidth + laneWidth / 2;
}
// Ground Y (where horse stands)
var groundY = 2200;
// Game speed (pixels per tick)
var baseSpeed = 16;
var speed = baseSpeed;
var speedIncrease = 0.0007; // per tick
var maxSpeed = 38;
// Arrays for obstacles and apples
var obstacles = [];
var apples = [];
// Score
var score = 0;
// Distance (for speed up)
var distance = 0;
// GUI
var scoreTxt = new Text2('0', {
	size: 120,
	fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Lane markers (visual only)
for (var i = 1; i < laneCount; i++) {
	var marker = LK.getAsset('laneMarker', {
		anchorX: 0.5,
		anchorY: 0,
		x: laneMargin + i * laneWidth,
		y: 0,
		scaleY: 1
	});
	game.addChild(marker);
}
// Create horse
var horse = new Horse();
horse.x = laneX(1);
horse.y = groundY;
horse.groundY = groundY;
game.addChild(horse);
// Touch/drag controls
var dragStartX = null;
var dragStartY = null;
var dragStartLane = null;
var dragStartTime = null;
var dragActive = false;
function getLaneFromX(x) {
	for (var i = 0; i < laneCount; i++) {
		var lx = laneX(i);
		if (x < lx + laneWidth / 2) return i;
	}
	return laneCount - 1;
}
// Touch down: record start
game.down = function (x, y, obj) {
	dragStartX = x;
	dragStartY = y;
	dragStartLane = horse.lane;
	dragStartTime = LK.ticks;
	dragActive = true;
};
// Touch move: if horizontal drag, change lane
game.move = function (x, y, obj) {
	if (!dragActive) return;
	var dx = x - dragStartX;
	var dy = y - dragStartY;
	if (Math.abs(dx) > 80 && Math.abs(dx) > Math.abs(dy)) {
		// Lane change
		if (dx > 0 && horse.lane < laneCount - 1) {
			horse.moveToLane(horse.lane + 1);
			dragStartX = x;
			dragStartLane = horse.lane;
		} else if (dx < 0 && horse.lane > 0) {
			horse.moveToLane(horse.lane - 1);
			dragStartX = x;
			dragStartLane = horse.lane;
		}
	}
};
// Touch up: if short tap or upward swipe, jump
game.up = function (x, y, obj) {
	if (!dragActive) return;
	var dt = LK.ticks - dragStartTime;
	var dx = x - dragStartX;
	var dy = y - dragStartY;
	if (dt < 30 && Math.abs(dx) < 60 && Math.abs(dy) < 60) {
		// Tap: jump
		horse.jump();
	} else if (dy < -100 && Math.abs(dy) > Math.abs(dx)) {
		// Upward swipe: jump
		horse.jump();
	}
	dragActive = false;
};
// Obstacle/Apple spawn logic
var lastObstacleY = 0;
var lastAppleY = 0;
var minObstacleGap = 520;
var minAppleGap = 340;
var obstacleTypes = ['rock', 'fence', 'puddle'];
// Helper: spawn obstacle at y, lane
function spawnObstacle(type, lane, y) {
	var obs;
	if (type === 'rock') obs = new Rock();else if (type === 'fence') obs = new Fence();else obs = new Puddle();
	obs.lane = lane;
	obs.x = laneX(lane);
	obs.y = y;
	game.addChild(obs);
	obstacles.push(obs);
}
// Helper: spawn apple at y, lane
function spawnApple(lane, y) {
	var apple = new Apple();
	apple.lane = lane;
	apple.x = laneX(lane);
	apple.y = y;
	game.addChild(apple);
	apples.push(apple);
}
// Main game update
game.update = function () {
	// Speed up over time
	if (speed < maxSpeed) speed += speedIncrease;
	distance += speed;
	// Move obstacles/apples down
	for (var i = obstacles.length - 1; i >= 0; i--) {
		var obs = obstacles[i];
		obs.y += speed;
		// Remove if off screen
		if (obs.y > 2800) {
			obs.destroy();
			obstacles.splice(i, 1);
			continue;
		}
		// Collision: only if in same lane and not already hit
		if (!obs.hit && obs.lane === horse.lane) {
			// Fence: must be jumped over
			if (obs instanceof Fence) {
				if (Math.abs(obs.y - horse.y) < 120 && horse.jumpY > -40) {
					// Not high enough: hit
					obs.hit = true;
					LK.effects.flashScreen(0xff0000, 800);
					LK.showGameOver();
					return;
				}
			} else {
				// Rock/Puddle: must be jumped or avoided
				if (Math.abs(obs.y - horse.y) < 100 && horse.jumpY > -40) {
					obs.hit = true;
					LK.effects.flashScreen(0xff0000, 800);
					LK.showGameOver();
					return;
				}
			}
		}
	}
	for (var i = apples.length - 1; i >= 0; i--) {
		var apple = apples[i];
		apple.y += speed;
		// Remove if off screen
		if (apple.y > 2800) {
			apple.destroy();
			apples.splice(i, 1);
			continue;
		}
		// Collect: same lane, close, not already collected, and not jumping over
		if (!apple.collected && apple.lane === horse.lane && Math.abs(apple.y - horse.y) < 120 && horse.jumpY > -120) {
			apple.collected = true;
			LK.setScore(LK.getScore() + 1);
			scoreTxt.setText(LK.getScore());
			// Animate apple
			tween(apple, {
				y: apple.y - 120,
				alpha: 0
			}, {
				duration: 320,
				easing: tween.cubicIn,
				onFinish: function onFinish() {
					apple.destroy();
				}
			});
			apples.splice(i, 1);
		}
	}
	// Spawn obstacles
	if (distance - lastObstacleY > minObstacleGap + Math.random() * 320) {
		var type = obstacleTypes[Math.floor(Math.random() * obstacleTypes.length)];
		var lane = Math.floor(Math.random() * laneCount);
		spawnObstacle(type, lane, -180);
		lastObstacleY = distance;
	}
	// Spawn apples
	if (distance - lastAppleY > minAppleGap + Math.random() * 220) {
		var lane = Math.floor(Math.random() * laneCount);
		spawnApple(lane, -120);
		lastAppleY = distance;
	}
};
// Reset score on game start
LK.setScore(0);
scoreTxt.setText('0');
:quality(85)/https://cdn.frvr.ai/682c7e242bfb043282cc6068.png%3F3) 
 horse with tongue sticking out with saddle . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
:quality(85)/https://cdn.frvr.ai/682c7ebd2bfb043282cc608f.png%3F3) 
 horse dung with green whiff cloud trailing out. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
:quality(85)/https://cdn.frvr.ai/682c7f4e2bfb043282cc60c6.png%3F3) 
 APPLE . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
:quality(85)/https://cdn.frvr.ai/682c80012bfb043282cc6130.png%3F3) 
 unlucky horse shoe. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat