/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
var Ball = Container.expand(function () {
	var self = Container.call(this);
	var ballGraphics = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.velocity = {
		x: 0,
		y: 0
	};
	self.gravity = 0.2;
	self.bounceFactor = 0.7;
	self.active = true;
	self.update = function () {
		if (!self.active) {
			return;
		}
		// Apply gravity
		self.velocity.y += self.gravity;
		// Update position
		self.x += self.velocity.x;
		self.y += self.velocity.y;
		// Check for collisions with pins
		for (var i = 0; i < pins.length; i++) {
			if (self.intersects(pins[i])) {
				self.handlePinCollision(pins[i]);
			}
		}
		// Check for wall collisions
		if (self.x < leftWall.x + leftWall.width / 2 + ballGraphics.width / 2) {
			self.x = leftWall.x + leftWall.width / 2 + ballGraphics.width / 2;
			self.velocity.x = Math.abs(self.velocity.x) * self.bounceFactor;
			LK.getSound('bounce').play();
		} else if (self.x > rightWall.x - rightWall.width / 2 - ballGraphics.width / 2) {
			self.x = rightWall.x - rightWall.width / 2 - ballGraphics.width / 2;
			self.velocity.x = -Math.abs(self.velocity.x) * self.bounceFactor;
			LK.getSound('bounce').play();
		}
		// Check for score zones
		if (self.y > gameHeight - 150) {
			if (self.intersects(scoreZone1)) {
				self.score(10);
			} else if (self.intersects(scoreZone2)) {
				self.score(30);
			} else if (self.intersects(scoreZone3)) {
				self.score(10);
			}
		}
		// Remove ball if it goes out of bounds
		if (self.y > gameHeight + 100) {
			self.destroy();
			var index = balls.indexOf(self);
			if (index !== -1) {
				balls.splice(index, 1);
			}
		}
	};
	self.handlePinCollision = function (pin) {
		// Calculate collision vector
		var dx = self.x - pin.x;
		var dy = self.y - pin.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		// Minimum distance to prevent overlap
		var minDistance = ballGraphics.width / 2 + pin.width / 2;
		if (distance < minDistance) {
			// Normalize direction vector
			var nx = dx / distance;
			var ny = dy / distance;
			// Move ball outside of pin
			var penetrationDepth = minDistance - distance;
			self.x += nx * penetrationDepth;
			self.y += ny * penetrationDepth;
			// Calculate bounce
			var dotProduct = self.velocity.x * nx + self.velocity.y * ny;
			// Apply bounce with some randomness
			self.velocity.x = (self.velocity.x - 2 * dotProduct * nx) * self.bounceFactor;
			self.velocity.y = (self.velocity.y - 2 * dotProduct * ny) * self.bounceFactor;
			// Add a bit of randomness for more interesting gameplay
			self.velocity.x += (Math.random() - 0.5) * 0.5;
			LK.getSound('bounce').play();
		}
	};
	self.score = function (points) {
		if (self.active) {
			LK.setScore(LK.getScore() + points);
			scoreTxt.setText(LK.getScore());
			LK.getSound('score').play();
			self.active = false;
			// Flash the ball
			LK.effects.flashObject(self, 0xFFFFFF, 500);
			// Check for win condition
			if (LK.getScore() >= winScore) {
				LK.showYouWin();
			}
		}
	};
	return self;
});
var Launcher = Container.expand(function () {
	var self = Container.call(this);
	var launcherGraphics = self.attachAsset('launcher', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.cooldown = 0;
	self.cooldownTime = 45; // Number of frames to wait between ball launches
	self.update = function () {
		if (self.cooldown > 0) {
			self.cooldown--;
		}
	};
	self.launch = function () {
		if (self.cooldown > 0 || remainingBalls <= 0) {
			return;
		}
		var ball = new Ball();
		ball.x = self.x;
		ball.y = self.y + 30;
		ball.velocity.x = (Math.random() - 0.5) * 2; // Small random horizontal velocity
		ball.velocity.y = 1; // Initial downward velocity
		game.addChild(ball);
		balls.push(ball);
		self.cooldown = self.cooldownTime;
		remainingBalls--;
		ballCountTxt.setText("Balls: " + remainingBalls);
		// Game over if no balls left and no active balls
		if (remainingBalls <= 0) {
			checkGameOver();
		}
	};
	self.down = function (x, y, obj) {
		self.launch();
	};
	return self;
});
var Pin = Container.expand(function () {
	var self = Container.call(this);
	var pinGraphics = self.attachAsset('pin', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x4477BB
});
/**** 
* Game Code
****/ 
// Game constants
var gameWidth = 2048;
var gameHeight = 2732;
var winScore = 500;
var initialBalls = 20;
var remainingBalls = initialBalls;
var balls = [];
var pins = [];
// Create timer UI
var timeLimit = 120; // 120 seconds time limit 
var timeRemaining = timeLimit;
var timerTxt = new Text2("Time: " + timeRemaining, {
	size: 80,
	fill: 0xFFFFFF
});
timerTxt.anchor.set(0.5, 0);
timerTxt.x = gameWidth / 2;
timerTxt.y = 50;
LK.gui.top.addChild(timerTxt);
// Create scoring UI
var scoreTxt = new Text2('0', {
	size: 120,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var ballCountTxt = new Text2("Balls: " + remainingBalls, {
	size: 80,
	fill: 0xFFFFFF
});
ballCountTxt.anchor.set(0, 0);
ballCountTxt.x = 150;
ballCountTxt.y = 50;
LK.gui.topRight.addChild(ballCountTxt);
// Add background image
var background = LK.getAsset('background', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: gameWidth / 2,
	y: gameHeight / 2,
	scaleX: gameWidth / 100,
	scaleY: gameHeight / 100
});
game.addChild(background);
// Create game elements
var launcher = new Launcher();
launcher.x = gameWidth / 2;
launcher.y = 100;
game.addChild(launcher);
// Create walls
var leftWall = game.addChild(LK.getAsset('wall', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 20,
	y: gameHeight / 2
}));
var rightWall = game.addChild(LK.getAsset('wall', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: gameWidth - 20,
	y: gameHeight / 2
}));
// Create score zones at the bottom
var scoreZone1 = game.addChild(LK.getAsset('scoreZone1', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: gameWidth / 6 + 100,
	y: gameHeight - 50
}));
var scoreZone2 = game.addChild(LK.getAsset('scoreZone2', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: gameWidth / 2,
	y: gameHeight - 50
}));
var scoreZone3 = game.addChild(LK.getAsset('scoreZone3', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: gameWidth - (gameWidth / 6 + 100),
	y: gameHeight - 50
}));
// Create pins in a triangle pattern
function createPins() {
	var rowSpacing = 150;
	var pinSpacing = 120;
	var startY = 400;
	var rows = 10;
	for (var row = 0; row < rows; row++) {
		var pinsInRow = row + 5;
		var rowWidth = pinSpacing * (pinsInRow - 1);
		var startX = (gameWidth - rowWidth) / 2;
		for (var i = 0; i < pinsInRow; i++) {
			var pin = new Pin();
			pin.x = startX + i * pinSpacing;
			pin.y = startY + row * rowSpacing;
			// Add some randomness to pin positions
			pin.x += (Math.random() - 0.5) * 20;
			pin.y += (Math.random() - 0.5) * 20;
			game.addChild(pin);
			pins.push(pin);
		}
	}
}
// Create game instructions
var instructionsTxt = new Text2("Tap anywhere to launch balls!", {
	size: 70,
	fill: 0xFFFFFF
});
instructionsTxt.anchor.set(0.5, 0);
instructionsTxt.y = 180;
LK.gui.top.addChild(instructionsTxt);
function checkGameOver() {
	var timeout = LK.setTimeout(function () {
		if (remainingBalls <= 0 && balls.length === 0) {
			LK.showGameOver();
		} else {
			checkGameOver();
		}
	}, 1000);
}
// Game touch controls
game.down = function (x, y, obj) {
	launcher.launch();
};
// Initialize pins
createPins();
// Play background music
LK.playMusic('bgmusic', {
	fade: {
		start: 0,
		end: 0.6,
		duration: 1000
	}
});
// Main game update loop
game.update = function () {
	launcher.update();
	// Update all balls
	for (var i = 0; i < balls.length; i++) {
		if (balls[i]) {
			balls[i].update();
			// Decrease the timer
			if (timeRemaining > 0) {
				timeRemaining -= 1 / 60; // Decrease by 1 second every 60 frames
				timerTxt.setText("Time: " + Math.ceil(timeRemaining));
			} else {
				// Time is up, show game over
				LK.showGameOver();
			}
		}
		;
	}
}; /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/**** 
* Classes
****/ 
var Ball = Container.expand(function () {
	var self = Container.call(this);
	var ballGraphics = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.velocity = {
		x: 0,
		y: 0
	};
	self.gravity = 0.2;
	self.bounceFactor = 0.7;
	self.active = true;
	self.update = function () {
		if (!self.active) {
			return;
		}
		// Apply gravity
		self.velocity.y += self.gravity;
		// Update position
		self.x += self.velocity.x;
		self.y += self.velocity.y;
		// Check for collisions with pins
		for (var i = 0; i < pins.length; i++) {
			if (self.intersects(pins[i])) {
				self.handlePinCollision(pins[i]);
			}
		}
		// Check for wall collisions
		if (self.x < leftWall.x + leftWall.width / 2 + ballGraphics.width / 2) {
			self.x = leftWall.x + leftWall.width / 2 + ballGraphics.width / 2;
			self.velocity.x = Math.abs(self.velocity.x) * self.bounceFactor;
			LK.getSound('bounce').play();
		} else if (self.x > rightWall.x - rightWall.width / 2 - ballGraphics.width / 2) {
			self.x = rightWall.x - rightWall.width / 2 - ballGraphics.width / 2;
			self.velocity.x = -Math.abs(self.velocity.x) * self.bounceFactor;
			LK.getSound('bounce').play();
		}
		// Check for score zones
		if (self.y > gameHeight - 150) {
			if (self.intersects(scoreZone1)) {
				self.score(10);
			} else if (self.intersects(scoreZone2)) {
				self.score(30);
			} else if (self.intersects(scoreZone3)) {
				self.score(10);
			}
		}
		// Remove ball if it goes out of bounds
		if (self.y > gameHeight + 100) {
			self.destroy();
			var index = balls.indexOf(self);
			if (index !== -1) {
				balls.splice(index, 1);
			}
		}
	};
	self.handlePinCollision = function (pin) {
		// Calculate collision vector
		var dx = self.x - pin.x;
		var dy = self.y - pin.y;
		var distance = Math.sqrt(dx * dx + dy * dy);
		// Minimum distance to prevent overlap
		var minDistance = ballGraphics.width / 2 + pin.width / 2;
		if (distance < minDistance) {
			// Normalize direction vector
			var nx = dx / distance;
			var ny = dy / distance;
			// Move ball outside of pin
			var penetrationDepth = minDistance - distance;
			self.x += nx * penetrationDepth;
			self.y += ny * penetrationDepth;
			// Calculate bounce
			var dotProduct = self.velocity.x * nx + self.velocity.y * ny;
			// Apply bounce with some randomness
			self.velocity.x = (self.velocity.x - 2 * dotProduct * nx) * self.bounceFactor;
			self.velocity.y = (self.velocity.y - 2 * dotProduct * ny) * self.bounceFactor;
			// Add a bit of randomness for more interesting gameplay
			self.velocity.x += (Math.random() - 0.5) * 0.5;
			LK.getSound('bounce').play();
		}
	};
	self.score = function (points) {
		if (self.active) {
			LK.setScore(LK.getScore() + points);
			scoreTxt.setText(LK.getScore());
			LK.getSound('score').play();
			self.active = false;
			// Flash the ball
			LK.effects.flashObject(self, 0xFFFFFF, 500);
			// Check for win condition
			if (LK.getScore() >= winScore) {
				LK.showYouWin();
			}
		}
	};
	return self;
});
var Launcher = Container.expand(function () {
	var self = Container.call(this);
	var launcherGraphics = self.attachAsset('launcher', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.cooldown = 0;
	self.cooldownTime = 45; // Number of frames to wait between ball launches
	self.update = function () {
		if (self.cooldown > 0) {
			self.cooldown--;
		}
	};
	self.launch = function () {
		if (self.cooldown > 0 || remainingBalls <= 0) {
			return;
		}
		var ball = new Ball();
		ball.x = self.x;
		ball.y = self.y + 30;
		ball.velocity.x = (Math.random() - 0.5) * 2; // Small random horizontal velocity
		ball.velocity.y = 1; // Initial downward velocity
		game.addChild(ball);
		balls.push(ball);
		self.cooldown = self.cooldownTime;
		remainingBalls--;
		ballCountTxt.setText("Balls: " + remainingBalls);
		// Game over if no balls left and no active balls
		if (remainingBalls <= 0) {
			checkGameOver();
		}
	};
	self.down = function (x, y, obj) {
		self.launch();
	};
	return self;
});
var Pin = Container.expand(function () {
	var self = Container.call(this);
	var pinGraphics = self.attachAsset('pin', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x4477BB
});
/**** 
* Game Code
****/ 
// Game constants
var gameWidth = 2048;
var gameHeight = 2732;
var winScore = 500;
var initialBalls = 20;
var remainingBalls = initialBalls;
var balls = [];
var pins = [];
// Create timer UI
var timeLimit = 120; // 120 seconds time limit 
var timeRemaining = timeLimit;
var timerTxt = new Text2("Time: " + timeRemaining, {
	size: 80,
	fill: 0xFFFFFF
});
timerTxt.anchor.set(0.5, 0);
timerTxt.x = gameWidth / 2;
timerTxt.y = 50;
LK.gui.top.addChild(timerTxt);
// Create scoring UI
var scoreTxt = new Text2('0', {
	size: 120,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var ballCountTxt = new Text2("Balls: " + remainingBalls, {
	size: 80,
	fill: 0xFFFFFF
});
ballCountTxt.anchor.set(0, 0);
ballCountTxt.x = 150;
ballCountTxt.y = 50;
LK.gui.topRight.addChild(ballCountTxt);
// Add background image
var background = LK.getAsset('background', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: gameWidth / 2,
	y: gameHeight / 2,
	scaleX: gameWidth / 100,
	scaleY: gameHeight / 100
});
game.addChild(background);
// Create game elements
var launcher = new Launcher();
launcher.x = gameWidth / 2;
launcher.y = 100;
game.addChild(launcher);
// Create walls
var leftWall = game.addChild(LK.getAsset('wall', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 20,
	y: gameHeight / 2
}));
var rightWall = game.addChild(LK.getAsset('wall', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: gameWidth - 20,
	y: gameHeight / 2
}));
// Create score zones at the bottom
var scoreZone1 = game.addChild(LK.getAsset('scoreZone1', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: gameWidth / 6 + 100,
	y: gameHeight - 50
}));
var scoreZone2 = game.addChild(LK.getAsset('scoreZone2', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: gameWidth / 2,
	y: gameHeight - 50
}));
var scoreZone3 = game.addChild(LK.getAsset('scoreZone3', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: gameWidth - (gameWidth / 6 + 100),
	y: gameHeight - 50
}));
// Create pins in a triangle pattern
function createPins() {
	var rowSpacing = 150;
	var pinSpacing = 120;
	var startY = 400;
	var rows = 10;
	for (var row = 0; row < rows; row++) {
		var pinsInRow = row + 5;
		var rowWidth = pinSpacing * (pinsInRow - 1);
		var startX = (gameWidth - rowWidth) / 2;
		for (var i = 0; i < pinsInRow; i++) {
			var pin = new Pin();
			pin.x = startX + i * pinSpacing;
			pin.y = startY + row * rowSpacing;
			// Add some randomness to pin positions
			pin.x += (Math.random() - 0.5) * 20;
			pin.y += (Math.random() - 0.5) * 20;
			game.addChild(pin);
			pins.push(pin);
		}
	}
}
// Create game instructions
var instructionsTxt = new Text2("Tap anywhere to launch balls!", {
	size: 70,
	fill: 0xFFFFFF
});
instructionsTxt.anchor.set(0.5, 0);
instructionsTxt.y = 180;
LK.gui.top.addChild(instructionsTxt);
function checkGameOver() {
	var timeout = LK.setTimeout(function () {
		if (remainingBalls <= 0 && balls.length === 0) {
			LK.showGameOver();
		} else {
			checkGameOver();
		}
	}, 1000);
}
// Game touch controls
game.down = function (x, y, obj) {
	launcher.launch();
};
// Initialize pins
createPins();
// Play background music
LK.playMusic('bgmusic', {
	fade: {
		start: 0,
		end: 0.6,
		duration: 1000
	}
});
// Main game update loop
game.update = function () {
	launcher.update();
	// Update all balls
	for (var i = 0; i < balls.length; i++) {
		if (balls[i]) {
			balls[i].update();
			// Decrease the timer
			if (timeRemaining > 0) {
				timeRemaining -= 1 / 60; // Decrease by 1 second every 60 frames
				timerTxt.setText("Time: " + Math.ceil(timeRemaining));
			} else {
				// Time is up, show game over
				LK.showGameOver();
			}
		}
		;
	}
};
 clown face. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
 circus tent. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
 gold blocks. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
 silver blocks. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
 anime circus tent field. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows