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: 683
User prompt
Remove direct tile placement creation calls, let the games elements initialization method handle it
User prompt
Remove any direct calls for grid creation, let the game elements initialization method handle it only
User prompt
Ensure no direct creation calls are happening for game elements
User prompt
Please fix the bug: 'createAndPositionCheeses is not defined' in or related to this line: 'createAndPositionCheeses();' Line Number: 313
User prompt
Please fix the bug: 'Timeout.tick error: createAndPositionCheeses is not defined' in or related to this line: 'createAndPositionCheeses();' Line Number: 313
User prompt
Please fix the bug: 'Timeout.tick error: positionEnemies is not defined' in or related to this line: 'positionEnemies();' Line Number: 297
User prompt
Create a method handles the creation of game elements (character, grid, enemies and cheeses) using the existing code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'x')' in or related to this line: 'var flyingCheese = game.addChild(LK.getAsset('cheese', {' Line Number: 499
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'x')' in or related to this line: 'var flyingCheese = game.addChild(LK.getAsset('cheese', {' Line Number: 499
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'x')' in or related to this line: 'var flyingCheese = game.addChild(LK.getAsset('cheese', {' Line Number: 499
User prompt
Check null errors for character and flying cheese
User prompt
On game elements initialization make sure only 2 Roomba are spawned and that the code is not recursive
User prompt
Please fix the bug: 'Uncaught ReferenceError: EventManager is not defined' in or related to this line: 'game.eventManager = EventManager;' Line Number: 303
User prompt
Delete event manager implementation and all events in game
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'subscribe')' in or related to this line: 'game.eventManager.subscribe('gameStart', finalizeGameSetup);' Line Number: 303
User prompt
Debug code base to ensure correct game element initialization from a single method
User prompt
Delete event man
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'subscribe')' in or related to this line: 'game.eventManager.subscribe('gameStart', finalizeGameSetup);' Line Number: 303
User prompt
Refactor the codabase to support a single method for game elements initialization
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'subscribe')' in or related to this line: 'game.eventManager.subscribe('gameStart', finalizeGameSetup);' Line Number: 299
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'subscribe')' in or related to this line: 'game.eventManager.subscribe('gameStart', finalizeGameSetup);' Line Number: 299
User prompt
Please fix the bug: 'Uncaught ReferenceError: initializeCharacter is not defined' in or related to this line: 'initializeCharacter();' Line Number: 297
User prompt
Please fix the bug: 'Uncaught ReferenceError: initializeEnemies is not defined' in or related to this line: 'initializeEnemies();' Line Number: 295
User prompt
Please fix the bug: 'Uncaught ReferenceError: placeCheeses is not defined' in or related to this line: 'placeCheeses();' Line Number: 289
/**** * Classes ****/ // Initialize screen dimensions var Cheese = Container.expand(function () { var self = Container.call(this); // Attach cheese asset with anchor point set to center var cheeseShadow = self.attachAsset('characterShadow', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6, alpha: 0.5, y: 50 }); var cheeseGraphics = self.attachAsset('cheese', { anchorX: 0.5, anchorY: 0.5 // zIndex removed }); // Lerp cheese to a target position self.lerpToPosition = function (startPos, endPos, duration, onComplete) { self.x = endPos.x; self.y = endPos.y; if (onComplete) { onComplete(); } }; }); // Modular Enemy class to support different enemy types var Enemy = Container.expand(function (type) { var self = Container.call(this); var shadowAssetId, enemyAssetId, shadowScale, enemySpeed; // Enemy type enumerator with stats var EnemyTypes = { Roomba: { shadowAssetId: 'CircularShadow', enemyAssetId: 'Roomba', shadowScale: 3.2, enemySpeed: 2.64 } // Define additional enemy types here }; // Retrieve enemy type stats 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; // Attach a shadow asset to the enemy and make it semitransparent var shadowGraphics = self.attachAsset(shadowAssetId, { anchorX: 0.5, anchorY: 0.5, alpha: 0.5, scaleX: shadowScale, scaleY: shadowScale // zIndex removed }); var enemyGraphics = self.attachAsset(enemyAssetId, { anchorX: 0.5, anchorY: 0.5 // zIndex removed }); // 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 () { // Implement avoidance behavior for Roombas enemies.forEach(function (otherEnemy) { if (otherEnemy !== self) { var dx = self.x - otherEnemy.x; var dy = self.y - otherEnemy.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { // Calculate direction to move away from the other Roomba var awayX = dx / distance; var awayY = dy / distance; self.x += awayX * self.speed; // Move self away from the other Roomba self.y += awayY * self.speed; } } }); // 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; }; }); // 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 ****/ // Function to place cheeses in the game function placeCheeses() { // Logic to place cheeses at specific locations } // Centralized game initialization method function initializeGameElements() { // Initialize screen dimensions LK.screen = { width: 2048, height: 2732 }; // 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, y: 1880 }); game.addChild(gameLogo); // Initialize the on-screen controller var onScreenController = game.addChild(new OnScreenController()); // Create tiles for the game environment createTiles(); // Place cheeses in the game placeCheeses(); // Initialize enemies initializeEnemies(); // Initialize the character initializeCharacter(); // Subscribe to 'gameStart' event to finalize game setup game.eventManager.subscribe('gameStart', finalizeGameSetup); } // Invoke the centralized game initialization method initializeGameElements(); // Method to check if all cheeses have been delivered function allCheesesDelivered() { // Destroy all cheeses cheeses.forEach(function (cheese) { cheese.destroy(); }); cheeses = []; // Clear the cheeses array // Destroy all enemies enemies.forEach(function (enemy) { enemy.destroy(); }); enemies = []; // Clear the enemies array // Destroy the character and its shadow if (character) { character.destroy(); character = null; } // Remove any remaining game elements like tiles floorTiles.forEach(function (tile) { tile.destroy(); }); floorTiles = []; // Clear the floorTiles array wallTiles.forEach(function (tile) { tile.destroy(); }); wallTiles = []; // Clear the wallTiles array if (holeTile) { holeTile.destroy(); holeTile = null; } } // This code block has been moved outside the game elements initialization var dakaloText = new Text2('@Dakalo777', { size: 50, fill: "#FFA500", x: LK.screen.width, y: LK.screen.height }); dakaloText.anchor.set(1.2, 1.2); // 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: 2300, // Considering half of the sticker's height for proper alignment rotation: 0.10 // Rotating 32 degrees in radians }); 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; character = LK.getAsset('character', { anchorX: 0.5, anchorY: 0.5, x: holeTile.x, y: holeTile.y - 50, scaleX: 1.5, scaleY: 1.5 }); // Force UI refresh window.updateCheeseScore(LK.getScore()); }); // 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 = 200, scoreBoardY = 125; var cheeseIconForScore = window.scoreBoardContainer.attachAsset('cheese', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5, x: 20, y: 0 }); // Dynamically add one character lives icon per available life var availableLives = 3; // Assuming 3 lives to start with var livesIcons = []; for (var i = 0; i < availableLives; i++) { var lifeIcon = window.scoreBoardContainer.attachAsset('characterLivesIcon', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, // Scale increased to make the icon 3 times bigger scaleY: 1.5, // Scale increased to make the icon 3 times bigger x: 1000 - i * 90, // Position each icon with a gap of 80px y: 0 }); livesIcons.push(lifeIcon); } // Cheese score display added to the scoreboard var cheeseScoreDisplay = new Text2('0', { size: 50, fill: "#E0E0E0", font: "Roboto, bold", x: cheeseIconForScore.x + 120, y: cheeseIconForScore.y }); cheeseScoreDisplay.anchor.set(-2.5, 0.7); window.scoreBoardContainer.addChild(cheeseScoreDisplay); // Update cheese score display function window.updateCheeseScore = updateCheeseScore; // 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: 50 }); playTimeDisplay.anchor.set(-5, 0.45); // Center the text horizontally window.scoreBoardContainer.addChild(playTimeDisplay); window.scoreBoardContainer.x = scoreBoardX; window.scoreBoardContainer.y = scoreBoardY; LK.gui.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) { 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 var flyingCheese = game.addChild(LK.getAsset('cheese', { anchorX: 0.5, anchorY: 0.5, x: character.x, y: character.y, scaleX: 1.0, // Scale up by 100% scaleY: 1.0 // Scale up by 100% })); var scoreBoardPos = { x: window.scoreBoardContainer.x + cheeseIconForScore.x, y: window.scoreBoardContainer.y + cheeseIconForScore.y }; 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 = character.x + (scoreBoardPos.x - character.x) * progress; flyingCheese.y = character.y + (scoreBoardPos.y - character.y) * progress; // Calculate the angle to rotate the flying cheese towards the scoreboard and add 180 degrees for rotation var angle = Math.atan2(scoreBoardPos.y - character.y, scoreBoardPos.x - character.x) + Math.PI; flyingCheese.rotation = angle; } else { game.removeChild(flyingCheese); window.updateCheeseScore(LK.getScore()); // Update displayed score } }); } 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.5, // Scale down by 50% scaleY: 0.5, // 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) { 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; } 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 var gridSize = 10; var character; var totalCheeses = 3; // Define total number of cheeses in the game var cheeses = []; // Initialize cheeses array globally var cheeseIcon; // Declare cheeseIcon as a global variable 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); for (var i = 0; i < gridSize * gridSize; i++) { var x = i % gridSize; var y = Math.floor(i / gridSize); var tile; 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 - 1)) / 2; // Adjust grid offset to account for new tile width var gridOffsetY = (LK.screen.height - tileHeight * (gridSize - 1)) / 2 - LK.screen.height * 0.15; // Adjust grid offset to account for new tile height if (!(x === 0 || y === 0 || x === gridSize - 1 || y === gridSize - 1)) { tile = LK.getAsset('floorTile', { anchorX: 0.5, anchorY: 0.5, x: x * tileWidth + gridOffsetX, y: y * tileHeight + gridOffsetY }); // Randomly replace some floor tiles with obstacle tiles, ensuring at least one valid path remains // Placeholder logic for path validation and obstacle placement if (Math.random() < 0.3 && !(x === 1 || y === 1 || x === gridSize - 2 || y === gridSize - 2)) { // Obstacle tile creation logic removed to ensure no obstacles are added to the game } else { floorTiles.push(tile); game.addChild(tile); grid[i] = tile; } // Note: The function isTileBlockingPath() needs to be implemented to check if placing an obstacle would block all paths to cheeses or the hole } } // 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 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 function isTileInCorner(tile) { var corners = [{ x: gridOffsetX, y: gridOffsetY }, { x: gridOffsetX, y: gridOffsetY + tileHeight * (gridSize - 1) }, { x: gridOffsetX + tileWidth * (gridSize - 1), y: gridOffsetY }, { x: gridOffsetX + tileWidth * (gridSize - 1), y: gridOffsetY + tileHeight * (gridSize - 1) }]; return corners.some(function (corner) { return Math.abs(tile.x - corner.x) < tileWidth / 2 && Math.abs(tile.y - corner.y) < tileHeight / 2; }); } // Filter out corner wall tiles before selecting a random wall tile for the hole var nonCornerWallTiles = wallTiles.filter(function (tile) { return !isTileInCorner(tile); }); var randomWallTile = nonCornerWallTiles[Math.floor(Math.random() * nonCornerWallTiles.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); var currentCheesePosition = { x: 0, y: 0 }; // Initialize variable to store cheese position // Initialize cheese instances to place them on the floor cheeses.push(game.addChild(new Cheese())); cheeses.push(game.addChild(new Cheese())); cheeses.push(game.addChild(new Cheese())); if (!cheesePlaced) { // Ensure cheese is initialized before accessing its properties // Since cheeses are now handled as an array, we iterate over them to save their positions cheeses.forEach(function (cheese) { currentCheesePosition.x = cheese.x; // Save current cheese x position currentCheesePosition.y = cheese.y; // Save current cheese y position }); // Filter out tiles that are too close to corners var nonCornerFloorTiles = floorTiles.filter(function (tile) { return !isTileInCorner(tile); }); // Further filter to find tiles farthest from the character's starting position var farthestTiles = nonCornerFloorTiles.filter(function (tile) { var distanceToCharacter = Math.sqrt(Math.pow(tile.x - character.x, 2) + Math.pow(tile.y - character.y, 2)); return distanceToCharacter > LK.screen.width / 2; // Arbitrary distance threshold }); // If no tile is found far enough (unlikely but possible), default to non-corner tiles var targetTiles = farthestTiles.length > 0 ? farthestTiles : nonCornerFloorTiles; // Select a random tile from the final list var randomFloorTile = targetTiles[Math.floor(Math.random() * targetTiles.length)]; // Correctly iterate over cheeses array to place each cheese on a unique random floor tile cheeses.forEach(function (cheese) { // Ensure a unique tile is selected for each 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) { // Check if a tile was successfully selected cheese.x = uniqueFloorTile.x; cheese.y = uniqueFloorTile.y; } }); cheesePlaced = true; // Indicate that cheeses have been placed } var characterShadow = LK.getAsset('characterShadow', { anchorX: 0.5, anchorY: 0.5, x: -15, y: 50, scaleX: 0.6, scaleY: 0.6, alpha: 0.5 // zIndex removed }); character.addChild(characterShadow); 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; // Tint character red when hit character.tint = character.visible ? 0xff0000 : 0xffffff; }, 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 } }); }); // 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; } // 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); return grid[index]; }
/****
* Classes
****/
// Initialize screen dimensions
var Cheese = Container.expand(function () {
var self = Container.call(this);
// Attach cheese asset with anchor point set to center
var cheeseShadow = self.attachAsset('characterShadow', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
alpha: 0.5,
y: 50
});
var cheeseGraphics = self.attachAsset('cheese', {
anchorX: 0.5,
anchorY: 0.5
// zIndex removed
});
// Lerp cheese to a target position
self.lerpToPosition = function (startPos, endPos, duration, onComplete) {
self.x = endPos.x;
self.y = endPos.y;
if (onComplete) {
onComplete();
}
};
});
// Modular Enemy class to support different enemy types
var Enemy = Container.expand(function (type) {
var self = Container.call(this);
var shadowAssetId, enemyAssetId, shadowScale, enemySpeed;
// Enemy type enumerator with stats
var EnemyTypes = {
Roomba: {
shadowAssetId: 'CircularShadow',
enemyAssetId: 'Roomba',
shadowScale: 3.2,
enemySpeed: 2.64
}
// Define additional enemy types here
};
// Retrieve enemy type stats
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;
// Attach a shadow asset to the enemy and make it semitransparent
var shadowGraphics = self.attachAsset(shadowAssetId, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5,
scaleX: shadowScale,
scaleY: shadowScale
// zIndex removed
});
var enemyGraphics = self.attachAsset(enemyAssetId, {
anchorX: 0.5,
anchorY: 0.5
// zIndex removed
});
// 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 () {
// Implement avoidance behavior for Roombas
enemies.forEach(function (otherEnemy) {
if (otherEnemy !== self) {
var dx = self.x - otherEnemy.x;
var dy = self.y - otherEnemy.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Calculate direction to move away from the other Roomba
var awayX = dx / distance;
var awayY = dy / distance;
self.x += awayX * self.speed; // Move self away from the other Roomba
self.y += awayY * self.speed;
}
}
});
// 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;
};
});
// 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
****/
// Function to place cheeses in the game
function placeCheeses() {
// Logic to place cheeses at specific locations
}
// Centralized game initialization method
function initializeGameElements() {
// Initialize screen dimensions
LK.screen = {
width: 2048,
height: 2732
};
// 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,
y: 1880
});
game.addChild(gameLogo);
// Initialize the on-screen controller
var onScreenController = game.addChild(new OnScreenController());
// Create tiles for the game environment
createTiles();
// Place cheeses in the game
placeCheeses();
// Initialize enemies
initializeEnemies();
// Initialize the character
initializeCharacter();
// Subscribe to 'gameStart' event to finalize game setup
game.eventManager.subscribe('gameStart', finalizeGameSetup);
}
// Invoke the centralized game initialization method
initializeGameElements();
// Method to check if all cheeses have been delivered
function allCheesesDelivered() {
// Destroy all cheeses
cheeses.forEach(function (cheese) {
cheese.destroy();
});
cheeses = []; // Clear the cheeses array
// Destroy all enemies
enemies.forEach(function (enemy) {
enemy.destroy();
});
enemies = []; // Clear the enemies array
// Destroy the character and its shadow
if (character) {
character.destroy();
character = null;
}
// Remove any remaining game elements like tiles
floorTiles.forEach(function (tile) {
tile.destroy();
});
floorTiles = []; // Clear the floorTiles array
wallTiles.forEach(function (tile) {
tile.destroy();
});
wallTiles = []; // Clear the wallTiles array
if (holeTile) {
holeTile.destroy();
holeTile = null;
}
}
// This code block has been moved outside the game elements initialization
var dakaloText = new Text2('@Dakalo777', {
size: 50,
fill: "#FFA500",
x: LK.screen.width,
y: LK.screen.height
});
dakaloText.anchor.set(1.2, 1.2); // 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: 2300,
// Considering half of the sticker's height for proper alignment
rotation: 0.10 // Rotating 32 degrees in radians
});
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;
character = LK.getAsset('character', {
anchorX: 0.5,
anchorY: 0.5,
x: holeTile.x,
y: holeTile.y - 50,
scaleX: 1.5,
scaleY: 1.5
});
// Force UI refresh
window.updateCheeseScore(LK.getScore());
});
// 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 = 200,
scoreBoardY = 125;
var cheeseIconForScore = window.scoreBoardContainer.attachAsset('cheese', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
x: 20,
y: 0
});
// Dynamically add one character lives icon per available life
var availableLives = 3; // Assuming 3 lives to start with
var livesIcons = [];
for (var i = 0; i < availableLives; i++) {
var lifeIcon = window.scoreBoardContainer.attachAsset('characterLivesIcon', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
// Scale increased to make the icon 3 times bigger
scaleY: 1.5,
// Scale increased to make the icon 3 times bigger
x: 1000 - i * 90,
// Position each icon with a gap of 80px
y: 0
});
livesIcons.push(lifeIcon);
}
// Cheese score display added to the scoreboard
var cheeseScoreDisplay = new Text2('0', {
size: 50,
fill: "#E0E0E0",
font: "Roboto, bold",
x: cheeseIconForScore.x + 120,
y: cheeseIconForScore.y
});
cheeseScoreDisplay.anchor.set(-2.5, 0.7);
window.scoreBoardContainer.addChild(cheeseScoreDisplay);
// Update cheese score display function
window.updateCheeseScore = updateCheeseScore;
// 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: 50
});
playTimeDisplay.anchor.set(-5, 0.45); // Center the text horizontally
window.scoreBoardContainer.addChild(playTimeDisplay);
window.scoreBoardContainer.x = scoreBoardX;
window.scoreBoardContainer.y = scoreBoardY;
LK.gui.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) {
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
var flyingCheese = game.addChild(LK.getAsset('cheese', {
anchorX: 0.5,
anchorY: 0.5,
x: character.x,
y: character.y,
scaleX: 1.0,
// Scale up by 100%
scaleY: 1.0 // Scale up by 100%
}));
var scoreBoardPos = {
x: window.scoreBoardContainer.x + cheeseIconForScore.x,
y: window.scoreBoardContainer.y + cheeseIconForScore.y
};
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 = character.x + (scoreBoardPos.x - character.x) * progress;
flyingCheese.y = character.y + (scoreBoardPos.y - character.y) * progress;
// Calculate the angle to rotate the flying cheese towards the scoreboard and add 180 degrees for rotation
var angle = Math.atan2(scoreBoardPos.y - character.y, scoreBoardPos.x - character.x) + Math.PI;
flyingCheese.rotation = angle;
} else {
game.removeChild(flyingCheese);
window.updateCheeseScore(LK.getScore()); // Update displayed score
}
});
} 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.5,
// Scale down by 50%
scaleY: 0.5,
// 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) {
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;
}
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
var gridSize = 10;
var character;
var totalCheeses = 3; // Define total number of cheeses in the game
var cheeses = []; // Initialize cheeses array globally
var cheeseIcon; // Declare cheeseIcon as a global variable
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);
for (var i = 0; i < gridSize * gridSize; i++) {
var x = i % gridSize;
var y = Math.floor(i / gridSize);
var tile;
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 - 1)) / 2; // Adjust grid offset to account for new tile width
var gridOffsetY = (LK.screen.height - tileHeight * (gridSize - 1)) / 2 - LK.screen.height * 0.15; // Adjust grid offset to account for new tile height
if (!(x === 0 || y === 0 || x === gridSize - 1 || y === gridSize - 1)) {
tile = LK.getAsset('floorTile', {
anchorX: 0.5,
anchorY: 0.5,
x: x * tileWidth + gridOffsetX,
y: y * tileHeight + gridOffsetY
});
// Randomly replace some floor tiles with obstacle tiles, ensuring at least one valid path remains
// Placeholder logic for path validation and obstacle placement
if (Math.random() < 0.3 && !(x === 1 || y === 1 || x === gridSize - 2 || y === gridSize - 2)) {
// Obstacle tile creation logic removed to ensure no obstacles are added to the game
} else {
floorTiles.push(tile);
game.addChild(tile);
grid[i] = tile;
}
// Note: The function isTileBlockingPath() needs to be implemented to check if placing an obstacle would block all paths to cheeses or the hole
}
}
// 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 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
function isTileInCorner(tile) {
var corners = [{
x: gridOffsetX,
y: gridOffsetY
}, {
x: gridOffsetX,
y: gridOffsetY + tileHeight * (gridSize - 1)
}, {
x: gridOffsetX + tileWidth * (gridSize - 1),
y: gridOffsetY
}, {
x: gridOffsetX + tileWidth * (gridSize - 1),
y: gridOffsetY + tileHeight * (gridSize - 1)
}];
return corners.some(function (corner) {
return Math.abs(tile.x - corner.x) < tileWidth / 2 && Math.abs(tile.y - corner.y) < tileHeight / 2;
});
}
// Filter out corner wall tiles before selecting a random wall tile for the hole
var nonCornerWallTiles = wallTiles.filter(function (tile) {
return !isTileInCorner(tile);
});
var randomWallTile = nonCornerWallTiles[Math.floor(Math.random() * nonCornerWallTiles.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);
var currentCheesePosition = {
x: 0,
y: 0
}; // Initialize variable to store cheese position
// Initialize cheese instances to place them on the floor
cheeses.push(game.addChild(new Cheese()));
cheeses.push(game.addChild(new Cheese()));
cheeses.push(game.addChild(new Cheese()));
if (!cheesePlaced) {
// Ensure cheese is initialized before accessing its properties
// Since cheeses are now handled as an array, we iterate over them to save their positions
cheeses.forEach(function (cheese) {
currentCheesePosition.x = cheese.x; // Save current cheese x position
currentCheesePosition.y = cheese.y; // Save current cheese y position
});
// Filter out tiles that are too close to corners
var nonCornerFloorTiles = floorTiles.filter(function (tile) {
return !isTileInCorner(tile);
});
// Further filter to find tiles farthest from the character's starting position
var farthestTiles = nonCornerFloorTiles.filter(function (tile) {
var distanceToCharacter = Math.sqrt(Math.pow(tile.x - character.x, 2) + Math.pow(tile.y - character.y, 2));
return distanceToCharacter > LK.screen.width / 2; // Arbitrary distance threshold
});
// If no tile is found far enough (unlikely but possible), default to non-corner tiles
var targetTiles = farthestTiles.length > 0 ? farthestTiles : nonCornerFloorTiles;
// Select a random tile from the final list
var randomFloorTile = targetTiles[Math.floor(Math.random() * targetTiles.length)];
// Correctly iterate over cheeses array to place each cheese on a unique random floor tile
cheeses.forEach(function (cheese) {
// Ensure a unique tile is selected for each 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) {
// Check if a tile was successfully selected
cheese.x = uniqueFloorTile.x;
cheese.y = uniqueFloorTile.y;
}
});
cheesePlaced = true; // Indicate that cheeses have been placed
}
var characterShadow = LK.getAsset('characterShadow', {
anchorX: 0.5,
anchorY: 0.5,
x: -15,
y: 50,
scaleX: 0.6,
scaleY: 0.6,
alpha: 0.5
// zIndex removed
});
character.addChild(characterShadow);
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;
// Tint character red when hit
character.tint = character.visible ? 0xff0000 : 0xffffff;
}, 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
}
});
});
// 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;
}
// 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);
return grid[index];
}
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.