Skip to content

Commit

Permalink
Merge pull request #70 from FailSpy/patch-footsteps-1
Browse files Browse the repository at this point in the history
Add multiple surface functionality for meshes in Footstep System
  • Loading branch information
Phazorknight authored Feb 18, 2024
2 parents 42438ad + 287eca2 commit 1df83e1
Showing 1 changed file with 74 additions and 4 deletions.
78 changes: 74 additions & 4 deletions COGITO/DynamicFootstepSystem/Scripts/footstep_surface_detector.gd
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class_name FootstepSurfaceDetector

@export var generic_fallback_footstep_profile : AudioStreamRandomizer
@export var footstep_material_library : FootstepMaterialLibrary
var last_result

func _ready():
if not generic_fallback_footstep_profile:
Expand All @@ -14,6 +15,7 @@ func play_footstep():
var result = get_world_3d().direct_space_state.intersect_ray(query)
if result:

last_result = result
if _play_by_footstep_surface(result.collider):
return
elif _play_by_material(result.collider):
Expand Down Expand Up @@ -59,14 +61,82 @@ func _get_footstep_surface_child(collider : Node3D) -> AudioStreamRandomizer:
return null

func _get_surface_material(collider : Node3D) -> Material:
var mesh_instance = null
var meshes = []
if collider is CSGShape3D:
return collider.material
if collider is CSGCombiner3D:
#composite mesh
if collider.material_override:
return collider.material_override
meshes = collider.get_meshes()
else:
return collider.material
elif collider is StaticBody3D or collider is RigidBody3D:
#find all children of the collider static body that are of type "MeshInstance3D"
#if there are multiple materials, just default to the first one found
var mesh_instances = collider.find_children("", "MeshInstance3D")
if mesh_instances:
return mesh_instances[0].mesh.material
if collider.get_parent() is MeshInstance3D:
mesh_instance = collider.get_parent()
else:
var mesh_instances = collider.find_children("", "MeshInstance3D")
if mesh_instances:
if len(mesh_instances) == 1:
mesh_instance = mesh_instances[0]
else:
meshes = mesh_instances

if meshes:
#TODO: Handle multiple meshes
mesh_instance = meshes[0]

if mesh_instance and 'mesh' in mesh_instance:
var mesh = mesh_instance.mesh
if mesh.get_surface_count() == 0:
return null
elif mesh.get_surface_count() == 1:
return mesh.surface_get_material(0)
else:
var face = null

var ray = last_result['position'] - global_position
var faces = mesh.get_faces()

var aabb = mesh.get_aabb() as AABB
var accuracy = round(4*aabb.size.length_squared()) # dynamically calculate a reasonable grid size
var snap = aabb.size/accuracy # this will be the size of our units to snap to

var coord = null

for i in range(len(faces) / 3):
# first, figure out what face we're standing on
var face_idx = i * 3
var a = mesh_instance.to_global(faces[face_idx])
var b = mesh_instance.to_global(faces[face_idx+1])
var c = mesh_instance.to_global(faces[face_idx+2])
var ray_t = Geometry3D.ray_intersects_triangle(global_position,ray,a,b,c)
if ray_t:
face = faces.slice(face_idx,face_idx+3)
# round out vert coordinates to avoid floating point errors
coord = [round(faces[face_idx]/snap),round(faces[face_idx+1]/snap),round(faces[face_idx+2]/snap)]
break
var mat = null
if face:
for surface in range(mesh.get_surface_count()):
var surf = mesh.surface_get_arrays(surface)[0]
var has_vert_a = false
var has_vert_b = false
var has_vert_c = false
for vert in surf:
var vert_coord = round(vert/snap)
has_vert_a = has_vert_a or vert_coord == coord[0]
has_vert_b = has_vert_b or vert_coord == coord[1]
has_vert_c = has_vert_c or vert_coord == coord[2]
if has_vert_a and has_vert_b and has_vert_c:
# we found it! note the material and break free!
mat = mesh.surface_get_material(surface)
break
if has_vert_a and has_vert_b and has_vert_c:
break
return mat
return null

func _play_footstep(footstep_profile : AudioStreamRandomizer):
Expand Down

0 comments on commit 1df83e1

Please sign in to comment.