/**** 
* Classes
****/ 
var BeachToys = Container.expand(function (index) {
	var self = Container.call(this);
	self.shadow = self.attachAsset('beachToysShadow', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 150,
		y: -150,
		alpha: 0.3,
		scaleX: -1,
		scaleY: 1,
		tint: 0x000000,
		rotation: 2.3,
		visible: !index
	});
	var alt = index ? "2" : "";
	var beachToysGraphics = self.attachAsset('beachToys' + alt, {
		anchorX: 0.5,
		anchorY: 1.0
	});
});
var Boat = Container.expand(function () {
	var self = Container.call(this);
	var boatGraphics = self.attachAsset('boat', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 2; // Speed of the boat movement
	self.direction = 1; // Direction of the boat movement, 1 for right, -1 for left
	self.update = function () {
		if (!self.startTime) {
			self.startTime = LK.ticks;
		}
		var elapsed = (LK.ticks - self.startTime) / 60; // Elapsed time in seconds
		var targetX = self.x + self.speed * self.direction;
		self.x = self.x + (targetX - self.x) * 0.1; // Linear interpolation for smoother movement
		if (self.x > 2048 + boatGraphics.width / 2) {
			self.x = -boatGraphics.width / 2; // Reset position to the left of the screen
		} else if (self.x < -boatGraphics.width / 2) {
			self.x = 2048 + boatGraphics.width / 2; // Reset position to the right of the screen
		}
		if (self.y > 2748 + self.height / 2) {
			self.visible = false; // Make the boat not visible when y > 2748
		}
	};
	/**
	* Reverses the direction of the boat.
	*/ 
	self.reverse = function () {
		self.direction *= -1;
		self.scale.x *= -1;
		self.visible = true;
		self.x = 2048 + self.width / 2; // Reset position to the right of the screen
	};
});
var Bucket = Container.expand(function () {
	var self = Container.call(this);
	var bucketGraphics = self.attachAsset('bucket', {
		anchorX: 0.5,
		anchorY: 0.0
	});
	self.scoreTxt = new Text2('00', {
		size: 200,
		fill: "#03a2c3",
		weight: 1000
	});
	self.scoreTxt.anchor.set(0.5, 0);
	self.scoreTxt.x = 0;
	self.scoreTxt.y = 330;
	self.addChild(self.scoreTxt);
});
var Cloud = Container.expand(function (index) {
	var self = Container.call(this);
	var cloudGraphics = self.attachAsset('cloud' + index, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 0.4 + (2 - index) * 0.2 + Math.random() * 0.2; // Speed of the cloud movement
	self.update = function () {
		if (!self.visible) {
			return;
		}
		self.x += self.speed;
		if (self.x > 2048 + cloudGraphics.width / 2) {
			self.x = -cloudGraphics.width / 2 - Math.random() * 2048; // Reset position to the left of the screen
			self.y = Math.random() * 512;
		}
	};
});
var Confetti = Container.expand(function () {
	var self = Container.call(this);
	var confettiColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];
	var confettiPieces = [];
	var nbConfettis = 3 + level * 7;
	nbConfettis = Math.min(500, nbConfettis);
	for (var i = 0; i < nbConfettis; i++) {
		var confettiPiece = self.attachAsset('confetti', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 15,
			height: 50,
			tint: confettiColors[Math.floor(Math.random() * confettiColors.length)]
		});
		confettiPiece.x = Math.random() * 2048;
		confettiPiece.y = Math.random() * 2732;
		confettiPiece.rotation = Math.random() * Math.PI * 2;
		confettiPiece.speedY = Math.random() * 5 + 4;
		confettiPiece.speedX = (Math.random() - 0.5) * 2;
		confettiPieces.push(confettiPiece);
	}
	self.update = function () {
		for (var i = 0; i < confettiPieces.length; i++) {
			var piece = confettiPieces[i];
			piece.y += piece.speedY;
			piece.x += piece.speedX;
			if (piece.y > 2732) {
				piece.y = -piece.height;
				piece.x = Math.random() * 2048;
			}
		}
	};
});
var FlyingObject = Container.expand(function (index) {
	var self = Container.call(this);
	var flyingObjectGraphics = self.attachAsset('flyingObject' + index, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.directionY = -1 * (Math.random() > 0.5);
	self.passed = true;
	self.speed = 3; // Speed of the flying object movement
	self.update = function () {
		if (!self.visible || self.passed) {
			return;
		}
		self.x += self.speed;
		self.y += self.speed * 0.1 * self.directionY;
		if (self.x > 2048 + flyingObjectGraphics.width / 2) {
			self.x = -flyingObjectGraphics.width / 2 - Math.random() * 1024; // Reset position to the left of the screen
			self.y = Math.random() * 512; // Reset position relative to the camera
			self.passed = true;
			self.visible = false;
		}
	};
});
var SandBlock = Container.expand(function () {
	var self = Container.call(this);
	var sandBlockGraphics = self.attachAsset('sandBlock', {
		anchorX: 0.5,
		anchorY: 0
	});
	self.height = sandBlockAssetHeight * sandBlockHeightBaseRatio;
	self.velocity = 0; // Initial velocity for natural falling speed increase
	self.update = function () {
		if (self.y > 2748 + self.height / 2) {
			self.visible = false;
		}
	};
});
/***********************************************************************************/ 
/********************************** SANDCASTLE CLASS ************************************/
/***********************************************************************************/ 
var Sandcastle = Container.expand(function () {
	var self = Container.call(this);
	self.shadow = self.attachAsset('shadow', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.5,
		visible: false
	});
	var sandcastleGraphics = self.attachAsset('sandcastle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.shadow.width = sandcastleGraphics.width;
	self.shadow.height = sandcastleGraphics.height * 0.5;
	self.shadow.y = sandcastleGraphics.height * 0.3;
	self.shadow.visible = false;
	self.update = function () {
		// Sandcastle specific update logic
	};
});
/**** 
* Initialize Game
****/ 
// Utility function to draw a polygon using drawLine
var game = new LK.Game({
	backgroundColor: 0x000050 // Initialize game with a black background
});
/**** 
* Game Code
****/ 
// Enumeration for game states
/****************************************************************************************** */ 
/************************************** GLOBAL VARIABLES ********************************** */
/****************************************************************************************** */ 
function easeInOutQuad(t) {
	return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
}
var isBucketMovingUp = false; // Flag to track if the bucket is moving up
var isBucketMovingDown = false; // Flag to track if the bucket is moving down
var GAME_STATE = {
	INIT: 'INIT',
	MENU: 'MENU',
	NEW_ROUND: 'NEW_ROUND',
	PLAYING: 'PLAYING',
	SCORE: 'SCORE'
};
var gameState = GAME_STATE.INIT;
var score = 0;
var level = 0;
var scoreTxt;
var isDebug = false;
var debugText;
var debugMarker;
var backgroundImage;
var bucket;
var banner;
var picketLeft;
var picketRight;
var sandBlocks = [];
var lives = 3;
var livesIcons = [];
var cameraMoved = false; // Flag to track if the camera has moved for the current sandblock fall
var sandBlockDropped = false; // Flag to track if a sand block has been dropped
var isCameraMoving = false; // Flag to track if the camera is currently moving
var bucketReady = false; // Flag to track if the bucket has reached y=0
var sandcastle;
var sandcastleBaseY = 2212;
var sandcastleHeight = 1640;
var previousBlockX = 1024;
var sandBlockWidth = 390;
var sandBlockHalfWidth = 195;
var sandBlockAssetHeight = 1618; // height of the asset
var sandBlockHeightBaseRatio = 0.6; // Extend effect start ratio
var sandBlockHeightRatio = sandBlockHeightBaseRatio; // Extend effect current ratio
var sandBlockSize = 460; // height of the visible sand block
var centralPointY = 1380 - sandBlockSize;
var bgHeight = 1152;
var bgHalfHeight = 576;
var gravity = 2; // Gravity effect for sand block falling
var bucketDirection = 1; // 1 for right, -1 for left
var isBucketMovingHorizontally = false; // Flag to track if the bucket is moving horizontally
var bucketMoveStep = 10; // Initial bucket move step size
var currentSandBlock = null; // Global variable to keep track of the current sand block
var startButton = null; // Global variable for the start button
var isPlaying = false; // Global variable to track if the game is currently in the playing state
var sandBlockMoveStep = 2; // Step size for sand block horizontal movement
var bgMusic;
var globalDelta = 0;
var beachToys = null; // Global variable for beach toys
var cloud1 = null; // Global variable for cloud1
var cloud2 = null; // Global variable for cloud2
var moveStep = 0; // Global variable for move step
var flyingObject1 = null; // Global variable for flyingObject1
var flyingObject2 = null; // Global variable for flyingObject2
var flyingObject3 = null; // Global variable for flyingObject2
var flyingObject4 = null; // Global variable for flyingObject2
var fadeOutStartButtonStartTime = 0;
var isCleaningNewRound = false; // Flag to prevent multiple calls to cleanNewRoundState
var lastUpdateTime = 0;
/****************************************************************************************** */ 
/*********************************** UTILITY FUNCTIONS ************************************ */
/****************************************************************************************** */ 
function moveCamera() {
	var targetY = backgroundImage.y + sandBlockSize;
	moveStep = sandBlockSize / 60; // Move over 1 second (60 frames)
	function progressiveMove() {
		if (backgroundImage.y < targetY) {
			log("Camera is moving. Current y position: " + backgroundImage.y);
			backgroundImage.y += moveStep;
			background2.y += moveStep;
			background3.y += moveStep;
			sandcastle.y += moveStep;
			background4.y += moveStep;
			background5.y += moveStep;
			banner.y += moveStep * 1.05;
			picketLeft.y += moveStep * 1.05;
			picketRight.y += moveStep * 1.05;
			for (var j = 0; j < sandBlocks.length; j++) {
				sandBlocks[j].y += moveStep;
			}
			if (cloud1) {
				cloud1.y += moveStep * 0.5;
			}
			if (cloud2) {
				cloud2.y += moveStep * 0.5;
			}
			if (flyingObject1 && flyingObject1.visible) {
				flyingObject1.y += moveStep * 0.75;
			}
			if (flyingObject2 && flyingObject2.visible) {
				flyingObject2.y += moveStep * 0.75;
			}
			if (flyingObject3 && flyingObject3.visible) {
				flyingObject3.y += moveStep * 0.75;
			}
			if (flyingObject4 && flyingObject4.visible) {
				flyingObject4.y += moveStep * 0.75;
			}
			if (boat) {
				boat.y += moveStep;
			}
			if (backgroundImage.y < targetY) {
				LK.setTimeout(progressiveMove, 1000 / 60); // Call progressiveMove every 1/60th of a second
			} else {
				isCameraMoving = false; // Set the flag to false when the camera stops moving
				var checkBucketUpCompletion = function checkBucketUpCompletion() {
					if (bucket.y <= -bucket.height && !isBucketMovingUp) {
						isBucketMovingHorizontally = true; // Resume horizontal movement of the bucket
						moveBucketDown(); // Progressively move the bucket down when the camera reaches the target
						game.addChild(bucket); // Ensure bucket is above sand blocks
					} else {
						LK.setTimeout(checkBucketUpCompletion, 1000 / 60); // Check again in the next frame
					}
				};
				checkBucketUpCompletion();
			}
			if (background2.y > 2732 + bgHalfHeight) {
				background2.y = background5.y - background5.height;
			}
			if (background3.y > 2732 + bgHalfHeight) {
				background3.y = background2.y - background2.height;
			}
			if (background4.y > 2732 + bgHalfHeight) {
				background4.y = background3.y - background3.height;
			}
			if (background5.y > 2732 + bgHalfHeight) {
				background5.y = background4.y - background4.height;
			}
		}
	}
	progressiveMove();
}
function log() {
	if (isDebug) {
		var _console;
		(_console = console).log.apply(_console, arguments);
	}
}
/****************************************************************************************** */ 
/************************************** INPUT HANDLERS ************************************ */
/****************************************************************************************** */ 
game.on('down', function (x, y, obj) {
	handleGameState(x, y, obj);
});
function handleGameState(x, y, obj) {
	switch (gameState) {
		case GAME_STATE.MENU:
			gameMenuDown(x, y, obj);
			break;
		case GAME_STATE.NEW_ROUND:
			gameNewRoundDown(x, y, obj);
			break;
		case GAME_STATE.PLAYING:
			gamePlayingDown(x, y, obj);
			break;
		case GAME_STATE.SCORE:
			gameScoreDown(x, y, obj);
			break;
	}
}
function gameMenuDown(x, y, obj) {
	log("gameMenuDown...");
	if (gameState != GAME_STATE.MENU) {
		return;
	}
	cleanMenuState();
	initNewRoundState();
}
function gameNewRoundDown(x, y, obj) {
	log("gameNewRoundDown...");
	if (gameState != GAME_STATE.NEW_ROUND || isCleaningNewRound) {
		return;
	}
	log("gameNewRoundDown Ok clean...");
	cleanNewRoundState();
}
function gamePlayingDown(x, y, obj) {
	log("gamePlayingDown...", "state=" + (gameState == GAME_STATE.PLAYING), "playing=" + isPlaying, "dropped=" + !sandBlockDropped, "camera=" + !isCameraMoving, "bucket=" + bucketReady);
	if (gameState != GAME_STATE.PLAYING || !isPlaying || sandBlockDropped || isCameraMoving || !bucketReady) {
		return; // Prevent taps during camera movement
	}
	sandBlockDropped = true;
	log("gamePlayingDown OK");
	// Pause horizontal movement of the bucket
	isBucketMovingHorizontally = false;
	lastUpdateTime = 0;
	// Move the bucket vertically to hide over the screen top with shake
	moveBucketUp();
	LK.setTimeout(createNewSandBlock, 512); // Delay creating new sand block until after shake
}
function gameScoreDown(x, y, obj) {
	log("gameScoreDown...");
	cleanScoreState();
}
/****************************************************************************************** */ 
/************************************* GAME FUNCTIONS ************************************* */
/****************************************************************************************** */ 
function moveBucketUp() {
	if (isBucketMovingDown) {
		return;
	} // Prevent concurrent moves
	isBucketMovingUp = true; // Set flag to true when bucket starts moving up
	var bucketMoveStep = 15; // Adjust the step size as needed
	var shakeStep = 40; // Step size for shake movement
	var shakeCount = 0; // Counter for shake movement
	function shakeBucket() {
		if (shakeCount < 5) {
			// Shake for 10 frames
			bucket.y += shakeCount % 2 === 0 ? -shakeStep : shakeStep;
			shakeCount++;
			LK.setTimeout(shakeBucket, 100); // Call shakeBucket every 1/60th of a second
		} else {
			moveBucketUpAfterShake(); // Move bucket up after shaking
		}
	}
	function moveBucketUpAfterShake() {
		if (isPlaying && bucket.y > -bucket.height) {
			isBucketMovingUp = true; // Ensure flag remains true while moving up
			//log("Bucket is moving up. Current y position: " + bucket.y);
			bucket.y -= bucketMoveStep;
			game.addChild(bucket); // Ensure bucket is above sand blocks
			LK.setTimeout(moveBucketUpAfterShake, 5); // Call moveBucketUp every 1/240th of a second
		} else {
			//log("Bucket end moving up. Current y position: " + bucket.y + "/-" + bucket.height);
			isBucketMovingUp = false; // Set flag to false when bucket finishes moving up
		}
	}
	shakeBucket(); // Start shaking the bucket
}
function moveBucketDown() {
	if (isBucketMovingUp) {
		return;
	} // Prevent concurrent moves
	isBucketMovingDown = true; // Set flag to true when bucket starts moving down
	var bucketMoveStep = 15; // Adjust the step size as needed
	if (isPlaying && bucket.y < -15) {
		log("Bucket is moving down. Current y position: " + bucket.y);
		bucketReady = false; // Reset the flag when the bucket is moving down
		bucket.y += bucketMoveStep;
		game.addChild(bucket); // Ensure bucket is above sand blocks
		LK.setTimeout(moveBucketDown, 1000 / 60); // Call moveBucketDown every 1/60th of a second
	} else {
		log("Bucket moving down. Ready ");
		bucketReady = true; // Set the flag to true when the bucket reaches y=0
		isBucketMovingDown = false; // Set flag to false when bucket finishes moving down
	}
}
function createNewSandBlock() {
	sandBlockHeightRatio = sandBlockHeightBaseRatio;
	currentSandBlock = new SandBlock();
	var sandBlock = currentSandBlock;
	sandBlock.x = bucket.x;
	sandBlock.y = 256;
	game.addChild(sandBlock);
	game.addChild(bucket);
	cameraMoved = false; // Reset the flag when a new sandblock is created
	sandBlockDropped = true; // Set the flag to true when a new sand block is created
}
function updateSandBlockPosition(sandBlock) {
	bucketReady = false;
	if (sandBlock.y < 512) {
		// Restore sand block height when out of bucket
		if (sandBlockHeightRatio < 1) {
			sandBlockHeightRatio += 0.05;
			sandBlock.height = sandBlockAssetHeight * Math.min(1, sandBlockHeightRatio);
		} else {
			sandBlockHeightRatio = 1;
			sandBlock.height = sandBlockAssetHeight;
		}
		//log("sandBlockHeightRatio=" + sandBlockHeightRatio);
	}
	if (sandBlock.y < centralPointY) {
		// Start of fall until center
		if (!sandBlock.falling) {
			LK.getSound('sandFall').play();
			sandBlock.falling = true;
		}
		sandBlock.velocity += gravity; // Increase velocity due to gravity
		sandBlock.y += sandBlock.velocity; // Update position based on velocity
	} else {
		// Center : Check if on previous block or out
		if (Math.abs(sandBlock.x - previousBlockX) > sandBlockHalfWidth) {
			// Out : Continue falling
			if (sandBlock.y < 2732 + sandBlockSize) {
				// Fall until botom
				sandBlock.rotation += 0.07 * Math.sign(sandBlock.x - previousBlockX);
				sandBlock.x += 20 * Math.sign(sandBlock.x - previousBlockX);
				sandBlock.velocity += gravity; // Increase velocity due to gravity
				sandBlock.y += sandBlock.velocity; // Update position based on velocity
			} else {
				var checkBucketUpCompletion = function checkBucketUpCompletion() {
					if (!isBucketMovingUp) {
						sandBlockDropped = false;
						isBucketMovingHorizontally = true; // Resume horizontal movement of the bucket
						moveBucketDown(); // Progressively move the bucket down when the camera reaches the target
						game.addChild(bucket); // Ensure bucket is above sand blocks
					} else {
						LK.setTimeout(checkBucketUpCompletion, 1000 / 60); // Check again in the next frame
					}
				};
				// Reached bottom
				checkBlockAlignmentAndUpdate(sandBlock);
				sandBlock.fallen = true;
				sandBlock.destroy();
				currentSandBlock = null;
				// Ensure bucket has finished moving up before running the next steps
				checkBucketUpCompletion();
			}
		} else {
			// Ok : Stop
			sandBlocks.push(currentSandBlock);
			globalDelta = Math.max(globalDelta, Math.abs(currentSandBlock.x - 1024));
			sandBlockMoveStep = Math.floor(globalDelta / 100);
			previousBlockX = currentSandBlock.x;
			// Move background, sandcastle, and fallen sandblock vertically by sandBlockSize
			if (!cameraMoved) {
				cameraMoved = true;
				isCameraMoving = true; // Set the flag to true when the camera starts moving
				LK.setTimeout(function () {
					moveCamera();
					// Set the flag to true after moving the camera
					//bucket.y = 0; // Reset bucket position when the camera moves
				}, 640); // Delay of 1 second before moving the camera
				// Check if sand block reached the base
				checkBlockAlignmentAndUpdate(sandBlock);
			}
			currentSandBlock = null;
		}
	}
}
function moveBucketHorizontally() {
	if (!level) {
		return;
	}
	if (!lastUpdateTime) {
		lastUpdateTime = Date.now();
	}
	var currentTime = Date.now();
	var dt = (currentTime - lastUpdateTime) / 1000; // Delta time in seconds
	lastUpdateTime = currentTime;
	var moveDistance = bucketMoveStep * bucketDirection * dt * 60; // Adjust for 60 FPS
	if (bucket.x >= 2048 - bucket.width / 2) {
		bucketDirection = -1; // Change direction to left
	} else if (bucket.x <= bucket.width / 2) {
		bucketDirection = 1; // Change direction to right
	}
	log("moveBucketHorizontally: x=" + bucket.x, "moveDistance=" + moveDistance, "dt=" + dt);
	bucket.x += moveDistance;
}
function checkBlockAlignmentAndUpdate(sandBlock) {
	if (Math.abs(sandBlock.x - previousBlockX) < sandBlockHalfWidth) {
		LK.getSound('dropped').play();
		// Check for perfect alignment
		level += 1;
		score += 1; // Bonus points for perfect alignment
		LK.setScore(score); // Store the score in LK score
		if (level > 0 && level % 3 === 0) {
			bucketMoveStep += 4; // Increase bucket speed by 2 units
		}
	} else {
		LK.getSound('missed').play();
		lives--;
		livesIcons[lives].destroy();
		livesIcons.pop();
		if (lives <= 0) {
			var checkBucketUpCompletionForScore = function checkBucketUpCompletionForScore() {
				if (!isBucketMovingUp) {
					cleanPlayingState();
					initScoreState();
				} else {
					LK.setTimeout(checkBucketUpCompletionForScore, 1000 / 60); // Check again in the next frame
				}
			};
			checkBucketUpCompletionForScore();
			return;
		}
	}
	sandBlock.falling = false; // Reset the falling flag
	sandBlockDropped = false; // Reset the flag after handling sand block reaching the base
	game.addChild(bucket); // Ensure bucket is above sand blocks
}
function initializeBackgrounds() {
	var mainBgY = 1566;
	var mainBgHeight = 2732;
	//var bgHeight = 1152;
	//var bgHalfHeight = 576;
	backgroundImage = LK.getAsset('backgroundImage', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: mainBgY
	});
	game.addChild(backgroundImage);
	background2 = LK.getAsset('background2', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2
	});
	background2.y = backgroundImage.y - mainBgHeight / 2 - bgHalfHeight;
	game.addChild(background2);
	background3 = LK.getAsset('background3', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2
	});
	background3.y = background2.y - bgHeight;
	background4 = LK.getAsset('background2', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2
	});
	background4.y = background3.y - bgHeight;
	game.addChild(background4);
	background5 = LK.getAsset('background3', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2
	});
	background5.y = background4.y - bgHeight;
	;
	game.addChild(background5);
	game.addChild(background3);
}
function loopBgMusic() {
	if (bgMusic && Date.now() - bgMusic.lastPlayTime > 10000) {
		bgMusic.lastPlayTime = Date.now();
		bgMusic.play();
	}
}
/****************************************************************************************** */ 
/************************************* GAME STATES **************************************** */
/****************************************************************************************** */ 
function gameInitialize() {
	log("Game initialize...");
	initializeBackgrounds();
	boat = new Boat();
	boat.x = boat.width;
	boat.y = 1090;
	boat.visible = true;
	game.addChild(boat);
	sandcastle = new Sandcastle();
	sandcastle.x = 2048 / 2;
	sandcastle.y = -sandcastleHeight; // Hide the sandcastle above the screen initially
	game.addChild(sandcastle);
	picketLeft = LK.getAsset('picket', {
		anchorX: 0.5,
		anchorY: 1,
		x: 30,
		y: 2140
	});
	game.addChild(picketLeft);
	picketRight = LK.getAsset('picket', {
		anchorX: 0.5,
		anchorY: 1,
		scaleX: -1,
		x: 2018,
		y: 2140
	});
	game.addChild(picketRight);
	banner = LK.getAsset('banner', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 1024,
		y: 300
	});
	game.addChild(banner);
	game.addChild(sandcastle);
	level = 0;
	score = 0;
	LK.setScore(score); // Initialize LK score to zero at game start
	bgMusic = LK.getSound('music');
	if (bgMusic && bgMusic.isPlaying) {
		bgMusic.stop();
	}
	bgMusic.lastPlayTime = 0;
	startButton = LK.getAsset('startButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 1420 // Center of the screen
	});
	startButton.visible = false; // Initially hidden
	game.addChild(startButton);
	beachToys = new BeachToys();
	beachToys.x = 2048 / 2;
	beachToys.y = 2922;
	game.addChild(beachToys);
	// Initialize clouds at the beginning but keep them invisible
	cloud1 = new Cloud(1);
	cloud1.x = -cloud1.width;
	cloud1.y = -cloud1.height;
	cloud1.visible = false;
	game.addChild(cloud1);
	cloud2 = new Cloud(2);
	cloud2.x = -cloud2.width;
	cloud2.y = -cloud2.height;
	cloud2.visible = false;
	game.addChild(cloud2);
	flyingObject1 = new FlyingObject(1);
	flyingObject1.x = -Math.random() * 512;
	flyingObject1.y = flyingObject1.height + 256 * Math.random();
	flyingObject1.visible = false;
	flyingObject1.passed = true;
	game.addChild(flyingObject1);
	flyingObject2 = new FlyingObject(2);
	flyingObject2.x = -Math.random() * 512;
	flyingObject2.y = flyingObject2.height + 256 * Math.random();
	flyingObject2.visible = false;
	flyingObject2.passed = true;
	game.addChild(flyingObject2);
	flyingObject3 = new FlyingObject(3);
	flyingObject3.x = -Math.random() * 512;
	flyingObject3.y = flyingObject3.height + 256 * Math.random();
	flyingObject3.visible = false;
	flyingObject3.passed = true;
	game.addChild(flyingObject3);
	flyingObject4 = new FlyingObject(4);
	flyingObject4.x = -Math.random() * 512;
	flyingObject4.y = flyingObject4.height + 256 * Math.random();
	flyingObject4.visible = false;
	flyingObject4.passed = true;
	game.addChild(flyingObject4);
	initMenuState();
	if (isDebug) {
		debugMarker = LK.getAsset('debugMarker', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: 1300,
			y: 160
		});
		game.addChild(debugMarker);
		debugText = new Text2('Debug Info', {
			size: 50,
			fill: "#ffffff"
		});
		debugText.anchor.set(0.5, 1); // Anchor to the bottom-right
		LK.gui.bottom.addChild(debugText);
	}
}
// GAME MENU
function initMenuState() {
	log("initMenuState...");
	gameState = GAME_STATE.MENU;
}
function handleMenuLoop() {
	// Menu animations here
}
function cleanMenuState() {
	log("cleanMenuState...");
}
// NEW ROUND
function initNewRoundState() {
	log("initNewRoundState...");
	gameState = GAME_STATE.NEW_ROUND;
	// Fade in the start button
	startButton.visible = true;
	startButton.alpha = 0;
	var fadeInStep = 0.05;
	function fadeInStartButton() {
		if (startButton.alpha < 1) {
			startButton.alpha += fadeInStep;
			LK.setTimeout(fadeInStartButton, 1000 / 60); // Call fadeInStartButton every 1/60th of a second
		}
	}
	fadeInStartButton();
}
function handleNewRoundLoop() {
	// New Round animations here
	loopBgMusic();
}
function cleanNewRoundState() {
	if (isCleaningNewRound) {
		return;
	} // Prevent multiple calls
	isCleaningNewRound = true;
	log("cleanNewRoundState...");
	// Animate the start button removal
	var fadeOutStep = 0.05;
	function fadeOutStartButton() {
		log("fadeOutStartButton...", startButton.alpha, "step=" + fadeOutStep);
		if (startButton.alpha > 0 && Date.now() - fadeOutStartButtonStartTime < 1000) {
			startButton.alpha -= fadeOutStep;
			LK.setTimeout(fadeOutStartButton, 1000 / 60); // Call fadeOutStartButton every 1/60th of a second
		} else {
			log("fadeOutStartButton End");
			startButton.alpha = 0;
			var fadeOutBeachToys = function fadeOutBeachToys() {
				log("fadeOutBeachToys...");
				if (beachToys.alpha > 0) {
					beachToys.alpha -= fadeOutStep;
					LK.setTimeout(fadeOutBeachToys, 1000 / 60);
				} else {
					log("fadeOutBeachToys End");
					beachToys.visible = false;
					beachToys.alpha = 1; // Reset alpha for future use
					var animateSandcastleFall = function animateSandcastleFall() {
						log("animateSandcastleFall...");
						if (sandcastle.y < sandcastleBaseY) {
							sandcastle.velocity += gravity; // Increase velocity due to gravity
							sandcastle.y += sandcastle.velocity; // Update position based on velocity
							LK.setTimeout(animateSandcastleFall, 1000 / 60); // Call animateSandcastleFall every 1/60th of a second
						} else {
							log("animateSandcastleFall End");
							sandcastle.y = sandcastleBaseY; // Ensure it stops exactly at the base
							LK.getSound('dropped').play(); // Play drop sound when it reaches its position
							initPlayingState();
							isCleaningNewRound = false; // Reset the flag after completion
						}
					};
					startButton.visible = false;
					startButton.alpha = 1; // Reset alpha for future use
					sandcastle.velocity = 0; // Initial velocity for natural falling speed increase
					animateSandcastleFall();
				}
			};
			fadeOutBeachToys();
		}
	}
	fadeOutStartButtonStartTime = Date.now(); // Prevent Bug alpha stucked on tap
	fadeOutStartButton();
}
// PLAYING
function initPlayingState() {
	log("initPlayingState...");
	gameState = GAME_STATE.PLAYING;
	isPlaying = true;
	for (var i = 0; i < lives; i++) {
		var lifeIcon = LK.getAsset('bucketIcon', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: 2048 - 100,
			y: 1166 + i * 130
		});
		livesIcons.push(lifeIcon);
		game.addChild(lifeIcon);
	}
	bucket = new Bucket();
	bucket.x = 2048 / 2;
	bucket.y = -bucket.height;
	game.addChild(bucket); // Ensure bucket is above sand blocks
	moveBucketDown();
}
function handlePlayingLoop() {
	loopBgMusic();
	if (isPlaying && currentSandBlock) {
		updateSandBlockPosition(currentSandBlock);
		//game.addChild(bucket); // Ensure bucket is above sand blocks
	}
	if (level >= 4) {
		for (var i = 0; i < sandBlocks.length; i++) {
			var sandBlock = sandBlocks[i];
			sandBlock.x += Math.sin(LK.ticks / 20) * sandBlockMoveStep; // Move sand blocks back and forth
		}
	}
	if (bucket && bucket.scoreTxt) {
		if (score === 0) {
			bucket.scoreTxt.visible = false;
		} else {
			bucket.scoreTxt.visible = true;
			bucket.scoreTxt.setText(score);
		}
	}
	if (isBucketMovingHorizontally) {
		moveBucketHorizontally(); // Ensure horizontal movement is restored
	}
	if (level >= 6 && cloud1 && cloud2 && !cloud1.visible) {
		cloud1.visible = true;
		cloud2.visible = true;
	}
	if (level && flyingObject1 && level % 4 == 0 && level < 20 && !flyingObject1.visible && flyingObject1.passed) {
		flyingObject1.visible = true;
		flyingObject1.passed = false;
	}
	if (level && flyingObject2 && level % 15 == 0 && level < 60 && !flyingObject2.visible && flyingObject2.passed) {
		flyingObject2.visible = true;
		flyingObject2.passed = false;
	}
	if (level && flyingObject3 && level % 10 == 0 && level < 40 && !flyingObject3.visible && flyingObject3.passed) {
		flyingObject3.visible = true;
		flyingObject3.passed = false;
	}
	if (level && flyingObject4 && level % 21 == 0 && !flyingObject4.visible && flyingObject4.passed) {
		flyingObject4.visible = true;
		flyingObject4.passed = false;
	}
	if (isDebug) {
		//debugText.setText("X: " + bucket.x + " Y: " + bucket.y);
		debugText.setText("Delta: " + globalDelta);
	}
}
function cleanPlayingState() {
	log("cleanPlayingState...");
	isPlaying = false;
	// TODO Remove elements
}
// SCORE
function initScoreState() {
	log("initScoreState...");
	gameState = GAME_STATE.SCORE;
	// Play camera sound
	LK.getSound('camera').play();
	// Prepare final animation
	// Add a 1-second white screen flash
	LK.effects.flashScreen(0xffffff, 2000);
	LK.setTimeout(setupFinalPhoto, 1000);
	confetti = new Confetti();
	confetti.visible = false;
	game.addChild(confetti);
}
function setupFinalPhoto() {
	// Set the background size to 2048x2732
	backgroundImage.width = 2048;
	backgroundImage.height = 2732;
	// Set the background position to the center of the screen
	backgroundImage.x = 2048 / 2;
	backgroundImage.y = 2732 / 2;
	background2.visible = false;
	background3.visible = false;
	background4.visible = false;
	background5.visible = false;
	cloud1.visible = false;
	cloud2.visible = false;
	var finalScoreTxt = new Text2(score.toString(), {
		size: 150,
		fill: "#FFFFFF",
		weight: 1000,
		dropShadow: true
	});
	finalScoreTxt.anchor.set(0.5, 0.2);
	LK.gui.top.addChild(finalScoreTxt);
	// Scale the sandcastle and the sandblocks down to fit in the screen
	var ratio = 1 / Math.ceil(sandBlocks.length / 3);
	sandcastle.width *= ratio;
	sandcastle.height *= ratio;
	sandcastle.x = 2048 / 2;
	sandcastle.y = sandcastleBaseY;
	sandcastle.shadow.visible = true;
	if (ratio <= 0.5) {
		beachToys = new BeachToys();
		beachToys.width *= ratio;
		beachToys.height *= ratio;
		beachToys.x = 1724;
		beachToys.y = sandcastleBaseY + 300;
		game.addChild(beachToys);
		var sandcastle2 = new Sandcastle();
		sandcastle2.x = 312;
		sandcastle2.y = sandcastleBaseY - 250; // Hide the sandcastle above the screen initially
		sandcastle2.width *= 0.8;
		sandcastle2.height *= 0.8;
		sandcastle2.width *= ratio;
		sandcastle2.height *= ratio;
		game.addChild(sandcastle2);
		sandcastle2.shadow.visible = true;
		beachToys2 = new BeachToys(2);
		beachToys2.width *= ratio;
		beachToys2.height *= ratio;
		beachToys2.shadow.visible = false;
		beachToys2.x = sandcastle2.x; // sandcastle2.x - sandcastle2.width / 2 - beachToys2.width / 2;
		beachToys2.y = sandcastle2.y + sandcastle2.height / 2 + 300 * ratio; //sandcastleBaseY + 350;
		game.addChild(beachToys2);
	}
	banner.width *= ratio;
	banner.height *= ratio;
	banner.x = 2048 / 2;
	banner.y = 2140 - picketLeft.height * ratio;
	picketLeft.width *= ratio;
	picketLeft.height *= ratio;
	picketLeft.x = 1024 - (1024 - 30) * ratio;
	picketLeft.y = 2140;
	picketRight.width *= ratio;
	picketRight.height *= ratio;
	picketRight.x = 1024 + (1024 - 30) * ratio;
	picketRight.y = 2140;
	var baseY = sandcastle.y - sandcastle.height / 2 - sandBlockSize * ratio;
	log("baseY ", baseY);
	for (var i = 0; i < sandBlocks.length; i++) {
		sandBlocks[i].width *= ratio;
		sandBlocks[i].height *= ratio;
		sandBlocks[i].x = 1024 - (1024 - sandBlocks[i].x) * ratio;
		sandBlocks[i].y = baseY - i * sandBlockSize * ratio;
		sandBlocks[i].visible = true;
		//log("block #", i, " h=" + sandBlockSize * ratio, " / y = ", sandBlocks[i].y);
	}
	// Show confetti
	confetti.visible = true;
	boat.y = 1000;
	boat.width *= ratio;
	boat.height *= ratio;
	boat.reverse();
}
function handleScoreLoop() {
	// Score display logic here
	loopBgMusic();
}
function cleanScoreState() {
	log("cleanScoreState...");
	LK.showGameOver();
}
/***********************************************************************************/ 
/******************************** MAIN GAME LOOP ***********************************/
/***********************************************************************************/ 
game.update = function () {
	switch (gameState) {
		case GAME_STATE.MENU:
			handleMenuLoop();
			break;
		case GAME_STATE.NEW_ROUND:
			handleNewRoundLoop();
			break;
		case GAME_STATE.PLAYING:
			handlePlayingLoop();
			break;
		case GAME_STATE.SCORE:
			handleScoreLoop();
			break;
	}
};
gameInitialize(); // Initialize the game
/********************************************************************************/
/**************************** GAME DESCRIPTION *********************************/
/******************************************************************************/
/* 
**Game Title**: **Sand Tower**
**Description**: Build towering sandcastles, perfect your alignment, and climb to the top! Sand Tower awaits! 🏖️🏰
**Objective**:
	- Players aim to construct the tallest sandcastle tower.
	- Perfect alignment of sand blocks is crucial for stability and bonus points.
**Visuals**:
	- The game features a sandy beach backdrop.
	- A basic sandcastle stands in the center, serving as the base.
	- The central tower is the focal point.
**Gameplay Mechanics**:
	- **Beach Bucket Mechanism**:
		- Players use an upside-down beach bucket.
		- When the player taps, the bucket tips over, releasing sand.
	- **Sand Block Placement**:
		- Sand falls vertically from the bucket onto the base.
		- The player must time their taps to stack the sand blocks.
		- Perfect alignment grants bonus points.
	- **Lives System**:
		- The player starts with 3 lives (represented by small bucket icons).
		- Each time a sand block isn't centered enough and falls, 1 life is lost.
	- **Scoring**:
		- Points increase with tower height.
		- Bonus points for precise alignment.
	- **Game Over**:
		- The game ends if the player loses all their lives (buckets).
**Audio**:
	- Gentle beach sounds (waves, distant chatter).
	- Encouraging music during gameplay.
*/  /**** 
* Classes
****/ 
var BeachToys = Container.expand(function (index) {
	var self = Container.call(this);
	self.shadow = self.attachAsset('beachToysShadow', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 150,
		y: -150,
		alpha: 0.3,
		scaleX: -1,
		scaleY: 1,
		tint: 0x000000,
		rotation: 2.3,
		visible: !index
	});
	var alt = index ? "2" : "";
	var beachToysGraphics = self.attachAsset('beachToys' + alt, {
		anchorX: 0.5,
		anchorY: 1.0
	});
});
var Boat = Container.expand(function () {
	var self = Container.call(this);
	var boatGraphics = self.attachAsset('boat', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 2; // Speed of the boat movement
	self.direction = 1; // Direction of the boat movement, 1 for right, -1 for left
	self.update = function () {
		if (!self.startTime) {
			self.startTime = LK.ticks;
		}
		var elapsed = (LK.ticks - self.startTime) / 60; // Elapsed time in seconds
		var targetX = self.x + self.speed * self.direction;
		self.x = self.x + (targetX - self.x) * 0.1; // Linear interpolation for smoother movement
		if (self.x > 2048 + boatGraphics.width / 2) {
			self.x = -boatGraphics.width / 2; // Reset position to the left of the screen
		} else if (self.x < -boatGraphics.width / 2) {
			self.x = 2048 + boatGraphics.width / 2; // Reset position to the right of the screen
		}
		if (self.y > 2748 + self.height / 2) {
			self.visible = false; // Make the boat not visible when y > 2748
		}
	};
	/**
	* Reverses the direction of the boat.
	*/ 
	self.reverse = function () {
		self.direction *= -1;
		self.scale.x *= -1;
		self.visible = true;
		self.x = 2048 + self.width / 2; // Reset position to the right of the screen
	};
});
var Bucket = Container.expand(function () {
	var self = Container.call(this);
	var bucketGraphics = self.attachAsset('bucket', {
		anchorX: 0.5,
		anchorY: 0.0
	});
	self.scoreTxt = new Text2('00', {
		size: 200,
		fill: "#03a2c3",
		weight: 1000
	});
	self.scoreTxt.anchor.set(0.5, 0);
	self.scoreTxt.x = 0;
	self.scoreTxt.y = 330;
	self.addChild(self.scoreTxt);
});
var Cloud = Container.expand(function (index) {
	var self = Container.call(this);
	var cloudGraphics = self.attachAsset('cloud' + index, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speed = 0.4 + (2 - index) * 0.2 + Math.random() * 0.2; // Speed of the cloud movement
	self.update = function () {
		if (!self.visible) {
			return;
		}
		self.x += self.speed;
		if (self.x > 2048 + cloudGraphics.width / 2) {
			self.x = -cloudGraphics.width / 2 - Math.random() * 2048; // Reset position to the left of the screen
			self.y = Math.random() * 512;
		}
	};
});
var Confetti = Container.expand(function () {
	var self = Container.call(this);
	var confettiColors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];
	var confettiPieces = [];
	var nbConfettis = 3 + level * 7;
	nbConfettis = Math.min(500, nbConfettis);
	for (var i = 0; i < nbConfettis; i++) {
		var confettiPiece = self.attachAsset('confetti', {
			anchorX: 0.5,
			anchorY: 0.5,
			width: 15,
			height: 50,
			tint: confettiColors[Math.floor(Math.random() * confettiColors.length)]
		});
		confettiPiece.x = Math.random() * 2048;
		confettiPiece.y = Math.random() * 2732;
		confettiPiece.rotation = Math.random() * Math.PI * 2;
		confettiPiece.speedY = Math.random() * 5 + 4;
		confettiPiece.speedX = (Math.random() - 0.5) * 2;
		confettiPieces.push(confettiPiece);
	}
	self.update = function () {
		for (var i = 0; i < confettiPieces.length; i++) {
			var piece = confettiPieces[i];
			piece.y += piece.speedY;
			piece.x += piece.speedX;
			if (piece.y > 2732) {
				piece.y = -piece.height;
				piece.x = Math.random() * 2048;
			}
		}
	};
});
var FlyingObject = Container.expand(function (index) {
	var self = Container.call(this);
	var flyingObjectGraphics = self.attachAsset('flyingObject' + index, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.directionY = -1 * (Math.random() > 0.5);
	self.passed = true;
	self.speed = 3; // Speed of the flying object movement
	self.update = function () {
		if (!self.visible || self.passed) {
			return;
		}
		self.x += self.speed;
		self.y += self.speed * 0.1 * self.directionY;
		if (self.x > 2048 + flyingObjectGraphics.width / 2) {
			self.x = -flyingObjectGraphics.width / 2 - Math.random() * 1024; // Reset position to the left of the screen
			self.y = Math.random() * 512; // Reset position relative to the camera
			self.passed = true;
			self.visible = false;
		}
	};
});
var SandBlock = Container.expand(function () {
	var self = Container.call(this);
	var sandBlockGraphics = self.attachAsset('sandBlock', {
		anchorX: 0.5,
		anchorY: 0
	});
	self.height = sandBlockAssetHeight * sandBlockHeightBaseRatio;
	self.velocity = 0; // Initial velocity for natural falling speed increase
	self.update = function () {
		if (self.y > 2748 + self.height / 2) {
			self.visible = false;
		}
	};
});
/***********************************************************************************/ 
/********************************** SANDCASTLE CLASS ************************************/
/***********************************************************************************/ 
var Sandcastle = Container.expand(function () {
	var self = Container.call(this);
	self.shadow = self.attachAsset('shadow', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.5,
		visible: false
	});
	var sandcastleGraphics = self.attachAsset('sandcastle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.shadow.width = sandcastleGraphics.width;
	self.shadow.height = sandcastleGraphics.height * 0.5;
	self.shadow.y = sandcastleGraphics.height * 0.3;
	self.shadow.visible = false;
	self.update = function () {
		// Sandcastle specific update logic
	};
});
/**** 
* Initialize Game
****/ 
// Utility function to draw a polygon using drawLine
var game = new LK.Game({
	backgroundColor: 0x000050 // Initialize game with a black background
});
/**** 
* Game Code
****/ 
// Enumeration for game states
/****************************************************************************************** */ 
/************************************** GLOBAL VARIABLES ********************************** */
/****************************************************************************************** */ 
function easeInOutQuad(t) {
	return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
}
var isBucketMovingUp = false; // Flag to track if the bucket is moving up
var isBucketMovingDown = false; // Flag to track if the bucket is moving down
var GAME_STATE = {
	INIT: 'INIT',
	MENU: 'MENU',
	NEW_ROUND: 'NEW_ROUND',
	PLAYING: 'PLAYING',
	SCORE: 'SCORE'
};
var gameState = GAME_STATE.INIT;
var score = 0;
var level = 0;
var scoreTxt;
var isDebug = false;
var debugText;
var debugMarker;
var backgroundImage;
var bucket;
var banner;
var picketLeft;
var picketRight;
var sandBlocks = [];
var lives = 3;
var livesIcons = [];
var cameraMoved = false; // Flag to track if the camera has moved for the current sandblock fall
var sandBlockDropped = false; // Flag to track if a sand block has been dropped
var isCameraMoving = false; // Flag to track if the camera is currently moving
var bucketReady = false; // Flag to track if the bucket has reached y=0
var sandcastle;
var sandcastleBaseY = 2212;
var sandcastleHeight = 1640;
var previousBlockX = 1024;
var sandBlockWidth = 390;
var sandBlockHalfWidth = 195;
var sandBlockAssetHeight = 1618; // height of the asset
var sandBlockHeightBaseRatio = 0.6; // Extend effect start ratio
var sandBlockHeightRatio = sandBlockHeightBaseRatio; // Extend effect current ratio
var sandBlockSize = 460; // height of the visible sand block
var centralPointY = 1380 - sandBlockSize;
var bgHeight = 1152;
var bgHalfHeight = 576;
var gravity = 2; // Gravity effect for sand block falling
var bucketDirection = 1; // 1 for right, -1 for left
var isBucketMovingHorizontally = false; // Flag to track if the bucket is moving horizontally
var bucketMoveStep = 10; // Initial bucket move step size
var currentSandBlock = null; // Global variable to keep track of the current sand block
var startButton = null; // Global variable for the start button
var isPlaying = false; // Global variable to track if the game is currently in the playing state
var sandBlockMoveStep = 2; // Step size for sand block horizontal movement
var bgMusic;
var globalDelta = 0;
var beachToys = null; // Global variable for beach toys
var cloud1 = null; // Global variable for cloud1
var cloud2 = null; // Global variable for cloud2
var moveStep = 0; // Global variable for move step
var flyingObject1 = null; // Global variable for flyingObject1
var flyingObject2 = null; // Global variable for flyingObject2
var flyingObject3 = null; // Global variable for flyingObject2
var flyingObject4 = null; // Global variable for flyingObject2
var fadeOutStartButtonStartTime = 0;
var isCleaningNewRound = false; // Flag to prevent multiple calls to cleanNewRoundState
var lastUpdateTime = 0;
/****************************************************************************************** */ 
/*********************************** UTILITY FUNCTIONS ************************************ */
/****************************************************************************************** */ 
function moveCamera() {
	var targetY = backgroundImage.y + sandBlockSize;
	moveStep = sandBlockSize / 60; // Move over 1 second (60 frames)
	function progressiveMove() {
		if (backgroundImage.y < targetY) {
			log("Camera is moving. Current y position: " + backgroundImage.y);
			backgroundImage.y += moveStep;
			background2.y += moveStep;
			background3.y += moveStep;
			sandcastle.y += moveStep;
			background4.y += moveStep;
			background5.y += moveStep;
			banner.y += moveStep * 1.05;
			picketLeft.y += moveStep * 1.05;
			picketRight.y += moveStep * 1.05;
			for (var j = 0; j < sandBlocks.length; j++) {
				sandBlocks[j].y += moveStep;
			}
			if (cloud1) {
				cloud1.y += moveStep * 0.5;
			}
			if (cloud2) {
				cloud2.y += moveStep * 0.5;
			}
			if (flyingObject1 && flyingObject1.visible) {
				flyingObject1.y += moveStep * 0.75;
			}
			if (flyingObject2 && flyingObject2.visible) {
				flyingObject2.y += moveStep * 0.75;
			}
			if (flyingObject3 && flyingObject3.visible) {
				flyingObject3.y += moveStep * 0.75;
			}
			if (flyingObject4 && flyingObject4.visible) {
				flyingObject4.y += moveStep * 0.75;
			}
			if (boat) {
				boat.y += moveStep;
			}
			if (backgroundImage.y < targetY) {
				LK.setTimeout(progressiveMove, 1000 / 60); // Call progressiveMove every 1/60th of a second
			} else {
				isCameraMoving = false; // Set the flag to false when the camera stops moving
				var checkBucketUpCompletion = function checkBucketUpCompletion() {
					if (bucket.y <= -bucket.height && !isBucketMovingUp) {
						isBucketMovingHorizontally = true; // Resume horizontal movement of the bucket
						moveBucketDown(); // Progressively move the bucket down when the camera reaches the target
						game.addChild(bucket); // Ensure bucket is above sand blocks
					} else {
						LK.setTimeout(checkBucketUpCompletion, 1000 / 60); // Check again in the next frame
					}
				};
				checkBucketUpCompletion();
			}
			if (background2.y > 2732 + bgHalfHeight) {
				background2.y = background5.y - background5.height;
			}
			if (background3.y > 2732 + bgHalfHeight) {
				background3.y = background2.y - background2.height;
			}
			if (background4.y > 2732 + bgHalfHeight) {
				background4.y = background3.y - background3.height;
			}
			if (background5.y > 2732 + bgHalfHeight) {
				background5.y = background4.y - background4.height;
			}
		}
	}
	progressiveMove();
}
function log() {
	if (isDebug) {
		var _console;
		(_console = console).log.apply(_console, arguments);
	}
}
/****************************************************************************************** */ 
/************************************** INPUT HANDLERS ************************************ */
/****************************************************************************************** */ 
game.on('down', function (x, y, obj) {
	handleGameState(x, y, obj);
});
function handleGameState(x, y, obj) {
	switch (gameState) {
		case GAME_STATE.MENU:
			gameMenuDown(x, y, obj);
			break;
		case GAME_STATE.NEW_ROUND:
			gameNewRoundDown(x, y, obj);
			break;
		case GAME_STATE.PLAYING:
			gamePlayingDown(x, y, obj);
			break;
		case GAME_STATE.SCORE:
			gameScoreDown(x, y, obj);
			break;
	}
}
function gameMenuDown(x, y, obj) {
	log("gameMenuDown...");
	if (gameState != GAME_STATE.MENU) {
		return;
	}
	cleanMenuState();
	initNewRoundState();
}
function gameNewRoundDown(x, y, obj) {
	log("gameNewRoundDown...");
	if (gameState != GAME_STATE.NEW_ROUND || isCleaningNewRound) {
		return;
	}
	log("gameNewRoundDown Ok clean...");
	cleanNewRoundState();
}
function gamePlayingDown(x, y, obj) {
	log("gamePlayingDown...", "state=" + (gameState == GAME_STATE.PLAYING), "playing=" + isPlaying, "dropped=" + !sandBlockDropped, "camera=" + !isCameraMoving, "bucket=" + bucketReady);
	if (gameState != GAME_STATE.PLAYING || !isPlaying || sandBlockDropped || isCameraMoving || !bucketReady) {
		return; // Prevent taps during camera movement
	}
	sandBlockDropped = true;
	log("gamePlayingDown OK");
	// Pause horizontal movement of the bucket
	isBucketMovingHorizontally = false;
	lastUpdateTime = 0;
	// Move the bucket vertically to hide over the screen top with shake
	moveBucketUp();
	LK.setTimeout(createNewSandBlock, 512); // Delay creating new sand block until after shake
}
function gameScoreDown(x, y, obj) {
	log("gameScoreDown...");
	cleanScoreState();
}
/****************************************************************************************** */ 
/************************************* GAME FUNCTIONS ************************************* */
/****************************************************************************************** */ 
function moveBucketUp() {
	if (isBucketMovingDown) {
		return;
	} // Prevent concurrent moves
	isBucketMovingUp = true; // Set flag to true when bucket starts moving up
	var bucketMoveStep = 15; // Adjust the step size as needed
	var shakeStep = 40; // Step size for shake movement
	var shakeCount = 0; // Counter for shake movement
	function shakeBucket() {
		if (shakeCount < 5) {
			// Shake for 10 frames
			bucket.y += shakeCount % 2 === 0 ? -shakeStep : shakeStep;
			shakeCount++;
			LK.setTimeout(shakeBucket, 100); // Call shakeBucket every 1/60th of a second
		} else {
			moveBucketUpAfterShake(); // Move bucket up after shaking
		}
	}
	function moveBucketUpAfterShake() {
		if (isPlaying && bucket.y > -bucket.height) {
			isBucketMovingUp = true; // Ensure flag remains true while moving up
			//log("Bucket is moving up. Current y position: " + bucket.y);
			bucket.y -= bucketMoveStep;
			game.addChild(bucket); // Ensure bucket is above sand blocks
			LK.setTimeout(moveBucketUpAfterShake, 5); // Call moveBucketUp every 1/240th of a second
		} else {
			//log("Bucket end moving up. Current y position: " + bucket.y + "/-" + bucket.height);
			isBucketMovingUp = false; // Set flag to false when bucket finishes moving up
		}
	}
	shakeBucket(); // Start shaking the bucket
}
function moveBucketDown() {
	if (isBucketMovingUp) {
		return;
	} // Prevent concurrent moves
	isBucketMovingDown = true; // Set flag to true when bucket starts moving down
	var bucketMoveStep = 15; // Adjust the step size as needed
	if (isPlaying && bucket.y < -15) {
		log("Bucket is moving down. Current y position: " + bucket.y);
		bucketReady = false; // Reset the flag when the bucket is moving down
		bucket.y += bucketMoveStep;
		game.addChild(bucket); // Ensure bucket is above sand blocks
		LK.setTimeout(moveBucketDown, 1000 / 60); // Call moveBucketDown every 1/60th of a second
	} else {
		log("Bucket moving down. Ready ");
		bucketReady = true; // Set the flag to true when the bucket reaches y=0
		isBucketMovingDown = false; // Set flag to false when bucket finishes moving down
	}
}
function createNewSandBlock() {
	sandBlockHeightRatio = sandBlockHeightBaseRatio;
	currentSandBlock = new SandBlock();
	var sandBlock = currentSandBlock;
	sandBlock.x = bucket.x;
	sandBlock.y = 256;
	game.addChild(sandBlock);
	game.addChild(bucket);
	cameraMoved = false; // Reset the flag when a new sandblock is created
	sandBlockDropped = true; // Set the flag to true when a new sand block is created
}
function updateSandBlockPosition(sandBlock) {
	bucketReady = false;
	if (sandBlock.y < 512) {
		// Restore sand block height when out of bucket
		if (sandBlockHeightRatio < 1) {
			sandBlockHeightRatio += 0.05;
			sandBlock.height = sandBlockAssetHeight * Math.min(1, sandBlockHeightRatio);
		} else {
			sandBlockHeightRatio = 1;
			sandBlock.height = sandBlockAssetHeight;
		}
		//log("sandBlockHeightRatio=" + sandBlockHeightRatio);
	}
	if (sandBlock.y < centralPointY) {
		// Start of fall until center
		if (!sandBlock.falling) {
			LK.getSound('sandFall').play();
			sandBlock.falling = true;
		}
		sandBlock.velocity += gravity; // Increase velocity due to gravity
		sandBlock.y += sandBlock.velocity; // Update position based on velocity
	} else {
		// Center : Check if on previous block or out
		if (Math.abs(sandBlock.x - previousBlockX) > sandBlockHalfWidth) {
			// Out : Continue falling
			if (sandBlock.y < 2732 + sandBlockSize) {
				// Fall until botom
				sandBlock.rotation += 0.07 * Math.sign(sandBlock.x - previousBlockX);
				sandBlock.x += 20 * Math.sign(sandBlock.x - previousBlockX);
				sandBlock.velocity += gravity; // Increase velocity due to gravity
				sandBlock.y += sandBlock.velocity; // Update position based on velocity
			} else {
				var checkBucketUpCompletion = function checkBucketUpCompletion() {
					if (!isBucketMovingUp) {
						sandBlockDropped = false;
						isBucketMovingHorizontally = true; // Resume horizontal movement of the bucket
						moveBucketDown(); // Progressively move the bucket down when the camera reaches the target
						game.addChild(bucket); // Ensure bucket is above sand blocks
					} else {
						LK.setTimeout(checkBucketUpCompletion, 1000 / 60); // Check again in the next frame
					}
				};
				// Reached bottom
				checkBlockAlignmentAndUpdate(sandBlock);
				sandBlock.fallen = true;
				sandBlock.destroy();
				currentSandBlock = null;
				// Ensure bucket has finished moving up before running the next steps
				checkBucketUpCompletion();
			}
		} else {
			// Ok : Stop
			sandBlocks.push(currentSandBlock);
			globalDelta = Math.max(globalDelta, Math.abs(currentSandBlock.x - 1024));
			sandBlockMoveStep = Math.floor(globalDelta / 100);
			previousBlockX = currentSandBlock.x;
			// Move background, sandcastle, and fallen sandblock vertically by sandBlockSize
			if (!cameraMoved) {
				cameraMoved = true;
				isCameraMoving = true; // Set the flag to true when the camera starts moving
				LK.setTimeout(function () {
					moveCamera();
					// Set the flag to true after moving the camera
					//bucket.y = 0; // Reset bucket position when the camera moves
				}, 640); // Delay of 1 second before moving the camera
				// Check if sand block reached the base
				checkBlockAlignmentAndUpdate(sandBlock);
			}
			currentSandBlock = null;
		}
	}
}
function moveBucketHorizontally() {
	if (!level) {
		return;
	}
	if (!lastUpdateTime) {
		lastUpdateTime = Date.now();
	}
	var currentTime = Date.now();
	var dt = (currentTime - lastUpdateTime) / 1000; // Delta time in seconds
	lastUpdateTime = currentTime;
	var moveDistance = bucketMoveStep * bucketDirection * dt * 60; // Adjust for 60 FPS
	if (bucket.x >= 2048 - bucket.width / 2) {
		bucketDirection = -1; // Change direction to left
	} else if (bucket.x <= bucket.width / 2) {
		bucketDirection = 1; // Change direction to right
	}
	log("moveBucketHorizontally: x=" + bucket.x, "moveDistance=" + moveDistance, "dt=" + dt);
	bucket.x += moveDistance;
}
function checkBlockAlignmentAndUpdate(sandBlock) {
	if (Math.abs(sandBlock.x - previousBlockX) < sandBlockHalfWidth) {
		LK.getSound('dropped').play();
		// Check for perfect alignment
		level += 1;
		score += 1; // Bonus points for perfect alignment
		LK.setScore(score); // Store the score in LK score
		if (level > 0 && level % 3 === 0) {
			bucketMoveStep += 4; // Increase bucket speed by 2 units
		}
	} else {
		LK.getSound('missed').play();
		lives--;
		livesIcons[lives].destroy();
		livesIcons.pop();
		if (lives <= 0) {
			var checkBucketUpCompletionForScore = function checkBucketUpCompletionForScore() {
				if (!isBucketMovingUp) {
					cleanPlayingState();
					initScoreState();
				} else {
					LK.setTimeout(checkBucketUpCompletionForScore, 1000 / 60); // Check again in the next frame
				}
			};
			checkBucketUpCompletionForScore();
			return;
		}
	}
	sandBlock.falling = false; // Reset the falling flag
	sandBlockDropped = false; // Reset the flag after handling sand block reaching the base
	game.addChild(bucket); // Ensure bucket is above sand blocks
}
function initializeBackgrounds() {
	var mainBgY = 1566;
	var mainBgHeight = 2732;
	//var bgHeight = 1152;
	//var bgHalfHeight = 576;
	backgroundImage = LK.getAsset('backgroundImage', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: mainBgY
	});
	game.addChild(backgroundImage);
	background2 = LK.getAsset('background2', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2
	});
	background2.y = backgroundImage.y - mainBgHeight / 2 - bgHalfHeight;
	game.addChild(background2);
	background3 = LK.getAsset('background3', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2
	});
	background3.y = background2.y - bgHeight;
	background4 = LK.getAsset('background2', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2
	});
	background4.y = background3.y - bgHeight;
	game.addChild(background4);
	background5 = LK.getAsset('background3', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2
	});
	background5.y = background4.y - bgHeight;
	;
	game.addChild(background5);
	game.addChild(background3);
}
function loopBgMusic() {
	if (bgMusic && Date.now() - bgMusic.lastPlayTime > 10000) {
		bgMusic.lastPlayTime = Date.now();
		bgMusic.play();
	}
}
/****************************************************************************************** */ 
/************************************* GAME STATES **************************************** */
/****************************************************************************************** */ 
function gameInitialize() {
	log("Game initialize...");
	initializeBackgrounds();
	boat = new Boat();
	boat.x = boat.width;
	boat.y = 1090;
	boat.visible = true;
	game.addChild(boat);
	sandcastle = new Sandcastle();
	sandcastle.x = 2048 / 2;
	sandcastle.y = -sandcastleHeight; // Hide the sandcastle above the screen initially
	game.addChild(sandcastle);
	picketLeft = LK.getAsset('picket', {
		anchorX: 0.5,
		anchorY: 1,
		x: 30,
		y: 2140
	});
	game.addChild(picketLeft);
	picketRight = LK.getAsset('picket', {
		anchorX: 0.5,
		anchorY: 1,
		scaleX: -1,
		x: 2018,
		y: 2140
	});
	game.addChild(picketRight);
	banner = LK.getAsset('banner', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 1024,
		y: 300
	});
	game.addChild(banner);
	game.addChild(sandcastle);
	level = 0;
	score = 0;
	LK.setScore(score); // Initialize LK score to zero at game start
	bgMusic = LK.getSound('music');
	if (bgMusic && bgMusic.isPlaying) {
		bgMusic.stop();
	}
	bgMusic.lastPlayTime = 0;
	startButton = LK.getAsset('startButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 2048 / 2,
		y: 1420 // Center of the screen
	});
	startButton.visible = false; // Initially hidden
	game.addChild(startButton);
	beachToys = new BeachToys();
	beachToys.x = 2048 / 2;
	beachToys.y = 2922;
	game.addChild(beachToys);
	// Initialize clouds at the beginning but keep them invisible
	cloud1 = new Cloud(1);
	cloud1.x = -cloud1.width;
	cloud1.y = -cloud1.height;
	cloud1.visible = false;
	game.addChild(cloud1);
	cloud2 = new Cloud(2);
	cloud2.x = -cloud2.width;
	cloud2.y = -cloud2.height;
	cloud2.visible = false;
	game.addChild(cloud2);
	flyingObject1 = new FlyingObject(1);
	flyingObject1.x = -Math.random() * 512;
	flyingObject1.y = flyingObject1.height + 256 * Math.random();
	flyingObject1.visible = false;
	flyingObject1.passed = true;
	game.addChild(flyingObject1);
	flyingObject2 = new FlyingObject(2);
	flyingObject2.x = -Math.random() * 512;
	flyingObject2.y = flyingObject2.height + 256 * Math.random();
	flyingObject2.visible = false;
	flyingObject2.passed = true;
	game.addChild(flyingObject2);
	flyingObject3 = new FlyingObject(3);
	flyingObject3.x = -Math.random() * 512;
	flyingObject3.y = flyingObject3.height + 256 * Math.random();
	flyingObject3.visible = false;
	flyingObject3.passed = true;
	game.addChild(flyingObject3);
	flyingObject4 = new FlyingObject(4);
	flyingObject4.x = -Math.random() * 512;
	flyingObject4.y = flyingObject4.height + 256 * Math.random();
	flyingObject4.visible = false;
	flyingObject4.passed = true;
	game.addChild(flyingObject4);
	initMenuState();
	if (isDebug) {
		debugMarker = LK.getAsset('debugMarker', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: 1300,
			y: 160
		});
		game.addChild(debugMarker);
		debugText = new Text2('Debug Info', {
			size: 50,
			fill: "#ffffff"
		});
		debugText.anchor.set(0.5, 1); // Anchor to the bottom-right
		LK.gui.bottom.addChild(debugText);
	}
}
// GAME MENU
function initMenuState() {
	log("initMenuState...");
	gameState = GAME_STATE.MENU;
}
function handleMenuLoop() {
	// Menu animations here
}
function cleanMenuState() {
	log("cleanMenuState...");
}
// NEW ROUND
function initNewRoundState() {
	log("initNewRoundState...");
	gameState = GAME_STATE.NEW_ROUND;
	// Fade in the start button
	startButton.visible = true;
	startButton.alpha = 0;
	var fadeInStep = 0.05;
	function fadeInStartButton() {
		if (startButton.alpha < 1) {
			startButton.alpha += fadeInStep;
			LK.setTimeout(fadeInStartButton, 1000 / 60); // Call fadeInStartButton every 1/60th of a second
		}
	}
	fadeInStartButton();
}
function handleNewRoundLoop() {
	// New Round animations here
	loopBgMusic();
}
function cleanNewRoundState() {
	if (isCleaningNewRound) {
		return;
	} // Prevent multiple calls
	isCleaningNewRound = true;
	log("cleanNewRoundState...");
	// Animate the start button removal
	var fadeOutStep = 0.05;
	function fadeOutStartButton() {
		log("fadeOutStartButton...", startButton.alpha, "step=" + fadeOutStep);
		if (startButton.alpha > 0 && Date.now() - fadeOutStartButtonStartTime < 1000) {
			startButton.alpha -= fadeOutStep;
			LK.setTimeout(fadeOutStartButton, 1000 / 60); // Call fadeOutStartButton every 1/60th of a second
		} else {
			log("fadeOutStartButton End");
			startButton.alpha = 0;
			var fadeOutBeachToys = function fadeOutBeachToys() {
				log("fadeOutBeachToys...");
				if (beachToys.alpha > 0) {
					beachToys.alpha -= fadeOutStep;
					LK.setTimeout(fadeOutBeachToys, 1000 / 60);
				} else {
					log("fadeOutBeachToys End");
					beachToys.visible = false;
					beachToys.alpha = 1; // Reset alpha for future use
					var animateSandcastleFall = function animateSandcastleFall() {
						log("animateSandcastleFall...");
						if (sandcastle.y < sandcastleBaseY) {
							sandcastle.velocity += gravity; // Increase velocity due to gravity
							sandcastle.y += sandcastle.velocity; // Update position based on velocity
							LK.setTimeout(animateSandcastleFall, 1000 / 60); // Call animateSandcastleFall every 1/60th of a second
						} else {
							log("animateSandcastleFall End");
							sandcastle.y = sandcastleBaseY; // Ensure it stops exactly at the base
							LK.getSound('dropped').play(); // Play drop sound when it reaches its position
							initPlayingState();
							isCleaningNewRound = false; // Reset the flag after completion
						}
					};
					startButton.visible = false;
					startButton.alpha = 1; // Reset alpha for future use
					sandcastle.velocity = 0; // Initial velocity for natural falling speed increase
					animateSandcastleFall();
				}
			};
			fadeOutBeachToys();
		}
	}
	fadeOutStartButtonStartTime = Date.now(); // Prevent Bug alpha stucked on tap
	fadeOutStartButton();
}
// PLAYING
function initPlayingState() {
	log("initPlayingState...");
	gameState = GAME_STATE.PLAYING;
	isPlaying = true;
	for (var i = 0; i < lives; i++) {
		var lifeIcon = LK.getAsset('bucketIcon', {
			anchorX: 0.5,
			anchorY: 0.5,
			x: 2048 - 100,
			y: 1166 + i * 130
		});
		livesIcons.push(lifeIcon);
		game.addChild(lifeIcon);
	}
	bucket = new Bucket();
	bucket.x = 2048 / 2;
	bucket.y = -bucket.height;
	game.addChild(bucket); // Ensure bucket is above sand blocks
	moveBucketDown();
}
function handlePlayingLoop() {
	loopBgMusic();
	if (isPlaying && currentSandBlock) {
		updateSandBlockPosition(currentSandBlock);
		//game.addChild(bucket); // Ensure bucket is above sand blocks
	}
	if (level >= 4) {
		for (var i = 0; i < sandBlocks.length; i++) {
			var sandBlock = sandBlocks[i];
			sandBlock.x += Math.sin(LK.ticks / 20) * sandBlockMoveStep; // Move sand blocks back and forth
		}
	}
	if (bucket && bucket.scoreTxt) {
		if (score === 0) {
			bucket.scoreTxt.visible = false;
		} else {
			bucket.scoreTxt.visible = true;
			bucket.scoreTxt.setText(score);
		}
	}
	if (isBucketMovingHorizontally) {
		moveBucketHorizontally(); // Ensure horizontal movement is restored
	}
	if (level >= 6 && cloud1 && cloud2 && !cloud1.visible) {
		cloud1.visible = true;
		cloud2.visible = true;
	}
	if (level && flyingObject1 && level % 4 == 0 && level < 20 && !flyingObject1.visible && flyingObject1.passed) {
		flyingObject1.visible = true;
		flyingObject1.passed = false;
	}
	if (level && flyingObject2 && level % 15 == 0 && level < 60 && !flyingObject2.visible && flyingObject2.passed) {
		flyingObject2.visible = true;
		flyingObject2.passed = false;
	}
	if (level && flyingObject3 && level % 10 == 0 && level < 40 && !flyingObject3.visible && flyingObject3.passed) {
		flyingObject3.visible = true;
		flyingObject3.passed = false;
	}
	if (level && flyingObject4 && level % 21 == 0 && !flyingObject4.visible && flyingObject4.passed) {
		flyingObject4.visible = true;
		flyingObject4.passed = false;
	}
	if (isDebug) {
		//debugText.setText("X: " + bucket.x + " Y: " + bucket.y);
		debugText.setText("Delta: " + globalDelta);
	}
}
function cleanPlayingState() {
	log("cleanPlayingState...");
	isPlaying = false;
	// TODO Remove elements
}
// SCORE
function initScoreState() {
	log("initScoreState...");
	gameState = GAME_STATE.SCORE;
	// Play camera sound
	LK.getSound('camera').play();
	// Prepare final animation
	// Add a 1-second white screen flash
	LK.effects.flashScreen(0xffffff, 2000);
	LK.setTimeout(setupFinalPhoto, 1000);
	confetti = new Confetti();
	confetti.visible = false;
	game.addChild(confetti);
}
function setupFinalPhoto() {
	// Set the background size to 2048x2732
	backgroundImage.width = 2048;
	backgroundImage.height = 2732;
	// Set the background position to the center of the screen
	backgroundImage.x = 2048 / 2;
	backgroundImage.y = 2732 / 2;
	background2.visible = false;
	background3.visible = false;
	background4.visible = false;
	background5.visible = false;
	cloud1.visible = false;
	cloud2.visible = false;
	var finalScoreTxt = new Text2(score.toString(), {
		size: 150,
		fill: "#FFFFFF",
		weight: 1000,
		dropShadow: true
	});
	finalScoreTxt.anchor.set(0.5, 0.2);
	LK.gui.top.addChild(finalScoreTxt);
	// Scale the sandcastle and the sandblocks down to fit in the screen
	var ratio = 1 / Math.ceil(sandBlocks.length / 3);
	sandcastle.width *= ratio;
	sandcastle.height *= ratio;
	sandcastle.x = 2048 / 2;
	sandcastle.y = sandcastleBaseY;
	sandcastle.shadow.visible = true;
	if (ratio <= 0.5) {
		beachToys = new BeachToys();
		beachToys.width *= ratio;
		beachToys.height *= ratio;
		beachToys.x = 1724;
		beachToys.y = sandcastleBaseY + 300;
		game.addChild(beachToys);
		var sandcastle2 = new Sandcastle();
		sandcastle2.x = 312;
		sandcastle2.y = sandcastleBaseY - 250; // Hide the sandcastle above the screen initially
		sandcastle2.width *= 0.8;
		sandcastle2.height *= 0.8;
		sandcastle2.width *= ratio;
		sandcastle2.height *= ratio;
		game.addChild(sandcastle2);
		sandcastle2.shadow.visible = true;
		beachToys2 = new BeachToys(2);
		beachToys2.width *= ratio;
		beachToys2.height *= ratio;
		beachToys2.shadow.visible = false;
		beachToys2.x = sandcastle2.x; // sandcastle2.x - sandcastle2.width / 2 - beachToys2.width / 2;
		beachToys2.y = sandcastle2.y + sandcastle2.height / 2 + 300 * ratio; //sandcastleBaseY + 350;
		game.addChild(beachToys2);
	}
	banner.width *= ratio;
	banner.height *= ratio;
	banner.x = 2048 / 2;
	banner.y = 2140 - picketLeft.height * ratio;
	picketLeft.width *= ratio;
	picketLeft.height *= ratio;
	picketLeft.x = 1024 - (1024 - 30) * ratio;
	picketLeft.y = 2140;
	picketRight.width *= ratio;
	picketRight.height *= ratio;
	picketRight.x = 1024 + (1024 - 30) * ratio;
	picketRight.y = 2140;
	var baseY = sandcastle.y - sandcastle.height / 2 - sandBlockSize * ratio;
	log("baseY ", baseY);
	for (var i = 0; i < sandBlocks.length; i++) {
		sandBlocks[i].width *= ratio;
		sandBlocks[i].height *= ratio;
		sandBlocks[i].x = 1024 - (1024 - sandBlocks[i].x) * ratio;
		sandBlocks[i].y = baseY - i * sandBlockSize * ratio;
		sandBlocks[i].visible = true;
		//log("block #", i, " h=" + sandBlockSize * ratio, " / y = ", sandBlocks[i].y);
	}
	// Show confetti
	confetti.visible = true;
	boat.y = 1000;
	boat.width *= ratio;
	boat.height *= ratio;
	boat.reverse();
}
function handleScoreLoop() {
	// Score display logic here
	loopBgMusic();
}
function cleanScoreState() {
	log("cleanScoreState...");
	LK.showGameOver();
}
/***********************************************************************************/ 
/******************************** MAIN GAME LOOP ***********************************/
/***********************************************************************************/ 
game.update = function () {
	switch (gameState) {
		case GAME_STATE.MENU:
			handleMenuLoop();
			break;
		case GAME_STATE.NEW_ROUND:
			handleNewRoundLoop();
			break;
		case GAME_STATE.PLAYING:
			handlePlayingLoop();
			break;
		case GAME_STATE.SCORE:
			handleScoreLoop();
			break;
	}
};
gameInitialize(); // Initialize the game
/********************************************************************************/
/**************************** GAME DESCRIPTION *********************************/
/******************************************************************************/
/* 
**Game Title**: **Sand Tower**
**Description**: Build towering sandcastles, perfect your alignment, and climb to the top! Sand Tower awaits! 🏖️🏰
**Objective**:
	- Players aim to construct the tallest sandcastle tower.
	- Perfect alignment of sand blocks is crucial for stability and bonus points.
**Visuals**:
	- The game features a sandy beach backdrop.
	- A basic sandcastle stands in the center, serving as the base.
	- The central tower is the focal point.
**Gameplay Mechanics**:
	- **Beach Bucket Mechanism**:
		- Players use an upside-down beach bucket.
		- When the player taps, the bucket tips over, releasing sand.
	- **Sand Block Placement**:
		- Sand falls vertically from the bucket onto the base.
		- The player must time their taps to stack the sand blocks.
		- Perfect alignment grants bonus points.
	- **Lives System**:
		- The player starts with 3 lives (represented by small bucket icons).
		- Each time a sand block isn't centered enough and falls, 1 life is lost.
	- **Scoring**:
		- Points increase with tower height.
		- Bonus points for precise alignment.
	- **Game Over**:
		- The game ends if the player loses all their lives (buckets).
**Audio**:
	- Gentle beach sounds (waves, distant chatter).
	- Encouraging music during gameplay.
*/ 
:quality(85)/https://cdn.frvr.ai/66710e708b857462b72d999a.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66716f398b857462b72d9a39.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6671f359dd6f02985af5acfd.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6672571fdd6f02985af5ad2a.png%3F3) 
 Front close view of a calm sea from the beach. nothing on the beach just flat sand. no sun... photorealistic
:quality(85)/https://cdn.frvr.ai/66731d8ddd6f02985af5aeff.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66764e3edd6f02985af5b1e5.png%3F3) 
 Start button. Beach themed
:quality(85)/https://cdn.frvr.ai/6677190edd6f02985af5b280.png%3F3) 
 face view of a red beach bucket with a blue handle.. photo
:quality(85)/https://cdn.frvr.ai/6677fa432fe7ff4a7658009a.png%3F3) 
 beach toys. photorealistic
:quality(85)/https://cdn.frvr.ai/6677fb742fe7ff4a765800a4.png%3F3) 
 beach construction toys. red bucket with blue handle.. photorealistic
:quality(85)/https://cdn.frvr.ai/667800742fe7ff4a765800de.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6678049a2fe7ff4a76580108.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/667860892fe7ff4a765801ff.png%3F3) 
 an horizontal cloud. photorealistic
:quality(85)/https://cdn.frvr.ai/667877582fe7ff4a765802a9.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/667877ee2fe7ff4a765802b5.png%3F3) 
 an air ballon. photorealistic
:quality(85)/https://cdn.frvr.ai/66787bbc2fe7ff4a765802c8.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6678fe9a2fe7ff4a76580433.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6679dcc3dd6f02985af5b64d.png%3F3) 
 simple rectangular white ribon.
:quality(85)/https://cdn.frvr.ai/667e7545dd6f02985af5bb3c.png%3F3) 
 a soaring gull. lateral view
:quality(85)/https://cdn.frvr.ai/667ea233dd6f02985af5bb9c.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/667eaa88dd6f02985af5bc40.png%3F3)