diff --git a/compile_navmesh.py b/compile_navmesh.py
index 2091722..d2826d5 100644
--- a/compile_navmesh.py
+++ b/compile_navmesh.py
@@ -5,8 +5,14 @@ _, inpath, outpath, basename = sys.argv
tree = lxml.etree.parse(inpath)
-tris = []
-edge2tri = {}
+polys = []
+edge2poly = {}
+
+# Polygons must be convex to work correctly, but we don't verify that
+
+def points_to_edges(points):
+ points = points + [points[0]]
+ return zip(points[:-1], points[1:])
for polygon in tree.findall("objectgroup[@name='navmesh']/object/polygon"):
basex = int(polygon.getparent().attrib["x"])
@@ -26,33 +32,32 @@ for polygon in tree.findall("objectgroup[@name='navmesh']/object/polygon"):
cross = abx*acy-acx*aby
# positive for clockwise winding order. Example clockwise winding order: (0,0), (1,0), (0,1)
if cross < 0:
- points = points[0],points[2],points[1]
- bx,by,cx,cy=cx,cy,bx,by
- cross = -cross
+ points = points[::-1]
- assert len(points)==3, "triangles only"
- tri_id = len(tris)
- tris.append(points)
+ poly_id = len(polys)
+ polys.append(points)
- for edge in [(points[0],points[1]), (points[1],points[2]), (points[2],points[0])]:
+ print(points)
+ for edge in points_to_edges(points):
edge_id = tuple(sorted(edge))
- if edge_id not in edge2tri: edge2tri[edge_id] = []
- edge2tri[edge_id].append(tri_id)
- assert len(edge2tri[edge_id]) <= 2, "more than 2 triangles share edge "+str(edge_id)
+ print(edge, edge_id)
+ if edge_id not in edge2poly: edge2poly[edge_id] = []
+ edge2poly[edge_id].append(poly_id)
+ assert len(edge2poly[edge_id]) <= 2, "more than 2 polygons share edge "+str(edge_id)
-pathfind_edges = [[] for _ in range(len(tris))]
-for edgetris in edge2tri.values():
- assert len(edgetris) in (1,2)
- if len(edgetris) == 1: continue
- t1,t2 = edgetris
- pathfind_edges[t1].append(t2)
- pathfind_edges[t2].append(t1)
+pathfind_edges = [[] for _ in range(len(polys))]
+for edgepolys in edge2poly.values():
+ assert len(edgepolys) in (1,2)
+ if len(edgepolys) == 1: continue
+ p1,p2 = edgepolys
+ pathfind_edges[p1].append(p2)
+ pathfind_edges[p2].append(p1)
-pathfind_matrix = [[255 for _1 in range(len(tris))] for _2 in range(len(tris))]
+pathfind_matrix = [[255 for _1 in range(len(polys))] for _2 in range(len(polys))]
# pathfind_matrix[source][dest] is how to get to dest from source
-for dest in range(len(tris)):
- # Find paths to tri by breadth-first search. We don't take the size of the triangle into account yet.
+for dest in range(len(polys)):
+ # Find paths to poly by breadth-first search. We don't take the size of the polygon into account yet.
openset = [dest]
while len(openset)>0:
cur, openset = openset[0], openset[1:]
@@ -66,11 +71,13 @@ for dest in range(len(tris)):
out = open(outpath,"w")
out.write("#include \"compiled_structures.h\"\n")
-out.write(f"static const struct navmesh_tri {basename}_triangles[{len(tris)}] = {{\n");
-for tri_id,points in enumerate(tris):
- out.write("\t{\n\t\t{\n");
- for a,b,c in [(points[0],points[1],points[2]), (points[1],points[2],points[0]), (points[2],points[0],points[1])]:
- (ax,ay),(bx,by),(cx,cy) = a,b,c
+out.write(f"static const struct navmesh_tri {basename}_triangles[{len(polys)}] = {{\n");
+for poly_id,points in enumerate(polys):
+ out.write("\t{\n")
+ out.write("\t\t"+str(len(points))+",\n")
+ out.write("\t\t(const struct navmesh_tri_edge[]){\n")
+ for a,b in points_to_edges(points):
+ (ax,ay),(bx,by) = a,b
# edge a-b and c is the other point
# Line equation Px+Qy+R=0 from https://math.stackexchange.com/questions/422602/convert-two-points-to-line-eq-ax-by-c-0
P,Q,R=ay-by,bx-ax,ax*by-bx*ay
@@ -82,29 +89,29 @@ for tri_id,points in enumerate(tris):
R *= norm
edge_id = tuple(sorted((a,b)))
- tris_on_edge = edge2tri[edge_id]
- assert len(tris_on_edge) in (1,2)
- assert tri_id in tris_on_edge
- if len(tris_on_edge) == 2:
- other_tri_id = [x for x in tris_on_edge if x!=tri_id][0]
+ polys_on_edge = edge2poly[edge_id]
+ assert len(polys_on_edge) in (1,2)
+ assert poly_id in polys_on_edge
+ if len(polys_on_edge) == 2:
+ other_poly_id = [x for x in polys_on_edge if x!=poly_id][0]
else:
- other_tri_id = -1
+ other_poly_id = -1
centx, centy = (ax+bx)/2, (ay+by)/2
- out.write(f"\t\t\t{{{P},{Q},{R},{other_tri_id},{{{int(centx)},{int(centy)}}}}},\n")
+ out.write(f"\t\t\t{{{P},{Q},{R},{other_poly_id},{{{int(centx)},{int(centy)}}}}},\n")
out.write("\t\t},\n")
- out.write("\t\t{" + ",".join(f"{{{x},{y}}}" for x,y in points) + "},\n")
+ out.write("\t\t(const struct navmesh_point[]){" + ",".join(f"{{{x},{y}}}" for x,y in points) + "},\n")
out.write("\t},\n");
out.write("};\n")
-out.write(f"static const unsigned char {basename}_pathfind[{len(tris)*len(tris)}] = {{\n")
-for dest in range(len(tris)):
+out.write(f"static const unsigned char {basename}_pathfind[{len(polys)*len(polys)}] = {{\n")
+for dest in range(len(polys)):
out.write("\t")
- for source in range(len(tris)):
+ for source in range(len(polys)):
out.write(str(pathfind_matrix[source][dest])+",")
out.write("\n")
out.write("};\n")
-out.write(f"extern const struct navmesh {basename} = {{{len(tris)}, {basename}_triangles, {basename}_pathfind}};\n")
+out.write(f"extern const struct navmesh {basename} = {{{len(polys)}, {basename}_triangles, {basename}_pathfind}};\n")
diff --git a/compiled_structures.h b/compiled_structures.h
index d772d2c..14d0e55 100644
--- a/compiled_structures.h
+++ b/compiled_structures.h
@@ -11,8 +11,10 @@ struct navmesh_tri_edge {
struct navmesh_point center; // intermediate point for use in routing. could be improved later.
};
struct navmesh_tri {
- struct navmesh_tri_edge edges[3];
- struct navmesh_point points[3];
+ int num_verts;
+ const struct navmesh_tri_edge *edges;
+ const struct navmesh_point *points;
+ // For a triangle:
// edges[0]: points[0]-points[1]
// edges[1]: points[1]-points[2]
// edges[2]: points[2]-points[0]
diff --git a/game.cpp b/game.cpp
index e8c72ca..d7abd6c 100644
--- a/game.cpp
+++ b/game.cpp
@@ -44,20 +44,22 @@ static void transition_scene_on_walk_finish(struct script *scr, int wakeupMode,
assert(wakeupMode == SCRIPT_WAKEUP_OTHER_SCRIPT_INTERRUPTED);
}
+static void start_player_walk_to_point_then_transition_scene(int x, int y, int scene) {
+ start_player_walk_to_point(x, y);
+
+ struct script *scr = scene_add_script(OBJID_PLAYER_WALK_TO_DOOR_SCRIPT, true);
+ scr->wakeupMode = SCRIPT_WAKEUP_OTHER_SCRIPT;
+ scr->wakeupArg1 = OBJID_PLAYER_WALK_SCRIPT;
+ scr->wakeupFn = transition_scene_on_walk_finish;
+ scr->vars[0] = scene;
+}
+
void onclick(int curscene, int objid) {
switch(curscene) {
case SCENE_LOBBY:
switch(objid) {
case OBJID_DOOR_TO_MANAGERS_OFFICE_FROM_LOBBY:
- {
- start_player_walk_to_point(312, 441);
-
- struct script *scr = scene_add_script(OBJID_PLAYER_WALK_TO_DOOR_SCRIPT, true);
- scr->wakeupMode = SCRIPT_WAKEUP_OTHER_SCRIPT;
- scr->wakeupArg1 = OBJID_PLAYER_WALK_SCRIPT;
- scr->wakeupFn = transition_scene_on_walk_finish;
- scr->vars[0] = SCENE_MANAGERS_OFFICE;
- }
+ start_player_walk_to_point_then_transition_scene(312, 441, SCENE_MANAGERS_OFFICE);
return;
}
break;
diff --git a/navmesh/lobby.tmx b/navmesh/lobby.tmx
index a1682c4..8e70227 100644
--- a/navmesh/lobby.tmx
+++ b/navmesh/lobby.tmx
@@ -41,28 +41,22 @@
-
-
diff --git a/navmesh/managers_office.tmx b/navmesh/managers_office.tmx
new file mode 100644
index 0000000..ce971d6
--- /dev/null
+++ b/navmesh/managers_office.tmx
@@ -0,0 +1,86 @@
+
+
diff --git a/pinetab2_framework.cpp b/pinetab2_framework.cpp
index 63861bf..446b7b6 100644
--- a/pinetab2_framework.cpp
+++ b/pinetab2_framework.cpp
@@ -228,7 +228,7 @@ static void closest_point_inside_tri(int *x, int *y, const struct navmesh_tri *t
// If this happens, we must be in a corner region.
// Repeated normal-vector moves don't necessarily bring us to the corner, but we can just hardcode the corner.
for(int j = 0; j < 2; j++) {
- for(int i = 0; i < 3; i++) {
+ for(int i = 0; i < tri->num_verts; i++) {
double edgeval = fx*tri->edges[i].a + fy*tri->edges[i].b + tri->edges[i].c;
if(edgeval <= 0) {
// edge.a,b is normalized so that moving 1 unit of a and 1 unit of b changes edgeval by 1.
@@ -239,6 +239,16 @@ static void closest_point_inside_tri(int *x, int *y, const struct navmesh_tri *t
}
}
+ for(int i = 0; i < tri->num_verts; i++) {
+ int next = (i+1) % tri->num_verts;
+ int mask = (1 << i) | (1 << next);
+ if((edgeHitMask & mask) == mask) {
+ *x = tri->points[next].x;
+ *y = tri->points[next].y;
+ return;
+ }
+ }
+/*
switch(edgeHitMask) {
case 3: // hit edge 0-1 and 1-2
*x = tri->points[1].x;
@@ -252,7 +262,7 @@ static void closest_point_inside_tri(int *x, int *y, const struct navmesh_tri *t
*x = tri->points[2].x;
*y = tri->points[2].y;
return;
- }
+ }*/
// may be slightly outside of triangle due to rounding errors, but good enough for us
*x = (int)(fx + 0.5);
@@ -267,16 +277,33 @@ static double point_to_point_dist(int x, int y, const struct navmesh_point *pt)
// Returns distance from triangle, 0 if inside.
static double is_point_in_tri(int x, int y, const struct navmesh_tri *tri) {
- double edgedist[3]; // positive if outside
+ /*double edgedist[3]; // positive if outside
for(int edge = 0; edge < 3; edge++)
edgedist[edge] = -(x*tri->edges[edge].a + y*tri->edges[edge].b + tri->edges[edge].c);
if(edgedist[0] < 0 && edgedist[1] < 0 && edgedist[2] < 0) return 0; // inside
- if(edgedist[0] >= 0 && edgedist[1] >= 0) return point_to_point_dist(x, y, &tri->points[0]);
+ if(edgedist[0] >= 0 && edgedist[1] >= 0) return point_to_point_dist(x, y, &tri->points[0]); // are these correct? shouldn't it be points 1,2,0?
if(edgedist[1] >= 0 && edgedist[2] >= 0) return point_to_point_dist(x, y, &tri->points[1]);
if(edgedist[2] >= 0 && edgedist[0] >= 0) return point_to_point_dist(x, y, &tri->points[2]);
if(edgedist[0] >= 0) return edgedist[0];
if(edgedist[1] >= 0) return edgedist[1];
- if(edgedist[2] >= 0) return edgedist[2];
+ if(edgedist[2] >= 0) return edgedist[2];*/
+
+ double edgedist[tri->num_verts];
+ bool all_inside = true;
+ for(int edge = 0; edge < tri->num_verts; edge++) {
+ edgedist[edge] = -(x*tri->edges[edge].a + y*tri->edges[edge].b + tri->edges[edge].c);
+ if(edgedist[edge] > 0)
+ all_inside = false;
+ }
+ if(all_inside) return 0;
+ for(int edge = 0; edge < tri->num_verts; edge++) {
+ int next = (edge+1)%tri->num_verts;
+ if(edgedist[edge] >= 0 && edgedist[next] >= 0) return point_to_point_dist(x, y, &tri->points[next]);
+ }
+ for(int edge = 0; edge < tri->num_verts; edge++)
+ if(edgedist[edge] >= 0)
+ return edgedist[edge];
+
return 0; // branch should be unreachable; maybe within epsilon of triangle border?
}
static int find_navmesh_tri(int x, int y, int tolerance) {
@@ -378,7 +405,7 @@ static void update_player_walk_script_on_frame(struct script *scr, int wakeupMod
} else {
nextTri = cur_navmesh->pathfindgrid[player_walk_script->targetNavmeshTri * cur_navmesh->num_tris + nmtri];
nextX = -1;
- for(int edge = 0; edge < 3; edge++) {
+ for(int edge = 0; edge < cur_navmesh->tris[nmtri].num_verts; edge++) {
if(cur_navmesh->tris[nmtri].edges[edge].other_tri == nextTri) {
nextX = cur_navmesh->tris[nmtri].edges[edge].center.x;
nextY = cur_navmesh->tris[nmtri].edges[edge].center.y;