User prompt
Create a variable to keep track of the collected cheeses
User prompt
Shuffle the obstacles with the last cheese is collected
User prompt
After all cheese are collected restart the game but keep the current score
User prompt
Debug the restarting logic
User prompt
When all available cheeses are collected and scored restart the level
User prompt
Use the score as the reference to restart the level
User prompt
Debug the restart behavior
User prompt
Restart the level when all cheese have been scored, increase Roomba speed a bit and chance the obstacles
User prompt
Restart the level until the last available cheese is scored
User prompt
If there are no more cheese to be collected restart the level.but keep the score and increase he Roomba movement
User prompt
Add feedback when player score points
User prompt
Re enable the visibility of the collected cheese once the player score
User prompt
Ensure only one cheese can be picked up at a time, and only until that cheese is collected and scored another cheese can be picked up
User prompt
Place the collected cheese on the hole
User prompt
Enable the visibility of the collected cheese when scored
User prompt
Enable the visibility of the collected cheese
User prompt
Remove lerping on the cheese logic
User prompt
Debug the hole tile checking corners a voidance and make sure to use grid offsets
User prompt
Debug hole tile placement logic, make sure to include grid offsets on the calculations
User prompt
Debug the hole tile logic
User prompt
Debug the hole tile placement logic, hole tiles cannot spawn on corners or have 2 empty neighbors
User prompt
Replace the cheese shadow for the character shadow
User prompt
Debug cheese collection logic for the icon, lerping and the cheese asset
User prompt
Avoid that the hole tile has more than 1 empty neighbor
User prompt
Please fix the bug: 'ReferenceError: cheese is not defined' in or related to this line: 'isCharacterMoving = cheese.isMoving ? false : true;' Line Number: 217
/****
* Classes
****/
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) {
var startTime = Date.now();
var lerpInterval = LK.setInterval(function () {
var currentTime = Date.now();
var timeElapsed = currentTime - startTime;
var lerpFactor = timeElapsed / duration;
if (lerpFactor >= 1) {
LK.clearInterval(lerpInterval);
self.x = endPos.x;
self.y = endPos.y;
if (onComplete) {
onComplete();
}
} else {
self.x = startPos.x + (endPos.x - startPos.x) * lerpFactor;
self.y = startPos.y + (endPos.y - startPos.y) * lerpFactor;
}
}, 16); // Update approximately every 16ms (~60fps)
};
});
// 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,
// Tint arrow yellow
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 check if a new obstacle tile fully surrounds any cheese
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;
});
});
});
}
// Function to check if placing a tile would block all paths to cheeses or the hole
function isTileBlockingPath(tile, cheeses, holeTile) {
// Placeholder for path checking logic
// This should implement an algorithm to check if any cheese or the holeTile is unreachable due to the new tile
// For simplicity, this example will just return false indicating the tile placement doesn't block the path
// Implement actual path checking logic here
return false;
}
// 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: 2200,
y: 2100,
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;
// EventManager class for centralized event handling
// 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: -35,
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: 1070 - i * 120,
// 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(-.4, 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(-3, 0.5); // Center the text horizontally
window.scoreBoardContainer.addChild(playTimeDisplay);
window.scoreBoardContainer.x = scoreBoardX;
window.scoreBoardContainer.y = scoreBoardY;
LK.gui.addChild(window.scoreBoardContainer);
window.scoreBoardInitialized = true;
}
// Update score dynamically without recreating the scoreboard elements
// Update score dynamically without recreating the scoreboard elements
// This block intentionally left blank to signify removal of the above code
// 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());
// Event listener for A button press to pick up the cheese using a refined proximity check and method encapsulation
onScreenController.aButton.on('down', function () {
// Check if character is near any cheese to pick it up
cheeses.forEach(function (cheese) {
if (isWithinProximity(character, cheese, 75) && !cheese.collected) {
console.log('Cheese picked up!');
cheese.visible = false; // Hide the picked cheese from the game
cheese.collected = true; // Mark cheese as collected
// Increment availableCheeses count when a cheese is picked up
availableCheeses += 1;
// Update cheeseIcon visibility based on availableCheeses count
if (availableCheeses > 0) {
if (!cheeseIcon) {
cheeseIcon = character.attachAsset('cheese', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -character.height * 0.75,
scaleX: 0.5,
scaleY: 0.5
});
}
cheeseIcon.visible = true;
}
}
});
// Check if character is on the hole tile to drop off collected cheese
if (isWithinProximity(character, holeTile, 75) && cheeseIcon && cheeseIcon.visible) {
console.log('Cheese placed on hole tile!');
cheeseIcon.visible = false; // Hide cheese icon on character after moving to scoreboard
// Increase score for each cheese collected and not yet scored
cheeses.forEach(function (cheese) {
if (cheese.collected && !cheese.scoreCounted) {
LK.setScore(LK.getScore() + 1); // Add one to the score for each cheese collected
cheese.scoreCounted = true; // Mark cheese as counted to prevent scoring it again
window.updateCheeseScore(LK.getScore()); // Update cheese score display
}
});
}
});
// 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 (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 cheeses = []; // Initialize cheeses array globally
var availableCheeses = 0; // Initialize variable to track available cheeses for collection
var cheeseScore = 0; // Initialize cheese score variable
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.8,
x: LK.screen.width / 2,
y: LK.screen.height / 2,
width: LK.screen.width * .9,
height: LK.screen.height * .6,
tint: 0xFFA500 // Apply orange tint
});
game.addChild(gridBackground);
var gridBackgroundShrunk = LK.getAsset('gridBackground', {
anchorX: 0.5,
anchorY: 0.8,
x: LK.screen.width / 2,
y: LK.screen.height / 2,
width: LK.screen.width * .9 - 50,
height: LK.screen.height * .6 - 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)) {
// Temporarily turn a tile into an obstacle to check if it blocks any path
var tempObstacleTile = LK.getAsset('obstacleTile', {
anchorX: 0.5,
anchorY: 0.5,
x: x * tileWidth + gridOffsetX,
y: y * tileHeight + gridOffsetY
});
// Check if the temporary obstacle tile blocks the path or fully surrounds any cheese
var blocksPathOrSurroundsCheese = isTileBlockingPath(tempObstacleTile, cheeses, holeTile) || doesTileSurroundCheese(tempObstacleTile, cheeses);
if (!blocksPathOrSurroundsCheese) {
// If it doesn't block the path or fully surround any cheese, add it to the game
game.addChild(tempObstacleTile);
grid[i] = tempObstacleTile;
} else {
// If it blocks the path or fully surrounds any cheese, revert to a floor tile
floorTiles.push(tile);
game.addChild(tile);
grid[i] = tile;
}
} 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 fully surrounds the hole
function doesTileSurroundHole(tile, wallTiles, obstacleTiles) {
// Placeholder for logic to check if the tile surrounds the hole
// This should implement an algorithm to check if the hole is fully surrounded by walls or obstacles due to the new tile
// For simplicity, this example will just return false indicating the tile placement doesn't surround the hole
// Implement actual surrounding checking logic here
return false;
}
// Function to check if a tile is in a corner
function isTileInCorner(tile) {
var corners = [{
x: LK.screen.width / 2 - tileWidth * gridSize / 2,
y: LK.screen.height / 2 - tileHeight * gridSize / 2
}, {
x: LK.screen.width / 2 - tileWidth * gridSize / 2,
y: LK.screen.height / 2 + tileHeight * (gridSize - 1) / 2
}, {
x: LK.screen.width / 2 + tileWidth * (gridSize - 1) / 2,
y: LK.screen.height / 2 - tileHeight * gridSize / 2
}, {
x: LK.screen.width / 2 + tileWidth * (gridSize - 1) / 2,
y: LK.screen.height / 2 + tileHeight * (gridSize - 1) / 2
}];
return corners.some(function (corner) {
return Math.abs(tile.x - corner.x) < tileWidth / 2 && Math.abs(tile.y - corner.y) < tileHeight / 2;
});
}
// Select a random wall tile and replace it with a hole tile, ensuring it's not in a corner
var validWallTiles = wallTiles.filter(function (tile) {
// Exclude tiles that are in the corners or could potentially fully surround the hole tile
return !isTileInCorner(tile) && !doesTileSurroundHole(tile, wallTiles, obstacleTiles) && function () {
// Count empty neighbors around the tile
var emptyNeighbors = 0;
var neighborOffsets = [[-1, 0], [1, 0], [0, -1], [0, 1]];
neighborOffsets.forEach(function (offset) {
var neighborX = tile.x / tileWidth + offset[0];
var neighborY = tile.y / tileHeight + offset[1];
if (neighborX >= 0 && neighborX < gridSize && neighborY >= 0 && neighborY < gridSize) {
var neighborIndex = neighborY * gridSize + neighborX;
if (!wallTiles.some(function (wall) {
return wall.x === neighborX * tileWidth && wall.y === neighborY * tileHeight;
}) && !obstacleTiles.some(function (obstacle) {
return obstacle.x === neighborX * tileWidth && obstacle.y === neighborY * tileHeight;
}) && !grid[neighborIndex]) {
emptyNeighbors++;
}
}
});
// Ensure hole tiles do not have 2 empty neighbors to avoid spawning in corners or with 2 empty neighbors
return emptyNeighbors <= 1;
}();
});
var randomWallTile = validWallTiles[Math.floor(Math.random() * validWallTiles.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);
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
if (availableLives <= 0) {
character.visible = false; // Make character invisible
LK.setTimeout(function () {
// Convert playTime to minutes and seconds
var minutes = Math.floor(playTime / 60);
var seconds = playTime % 60;
var formattedTime = (minutes < 10 ? '0' : '') + minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
// Show game over pop up with final play time
LK.showGameOver("Final Time: " + formattedTime);
}, 1000); // Wait one second before showing game over
}
}
});
});
// Create instances of enemies and store them in an array
var enemies = [];
// Create instances of enemies and store them in an array
enemies.push(game.addChild(new Enemy('Roomba')));
enemies.push(game.addChild(new Enemy('Roomba')));
// 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];
} ===================================================================
--- original.js
+++ change.js
@@ -648,15 +648,15 @@
if (!wallTiles.some(function (wall) {
return wall.x === neighborX * tileWidth && wall.y === neighborY * tileHeight;
}) && !obstacleTiles.some(function (obstacle) {
return obstacle.x === neighborX * tileWidth && obstacle.y === neighborY * tileHeight;
- })) {
+ }) && !grid[neighborIndex]) {
emptyNeighbors++;
}
}
});
// Ensure hole tiles do not have 2 empty neighbors to avoid spawning in corners or with 2 empty neighbors
- return emptyNeighbors < 2;
+ return emptyNeighbors <= 1;
}();
});
var randomWallTile = validWallTiles[Math.floor(Math.random() * validWallTiles.length)];
var holeTile = LK.getAsset('holeTile', {
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.