User prompt
Tint the roombas red
User prompt
Make the enemies red
User prompt
Migrate to the latest version of LK
User prompt
Please fix the bug: 'Uncaught ReferenceError: polygon is not defined' in or related to this line: 'polygon.graphics.beginFill(0xFF3300);' Line Number: 314
User prompt
Please fix the bug: 'Uncaught TypeError: LK.Shape is not a constructor' in or related to this line: 'var polygon = new LK.Shape();' Line Number: 311
User prompt
Draw a polygon when 5 points
User prompt
Give me access to the graphics API
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'width')' in or related to this line: 'var fieldOfView = LK.getAsset('gridBackground', {' Line Number: 279
User prompt
Add s field of view for the room as
User prompt
Ensure the flag asset is created on level load
User prompt
Add a flag to the hole tile on the top right corner
User prompt
Debug, the flag is not visible
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var flag = LK.getAsset('Flag', {' Line Number: 279
User prompt
Create a flag placing it on the side of the hole tile, always outside the grid
User prompt
Please fix the bug: 'Timeout.tick error: Cannot read properties of undefined (reading 'x')' in or related to this line: 'enemies[0].x = floorTiles[0].x;' Line Number: 859
User prompt
Please fix the bug: 'Timeout.tick error: Cannot read properties of undefined (reading 'x')' in or related to this line: 'enemies[0].x = floorTiles[0].x;' Line Number: 859
User prompt
Create the flag tile last on the creste tile function
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var holeTile = LK.getAsset('holeTile', {' Line Number: 872
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var holeTile = LK.getAsset('holeTile', {' Line Number: 868
User prompt
Create the flag tile last on the create tile function
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var holeTile = LK.getAsset('holeTile', {' Line Number: 865
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var holeTile = LK.getAsset('holeTile', {' Line Number: 859
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var holeTile = LK.getAsset('holeTile', {' Line Number: 806
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'flagTile.x = holeTile.x;' Line Number: 806
User prompt
Instead of placing the flag random, place it aways on top of the hole tile
/**** * Classes ****/ var Character = Container.expand(function () { var self = Container.call(this); // Character shadow attachment removed // Character shadow attachment removed var characterGraphics = self.attachAsset('character', { anchorX: 0.5, anchorY: 0.5 }); characterGraphics.scaleX = 1; characterGraphics.scaleY = 1; }); var Cheese = Container.expand(function () { var self = Container.call(this); // Cheese shadow attachment removed var cheeseGraphics = self.attachAsset('cheese', { anchorX: 0.5, anchorY: 0.5 }); self.lerpToPosition = function (startPos, endPos, duration, onComplete) { self.x = endPos.x; self.y = endPos.y; if (onComplete) { onComplete(); } }; }); var Enemy = Container.expand(function (type) { var self = Container.call(this); self.id = Math.random().toString(36).substr(2, 9); // Unique ID for each Roomba var shadowAssetId, enemyAssetId, shadowScale, enemySpeed; // Moved globalEnemySpeed initialization outside of Enemy class to fix 'ReferenceError' var level = 0; // Initialize level variable // Moved globalEnemySpeed initialization outside of Enemy class to fix 'ReferenceError' var defaultEnemySpeed = globalEnemySpeed; // Use global enemy speed for initial speed var EnemyTypes = { Roomba: { shadowAssetId: 'CircularShadow', enemyAssetId: 'Roomba', shadowScale: 3.2, enemySpeed: defaultEnemySpeed * (1.03 + level * 0.05) // Increase speed by 3% plus an additional 5% per level } }; var enemyStats = EnemyTypes[type]; if (!enemyStats) { console.error('Unknown enemy type:', type); return; } shadowAssetId = enemyStats.shadowAssetId; enemyAssetId = enemyStats.enemyAssetId; shadowScale = enemyStats.shadowScale; enemySpeed = enemyStats.enemySpeed; var shadowGraphics = self.attachAsset(shadowAssetId, { anchorX: 0.5, anchorY: 0.5, alpha: 0.5, scaleX: shadowScale, scaleY: shadowScale }); var enemyGraphics = self.attachAsset(enemyAssetId, { anchorX: 0.5, anchorY: 0.5 }); // Adjust shadow position relative to the enemy shadowGraphics.x = enemyGraphics.x; shadowGraphics.y = enemyGraphics.y + 40; // Slightly below the enemy for a realistic shadow effect // Set enemy speed self.speed = enemySpeed; // Enemy movement logic self.move = function () { // Enhanced enemy behavior with dynamic avoidance and pathfinding enemies.forEach(function (otherEnemy) { if (otherEnemy.id !== self.id) { var dx = self.x - otherEnemy.x; var dy = self.y - otherEnemy.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 250 && distance > 0) { var awayX = dx / distance; var awayY = dy / distance; // Adjust repulsion to be more dynamic based on distance var repulsionStrength = Math.max(1, 250 - distance) / 50; // Increase repulsion as enemies get closer self.x += awayX * self.speed * repulsionStrength; self.y += awayY * self.speed * repulsionStrength; // Force Roombas to change direction upon collision self.targetTile = floorTiles[Math.floor(Math.random() * floorTiles.length)]; } } }); // Pick a random floor tile as a new target to keep Roombas apart if (!self.targetTile || self.collisionCounter > 50 || Math.sqrt(Math.pow(self.x - self.targetTile.x, 2) + Math.pow(self.y - self.targetTile.y, 2)) < 15) { var randomIndex = Math.floor(Math.random() * floorTiles.length); self.targetTile = floorTiles[randomIndex]; self.collisionCounter = 0; // Reset collision counter after changing target } // Introduce a collision counter to track continuous collisions if (!self.collisionCounter) { self.collisionCounter = 0; } // Increase collision counter on collision if (self.colliding) { self.collisionCounter++; } else { self.collisionCounter = 0; // Reset counter if not colliding } // Change target tile if colliding for too long or reached current target if (!self.targetTile || self.collisionCounter > 30 || Math.sqrt(Math.pow(self.x - self.targetTile.x, 2) + Math.pow(self.y - self.targetTile.y, 2)) < 10) { self.targetTile = floorTiles[Math.floor(Math.random() * floorTiles.length)]; self.collisionCounter = 0; // Reset collision counter after changing target } // Reset colliding flag for the next tick self.colliding = false; var angleToTarget = Math.atan2(self.targetTile.y - self.y, self.targetTile.x - self.x); self.x += Math.cos(angleToTarget) * self.speed; self.y += Math.sin(angleToTarget) * self.speed; // Smoothly rotate the enemy towards the target angle var currentAngle = enemyGraphics.rotation; var targetAngle = angleToTarget; // Calculate the shortest direction to rotate var angleDifference = targetAngle - currentAngle; angleDifference += angleDifference > Math.PI ? -2 * Math.PI : angleDifference < -Math.PI ? 2 * Math.PI : 0; var rotationSpeed = 0.1; // Adjust rotation speed as needed enemyGraphics.rotation += angleDifference * rotationSpeed; }; }); var FlagTile = Container.expand(function () { var self = Container.call(this); var flagGraphics = self.attachAsset('Flag', { anchorX: 0.5, anchorY: 0.5 }); }); // OnScreenController class encapsulating A, B buttons and D-pad var OnScreenController = Container.expand(function () { var self = Container.call(this); // Add a background for the on screen controllers var yPosAdjustment = -180; var buttonYPosAdjustment = -273.2; var dpadButtonSize = 350; // Increased size for better visibility and interaction // Removed redundant tint application on A and B buttons LK.screen = { width: 2048, height: 2732 }; // Initialize screen dimensions var aButtonPosition = { x: LK.screen.width * 0.75, y: LK.screen.height * 0.85 + buttonYPosAdjustment + LK.screen.height * 0.055 }; var buttonSize = { width: 400, height: 400 }; var dPadSize = { width: 750, height: 750 }; this.aButton = self.attachAsset('aButton', { anchorX: 0.5, anchorY: 0.5, x: aButtonPosition.x, y: aButtonPosition.y, width: buttonSize.width, height: buttonSize.height }); // D-pad var dpadBase = self.attachAsset('dpadBase', { anchorX: 0.5, anchorY: 0.5, x: LK.screen.width * 0.24, y: LK.screen.height * 0.89 + yPosAdjustment - 10, width: dPadSize.width, height: dPadSize.height }); self.setChildIndex(dpadBase, self.children.length - 1); var dpadLeft = self.attachAsset('dpadButtonLeft', { anchorX: 0.5, anchorY: 0.5, x: dpadBase.x - 300, y: dpadBase.y, width: dpadButtonSize, height: dpadButtonSize, alpha: 0, // Tint arrow yellow orientation: 3 }); var moveInterval; function startMovingCharacter(xDir, yDir) { if (moveInterval) { LK.clearInterval(moveInterval); } isCharacterMoving = true; moveCharacter(xDir, yDir); moveInterval = LK.setInterval(function () { moveCharacter(xDir, yDir); }, 150); } dpadLeft.on('down', function () { startMovingCharacter(-1, 0); }); var dpadUp = self.attachAsset('dpadButtonUp', { anchorX: 0.5, anchorY: 0.5, x: dpadBase.x, y: dpadBase.y - 300, width: dpadButtonSize, height: dpadButtonSize, alpha: 0, orientation: 0 }); dpadUp.on('down', function () { startMovingCharacter(0, -1); }); var dpadRight = self.attachAsset('dpadButtonRight', { anchorX: 0.5, anchorY: 0.5, x: dpadBase.x + 300, y: dpadBase.y, width: dpadButtonSize, height: dpadButtonSize, alpha: 0, orientation: 1 }); dpadRight.on('down', function () { startMovingCharacter(1, 0); }); var dpadDown = self.attachAsset('dpadButtonDown', { anchorX: 0.5, anchorY: 0.5, x: dpadBase.x, y: dpadBase.y + 300, width: dpadButtonSize, height: dpadButtonSize, alpha: 0, orientation: 2 }); dpadDown.on('down', function () { startMovingCharacter(0, 1); }); function stopMovingCharacter() { isCharacterMoving = false; LK.clearInterval(moveInterval); } dpadLeft.on('up', stopMovingCharacter); dpadUp.on('up', stopMovingCharacter); dpadRight.on('up', stopMovingCharacter); dpadDown.on('up', stopMovingCharacter); }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xf9e076 // Fun yellow background }); /**** * Game Code ****/ // characterShadow asset initialization removed // Function to spawn cheeses at random floor tile positions function spawnCheeses() { // Clear existing cheeses before spawning new ones cheeses.forEach(function (cheese) { cheese.destroy(); }); cheeses = []; // Reset the cheeses array // Spawn new cheeses for (var i = 0; i < totalCheeses; i++) { cheeses.push(game.addChild(new Cheese())); } // Place cheeses on non-corner floor tiles that are far from the character var nonCornerFloorTiles = floorTiles.filter(function (tile) { return true; }); var farthestTiles = nonCornerFloorTiles.filter(function (tile) { // Ensure character is defined before calculating distance var distanceToCharacter = typeof character !== 'undefined' && character !== null ? Math.sqrt(Math.pow(tile.x - character.x, 2) + Math.pow(tile.y - character.y, 2)) : Infinity; return distanceToCharacter > LK.screen.width / 2; // Arbitrary distance threshold }); // Exclude tiles that are too close to the hole tile var safeDistanceTiles = nonCornerFloorTiles.filter(function (tile) { var distanceToHole = Math.sqrt(Math.pow(tile.x - holeTile.x, 2) + Math.pow(tile.y - holeTile.y, 2)); return distanceToHole > LK.screen.width / 4; // Arbitrary distance threshold to keep cheese away from the hole }); // Filter out tiles that are surrounded by obstacles horizontally and vertically // Move the declaration of 'targetTiles' before its first use var targetTiles = safeDistanceTiles.length > 0 ? safeDistanceTiles : farthestTiles; var validTilesForCheese = targetTiles.filter(function (tile) { var leftTile = getTileAtPosition(tile.x - tileWidth, tile.y); var rightTile = getTileAtPosition(tile.x + tileWidth, tile.y); var topTile = getTileAtPosition(tile.x, tile.y - tileHeight); var bottomTile = getTileAtPosition(tile.x, tile.y + tileHeight); // Check if the tile is surrounded by obstacles on all four sides return !(obstacleTiles.includes(leftTile) || obstacleTiles.includes(rightTile) || obstacleTiles.includes(topTile) || obstacleTiles.includes(bottomTile)); }); var targetTiles = validTilesForCheese.length > 0 ? validTilesForCheese : nonCornerFloorTiles; // Place each cheese on a unique random floor tile cheeses.forEach(function (cheese) { var uniqueTileIndex = Math.floor(Math.random() * targetTiles.length); var uniqueFloorTile = targetTiles.splice(uniqueTileIndex, 1)[0]; // Remove the selected tile from the pool to ensure uniqueness if (uniqueFloorTile) { cheese.x = uniqueFloorTile.x; cheese.y = uniqueFloorTile.y; } }); } // Method to check if all cheeses have been delivered function allCheesesDelivered() { // Destroy grid and tiles grid.forEach(function (tile) { if (tile) { tile.destroy(); } }); grid = []; // Clear the grid array floorTiles.forEach(function (tile) { tile.destroy(); }); floorTiles = []; // Clear the floorTiles array wallTiles.forEach(function (tile) { tile.destroy(); }); wallTiles = []; // Clear the wallTiles array obstacleTiles.forEach(function (tile) { tile.destroy(); }); obstacleTiles = []; // Clear the obstacleTiles array // Destroy character and cheese icon if (character) { if (cheeseIcon) { cheeseIcon.destroy(); } character.destroy(); character = null; } // Destroy enemies enemies.forEach(function (enemy) { enemy.destroy(); }); enemies = []; // Clear the enemies array globalEnemySpeed *= 1.1; // Increase global enemy speed by 10% on each level load console.log("building next level"); // Rebuild game elements createTiles(); // Rebuild the tiles for the level var nonCornerWallTiles = wallTiles.filter(function (tile) { var x = tile.x, y = tile.y; var isCornerTile = x === gridOffsetX && y === gridOffsetY || x === gridOffsetX + (gridSize - 1) * tileWidth && y === gridOffsetY || x === gridOffsetX && y === gridOffsetY + (gridSize - 1) * tileHeight || x === gridOffsetX + (gridSize - 1) * tileWidth && y === gridOffsetY + (gridSize - 1) * tileHeight; return !isCornerTile; }); var randomWallTile = nonCornerWallTiles[Math.floor(Math.random() * nonCornerWallTiles.length)]; holeTile = LK.getAsset('holeTile', { anchorX: 0.5, anchorY: 0.5, x: randomWallTile.x, y: randomWallTile.y }); game.addChild(holeTile); game.removeChild(randomWallTile); spawnCheeses(); // Spawn cheeses for the new level // Re-instantiate character for the new level with correct shadow and position character = game.addChild(new Character()); // Attach cheese icon to the new character if cheese is collected if (cheeseIcon && cheeseIcon.visible) { cheeseIcon = character.attachAsset('cheese', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8, x: 0, y: -character.height / 2 // Position closer to the character top }); } // Create a new cheese icon and disable it cheeseIcon = character.attachAsset('cheese', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8, x: 0, y: -character.height / 2, // Position closer to the character top visible: false // Disable cheese icon after creation }); // Attach cheese icon to the new character if cheese is collected // Ensure the cheese icon is visible on the new character instance character.x = holeTile.x; // Position character at the hole's location character.y = holeTile.y - 50; // Adjust Y position to not overlap with the hole enemies.forEach(function (enemy) { enemy.destroy(); }); // Destroy existing enemies enemies = []; // Clear enemies array enemies.push(game.addChild(new Enemy('Roomba'))); // Add first Roomba enemy enemies.push(game.addChild(new Enemy('Roomba'))); // Add second Roomba enemy // Position Roombas on opposite sides of the grid if (enemies[0]) { enemies[0].x = floorTiles[0].x; // Position the first Roomba on the left side enemies[0].y = floorTiles[0].y; } if (enemies[1]) { var lastTileIndex = floorTiles.length - 1; enemies[1].x = floorTiles[lastTileIndex].x; // Position the second Roomba on the right side enemies[1].y = floorTiles[lastTileIndex].y; } } // Ensure LK.screen dimensions are defined before using them var globalEnemySpeed = 3; // Define initial global enemy speed LK.screen = { width: 2048, height: 2732 }; // Initialize screen dimensions // Instantiate and center the game logo asset on the screen var gameLogo = LK.getAsset('stickerLogo', { anchorX: 0.5, anchorY: 0.5, x: LK.screen.width / 2 + 50, y: 1955 }); game.addChild(gameLogo); var dakaloText = new Text2('@Dakalo777', { size: 50, fill: "#FFA500", x: LK.screen.width - 20, // Adjust for space from the right edge y: LK.screen.height - 20 // Adjust for space from the bottom edge }); dakaloText.anchor.set(1, 1); // Anchor to bottom right LK.gui.bottomRight.addChild(dakaloText); // Function to check if a new obstacle tile fully surrounds any cheese // Removed redundant cheese tracking variables function doesTileSurroundCheese(obstacleTile, cheeses) { return cheeses.some(function (cheese) { // Calculate adjacent tiles to the cheese var adjacentTiles = [{ x: cheese.x - tileWidth, y: cheese.y }, { x: cheese.x + tileWidth, y: cheese.y }, { x: cheese.x, y: cheese.y - tileHeight }, { x: cheese.x, y: cheese.y + tileHeight }]; // Check if all adjacent tiles are either walls, obstacles, or the new obstacle tile return adjacentTiles.every(function (tile) { return wallTiles.some(function (wallTile) { return wallTile.x === tile.x && wallTile.y === tile.y; }) || grid.some(function (gridTile) { return gridTile && gridTile.x === tile.x && gridTile.y === tile.y && gridTile !== cheese && gridTile !== obstacleTile; }); }); }); } // Add sticker02 asset to the bottom of the screen next to sticker and rotate it 32 degrees var sticker02 = game.addChild(LK.getAsset('sticker02', { anchorX: 1.0, anchorY: 1.0, x: 2100, y: 2300, rotation: -0.558 })); // Add sticker asset to the bottom of the screen and rotate it 32 degrees var sticker = LK.getAsset('sticker', { anchorX: 0.5, anchorY: 0.5, x: 900, y: 2400, scaleX: 0.7, // Scale down by 0.7 scaleY: 0.7, // Scale down by 0.7 rotation: 0.10 }); game.addChild(sticker); // Update play time display every second LK.on('tick', function () { var minutes = Math.floor(playTime / 60); var seconds = playTime % 60; playTimeDisplay.setText((minutes < 10 ? '0' : '') + minutes + ':' + (seconds < 10 ? '0' : '') + seconds); }); // Create a timer to update play time every second var playTimeTimer = LK.setInterval(function () { playTime += 1; }, 1000); // Initialize play time tracking var playTime = 0; // Initialize EventManager for global event handling var EventManager = { events: {}, subscribe: function subscribe(eventType, listener) { if (!this.events[eventType]) { this.events[eventType] = []; } this.events[eventType].push(listener); }, unsubscribe: function unsubscribe(eventType, listener) { if (this.events[eventType]) { var index = this.events[eventType].indexOf(listener); if (index > -1) { this.events[eventType].splice(index, 1); } } }, publish: function publish(eventType, data) { if (this.events[eventType]) { this.events[eventType].forEach(function (listener) { listener(data); }); } } }; game.eventManager = EventManager; // Subscribe to 'gameStart' event to initialize character and game state game.eventManager.subscribe('gameStart', function () { isGameStarted = true; // Method to instantiate and return a new character function createCharacter() { return LK.getAsset('character', { anchorX: 0.5, anchorY: 0.5, x: holeTile.x, y: holeTile.y - 50, scaleX: 1, scaleY: 1 }); } character = createCharacter(); // Reset cheese score display to '0' to prevent UI text overlap on game reset cheeseScoreDisplay.setText('0'); }); // Reset UI elements correctly when playing again if (window.scoreBoardContainer) { window.scoreBoardContainer.children.forEach(function (child) { child.destroy(); // Destroy each child to ensure clean slate }); window.scoreBoardContainer.destroy(); // Ensure the container is properly destroyed window.scoreBoardContainer = null; } // Reinitialize the scoreboard container to prevent UI text overlap on game reset window.scoreBoardInitialized = false; // Initialize scoreboard container and elements once and update score dynamically if (!window.scoreBoardInitialized) { var updateCheeseScore = function updateCheeseScore(score) { cheeseScoreDisplay.setText(score.toString()); }; window.scoreBoardContainer = new Container(); var scoreBoardX = 0, scoreBoardY = 0; var cheeseIconForScore = window.scoreBoardContainer.attachAsset('cheese', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5, x: -500, y: 55 }); // Dynamically add one character lives icon per available life var availableLives = 3; // Assuming 3 lives to start with var livesIcons = []; for (var i = availableLives - 1; i >= 0; i--) { var lifeIcon = window.scoreBoardContainer.attachAsset('characterLivesIcon', { anchorX: 0, anchorY: 0, scaleX: 1.5, scaleY: 1.5, x: (availableLives - 1 - i) * 90 + 250, y: 0 }); livesIcons.unshift(lifeIcon); } // Cheese score display added to the scoreboard var cheeseScoreDisplay = new Text2('0', { size: 50, fill: "#ffffff", stroke: "#ffffff", strokeThickness: 4, font: "Roboto, bold", x: cheeseIconForScore.x + 60, // Adjust x position to place score text right side of the cheese icon y: cheeseIconForScore.y }); cheeseScoreDisplay.anchor.set(14.5, -.8); window.scoreBoardContainer.addChild(cheeseScoreDisplay); // Update cheese score display function window.updateCheeseScore = function (score) { updateCheeseScore(score); // Initiate bounce effect var originalScaleX = cheeseScoreDisplay.scaleX; var originalScaleY = cheeseScoreDisplay.scaleY; var scaleUpDuration = 150; // Duration to scale up var scaleDownDuration = 150; // Duration to scale down back to original size var scaleAmount = 1.2; // Amount to scale up // Scale up cheeseScoreDisplay.scaleX = originalScaleX * scaleAmount; cheeseScoreDisplay.scaleY = originalScaleY * scaleAmount; // Delay before scaling down LK.setTimeout(function () { // Scale down back to original size cheeseScoreDisplay.scaleX = originalScaleX; cheeseScoreDisplay.scaleY = originalScaleY; }, scaleUpDuration); }; // Character lives text asset creation and addition to scoreBoardContainer removed // Add play time display to the scoreboard // Initialize screen dimensions for playTimeDisplay positioning LK.screen = { width: 2048, height: 2732 }; var playTimeDisplay = new Text2('00:00', { size: 50, fill: "#E0E0E0", font: "Roboto, bold", x: -LK.screen.width / 2, y: 0 }); playTimeDisplay.anchor.set(-0.75, 0); // Center the text horizontally window.scoreBoardContainer.addChild(playTimeDisplay); window.scoreBoardContainer.x = 0; window.scoreBoardContainer.y = 55; LK.gui.top.addChild(window.scoreBoardContainer); window.scoreBoardInitialized = true; } var onScreenController = game.addChild(new OnScreenController()); // Refactored event listener for A button press to manage cheese collection and scoring more efficiently onScreenController.aButton.on('down', function () { if (isWithinProximity(character, holeTile, 75) && cheeseIcon && cheeseIcon.visible) { var createFlyingCheeseEffect = function createFlyingCheeseEffect(fromX, fromY) { var flyingCheese = game.addChild(LK.getAsset('cheese', { anchorX: 0.5, anchorY: 0.5, x: fromX, y: fromY, scaleX: 1.0, // Scale up by 100% scaleY: 1.0 // Scale up by 100% })); var leftTopCornerTile = floorTiles[0]; // Assuming the first tile in the array is the top left corner var scoreBoardPos = { x: leftTopCornerTile.x - tileHeight, y: leftTopCornerTile.y - tileHeight }; var cheeseFlyDuration = 750; // Duration in milliseconds var startTime = Date.now(); LK.on('tick', function () { var currentTime = Date.now(); var progress = (currentTime - startTime) / cheeseFlyDuration; if (progress < 1) { flyingCheese.x = fromX + (scoreBoardPos.x - fromX) * progress; flyingCheese.y = fromY + (scoreBoardPos.y - fromY) * progress; // Calculate the angle to rotate the flying cheese towards the scoreboard and add 180 degrees for rotation var angle = Math.atan2(scoreBoardPos.y - fromY, scoreBoardPos.x - fromX) + Math.PI; flyingCheese.rotation = angle; } else { game.removeChild(flyingCheese); window.updateCheeseScore(LK.getScore()); // Update displayed score } }); }; // Invoke createFlyingCheeseEffect with character's position when cheese is delivered console.log('Cheese delivered!'); cheeseIcon.visible = false; // Hide the cheese icon to indicate delivery // If it's the last cheese, increment score by 2, otherwise by 1 if (cheeses.length === 0) { LK.setScore(LK.getScore() + 2); allCheesesDelivered(); // Invoke allCheesesDelivered method after scoring for the last cheese } else { LK.setScore(LK.getScore() + 1); } // Create a visual cheese flying effect towards the scoreboard on cheese delivery createFlyingCheeseEffect(holeTile.x, holeTile.y); } else { if (!cheeseIcon || !cheeseIcon.visible) { cheeses.forEach(function (cheese, index) { if (isWithinProximity(character, cheese, 75)) { console.log('Cheese collected!'); game.removeChild(cheese); // Remove cheese from game cheeses.splice(index, 1); // Remove cheese from cheeses array // Display cheese icon above character to indicate cheese collection if (!cheeseIcon) { cheeseIcon = character.attachAsset('cheese', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, // Scale down by 50% scaleY: 0.8, // Scale down by 50% x: 0, y: -character.height / 2 // Position closer to the character top }); } else { cheeseIcon.visible = true; // Make the cheese icon visible if already exists } } }); } } }); // Helper function to check if two objects are within a certain distance function isWithinProximity(obj1, obj2, threshold) { if (!obj1 || !obj2) { return false; } return Math.abs(obj1.x - obj2.x) < threshold && Math.abs(obj1.y - obj2.y) < threshold; } var isCharacterMoving = false; // Function to move character based on direction var dpadButtonSize = { width: 450, height: 450 }; function moveCharacter(xDir, yDir) { if (availableLives <= 0) { return; } if (character) { var nextX = character.x + xDir * tileWidth; var nextY = character.y + yDir * tileHeight; } // Check if the next position is within the grid boundaries if (nextX >= gridOffsetX && nextX <= gridOffsetX + gridSize * tileWidth && nextY >= gridOffsetY && nextY <= gridOffsetY + gridSize * tileHeight) { // Check if the next tile is not a wall var nextTileIndex = Math.floor((nextY - gridOffsetY) / tileHeight) * gridSize + Math.floor((nextX - gridOffsetX) / tileWidth); if (grid[nextTileIndex] && (floorTiles.includes(grid[nextTileIndex]) || holeTile && grid[nextTileIndex].x === holeTile.x && grid[nextTileIndex].y === holeTile.y)) { character.x = nextX; character.y = nextY; character.currentTile = grid[nextTileIndex]; } } } LK.screen = { width: 2048, height: 2732 }; // Initialize screen dimensions // Removed redundant globalEnemySpeed initialization var gridSize = 10; // Character initialization removed to prevent duplication var totalCheeses = Math.floor(Math.random() * 3) + 1; // Define total number of cheeses in the game as a random number between 1 and 3 var cheeses = []; // Initialize cheeses array globally // Declare cheeseIcon as a global variable var cheeseIcon; var wallTiles = []; var obstacleTiles = []; // Define obstacleTiles array var floorTiles = []; var grid = new Array(gridSize * gridSize); var tileWidth = LK.screen.width * .6 / (gridSize - 1); // Adjust tile width to ensure tiles are touching var tileHeight = tileWidth; // Ensure square tiles for a uniform grid var gridOffsetX = (LK.screen.width - tileWidth * gridSize) / 2; // Corrected grid offset X calculation var gridOffsetY = (LK.screen.height - tileHeight * gridSize) / 2 - LK.screen.height * 0.15; // Corrected grid offset Y calculation // Move the onScreenController initialization to the top of Game Code section to ensure it's available before adding event listeners var onScreenController = game.addChild(new OnScreenController()); // Removed the A button press event listener for picking up cheese based on tile comparison function createTiles() { // Create a black square background for the grid var gridBackground = LK.getAsset('gridBackground', { anchorX: 0.5, anchorY: 0.75, x: LK.screen.width / 2, y: LK.screen.height / 2, width: LK.screen.width * .9, height: LK.screen.height * .65, tint: 0xFFA500 // Apply orange tint }); game.addChild(gridBackground); var gridBackgroundShrunk = LK.getAsset('gridBackground', { anchorX: 0.5, anchorY: 0.75, x: LK.screen.width / 2, y: LK.screen.height / 2, width: LK.screen.width * .9 - 50, height: LK.screen.height * .65 - 50, tint: 0x000000 // Apply black tint }); game.addChild(gridBackgroundShrunk); game.setChildIndex(gridBackgroundShrunk, game.getChildIndex(gridBackground) + 1); // Place the flag tile on top of the hole tile var flagTile = game.addChild(new FlagTile()); flagTile.x = holeTile.x; flagTile.y = holeTile.y; // Add walls after floor tiles to ensure they render on top for (var i = 0; i < gridSize * gridSize; i++) { var x = i % gridSize; var y = Math.floor(i / gridSize); if (x === 0 || y === 0 || x === gridSize - 1 || y === gridSize - 1) { var isCornerTile = x === 0 && y === 0 || x === 0 && y === gridSize - 1 || x === gridSize - 1 && y === 0 || x === gridSize - 1 && y === gridSize - 1; if (isCornerTile) { var tile = LK.getAsset('CornerTile', { anchorX: 0.5, anchorY: 0.5, x: x * tileWidth + gridOffsetX, y: y * tileHeight + gridOffsetY }); game.addChild(tile); grid[i] = tile; } else { var tile = LK.getAsset('wallTile', { anchorX: 0.5, anchorY: 0.5, x: x * tileWidth + gridOffsetX, y: y * tileHeight + gridOffsetY }); wallTiles.push(tile); game.addChild(tile); grid[i] = tile; } } } } createTiles(); // Function to check if a tile is in a corner // Corner logic removed var randomWallTile = wallTiles[Math.floor(Math.random() * wallTiles.length)]; var holeTile = LK.getAsset('holeTile', { anchorX: 0.5, anchorY: 0.5, x: randomWallTile.x, y: randomWallTile.y }); game.addChild(holeTile); game.removeChild(randomWallTile); var randomWallTileIndex = wallTiles.indexOf(randomWallTile); wallTiles[randomWallTileIndex] = holeTile; var isGameStarted = false; var cheesePlaced = false; LK.on('tick', function () { if (!isGameStarted) { game.eventManager.publish('gameStart', null); LK.setTimeout(function () { enemies.push(game.addChild(new Enemy('Roomba'))); enemies.push(game.addChild(new Enemy('Roomba'))); // Position Roombas on opposite sides of the grid if (enemies[0]) { // Position the first Roomba on the left side enemies[0].x = floorTiles[0].x; enemies[0].y = floorTiles[0].y; } if (enemies[1]) { // Position the second Roomba on the right side var lastTileIndex = floorTiles.length - 1; enemies[1].x = floorTiles[lastTileIndex].x; enemies[1].y = floorTiles[lastTileIndex].y; } }, 1000); // Initialize cheese instances to place them on the floor // No changes needed here as the character shadow consistency is maintained with the original creation. character.currentTile = getTileAtPosition(holeTile.x, holeTile.y); // Correctly initialize character's current tile game.addChild(character); } // Iterate over enemies array to move each enemy and check for collision with character enemies.forEach(function (enemy) { enemy.move(); // Check if enemy intersects with character if (enemy.intersects(character) && Math.sqrt(Math.pow(enemy.x - character.x, 2) + Math.pow(enemy.y - character.y, 2)) < 200 && !character.isImmune && !(Math.abs(character.x - holeTile.x) < 75 && Math.abs(character.y - holeTile.y) < 75)) { // Reduce character lives by 1 availableLives -= 1; // Update lives display and make live icons disappear when player gets hit // Update lives display and make live icons disappear when player loses a life livesIcons.forEach(function (icon, index) { icon.visible = index < availableLives; }); // Make character blink to indicate damage and grant temporary immunity character.isImmune = true; // Set immunity flag to true var blinkInterval = LK.setInterval(function () { character.visible = !character.visible; // Removed tint logic }, 100); LK.setTimeout(function () { LK.clearInterval(blinkInterval); character.visible = true; // Reset tint to normal after blinking character.tint = 0xffffff; character.isImmune = false; // Remove immunity after 1 second }, 1000); // Check if lives are depleted or all cheeses have been delivered to win the game if (availableLives <= 0) { character.visible = false; // Make character invisible LK.setTimeout(function () { LK.showGameOver("You've been caught! Better luck next time."); }, 1000); // Wait one second before showing game over } // Removed win game logic based on cheese delivery } }); }); spawnCheeses(); // Create instances of enemies and store them in an array var enemies = []; // Removed two Roomba enemies // Position enemies // Position Roombas on opposite sides of the grid if (enemies[0]) { // Position the first Roomba on the left side enemies[0].x = floorTiles[0].x; enemies[0].y = floorTiles[0].y; } if (enemies[1]) { // Position the second Roomba on the right side var lastTileIndex = floorTiles.length - 1; enemies[1].x = floorTiles[lastTileIndex].x; enemies[1].y = floorTiles[lastTileIndex].y; } // Function to select a new target tile avoiding obstacles function selectNewTargetTileAvoidingObstacles(currentX, currentY, floorTiles, obstacleTiles) { // Placeholder for pathfinding logic to select a new target tile // For simplicity, this example randomly selects a floor tile not in the obstacleTiles array var validTiles = floorTiles.filter(function (tile) { return !obstacleTiles.includes(tile); }); if (validTiles.length > 0) { var randomIndex = Math.floor(Math.random() * validTiles.length); return validTiles[randomIndex]; } else { console.error('No valid tiles found to move to.'); return null; // Return null if no valid tiles are found } } // Define a function to get the tile at a given position function getTileAtPosition(x, y) { var index = Math.floor(y / 100) * gridSize + Math.floor(x / 100); if (index >= 0 && index < grid.length && grid[index]) { return grid[index]; } else { console.error('Tile at position', x, y, 'is out of bounds or null.'); return undefined; // Return undefined to indicate no tile found or out of bounds without error } }
/****
* Classes
****/
var Character = Container.expand(function () {
var self = Container.call(this);
// Character shadow attachment removed
// Character shadow attachment removed
var characterGraphics = self.attachAsset('character', {
anchorX: 0.5,
anchorY: 0.5
});
characterGraphics.scaleX = 1;
characterGraphics.scaleY = 1;
});
var Cheese = Container.expand(function () {
var self = Container.call(this);
// Cheese shadow attachment removed
var cheeseGraphics = self.attachAsset('cheese', {
anchorX: 0.5,
anchorY: 0.5
});
self.lerpToPosition = function (startPos, endPos, duration, onComplete) {
self.x = endPos.x;
self.y = endPos.y;
if (onComplete) {
onComplete();
}
};
});
var Enemy = Container.expand(function (type) {
var self = Container.call(this);
self.id = Math.random().toString(36).substr(2, 9); // Unique ID for each Roomba
var shadowAssetId, enemyAssetId, shadowScale, enemySpeed;
// Moved globalEnemySpeed initialization outside of Enemy class to fix 'ReferenceError'
var level = 0; // Initialize level variable
// Moved globalEnemySpeed initialization outside of Enemy class to fix 'ReferenceError'
var defaultEnemySpeed = globalEnemySpeed; // Use global enemy speed for initial speed
var EnemyTypes = {
Roomba: {
shadowAssetId: 'CircularShadow',
enemyAssetId: 'Roomba',
shadowScale: 3.2,
enemySpeed: defaultEnemySpeed * (1.03 + level * 0.05) // Increase speed by 3% plus an additional 5% per level
}
};
var enemyStats = EnemyTypes[type];
if (!enemyStats) {
console.error('Unknown enemy type:', type);
return;
}
shadowAssetId = enemyStats.shadowAssetId;
enemyAssetId = enemyStats.enemyAssetId;
shadowScale = enemyStats.shadowScale;
enemySpeed = enemyStats.enemySpeed;
var shadowGraphics = self.attachAsset(shadowAssetId, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5,
scaleX: shadowScale,
scaleY: shadowScale
});
var enemyGraphics = self.attachAsset(enemyAssetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Adjust shadow position relative to the enemy
shadowGraphics.x = enemyGraphics.x;
shadowGraphics.y = enemyGraphics.y + 40; // Slightly below the enemy for a realistic shadow effect
// Set enemy speed
self.speed = enemySpeed;
// Enemy movement logic
self.move = function () {
// Enhanced enemy behavior with dynamic avoidance and pathfinding
enemies.forEach(function (otherEnemy) {
if (otherEnemy.id !== self.id) {
var dx = self.x - otherEnemy.x;
var dy = self.y - otherEnemy.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 250 && distance > 0) {
var awayX = dx / distance;
var awayY = dy / distance;
// Adjust repulsion to be more dynamic based on distance
var repulsionStrength = Math.max(1, 250 - distance) / 50; // Increase repulsion as enemies get closer
self.x += awayX * self.speed * repulsionStrength;
self.y += awayY * self.speed * repulsionStrength;
// Force Roombas to change direction upon collision
self.targetTile = floorTiles[Math.floor(Math.random() * floorTiles.length)];
}
}
});
// Pick a random floor tile as a new target to keep Roombas apart
if (!self.targetTile || self.collisionCounter > 50 || Math.sqrt(Math.pow(self.x - self.targetTile.x, 2) + Math.pow(self.y - self.targetTile.y, 2)) < 15) {
var randomIndex = Math.floor(Math.random() * floorTiles.length);
self.targetTile = floorTiles[randomIndex];
self.collisionCounter = 0; // Reset collision counter after changing target
}
// Introduce a collision counter to track continuous collisions
if (!self.collisionCounter) {
self.collisionCounter = 0;
}
// Increase collision counter on collision
if (self.colliding) {
self.collisionCounter++;
} else {
self.collisionCounter = 0; // Reset counter if not colliding
}
// Change target tile if colliding for too long or reached current target
if (!self.targetTile || self.collisionCounter > 30 || Math.sqrt(Math.pow(self.x - self.targetTile.x, 2) + Math.pow(self.y - self.targetTile.y, 2)) < 10) {
self.targetTile = floorTiles[Math.floor(Math.random() * floorTiles.length)];
self.collisionCounter = 0; // Reset collision counter after changing target
}
// Reset colliding flag for the next tick
self.colliding = false;
var angleToTarget = Math.atan2(self.targetTile.y - self.y, self.targetTile.x - self.x);
self.x += Math.cos(angleToTarget) * self.speed;
self.y += Math.sin(angleToTarget) * self.speed;
// Smoothly rotate the enemy towards the target angle
var currentAngle = enemyGraphics.rotation;
var targetAngle = angleToTarget;
// Calculate the shortest direction to rotate
var angleDifference = targetAngle - currentAngle;
angleDifference += angleDifference > Math.PI ? -2 * Math.PI : angleDifference < -Math.PI ? 2 * Math.PI : 0;
var rotationSpeed = 0.1; // Adjust rotation speed as needed
enemyGraphics.rotation += angleDifference * rotationSpeed;
};
});
var FlagTile = Container.expand(function () {
var self = Container.call(this);
var flagGraphics = self.attachAsset('Flag', {
anchorX: 0.5,
anchorY: 0.5
});
});
// OnScreenController class encapsulating A, B buttons and D-pad
var OnScreenController = Container.expand(function () {
var self = Container.call(this);
// Add a background for the on screen controllers
var yPosAdjustment = -180;
var buttonYPosAdjustment = -273.2;
var dpadButtonSize = 350; // Increased size for better visibility and interaction
// Removed redundant tint application on A and B buttons
LK.screen = {
width: 2048,
height: 2732
}; // Initialize screen dimensions
var aButtonPosition = {
x: LK.screen.width * 0.75,
y: LK.screen.height * 0.85 + buttonYPosAdjustment + LK.screen.height * 0.055
};
var buttonSize = {
width: 400,
height: 400
};
var dPadSize = {
width: 750,
height: 750
};
this.aButton = self.attachAsset('aButton', {
anchorX: 0.5,
anchorY: 0.5,
x: aButtonPosition.x,
y: aButtonPosition.y,
width: buttonSize.width,
height: buttonSize.height
});
// D-pad
var dpadBase = self.attachAsset('dpadBase', {
anchorX: 0.5,
anchorY: 0.5,
x: LK.screen.width * 0.24,
y: LK.screen.height * 0.89 + yPosAdjustment - 10,
width: dPadSize.width,
height: dPadSize.height
});
self.setChildIndex(dpadBase, self.children.length - 1);
var dpadLeft = self.attachAsset('dpadButtonLeft', {
anchorX: 0.5,
anchorY: 0.5,
x: dpadBase.x - 300,
y: dpadBase.y,
width: dpadButtonSize,
height: dpadButtonSize,
alpha: 0,
// Tint arrow yellow
orientation: 3
});
var moveInterval;
function startMovingCharacter(xDir, yDir) {
if (moveInterval) {
LK.clearInterval(moveInterval);
}
isCharacterMoving = true;
moveCharacter(xDir, yDir);
moveInterval = LK.setInterval(function () {
moveCharacter(xDir, yDir);
}, 150);
}
dpadLeft.on('down', function () {
startMovingCharacter(-1, 0);
});
var dpadUp = self.attachAsset('dpadButtonUp', {
anchorX: 0.5,
anchorY: 0.5,
x: dpadBase.x,
y: dpadBase.y - 300,
width: dpadButtonSize,
height: dpadButtonSize,
alpha: 0,
orientation: 0
});
dpadUp.on('down', function () {
startMovingCharacter(0, -1);
});
var dpadRight = self.attachAsset('dpadButtonRight', {
anchorX: 0.5,
anchorY: 0.5,
x: dpadBase.x + 300,
y: dpadBase.y,
width: dpadButtonSize,
height: dpadButtonSize,
alpha: 0,
orientation: 1
});
dpadRight.on('down', function () {
startMovingCharacter(1, 0);
});
var dpadDown = self.attachAsset('dpadButtonDown', {
anchorX: 0.5,
anchorY: 0.5,
x: dpadBase.x,
y: dpadBase.y + 300,
width: dpadButtonSize,
height: dpadButtonSize,
alpha: 0,
orientation: 2
});
dpadDown.on('down', function () {
startMovingCharacter(0, 1);
});
function stopMovingCharacter() {
isCharacterMoving = false;
LK.clearInterval(moveInterval);
}
dpadLeft.on('up', stopMovingCharacter);
dpadUp.on('up', stopMovingCharacter);
dpadRight.on('up', stopMovingCharacter);
dpadDown.on('up', stopMovingCharacter);
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xf9e076 // Fun yellow background
});
/****
* Game Code
****/
// characterShadow asset initialization removed
// Function to spawn cheeses at random floor tile positions
function spawnCheeses() {
// Clear existing cheeses before spawning new ones
cheeses.forEach(function (cheese) {
cheese.destroy();
});
cheeses = []; // Reset the cheeses array
// Spawn new cheeses
for (var i = 0; i < totalCheeses; i++) {
cheeses.push(game.addChild(new Cheese()));
}
// Place cheeses on non-corner floor tiles that are far from the character
var nonCornerFloorTiles = floorTiles.filter(function (tile) {
return true;
});
var farthestTiles = nonCornerFloorTiles.filter(function (tile) {
// Ensure character is defined before calculating distance
var distanceToCharacter = typeof character !== 'undefined' && character !== null ? Math.sqrt(Math.pow(tile.x - character.x, 2) + Math.pow(tile.y - character.y, 2)) : Infinity;
return distanceToCharacter > LK.screen.width / 2; // Arbitrary distance threshold
});
// Exclude tiles that are too close to the hole tile
var safeDistanceTiles = nonCornerFloorTiles.filter(function (tile) {
var distanceToHole = Math.sqrt(Math.pow(tile.x - holeTile.x, 2) + Math.pow(tile.y - holeTile.y, 2));
return distanceToHole > LK.screen.width / 4; // Arbitrary distance threshold to keep cheese away from the hole
});
// Filter out tiles that are surrounded by obstacles horizontally and vertically
// Move the declaration of 'targetTiles' before its first use
var targetTiles = safeDistanceTiles.length > 0 ? safeDistanceTiles : farthestTiles;
var validTilesForCheese = targetTiles.filter(function (tile) {
var leftTile = getTileAtPosition(tile.x - tileWidth, tile.y);
var rightTile = getTileAtPosition(tile.x + tileWidth, tile.y);
var topTile = getTileAtPosition(tile.x, tile.y - tileHeight);
var bottomTile = getTileAtPosition(tile.x, tile.y + tileHeight);
// Check if the tile is surrounded by obstacles on all four sides
return !(obstacleTiles.includes(leftTile) || obstacleTiles.includes(rightTile) || obstacleTiles.includes(topTile) || obstacleTiles.includes(bottomTile));
});
var targetTiles = validTilesForCheese.length > 0 ? validTilesForCheese : nonCornerFloorTiles;
// Place each cheese on a unique random floor tile
cheeses.forEach(function (cheese) {
var uniqueTileIndex = Math.floor(Math.random() * targetTiles.length);
var uniqueFloorTile = targetTiles.splice(uniqueTileIndex, 1)[0]; // Remove the selected tile from the pool to ensure uniqueness
if (uniqueFloorTile) {
cheese.x = uniqueFloorTile.x;
cheese.y = uniqueFloorTile.y;
}
});
}
// Method to check if all cheeses have been delivered
function allCheesesDelivered() {
// Destroy grid and tiles
grid.forEach(function (tile) {
if (tile) {
tile.destroy();
}
});
grid = []; // Clear the grid array
floorTiles.forEach(function (tile) {
tile.destroy();
});
floorTiles = []; // Clear the floorTiles array
wallTiles.forEach(function (tile) {
tile.destroy();
});
wallTiles = []; // Clear the wallTiles array
obstacleTiles.forEach(function (tile) {
tile.destroy();
});
obstacleTiles = []; // Clear the obstacleTiles array
// Destroy character and cheese icon
if (character) {
if (cheeseIcon) {
cheeseIcon.destroy();
}
character.destroy();
character = null;
}
// Destroy enemies
enemies.forEach(function (enemy) {
enemy.destroy();
});
enemies = []; // Clear the enemies array
globalEnemySpeed *= 1.1; // Increase global enemy speed by 10% on each level load
console.log("building next level");
// Rebuild game elements
createTiles(); // Rebuild the tiles for the level
var nonCornerWallTiles = wallTiles.filter(function (tile) {
var x = tile.x,
y = tile.y;
var isCornerTile = x === gridOffsetX && y === gridOffsetY || x === gridOffsetX + (gridSize - 1) * tileWidth && y === gridOffsetY || x === gridOffsetX && y === gridOffsetY + (gridSize - 1) * tileHeight || x === gridOffsetX + (gridSize - 1) * tileWidth && y === gridOffsetY + (gridSize - 1) * tileHeight;
return !isCornerTile;
});
var randomWallTile = nonCornerWallTiles[Math.floor(Math.random() * nonCornerWallTiles.length)];
holeTile = LK.getAsset('holeTile', {
anchorX: 0.5,
anchorY: 0.5,
x: randomWallTile.x,
y: randomWallTile.y
});
game.addChild(holeTile);
game.removeChild(randomWallTile);
spawnCheeses(); // Spawn cheeses for the new level
// Re-instantiate character for the new level with correct shadow and position
character = game.addChild(new Character());
// Attach cheese icon to the new character if cheese is collected
if (cheeseIcon && cheeseIcon.visible) {
cheeseIcon = character.attachAsset('cheese', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
x: 0,
y: -character.height / 2 // Position closer to the character top
});
}
// Create a new cheese icon and disable it
cheeseIcon = character.attachAsset('cheese', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
x: 0,
y: -character.height / 2,
// Position closer to the character top
visible: false // Disable cheese icon after creation
});
// Attach cheese icon to the new character if cheese is collected
// Ensure the cheese icon is visible on the new character instance
character.x = holeTile.x; // Position character at the hole's location
character.y = holeTile.y - 50; // Adjust Y position to not overlap with the hole
enemies.forEach(function (enemy) {
enemy.destroy();
}); // Destroy existing enemies
enemies = []; // Clear enemies array
enemies.push(game.addChild(new Enemy('Roomba'))); // Add first Roomba enemy
enemies.push(game.addChild(new Enemy('Roomba'))); // Add second Roomba enemy
// Position Roombas on opposite sides of the grid
if (enemies[0]) {
enemies[0].x = floorTiles[0].x; // Position the first Roomba on the left side
enemies[0].y = floorTiles[0].y;
}
if (enemies[1]) {
var lastTileIndex = floorTiles.length - 1;
enemies[1].x = floorTiles[lastTileIndex].x; // Position the second Roomba on the right side
enemies[1].y = floorTiles[lastTileIndex].y;
}
}
// Ensure LK.screen dimensions are defined before using them
var globalEnemySpeed = 3; // Define initial global enemy speed
LK.screen = {
width: 2048,
height: 2732
}; // Initialize screen dimensions
// Instantiate and center the game logo asset on the screen
var gameLogo = LK.getAsset('stickerLogo', {
anchorX: 0.5,
anchorY: 0.5,
x: LK.screen.width / 2 + 50,
y: 1955
});
game.addChild(gameLogo);
var dakaloText = new Text2('@Dakalo777', {
size: 50,
fill: "#FFA500",
x: LK.screen.width - 20,
// Adjust for space from the right edge
y: LK.screen.height - 20 // Adjust for space from the bottom edge
});
dakaloText.anchor.set(1, 1); // Anchor to bottom right
LK.gui.bottomRight.addChild(dakaloText);
// Function to check if a new obstacle tile fully surrounds any cheese
// Removed redundant cheese tracking variables
function doesTileSurroundCheese(obstacleTile, cheeses) {
return cheeses.some(function (cheese) {
// Calculate adjacent tiles to the cheese
var adjacentTiles = [{
x: cheese.x - tileWidth,
y: cheese.y
}, {
x: cheese.x + tileWidth,
y: cheese.y
}, {
x: cheese.x,
y: cheese.y - tileHeight
}, {
x: cheese.x,
y: cheese.y + tileHeight
}];
// Check if all adjacent tiles are either walls, obstacles, or the new obstacle tile
return adjacentTiles.every(function (tile) {
return wallTiles.some(function (wallTile) {
return wallTile.x === tile.x && wallTile.y === tile.y;
}) || grid.some(function (gridTile) {
return gridTile && gridTile.x === tile.x && gridTile.y === tile.y && gridTile !== cheese && gridTile !== obstacleTile;
});
});
});
}
// Add sticker02 asset to the bottom of the screen next to sticker and rotate it 32 degrees
var sticker02 = game.addChild(LK.getAsset('sticker02', {
anchorX: 1.0,
anchorY: 1.0,
x: 2100,
y: 2300,
rotation: -0.558
}));
// Add sticker asset to the bottom of the screen and rotate it 32 degrees
var sticker = LK.getAsset('sticker', {
anchorX: 0.5,
anchorY: 0.5,
x: 900,
y: 2400,
scaleX: 0.7,
// Scale down by 0.7
scaleY: 0.7,
// Scale down by 0.7
rotation: 0.10
});
game.addChild(sticker);
// Update play time display every second
LK.on('tick', function () {
var minutes = Math.floor(playTime / 60);
var seconds = playTime % 60;
playTimeDisplay.setText((minutes < 10 ? '0' : '') + minutes + ':' + (seconds < 10 ? '0' : '') + seconds);
});
// Create a timer to update play time every second
var playTimeTimer = LK.setInterval(function () {
playTime += 1;
}, 1000);
// Initialize play time tracking
var playTime = 0;
// Initialize EventManager for global event handling
var EventManager = {
events: {},
subscribe: function subscribe(eventType, listener) {
if (!this.events[eventType]) {
this.events[eventType] = [];
}
this.events[eventType].push(listener);
},
unsubscribe: function unsubscribe(eventType, listener) {
if (this.events[eventType]) {
var index = this.events[eventType].indexOf(listener);
if (index > -1) {
this.events[eventType].splice(index, 1);
}
}
},
publish: function publish(eventType, data) {
if (this.events[eventType]) {
this.events[eventType].forEach(function (listener) {
listener(data);
});
}
}
};
game.eventManager = EventManager;
// Subscribe to 'gameStart' event to initialize character and game state
game.eventManager.subscribe('gameStart', function () {
isGameStarted = true;
// Method to instantiate and return a new character
function createCharacter() {
return LK.getAsset('character', {
anchorX: 0.5,
anchorY: 0.5,
x: holeTile.x,
y: holeTile.y - 50,
scaleX: 1,
scaleY: 1
});
}
character = createCharacter();
// Reset cheese score display to '0' to prevent UI text overlap on game reset
cheeseScoreDisplay.setText('0');
});
// Reset UI elements correctly when playing again
if (window.scoreBoardContainer) {
window.scoreBoardContainer.children.forEach(function (child) {
child.destroy(); // Destroy each child to ensure clean slate
});
window.scoreBoardContainer.destroy(); // Ensure the container is properly destroyed
window.scoreBoardContainer = null;
}
// Reinitialize the scoreboard container to prevent UI text overlap on game reset
window.scoreBoardInitialized = false;
// Initialize scoreboard container and elements once and update score dynamically
if (!window.scoreBoardInitialized) {
var updateCheeseScore = function updateCheeseScore(score) {
cheeseScoreDisplay.setText(score.toString());
};
window.scoreBoardContainer = new Container();
var scoreBoardX = 0,
scoreBoardY = 0;
var cheeseIconForScore = window.scoreBoardContainer.attachAsset('cheese', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: -500,
y: 55
});
// Dynamically add one character lives icon per available life
var availableLives = 3; // Assuming 3 lives to start with
var livesIcons = [];
for (var i = availableLives - 1; i >= 0; i--) {
var lifeIcon = window.scoreBoardContainer.attachAsset('characterLivesIcon', {
anchorX: 0,
anchorY: 0,
scaleX: 1.5,
scaleY: 1.5,
x: (availableLives - 1 - i) * 90 + 250,
y: 0
});
livesIcons.unshift(lifeIcon);
}
// Cheese score display added to the scoreboard
var cheeseScoreDisplay = new Text2('0', {
size: 50,
fill: "#ffffff",
stroke: "#ffffff",
strokeThickness: 4,
font: "Roboto, bold",
x: cheeseIconForScore.x + 60,
// Adjust x position to place score text right side of the cheese icon
y: cheeseIconForScore.y
});
cheeseScoreDisplay.anchor.set(14.5, -.8);
window.scoreBoardContainer.addChild(cheeseScoreDisplay);
// Update cheese score display function
window.updateCheeseScore = function (score) {
updateCheeseScore(score);
// Initiate bounce effect
var originalScaleX = cheeseScoreDisplay.scaleX;
var originalScaleY = cheeseScoreDisplay.scaleY;
var scaleUpDuration = 150; // Duration to scale up
var scaleDownDuration = 150; // Duration to scale down back to original size
var scaleAmount = 1.2; // Amount to scale up
// Scale up
cheeseScoreDisplay.scaleX = originalScaleX * scaleAmount;
cheeseScoreDisplay.scaleY = originalScaleY * scaleAmount;
// Delay before scaling down
LK.setTimeout(function () {
// Scale down back to original size
cheeseScoreDisplay.scaleX = originalScaleX;
cheeseScoreDisplay.scaleY = originalScaleY;
}, scaleUpDuration);
};
// Character lives text asset creation and addition to scoreBoardContainer removed
// Add play time display to the scoreboard
// Initialize screen dimensions for playTimeDisplay positioning
LK.screen = {
width: 2048,
height: 2732
};
var playTimeDisplay = new Text2('00:00', {
size: 50,
fill: "#E0E0E0",
font: "Roboto, bold",
x: -LK.screen.width / 2,
y: 0
});
playTimeDisplay.anchor.set(-0.75, 0); // Center the text horizontally
window.scoreBoardContainer.addChild(playTimeDisplay);
window.scoreBoardContainer.x = 0;
window.scoreBoardContainer.y = 55;
LK.gui.top.addChild(window.scoreBoardContainer);
window.scoreBoardInitialized = true;
}
var onScreenController = game.addChild(new OnScreenController());
// Refactored event listener for A button press to manage cheese collection and scoring more efficiently
onScreenController.aButton.on('down', function () {
if (isWithinProximity(character, holeTile, 75) && cheeseIcon && cheeseIcon.visible) {
var createFlyingCheeseEffect = function createFlyingCheeseEffect(fromX, fromY) {
var flyingCheese = game.addChild(LK.getAsset('cheese', {
anchorX: 0.5,
anchorY: 0.5,
x: fromX,
y: fromY,
scaleX: 1.0,
// Scale up by 100%
scaleY: 1.0 // Scale up by 100%
}));
var leftTopCornerTile = floorTiles[0]; // Assuming the first tile in the array is the top left corner
var scoreBoardPos = {
x: leftTopCornerTile.x - tileHeight,
y: leftTopCornerTile.y - tileHeight
};
var cheeseFlyDuration = 750; // Duration in milliseconds
var startTime = Date.now();
LK.on('tick', function () {
var currentTime = Date.now();
var progress = (currentTime - startTime) / cheeseFlyDuration;
if (progress < 1) {
flyingCheese.x = fromX + (scoreBoardPos.x - fromX) * progress;
flyingCheese.y = fromY + (scoreBoardPos.y - fromY) * progress;
// Calculate the angle to rotate the flying cheese towards the scoreboard and add 180 degrees for rotation
var angle = Math.atan2(scoreBoardPos.y - fromY, scoreBoardPos.x - fromX) + Math.PI;
flyingCheese.rotation = angle;
} else {
game.removeChild(flyingCheese);
window.updateCheeseScore(LK.getScore()); // Update displayed score
}
});
}; // Invoke createFlyingCheeseEffect with character's position when cheese is delivered
console.log('Cheese delivered!');
cheeseIcon.visible = false; // Hide the cheese icon to indicate delivery
// If it's the last cheese, increment score by 2, otherwise by 1
if (cheeses.length === 0) {
LK.setScore(LK.getScore() + 2);
allCheesesDelivered(); // Invoke allCheesesDelivered method after scoring for the last cheese
} else {
LK.setScore(LK.getScore() + 1);
}
// Create a visual cheese flying effect towards the scoreboard on cheese delivery
createFlyingCheeseEffect(holeTile.x, holeTile.y);
} else {
if (!cheeseIcon || !cheeseIcon.visible) {
cheeses.forEach(function (cheese, index) {
if (isWithinProximity(character, cheese, 75)) {
console.log('Cheese collected!');
game.removeChild(cheese); // Remove cheese from game
cheeses.splice(index, 1); // Remove cheese from cheeses array
// Display cheese icon above character to indicate cheese collection
if (!cheeseIcon) {
cheeseIcon = character.attachAsset('cheese', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
// Scale down by 50%
scaleY: 0.8,
// Scale down by 50%
x: 0,
y: -character.height / 2 // Position closer to the character top
});
} else {
cheeseIcon.visible = true; // Make the cheese icon visible if already exists
}
}
});
}
}
});
// Helper function to check if two objects are within a certain distance
function isWithinProximity(obj1, obj2, threshold) {
if (!obj1 || !obj2) {
return false;
}
return Math.abs(obj1.x - obj2.x) < threshold && Math.abs(obj1.y - obj2.y) < threshold;
}
var isCharacterMoving = false;
// Function to move character based on direction
var dpadButtonSize = {
width: 450,
height: 450
};
function moveCharacter(xDir, yDir) {
if (availableLives <= 0) {
return;
}
if (character) {
var nextX = character.x + xDir * tileWidth;
var nextY = character.y + yDir * tileHeight;
}
// Check if the next position is within the grid boundaries
if (nextX >= gridOffsetX && nextX <= gridOffsetX + gridSize * tileWidth && nextY >= gridOffsetY && nextY <= gridOffsetY + gridSize * tileHeight) {
// Check if the next tile is not a wall
var nextTileIndex = Math.floor((nextY - gridOffsetY) / tileHeight) * gridSize + Math.floor((nextX - gridOffsetX) / tileWidth);
if (grid[nextTileIndex] && (floorTiles.includes(grid[nextTileIndex]) || holeTile && grid[nextTileIndex].x === holeTile.x && grid[nextTileIndex].y === holeTile.y)) {
character.x = nextX;
character.y = nextY;
character.currentTile = grid[nextTileIndex];
}
}
}
LK.screen = {
width: 2048,
height: 2732
}; // Initialize screen dimensions
// Removed redundant globalEnemySpeed initialization
var gridSize = 10;
// Character initialization removed to prevent duplication
var totalCheeses = Math.floor(Math.random() * 3) + 1; // Define total number of cheeses in the game as a random number between 1 and 3
var cheeses = []; // Initialize cheeses array globally
// Declare cheeseIcon as a global variable
var cheeseIcon;
var wallTiles = [];
var obstacleTiles = []; // Define obstacleTiles array
var floorTiles = [];
var grid = new Array(gridSize * gridSize);
var tileWidth = LK.screen.width * .6 / (gridSize - 1); // Adjust tile width to ensure tiles are touching
var tileHeight = tileWidth; // Ensure square tiles for a uniform grid
var gridOffsetX = (LK.screen.width - tileWidth * gridSize) / 2; // Corrected grid offset X calculation
var gridOffsetY = (LK.screen.height - tileHeight * gridSize) / 2 - LK.screen.height * 0.15; // Corrected grid offset Y calculation
// Move the onScreenController initialization to the top of Game Code section to ensure it's available before adding event listeners
var onScreenController = game.addChild(new OnScreenController());
// Removed the A button press event listener for picking up cheese based on tile comparison
function createTiles() {
// Create a black square background for the grid
var gridBackground = LK.getAsset('gridBackground', {
anchorX: 0.5,
anchorY: 0.75,
x: LK.screen.width / 2,
y: LK.screen.height / 2,
width: LK.screen.width * .9,
height: LK.screen.height * .65,
tint: 0xFFA500 // Apply orange tint
});
game.addChild(gridBackground);
var gridBackgroundShrunk = LK.getAsset('gridBackground', {
anchorX: 0.5,
anchorY: 0.75,
x: LK.screen.width / 2,
y: LK.screen.height / 2,
width: LK.screen.width * .9 - 50,
height: LK.screen.height * .65 - 50,
tint: 0x000000 // Apply black tint
});
game.addChild(gridBackgroundShrunk);
game.setChildIndex(gridBackgroundShrunk, game.getChildIndex(gridBackground) + 1);
// Place the flag tile on top of the hole tile
var flagTile = game.addChild(new FlagTile());
flagTile.x = holeTile.x;
flagTile.y = holeTile.y;
// Add walls after floor tiles to ensure they render on top
for (var i = 0; i < gridSize * gridSize; i++) {
var x = i % gridSize;
var y = Math.floor(i / gridSize);
if (x === 0 || y === 0 || x === gridSize - 1 || y === gridSize - 1) {
var isCornerTile = x === 0 && y === 0 || x === 0 && y === gridSize - 1 || x === gridSize - 1 && y === 0 || x === gridSize - 1 && y === gridSize - 1;
if (isCornerTile) {
var tile = LK.getAsset('CornerTile', {
anchorX: 0.5,
anchorY: 0.5,
x: x * tileWidth + gridOffsetX,
y: y * tileHeight + gridOffsetY
});
game.addChild(tile);
grid[i] = tile;
} else {
var tile = LK.getAsset('wallTile', {
anchorX: 0.5,
anchorY: 0.5,
x: x * tileWidth + gridOffsetX,
y: y * tileHeight + gridOffsetY
});
wallTiles.push(tile);
game.addChild(tile);
grid[i] = tile;
}
}
}
}
createTiles();
// Function to check if a tile is in a corner
// Corner logic removed
var randomWallTile = wallTiles[Math.floor(Math.random() * wallTiles.length)];
var holeTile = LK.getAsset('holeTile', {
anchorX: 0.5,
anchorY: 0.5,
x: randomWallTile.x,
y: randomWallTile.y
});
game.addChild(holeTile);
game.removeChild(randomWallTile);
var randomWallTileIndex = wallTiles.indexOf(randomWallTile);
wallTiles[randomWallTileIndex] = holeTile;
var isGameStarted = false;
var cheesePlaced = false;
LK.on('tick', function () {
if (!isGameStarted) {
game.eventManager.publish('gameStart', null);
LK.setTimeout(function () {
enemies.push(game.addChild(new Enemy('Roomba')));
enemies.push(game.addChild(new Enemy('Roomba')));
// Position Roombas on opposite sides of the grid
if (enemies[0]) {
// Position the first Roomba on the left side
enemies[0].x = floorTiles[0].x;
enemies[0].y = floorTiles[0].y;
}
if (enemies[1]) {
// Position the second Roomba on the right side
var lastTileIndex = floorTiles.length - 1;
enemies[1].x = floorTiles[lastTileIndex].x;
enemies[1].y = floorTiles[lastTileIndex].y;
}
}, 1000);
// Initialize cheese instances to place them on the floor
// No changes needed here as the character shadow consistency is maintained with the original creation.
character.currentTile = getTileAtPosition(holeTile.x, holeTile.y); // Correctly initialize character's current tile
game.addChild(character);
}
// Iterate over enemies array to move each enemy and check for collision with character
enemies.forEach(function (enemy) {
enemy.move();
// Check if enemy intersects with character
if (enemy.intersects(character) && Math.sqrt(Math.pow(enemy.x - character.x, 2) + Math.pow(enemy.y - character.y, 2)) < 200 && !character.isImmune && !(Math.abs(character.x - holeTile.x) < 75 && Math.abs(character.y - holeTile.y) < 75)) {
// Reduce character lives by 1
availableLives -= 1;
// Update lives display and make live icons disappear when player gets hit
// Update lives display and make live icons disappear when player loses a life
livesIcons.forEach(function (icon, index) {
icon.visible = index < availableLives;
});
// Make character blink to indicate damage and grant temporary immunity
character.isImmune = true; // Set immunity flag to true
var blinkInterval = LK.setInterval(function () {
character.visible = !character.visible;
// Removed tint logic
}, 100);
LK.setTimeout(function () {
LK.clearInterval(blinkInterval);
character.visible = true;
// Reset tint to normal after blinking
character.tint = 0xffffff;
character.isImmune = false; // Remove immunity after 1 second
}, 1000);
// Check if lives are depleted or all cheeses have been delivered to win the game
if (availableLives <= 0) {
character.visible = false; // Make character invisible
LK.setTimeout(function () {
LK.showGameOver("You've been caught! Better luck next time.");
}, 1000); // Wait one second before showing game over
} // Removed win game logic based on cheese delivery
}
});
});
spawnCheeses();
// Create instances of enemies and store them in an array
var enemies = [];
// Removed two Roomba enemies
// Position enemies
// Position Roombas on opposite sides of the grid
if (enemies[0]) {
// Position the first Roomba on the left side
enemies[0].x = floorTiles[0].x;
enemies[0].y = floorTiles[0].y;
}
if (enemies[1]) {
// Position the second Roomba on the right side
var lastTileIndex = floorTiles.length - 1;
enemies[1].x = floorTiles[lastTileIndex].x;
enemies[1].y = floorTiles[lastTileIndex].y;
}
// Function to select a new target tile avoiding obstacles
function selectNewTargetTileAvoidingObstacles(currentX, currentY, floorTiles, obstacleTiles) {
// Placeholder for pathfinding logic to select a new target tile
// For simplicity, this example randomly selects a floor tile not in the obstacleTiles array
var validTiles = floorTiles.filter(function (tile) {
return !obstacleTiles.includes(tile);
});
if (validTiles.length > 0) {
var randomIndex = Math.floor(Math.random() * validTiles.length);
return validTiles[randomIndex];
} else {
console.error('No valid tiles found to move to.');
return null; // Return null if no valid tiles are found
}
}
// Define a function to get the tile at a given position
function getTileAtPosition(x, y) {
var index = Math.floor(y / 100) * gridSize + Math.floor(x / 100);
if (index >= 0 && index < grid.length && grid[index]) {
return grid[index];
} else {
console.error('Tile at position', x, y, 'is out of bounds or null.');
return undefined; // Return undefined to indicate no tile found or out of bounds without error
}
}
grey square, black border. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
simple light yellow button front view game console, clean, rounded edges, high resolution, graphic. Single Game Texture. In-Game asset. 2d. Blank background. High contrast.
Worn out sticker for a video game, 90s style, cheese, simple, vintage. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
wall view from top-down, game asset videogame, black color, simple. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows. worn out sticker. 90's style. vintage. simple. top-down view. poster. sticker
top-down view, videogame character enemy, roomba, 90s style sticker, flat, no perspective, silhouette, black and white, cartoon, fun, simple, from above. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
top-down view, videogame heart, 90s style sticker, flat, no perspective, silhouette, white, cartoon, fun, simple, from above. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Black square with white outline. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.