/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
	highScore: 0
});
/**** 
* Classes
****/ 
var AimArrow = Container.expand(function () {
	var self = Container.call(this);
	// Create arrow components
	var arrowLine = self.attachAsset('aimLine', {
		anchorX: 0.5,
		anchorY: 1.0,
		width: 10,
		height: 150
	});
	// Set initial visibility
	self.visible = false;
	// Update arrow position and rotation based on angle
	self.updateArrow = function (startX, startY, angle) {
		self.x = startX;
		self.y = startY;
		self.rotation = angle;
		self.visible = true;
	};
	self.hide = function () {
		self.visible = false;
	};
	return self;
});
var BowlingPin = Container.expand(function () {
	var self = Container.call(this);
	var pinGraphics = self.attachAsset('bowlingPin', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.isKnockedDown = false;
	self.velocityX = 0;
	self.velocityY = 0;
	self.friction = 0.95;
	self.lastX = 0;
	self.lastY = 0;
	self.row = 0; // Store which row this pin belongs to
	self.mass = 1 + Math.random() * 0.2; // Slight mass variation for more realistic physics
	self.collisionEnergy = 0; // Track collision energy for better pin-to-pin interactions
	self.rotationVelocity = 0; // Track rotation velocity separately
	self.knockDown = function () {
		if (!self.isKnockedDown) {
			self.isKnockedDown = true;
			// Calculate direction based on the impact
			var directionX = Math.random() - 0.5;
			var directionY = Math.random() * 0.3 + 0.7; // Mostly forward, slight randomness
			// More realistic physics - calculate velocity based on position, mass, etc.
			self.velocityX = directionX * (5 + Math.random() * 3);
			self.velocityY = directionY * (5 + Math.random() * 3);
			self.rotationVelocity = (Math.random() - 0.5) * 0.2;
			// Add collision energy for pin-to-pin interactions
			self.collisionEnergy = 10;
			LK.getSound('pinHit').play();
			return true;
		}
		return false;
	};
	self.applyImpact = function (impactX, impactY, energy) {
		// Apply an impact force from another object (pin or penguin)
		// Direction based on impact position
		var dirX = self.x - impactX;
		var dirY = self.y - impactY;
		// Normalize
		var length = Math.sqrt(dirX * dirX + dirY * dirY);
		if (length > 0) {
			dirX /= length;
			dirY /= length;
		}
		// Apply velocity based on energy and direction
		var forceScale = energy / self.mass;
		self.velocityX += dirX * forceScale;
		self.velocityY += dirY * forceScale;
		// Add some rotation based on impact offset
		var rotationImpact = (Math.random() - 0.5) * 0.1 * forceScale;
		self.rotationVelocity += rotationImpact;
		// Mark as knocked down
		if (!self.isKnockedDown) {
			self.isKnockedDown = true;
			self.collisionEnergy = energy * 0.8; // Transfer most of the energy
			LK.getSound('pinHit').play();
			return true;
		}
		return false;
	};
	self.update = function () {
		// Store last position for collision detection
		self.lastX = self.x;
		self.lastY = self.y;
		if (self.isKnockedDown) {
			// Apply velocity
			self.x += self.velocityX;
			self.y += self.velocityY;
			// Apply friction
			self.velocityX *= self.friction;
			self.velocityY *= self.friction;
			// Apply rotation
			pinGraphics.rotation += self.rotationVelocity;
			self.rotationVelocity *= 0.98; // Dampen rotation
			// Gradually reduce collision energy
			self.collisionEnergy *= 0.95;
			// More realistic falling behavior with physics-based motion
			// Pins slow down more when they're almost stopped
			if (Math.abs(self.velocityX) < 0.5 && Math.abs(self.velocityY) < 0.5) {
				self.velocityX *= 0.9;
				self.velocityY *= 0.9;
			}
			// Slower fade out for more realistic pin falling
			if (Math.abs(self.velocityX) < 0.1 && Math.abs(self.velocityY) < 0.1) {
				pinGraphics.alpha *= 0.99; // Slower fade when stopped
			} else {
				pinGraphics.alpha *= 0.995; // Normal fade when moving
			}
			// Remove from game when almost invisible
			if (pinGraphics.alpha < 0.1) {
				self.visible = false;
			}
		}
	};
	self.reset = function () {
		self.isKnockedDown = false;
		self.velocityX = 0;
		self.velocityY = 0;
		self.rotationVelocity = 0;
		self.collisionEnergy = 0;
		pinGraphics.rotation = 0;
		pinGraphics.alpha = 1;
		self.visible = true;
	};
	return self;
});
var Penguin = Container.expand(function () {
	var self = Container.call(this);
	var penguinGraphics = self.attachAsset('penguin', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Physics properties
	self.velocityX = 0;
	self.velocityY = 0;
	self.friction = 0.985; // Further decreased value for even slower sliding
	self.active = false;
	self.hasCollided = false;
	self.burnCount = 0; // Track how many times penguin has hit the obstacle
	self.isBurned = false; // Track if penguin is burned
	self.pullDistance = 0; // Store the pull distance for power calculation
	self.launch = function (angle, power, dragSpeed) {
		// Use the drag speed to determine penguin velocity
		// dragSpeed is calculated based on how quickly the player dragged and released
		var speedMultiplier = power / MAX_POWER; // Base power from pull distance
		// Use dragSpeed as a multiplier to the base power calculation
		var baseSpeed = 18; // Minimum speed needed to move (reduced from 25)
		var reachPinsSpeed = 30; // Speed needed to reach pins (reduced from 40)
		var maxSpeed = baseSpeed + (reachPinsSpeed - baseSpeed) * speedMultiplier;
		// Multiply by dragSpeed factor for more dynamic speed control
		maxSpeed *= dragSpeed || 0.8;
		self.velocityX = Math.cos(angle) * maxSpeed;
		self.velocityY = Math.sin(angle) * maxSpeed;
		// Special case for throwing straight - make sure it reaches pins at max power
		if (Math.abs(Math.cos(angle)) < 0.2 && Math.sin(angle) < -0.8 && speedMultiplier > 0.9) {
			// Adjust vertical speed to ensure it reaches the pins
			self.velocityY = -reachPinsSpeed * (dragSpeed || 0.8);
		}
		self.active = true;
		self.hasCollided = false;
		LK.getSound('slide').play();
	};
	self.update = function () {
		if (!self.active) return;
		// Apply velocity
		self.x += self.velocityX;
		self.y += self.velocityY;
		// Apply friction
		// Ice physics - lower friction when moving fast, gradually increases as slowing down
		var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
		var dynamicFriction = speed > 10 ? 0.988 : speed > 5 ? 0.982 : 0.975; // More graduated and further reduced friction for slower ice physics
		self.velocityX *= dynamicFriction;
		self.velocityY *= dynamicFriction;
		// More realistic penguin rotation while sliding
		var rotationFactor = speed > 5 ? 0.005 : 0.01; // Less rotation at high speeds
		penguinGraphics.rotation += self.velocityX * rotationFactor;
		// Stop if velocity is very small
		if (Math.abs(self.velocityX) < 0.1 && Math.abs(self.velocityY) < 0.1) {
			self.active = false;
			self.velocityX = 0;
			self.velocityY = 0;
			penguinGraphics.rotation = 0; // Reset rotation when stopped
		}
		// Frame boundary checks with proper reflection vectors
		// Left boundary
		if (self.x < 0) {
			self.x = 0;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityX = -self.velocityX * 0.8; // Reverse X direction with reduced speed
			// If X velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityX) < 0.5) {
				self.velocityX = 0; // Perfect 90 degrees means no horizontal movement
				self.velocityY = self.velocityY > 0 ? speed : -speed; // Maintain vertical direction
			}
			// Award wall bounce bonus if active and hasn't collided yet
			if (self.active && !self.hasCollided) {
				self.wallBounceCount = self.wallBounceCount || 0;
				self.wallBounceCount++;
			}
		}
		// Right boundary
		else if (self.x > 2048) {
			self.x = 2048;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityX = -self.velocityX * 0.8; // Reverse X direction with reduced speed
			// If X velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityX) < 0.5) {
				self.velocityX = 0; // Perfect 90 degrees means no horizontal movement
				self.velocityY = self.velocityY > 0 ? speed : -speed; // Maintain vertical direction
			}
		}
		// Top boundary
		if (self.y < 0) {
			self.y = 0;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityY = -self.velocityY * 0.8; // Reverse Y direction with reduced speed
			// If Y velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityY) < 0.5) {
				self.velocityY = 0; // Perfect 90 degrees means no vertical movement
				self.velocityX = self.velocityX > 0 ? speed : -speed; // Maintain horizontal direction
			}
		}
		// Bottom boundary
		if (self.y > 2732) {
			self.y = 2732;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityY = -self.velocityY * 0.8; // Reverse Y direction with reduced speed
			// If Y velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityY) < 0.5) {
				self.velocityY = 0; // Perfect 90 degrees means no vertical movement
				self.velocityX = self.velocityX > 0 ? speed : -speed; // Maintain horizontal direction
			}
		}
		// Bowling lane boundary checks (light blue area)
		// Calculate bowling lane boundaries
		var laneLeftBoundary = bowlingLane.x - bowlingLane.width / 2;
		var laneRightBoundary = bowlingLane.x + bowlingLane.width / 2;
		var laneTopBoundary = bowlingLane.y;
		var laneBottomBoundary = bowlingLane.y + bowlingLane.height;
		// Check if penguin is outside the lane but not outside the game boundaries
		// Left lane boundary
		if (self.x < laneLeftBoundary && self.x > 0) {
			self.x = laneLeftBoundary;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityX = -self.velocityX * 0.8; // Reverse X direction with reduced speed
			// If X velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityX) < 0.5) {
				self.velocityX = 0;
				self.velocityY = self.velocityY > 0 ? speed : -speed;
			}
		}
		// Right lane boundary
		else if (self.x > laneRightBoundary && self.x < 2048) {
			self.x = laneRightBoundary;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityX = -self.velocityX * 0.8; // Reverse X direction with reduced speed
			// If X velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityX) < 0.5) {
				self.velocityX = 0;
				self.velocityY = self.velocityY > 0 ? speed : -speed;
			}
		}
		// Top lane boundary
		if (self.y < laneTopBoundary && self.y > 0) {
			self.y = laneTopBoundary;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityY = -self.velocityY * 0.8; // Reverse Y direction with reduced speed
			// If Y velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityY) < 0.5) {
				self.velocityY = 0;
				self.velocityX = self.velocityX > 0 ? speed : -speed;
			}
		}
		// Bottom lane boundary
		if (self.y > laneBottomBoundary && self.y < 2732) {
			self.y = laneBottomBoundary;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityY = -self.velocityY * 0.8; // Reverse Y direction with reduced speed
			// If Y velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityY) < 0.5) {
				self.velocityY = 0;
				self.velocityX = self.velocityX > 0 ? speed : -speed;
			}
		}
	};
	self.reset = function () {
		self.x = launchArea.x;
		self.y = launchArea.y - 250; // Move penguin further up the lane
		self.velocityX = 0;
		self.velocityY = 0;
		self.active = false;
		self.hasCollided = false;
		self.pullDistance = 0; // Reset pull distance
		self.wallBounceCount = 0; // Reset wall bounce counter
		self.dragSpeed = 0; // Reset drag speed
		self.lastMoveTime = 0; // Reset time tracking
		self.lastMoveX = 0; // Reset position tracking
		self.lastMoveY = 0; // Reset position tracking
		penguinGraphics.rotation = 0;
		self.resetBurnState();
	};
	// Add function to reset burn state
	self.resetBurnState = function () {
		self.burnCount = 0;
		self.isBurned = false;
		// Restore original penguin image
		penguinGraphics.texture = LK.getAsset('penguin', {}).texture;
	};
	// Add function to set penguin burned state
	self.setBurned = function () {
		self.isBurned = true;
		// Remove the old penguin graphics
		self.removeChild(penguinGraphics);
		// Create and add the burned penguin graphics with same anchor points
		penguinGraphics = self.attachAsset('burntPenguin', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Flash red to show penguin is burned
		LK.effects.flashObject(self, 0xff0000, 1000);
		// Stop penguin movement
		self.velocityX = 0;
		self.velocityY = 0;
		self.active = false;
	};
	return self;
});
var PowerMeter = Container.expand(function () {
	var self = Container.call(this);
	var meterBG = self.attachAsset('powerMeterBG', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var meter = self.attachAsset('powerMeter', {
		anchorX: 0.5,
		anchorY: 1.0,
		height: 0 // Start with no power
	});
	var maxPower = 300;
	self.power = 0;
	self.increasing = true;
	self.update = function () {
		if (self.visible) {
			if (self.increasing) {
				self.power += 5;
				if (self.power >= maxPower) {
					self.power = maxPower;
					self.increasing = false;
				}
			} else {
				self.power -= 5;
				if (self.power <= 0) {
					self.power = 0;
					self.increasing = true;
				}
			}
			// Update meter height based on power
			meter.height = self.power;
			meter.y = meterBG.y + meterBG.height / 2 - meter.height / 2;
		}
	};
	self.getPowerRatio = function () {
		return self.power / maxPower;
	};
	self.reset = function () {
		self.power = 0;
		self.increasing = true;
		meter.height = 0;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0xC7E6F7
});
/**** 
* Game Code
****/ 
// Game constants
var MAX_POWER = 15; // Reduced from 20 to make penguin slower
var PIN_ROWS = 4;
var FRAMES = 10;
var PINS_PER_FRAME = 10;
// Game state variables
var currentFrame = 1;
var pinsKnockedDown = 0;
var totalScore = 0;
var aiming = false;
var powering = false;
var gameState = "aiming"; // States: aiming, powering, sliding, scoring, gameover
var aimAngle = -Math.PI / 2; // Start aiming straight up
var consecutiveFailedStrikes = 0; // Track consecutive failures to get a strike
var strikeInLastFrame = false; // Track if the player got a strike in the last frame
var obstacle = null; // Reference to obstacle object
// Create background
var background = game.addChild(LK.getAsset('background', {
	anchorX: 0,
	anchorY: 0
}));
// Create bowling lane
var bowlingLane = game.addChild(LK.getAsset('bowlingLane', {
	anchorX: 0.5,
	anchorY: 0,
	x: 2048 / 2,
	y: 100
}));
// Create launch area
var launchArea = game.addChild(LK.getAsset('launchArea', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: 2400
}));
// Create the aiming line
var aimLine = game.addChild(LK.getAsset('aimLine', {
	anchorX: 0.5,
	anchorY: 1.0,
	x: launchArea.x,
	y: launchArea.y,
	visible: false
}));
// Arrow removed as requested
// Create the power meter
var powerMeter = game.addChild(new PowerMeter());
powerMeter.x = 1900;
powerMeter.y = 1400;
powerMeter.visible = false;
// Create the penguin
var penguin = game.addChild(new Penguin());
penguin.x = launchArea.x;
penguin.y = launchArea.y - 250; // Move penguin further up the lane
// Create bowling pins
var pins = [];
setupPins();
// Create UI elements
var frameText = new Text2('Frame: 1/10', {
	size: 70,
	fill: 0x000000
});
frameText.anchor.set(0.5, 0);
// Position frame text under the penguin's position
frameText.y = penguin.y + 150;
LK.gui.center.addChild(frameText);
var scoreText = new Text2('Score: 0', {
	size: 70,
	fill: 0x000000
});
scoreText.anchor.set(0.5, 0);
scoreText.y = 80;
LK.gui.top.addChild(scoreText);
var instructionText = new Text2('Tap and drag to pull penguin back, release to launch', {
	size: 50,
	fill: 0x000000
});
instructionText.anchor.set(0.5, 0);
instructionText.y = 180;
LK.gui.top.addChild(instructionText);
// Helper functions
function setupPins() {
	// Clear any existing pins
	for (var i = 0; i < pins.length; i++) {
		pins[i].destroy();
	}
	pins = [];
	// Create pin layout in traditional bowling triangle formation
	// Ensure pins are exactly centered on the lane
	var startX = 2048 / 2; // Center of screen
	var startY = 400; // Position from top
	var pinSpacingX = 120; // Fixed horizontal spacing regardless of strikes
	var pinSpacingY = 120; // Fixed vertical spacing regardless of strikes
	// Standard bowling pin layout (4-3-2-1 triangle)
	// First row (back) - 4 pins
	for (var i = 0; i < 4; i++) {
		var pin = new BowlingPin();
		pin.x = startX + (i - 1.5) * pinSpacingX; // Perfectly centered
		pin.y = startY;
		pin.row = 1; // Back row
		pin.lastX = pin.x;
		pin.lastY = pin.y;
		pins.push(pin);
		game.addChild(pin);
	}
	// Second row - 3 pins
	for (var i = 0; i < 3; i++) {
		var pin = new BowlingPin();
		pin.x = startX + (i - 1) * pinSpacingX; // Centered relative to first row
		pin.y = startY + pinSpacingY;
		pin.row = 2; // Second row
		pin.lastX = pin.x;
		pin.lastY = pin.y;
		pins.push(pin);
		game.addChild(pin);
	}
	// Third row - 2 pins
	for (var i = 0; i < 2; i++) {
		var pin = new BowlingPin();
		pin.x = startX + (i - 0.5) * pinSpacingX; // Centered relative to second row
		pin.y = startY + 2 * pinSpacingY;
		pin.row = 3; // Third row
		pin.lastX = pin.x;
		pin.lastY = pin.y;
		pins.push(pin);
		game.addChild(pin);
	}
	// Fourth row (front) - 1 pin
	var pin = new BowlingPin();
	pin.x = startX; // Center pin
	pin.y = startY + 3 * pinSpacingY;
	pin.row = 4; // Front row
	pin.lastX = pin.x;
	pin.lastY = pin.y;
	pins.push(pin);
	game.addChild(pin);
	pinsKnockedDown = 0;
	// Reset penguin burn state for new frame
	penguin.resetBurnState();
	// Remove any existing obstacle
	if (typeof obstacle !== 'undefined' && obstacle) {
		obstacle.destroy();
		obstacle = null;
	}
	// Add obstacle after strike
	if (currentFrame > 1 && strikeInLastFrame) {
		// Create obstacle based on a random position (left or right)
		var obstaclePosition = Math.random() < 0.5 ? "left" : "right";
		obstacle = game.addChild(LK.getAsset('horizontalline', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 500,
			height: 50,
			x: startX,
			y: 1200
		}));
		// If obstacle is on the left side, move it to the left half of the lane
		if (obstaclePosition === "left") {
			obstacle.x = startX - 300;
		} else {
			obstacle.x = startX + 300;
		}
		// Display instruction about the obstacle
		instructionText.setText("Obstacle added! Find a way around it to hit the pins!");
	}
}
function updateAimLine() {
	aimLine.rotation = aimAngle;
	// Ensure the aim line points from the penguin position
	aimLine.x = launchArea.x;
	aimLine.y = launchArea.y;
}
function launchPenguin() {
	// Calculate power based on the pull distance
	var powerRatio = Math.min(penguin.pullDistance / 300, 1); // Normalize based on max drag distance
	var power = powerRatio * MAX_POWER;
	// Launch penguin from current position toward the launch area
	var launchAngle = aimAngle + Math.PI; // Reverse the angle to launch toward the pins
	// Calculate final drag speed, normalize between 0.4 and 1.5 (reduced from 0.5-2.0)
	var dragSpeedFactor = 0.8; // Default if no drag speed calculated (reduced from 1.0)
	if (penguin.dragSpeed) {
		// Cap the drag speed between 0.4 (slower) and 1.5 (faster)
		dragSpeedFactor = Math.max(0.4, Math.min(1.5, penguin.dragSpeed / 6));
	}
	// Launch with power and drag speed
	penguin.launch(launchAngle, power, dragSpeedFactor);
	gameState = "sliding";
	powerMeter.visible = false;
	// Update instruction text to include drag speed information
	var speedMsg = dragSpeedFactor > 1.0 ? " Fast release!" : dragSpeedFactor < 0.8 ? " Slow release!" : "";
	var difficultyMsg = pinSpacingMultiplier > 1.0 ? " - Difficulty: " + Math.round((pinSpacingMultiplier - 1) * 100) + "%" : "";
	if (powerRatio >= 0.9) {
		instructionText.setText("Full power!" + speedMsg + " Watch the penguin slide!" + difficultyMsg);
	} else {
		instructionText.setText("Watch the penguin slide! (Power: " + Math.round(powerRatio * 100) + "%)" + speedMsg + difficultyMsg);
	}
}
function checkCollisions() {
	if (!penguin.active || penguin.hasCollided) return;
	var newKnockdowns = 0;
	// Calculate penguin velocity magnitude for physics-based knockdown
	var penguinSpeed = Math.sqrt(penguin.velocityX * penguin.velocityX + penguin.velocityY * penguin.velocityY);
	var penguinDirection = Math.atan2(penguin.velocityY, penguin.velocityX);
	// Check penguin collision with ANY pin based on realistic physics
	for (var i = 0; i < pins.length; i++) {
		var pin = pins[i];
		if (!pin.isKnockedDown && penguin.intersects(pin)) {
			// Calculate direction of impact from penguin to pin
			var impactAngle = Math.atan2(pin.y - penguin.y, pin.x - penguin.x);
			// Calculate angle difference to determine if hitting from front, side, etc.
			var angleDiff = Math.abs((impactAngle - penguinDirection + Math.PI) % (2 * Math.PI) - Math.PI);
			// More realistic physics: energy transfer based on angle of impact and penguin speed
			var energyTransfer = penguinSpeed * (1 - angleDiff / Math.PI);
			// Knock down pin with physics impact
			if (pin.applyImpact(penguin.x, penguin.y, energyTransfer)) {
				newKnockdowns++;
				pinsKnockedDown++;
				// Update score
				totalScore += 1;
				updateScoreDisplay();
			}
		}
	}
	// Now check for pin-to-pin collisions between ALL pins with realistic physics
	for (var i = 0; i < pins.length; i++) {
		var pin1 = pins[i];
		if (pin1.isKnockedDown && pin1.collisionEnergy > 1) {
			// This pin is moving with enough energy to cause collisions
			for (var j = 0; j < pins.length; j++) {
				var pin2 = pins[j];
				if (i !== j && pin1.intersects(pin2)) {
					// Calculate impact dynamics
					var impactDirection = Math.atan2(pin2.y - pin1.y, pin2.x - pin1.x);
					var impactSpeed = Math.sqrt(pin1.velocityX * pin1.velocityX + pin1.velocityY * pin1.velocityY);
					// If pin2 is not knocked down, apply impact
					if (!pin2.isKnockedDown) {
						if (pin2.applyImpact(pin1.x, pin1.y, pin1.collisionEnergy * 0.7)) {
							pinsKnockedDown++;
							totalScore += 1;
							updateScoreDisplay();
						}
					}
					// Both pins are moving - apply realistic collision physics
					else {
						// Calculate new velocities based on conservation of momentum
						var velocity1 = Math.sqrt(pin1.velocityX * pin1.velocityX + pin1.velocityY * pin1.velocityY);
						var velocity2 = Math.sqrt(pin2.velocityX * pin2.velocityX + pin2.velocityY * pin2.velocityY);
						if (velocity1 > 0.5 || velocity2 > 0.5) {
							// Simple elastic collision - exchange some momentum
							var tempVX = pin1.velocityX * 0.5;
							var tempVY = pin1.velocityY * 0.5;
							pin1.velocityX = pin1.velocityX * 0.5 + pin2.velocityX * 0.5;
							pin1.velocityY = pin1.velocityY * 0.5 + pin2.velocityY * 0.5;
							pin2.velocityX = tempVX * 0.5 + pin2.velocityX * 0.5;
							pin2.velocityY = tempVY * 0.5 + pin2.velocityY * 0.5;
							// Add some random scatter for realism
							pin1.velocityX += (Math.random() - 0.5) * 0.5;
							pin1.velocityY += (Math.random() - 0.5) * 0.5;
							pin2.velocityX += (Math.random() - 0.5) * 0.5;
							pin2.velocityY += (Math.random() - 0.5) * 0.5;
							// Update rotation velocities
							pin1.rotationVelocity += (Math.random() - 0.5) * 0.1;
							pin2.rotationVelocity += (Math.random() - 0.5) * 0.1;
						}
					}
				}
			}
		}
	}
	// Handle collision with obstacle if present - make it completely impassable like a solid wall
	if (typeof obstacle !== 'undefined' && obstacle && penguin.intersects(obstacle)) {
		// Store previous position before intersection occurred
		var prevX = penguin.lastX || penguin.x;
		var prevY = penguin.lastY || penguin.y;
		// Determine collision direction by comparing previous position to obstacle
		var hitFromLeft = prevX < obstacle.x - obstacle.width / 4;
		var hitFromRight = prevX > obstacle.x + obstacle.width / 4;
		var hitFromTop = prevY < obstacle.y - obstacle.height / 4;
		var hitFromBottom = prevY > obstacle.y + obstacle.height / 4;
		// Calculate bounce velocity with energy loss
		var bounceMultiplier = 0.7; // 30% energy loss on bounce
		// Horizontal collision (from left or right)
		if (hitFromLeft || hitFromRight) {
			// Position correction - move outside obstacle
			penguin.x = hitFromLeft ? obstacle.x - obstacle.width / 2 - penguin.width / 2 - 5 :
			// 5px extra buffer
			obstacle.x + obstacle.width / 2 + penguin.width / 2 + 5;
			// Reverse X velocity with energy loss
			penguin.velocityX = -penguin.velocityX * bounceMultiplier;
		}
		// Vertical collision (from top or bottom)
		if (hitFromTop || hitFromBottom) {
			// Position correction - move outside obstacle
			penguin.y = hitFromTop ? obstacle.y - obstacle.height / 2 - penguin.height / 2 - 5 :
			// 5px extra buffer
			obstacle.y + obstacle.height / 2 + penguin.height / 2 + 5;
			// Reverse Y velocity with energy loss
			penguin.velocityY = -penguin.velocityY * bounceMultiplier;
		}
		// Ensure minimum bounce velocity
		var minBounceVelocity = 2.0;
		if (Math.abs(penguin.velocityX) < minBounceVelocity && (hitFromLeft || hitFromRight)) {
			penguin.velocityX = hitFromLeft ? -minBounceVelocity : minBounceVelocity;
		}
		if (Math.abs(penguin.velocityY) < minBounceVelocity && (hitFromTop || hitFromBottom)) {
			penguin.velocityY = hitFromTop ? -minBounceVelocity : minBounceVelocity;
		}
		// Play sound effect for the bounce
		LK.getSound('pinHit').play();
		// Track obstacle collisions for burn mechanic
		penguin.burnCount++;
		// When penguin hits the obstacle, immediately set it to burned
		penguin.setBurned();
		// Play burn sound effect
		LK.getSound('burn').play();
		instructionText.setText("Penguin got burned after hitting the obstacle!");
		// Game over after a short delay
		LK.setTimeout(function () {
			LK.showGameOver();
		}, 2000);
		// Flash screen red to indicate burn
		LK.effects.flashScreen(0xff0000, 1000);
	}
	if (newKnockdowns > 0) {
		penguin.hasCollided = true;
		// Play strike sound if all pins are knocked down
		if (pinsKnockedDown === PINS_PER_FRAME) {
			LK.getSound('strike').play();
			LK.effects.flashScreen(0xFFFFFF, 500);
			instructionText.setText("STRIKE!");
		}
	}
}
function updateScoreDisplay() {
	scoreText.setText("Score: " + totalScore);
	// Update high score if needed
	if (totalScore > storage.highScore) {
		storage.highScore = totalScore;
	}
}
function nextFrame() {
	// Check if player got a strike
	var isStrike = pinsKnockedDown === PINS_PER_FRAME;
	// Store if we had a strike in the last frame to use in setupPins
	strikeInLastFrame = isStrike;
	// Update consecutive fails counter
	if (isStrike) {
		consecutiveFailedStrikes = 0;
		instructionText.setText("STRIKE! Next frame will have an obstacle!");
		// Make penguin slower after each strike
		MAX_POWER = Math.max(5, MAX_POWER - 1); // Decrease power but ensure minimum of 5
		// If there's an existing obstacle, make it wider for the next frame
		if (typeof obstacle !== 'undefined' && obstacle) {
			obstacle.width += 100; // Increase obstacle width by 100px
		}
	} else {
		consecutiveFailedStrikes++;
		// Check for game over condition (2 consecutive failed strikes)
		if (consecutiveFailedStrikes >= 2) {
			gameState = "gameover";
			instructionText.setText("Game Over! 2 consecutive misses! Final Score: " + totalScore);
			// Show game over screen after a brief delay
			LK.setTimeout(function () {
				LK.showGameOver();
			}, 2000);
			return;
		}
	}
	currentFrame++;
	if (currentFrame > FRAMES) {
		// Game over
		gameState = "gameover";
		instructionText.setText("Game Over! Final Score: " + totalScore);
		// Show game over screen after a brief delay
		LK.setTimeout(function () {
			LK.showGameOver();
		}, 2000);
	} else {
		// Setup for next frame
		frameText.setText("Frame: " + currentFrame + "/10");
		// Reset pins regardless of strike
		setupPins();
		penguin.reset();
		gameState = "aiming";
		// Update instruction based on presence of obstacle
		if (typeof obstacle !== 'undefined' && obstacle) {
			instructionText.setText("Tap and drag backward to aim, find a path around the obstacle!");
		} else {
			instructionText.setText("Tap and drag backward to aim, release to launch");
		}
	}
}
function checkGameStateTransition() {
	if (gameState === "sliding") {
		// Check if penguin has stopped
		if (!penguin.active) {
			// Add wall bounce bonus if any
			if (penguin.wallBounceCount && penguin.wallBounceCount > 0) {
				var bounceBonus = penguin.wallBounceCount * 2;
				totalScore += bounceBonus;
				instructionText.setText("Nice trick shot! +" + bounceBonus + " bonus points!");
				updateScoreDisplay();
			}
			// Wait a bit for pins to settle and then move to next frame
			LK.setTimeout(function () {
				nextFrame();
			}, 2000);
			gameState = "scoring";
		}
	}
}
// Event handlers
game.down = function (x, y, obj) {
	if (gameState === "aiming") {
		aiming = true;
		aimLine.visible = false;
		// Store original penguin position
		penguin.originalX = penguin.x;
		penguin.originalY = penguin.y;
	}
};
game.move = function (x, y, obj) {
	if (aiming) {
		// Store the current time and position for calculating drag speed
		var currentTime = Date.now();
		if (!penguin.lastMoveTime) {
			penguin.lastMoveTime = currentTime;
			penguin.lastMoveX = x;
			penguin.lastMoveY = y;
		}
		// Calculate aim angle from penguin to opposite of pull direction
		var dx = launchArea.x - x;
		var dy = launchArea.y - y;
		// Calculate the distance of the pull for power
		var distance = Math.sqrt(dx * dx + dy * dy);
		// Limit the maximum drag distance
		var maxDrag = 300;
		distance = Math.min(distance, maxDrag);
		// Calculate the angle
		aimAngle = Math.atan2(dy, dx);
		// Move the penguin to the drag position
		penguin.x = launchArea.x - Math.cos(aimAngle) * distance;
		penguin.y = launchArea.y - Math.sin(aimAngle) * distance;
		// Store the pull distance for calculating power later
		penguin.pullDistance = distance;
		// Calculate drag speed based on pointer movement
		var timeDiff = currentTime - penguin.lastMoveTime;
		if (timeDiff > 0) {
			var moveDistX = x - penguin.lastMoveX;
			var moveDistY = y - penguin.lastMoveY;
			var moveDist = Math.sqrt(moveDistX * moveDistX + moveDistY * moveDistY);
			penguin.dragSpeed = moveDist / timeDiff * 10; // Scale factor to make it reasonable
			// Update last values for next calculation
			penguin.lastMoveTime = currentTime;
			penguin.lastMoveX = x;
			penguin.lastMoveY = y;
		}
	}
};
game.up = function (x, y, obj) {
	if (aiming) {
		aiming = false;
		// Calculate final drag speed on release
		var currentTime = Date.now();
		if (penguin.lastMoveTime && currentTime - penguin.lastMoveTime < 200) {
			// If the player released quickly after the last move, use that as speed indicator
			var timeDiff = currentTime - penguin.lastMoveTime;
			if (timeDiff > 0) {
				var moveDistX = x - penguin.lastMoveX;
				var moveDistY = y - penguin.lastMoveY;
				var moveDist = Math.sqrt(moveDistX * moveDistX + moveDistY * moveDistY);
				// Final release speed calculation
				var releaseSpeed = moveDist / timeDiff * 15; // Scale factor for release speed
				// Combine with ongoing drag speed for a weighted average
				penguin.dragSpeed = (penguin.dragSpeed + releaseSpeed) / 2;
			}
		}
		// Only launch if penguin was actually pulled back
		if (penguin.pullDistance > 10) {
			// Launch immediately after release
			launchPenguin();
		} else {
			// Reset penguin position if not pulled back enough
			penguin.x = penguin.originalX;
			penguin.y = penguin.originalY;
			penguin.dragSpeed = 0; // Reset drag speed if not launching
		}
	}
};
// Game update loop
game.update = function () {
	if (gameState === "sliding") {
		penguin.update();
		// Update pin physics
		for (var i = 0; i < pins.length; i++) {
			pins[i].update();
		}
		checkCollisions();
		// Check for pin-to-pin collisions even after penguin has finished moving
		if (penguin.hasCollided) {
			for (var i = 0; i < pins.length; i++) {
				var pin1 = pins[i];
				if (pin1.isKnockedDown && pin1.visible && (Math.abs(pin1.velocityX) > 0.5 || Math.abs(pin1.velocityY) > 0.5)) {
					for (var j = 0; j < pins.length; j++) {
						var pin2 = pins[j];
						if (i !== j && !pin2.isKnockedDown && pin2.visible && pin1.intersects(pin2)) {
							if (pin2.knockDown()) {
								pinsKnockedDown++;
								totalScore++;
								updateScoreDisplay();
							}
						}
					}
				}
			}
		}
		checkGameStateTransition();
	}
};
// Initialize variables and start the game
consecutiveFailedStrikes = 0;
pinSpacingMultiplier = 1.0;
// Show initial instructions
instructionText.setText("Tap and drag backward to aim, release to launch. 2 misses = Game Over!");
// Start background music
LK.playMusic('gameMusic');
; /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
	highScore: 0
});
/**** 
* Classes
****/ 
var AimArrow = Container.expand(function () {
	var self = Container.call(this);
	// Create arrow components
	var arrowLine = self.attachAsset('aimLine', {
		anchorX: 0.5,
		anchorY: 1.0,
		width: 10,
		height: 150
	});
	// Set initial visibility
	self.visible = false;
	// Update arrow position and rotation based on angle
	self.updateArrow = function (startX, startY, angle) {
		self.x = startX;
		self.y = startY;
		self.rotation = angle;
		self.visible = true;
	};
	self.hide = function () {
		self.visible = false;
	};
	return self;
});
var BowlingPin = Container.expand(function () {
	var self = Container.call(this);
	var pinGraphics = self.attachAsset('bowlingPin', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.isKnockedDown = false;
	self.velocityX = 0;
	self.velocityY = 0;
	self.friction = 0.95;
	self.lastX = 0;
	self.lastY = 0;
	self.row = 0; // Store which row this pin belongs to
	self.mass = 1 + Math.random() * 0.2; // Slight mass variation for more realistic physics
	self.collisionEnergy = 0; // Track collision energy for better pin-to-pin interactions
	self.rotationVelocity = 0; // Track rotation velocity separately
	self.knockDown = function () {
		if (!self.isKnockedDown) {
			self.isKnockedDown = true;
			// Calculate direction based on the impact
			var directionX = Math.random() - 0.5;
			var directionY = Math.random() * 0.3 + 0.7; // Mostly forward, slight randomness
			// More realistic physics - calculate velocity based on position, mass, etc.
			self.velocityX = directionX * (5 + Math.random() * 3);
			self.velocityY = directionY * (5 + Math.random() * 3);
			self.rotationVelocity = (Math.random() - 0.5) * 0.2;
			// Add collision energy for pin-to-pin interactions
			self.collisionEnergy = 10;
			LK.getSound('pinHit').play();
			return true;
		}
		return false;
	};
	self.applyImpact = function (impactX, impactY, energy) {
		// Apply an impact force from another object (pin or penguin)
		// Direction based on impact position
		var dirX = self.x - impactX;
		var dirY = self.y - impactY;
		// Normalize
		var length = Math.sqrt(dirX * dirX + dirY * dirY);
		if (length > 0) {
			dirX /= length;
			dirY /= length;
		}
		// Apply velocity based on energy and direction
		var forceScale = energy / self.mass;
		self.velocityX += dirX * forceScale;
		self.velocityY += dirY * forceScale;
		// Add some rotation based on impact offset
		var rotationImpact = (Math.random() - 0.5) * 0.1 * forceScale;
		self.rotationVelocity += rotationImpact;
		// Mark as knocked down
		if (!self.isKnockedDown) {
			self.isKnockedDown = true;
			self.collisionEnergy = energy * 0.8; // Transfer most of the energy
			LK.getSound('pinHit').play();
			return true;
		}
		return false;
	};
	self.update = function () {
		// Store last position for collision detection
		self.lastX = self.x;
		self.lastY = self.y;
		if (self.isKnockedDown) {
			// Apply velocity
			self.x += self.velocityX;
			self.y += self.velocityY;
			// Apply friction
			self.velocityX *= self.friction;
			self.velocityY *= self.friction;
			// Apply rotation
			pinGraphics.rotation += self.rotationVelocity;
			self.rotationVelocity *= 0.98; // Dampen rotation
			// Gradually reduce collision energy
			self.collisionEnergy *= 0.95;
			// More realistic falling behavior with physics-based motion
			// Pins slow down more when they're almost stopped
			if (Math.abs(self.velocityX) < 0.5 && Math.abs(self.velocityY) < 0.5) {
				self.velocityX *= 0.9;
				self.velocityY *= 0.9;
			}
			// Slower fade out for more realistic pin falling
			if (Math.abs(self.velocityX) < 0.1 && Math.abs(self.velocityY) < 0.1) {
				pinGraphics.alpha *= 0.99; // Slower fade when stopped
			} else {
				pinGraphics.alpha *= 0.995; // Normal fade when moving
			}
			// Remove from game when almost invisible
			if (pinGraphics.alpha < 0.1) {
				self.visible = false;
			}
		}
	};
	self.reset = function () {
		self.isKnockedDown = false;
		self.velocityX = 0;
		self.velocityY = 0;
		self.rotationVelocity = 0;
		self.collisionEnergy = 0;
		pinGraphics.rotation = 0;
		pinGraphics.alpha = 1;
		self.visible = true;
	};
	return self;
});
var Penguin = Container.expand(function () {
	var self = Container.call(this);
	var penguinGraphics = self.attachAsset('penguin', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Physics properties
	self.velocityX = 0;
	self.velocityY = 0;
	self.friction = 0.985; // Further decreased value for even slower sliding
	self.active = false;
	self.hasCollided = false;
	self.burnCount = 0; // Track how many times penguin has hit the obstacle
	self.isBurned = false; // Track if penguin is burned
	self.pullDistance = 0; // Store the pull distance for power calculation
	self.launch = function (angle, power, dragSpeed) {
		// Use the drag speed to determine penguin velocity
		// dragSpeed is calculated based on how quickly the player dragged and released
		var speedMultiplier = power / MAX_POWER; // Base power from pull distance
		// Use dragSpeed as a multiplier to the base power calculation
		var baseSpeed = 18; // Minimum speed needed to move (reduced from 25)
		var reachPinsSpeed = 30; // Speed needed to reach pins (reduced from 40)
		var maxSpeed = baseSpeed + (reachPinsSpeed - baseSpeed) * speedMultiplier;
		// Multiply by dragSpeed factor for more dynamic speed control
		maxSpeed *= dragSpeed || 0.8;
		self.velocityX = Math.cos(angle) * maxSpeed;
		self.velocityY = Math.sin(angle) * maxSpeed;
		// Special case for throwing straight - make sure it reaches pins at max power
		if (Math.abs(Math.cos(angle)) < 0.2 && Math.sin(angle) < -0.8 && speedMultiplier > 0.9) {
			// Adjust vertical speed to ensure it reaches the pins
			self.velocityY = -reachPinsSpeed * (dragSpeed || 0.8);
		}
		self.active = true;
		self.hasCollided = false;
		LK.getSound('slide').play();
	};
	self.update = function () {
		if (!self.active) return;
		// Apply velocity
		self.x += self.velocityX;
		self.y += self.velocityY;
		// Apply friction
		// Ice physics - lower friction when moving fast, gradually increases as slowing down
		var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY);
		var dynamicFriction = speed > 10 ? 0.988 : speed > 5 ? 0.982 : 0.975; // More graduated and further reduced friction for slower ice physics
		self.velocityX *= dynamicFriction;
		self.velocityY *= dynamicFriction;
		// More realistic penguin rotation while sliding
		var rotationFactor = speed > 5 ? 0.005 : 0.01; // Less rotation at high speeds
		penguinGraphics.rotation += self.velocityX * rotationFactor;
		// Stop if velocity is very small
		if (Math.abs(self.velocityX) < 0.1 && Math.abs(self.velocityY) < 0.1) {
			self.active = false;
			self.velocityX = 0;
			self.velocityY = 0;
			penguinGraphics.rotation = 0; // Reset rotation when stopped
		}
		// Frame boundary checks with proper reflection vectors
		// Left boundary
		if (self.x < 0) {
			self.x = 0;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityX = -self.velocityX * 0.8; // Reverse X direction with reduced speed
			// If X velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityX) < 0.5) {
				self.velocityX = 0; // Perfect 90 degrees means no horizontal movement
				self.velocityY = self.velocityY > 0 ? speed : -speed; // Maintain vertical direction
			}
			// Award wall bounce bonus if active and hasn't collided yet
			if (self.active && !self.hasCollided) {
				self.wallBounceCount = self.wallBounceCount || 0;
				self.wallBounceCount++;
			}
		}
		// Right boundary
		else if (self.x > 2048) {
			self.x = 2048;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityX = -self.velocityX * 0.8; // Reverse X direction with reduced speed
			// If X velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityX) < 0.5) {
				self.velocityX = 0; // Perfect 90 degrees means no horizontal movement
				self.velocityY = self.velocityY > 0 ? speed : -speed; // Maintain vertical direction
			}
		}
		// Top boundary
		if (self.y < 0) {
			self.y = 0;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityY = -self.velocityY * 0.8; // Reverse Y direction with reduced speed
			// If Y velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityY) < 0.5) {
				self.velocityY = 0; // Perfect 90 degrees means no vertical movement
				self.velocityX = self.velocityX > 0 ? speed : -speed; // Maintain horizontal direction
			}
		}
		// Bottom boundary
		if (self.y > 2732) {
			self.y = 2732;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityY = -self.velocityY * 0.8; // Reverse Y direction with reduced speed
			// If Y velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityY) < 0.5) {
				self.velocityY = 0; // Perfect 90 degrees means no vertical movement
				self.velocityX = self.velocityX > 0 ? speed : -speed; // Maintain horizontal direction
			}
		}
		// Bowling lane boundary checks (light blue area)
		// Calculate bowling lane boundaries
		var laneLeftBoundary = bowlingLane.x - bowlingLane.width / 2;
		var laneRightBoundary = bowlingLane.x + bowlingLane.width / 2;
		var laneTopBoundary = bowlingLane.y;
		var laneBottomBoundary = bowlingLane.y + bowlingLane.height;
		// Check if penguin is outside the lane but not outside the game boundaries
		// Left lane boundary
		if (self.x < laneLeftBoundary && self.x > 0) {
			self.x = laneLeftBoundary;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityX = -self.velocityX * 0.8; // Reverse X direction with reduced speed
			// If X velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityX) < 0.5) {
				self.velocityX = 0;
				self.velocityY = self.velocityY > 0 ? speed : -speed;
			}
		}
		// Right lane boundary
		else if (self.x > laneRightBoundary && self.x < 2048) {
			self.x = laneRightBoundary;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityX = -self.velocityX * 0.8; // Reverse X direction with reduced speed
			// If X velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityX) < 0.5) {
				self.velocityX = 0;
				self.velocityY = self.velocityY > 0 ? speed : -speed;
			}
		}
		// Top lane boundary
		if (self.y < laneTopBoundary && self.y > 0) {
			self.y = laneTopBoundary;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityY = -self.velocityY * 0.8; // Reverse Y direction with reduced speed
			// If Y velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityY) < 0.5) {
				self.velocityY = 0;
				self.velocityX = self.velocityX > 0 ? speed : -speed;
			}
		}
		// Bottom lane boundary
		if (self.y > laneBottomBoundary && self.y < 2732) {
			self.y = laneBottomBoundary;
			// Calculate reflection vector for a 90-degree bounce with reduced speed
			var speed = Math.sqrt(self.velocityX * self.velocityX + self.velocityY * self.velocityY) * 0.8;
			self.velocityY = -self.velocityY * 0.8; // Reverse Y direction with reduced speed
			// If Y velocity is very small, set to zero for perfect 90-degree bounce
			if (Math.abs(self.velocityY) < 0.5) {
				self.velocityY = 0;
				self.velocityX = self.velocityX > 0 ? speed : -speed;
			}
		}
	};
	self.reset = function () {
		self.x = launchArea.x;
		self.y = launchArea.y - 250; // Move penguin further up the lane
		self.velocityX = 0;
		self.velocityY = 0;
		self.active = false;
		self.hasCollided = false;
		self.pullDistance = 0; // Reset pull distance
		self.wallBounceCount = 0; // Reset wall bounce counter
		self.dragSpeed = 0; // Reset drag speed
		self.lastMoveTime = 0; // Reset time tracking
		self.lastMoveX = 0; // Reset position tracking
		self.lastMoveY = 0; // Reset position tracking
		penguinGraphics.rotation = 0;
		self.resetBurnState();
	};
	// Add function to reset burn state
	self.resetBurnState = function () {
		self.burnCount = 0;
		self.isBurned = false;
		// Restore original penguin image
		penguinGraphics.texture = LK.getAsset('penguin', {}).texture;
	};
	// Add function to set penguin burned state
	self.setBurned = function () {
		self.isBurned = true;
		// Remove the old penguin graphics
		self.removeChild(penguinGraphics);
		// Create and add the burned penguin graphics with same anchor points
		penguinGraphics = self.attachAsset('burntPenguin', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Flash red to show penguin is burned
		LK.effects.flashObject(self, 0xff0000, 1000);
		// Stop penguin movement
		self.velocityX = 0;
		self.velocityY = 0;
		self.active = false;
	};
	return self;
});
var PowerMeter = Container.expand(function () {
	var self = Container.call(this);
	var meterBG = self.attachAsset('powerMeterBG', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var meter = self.attachAsset('powerMeter', {
		anchorX: 0.5,
		anchorY: 1.0,
		height: 0 // Start with no power
	});
	var maxPower = 300;
	self.power = 0;
	self.increasing = true;
	self.update = function () {
		if (self.visible) {
			if (self.increasing) {
				self.power += 5;
				if (self.power >= maxPower) {
					self.power = maxPower;
					self.increasing = false;
				}
			} else {
				self.power -= 5;
				if (self.power <= 0) {
					self.power = 0;
					self.increasing = true;
				}
			}
			// Update meter height based on power
			meter.height = self.power;
			meter.y = meterBG.y + meterBG.height / 2 - meter.height / 2;
		}
	};
	self.getPowerRatio = function () {
		return self.power / maxPower;
	};
	self.reset = function () {
		self.power = 0;
		self.increasing = true;
		meter.height = 0;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0xC7E6F7
});
/**** 
* Game Code
****/ 
// Game constants
var MAX_POWER = 15; // Reduced from 20 to make penguin slower
var PIN_ROWS = 4;
var FRAMES = 10;
var PINS_PER_FRAME = 10;
// Game state variables
var currentFrame = 1;
var pinsKnockedDown = 0;
var totalScore = 0;
var aiming = false;
var powering = false;
var gameState = "aiming"; // States: aiming, powering, sliding, scoring, gameover
var aimAngle = -Math.PI / 2; // Start aiming straight up
var consecutiveFailedStrikes = 0; // Track consecutive failures to get a strike
var strikeInLastFrame = false; // Track if the player got a strike in the last frame
var obstacle = null; // Reference to obstacle object
// Create background
var background = game.addChild(LK.getAsset('background', {
	anchorX: 0,
	anchorY: 0
}));
// Create bowling lane
var bowlingLane = game.addChild(LK.getAsset('bowlingLane', {
	anchorX: 0.5,
	anchorY: 0,
	x: 2048 / 2,
	y: 100
}));
// Create launch area
var launchArea = game.addChild(LK.getAsset('launchArea', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: 2400
}));
// Create the aiming line
var aimLine = game.addChild(LK.getAsset('aimLine', {
	anchorX: 0.5,
	anchorY: 1.0,
	x: launchArea.x,
	y: launchArea.y,
	visible: false
}));
// Arrow removed as requested
// Create the power meter
var powerMeter = game.addChild(new PowerMeter());
powerMeter.x = 1900;
powerMeter.y = 1400;
powerMeter.visible = false;
// Create the penguin
var penguin = game.addChild(new Penguin());
penguin.x = launchArea.x;
penguin.y = launchArea.y - 250; // Move penguin further up the lane
// Create bowling pins
var pins = [];
setupPins();
// Create UI elements
var frameText = new Text2('Frame: 1/10', {
	size: 70,
	fill: 0x000000
});
frameText.anchor.set(0.5, 0);
// Position frame text under the penguin's position
frameText.y = penguin.y + 150;
LK.gui.center.addChild(frameText);
var scoreText = new Text2('Score: 0', {
	size: 70,
	fill: 0x000000
});
scoreText.anchor.set(0.5, 0);
scoreText.y = 80;
LK.gui.top.addChild(scoreText);
var instructionText = new Text2('Tap and drag to pull penguin back, release to launch', {
	size: 50,
	fill: 0x000000
});
instructionText.anchor.set(0.5, 0);
instructionText.y = 180;
LK.gui.top.addChild(instructionText);
// Helper functions
function setupPins() {
	// Clear any existing pins
	for (var i = 0; i < pins.length; i++) {
		pins[i].destroy();
	}
	pins = [];
	// Create pin layout in traditional bowling triangle formation
	// Ensure pins are exactly centered on the lane
	var startX = 2048 / 2; // Center of screen
	var startY = 400; // Position from top
	var pinSpacingX = 120; // Fixed horizontal spacing regardless of strikes
	var pinSpacingY = 120; // Fixed vertical spacing regardless of strikes
	// Standard bowling pin layout (4-3-2-1 triangle)
	// First row (back) - 4 pins
	for (var i = 0; i < 4; i++) {
		var pin = new BowlingPin();
		pin.x = startX + (i - 1.5) * pinSpacingX; // Perfectly centered
		pin.y = startY;
		pin.row = 1; // Back row
		pin.lastX = pin.x;
		pin.lastY = pin.y;
		pins.push(pin);
		game.addChild(pin);
	}
	// Second row - 3 pins
	for (var i = 0; i < 3; i++) {
		var pin = new BowlingPin();
		pin.x = startX + (i - 1) * pinSpacingX; // Centered relative to first row
		pin.y = startY + pinSpacingY;
		pin.row = 2; // Second row
		pin.lastX = pin.x;
		pin.lastY = pin.y;
		pins.push(pin);
		game.addChild(pin);
	}
	// Third row - 2 pins
	for (var i = 0; i < 2; i++) {
		var pin = new BowlingPin();
		pin.x = startX + (i - 0.5) * pinSpacingX; // Centered relative to second row
		pin.y = startY + 2 * pinSpacingY;
		pin.row = 3; // Third row
		pin.lastX = pin.x;
		pin.lastY = pin.y;
		pins.push(pin);
		game.addChild(pin);
	}
	// Fourth row (front) - 1 pin
	var pin = new BowlingPin();
	pin.x = startX; // Center pin
	pin.y = startY + 3 * pinSpacingY;
	pin.row = 4; // Front row
	pin.lastX = pin.x;
	pin.lastY = pin.y;
	pins.push(pin);
	game.addChild(pin);
	pinsKnockedDown = 0;
	// Reset penguin burn state for new frame
	penguin.resetBurnState();
	// Remove any existing obstacle
	if (typeof obstacle !== 'undefined' && obstacle) {
		obstacle.destroy();
		obstacle = null;
	}
	// Add obstacle after strike
	if (currentFrame > 1 && strikeInLastFrame) {
		// Create obstacle based on a random position (left or right)
		var obstaclePosition = Math.random() < 0.5 ? "left" : "right";
		obstacle = game.addChild(LK.getAsset('horizontalline', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 500,
			height: 50,
			x: startX,
			y: 1200
		}));
		// If obstacle is on the left side, move it to the left half of the lane
		if (obstaclePosition === "left") {
			obstacle.x = startX - 300;
		} else {
			obstacle.x = startX + 300;
		}
		// Display instruction about the obstacle
		instructionText.setText("Obstacle added! Find a way around it to hit the pins!");
	}
}
function updateAimLine() {
	aimLine.rotation = aimAngle;
	// Ensure the aim line points from the penguin position
	aimLine.x = launchArea.x;
	aimLine.y = launchArea.y;
}
function launchPenguin() {
	// Calculate power based on the pull distance
	var powerRatio = Math.min(penguin.pullDistance / 300, 1); // Normalize based on max drag distance
	var power = powerRatio * MAX_POWER;
	// Launch penguin from current position toward the launch area
	var launchAngle = aimAngle + Math.PI; // Reverse the angle to launch toward the pins
	// Calculate final drag speed, normalize between 0.4 and 1.5 (reduced from 0.5-2.0)
	var dragSpeedFactor = 0.8; // Default if no drag speed calculated (reduced from 1.0)
	if (penguin.dragSpeed) {
		// Cap the drag speed between 0.4 (slower) and 1.5 (faster)
		dragSpeedFactor = Math.max(0.4, Math.min(1.5, penguin.dragSpeed / 6));
	}
	// Launch with power and drag speed
	penguin.launch(launchAngle, power, dragSpeedFactor);
	gameState = "sliding";
	powerMeter.visible = false;
	// Update instruction text to include drag speed information
	var speedMsg = dragSpeedFactor > 1.0 ? " Fast release!" : dragSpeedFactor < 0.8 ? " Slow release!" : "";
	var difficultyMsg = pinSpacingMultiplier > 1.0 ? " - Difficulty: " + Math.round((pinSpacingMultiplier - 1) * 100) + "%" : "";
	if (powerRatio >= 0.9) {
		instructionText.setText("Full power!" + speedMsg + " Watch the penguin slide!" + difficultyMsg);
	} else {
		instructionText.setText("Watch the penguin slide! (Power: " + Math.round(powerRatio * 100) + "%)" + speedMsg + difficultyMsg);
	}
}
function checkCollisions() {
	if (!penguin.active || penguin.hasCollided) return;
	var newKnockdowns = 0;
	// Calculate penguin velocity magnitude for physics-based knockdown
	var penguinSpeed = Math.sqrt(penguin.velocityX * penguin.velocityX + penguin.velocityY * penguin.velocityY);
	var penguinDirection = Math.atan2(penguin.velocityY, penguin.velocityX);
	// Check penguin collision with ANY pin based on realistic physics
	for (var i = 0; i < pins.length; i++) {
		var pin = pins[i];
		if (!pin.isKnockedDown && penguin.intersects(pin)) {
			// Calculate direction of impact from penguin to pin
			var impactAngle = Math.atan2(pin.y - penguin.y, pin.x - penguin.x);
			// Calculate angle difference to determine if hitting from front, side, etc.
			var angleDiff = Math.abs((impactAngle - penguinDirection + Math.PI) % (2 * Math.PI) - Math.PI);
			// More realistic physics: energy transfer based on angle of impact and penguin speed
			var energyTransfer = penguinSpeed * (1 - angleDiff / Math.PI);
			// Knock down pin with physics impact
			if (pin.applyImpact(penguin.x, penguin.y, energyTransfer)) {
				newKnockdowns++;
				pinsKnockedDown++;
				// Update score
				totalScore += 1;
				updateScoreDisplay();
			}
		}
	}
	// Now check for pin-to-pin collisions between ALL pins with realistic physics
	for (var i = 0; i < pins.length; i++) {
		var pin1 = pins[i];
		if (pin1.isKnockedDown && pin1.collisionEnergy > 1) {
			// This pin is moving with enough energy to cause collisions
			for (var j = 0; j < pins.length; j++) {
				var pin2 = pins[j];
				if (i !== j && pin1.intersects(pin2)) {
					// Calculate impact dynamics
					var impactDirection = Math.atan2(pin2.y - pin1.y, pin2.x - pin1.x);
					var impactSpeed = Math.sqrt(pin1.velocityX * pin1.velocityX + pin1.velocityY * pin1.velocityY);
					// If pin2 is not knocked down, apply impact
					if (!pin2.isKnockedDown) {
						if (pin2.applyImpact(pin1.x, pin1.y, pin1.collisionEnergy * 0.7)) {
							pinsKnockedDown++;
							totalScore += 1;
							updateScoreDisplay();
						}
					}
					// Both pins are moving - apply realistic collision physics
					else {
						// Calculate new velocities based on conservation of momentum
						var velocity1 = Math.sqrt(pin1.velocityX * pin1.velocityX + pin1.velocityY * pin1.velocityY);
						var velocity2 = Math.sqrt(pin2.velocityX * pin2.velocityX + pin2.velocityY * pin2.velocityY);
						if (velocity1 > 0.5 || velocity2 > 0.5) {
							// Simple elastic collision - exchange some momentum
							var tempVX = pin1.velocityX * 0.5;
							var tempVY = pin1.velocityY * 0.5;
							pin1.velocityX = pin1.velocityX * 0.5 + pin2.velocityX * 0.5;
							pin1.velocityY = pin1.velocityY * 0.5 + pin2.velocityY * 0.5;
							pin2.velocityX = tempVX * 0.5 + pin2.velocityX * 0.5;
							pin2.velocityY = tempVY * 0.5 + pin2.velocityY * 0.5;
							// Add some random scatter for realism
							pin1.velocityX += (Math.random() - 0.5) * 0.5;
							pin1.velocityY += (Math.random() - 0.5) * 0.5;
							pin2.velocityX += (Math.random() - 0.5) * 0.5;
							pin2.velocityY += (Math.random() - 0.5) * 0.5;
							// Update rotation velocities
							pin1.rotationVelocity += (Math.random() - 0.5) * 0.1;
							pin2.rotationVelocity += (Math.random() - 0.5) * 0.1;
						}
					}
				}
			}
		}
	}
	// Handle collision with obstacle if present - make it completely impassable like a solid wall
	if (typeof obstacle !== 'undefined' && obstacle && penguin.intersects(obstacle)) {
		// Store previous position before intersection occurred
		var prevX = penguin.lastX || penguin.x;
		var prevY = penguin.lastY || penguin.y;
		// Determine collision direction by comparing previous position to obstacle
		var hitFromLeft = prevX < obstacle.x - obstacle.width / 4;
		var hitFromRight = prevX > obstacle.x + obstacle.width / 4;
		var hitFromTop = prevY < obstacle.y - obstacle.height / 4;
		var hitFromBottom = prevY > obstacle.y + obstacle.height / 4;
		// Calculate bounce velocity with energy loss
		var bounceMultiplier = 0.7; // 30% energy loss on bounce
		// Horizontal collision (from left or right)
		if (hitFromLeft || hitFromRight) {
			// Position correction - move outside obstacle
			penguin.x = hitFromLeft ? obstacle.x - obstacle.width / 2 - penguin.width / 2 - 5 :
			// 5px extra buffer
			obstacle.x + obstacle.width / 2 + penguin.width / 2 + 5;
			// Reverse X velocity with energy loss
			penguin.velocityX = -penguin.velocityX * bounceMultiplier;
		}
		// Vertical collision (from top or bottom)
		if (hitFromTop || hitFromBottom) {
			// Position correction - move outside obstacle
			penguin.y = hitFromTop ? obstacle.y - obstacle.height / 2 - penguin.height / 2 - 5 :
			// 5px extra buffer
			obstacle.y + obstacle.height / 2 + penguin.height / 2 + 5;
			// Reverse Y velocity with energy loss
			penguin.velocityY = -penguin.velocityY * bounceMultiplier;
		}
		// Ensure minimum bounce velocity
		var minBounceVelocity = 2.0;
		if (Math.abs(penguin.velocityX) < minBounceVelocity && (hitFromLeft || hitFromRight)) {
			penguin.velocityX = hitFromLeft ? -minBounceVelocity : minBounceVelocity;
		}
		if (Math.abs(penguin.velocityY) < minBounceVelocity && (hitFromTop || hitFromBottom)) {
			penguin.velocityY = hitFromTop ? -minBounceVelocity : minBounceVelocity;
		}
		// Play sound effect for the bounce
		LK.getSound('pinHit').play();
		// Track obstacle collisions for burn mechanic
		penguin.burnCount++;
		// When penguin hits the obstacle, immediately set it to burned
		penguin.setBurned();
		// Play burn sound effect
		LK.getSound('burn').play();
		instructionText.setText("Penguin got burned after hitting the obstacle!");
		// Game over after a short delay
		LK.setTimeout(function () {
			LK.showGameOver();
		}, 2000);
		// Flash screen red to indicate burn
		LK.effects.flashScreen(0xff0000, 1000);
	}
	if (newKnockdowns > 0) {
		penguin.hasCollided = true;
		// Play strike sound if all pins are knocked down
		if (pinsKnockedDown === PINS_PER_FRAME) {
			LK.getSound('strike').play();
			LK.effects.flashScreen(0xFFFFFF, 500);
			instructionText.setText("STRIKE!");
		}
	}
}
function updateScoreDisplay() {
	scoreText.setText("Score: " + totalScore);
	// Update high score if needed
	if (totalScore > storage.highScore) {
		storage.highScore = totalScore;
	}
}
function nextFrame() {
	// Check if player got a strike
	var isStrike = pinsKnockedDown === PINS_PER_FRAME;
	// Store if we had a strike in the last frame to use in setupPins
	strikeInLastFrame = isStrike;
	// Update consecutive fails counter
	if (isStrike) {
		consecutiveFailedStrikes = 0;
		instructionText.setText("STRIKE! Next frame will have an obstacle!");
		// Make penguin slower after each strike
		MAX_POWER = Math.max(5, MAX_POWER - 1); // Decrease power but ensure minimum of 5
		// If there's an existing obstacle, make it wider for the next frame
		if (typeof obstacle !== 'undefined' && obstacle) {
			obstacle.width += 100; // Increase obstacle width by 100px
		}
	} else {
		consecutiveFailedStrikes++;
		// Check for game over condition (2 consecutive failed strikes)
		if (consecutiveFailedStrikes >= 2) {
			gameState = "gameover";
			instructionText.setText("Game Over! 2 consecutive misses! Final Score: " + totalScore);
			// Show game over screen after a brief delay
			LK.setTimeout(function () {
				LK.showGameOver();
			}, 2000);
			return;
		}
	}
	currentFrame++;
	if (currentFrame > FRAMES) {
		// Game over
		gameState = "gameover";
		instructionText.setText("Game Over! Final Score: " + totalScore);
		// Show game over screen after a brief delay
		LK.setTimeout(function () {
			LK.showGameOver();
		}, 2000);
	} else {
		// Setup for next frame
		frameText.setText("Frame: " + currentFrame + "/10");
		// Reset pins regardless of strike
		setupPins();
		penguin.reset();
		gameState = "aiming";
		// Update instruction based on presence of obstacle
		if (typeof obstacle !== 'undefined' && obstacle) {
			instructionText.setText("Tap and drag backward to aim, find a path around the obstacle!");
		} else {
			instructionText.setText("Tap and drag backward to aim, release to launch");
		}
	}
}
function checkGameStateTransition() {
	if (gameState === "sliding") {
		// Check if penguin has stopped
		if (!penguin.active) {
			// Add wall bounce bonus if any
			if (penguin.wallBounceCount && penguin.wallBounceCount > 0) {
				var bounceBonus = penguin.wallBounceCount * 2;
				totalScore += bounceBonus;
				instructionText.setText("Nice trick shot! +" + bounceBonus + " bonus points!");
				updateScoreDisplay();
			}
			// Wait a bit for pins to settle and then move to next frame
			LK.setTimeout(function () {
				nextFrame();
			}, 2000);
			gameState = "scoring";
		}
	}
}
// Event handlers
game.down = function (x, y, obj) {
	if (gameState === "aiming") {
		aiming = true;
		aimLine.visible = false;
		// Store original penguin position
		penguin.originalX = penguin.x;
		penguin.originalY = penguin.y;
	}
};
game.move = function (x, y, obj) {
	if (aiming) {
		// Store the current time and position for calculating drag speed
		var currentTime = Date.now();
		if (!penguin.lastMoveTime) {
			penguin.lastMoveTime = currentTime;
			penguin.lastMoveX = x;
			penguin.lastMoveY = y;
		}
		// Calculate aim angle from penguin to opposite of pull direction
		var dx = launchArea.x - x;
		var dy = launchArea.y - y;
		// Calculate the distance of the pull for power
		var distance = Math.sqrt(dx * dx + dy * dy);
		// Limit the maximum drag distance
		var maxDrag = 300;
		distance = Math.min(distance, maxDrag);
		// Calculate the angle
		aimAngle = Math.atan2(dy, dx);
		// Move the penguin to the drag position
		penguin.x = launchArea.x - Math.cos(aimAngle) * distance;
		penguin.y = launchArea.y - Math.sin(aimAngle) * distance;
		// Store the pull distance for calculating power later
		penguin.pullDistance = distance;
		// Calculate drag speed based on pointer movement
		var timeDiff = currentTime - penguin.lastMoveTime;
		if (timeDiff > 0) {
			var moveDistX = x - penguin.lastMoveX;
			var moveDistY = y - penguin.lastMoveY;
			var moveDist = Math.sqrt(moveDistX * moveDistX + moveDistY * moveDistY);
			penguin.dragSpeed = moveDist / timeDiff * 10; // Scale factor to make it reasonable
			// Update last values for next calculation
			penguin.lastMoveTime = currentTime;
			penguin.lastMoveX = x;
			penguin.lastMoveY = y;
		}
	}
};
game.up = function (x, y, obj) {
	if (aiming) {
		aiming = false;
		// Calculate final drag speed on release
		var currentTime = Date.now();
		if (penguin.lastMoveTime && currentTime - penguin.lastMoveTime < 200) {
			// If the player released quickly after the last move, use that as speed indicator
			var timeDiff = currentTime - penguin.lastMoveTime;
			if (timeDiff > 0) {
				var moveDistX = x - penguin.lastMoveX;
				var moveDistY = y - penguin.lastMoveY;
				var moveDist = Math.sqrt(moveDistX * moveDistX + moveDistY * moveDistY);
				// Final release speed calculation
				var releaseSpeed = moveDist / timeDiff * 15; // Scale factor for release speed
				// Combine with ongoing drag speed for a weighted average
				penguin.dragSpeed = (penguin.dragSpeed + releaseSpeed) / 2;
			}
		}
		// Only launch if penguin was actually pulled back
		if (penguin.pullDistance > 10) {
			// Launch immediately after release
			launchPenguin();
		} else {
			// Reset penguin position if not pulled back enough
			penguin.x = penguin.originalX;
			penguin.y = penguin.originalY;
			penguin.dragSpeed = 0; // Reset drag speed if not launching
		}
	}
};
// Game update loop
game.update = function () {
	if (gameState === "sliding") {
		penguin.update();
		// Update pin physics
		for (var i = 0; i < pins.length; i++) {
			pins[i].update();
		}
		checkCollisions();
		// Check for pin-to-pin collisions even after penguin has finished moving
		if (penguin.hasCollided) {
			for (var i = 0; i < pins.length; i++) {
				var pin1 = pins[i];
				if (pin1.isKnockedDown && pin1.visible && (Math.abs(pin1.velocityX) > 0.5 || Math.abs(pin1.velocityY) > 0.5)) {
					for (var j = 0; j < pins.length; j++) {
						var pin2 = pins[j];
						if (i !== j && !pin2.isKnockedDown && pin2.visible && pin1.intersects(pin2)) {
							if (pin2.knockDown()) {
								pinsKnockedDown++;
								totalScore++;
								updateScoreDisplay();
							}
						}
					}
				}
			}
		}
		checkGameStateTransition();
	}
};
// Initialize variables and start the game
consecutiveFailedStrikes = 0;
pinSpacingMultiplier = 1.0;
// Show initial instructions
instructionText.setText("Tap and drag backward to aim, release to launch. 2 misses = Game Over!");
// Start background music
LK.playMusic('gameMusic');
;
 A cartoon-style penguin lying flat on its belly, facing forward with its body stretched out. In-Game asset. 2d. High contrast. No shadows
 Bowling pin. In-Game asset. 2d. High contrast. No shadows
 iglo. In-Game asset. 2d. High contrast. No shadows
 Icy surface. In-Game asset. 2d. High contrast. No shadows
 Snow gently falling from the sky in a peaceful winter scene. The snowflakes are soft and light, creating a calm atmosphere. The snow is falling in large, delicate flakes, covering the icy surface and creating a serene, magical ambiance.". In-Game asset. 2d. High contrast. No shadows
 horizontal fire. In-Game asset. 2d. High contrast. No shadows
 pişmiş tavuk. In-Game asset. 2d. High contrast. No shadows