Code edit (6 edits merged)
Please save this source code
User prompt
ok, but make sandcastle Fall more natural (gravity), and play drop sound when it reached its position
User prompt
hide the sandcastle at the begining, then after Start button disapears, animate it fall from the top to sandcastleBaseY
Code edit (1 edits merged)
Please save this source code
User prompt
play missed sound when missed
User prompt
play dropped sound when block is well dropped
User prompt
in updateSandBlockPosition, in the case of (sandBlock.y >= centralPointY) and (Math.abs(sandBlock.x - previousBlockX) > sandBlockHalfWidth) and (sandBlock.y < 2732 + sandBlockSize) , check for colisions with sandblocks to simulate physics, don't "stopping the falling block" but update its x and rotation to simulate a physical colision of the falling sand block with fixed sand blocks. use serious physics calculations to simulate a natural fall of the block with the obstacle (previous sandblock). Given that sandblocks aren't balls, they shouldn't bounce but keep, falling, but their move is influenced by the collision. updateSandBlockPosition is called in the update loop, so beware not to treat 1 intersection/collision multiple times. the sand block should not return to the top of the screens and fall again indefinetly. use trajectory calculation.
User prompt
X and rotation of the fall looks ok, but y not : the sand block keeps returning to the top of the screens and falling again indefinetly
User prompt
in updateSandBlockPosition, in the case of (sandBlock.y >= centralPointY) and (Math.abs(sandBlock.x - previousBlockX) > sandBlockHalfWidth) and (sandBlock.y < 2732 + sandBlockSize) , check for colisions with sandblocks to simulate physics, don't "stopping the falling block" but update its x and rotation to simulate a physical colision of the falling sand block with fixed sand blocks. use serious physics calculations to simulate a natural fall of the block with the obstacle (previous sandblock). Given that sandblocks aren't balls, they shouldn't bounce but keep, falling, but their move is influenced by the collision. updateSandBlockPosition is called in the update loop, so beware not to treat 1 intersection/collision multiple times.
User prompt
in updateSandBlockPosition, in the case of (sandBlock.y >= centralPointY) and (Math.abs(sandBlock.x - previousBlockX) > sandBlockHalfWidth) and (sandBlock.y < 2732 + sandBlockSize) , check for colisions with sandblocks to simulate physics, don't "stopping the falling block" but update its x and rotation to simulate a physical colision of the falling sand block with fixed sand blocks. use serious physics calculations to simulate a natural fall of the block with the obstacle (previous sandblock). Given that sandblocks aren't balls, they shouldn't bounce but keep, falling, but their move is influenced by the collision
User prompt
when "// Continue falling" use advanced physics to sumulate the fall and collision
User prompt
it's better but sandblocs aren't balls, it should not bouce
User prompt
No, ``` sandBlock.y = otherBlock.y - sandBlock.height; sandBlock.x += (Math.random() - 0.5) * 20; // Random small x displacement sandBlock.rotation = (Math.random() - 0.5) * 0.1; // Random small rotation ``` Is wrong, please make serious physics calculations to simulate a natural fall of the block with the obstacle (previous sandblock)
User prompt
don't "stopping the falling block" but update its x and rotation to simulate a physical colision of the falling sand block with fixed sand blocks
User prompt
in updateSandBlockPosition, in the cas of (sandBlock.y >= centralPointY) and (Math.abs(sandBlock.x - previousBlockX) > sandBlockHalfWidth) and (sandBlock.y < 2732 + sandBlockSize) , check for colosions with sandblocks to simulate physics
User prompt
log the target scale (with log())
User prompt
calculate the targetScale so that the entire sandcastle and the tower of sand blocks fits in the screnn
User prompt
create a "zoom out" animation in score state so that the entire sandcastle and the tower of sand blocks is visible
User prompt
only move the bucket if isPlaying
User prompt
add a global isPlaying variable
Code edit (1 edits merged)
Please save this source code
User prompt
only add the sandBlock to the sandBlocks array if it has not fallen
Code edit (1 edits merged)
Please save this source code
User prompt
in cleanNewRoundState, animate the start button removal
Code edit (13 edits merged)
Please save this source code
/**** * Classes ****/ var SandBlock = Container.expand(function () { var self = Container.call(this); var sandBlockGraphics = self.attachAsset('sandBlock', { anchorX: 0.5, anchorY: 0 }); self.velocity = 0; // Initial velocity for natural falling speed increase self.update = function () { // SandBlock specific update logic }; }); /***********************************************************************************/ /********************************** SANDCASTLE CLASS ************************************/ /***********************************************************************************/ var Sandcastle = Container.expand(function () { var self = Container.call(this); var sandcastleGraphics = self.attachAsset('sandcastle', { anchorX: 0.5, anchorY: 0.5 }); 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 ********************************** */ /****************************************************************************************** */ var GAME_STATE = { INIT: 'INIT', MENU: 'MENU', NEW_ROUND: 'NEW_ROUND', PLAYING: 'PLAYING', SCORE: 'SCORE' }; var gameState = GAME_STATE.INIT; var score = 0; var scoreTxt; var isDebug = true; var debugText; var debugMarker; var backgroundImage; var bucket; var banner; var picketLeft; var picketRight; var sandBlocks = []; var lives = 1; 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 previousBlockX = 1024; var sandBlockWidth = 390; var sandBlockHalfWidth = 195; var sandBlockSize = 460; var centralPointY = 1380 - sandBlockSize; var bgHeight = 1152; var bgHalfHeight = 576; var gravity = 2; // Gravity effect for sand block falling var isBucketMovingHorizontally = false; // Flag to track if the bucket is moving horizontally 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 /****************************************************************************************** */ /*********************************** UTILITY FUNCTIONS ************************************ */ /****************************************************************************************** */ function moveCamera() { var targetY = backgroundImage.y + sandBlockSize; var moveStep = sandBlockSize / 60; // Move over 1 second (60 frames) function progressiveMove() { if (backgroundImage.y < targetY) { 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 (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 moveBucketDown(); // Progressively move the bucket down when the camera reaches the target game.addChild(bucket); // Ensure bucket is above sand blocks } 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 gameMenuDown(x, y, obj) { log("gameMenuDown..."); cleanMenuState(); initNewRoundState(); } function gameNewRoundDown(x, y, obj) { log("gameNewRoundDown..."); cleanNewRoundState(); } function gamePlayingDown(x, y, obj) { log("gamePlayingDown..."); if (!isPlaying || sandBlockDropped || isCameraMoving || !bucketReady) { return; // Prevent taps during camera movement } createNewSandBlock(); // Move the bucket vertically to hide over the screen top moveBucketUp(); } function gameScoreDown(x, y, obj) { log("gameScoreDown..."); cleanScoreState(); } /****************************************************************************************** */ /************************************* GAME FUNCTIONS ************************************* */ /****************************************************************************************** */ function moveBucketUp() { var bucketMoveStep = 15; // Adjust the step size as needed if (isPlaying && bucket.y > -bucket.height) { bucket.y -= bucketMoveStep; game.addChild(bucket); // Ensure bucket is above sand blocks LK.setTimeout(moveBucketUp, 1000 / 240); // Call moveBucketUp every 1/60th of a second } } function moveBucketDown() { var bucketMoveStep = 15; // Adjust the step size as needed if (isPlaying && bucket.y < 0) { 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 { bucketReady = true; // Set the flag to true when the bucket reaches y=0 } } function createNewSandBlock() { currentSandBlock = new SandBlock(); var sandBlock = currentSandBlock; sandBlock.x = bucket.x; sandBlock.y = bucket.y - bucket.height / 2; 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 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: if (isPlaying) { gamePlayingDown(x, y, obj); } break; case GAME_STATE.SCORE: gameScoreDown(x, y, obj); break; } } function updateSandBlockPosition(sandBlock) { if (sandBlock.y < centralPointY) { sandBlock.velocity += gravity; // Increase velocity due to gravity sandBlock.y += sandBlock.velocity; // Update position based on velocity } else { if (Math.abs(sandBlock.x - previousBlockX) > sandBlockHalfWidth) { // Continue falling if (sandBlock.y < 2732 + sandBlockSize) { sandBlock.velocity += gravity; // Increase velocity due to gravity sandBlock.y += sandBlock.velocity; // Update position based on velocity } else { checkBlockAlignmentAndUpdate(sandBlock); sandBlock.fallen = true; sandBlock.destroy(); currentSandBlock = null; sandBlockDropped = false; moveBucketDown(); // Progressively move the bucket down when the camera reaches the target game.addChild(bucket); // Ensure bucket is above sand blocks } } else { // Stop sandBlocks.push(currentSandBlock); 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() { var bucketMoveStep = 10; // Adjust the step size as needed var direction = 1; // 1 for right, -1 for left function progressiveMove() { if (bucket.x >= 2048 - bucket.width / 2) { direction = -1; // Change direction to left } else if (bucket.x <= bucket.width / 2) { direction = 1; // Change direction to right } bucket.x += bucketMoveStep * direction; if (isPlaying && isBucketMovingHorizontally) { LK.setTimeout(progressiveMove, 1000 / 60); // Call progressiveMove every 1/60th of a second } } isBucketMovingHorizontally = true; progressiveMove(); } function checkBlockAlignmentAndUpdate(sandBlock) { if (Math.abs(sandBlock.x - 2048 / 2) < sandBlockHalfWidth) { // Check for perfect alignment score += 10; // Bonus points for perfect alignment } else { lives--; livesIcons[lives].destroy(); livesIcons.pop(); if (lives <= 0) { cleanPlayingState(); initScoreState(); return; } } sandBlockDropped = false; // Reset the flag after handling sand block reaching the base if (!isBucketMovingHorizontally) { moveBucketHorizontally(); // Start moving the bucket horizontally after the first drop } 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); } /****************************************************************************************** */ /************************************* GAME STATES **************************************** */ /****************************************************************************************** */ function gameInitialize() { log("Game initialize..."); initializeBackgrounds(); sandcastle = new Sandcastle(); sandcastle.x = 2048 / 2; sandcastle.y = 2212; //2732 - 1640 / 2 + 300; 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: 400 }); game.addChild(banner); game.addChild(sandcastle); score = 0; scoreTxt = new Text2('0', { size: 150, fill: "#ffffff" }); scoreTxt.anchor.set(0.5, 0); scoreTxt.x = 2048 / 2; scoreTxt.y = 50; LK.gui.top.addChild(scoreTxt); if (isDebug) { debugMarker = LK.getAsset('debugMarker', { anchorX: 0.5, anchorY: 0.5, x: 825 + 390, y: 1526 }); 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); } startButton = LK.getAsset('startButton', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1366 // Center of the screen }); startButton.visible = false; // Initially hidden game.addChild(startButton); initMenuState(); } // 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; startButton.visible = true; // Make start button visible // Round preparation logic here. } function handleNewRoundLoop() { // New Round animations here } function cleanNewRoundState() { log("cleanNewRoundState..."); // Animate the start button removal var fadeOutStep = 0.05; function fadeOutStartButton() { if (startButton.alpha > 0) { startButton.alpha -= fadeOutStep; LK.setTimeout(fadeOutStartButton, 1000 / 60); // Call fadeOutStartButton every 1/60th of a second } else { startButton.visible = false; startButton.alpha = 1; // Reset alpha for future use initPlayingState(); } } 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); } game.addChild(bucket); // Ensure bucket is above sand blocks bucket = LK.getAsset('bucket', { anchorX: 0.5, anchorY: 0.0, x: 2048 / 2, y: 0 }); bucket.y = -bucket.height; game.addChild(bucket); moveBucketDown(); } function handlePlayingLoop() { if (isPlaying && currentSandBlock) { updateSandBlockPosition(currentSandBlock); //game.addChild(bucket); // Ensure bucket is above sand blocks } scoreTxt.setText(score); if (isDebug) { debugText.setText("X: " + bucket.x + " Y: " + bucket.y); } } function cleanPlayingState() { log("cleanPlayingState..."); isPlaying = false; // TODO Remove elements } // SCORE function initScoreState() { log("initScoreState..."); gameState = GAME_STATE.SCORE; // Prepare final animation var zoomOutStep = 0.05; var targetScale = Math.min(2048 / (sandcastle.width + sandBlockWidth), 2732 / (sandcastle.height + sandBlocks.length * sandBlockSize)); // Calculate target scale log("Target Scale: ", targetScale); function zoomOut() { if (game.scale.x > targetScale) { game.scale.x -= zoomOutStep; game.scale.y -= zoomOutStep; game.x += 2048 * zoomOutStep / 2; // Adjust x position to keep centered game.y += 2732 * zoomOutStep / 2; // Adjust y position to keep centered LK.setTimeout(zoomOut, 1000 / 60); // Call zoomOut every 1/60th of a second } } zoomOut(); } function handleScoreLoop() { // Score display logic here } function cleanScoreState() { log("cleanScoreState..."); // Reset game scale and position game.scale.x = 1; game.scale.y = 1; game.x = 0; game.y = 0; 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. */
===================================================================
--- original.js
+++ change.js
@@ -475,8 +475,9 @@
gameState = GAME_STATE.SCORE;
// Prepare final animation
var zoomOutStep = 0.05;
var targetScale = Math.min(2048 / (sandcastle.width + sandBlockWidth), 2732 / (sandcastle.height + sandBlocks.length * sandBlockSize)); // Calculate target scale
+ log("Target Scale: ", targetScale);
function zoomOut() {
if (game.scale.x > targetScale) {
game.scale.x -= zoomOutStep;
game.scale.y -= zoomOutStep;
Front close view of a calm sea from the beach. nothing on the beach just flat sand. no sun... photorealistic
Start button. Beach themed
face view of a red beach bucket with a blue handle.. photo
beach toys. photorealistic
beach construction toys. red bucket with blue handle.. photorealistic
an horizontal cloud. photorealistic
an air ballon. photorealistic
simple rectangular white ribon.
a soaring gull. lateral view