johnny961's picture
game up
75ffe4b
raw
history blame
20.4 kB
<!DOCTYPE html>
<html>
<head>
<title>Apartment Simulator Level Editor</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script>
<style>
body {
margin: 0;
display: flex;
flex-direction: column;
align-items: center;
font-family: Arial, sans-serif;
}
#controls {
margin: 10px;
padding: 10px;
background: #f0f0f0;
border-radius: 5px;
}
button {
margin: 0 5px;
padding: 5px 10px;
cursor: pointer;
}
select, input[type="number"] {
margin: 0 5px;
padding: 5px;
}
.active {
background: #4CAF50;
color: white;
}
</style>
</head>
<body>
<div id="controls">
<button id="wallBtn" onclick="setTool('wall')">Wall</button>
<button id="doorBtn" onclick="setTool('door')">Door</button>
<button id="eraseBtn" onclick="setTool('erase')">Erase</button>
<button id="characterBtn" onclick="setTool('character')">Place Character</button>
|
<button id="yellowBtn" onclick="setTool('yellow')" style="background-color: #ffeb3b">Yellow</button>
<button id="blueBtn" onclick="setTool('blue')" style="background-color: #2196f3">Blue</button>
<button id="greenBtn" onclick="setTool('green')" style="background-color: #4caf50">Green</button>
<button id="redBtn" onclick="setTool('red')" style="background-color: #f44336">Red</button>
|
<input type="text" id="roomName" placeholder="Room name">
<button id="assignRoom" onclick="setTool('assign')">Assign Room</button>
<select id="roomSelect">
<option value="">Select Destination Room</option>
</select>
<select id="viaRoomSelect">
<option value="">Via Room (Optional)</option>
</select>
<button id="removeRoom" onclick="removeSelectedRoom()">Remove Room</button>
<button id="goBtn" onclick="startPathfinding()">Go!</button>
|
<button onclick="saveMap()">Save Map</button>
<button onclick="loadMap()">Load Map</button>
|
<input type="number" id="gridCols" value="40" min="1" style="width: 60px"> ×
<input type="number" id="gridRows" value="20" min="1" style="width: 60px">
<button onclick="resizeGrid()">Resize Grid</button>
</div>
<!-- Insert a new container for the P5 sketch -->
<div id="sketch-container"></div>
<!-- Move the JSON text areas here so they appear after the editor and canvas -->
<div style="margin-top: 20px; width: 100%; max-width: 1200px; text-align: center;">
<textarea id="roomsJson" readonly style="width: 90%; height: 100px; margin: 10px; padding: 10px;" placeholder="Rooms will appear here in JSON format"></textarea>
<textarea id="gameJson" readonly style="width: 90%; height: 200px; margin: 10px; padding: 10px;" placeholder="Complete game definition will appear here in JSON format"></textarea>
</div>
<script>
const CELL_SIZE = 30;
let GRID_COLS = 40;
let GRID_ROWS = 20;
let grid = [];
let rooms = new Map(); // roomName -> array of cells
let currentTool = 'wall';
let characterPos = null;
let isDragging = false;
let roomBeingAssigned = null;
let path = [];
let isMoving = false;
let moveInterval = null;
function setup() {
GRID_COLS = parseInt(document.getElementById('gridCols').value) || 40;
GRID_ROWS = parseInt(document.getElementById('gridRows').value) || 20;
// Attach the P5 canvas to #sketch-container
createCanvas(GRID_COLS * CELL_SIZE, GRID_ROWS * CELL_SIZE)
.parent('sketch-container');
initGrid();
}
function initGrid() {
grid = []; // Clear the grid first
for (let y = 0; y < GRID_ROWS; y++) {
grid[y] = [];
for (let x = 0; x < GRID_COLS; x++) {
grid[y][x] = {
type: 'empty',
room: null,
color: null
};
}
}
}
function draw() {
background(255);
drawGrid();
drawRooms();
drawWallsAndDoors();
drawPath();
drawCharacter();
// Draw hover effect
if (mouseInCanvas()) {
const [gridX, gridY] = getGridCoord(mouseX, mouseY);
noFill();
stroke(100);
rect(gridX * CELL_SIZE, gridY * CELL_SIZE, CELL_SIZE, CELL_SIZE);
}
}
function drawGrid() {
stroke(200);
for (let x = 0; x <= GRID_COLS; x++) {
line(x * CELL_SIZE, 0, x * CELL_SIZE, height);
}
for (let y = 0; y <= GRID_ROWS; y++) {
line(0, y * CELL_SIZE, width, y * CELL_SIZE);
}
}
function drawWallsAndDoors() {
for (let y = 0; y < GRID_ROWS; y++) {
for (let x = 0; x < GRID_COLS; x++) {
const cell = grid[y][x];
if (cell.type === 'wall') {
fill(0);
noStroke();
rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
} else if (cell.type === 'door') {
fill(139, 69, 19);
noStroke();
rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
} else if (cell.color) {
noStroke();
switch(cell.color) {
case 'yellow':
fill('#ffeb3b');
break;
case 'blue':
fill('#2196f3');
break;
case 'green':
fill('#4caf50');
break;
case 'red':
fill('#f44336');
break;
}
rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
}
}
}
}
function drawRooms() {
for (let [roomName, cells] of rooms) {
const hue = stringToHue(roomName);
fill(hue, 30, 95, 0.3);
noStroke();
for (let cell of cells) {
rect(cell.x * CELL_SIZE, cell.y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
}
// Draw room name on first cell
if (cells.length > 0) {
fill(0);
textAlign(CENTER, CENTER);
textSize(10);
text(roomName, cells[0].x * CELL_SIZE + CELL_SIZE/2, cells[0].y * CELL_SIZE + CELL_SIZE/2);
}
}
}
function drawCharacter() {
if (characterPos) {
textSize(CELL_SIZE * 0.8);
textAlign(CENTER, CENTER);
text('👧',
characterPos.x * CELL_SIZE + CELL_SIZE/2,
characterPos.y * CELL_SIZE + CELL_SIZE/2
);
}
}
function mousePressed() {
if (!mouseInCanvas()) return;
isDragging = true;
handleDraw();
}
function mouseDragged() {
if (isDragging) handleDraw();
}
function mouseReleased() {
isDragging = false;
if (currentTool === 'assign') {
const roomName = document.getElementById('roomName').value;
if (roomName && roomBeingAssigned && roomBeingAssigned.length > 0) {
rooms.set(roomName, roomBeingAssigned);
updateRoomDropdown();
}
roomBeingAssigned = null;
}
}
function handleDraw() {
if (!mouseInCanvas()) return;
const [gridX, gridY] = getGridCoord(mouseX, mouseY);
switch(currentTool) {
case 'wall':
grid[gridY][gridX].type = 'wall';
grid[gridY][gridX].color = null;
break;
case 'door':
grid[gridY][gridX].type = 'door';
grid[gridY][gridX].color = null;
break;
case 'erase':
grid[gridY][gridX].type = 'empty';
grid[gridY][gridX].color = null;
break;
case 'character':
characterPos = {x: gridX, y: gridY};
currentTool = 'wall'; // Reset to wall tool after placing character
break;
case 'assign':
if (!roomBeingAssigned) roomBeingAssigned = [];
roomBeingAssigned.push({x: gridX, y: gridY});
break;
case 'yellow':
case 'blue':
case 'green':
case 'red':
grid[gridY][gridX].type = 'empty';
grid[gridY][gridX].color = currentTool;
break;
}
updateGameJson(); // Update game JSON after any grid changes
}
function setTool(tool) {
currentTool = tool;
// Reset room being assigned if switching tools
if (tool !== 'assign') roomBeingAssigned = null;
// Update button states
document.querySelectorAll('button').forEach(btn => btn.classList.remove('active'));
document.getElementById(tool + 'Btn')?.classList.add('active');
}
function mouseInCanvas() {
return mouseX >= 0 && mouseX < width && mouseY >= 0 && mouseY < height;
}
function getGridCoord(x, y) {
const gridX = Math.floor(x / CELL_SIZE);
const gridY = Math.floor(y / CELL_SIZE);
return [
Math.min(Math.max(gridX, 0), GRID_COLS - 1),
Math.min(Math.max(gridY, 0), GRID_ROWS - 1)
];
}
function stringToHue(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
return hash % 360;
}
function updateRoomDropdown() {
const select = document.getElementById('roomSelect');
const viaSelect = document.getElementById('viaRoomSelect');
select.innerHTML = '<option value="">Select Destination Room</option>';
viaSelect.innerHTML = '<option value="">Via Room (Optional)</option>';
for (let roomName of rooms.keys()) {
const option = document.createElement('option');
option.value = roomName;
option.textContent = roomName;
select.appendChild(option.cloneNode(true));
viaSelect.appendChild(option);
}
updateRoomsJson();
}
function updateRoomsJson() {
const roomsTextArea = document.getElementById('roomsJson');
const roomsList = Array.from(rooms.keys());
roomsTextArea.value = JSON.stringify(roomsList, null, 2);
updateGameJson(); // Update game JSON whenever rooms are updated
}
function updateGameJson() {
const gameTextArea = document.getElementById('gameJson');
const gameData = {
grid: grid,
rooms: Array.from(rooms.entries()),
characterPos: characterPos,
gridCols: GRID_COLS,
gridRows: GRID_ROWS
};
gameTextArea.value = JSON.stringify(gameData, null, 2);
}
function startPathfinding() {
const targetRoom = document.getElementById('roomSelect').value;
const viaRoom = document.getElementById('viaRoomSelect').value;
if (!targetRoom || !characterPos) return;
const targetCells = rooms.get(targetRoom);
if (!targetCells || targetCells.length === 0) return;
if (viaRoom && viaRoom !== targetRoom) {
const viaCells = rooms.get(viaRoom);
if (!viaCells || viaCells.length === 0) return;
// Find path to via room first
const pathToVia = findPath(characterPos, viaCells[0]);
if (pathToVia.length === 0) return; // No path to via room
// Find path from via room to target
const pathFromVia = findPath(viaCells[0], targetCells[0]);
if (pathFromVia.length === 0) return; // No path from via to target
// Combine paths (remove duplicate via point)
path = [...pathToVia, ...pathFromVia.slice(1)];
} else {
// Direct path to target
path = findPath(characterPos, targetCells[0]);
}
if (path.length > 0) {
isMoving = true;
moveCharacterAlongPath();
}
}
function findPath(start, end) {
const queue = [[start]];
const visited = new Set();
const key = pos => `${pos.x},${pos.y}`;
visited.add(key(start));
while (queue.length > 0) {
const currentPath = queue.shift();
const current = currentPath[currentPath.length - 1];
if (current.x === end.x && current.y === end.y) {
return currentPath;
}
// Get neighbors (up, right, down, left)
const neighbors = [
{x: current.x, y: current.y - 1},
{x: current.x + 1, y: current.y},
{x: current.x, y: current.y + 1},
{x: current.x - 1, y: current.y}
];
for (const next of neighbors) {
if (next.x < 0 || next.x >= GRID_COLS || next.y < 0 || next.y >= GRID_ROWS) continue;
const nextKey = key(next);
if (visited.has(nextKey)) continue;
// Check if the cell is walkable (empty or door)
const cell = grid[next.y][next.x];
if (cell.type === 'wall') continue;
visited.add(nextKey);
queue.push([...currentPath, next]);
}
}
return []; // No path found
}
function moveCharacterAlongPath() {
if (moveInterval) clearInterval(moveInterval);
moveInterval = setInterval(() => {
if (path.length === 0) {
isMoving = false;
clearInterval(moveInterval);
return;
}
const nextPos = path.shift();
characterPos = nextPos;
}, 200); // Move every 200ms
}
function drawPath() {
if (path.length > 0 && isMoving) {
noFill();
stroke(0, 255, 0);
strokeWeight(2);
// Draw line from character to first path point
line(
characterPos.x * CELL_SIZE + CELL_SIZE/2,
characterPos.y * CELL_SIZE + CELL_SIZE/2,
path[0].x * CELL_SIZE + CELL_SIZE/2,
path[0].y * CELL_SIZE + CELL_SIZE/2
);
// Draw lines between path points
for (let i = 0; i < path.length - 1; i++) {
line(
path[i].x * CELL_SIZE + CELL_SIZE/2,
path[i].y * CELL_SIZE + CELL_SIZE/2,
path[i + 1].x * CELL_SIZE + CELL_SIZE/2,
path[i + 1].y * CELL_SIZE + CELL_SIZE/2
);
}
strokeWeight(1);
}
}
function saveMap() {
const mapData = {
grid: grid,
rooms: Array.from(rooms.entries()),
characterPos: characterPos,
gridCols: GRID_COLS,
gridRows: GRID_ROWS
};
localStorage.setItem('apartmentMap', JSON.stringify(mapData));
alert('Map saved!');
updateGameJson(); // Update game JSON after saving
}
function loadMap() {
const mapData = localStorage.getItem('apartmentMap');
if (!mapData) {
alert('No saved map found!');
return;
}
const data = JSON.parse(mapData);
// Update grid dimensions and input fields
GRID_COLS = data.gridCols || 40;
GRID_ROWS = data.gridRows || 20;
document.getElementById('gridCols').value = GRID_COLS;
document.getElementById('gridRows').value = GRID_ROWS;
// Resize canvas and initialize grid
resizeCanvas(GRID_COLS * CELL_SIZE, GRID_ROWS * CELL_SIZE);
initGrid();
// Load saved data
grid = data.grid;
rooms = new Map(data.rooms);
characterPos = data.characterPos;
updateRoomDropdown();
updateGameJson(); // Update game JSON after loading
}
function removeSelectedRoom() {
const roomName = document.getElementById('roomSelect').value;
if (!roomName) return;
// Remove room from the rooms Map
rooms.delete(roomName);
// Update the dropdown
updateRoomDropdown();
}
function resizeGrid() {
const newCols = parseInt(document.getElementById('gridCols').value) || 40;
const newRows = parseInt(document.getElementById('gridRows').value) || 20;
// Save old grid data
const oldGrid = JSON.parse(JSON.stringify(grid)); // Deep copy
const oldCols = GRID_COLS;
const oldRows = GRID_ROWS;
// Update dimensions
GRID_COLS = newCols;
GRID_ROWS = newRows;
// Initialize new grid first
initGrid();
// Copy old data to new grid where possible
for (let y = 0; y < Math.min(oldRows, GRID_ROWS); y++) {
for (let x = 0; x < Math.min(oldCols, GRID_COLS); x++) {
if (oldGrid[y] && oldGrid[y][x]) {
grid[y][x] = oldGrid[y][x];
}
}
}
// Resize canvas
resizeCanvas(GRID_COLS * CELL_SIZE, GRID_ROWS * CELL_SIZE);
// Adjust character position if outside new bounds
if (characterPos) {
if (characterPos.x >= GRID_COLS) characterPos.x = GRID_COLS - 1;
if (characterPos.y >= GRID_ROWS) characterPos.y = GRID_ROWS - 1;
}
// Adjust room cells to fit new grid
for (let [roomName, cells] of rooms) {
rooms.set(roomName, cells.filter(cell =>
cell.x < GRID_COLS && cell.y < GRID_ROWS
));
}
// Clear path if any
path = [];
if (moveInterval) clearInterval(moveInterval);
isMoving = false;
updateGameJson(); // Update game JSON after resizing
}
</script>
</body>
</html>