class_name StairGuard extends RefCounted # One continuous sloping prism replaces the stepped collision faces of a guard. static func build(parent: Node3D, x: float, first_z: float, direction: float, bottom: float, rise: float, batch: UrbanMeshBatch = null) -> void: var body := parent as StaticBody3D if body == null: body = StaticBody3D.new() if body != parent: body.name = "SmoothStairGuard" body.collision_layer = 1 body.collision_mask = 0 var points := PackedVector3Array() for end in [0.0, 1.0]: var z: float = first_z + direction * (-0.2 + end * 7.6) var y: float = bottom + rise / 38.0 + end * rise for side in [-0.06, 0.06]: for height in [0.0, 0.96]: points.append(Vector3(x + side, y + height, z)) var shape := ConvexPolygonShape3D.new() shape.points = points var collider := CollisionShape3D.new() collider.shape = shape body.add_child(collider) if body != parent: parent.add_child(body) if batch: batch.mesh(surface(points), Vector3.ZERO, "metal", Color("343b3d")) static func surface(points: PackedVector3Array) -> ArrayMesh: # Use the collision prism's exact corners: the visible top is equally smooth. var tool := SurfaceTool.new() tool.begin(Mesh.PRIMITIVE_TRIANGLES) var center := Vector3.ZERO for point in points: center += point / 8.0 for face in [[0,2,3,1], [4,5,7,6], [0,1,5,4], [2,6,7,3], [1,3,7,5], [0,4,6,2]]: for triangle in [[face[0],face[1],face[2]], [face[0],face[2],face[3]]]: var a: Vector3 = points[triangle[0]] var b: Vector3 = points[triangle[1]] var c: Vector3 = points[triangle[2]] var normal := (c-a).cross(b-a).normalized() if normal.dot((a+b+c)/3.0-center) < 0: var swap := b b = c c = swap normal = -normal for vertex in [a,b,c]: tool.set_normal(normal) tool.set_uv(Vector2(vertex.z,vertex.y)) tool.add_vertex(vertex) return tool.commit()