Add configuration option for ghost reset distance. Improve documentation.
This commit is contained in:
@@ -1,17 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Generate maze.txt geometry by tracing the outline of a binary maze image.
|
||||
# The script expects the maze PNG to be white-on-black and writes walls/floor
|
||||
# segments in the format ghostland.cpp consumes at runtime.
|
||||
|
||||
import matplotlib.image as mpimage
|
||||
|
||||
# TODO: parameterize this path via CLI flags or config.
|
||||
img = mpimage.imread("/home/cowley/Pictures/maze.png")
|
||||
rows = len(img)
|
||||
cols = len(img[0])
|
||||
|
||||
|
||||
def isfilled(val):
|
||||
# Pixels brighter than ~20% are treated as walls.
|
||||
return all(x > 0.2 for x in val)
|
||||
|
||||
|
||||
def getval(img, x, y):
|
||||
# Bounds-check helpers so we can safely probe virtual border pixels.
|
||||
if y < 0 or y >= len(img):
|
||||
return False
|
||||
if x < 0 or x >= len(img[y]):
|
||||
@@ -20,6 +27,8 @@ def getval(img, x, y):
|
||||
|
||||
|
||||
segments = []
|
||||
# Sweep the image in four directions to emit axis-aligned wall segments.
|
||||
# Horizontal sweep detecting transitions from empty -> filled above (top edges).
|
||||
for iy in range(-1, rows + 1):
|
||||
seg_start = None
|
||||
for ix in range(-1, cols + 1):
|
||||
@@ -34,6 +43,7 @@ for iy in range(-1, rows + 1):
|
||||
segments.append((seg_start, (cols - 0.5, iy - 0.5), (0.0, 0.0, 1.0)))
|
||||
|
||||
|
||||
# Horizontal sweep detecting transitions from empty -> filled below (bottom edges).
|
||||
for iy in range(-1, rows + 1):
|
||||
seg_start = None
|
||||
for ix in range(-1, cols + 1):
|
||||
@@ -47,6 +57,7 @@ for iy in range(-1, rows + 1):
|
||||
if seg_start is not None:
|
||||
segments.append((seg_start, (cols - 0.5, iy + 0.5), (0.0, 0.0, -1.0)))
|
||||
|
||||
# Vertical sweep detecting transitions from empty -> filled on the left.
|
||||
for ix in range(-1, cols + 1):
|
||||
seg_start = None
|
||||
for iy in range(-1, rows + 1):
|
||||
@@ -60,6 +71,7 @@ for ix in range(-1, cols + 1):
|
||||
if seg_start is not None:
|
||||
segments.append((seg_start, (ix - 0.5, rows - 0.5), (-1.0, 0.0, 0.0)))
|
||||
|
||||
# Vertical sweep detecting transitions from empty -> filled on the right.
|
||||
for ix in range(-1, cols + 1):
|
||||
seg_start = None
|
||||
for iy in range(-1, rows + 1):
|
||||
@@ -73,10 +85,12 @@ for ix in range(-1, cols + 1):
|
||||
if seg_start is not None:
|
||||
segments.append((seg_start, (ix + 0.5, rows - 0.5), (1.0, 0.0, 0.0)))
|
||||
|
||||
print(segments[:10])
|
||||
print(segments[:10]) # Quick sanity check; remove or redirect for batch runs.
|
||||
|
||||
# Serialize into the legacy maze.txt format ghostland.cpp expects.
|
||||
res = {}
|
||||
res["players"] = []
|
||||
# Hard-coded spawn until a better level editor exists.
|
||||
player = {
|
||||
"y": 2.5,
|
||||
"x": 845.0,
|
||||
@@ -86,6 +100,7 @@ player = {
|
||||
res["players"].append(player)
|
||||
res["surfaces"] = []
|
||||
for segment in segments:
|
||||
# Build quads with outward normals stored as the fifth element.
|
||||
p1 = {"x": segment[0][0], "z": -segment[0][1], "y": 0.0}
|
||||
p2 = {
|
||||
"x": segment[1][0],
|
||||
@@ -110,10 +125,12 @@ xmax = 0.0
|
||||
zmin = 0.0
|
||||
zmax = 0.0
|
||||
|
||||
# Write the flattened surfaces followed by a floor bounding box so the game can detect footsteps.
|
||||
with open("maze.txt", "w") as f:
|
||||
f.write(f"{player['x']} {player['y']} {player['z']} {player['yaw']}\n")
|
||||
f.write(f"{len(res['surfaces'])}\n")
|
||||
for segment in res["surfaces"]:
|
||||
# Track extrema to write a single floor plane at the end.
|
||||
for point in segment[:4]:
|
||||
if point["x"] < xmin:
|
||||
xmin = point["x"]
|
||||
|
||||
Reference in New Issue
Block a user