User prompt
Top daha yavaş hareket etsin
User prompt
Kamera görüntüsü iki kat küçük olsun ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
Görüntü iki kat küçük olsun
User prompt
Top daha yavaş hareket etsin
Code edit (1 edits merged)
Please save this source code
User prompt
top sekerken dönerek ilerlesin
User prompt
bonus nesnesini aldıktan sonra yeni bir bonus nesnesi oluşsun
User prompt
bonus nesnesi ekranın üst taraflarına yakın yerlerde oluşsun.
User prompt
ekranın rastgele bir yerinde bonus nesnesi oluşsun. top ona çarparsa 2 kat fazla puan toplayalım
User prompt
top biraz daha yavaş seksin
User prompt
topun sekme hızı kafa atma hızımızla uyumlu olsun. top ekrandan dışarı çıkamasın. üst tarafa ve kenarlara çarpabilsin ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
topun sekme hızı kafa atma hızımızla uyumlu olsun ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
Code edit (1 edits merged)
Please save this source code
User prompt
topa kafamızın üstüyle vuralım. ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
User prompt
burnumla değil de kafamızın üstü ile topa vurabilelim ↪💡 Consider importing and using the following plugins: @upit/facekit.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Face Bounce
Initial prompt
yüzümü kameradan tanı. ekranda bir top olsun. kaameradan görünen kafamla bu topu sektirebileyim
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
	highScore: 0,
	level: 0
});
var facekit = LK.import("@upit/facekit.v1");
/**** 
* Classes
****/ 
var Ball = Container.expand(function () {
	var self = Container.call(this);
	// Ball visual
	var ballGraphics = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Physics properties
	self.velocityX = 0;
	self.velocityY = 0;
	self.gravity = 0.4;
	self.bounceForce = -5;
	self.bounceDecay = 0.95;
	self.isActive = true;
	// Game state properties
	self.bounceCount = 0;
	self.lastBounceY = 0;
	// Apply force to ball
	self.applyForce = function (forceX, forceY) {
		self.velocityX += forceX;
		self.velocityY += forceY;
	};
	// Bounce the ball
	self.bounce = function (multiplier) {
		multiplier = multiplier || 1;
		self.velocityY = self.bounceForce * multiplier;
		self.bounceCount++;
		self.lastBounceY = self.y;
		// Play bounce sound
		LK.getSound('bounce').play();
		// Scale effect on bounce
		tween(ballGraphics, {
			scaleX: 1.3,
			scaleY: 0.7
		}, {
			duration: 150,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(ballGraphics, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 150,
					easing: tween.elastic
				});
			}
		});
		return self.bounceCount;
	};
	// Reset ball
	self.reset = function (x, y) {
		self.x = x || 2048 / 2;
		self.y = y || 300;
		self.velocityX = Math.random() * 8 - 4;
		self.velocityY = 0;
		self.bounceCount = 0;
		self.isActive = true;
		ballGraphics.alpha = 1;
	};
	// Update is automatically called by LK
	self.update = function () {
		if (!self.isActive) {
			return;
		}
		// Apply gravity
		self.velocityY += self.gravity;
		// Apply velocity
		self.x += self.velocityX;
		self.y += self.velocityY;
		// Prevent ball from going off-screen at the top
		if (self.y < ballGraphics.height / 2) {
			self.y = ballGraphics.height / 2;
			self.velocityY *= -0.9;
		}
		// Bounce off walls
		if (self.x < ballGraphics.width / 2) {
			self.x = ballGraphics.width / 2;
			self.velocityX *= -0.9;
		} else if (self.x > 2048 - ballGraphics.width / 2) {
			self.x = 2048 - ballGraphics.width / 2;
			self.velocityX *= -0.9;
		}
		// Add some drag
		self.velocityX *= 0.99;
	};
	// Deactivate ball with fade effect
	self.deactivate = function () {
		self.isActive = false;
		tween(ballGraphics, {
			alpha: 0
		}, {
			duration: 500,
			easing: tween.easeOut
		});
	};
	return self;
});
var Bonus = Container.expand(function () {
	var self = Container.call(this);
	// Bonus visual
	var bonusGraphics = self.attachAsset('bonus', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Randomly position the bonus on the screen
	self.reset = function () {
		self.x = Math.random() * (2048 - bonusGraphics.width) + bonusGraphics.width / 2;
		self.y = Math.random() * (1100 - bonusGraphics.height) + bonusGraphics.height;
	};
	// Update is automatically called by LK
	self.update = function () {
		// Check for collision with the ball
		if (ball.intersects(self)) {
			// Double the score
			addScore(50);
			// Reset bonus position
			self.reset();
		}
	};
	return self;
});
var ScoreDisplay = Container.expand(function () {
	var self = Container.call(this);
	// Score text
	self.scoreText = new Text2('SCORE: 0', {
		size: 60,
		fill: '#FFFFFF'
	});
	self.scoreText.anchor.set(0.5, 0);
	//self.scoreText.y = 300;
	self.addChild(self.scoreText);
	// High score text
	self.highScoreText = new Text2('BEST: 0', {
		size: 50,
		fill: '#CCCCCC'
	});
	self.highScoreText.anchor.set(0.5, 0);
	//self.highScoreText.y = 90;
	self.highScoreText.x = 500;
	self.addChild(self.highScoreText);
	// Level display
	self.levelText = new Text2('LEVEL: 1', {
		size: 50,
		fill: '#FFCC00'
	});
	self.levelText.anchor.set(0.5, 0);
	//self.levelText.y = 150;
	self.levelText.x = -450;
	self.addChild(self.levelText);
	// Update score display
	self.updateScore = function (score) {
		self.scoreText.setText('SCORE: ' + score);
		// Check if new high score
		if (score > storage.highScore && score > 500) {
			// Play high score sound only once per game session
			if (!self.highScoreSoundPlayed) {
				LK.getSound('score').play();
				self.highScoreSoundPlayed = true;
			}
			storage.highScore = score;
			self.highScoreText.setText('BEST: ' + score);
			// Highlight effect for new high score
			tween(self.highScoreText, {
				tint: 0xFFFF00
			}, {
				duration: 500,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(self.highScoreText, {
						tint: 0xCCCCCC
					}, {
						duration: 500,
						easing: tween.easeIn
					});
				}
			});
		}
	};
	// Update level display
	self.updateLevel = function (level) {
		self.levelText.setText('LEVEL: ' + level);
		storage.level = level;
		// Highlight effect for level change
		tween(self.levelText, {
			tint: 0xFFFF00,
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 300,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(self.levelText, {
					tint: 0xFFCC00,
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 300,
					easing: tween.easeIn
				});
			}
		});
	};
	// Initialize
	self.init = function () {
		self.highScoreText.setText('BEST: ' + storage.highScore);
		self.highScoreSoundPlayed = false; // Initialize flag to track score sound
		self.levelText.setText('LEVEL: ' + storage.level);
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000
});
/**** 
* Game Code
****/ 
//storage.highScore = 0;
// Game variables
storage.level = 1;
var score = 0;
var level = storage.level || 1;
var isGameOver = false;
var consecutiveBounces = 0;
var facePosition = {
	x: 2048 / 2,
	y: 2732 / 2
};
var lastBounceTime = 0;
var bounceCooldown = 500; // Milliseconds between bounces
var debugMode = false;
// Create game elements
var ball = new Ball();
// Create ball object
var ball = new Ball();
// Create bonus object
var bonus = new Bonus();
// Create score display
var scoreDisplay = new ScoreDisplay();
scoreDisplay.init();
LK.gui.top.addChild(scoreDisplay);
// Create floor (just for visual reference)
var floor = LK.getAsset('floor', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: 2650,
	alpha: 1
});
game.addChild(floor);
// Create score zone (invisible)
var scoreZone = LK.getAsset('scoreZone', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: 300,
	alpha: 0
});
game.addChild(scoreZone);
// Add start button
var startButton = new Text2('START GAME', {
	size: 150,
	fill: '#00FF00'
});
startButton.anchor.set(0.5, 0.5);
startButton.x = 2048 / 2;
startButton.y = 2732 / 2;
game.addChild(startButton);
// Start game on button press
startButton.down = function () {
	startButton.destroy(); // Remove start button
	game.addChild(ball); // Add ball to the game
	ball.reset(); // Reset ball position
	game.addChild(bonus); // Add bonus to the game
	bonus.reset(); // Reset bonus position
	instructionText.alpha = 1; // Show instructions
	// Fade out instructions after 3 seconds
	LK.setTimeout(function () {
		tween(instructionText, {
			alpha: 0
		}, {
			duration: 1000,
			easing: tween.easeOut
		});
	}, 3000);
};
// Add instruction text
var instructionText = new Text2('Position your head to bounce the ball!', {
	size: 110,
	fill: '#FFFFFF'
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 2048 / 2;
instructionText.y = 2732 / 2;
game.addChild(instructionText);
instructionText.alpha = 0; // Initially hide instructions
// Start background music
LK.playMusic('gameMusic', {
	fade: {
		start: 0,
		end: 0.4,
		duration: 1000
	}
});
// Update face position smoothly
function updateFacePosition() {
	var targetX = facekit.noseTip ? facekit.noseTip.x : 2048 / 2;
	var targetY = facekit.noseTip ? facekit.noseTip.y - 500 : 2732 / 2;
	// Smooth the movement
	facePosition.x += (targetX - facePosition.x) * 0.3;
	facePosition.y += (targetY - facePosition.y) * 0.3;
	// Draw face position debug if enabled
	if (debugMode && facekit.noseTip) {
		// Debug code would go here
	}
}
// Check if ball bounces on face
function checkFaceBounce() {
	if (!ball.isActive) {
		return;
	}
	// Calculate distance between ball and face
	var dx = ball.x - facePosition.x;
	var dy = ball.y - facePosition.y;
	var distance = Math.sqrt(dx * dx + dy * dy);
	// Face radius (approximation)
	var faceRadius = 150;
	var ballRadius = ball.children[0].width / 2;
	// Check collision with face
	if (distance < faceRadius + ballRadius && ball.velocityY > 0 && Date.now() - lastBounceTime > bounceCooldown) {
		// Calculate bounce direction based on where it hit the face
		var headSpeed = Math.abs(facekit.noseTip.y - facePosition.y);
		var bounceMultiplier = 1 + level * 0.05 + headSpeed * 0.01;
		var bounceCount = ball.bounce(bounceMultiplier);
		consecutiveBounces = bounceCount;
		// Add horizontal velocity based on where the ball hit the face
		ball.velocityX = dx * 0.1;
		// Record bounce time
		lastBounceTime = Date.now();
		// Add score
		addScore(10 * bounceMultiplier);
		// Check for level up
		checkLevelUp();
	}
}
// Check for ball hitting bottom
function checkMiss() {
	if (!ball.isActive) {
		return;
	}
	if (ball.y > 2650) {
		// Play miss sound
		LK.getSound('miss').play();
		// Flash screen
		LK.effects.flashScreen(0xFF0000, 300);
		// Game over
		endGame();
	}
}
// Add score points
function addScore(points) {
	score += Math.floor(points);
	scoreDisplay.updateScore(score);
	// Play score sound
	//LK.getSound('score').play();
	// Show floating score text
	var floatingScore = new Text2("+" + Math.floor(points), {
		size: 120,
		// Increased size from 90 to 120 
		fill: 0xFFFF00
	});
	floatingScore.anchor.set(0.5, 0.5);
	floatingScore.x = ball.x;
	floatingScore.y = ball.y - 100;
	game.addChild(floatingScore);
	// Animate floating score
	tween(floatingScore, {
		y: floatingScore.y - 100,
		alpha: 0
	}, {
		duration: 800,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			floatingScore.destroy();
		}
	});
}
// Check for level up
function checkLevelUp() {
	// Level up every 500 points
	var newLevel = Math.floor(score / 500) + 1;
	if (newLevel > level) {
		level = newLevel;
		scoreDisplay.updateLevel(level);
		// Play level up sound
		LK.getSound('levelup').play();
		// Increase difficulty
		ball.gravity = 0.4 + level * 0.02;
		ball.bounceDecay += 0.08;
		ball.velocityX *= 1.02; // Increase horizontal speed slightly
		ball.bounceForce *= 1.02; // Increase bounce force slightly
		// Reduce ball size by 10px on each level up, but not below 80px
		if (ball.children[0].width > 80 && ball.children[0].height > 80) {
			ball.children[0].width -= 10;
			ball.children[0].height -= 10;
		}
		// Show level up text
		var levelUpText = new Text2("LEVEL UP!", {
			size: 150,
			fill: 0xFFFF00
		});
		levelUpText.anchor.set(0.5, 0.5);
		levelUpText.x = 2048 / 2;
		levelUpText.y = 2732 / 2;
		game.addChild(levelUpText);
		// Animate level up text
		tween(levelUpText, {
			scaleX: 1.5,
			scaleY: 1.5
		}, {
			duration: 500,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(levelUpText, {
					alpha: 0
				}, {
					duration: 500,
					easing: tween.easeIn,
					onFinish: function onFinish() {
						levelUpText.destroy();
					}
				});
			}
		});
	}
}
// End the game
function endGame() {
	if (isGameOver) {
		return;
	}
	isGameOver = true;
	// Deactivate ball
	ball.deactivate();
	// Show game over screen
	LK.showGameOver();
}
// Reset the game
function resetGame() {
	score = 0;
	consecutiveBounces = 0;
	isGameOver = false;
	// Reset ball
	ball.reset();
	scoreDisplay.highScoreSoundPlayed = false; // Reset flag for score sound
	scoreDisplay.updateScore(0);
}
// Game update function (called every frame)
game.update = function () {
	if (isGameOver) {
		return;
	}
	// Update face position
	updateFacePosition();
	// Check for face bounce
	checkFaceBounce();
	// Check for miss
	checkMiss();
};
// Handle tap to restart
game.down = function (x, y, obj) {
	// Just for debugging if needed
};
// Handle move events
game.move = function (x, y, obj) {
	// Just for debugging if needed
};
// Update score when game starts (in case of high score from previous games)
scoreDisplay.updateScore(0); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
	highScore: 0,
	level: 0
});
var facekit = LK.import("@upit/facekit.v1");
/**** 
* Classes
****/ 
var Ball = Container.expand(function () {
	var self = Container.call(this);
	// Ball visual
	var ballGraphics = self.attachAsset('ball', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Physics properties
	self.velocityX = 0;
	self.velocityY = 0;
	self.gravity = 0.4;
	self.bounceForce = -5;
	self.bounceDecay = 0.95;
	self.isActive = true;
	// Game state properties
	self.bounceCount = 0;
	self.lastBounceY = 0;
	// Apply force to ball
	self.applyForce = function (forceX, forceY) {
		self.velocityX += forceX;
		self.velocityY += forceY;
	};
	// Bounce the ball
	self.bounce = function (multiplier) {
		multiplier = multiplier || 1;
		self.velocityY = self.bounceForce * multiplier;
		self.bounceCount++;
		self.lastBounceY = self.y;
		// Play bounce sound
		LK.getSound('bounce').play();
		// Scale effect on bounce
		tween(ballGraphics, {
			scaleX: 1.3,
			scaleY: 0.7
		}, {
			duration: 150,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(ballGraphics, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 150,
					easing: tween.elastic
				});
			}
		});
		return self.bounceCount;
	};
	// Reset ball
	self.reset = function (x, y) {
		self.x = x || 2048 / 2;
		self.y = y || 300;
		self.velocityX = Math.random() * 8 - 4;
		self.velocityY = 0;
		self.bounceCount = 0;
		self.isActive = true;
		ballGraphics.alpha = 1;
	};
	// Update is automatically called by LK
	self.update = function () {
		if (!self.isActive) {
			return;
		}
		// Apply gravity
		self.velocityY += self.gravity;
		// Apply velocity
		self.x += self.velocityX;
		self.y += self.velocityY;
		// Prevent ball from going off-screen at the top
		if (self.y < ballGraphics.height / 2) {
			self.y = ballGraphics.height / 2;
			self.velocityY *= -0.9;
		}
		// Bounce off walls
		if (self.x < ballGraphics.width / 2) {
			self.x = ballGraphics.width / 2;
			self.velocityX *= -0.9;
		} else if (self.x > 2048 - ballGraphics.width / 2) {
			self.x = 2048 - ballGraphics.width / 2;
			self.velocityX *= -0.9;
		}
		// Add some drag
		self.velocityX *= 0.99;
	};
	// Deactivate ball with fade effect
	self.deactivate = function () {
		self.isActive = false;
		tween(ballGraphics, {
			alpha: 0
		}, {
			duration: 500,
			easing: tween.easeOut
		});
	};
	return self;
});
var Bonus = Container.expand(function () {
	var self = Container.call(this);
	// Bonus visual
	var bonusGraphics = self.attachAsset('bonus', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Randomly position the bonus on the screen
	self.reset = function () {
		self.x = Math.random() * (2048 - bonusGraphics.width) + bonusGraphics.width / 2;
		self.y = Math.random() * (1100 - bonusGraphics.height) + bonusGraphics.height;
	};
	// Update is automatically called by LK
	self.update = function () {
		// Check for collision with the ball
		if (ball.intersects(self)) {
			// Double the score
			addScore(50);
			// Reset bonus position
			self.reset();
		}
	};
	return self;
});
var ScoreDisplay = Container.expand(function () {
	var self = Container.call(this);
	// Score text
	self.scoreText = new Text2('SCORE: 0', {
		size: 60,
		fill: '#FFFFFF'
	});
	self.scoreText.anchor.set(0.5, 0);
	//self.scoreText.y = 300;
	self.addChild(self.scoreText);
	// High score text
	self.highScoreText = new Text2('BEST: 0', {
		size: 50,
		fill: '#CCCCCC'
	});
	self.highScoreText.anchor.set(0.5, 0);
	//self.highScoreText.y = 90;
	self.highScoreText.x = 500;
	self.addChild(self.highScoreText);
	// Level display
	self.levelText = new Text2('LEVEL: 1', {
		size: 50,
		fill: '#FFCC00'
	});
	self.levelText.anchor.set(0.5, 0);
	//self.levelText.y = 150;
	self.levelText.x = -450;
	self.addChild(self.levelText);
	// Update score display
	self.updateScore = function (score) {
		self.scoreText.setText('SCORE: ' + score);
		// Check if new high score
		if (score > storage.highScore && score > 500) {
			// Play high score sound only once per game session
			if (!self.highScoreSoundPlayed) {
				LK.getSound('score').play();
				self.highScoreSoundPlayed = true;
			}
			storage.highScore = score;
			self.highScoreText.setText('BEST: ' + score);
			// Highlight effect for new high score
			tween(self.highScoreText, {
				tint: 0xFFFF00
			}, {
				duration: 500,
				easing: tween.easeOut,
				onFinish: function onFinish() {
					tween(self.highScoreText, {
						tint: 0xCCCCCC
					}, {
						duration: 500,
						easing: tween.easeIn
					});
				}
			});
		}
	};
	// Update level display
	self.updateLevel = function (level) {
		self.levelText.setText('LEVEL: ' + level);
		storage.level = level;
		// Highlight effect for level change
		tween(self.levelText, {
			tint: 0xFFFF00,
			scaleX: 1.2,
			scaleY: 1.2
		}, {
			duration: 300,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(self.levelText, {
					tint: 0xFFCC00,
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 300,
					easing: tween.easeIn
				});
			}
		});
	};
	// Initialize
	self.init = function () {
		self.highScoreText.setText('BEST: ' + storage.highScore);
		self.highScoreSoundPlayed = false; // Initialize flag to track score sound
		self.levelText.setText('LEVEL: ' + storage.level);
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000
});
/**** 
* Game Code
****/ 
//storage.highScore = 0;
// Game variables
storage.level = 1;
var score = 0;
var level = storage.level || 1;
var isGameOver = false;
var consecutiveBounces = 0;
var facePosition = {
	x: 2048 / 2,
	y: 2732 / 2
};
var lastBounceTime = 0;
var bounceCooldown = 500; // Milliseconds between bounces
var debugMode = false;
// Create game elements
var ball = new Ball();
// Create ball object
var ball = new Ball();
// Create bonus object
var bonus = new Bonus();
// Create score display
var scoreDisplay = new ScoreDisplay();
scoreDisplay.init();
LK.gui.top.addChild(scoreDisplay);
// Create floor (just for visual reference)
var floor = LK.getAsset('floor', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: 2650,
	alpha: 1
});
game.addChild(floor);
// Create score zone (invisible)
var scoreZone = LK.getAsset('scoreZone', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 2048 / 2,
	y: 300,
	alpha: 0
});
game.addChild(scoreZone);
// Add start button
var startButton = new Text2('START GAME', {
	size: 150,
	fill: '#00FF00'
});
startButton.anchor.set(0.5, 0.5);
startButton.x = 2048 / 2;
startButton.y = 2732 / 2;
game.addChild(startButton);
// Start game on button press
startButton.down = function () {
	startButton.destroy(); // Remove start button
	game.addChild(ball); // Add ball to the game
	ball.reset(); // Reset ball position
	game.addChild(bonus); // Add bonus to the game
	bonus.reset(); // Reset bonus position
	instructionText.alpha = 1; // Show instructions
	// Fade out instructions after 3 seconds
	LK.setTimeout(function () {
		tween(instructionText, {
			alpha: 0
		}, {
			duration: 1000,
			easing: tween.easeOut
		});
	}, 3000);
};
// Add instruction text
var instructionText = new Text2('Position your head to bounce the ball!', {
	size: 110,
	fill: '#FFFFFF'
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 2048 / 2;
instructionText.y = 2732 / 2;
game.addChild(instructionText);
instructionText.alpha = 0; // Initially hide instructions
// Start background music
LK.playMusic('gameMusic', {
	fade: {
		start: 0,
		end: 0.4,
		duration: 1000
	}
});
// Update face position smoothly
function updateFacePosition() {
	var targetX = facekit.noseTip ? facekit.noseTip.x : 2048 / 2;
	var targetY = facekit.noseTip ? facekit.noseTip.y - 500 : 2732 / 2;
	// Smooth the movement
	facePosition.x += (targetX - facePosition.x) * 0.3;
	facePosition.y += (targetY - facePosition.y) * 0.3;
	// Draw face position debug if enabled
	if (debugMode && facekit.noseTip) {
		// Debug code would go here
	}
}
// Check if ball bounces on face
function checkFaceBounce() {
	if (!ball.isActive) {
		return;
	}
	// Calculate distance between ball and face
	var dx = ball.x - facePosition.x;
	var dy = ball.y - facePosition.y;
	var distance = Math.sqrt(dx * dx + dy * dy);
	// Face radius (approximation)
	var faceRadius = 150;
	var ballRadius = ball.children[0].width / 2;
	// Check collision with face
	if (distance < faceRadius + ballRadius && ball.velocityY > 0 && Date.now() - lastBounceTime > bounceCooldown) {
		// Calculate bounce direction based on where it hit the face
		var headSpeed = Math.abs(facekit.noseTip.y - facePosition.y);
		var bounceMultiplier = 1 + level * 0.05 + headSpeed * 0.01;
		var bounceCount = ball.bounce(bounceMultiplier);
		consecutiveBounces = bounceCount;
		// Add horizontal velocity based on where the ball hit the face
		ball.velocityX = dx * 0.1;
		// Record bounce time
		lastBounceTime = Date.now();
		// Add score
		addScore(10 * bounceMultiplier);
		// Check for level up
		checkLevelUp();
	}
}
// Check for ball hitting bottom
function checkMiss() {
	if (!ball.isActive) {
		return;
	}
	if (ball.y > 2650) {
		// Play miss sound
		LK.getSound('miss').play();
		// Flash screen
		LK.effects.flashScreen(0xFF0000, 300);
		// Game over
		endGame();
	}
}
// Add score points
function addScore(points) {
	score += Math.floor(points);
	scoreDisplay.updateScore(score);
	// Play score sound
	//LK.getSound('score').play();
	// Show floating score text
	var floatingScore = new Text2("+" + Math.floor(points), {
		size: 120,
		// Increased size from 90 to 120 
		fill: 0xFFFF00
	});
	floatingScore.anchor.set(0.5, 0.5);
	floatingScore.x = ball.x;
	floatingScore.y = ball.y - 100;
	game.addChild(floatingScore);
	// Animate floating score
	tween(floatingScore, {
		y: floatingScore.y - 100,
		alpha: 0
	}, {
		duration: 800,
		easing: tween.easeOut,
		onFinish: function onFinish() {
			floatingScore.destroy();
		}
	});
}
// Check for level up
function checkLevelUp() {
	// Level up every 500 points
	var newLevel = Math.floor(score / 500) + 1;
	if (newLevel > level) {
		level = newLevel;
		scoreDisplay.updateLevel(level);
		// Play level up sound
		LK.getSound('levelup').play();
		// Increase difficulty
		ball.gravity = 0.4 + level * 0.02;
		ball.bounceDecay += 0.08;
		ball.velocityX *= 1.02; // Increase horizontal speed slightly
		ball.bounceForce *= 1.02; // Increase bounce force slightly
		// Reduce ball size by 10px on each level up, but not below 80px
		if (ball.children[0].width > 80 && ball.children[0].height > 80) {
			ball.children[0].width -= 10;
			ball.children[0].height -= 10;
		}
		// Show level up text
		var levelUpText = new Text2("LEVEL UP!", {
			size: 150,
			fill: 0xFFFF00
		});
		levelUpText.anchor.set(0.5, 0.5);
		levelUpText.x = 2048 / 2;
		levelUpText.y = 2732 / 2;
		game.addChild(levelUpText);
		// Animate level up text
		tween(levelUpText, {
			scaleX: 1.5,
			scaleY: 1.5
		}, {
			duration: 500,
			easing: tween.easeOut,
			onFinish: function onFinish() {
				tween(levelUpText, {
					alpha: 0
				}, {
					duration: 500,
					easing: tween.easeIn,
					onFinish: function onFinish() {
						levelUpText.destroy();
					}
				});
			}
		});
	}
}
// End the game
function endGame() {
	if (isGameOver) {
		return;
	}
	isGameOver = true;
	// Deactivate ball
	ball.deactivate();
	// Show game over screen
	LK.showGameOver();
}
// Reset the game
function resetGame() {
	score = 0;
	consecutiveBounces = 0;
	isGameOver = false;
	// Reset ball
	ball.reset();
	scoreDisplay.highScoreSoundPlayed = false; // Reset flag for score sound
	scoreDisplay.updateScore(0);
}
// Game update function (called every frame)
game.update = function () {
	if (isGameOver) {
		return;
	}
	// Update face position
	updateFacePosition();
	// Check for face bounce
	checkFaceBounce();
	// Check for miss
	checkMiss();
};
// Handle tap to restart
game.down = function (x, y, obj) {
	// Just for debugging if needed
};
// Handle move events
game.move = function (x, y, obj) {
	// Just for debugging if needed
};
// Update score when game starts (in case of high score from previous games)
scoreDisplay.updateScore(0);