Fix tile rendering dimensions and alignment, update tile definitions to use height
This commit is contained in:
@@ -1,296 +1,317 @@
|
||||
|
||||
import { DIRECTIONS } from './Constants.js';
|
||||
import { GridSystem } from './GridSystem.js';
|
||||
import { DungeonDeck } from './DungeonDeck.js';
|
||||
import { TILES } from './TileDefinitions.js';
|
||||
|
||||
const PLACEMENT_STATE = {
|
||||
WAITING_DOOR: 'WAITING_DOOR',
|
||||
PLACING_TILE: 'PLACING_TILE',
|
||||
COMPLETE: 'COMPLETE'
|
||||
};
|
||||
|
||||
export class DungeonGenerator {
|
||||
constructor() {
|
||||
this.grid = new GridSystem();
|
||||
this.deck = new DungeonDeck();
|
||||
this.pendingExits = []; // Array of global {x, y, direction}
|
||||
this.placedTiles = [];
|
||||
this.isComplete = false;
|
||||
this.availableExits = []; // Exits where player can choose to expand
|
||||
|
||||
// Placement State
|
||||
this.state = PLACEMENT_STATE.WAITING_DOOR;
|
||||
this.currentCard = null;
|
||||
this.placementRotation = DIRECTIONS.NORTH;
|
||||
this.placementX = 0;
|
||||
this.placementY = 0;
|
||||
this.selectedExit = null;
|
||||
|
||||
// Callbacks for UI
|
||||
this.onStateChange = null;
|
||||
this.onPlacementUpdate = null;
|
||||
}
|
||||
|
||||
startDungeon(missionConfig) {
|
||||
// 1. Prepare Deck (Rulebook: 13 cards, 6+1+6)
|
||||
// We need an objective tile ID from the config
|
||||
const objectiveId = missionConfig.type === 'quest' ? 'room_objective' : 'room_dungeon'; // Fallback for now
|
||||
const objectiveId = missionConfig?.type === 'quest' ? 'room_objective' : 'room_dungeon';
|
||||
this.deck.generateMissionDeck(objectiveId);
|
||||
|
||||
// 2. Rulebook Step 4: "Flip the first card. This is the entrance."
|
||||
const startCard = this.deck.draw();
|
||||
|
||||
if (!startCard) {
|
||||
console.error("Deck is empty on start!");
|
||||
// 1. Draw and place first card automatically at origin
|
||||
const firstCard = this.deck.draw();
|
||||
if (!firstCard) {
|
||||
console.error("❌ Empty deck");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Place the Entry Tile at (0,0)
|
||||
// We assume rotation NORTH by default for the first piece
|
||||
const startInstance = {
|
||||
id: `tile_0_${startCard.id}`,
|
||||
defId: startCard.id,
|
||||
x: 0,
|
||||
y: 0,
|
||||
rotation: DIRECTIONS.NORTH
|
||||
};
|
||||
this.placeCardFinal(firstCard, 0, 0, DIRECTIONS.NORTH);
|
||||
console.log(`🏰 Dungeon started with ${firstCard.name}`);
|
||||
|
||||
if (this.grid.canPlace(startCard, 0, 0, DIRECTIONS.NORTH)) {
|
||||
this.grid.placeTile(startInstance, startCard);
|
||||
this.placedTiles.push(startInstance);
|
||||
this.addExitsToQueue(startInstance, startCard);
|
||||
console.log(`Dungeon started with ${startCard.name}`);
|
||||
} else {
|
||||
console.error("Failed to place starting tile (Grid collision at 0,0?)");
|
||||
}
|
||||
// 2. Transition to door selection
|
||||
this.state = PLACEMENT_STATE.WAITING_DOOR;
|
||||
this.notifyStateChange();
|
||||
}
|
||||
|
||||
step() {
|
||||
if (this.isComplete) return false;
|
||||
if (this.pendingExits.length === 0) {
|
||||
console.log("No more exits available. Dungeon generation stopped.");
|
||||
this.isComplete = true;
|
||||
/**
|
||||
* Player selects a door to expand from
|
||||
*/
|
||||
selectDoor(exitPoint) {
|
||||
console.log('[DungeonGenerator] selectDoor called with:', exitPoint);
|
||||
console.log('[DungeonGenerator] Current state:', this.state);
|
||||
console.log('[DungeonGenerator] Available exits:', this.availableExits);
|
||||
|
||||
if (this.state !== PLACEMENT_STATE.WAITING_DOOR) {
|
||||
console.warn("Not in door selection mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
const card = this.deck.draw();
|
||||
if (!card) {
|
||||
console.log("Deck empty. Dungeon complete.");
|
||||
this.isComplete = true;
|
||||
if (!exitPoint) {
|
||||
console.error("exitPoint is undefined!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// We process exits in groups now?
|
||||
// Or simply: When we pick an exit, we verify if it is part of a larger door.
|
||||
// Actually, 'pendingExits' contains individual cells.
|
||||
// Let's pick one.
|
||||
const targetExit = this.pendingExits.shift();
|
||||
// Validate exit exists
|
||||
const exitExists = this.availableExits.some(
|
||||
e => e.x === exitPoint.x && e.y === exitPoint.y && e.direction === exitPoint.direction
|
||||
);
|
||||
|
||||
// 1. Identify the "Global Reference Point" for the door this exit belongs to.
|
||||
// (If door is 2-wide, we want the One with the LOWEST X or LOWEST Y).
|
||||
// WE MUST FIND ITS SIBLING if it exists in 'pendingExits'.
|
||||
// This stops us from trying to attach a door twice (once per cell).
|
||||
|
||||
// Simple heuristic: If we have an exit at (x,y), check (x+1,y) or (x,y+1) depending on dir.
|
||||
// If the sibling is also in pendingExits, we effectively "consume" it too for this placement.
|
||||
|
||||
// Better: Find the "Left-Most" or "Bottom-Most" cell of this specific connection interface.
|
||||
// And use THAT as the target.
|
||||
|
||||
const targetRef = this.findExitReference(targetExit);
|
||||
console.log(`Attempting to place ${card.name} at Global Ref ${targetRef.x},${targetRef.y} (${targetRef.direction})`);
|
||||
|
||||
const requiredInputDirection = this.getOppositeDirection(targetRef.direction);
|
||||
let placed = false;
|
||||
|
||||
// Try to fit the card
|
||||
// We iterate input exits on the NEW card.
|
||||
// We only look at "Reference" exits on the new card too (min x/y) to avoid duplicate attempts.
|
||||
const candidateExits = this.UniqueExits(card);
|
||||
|
||||
for (const candidateExit of candidateExits) {
|
||||
|
||||
const rotation = this.calculateRequiredRotation(candidateExit.direction, requiredInputDirection);
|
||||
|
||||
// Now calculate ALIGNMENT.
|
||||
// We want the "Min Cell" of the Candidate Door (after rotation)
|
||||
// To overlap with the "Neighbor Cell" of the "Min Cell" of the Target Door?
|
||||
// NO.
|
||||
// Target Door Min Cell is at (TX, TY).
|
||||
// Its "Connection Neighbor" is at (NX, NY).
|
||||
// We want Candidate Door (Rotated) Min Cell to be at (NX, NY).
|
||||
|
||||
// 1. Calculate the offset of Candidate 'Min Cell' relative to Tile Origin (0,0) AFTER rotation.
|
||||
const rotatedOffset = this.getRotatedOffset(candidateExit, rotation);
|
||||
|
||||
// 2. Calculate the global connection point input
|
||||
const connectionPoint = this.getNeighborCell(targetRef.x, targetRef.y, targetRef.direction);
|
||||
|
||||
// 3. Tile Position
|
||||
const posX = connectionPoint.x - rotatedOffset.x;
|
||||
const posY = connectionPoint.y - rotatedOffset.y;
|
||||
|
||||
if (this.grid.canPlace(card, posX, posY, rotation)) {
|
||||
// Success
|
||||
const newInstance = {
|
||||
id: `tile_${this.placedTiles.length}_${card.id}`,
|
||||
defId: card.id,
|
||||
x: posX,
|
||||
y: posY,
|
||||
rotation: rotation
|
||||
};
|
||||
|
||||
this.grid.placeTile(newInstance, card);
|
||||
this.placedTiles.push(newInstance);
|
||||
|
||||
// Add NEW exits
|
||||
this.addExitsToQueue(newInstance, card);
|
||||
|
||||
// Cleanup: Remove the used exit(s) from pendingExits
|
||||
// We used targetRef. We must also remove its sibling if it exists.
|
||||
// Or simply: filter out any pending exit that is now blocked.
|
||||
this.cleanupPendingExits();
|
||||
|
||||
placed = true;
|
||||
break;
|
||||
}
|
||||
if (!exitExists) {
|
||||
console.warn("Invalid exit selected");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!placed) {
|
||||
console.log(`Could not fit ${card.name}. Discarding.`);
|
||||
// If failed, return the exit to the pool?
|
||||
// Or discard the exit as "Dead End"?
|
||||
// For now, put it back at the end of queue.
|
||||
this.pendingExits.push(targetExit);
|
||||
this.selectedExit = exitPoint;
|
||||
|
||||
// Draw next card
|
||||
this.currentCard = this.deck.draw();
|
||||
if (!this.currentCard) {
|
||||
console.log("Deck empty - dungeon complete");
|
||||
this.state = PLACEMENT_STATE.COMPLETE;
|
||||
this.notifyStateChange();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate initial placement position (3 units above the connection point)
|
||||
const connectionPoint = this.neighbor(exitPoint.x, exitPoint.y, exitPoint.direction);
|
||||
|
||||
// Start with NORTH rotation
|
||||
this.placementRotation = DIRECTIONS.NORTH;
|
||||
const variant = this.currentCard.variants[this.placementRotation];
|
||||
|
||||
// Find the exit on the new tile that should connect to selectedExit
|
||||
const requiredDirection = this.opposite(exitPoint.direction);
|
||||
const matchingExits = variant.exits.filter(e => e.direction === requiredDirection);
|
||||
|
||||
if (matchingExits.length > 0) {
|
||||
// Use first matching exit as anchor
|
||||
const anchor = matchingExits[0];
|
||||
this.placementX = Math.round(connectionPoint.x - anchor.x);
|
||||
this.placementY = Math.round(connectionPoint.y - anchor.y);
|
||||
} else {
|
||||
// Fallback: center on connection point
|
||||
this.placementX = Math.round(connectionPoint.x);
|
||||
this.placementY = Math.round(connectionPoint.y);
|
||||
}
|
||||
|
||||
this.state = PLACEMENT_STATE.PLACING_TILE;
|
||||
this.notifyPlacementUpdate();
|
||||
this.notifyStateChange();
|
||||
|
||||
console.log(`📦 Placing ${this.currentCard.name} at (${this.placementX}, ${this.placementY})`);
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- Helpers ---
|
||||
getNeighborCell(x, y, dir) {
|
||||
switch (dir) {
|
||||
case DIRECTIONS.NORTH: return { x: x, y: y + 1 };
|
||||
case DIRECTIONS.SOUTH: return { x: x, y: y - 1 };
|
||||
case DIRECTIONS.EAST: return { x: x + 1, y: y };
|
||||
case DIRECTIONS.WEST: return { x: x - 1, y: y };
|
||||
}
|
||||
/**
|
||||
* Rotate placement tile 90° clockwise
|
||||
*/
|
||||
rotatePlacement() {
|
||||
if (this.state !== PLACEMENT_STATE.PLACING_TILE) return;
|
||||
|
||||
const rotations = [DIRECTIONS.NORTH, DIRECTIONS.EAST, DIRECTIONS.SOUTH, DIRECTIONS.WEST];
|
||||
const currentIndex = rotations.indexOf(this.placementRotation);
|
||||
this.placementRotation = rotations[(currentIndex + 1) % 4];
|
||||
|
||||
console.log(`🔄 Rotated to ${this.placementRotation}`);
|
||||
this.notifyPlacementUpdate();
|
||||
}
|
||||
|
||||
findExitReference(exit) {
|
||||
// If facing North/South, Reference is Minimum X.
|
||||
// If facing East/West, Reference is Minimum Y.
|
||||
/**
|
||||
* Move placement tile by offset
|
||||
*/
|
||||
movePlacement(dx, dy) {
|
||||
if (this.state !== PLACEMENT_STATE.PLACING_TILE) return;
|
||||
|
||||
// This function assumes 'exit' is from pendingExits (Global coords).
|
||||
// It checks if there is a "Lower" sibling also in pendingExits.
|
||||
// If so, returns the lower sibling. BEFORE using this exit.
|
||||
this.placementX += dx;
|
||||
this.placementY += dy;
|
||||
|
||||
let bestExit = exit;
|
||||
|
||||
// Check for siblings in pendingExits that match direction and are < coordinate
|
||||
// This is O(N) but N is small.
|
||||
for (const other of this.pendingExits) {
|
||||
if (other === exit) continue;
|
||||
if (other.direction !== exit.direction) continue;
|
||||
|
||||
if (exit.direction === DIRECTIONS.NORTH || exit.direction === DIRECTIONS.SOUTH) {
|
||||
// Check X. Adjacent implies y same, x diff 1.
|
||||
if (other.y === exit.y && Math.abs(other.x - exit.x) === 1) {
|
||||
if (other.x < bestExit.x) bestExit = other;
|
||||
}
|
||||
} else {
|
||||
// Check Y. adjacent implies x same, y diff 1.
|
||||
if (other.x === exit.x && Math.abs(other.y - exit.y) === 1) {
|
||||
if (other.y < bestExit.y) bestExit = other;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestExit;
|
||||
console.log(`↔️ Moved to (${this.placementX}, ${this.placementY})`);
|
||||
this.notifyPlacementUpdate();
|
||||
}
|
||||
|
||||
UniqueExits(tileDef) {
|
||||
// Filter tileDef.exits to only return the "Reference" (Min x/y) for each face/group.
|
||||
// This prevents trying to attach the same door 2 times.
|
||||
const unique = [];
|
||||
const seen = new Set(); // store "dir_coord" keys
|
||||
/**
|
||||
* Check if current placement is valid
|
||||
*/
|
||||
isPlacementValid() {
|
||||
if (!this.currentCard || this.state !== PLACEMENT_STATE.PLACING_TILE) return false;
|
||||
|
||||
// Sort exits to ensure we find Min first
|
||||
const sorted = [...tileDef.exits].sort((a, b) => {
|
||||
if (a.direction !== b.direction) return a.direction.localeCompare(b.direction);
|
||||
if (a.x !== b.x) return a.x - b.x;
|
||||
return a.y - b.y;
|
||||
});
|
||||
|
||||
for (const ex of sorted) {
|
||||
// Identifier for the "Door Group".
|
||||
// If North/South: ID is "Dir_Y". (X varies)
|
||||
// If East/West: ID is "Dir_X". (Y varies)
|
||||
// Actually, we just need to pick the first one we see (since we sorted by X then Y).
|
||||
// If we have (0,0) and (1,0) for SOUTH. Sorted -> (0,0) comes first.
|
||||
// We take (0,0). We assume (1,0) is part of same door.
|
||||
|
||||
// Heuristic: If this exit is adjacent to the last added unique exit of same direction, skip it.
|
||||
const last = unique[unique.length - 1];
|
||||
let isSameDoor = false;
|
||||
|
||||
if (last && last.direction === ex.direction) {
|
||||
if (ex.direction === DIRECTIONS.NORTH || ex.direction === DIRECTIONS.SOUTH) {
|
||||
// Vertical door, check horizontal adjacency
|
||||
if (last.y === ex.y && Math.abs(last.x - ex.x) <= 1) isSameDoor = true;
|
||||
} else {
|
||||
// Horizontal door, check vertical adjacency
|
||||
if (last.x === ex.x && Math.abs(last.y - ex.y) <= 1) isSameDoor = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSameDoor) {
|
||||
unique.push(ex);
|
||||
}
|
||||
}
|
||||
return unique;
|
||||
const variant = this.currentCard.variants[this.placementRotation];
|
||||
return this.grid.canPlace(variant, this.placementX, this.placementY);
|
||||
}
|
||||
|
||||
getRotatedOffset(localExit, rotation) {
|
||||
// Calculate where the 'localExit' ends up relative to (0,0) after rotation.
|
||||
// localExit is the "Reference" (Min) of the candidate door.
|
||||
|
||||
let rx, ry;
|
||||
const lx = localExit.x;
|
||||
const ly = localExit.y;
|
||||
|
||||
switch (rotation) {
|
||||
case DIRECTIONS.NORTH: rx = lx; ry = ly; break;
|
||||
case DIRECTIONS.SOUTH: rx = -lx; ry = -ly; break;
|
||||
case DIRECTIONS.EAST: rx = ly; ry = -lx; break;
|
||||
case DIRECTIONS.WEST: rx = -ly; ry = lx; break;
|
||||
/**
|
||||
* Confirm and finalize tile placement
|
||||
*/
|
||||
confirmPlacement() {
|
||||
if (this.state !== PLACEMENT_STATE.PLACING_TILE) {
|
||||
console.warn("Not in placement mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
return { x: rx, y: ry };
|
||||
}
|
||||
|
||||
getOppositeDirection(dir) {
|
||||
switch (dir) {
|
||||
case DIRECTIONS.NORTH: return DIRECTIONS.SOUTH;
|
||||
case DIRECTIONS.SOUTH: return DIRECTIONS.NORTH;
|
||||
case DIRECTIONS.EAST: return DIRECTIONS.WEST;
|
||||
case DIRECTIONS.WEST: return DIRECTIONS.EAST;
|
||||
if (!this.isPlacementValid()) {
|
||||
console.warn("❌ Cannot place tile - invalid position");
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log(`[confirmPlacement] Placing at (${this.placementX}, ${this.placementY}) rotation: ${this.placementRotation}`);
|
||||
|
||||
// Round to integers (tiles must be on grid cells)
|
||||
const finalX = Math.round(this.placementX);
|
||||
const finalY = Math.round(this.placementY);
|
||||
|
||||
console.log(`[confirmPlacement] Rounded to (${finalX}, ${finalY})`);
|
||||
|
||||
// Place the tile
|
||||
this.placeCardFinal(
|
||||
this.currentCard,
|
||||
finalX,
|
||||
finalY,
|
||||
this.placementRotation
|
||||
);
|
||||
|
||||
// Reset placement state
|
||||
this.currentCard = null;
|
||||
this.selectedExit = null;
|
||||
this.state = PLACEMENT_STATE.WAITING_DOOR;
|
||||
|
||||
this.notifyPlacementUpdate(); // Clear preview
|
||||
this.notifyStateChange();
|
||||
console.log("✅ Tile placed successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
calculateRequiredRotation(localDir, targetGlobalDir) {
|
||||
const dirs = [DIRECTIONS.NORTH, DIRECTIONS.EAST, DIRECTIONS.SOUTH, DIRECTIONS.WEST];
|
||||
const localIdx = dirs.indexOf(localDir);
|
||||
const targetIdx = dirs.indexOf(targetGlobalDir);
|
||||
const diff = (targetIdx - localIdx + 4) % 4;
|
||||
return dirs[diff];
|
||||
/**
|
||||
* Internal: Actually place a card on the grid
|
||||
*/
|
||||
placeCardFinal(card, x, y, rotation) {
|
||||
console.log('[placeCardFinal] Card:', card);
|
||||
console.log('[placeCardFinal] Card.variants:', card.variants);
|
||||
console.log('[placeCardFinal] Rotation:', rotation, 'Type:', typeof rotation);
|
||||
|
||||
const variant = card.variants[rotation];
|
||||
console.log('[placeCardFinal] Variant:', variant);
|
||||
|
||||
const instance = {
|
||||
id: `tile_${this.placedTiles.length}`,
|
||||
defId: card.id,
|
||||
x, y, rotation,
|
||||
name: card.name
|
||||
};
|
||||
|
||||
this.grid.placeTile(instance, variant, card);
|
||||
this.placedTiles.push(instance);
|
||||
|
||||
// Update available exits
|
||||
this.updateAvailableExits(instance, variant, x, y);
|
||||
}
|
||||
|
||||
addExitsToQueue(tileInstance, tileDef) {
|
||||
for (const exit of tileDef.exits) {
|
||||
const globalPoint = this.grid.getGlobalPoint(exit.x, exit.y, tileInstance);
|
||||
const globalDir = this.grid.getRotatedDirection(exit.direction, tileInstance.rotation);
|
||||
/**
|
||||
* Update list of exits player can choose from
|
||||
*/
|
||||
updateAvailableExits(instance, variant, anchorX, anchorY) {
|
||||
console.log('[updateAvailableExits] ===== NUEVO CODIGO ===== Called for tile:', instance.id);
|
||||
console.log('[updateAvailableExits] Variant exits:', variant.exits);
|
||||
console.log('[updateAvailableExits] Anchor:', anchorX, anchorY);
|
||||
|
||||
// Check if blocked immediately
|
||||
const neighbor = this.getNeighborCell(globalPoint.x, globalPoint.y, globalDir);
|
||||
const key = `${neighbor.x},${neighbor.y}`;
|
||||
// Add new exits from this tile
|
||||
for (const ex of variant.exits) {
|
||||
const gx = anchorX + ex.x;
|
||||
const gy = anchorY + ex.y;
|
||||
|
||||
if (!this.grid.occupiedCells.has(key)) {
|
||||
this.pendingExits.push({
|
||||
x: globalPoint.x,
|
||||
y: globalPoint.y,
|
||||
direction: globalDir
|
||||
const leadingTo = this.neighbor(gx, gy, ex.direction);
|
||||
const isOccupied = this.grid.isOccupied(leadingTo.x, leadingTo.y);
|
||||
|
||||
console.log(`[updateAvailableExits] Exit at (${gx}, ${gy}) dir ${ex.direction} -> leads to (${leadingTo.x}, ${leadingTo.y}) occupied: ${isOccupied}`);
|
||||
|
||||
if (!isOccupied) {
|
||||
this.availableExits.push({
|
||||
x: gx,
|
||||
y: gy,
|
||||
direction: ex.direction,
|
||||
tileId: instance.id
|
||||
});
|
||||
console.log('[updateAvailableExits] ✓ Added exit');
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[updateAvailableExits] Total available exits now:', this.availableExits.length);
|
||||
|
||||
// Remove exits that are now blocked or connected
|
||||
this.availableExits = this.availableExits.filter(exit => {
|
||||
const leadingTo = this.neighbor(exit.x, exit.y, exit.direction);
|
||||
return !this.grid.isOccupied(leadingTo.x, leadingTo.y);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current placement preview data for renderer
|
||||
*/
|
||||
getPlacementPreview() {
|
||||
if (this.state !== PLACEMENT_STATE.PLACING_TILE || !this.currentCard) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const variant = this.currentCard.variants[this.placementRotation];
|
||||
const cells = this.grid.calculateCells(variant, this.placementX, this.placementY);
|
||||
const isValid = this.isPlacementValid();
|
||||
|
||||
return {
|
||||
card: this.currentCard,
|
||||
rotation: this.placementRotation,
|
||||
x: this.placementX,
|
||||
y: this.placementY,
|
||||
cells,
|
||||
isValid,
|
||||
variant
|
||||
};
|
||||
}
|
||||
|
||||
// --- Helpers ---
|
||||
|
||||
notifyStateChange() {
|
||||
if (this.onStateChange) {
|
||||
this.onStateChange(this.state);
|
||||
}
|
||||
}
|
||||
|
||||
cleanupPendingExits() {
|
||||
// Remove exits that now point to occupied cells (blocked by newly placed tile)
|
||||
this.pendingExits = this.pendingExits.filter(ex => {
|
||||
const neighbor = this.getNeighborCell(ex.x, ex.y, ex.direction);
|
||||
const key = `${neighbor.x},${neighbor.y}`;
|
||||
return !this.grid.occupiedCells.has(key);
|
||||
});
|
||||
notifyPlacementUpdate() {
|
||||
if (this.onPlacementUpdate) {
|
||||
const preview = this.getPlacementPreview();
|
||||
this.onPlacementUpdate(preview);
|
||||
}
|
||||
}
|
||||
|
||||
neighbor(x, y, dir) {
|
||||
switch (dir) {
|
||||
case DIRECTIONS.NORTH: return { x, y: y + 1 };
|
||||
case DIRECTIONS.SOUTH: return { x, y: y - 1 };
|
||||
case DIRECTIONS.EAST: return { x: x + 1, y };
|
||||
case DIRECTIONS.WEST: return { x: x - 1, y };
|
||||
}
|
||||
}
|
||||
|
||||
opposite(dir) {
|
||||
const map = {
|
||||
[DIRECTIONS.NORTH]: DIRECTIONS.SOUTH,
|
||||
[DIRECTIONS.SOUTH]: DIRECTIONS.NORTH,
|
||||
[DIRECTIONS.EAST]: DIRECTIONS.WEST,
|
||||
[DIRECTIONS.WEST]: DIRECTIONS.EAST
|
||||
};
|
||||
return map[dir];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user