/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// PipePair class (top and bottom pipes)
var PipePair = Container.expand(function () {
	var self = Container.call(this);
	// Gap size and vertical position
	self.gap = 600;
	self.pipeWidth = 220;
	self.pipeHeight = 900;
	// Top pipe
	self.topPipe = self.attachAsset('pipe', {
		anchorX: 0.5,
		anchorY: 1.0,
		x: 0,
		y: 0
	});
	// Bottom pipe
	self.bottomPipe = self.attachAsset('pipe', {
		anchorX: 0.5,
		anchorY: 0.0,
		x: 0,
		y: self.gap + self.pipeHeight
	});
	// Used to check if player has passed this pipe
	self.passed = false;
	// Set vertical gap position
	self.setGapY = function (gapY) {
		// gapY is the y of the center of the gap
		self.topPipe.y = gapY - self.gap / 2;
		self.bottomPipe.y = gapY + self.gap / 2;
	};
	// Update method
	self.update = function () {
		self.x -= pipeSpeed;
	};
	// Get bounds for collision
	self.getTopPipeBounds = function () {
		return {
			x: self.x - self.pipeWidth / 2,
			y: self.topPipe.y - self.pipeHeight,
			width: self.pipeWidth,
			height: self.pipeHeight
		};
	};
	self.getBottomPipeBounds = function () {
		return {
			x: self.x - self.pipeWidth / 2,
			y: self.bottomPipe.y,
			width: self.pipeWidth,
			height: self.pipeHeight
		};
	};
	return self;
});
// Player class
var Player = Container.expand(function () {
	var self = Container.call(this);
	var playerGfx = self.attachAsset('playerSquare', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.vy = 0; // vertical velocity
	self.gravity = 0; // gravity per frame (slower fall)
	self.flapStrength = -28; // negative = up (slower flap)
	// Flap method
	self.flap = function () {
		self.vy = self.flapStrength;
		// Animate a quick scale for feedback
		tween(playerGfx, {
			scaleY: 0.7
		}, {
			duration: 60,
			easing: tween.cubicOut,
			onFinish: function onFinish() {
				tween(playerGfx, {
					scaleY: 1
				}, {
					duration: 120,
					easing: tween.cubicOut
				});
			}
		});
	};
	// Update method
	self.update = function () {
		self.vy += self.gravity;
		self.y += self.vy;
		// Clamp rotation for visual feedback
		var maxAngle = Math.PI / 5;
		var minAngle = -Math.PI / 6;
		var targetRot = Math.max(minAngle, Math.min(maxAngle, self.vy / 60));
		playerGfx.rotation = targetRot;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x87ceeb // Sky blue
});
/**** 
* Game Code
****/ 
// Game constants
// Square player
// Pipe (top and bottom, same asset, different y/flip)
// Ground
var GROUND_HEIGHT = 120;
var PLAYER_START_X = 500;
var PLAYER_START_Y = 1200;
var PIPE_INTERVAL = 900; // px between pipes horizontally
var PIPE_MIN_Y = 500;
var PIPE_MAX_Y = 2732 - GROUND_HEIGHT - 500;
var pipeSpeed = 10;
// Game state
var player;
var pipes = [];
var ground;
var score = 0;
var scoreTxt;
var gameStarted = true;
var gameOver = false;
var lastPipeX = 0;
// Player speed factor: starts at 0.5 (half speed), becomes 1 after first movement
var playerSpeedFactor = 0.5;
var playerHasMoved = false;
// Start menu overlay
var startMenu = new Container();
var startBg = LK.getAsset('ground', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 1024,
	y: 1366,
	width: 900,
	height: 600
});
startBg.alpha = 0.92;
startMenu.addChild(startBg);
var startText = new Text2("Tap to Start", {
	size: 180,
	fill: 0xffffff
});
startText.anchor.set(0.5, 0.5);
startText.x = 1024;
startText.y = 1366 - 60;
startMenu.addChild(startText);
var howToText = new Text2("Touch and drag to move the square", {
	size: 80,
	fill: 0xffffff
});
howToText.anchor.set(0.5, 0.5);
howToText.x = 1024;
howToText.y = 1366 + 120;
startMenu.addChild(howToText);
// Start menu overlay is not shown since game starts immediately
// LK.gui.center.addChild(startMenu);
// Add cloudy background image (behind everything)
var background = LK.getAsset('cloudyBackground', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	width: 2048,
	height: 2732
});
game.addChild(background);
// Track background offset for parallax effect
var backgroundOffsetY = 0;
// Add ground
ground = LK.getAsset('ground', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 2732 - GROUND_HEIGHT
});
game.addChild(ground);
// Add player
player = new Player();
player.x = PLAYER_START_X;
player.y = PLAYER_START_Y;
game.addChild(player);
// Add score text
scoreTxt = new Text2('0', {
	size: 150,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Helper: reset game state
function resetGame() {
	// Remove pipes
	for (var i = 0; i < pipes.length; i++) {
		pipes[i].destroy();
	}
	pipes = [];
	// Reset player
	player.x = PLAYER_START_X;
	player.y = PLAYER_START_Y;
	player.vy = 0;
	// Reset score
	score = 0;
	scoreTxt.setText(score);
	// Reset state
	gameStarted = false;
	gameOver = false;
	lastPipeX = 0;
	playerSpeedFactor = 0.5;
	playerHasMoved = false;
	// Show start menu again
	if (startMenu && !startMenu.parent) {
		LK.gui.center.addChild(startMenu);
	}
}
// Helper: spawn a new pipe pair
function spawnPipePair(x) {
	var pipe = new PipePair();
	// Randomize gap center
	var gapY = PIPE_MIN_Y + Math.floor(Math.random() * (PIPE_MAX_Y - PIPE_MIN_Y));
	pipe.x = x;
	pipe.setGapY(gapY);
	pipes.push(pipe);
	game.addChild(pipe);
}
// Start with 3 pipes offscreen to the right
for (var i = 0; i < 3; i++) {
	spawnPipePair(2048 + i * PIPE_INTERVAL);
	lastPipeX = 2048 + i * PIPE_INTERVAL;
}
// --- Add up and down control buttons ---
var btnUp = LK.getAsset('btnUp', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 - 200,
	y: 2732 - 500
});
var btnDown = LK.getAsset('btnDown', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 - 200,
	y: 2732 - 250
});
btnUp.alpha = 0.85;
btnDown.alpha = 0.85;
game.addChild(btnUp);
game.addChild(btnDown);
// Button state
var btnUpPressed = false;
var btnDownPressed = false;
// Helper to check if a point is inside a button
function isInsideBtn(btn, x, y) {
	var bx = btn.x,
		by = btn.y;
	var bw = btn.width,
		bh = btn.height;
	return x >= bx - bw / 2 && x <= bx + bw / 2 && y >= by - bh / 2 && y <= by + bh / 2;
}
// Input: touch and drag to control the square directly or press buttons
game.down = function (x, y, obj) {
	if (gameOver) {
		return;
	}
	// No need to handle start menu or gameStarted here since game starts immediately
	// Check if up or down button pressed
	if (isInsideBtn(btnUp, x, y)) {
		btnUpPressed = true;
		btnDownPressed = false;
		return;
	}
	if (isInsideBtn(btnDown, x, y)) {
		btnDownPressed = true;
		btnUpPressed = false;
		return;
	}
	// No direct touch control of the square
};
game.move = function (x, y, obj) {
	if (gameOver || !gameStarted) return;
	// If holding up or down button, ignore drag
	if (btnUpPressed || btnDownPressed) return;
	if (!game._touching) return;
	// No direct touch drag control of the square
};
game.up = function (x, y, obj) {
	btnUpPressed = false;
	btnDownPressed = false;
	game._touching = false;
};
// Main update loop
game.update = function () {
	if (gameOver) {
		return;
	}
	// Only update if started
	if (gameStarted) {
		// Button control: move player up/down if button held
		if (btnUpPressed) {
			var oldY = player.y;
			player.y = Math.max(60, player.y - 22 * playerSpeedFactor);
			player.vy = 0;
			// Move background at half the speed of the player
			var deltaY = player.y - oldY;
			backgroundOffsetY += deltaY * 0.5;
			// Clamp backgroundOffsetY to [0, 2732 - background.height]
			backgroundOffsetY = Math.max(0, Math.min(2732 - background.height, backgroundOffsetY));
			background.y = -backgroundOffsetY;
			// On first movement, restore speed to 1
			if (!playerHasMoved) {
				playerSpeedFactor = 1;
				playerHasMoved = true;
			}
		}
		if (btnDownPressed) {
			var oldY = player.y;
			player.y = Math.min(2732 - GROUND_HEIGHT - 60, player.y + 22 * playerSpeedFactor);
			player.vy = 0;
			// Move background at half the speed of the player
			var deltaY = player.y - oldY;
			backgroundOffsetY += deltaY * 0.5;
			// Clamp backgroundOffsetY to [0, 2732 - background.height]
			backgroundOffsetY = Math.max(0, Math.min(2732 - background.height, backgroundOffsetY));
			background.y = -backgroundOffsetY;
			// On first movement, restore speed to 1
			if (!playerHasMoved) {
				playerSpeedFactor = 1;
				playerHasMoved = true;
			}
		}
		player.update();
		// Move pipes and check for offscreen
		for (var i = pipes.length - 1; i >= 0; i--) {
			var pipe = pipes[i];
			pipe.update();
			// Remove pipes that are offscreen left
			if (pipe.x < -pipe.pipeWidth) {
				pipe.destroy();
				pipes.splice(i, 1);
				continue;
			}
			// Check for passing pipe (score)
			if (!pipe.passed && pipe.x + pipe.pipeWidth / 2 < player.x) {
				pipe.passed = true;
				score += 1;
				scoreTxt.setText(score);
			}
		}
		// Spawn new pipes as needed
		if (pipes.length === 0 || lastPipeX - pipes[pipes.length - 1].x >= PIPE_INTERVAL) {
			lastPipeX += PIPE_INTERVAL;
			spawnPipePair(lastPipeX);
		}
		// Collision detection: pipes
		for (var i = 0; i < pipes.length; i++) {
			var pipe = pipes[i];
			// Top pipe
			var topB = pipe.getTopPipeBounds();
			if (rectsIntersect(player, topB)) {
				endGame();
				return;
			}
			// Bottom pipe
			var botB = pipe.getBottomPipeBounds();
			if (rectsIntersect(player, botB)) {
				endGame();
				return;
			}
		}
		// Collision detection: ground
		if (player.y + 60 > 2732 - GROUND_HEIGHT) {
			player.y = 2732 - GROUND_HEIGHT - 60;
			endGame();
			return;
		}
		// Collision detection: ceiling
		if (player.y - 60 < 0) {
			player.y = 60;
			player.vy = 0;
		}
	}
};
// Rectangle intersection helper (player is a square, pipes are rectangles)
function rectsIntersect(playerObj, rect) {
	// Player bounds
	var px = playerObj.x - 60;
	var py = playerObj.y - 60;
	var pw = 120;
	var ph = 120;
	// Rect bounds
	var rx = rect.x;
	var ry = rect.y;
	var rw = rect.width;
	var rh = rect.height;
	// Check overlap
	return !(px + pw < rx || px > rx + rw || py + ph < ry || py > ry + rh);
}
// End game
function endGame() {
	gameOver = true;
	// Flash red
	LK.effects.flashScreen(0xff0000, 800);
	// Show game over (auto resets game)
	LK.setScore(score);
	LK.showGameOver();
}
// Reset game on game over
LK.on('gameover', function () {
	resetGame();
});
// Also reset on you win (not used, but for completeness)
LK.on('youwin', function () {
	resetGame();
}); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// PipePair class (top and bottom pipes)
var PipePair = Container.expand(function () {
	var self = Container.call(this);
	// Gap size and vertical position
	self.gap = 600;
	self.pipeWidth = 220;
	self.pipeHeight = 900;
	// Top pipe
	self.topPipe = self.attachAsset('pipe', {
		anchorX: 0.5,
		anchorY: 1.0,
		x: 0,
		y: 0
	});
	// Bottom pipe
	self.bottomPipe = self.attachAsset('pipe', {
		anchorX: 0.5,
		anchorY: 0.0,
		x: 0,
		y: self.gap + self.pipeHeight
	});
	// Used to check if player has passed this pipe
	self.passed = false;
	// Set vertical gap position
	self.setGapY = function (gapY) {
		// gapY is the y of the center of the gap
		self.topPipe.y = gapY - self.gap / 2;
		self.bottomPipe.y = gapY + self.gap / 2;
	};
	// Update method
	self.update = function () {
		self.x -= pipeSpeed;
	};
	// Get bounds for collision
	self.getTopPipeBounds = function () {
		return {
			x: self.x - self.pipeWidth / 2,
			y: self.topPipe.y - self.pipeHeight,
			width: self.pipeWidth,
			height: self.pipeHeight
		};
	};
	self.getBottomPipeBounds = function () {
		return {
			x: self.x - self.pipeWidth / 2,
			y: self.bottomPipe.y,
			width: self.pipeWidth,
			height: self.pipeHeight
		};
	};
	return self;
});
// Player class
var Player = Container.expand(function () {
	var self = Container.call(this);
	var playerGfx = self.attachAsset('playerSquare', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.vy = 0; // vertical velocity
	self.gravity = 0; // gravity per frame (slower fall)
	self.flapStrength = -28; // negative = up (slower flap)
	// Flap method
	self.flap = function () {
		self.vy = self.flapStrength;
		// Animate a quick scale for feedback
		tween(playerGfx, {
			scaleY: 0.7
		}, {
			duration: 60,
			easing: tween.cubicOut,
			onFinish: function onFinish() {
				tween(playerGfx, {
					scaleY: 1
				}, {
					duration: 120,
					easing: tween.cubicOut
				});
			}
		});
	};
	// Update method
	self.update = function () {
		self.vy += self.gravity;
		self.y += self.vy;
		// Clamp rotation for visual feedback
		var maxAngle = Math.PI / 5;
		var minAngle = -Math.PI / 6;
		var targetRot = Math.max(minAngle, Math.min(maxAngle, self.vy / 60));
		playerGfx.rotation = targetRot;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x87ceeb // Sky blue
});
/**** 
* Game Code
****/ 
// Game constants
// Square player
// Pipe (top and bottom, same asset, different y/flip)
// Ground
var GROUND_HEIGHT = 120;
var PLAYER_START_X = 500;
var PLAYER_START_Y = 1200;
var PIPE_INTERVAL = 900; // px between pipes horizontally
var PIPE_MIN_Y = 500;
var PIPE_MAX_Y = 2732 - GROUND_HEIGHT - 500;
var pipeSpeed = 10;
// Game state
var player;
var pipes = [];
var ground;
var score = 0;
var scoreTxt;
var gameStarted = true;
var gameOver = false;
var lastPipeX = 0;
// Player speed factor: starts at 0.5 (half speed), becomes 1 after first movement
var playerSpeedFactor = 0.5;
var playerHasMoved = false;
// Start menu overlay
var startMenu = new Container();
var startBg = LK.getAsset('ground', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 1024,
	y: 1366,
	width: 900,
	height: 600
});
startBg.alpha = 0.92;
startMenu.addChild(startBg);
var startText = new Text2("Tap to Start", {
	size: 180,
	fill: 0xffffff
});
startText.anchor.set(0.5, 0.5);
startText.x = 1024;
startText.y = 1366 - 60;
startMenu.addChild(startText);
var howToText = new Text2("Touch and drag to move the square", {
	size: 80,
	fill: 0xffffff
});
howToText.anchor.set(0.5, 0.5);
howToText.x = 1024;
howToText.y = 1366 + 120;
startMenu.addChild(howToText);
// Start menu overlay is not shown since game starts immediately
// LK.gui.center.addChild(startMenu);
// Add cloudy background image (behind everything)
var background = LK.getAsset('cloudyBackground', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	width: 2048,
	height: 2732
});
game.addChild(background);
// Track background offset for parallax effect
var backgroundOffsetY = 0;
// Add ground
ground = LK.getAsset('ground', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 2732 - GROUND_HEIGHT
});
game.addChild(ground);
// Add player
player = new Player();
player.x = PLAYER_START_X;
player.y = PLAYER_START_Y;
game.addChild(player);
// Add score text
scoreTxt = new Text2('0', {
	size: 150,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Helper: reset game state
function resetGame() {
	// Remove pipes
	for (var i = 0; i < pipes.length; i++) {
		pipes[i].destroy();
	}
	pipes = [];
	// Reset player
	player.x = PLAYER_START_X;
	player.y = PLAYER_START_Y;
	player.vy = 0;
	// Reset score
	score = 0;
	scoreTxt.setText(score);
	// Reset state
	gameStarted = false;
	gameOver = false;
	lastPipeX = 0;
	playerSpeedFactor = 0.5;
	playerHasMoved = false;
	// Show start menu again
	if (startMenu && !startMenu.parent) {
		LK.gui.center.addChild(startMenu);
	}
}
// Helper: spawn a new pipe pair
function spawnPipePair(x) {
	var pipe = new PipePair();
	// Randomize gap center
	var gapY = PIPE_MIN_Y + Math.floor(Math.random() * (PIPE_MAX_Y - PIPE_MIN_Y));
	pipe.x = x;
	pipe.setGapY(gapY);
	pipes.push(pipe);
	game.addChild(pipe);
}
// Start with 3 pipes offscreen to the right
for (var i = 0; i < 3; i++) {
	spawnPipePair(2048 + i * PIPE_INTERVAL);
	lastPipeX = 2048 + i * PIPE_INTERVAL;
}
// --- Add up and down control buttons ---
var btnUp = LK.getAsset('btnUp', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 - 200,
	y: 2732 - 500
});
var btnDown = LK.getAsset('btnDown', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 - 200,
	y: 2732 - 250
});
btnUp.alpha = 0.85;
btnDown.alpha = 0.85;
game.addChild(btnUp);
game.addChild(btnDown);
// Button state
var btnUpPressed = false;
var btnDownPressed = false;
// Helper to check if a point is inside a button
function isInsideBtn(btn, x, y) {
	var bx = btn.x,
		by = btn.y;
	var bw = btn.width,
		bh = btn.height;
	return x >= bx - bw / 2 && x <= bx + bw / 2 && y >= by - bh / 2 && y <= by + bh / 2;
}
// Input: touch and drag to control the square directly or press buttons
game.down = function (x, y, obj) {
	if (gameOver) {
		return;
	}
	// No need to handle start menu or gameStarted here since game starts immediately
	// Check if up or down button pressed
	if (isInsideBtn(btnUp, x, y)) {
		btnUpPressed = true;
		btnDownPressed = false;
		return;
	}
	if (isInsideBtn(btnDown, x, y)) {
		btnDownPressed = true;
		btnUpPressed = false;
		return;
	}
	// No direct touch control of the square
};
game.move = function (x, y, obj) {
	if (gameOver || !gameStarted) return;
	// If holding up or down button, ignore drag
	if (btnUpPressed || btnDownPressed) return;
	if (!game._touching) return;
	// No direct touch drag control of the square
};
game.up = function (x, y, obj) {
	btnUpPressed = false;
	btnDownPressed = false;
	game._touching = false;
};
// Main update loop
game.update = function () {
	if (gameOver) {
		return;
	}
	// Only update if started
	if (gameStarted) {
		// Button control: move player up/down if button held
		if (btnUpPressed) {
			var oldY = player.y;
			player.y = Math.max(60, player.y - 22 * playerSpeedFactor);
			player.vy = 0;
			// Move background at half the speed of the player
			var deltaY = player.y - oldY;
			backgroundOffsetY += deltaY * 0.5;
			// Clamp backgroundOffsetY to [0, 2732 - background.height]
			backgroundOffsetY = Math.max(0, Math.min(2732 - background.height, backgroundOffsetY));
			background.y = -backgroundOffsetY;
			// On first movement, restore speed to 1
			if (!playerHasMoved) {
				playerSpeedFactor = 1;
				playerHasMoved = true;
			}
		}
		if (btnDownPressed) {
			var oldY = player.y;
			player.y = Math.min(2732 - GROUND_HEIGHT - 60, player.y + 22 * playerSpeedFactor);
			player.vy = 0;
			// Move background at half the speed of the player
			var deltaY = player.y - oldY;
			backgroundOffsetY += deltaY * 0.5;
			// Clamp backgroundOffsetY to [0, 2732 - background.height]
			backgroundOffsetY = Math.max(0, Math.min(2732 - background.height, backgroundOffsetY));
			background.y = -backgroundOffsetY;
			// On first movement, restore speed to 1
			if (!playerHasMoved) {
				playerSpeedFactor = 1;
				playerHasMoved = true;
			}
		}
		player.update();
		// Move pipes and check for offscreen
		for (var i = pipes.length - 1; i >= 0; i--) {
			var pipe = pipes[i];
			pipe.update();
			// Remove pipes that are offscreen left
			if (pipe.x < -pipe.pipeWidth) {
				pipe.destroy();
				pipes.splice(i, 1);
				continue;
			}
			// Check for passing pipe (score)
			if (!pipe.passed && pipe.x + pipe.pipeWidth / 2 < player.x) {
				pipe.passed = true;
				score += 1;
				scoreTxt.setText(score);
			}
		}
		// Spawn new pipes as needed
		if (pipes.length === 0 || lastPipeX - pipes[pipes.length - 1].x >= PIPE_INTERVAL) {
			lastPipeX += PIPE_INTERVAL;
			spawnPipePair(lastPipeX);
		}
		// Collision detection: pipes
		for (var i = 0; i < pipes.length; i++) {
			var pipe = pipes[i];
			// Top pipe
			var topB = pipe.getTopPipeBounds();
			if (rectsIntersect(player, topB)) {
				endGame();
				return;
			}
			// Bottom pipe
			var botB = pipe.getBottomPipeBounds();
			if (rectsIntersect(player, botB)) {
				endGame();
				return;
			}
		}
		// Collision detection: ground
		if (player.y + 60 > 2732 - GROUND_HEIGHT) {
			player.y = 2732 - GROUND_HEIGHT - 60;
			endGame();
			return;
		}
		// Collision detection: ceiling
		if (player.y - 60 < 0) {
			player.y = 60;
			player.vy = 0;
		}
	}
};
// Rectangle intersection helper (player is a square, pipes are rectangles)
function rectsIntersect(playerObj, rect) {
	// Player bounds
	var px = playerObj.x - 60;
	var py = playerObj.y - 60;
	var pw = 120;
	var ph = 120;
	// Rect bounds
	var rx = rect.x;
	var ry = rect.y;
	var rw = rect.width;
	var rh = rect.height;
	// Check overlap
	return !(px + pw < rx || px > rx + rw || py + ph < ry || py > ry + rh);
}
// End game
function endGame() {
	gameOver = true;
	// Flash red
	LK.effects.flashScreen(0xff0000, 800);
	// Show game over (auto resets game)
	LK.setScore(score);
	LK.showGameOver();
}
// Reset game on game over
LK.on('gameover', function () {
	resetGame();
});
// Also reset on you win (not used, but for completeness)
LK.on('youwin', function () {
	resetGame();
});