xxxxxxxxxx
1055
if (window.Program !== undefined)
{
console.warn("Program object already exists: " + Program.toString());
}
Program =
{
InitFunctions: [],
};
let grid;
let hWalls;
let vWalls;
let hLines;
let vLines;
let cellStripes;
let cols = 16;
let rows = 8;
let cellW = 36;
let cellH = 36;
let zoomFactor = 4;
let wallThickness = 4;
let gridLineThickness = 2;
let gridW = cellW * cols;
let gridH = cellH * rows;
let gridOriginX, gridOriginY;
let gridTLX, gridTLY, gridTRX, gridTRY, gridBLX, gridBLY, gridBRX, gridBRY;
let gridBackgroundColor;
let cellColor;
let wallColor;
let gridLineColor;
let cursorOuterColor;
let cursorInnerColor;
let cursorX = 0;
let cursorY = 0;
let cursorWMin = cellW + wallThickness * 1.5;
let cursorWMax = cellW + wallThickness * 4.5;
let cursorHMin = cellH + wallThickness * 1.5;
let cursorHMax = cellH + wallThickness * 4.5;
let cursorTimer = 0;
let cursorPeriod = 2;
let cursorHidden = false;
function setup()
{
let w = Math.floor(windowWidth);
let h = Math.floor(windowHeight);
createCanvas(w, h);
angleMode(RADIANS);
gridBackgroundColor = color(255, 20);
cellColor = color(255, 100);
wallColor = color(255, 180);
cursorOuterColor = color(0, 180);
cursorInnerColor = color(255, 255, 0);
gridLineColor = color(255, 20);
GridSetup();
Program.Initialize();
}
Program.Initialize = function()
{
let initializer = { Counter: 0 }
for (const init of this.InitFunctions)
{
init(initializer);
++initializer.Counter;
}
}
Program.RegisterInit = function(init)
{
// TODO: check whether it's already there?
this.InitFunctions.push(init);
}
function draw()
{
IM.Update();
background(20);
HandleInput();
DrawGrid();
DrawCursor();
DrawZoom();
DrawText();
// PrintGamepadData();
}
function PrintGamepadData()
{
// noStroke();
// fill(255);
// textStyle(NORMAL);
// textAlign(LEFT);
// textSize(16);
// let x = 8;
// let y = 8;
// for (const name in Inputs)
// {
// let input = Inputs[name];
// text(input.Name, x, y);
// text(input.Down(), x + 48, y);
// y += 16;
// }
if (!IM.Gamepad) return;
textSize(12);
textStyle(NORMAL);
noStroke();
fill(255);
textAlign(LEFT);
let buttons = IM.Gamepad.buttons;
for (let i = 0; i < buttons.length; ++i)
{
text(i, 8, 8 + i * 12);
text(buttons[i].pressed, 30, 8 + i * 12);
text(buttons[i].touched, 60, 8 + i * 12);
text(buttons[i].value, 90, 8 + i * 12);
}
}
function keyPressed()
{
if (keyCode === RIGHT_ARROW)
{
if (keyIsDown(32)) // Spacebar
ToggleCurrentWallE();
else
MoveCursorE();
}
if (keyCode === LEFT_ARROW)
{
if (keyIsDown(32)) // Spacebar
ToggleCurrentWallW()
else
MoveCursorW();
}
if (keyCode === DOWN_ARROW)
{
if (keyIsDown(32)) // Spacebar
ToggleCurrentWallS()
else
MoveCursorS();
}
if (keyCode === UP_ARROW)
{
if (keyIsDown(32)) // Spacebar
ToggleCurrentWallN();
else
MoveCursorN();
}
if (keyCode === 32) // Spacebar
SetCurrentCellVisited();
if (keyCode === BACKSPACE || keyCode === DELETE)
ClearCurrentCellVisited();
if (keyCode === TAB)
{
ToggleCursor();
return false;
}
}
function GridSetup()
{
grid = new Array(cols);
for (let x = 0; x < cols; ++x)
{
let col = new Array(rows);
for (let y = 0; y < rows; ++y)
{
let cell = new Cell(x, y);
col[y] = cell;
}
grid[x] = col;
}
gridOriginX = floor((width - gridW) / 2);
gridOriginY = floor(wallThickness * 2);
gridTLX = gridOriginX;
gridTLY = gridOriginY;
gridTRX = gridOriginX + gridW;
gridTRY = gridOriginY;
gridBLX = gridOriginX;
gridBLY = gridOriginY + gridH;
gridBRX = gridOriginX + gridW;
gridBRY = gridOriginY + gridH;
hWalls = new Array(cols);
for (let i = 0; i < hWalls.length; ++i)
hWalls[i] = new Array(rows - 1).fill(false);
vWalls = new Array(cols - 1);
for (let i = 0; i < vWalls.length; ++i)
vWalls[i] = new Array(cols).fill(false);
hLines = new Array(rows - 1).fill([]);
vLines = new Array(cols - 1).fill([]);
cellStripes = new Array(rows).fill([]);
}
function DrawGrid()
{
DrawGridBackground();
DrawGridCells();
DrawGridEdges();
DrawGridWalls();
DrawGridLines();
}
function DrawGridBackground()
{
noStroke();
fill(gridBackgroundColor);
Rect(gridOriginX, gridOriginY, gridW, gridH);
}
function DrawGridCells()
{
noStroke();
fill(cellColor);
for (let rowIndex = 0; rowIndex < cellStripes.length; ++rowIndex)
{
let stripeRow = cellStripes[rowIndex];
for (let stripeIndex = 0; stripeIndex < stripeRow.length; ++stripeIndex)
{
let stripe = stripeRow[stripeIndex];
DrawCellStripe(stripe, rowIndex);
}
}
}
function DrawGridEdges()
{
stroke(wallColor);
strokeWeight(wallThickness);
Line(gridTLX, gridTLY, gridTRX, gridTRY);
Line(gridBLX, gridBLY, gridBRX, gridBRY);
Line(gridTLX, gridTLY, gridBLX, gridBLY);
Line(gridTRX, gridTRY, gridBRX, gridBRY);
}
function DrawGridWalls()
{
stroke(wallColor);
strokeWeight(wallThickness);
DrawGridHWalls();
DrawGridVWalls();
}
function DrawGridLines()
{
stroke(gridLineColor);
strokeWeight(gridLineThickness);
for (let i = 0; i <= cols; ++i)
{
let x0 = gridOriginX + i * cellW;
let y0 = gridOriginY;
let x1 = x0;
let y1 = y0 + gridH;
Line(x0, y0, x1, y1);
}
for (let i = 0; i <= rows; ++i)
{
let x0 = gridOriginX;
let y0 = gridOriginY + i * cellH;
let x1 = x0 + gridW;
let y1 = y0;
Line(x0, y0, x1, y1);
}
}
function DrawGridHWalls()
{
for (let rowIndex = 0; rowIndex < hLines.length; ++rowIndex)
{
let lineRow = hLines[rowIndex];
for (let lineIndex = 0; lineIndex < lineRow.length; ++lineIndex)
{
let hLine = lineRow[lineIndex];
DrawHLine(hLine, rowIndex);
}
}
}
function DrawGridVWalls()
{
for (let colIndex = 0; colIndex < vLines.length; ++colIndex)
{
let lineCol = vLines[colIndex];
for (let lineIndex = 0; lineIndex < lineCol.length; ++lineIndex)
{
let vLine = lineCol[lineIndex];
DrawVLine(vLine, colIndex);
}
}
}
function DrawCellStripe(stripe, rowIndex)
{
let x = gridOriginX + stripe.Start * cellW;
let y = gridOriginY + rowIndex * cellH;
let w = stripe.Length * cellW;
let h = cellH;
Rect(x, y, w, h);
}
function DrawHLine(hLine, rowIndex)
{
let x0 = gridOriginX + hLine.Start * cellW;
let y0 = gridOriginY + (rowIndex + 1) * cellH;
let x1 = x0 + hLine.Length * cellW;
let y1 = y0;
Line(x0, y0, x1, y1);
}
function DrawVLine(vLine, colIndex)
{
let x0 = gridOriginX + (colIndex + 1) * cellW;
let y0 = gridOriginY + vLine.Start * cellH;
let x1 = x0;
let y1 = y0 + vLine.Length * cellH;
Line(x0, y0, x1, y1);
}
function DrawCursor()
{
cursorTimer = (cursorTimer + (deltaTime / 1000)) % cursorPeriod;
if (cursorHidden) return;
let c = (cos(TAU * cursorTimer / cursorPeriod) + 1) / 2;
let w = (cursorWMax - cursorWMin) * c + cursorWMin;
let h = (cursorHMax - cursorHMin) * c + cursorHMin;
let x = gridOriginX + (cursorX + 0.5) * cellW;
let y = gridOriginY + (cursorY + 0.5) * cellH;
push();
{
rectMode(CENTER);
noFill();
stroke(cursorOuterColor);
strokeWeight(wallThickness);
Rect(x, y, w, h);
stroke(cursorInnerColor);
strokeWeight(wallThickness / 3);
Rect(x, y, w, h);
}
pop();
}
function DrawZoom()
{
let cell = GetCurrentCell();
let zoomOriginX = (width - cellW * zoomFactor) / 2;
let zoomOriginY = gridOriginY + gridH + wallThickness * 3 + 40;
let zoomW = cellW * zoomFactor;
let zoomH = cellH * zoomFactor;
let zoomTLX = zoomOriginX;
let zoomTLY = zoomOriginY;
let zoomTRX = zoomTLX + zoomW;
let zoomTRY = zoomTLY;
let zoomBLX = zoomTLX;
let zoomBLY = zoomTLY + zoomH;
let zoomBRX = zoomTRX;
let zoomBRY = zoomBLY;
noStroke();
fill(gridBackgroundColor);
Rect(zoomOriginX, zoomOriginY, zoomW, zoomH);
if (cell.Visited)
{
fill(cellColor);
Rect(zoomOriginX, zoomOriginY, zoomW, zoomH);
}
stroke(wallColor);
strokeWeight(wallThickness * 2);
if (GetCellNSolid(cell))
Line(zoomTLX, zoomTLY, zoomTRX, zoomTRY);
if (GetCellSSolid(cell))
Line(zoomBLX, zoomBLY, zoomBRX, zoomBRY);
if (GetCellESolid(cell))
Line(zoomTRX, zoomTRY, zoomBRX, zoomBRY);
if (GetCellWSolid(cell))
Line(zoomTLX, zoomTLY, zoomBLX, zoomBLY);
}
function DrawText()
{
let cell = GetCurrentCell();
let textOriginX = gridOriginX;
let textOriginY = gridOriginY + gridH + wallThickness * 3;
noStroke();
textSize(16);
textStyle(NORMAL);
textAlign(LEFT, TOP);
fill(255, 180);
text("Cell", textOriginX, textOriginY);
textStyle(BOLD);
fill(255, 255, 0);
text(`(${cell.X}, ${cell.Y})`, textOriginX + 40, textOriginY);
}
function GetCell(x, y)
{
if (x < 0 || x >= cols || y < 0 || y >= rows)
{
print(`Tried to get cell at invalid index (${x}, ${y})`);
return undefined;
}
return grid[x][y];
}
function GetCellVisited(x, y)
{
return GetCell(x, y).Visited;
}
function SetCellVisited(x, y)
{
if (x < 0 || x >= cols || y < 0 || y >= rows)
{
print(`Tried to set cell at invalid index (${x}, ${y})`);
return;
}
if (grid[x][y].Visited) return;
grid[x][y].Visited = true;
ComputeCellStripes(y);
}
function ClearCellVisited(x, y)
{
if (x < 0 || x >= cols || y < 0 || y >= rows)
{
print(`Tried to delete cell at invalid index (${x}, ${y})`);
return;
}
let cell = GetCell(x, y);
if (!cell.Visited) return;
cell.Visited = false;
if (y >= 1 && !GetCellVisited(x, y - 1))
SetN(x, y, DoorType.Open);
if (y < rows - 1 && !GetCellVisited(x, y + 1))
SetS(x, y, DoorType.Open);
if (x < cols - 1 && !GetCellVisited(x + 1, y))
SetE(x, y, DoorType.Open);
if (x >= 1 && !GetCellVisited(x - 1, y))
SetW(x, y, DoorType.Open);
ComputeCellStripes(y);
}
function GetN(x, y) { return GetCell(x, y).N; }
function GetS(x, y) { return GetCell(x, y).S; }
function GetE(x, y) { return GetCell(x, y).E; }
function GetW(x, y) { return GetCell(x, y).W; }
function SetN(x, y, doorType)
{
if (y <= 0) return; // TODO: more robust error checking
let cell = GetCell(x, y);
if (cell.N === doorType) return;
cell.N = doorType;
ComputeHLines(y - 1);
}
function SetS(x, y, doorType)
{
if (y >= rows - 1) return; // TODO: more robust error checking
let cell = GetCell(x, y);
if (cell.S === doorType) return;
cell.S = doorType;
ComputeHLines(y);
}
function SetE(x, y, doorType)
{
if (x >= cols - 1) return; // TODO: more robust error checking
let cell = GetCell(x, y);
if (cell.E === doorType) return;
cell.E = doorType;
ComputeVLines(x);
}
function SetW(x, y, doorType)
{
if (x <= 0) return; // TODO: more robust error checking
let cell = GetCell(x, y);
if (cell.W === doorType) return;
cell.W = doorType;
ComputeVLines(x - 1);
}
function GetCellNSolid(cell)
{
return cell.N === DoorType.Wall || cell.N === DoorType.OneWay ||
cell.N === DoorType.Bomb || cell.N === DoorType.Secret;
}
function GetCellSSolid(cell)
{
return cell.S === DoorType.Wall || cell.S === DoorType.OneWay ||
cell.S === DoorType.Bomb || cell.S === DoorType.Secret;
}
function GetCellESolid(cell)
{
return cell.E === DoorType.Wall || cell.E === DoorType.OneWay ||
cell.E === DoorType.Bomb || cell.E === DoorType.Secret;
}
function GetCellWSolid(cell)
{
return cell.W === DoorType.Wall || cell.W === DoorType.OneWay ||
cell.W === DoorType.Bomb || cell.W === DoorType.Secret;
}
function GetNSolid(x, y)
{
let d = GetN(x, y);
return d === DoorType.Wall || d === DoorType.OneWay ||
d === DoorType.Bomb || d === DoorType.Secret;
}
function GetSSolid(x, y)
{
let d = GetS(x, y);
return d === DoorType.Wall || d === DoorType.OneWay ||
d === DoorType.Bomb || d === DoorType.Secret;
}
function GetESolid(x, y)
{
let d = GetE(x, y);
return d === DoorType.Wall || d === DoorType.OneWay ||
d === DoorType.Bomb || d === DoorType.Secret;
}
function GetWSolid(x, y)
{
let d = GetW(x, y);
return d === DoorType.Wall || d === DoorType.OneWay ||
d === DoorType.Bomb || d === DoorType.Secret;
}
function GetHWall(x, y)
{
if (x < 0 || x >= cols || y < 0 || y >= rows - 1)
{
print(`Tried to get hWall at invalid index (${x}, ${y})`);
return;
}
return hWalls[x][y];
}
function SetHWall(x, y)
{
if (x < 0 || x >= cols || y < 0 || y >= rows - 1)
{
print(`Tried to set hWall at invalid index (${x}, ${y})`);
return;
}
if (hWalls[x][y]) return;
hWalls[x][y] = true;
ComputeHLines(y);
}
function ClearHWall(x, y)
{
if (x < 0 || x >= cols || y < 0 || y >= rows - 1)
{
print(`Tried to clear hWall at invalid index (${x}, ${y})`);
return;
}
if (!hWalls[x][y]) return;
hWalls[x][y] = false;
ComputeHLines(y);
}
function GetVWall(x, y)
{
if (x < 0 || x >= cols - 1 || y < 0 || y >= rows)
{
print(`Tried to get vWall at invalid index (${x}, ${y})`);
return;
}
return vWalls[x][y];
}
function SetVWall(x, y)
{
if (x < 0 || x >= cols - 1 || y < 0 || y >= rows)
{
print(`Tried to set vWall at invalid index (${x}, ${y})`);
return;
}
if (vWalls[x][y]) return;
vWalls[x][y] = true;
ComputeVLines(x);
}
function ClearVWall(x, y)
{
if (x < 0 || x >= cols - 1 || y < 0 || y >= rows)
{
print(`Tried to clear vWall at invalid index (${x}, ${y})`);
return;
}
if (!vWalls[x][y]) return;
vWalls[x][y] = false;
ComputeVLines(x);
}
function ComputeCellStripes(rowIndex)
{
let stripes = [];
let stripe = null;
for (let colIndex = 0; colIndex < cols; ++colIndex)
{
if (GetCellVisited(colIndex, rowIndex))
{
if (!stripe)
{
stripe =
{
Start: colIndex,
Length: 0,
};
}
++stripe.Length;
}
else
{
if (stripe)
{
stripes.push(stripe);
stripe = null;
}
}
}
if (stripe)
stripes.push(stripe);
cellStripes[rowIndex] = stripes;
}
function ComputeHLines(rowIndex)
{
let lines = [];
let hLine = null;
for (let colIndex = 0; colIndex < cols; ++colIndex)
{
if (GetSSolid(colIndex, rowIndex) || GetNSolid(colIndex, rowIndex + 1))
{
if (!hLine)
{
hLine =
{
Start: colIndex,
Length: 0,
};
}
++hLine.Length;
}
else
{
if (hLine)
{
lines.push(hLine);
hLine = null;
}
}
}
if (hLine)
lines.push(hLine);
hLines[rowIndex] = lines;
}
function ComputeVLines(colIndex)
{
let lines = [];
let vLine = null;
for (let rowIndex = 0; rowIndex < rows; ++rowIndex)
{
if (GetESolid(colIndex, rowIndex) || GetWSolid(colIndex + 1, rowIndex))
{
if (!vLine)
{
vLine =
{
Start: rowIndex,
Length: 0,
};
}
++vLine.Length;
}
else
{
if (vLine)
{
lines.push(vLine);
vLine = null;
}
}
}
if (vLine)
lines.push(vLine);
vLines[colIndex] = lines;
}
function HandleInput()
{
if (Inputs.Right.Triggered())
{
if (Inputs.A.Down())
ToggleCurrentWallE();
else
MoveCursorE();
}
if (Inputs.Left.Triggered())
{
if (Inputs.A.Down())
ToggleCurrentWallW()
else
MoveCursorW();
}
if (Inputs.Down.Triggered())
{
if (Inputs.A.Down())
ToggleCurrentWallS()
else
MoveCursorS();
}
if (Inputs.Up.Triggered())
{
if (Inputs.A.Down())
ToggleCurrentWallN();
else
MoveCursorN();
}
if (Inputs.A.Triggered())
SetCurrentCellVisited();
}
function MoveCursorN()
{
--cursorY;
if (cursorY < 0)
cursorY += rows;
}
function MoveCursorS()
{
++cursorY;
if (cursorY >= rows)
cursorY -= rows;
}
function MoveCursorE()
{
++cursorX;
if (cursorX >= cols)
cursorX -= cols;
}
function MoveCursorW()
{
--cursorX;
if (cursorX < 0)
cursorX += cols;
}
function GetCurrentCell()
{
return GetCell(cursorX, cursorY);
}
function GetCurrentCellVisited()
{
return GetCellVisited(cursorX, cursorY);
}
function SetCurrentCellVisited()
{
SetCellVisited(cursorX, cursorY);
}
function ClearCurrentCellVisited()
{
ClearCellVisited(cursorX, cursorY);
}
function ToggleCurrentWallN()
{
if (cursorY <= 0) return;
if (GetNSolid(cursorX, cursorY))
{
SetN(cursorX, cursorY, DoorType.Open);
SetS(cursorX, cursorY - 1, DoorType.Open);
}
else
{
SetN(cursorX, cursorY, DoorType.Wall);
SetS(cursorX, cursorY - 1, DoorType.Wall);
}
}
function ToggleCurrentWallS()
{
if (cursorY >= rows - 1) return;
if (GetSSolid(cursorX, cursorY))
{
SetS(cursorX, cursorY, DoorType.Open);
SetN(cursorX, cursorY + 1, DoorType.Open);
}
else
{
SetS(cursorX, cursorY, DoorType.Wall);
SetN(cursorX, cursorY + 1, DoorType.Wall);
}
}
function ToggleCurrentWallE()
{
if (cursorX >= cols - 1) return;
if (GetESolid(cursorX, cursorY))
{
SetE(cursorX, cursorY, DoorType.Open);
SetW(cursorX + 1, cursorY, DoorType.Open);
}
else
{
SetE(cursorX, cursorY, DoorType.Wall);
SetW(cursorX + 1, cursorY, DoorType.Wall);
}
}
function ToggleCurrentWallW()
{
if (cursorX <= 0) return;
if (GetWSolid(cursorX, cursorY))
{
SetW(cursorX, cursorY, DoorType.Open);
SetE(cursorX - 1, cursorY, DoorType.Open);
}
else
{
SetW(cursorX, cursorY, DoorType.Wall);
SetE(cursorX - 1, cursorY, DoorType.Wall);
}
}
function ShowCursor()
{
cursorHidden = false;
}
function HideCursor()
{
cursorHidden = true;
}
function ToggleCursor()
{
if (cursorHidden)
ShowCursor();
else
HideCursor();
}
function Line(x0, y0, x1, y1)
{
x0 = floor(x0) + 0.5;
y0 = floor(y0) + 0.5;
x1 = floor(x1) + 0.5;
y1 = floor(y1) + 0.5;
line(x0, y0, x1, y1);
}
function Rect(x, y, w, h)
{
// x = floor(x) + 0.5;
// y = floor(y) + 0.5;
// w = floor(w) + 0.5;
// h = floor(h) + 0.5;
rect(x, y, w, h);
}