Attaching Colliders To Avatar Feet

I’m not sure if anyone knows, but In my world I want to implement a system for footstep sounds in udon. However it requires a collider on the avatar feet so when the collider collides with the floor of the world, a sound will play.

My question is, how can you attach a collider to player avatar feet in a udon world?

Short answer: get a reference to the foot bones from VRCPlayerApi.GetBonePosition and do transform.SetPositionAndRotation() on the collider during FixedUpdate.

Important concerns:

  1. Not all avatars have foot bones! If you try to get the position of a non-existant bone, it won’t return null, it will instead return {0, 0, 0} a.k.a. Vector3.zero.
  2. Foot bones aren’t actually where feet are! The bone is where the foot begins, and therefore a foot bone’s location is usually right at a humanoid’s ankle.
  3. PostLateUpdate gives more accurate bone position than FixedUpdate, but it runs every frame and I’ve recommended FixedUpdate instead because this is a physics concern.

More on #2: you can do some math to try to find the position of a player’s heel:
Find the vector from the player’s knee to their ankle. This is implicitly the same direction you’ll want to move from ankle to heel (downward, or more technically “distally”). In avatar rig terms, the knee is the “Lower Leg” bone, so find ~ (foot bone position) - (lower leg position) and you’ll have that direction vector.
The obstacle is how far to move in that direction, because the distance from ankle to heel on a 6-meter-tall dragon is not the same as a 0.4-meter-tall kobold. I’ll leave it to you to figure out how to guess on that. You might consider the length of the vector you just found as a starting point.

I had to do a bunch of this math for SoccerBox. You can see my code here, in the method _AutoCalibrateLeg(): soccerbox/FootColliderCalibration.cs at main · jokerIsPunk/soccerbox · GitHub

If you’re using Udon Graph, that’s fine, it all works the same way, you’ll just have to apply the concept I described using nodes. But the functionality will work.