Godot VR Climbing

In AR/VR Development


Godot VR Climbing - read the full article about VR tutorial, AR/VR Development and Augmented & Virtual Reality Solutions from Bastiaan Olij on Qualified.One
alt
Bastiaan Olij
Youtube Blogger
alt

Hi and welcome to another Godot VR tutorial video.

Today were going to look at a climbing mechanic.

Ive created this example project and  well just look at how its put together.  The link to the github project  is in the description below.  Let me know in the comments if  you prefer this style of video.

The mechanic is pretty straight forward, the player can grab the hand holds  and pull themselves upwards.   The scene in Godot consists off  a small section of a rock face, its only about 60 meters high and maybe  100 meters wide. Most of the rock face is created with a single asset that is used multiple  times and simply rotated to create variations.

Standing on the rock face obscures  enough of the surroundings that the player has no idea there  isnt a whole mountain there.

This is a very simple scene that  can be dressed up a lot further but it does show how you can obtain a  really nice effect with very little assets.

We have a player sub scene here, well  have a closer look at that in a minute.

Well start with the hand holds  scattered along our path up the mountain.

We have a single scene for a hand hold  that is just used a number of times.

Looking at this scene we see  that is a very simple scene.

Ive just used two bars to make the hand hold, you can replace it with a nicer  mesh or create variations.

At the root we have a static body, this  allows us to interact with the hand hold.  Ive put this static body into  layer 2 to make detection easier.

We also need a collision shape for our static body and this is just a box  that contains the hand hold.

We also have two spatial nodes that allow us to  anchor our hands to when we grab the hand hold.

There are separate ones for each hand as  their orientation is slightly different.

Just to demonstrate this Ill  load in my hand mesh scene and we can see the hand anchored  to one of these spatial points.

Looking at the script for this scene  all we find here is a helper method that returns the global transform  of the anchor for a given hand.

Looking at our player we find our standard  ARVROrigin node at the root. Im using the OpenXR plugin here and have assigned its first  person controller script to my root node.

The rest of the scene is setup with  different subscenes for the hands hence Im not using the first person  controller scene from the plugin.

We have a configuration node that provides easy  access to the configuration of the OpenXR plugin.

We also have an ARVRCamera node,  note that I have unticked layer 10 and added a mesh as a child that  has been placed in this layer.

This results in our head casting a shadow without  the head actually being visible to the player.

For now the head is just a capsule shape.

Next are our left and right hand  scenes, we reuse the same scenes as we want the same logic to enable  grabbing hand holds with either hand.

At the root of our hand scene  is an ARVRController node.

Next is a spatial node on  which we anchor our hand mesh.

This is the node well be moving to  adjust the position of the hand mesh when we grab a hand hold.

Note that this node is moved into place so our hand mesh is in a natural position as  our controller node is not centered on the hand.

Finally we have a subscene  that is our hand detector node.

At the root here is an area  node that is set to detect any object within the area that are in layer  2, so it will only detect our hand holds.

Looking at the script on our  hand controller well find all the logic that allows us to grab the hand holds.

At the top weve got a variable that keeps  track of which hand hold is nearest to us.

We have a variable that indicates whether  we are holding on to that hand hold.

And we have a variable in which we store  our original transform for our anchor. As well be moving this we  need to remember this location.

Next we have a helper method that returns our  is holding variable, well need this later on.

Then when our script is ready, and when our  detector area detects hand holds entering or leaving our area we call a function that  will determine our closest hand hold.

We can see here how our signals are setup.

We obtain an array with hand  holds that are in our area, if this array is empty we clear our variable.

If we do have entries in our area we loop through  this to find out which one is closest to us.

Looking at our process code we  default our is holding to false and then check if we have a nearest hand hold.

If not we simply reset the  transform to our original value and we assign our grab property on our  hand mesh scene based on our grip value.

On controllers that support it, our grip value represents how much  we are squeezing our controller.

The property on our hand mesh scene  changes whether our hand is open or closed.

If we do have a hand hold were  closest to we first obtain the transform for the correct anchor  point from our hand held scene.

We want this transform in the local space of  our controller node, to do this we multiply the inverse of our controllers global  transform with the anchors transform.

This means that both our hand held anchor and  our source anchor are in the same locality making it easy to work with them.

Now we check if our grip button is pressed.

If this is true we place our hand anchor using the transform we calculated from the  hand holds anchor. This places our hand on that hand hold even if the physical location  of our hand isnt exactly at this position.

We also set our grab property to 1 closing our  hand so it looks like weve grabbed the hand hold.

Finally we set our is holding variable to true.

If our grip button is not pressed we are going  to move our hand between our controllers position and the position of the hand hold based on the  distance our controller is to our hand hold.

This gives the effect our hand hold  acts like a magnet to our hand.

We simply calculate this distance, divide it by  the radius of our detector to get a value between 0 and 1 and then interpolate between our hand  hold anchor transform and our original transform.

We also assign our grab property based  on our grab input on our controller.

All the code so far allows us to grab the  hand holds we have placed around our scene but it doesnt yet move our player when the player  moves their hands while holding a hand hold.

This logic is controlled by a script placed  on a helper node called movement control.

As we want this logic to be performed after the logic on each hand, we want  this further down in our node tree.

In our script we setup a few export variables so we know which nodes represent our  hands and which node is our origin node.

Next we keep track off which hands are current holding hand  holds and what their last position was.  We also have a variable that tracks how fast were  falling when were not holding any hand holds.

In our process function were  going to check each hand.

First we obtain the is holding  value from the script on our hand and then we compare it to the previous value.

If it has changed we simply assign the new  value. When weve just grabbed a hand hold we dont know yet how much weve moved  since grabbing it so we skip that bit.

If the value didnt change and  we are holding our hand hold, we calculate our delta movement and add it  to our delta variable and increase our count.

We do the same for our right  hand as we did for our left hand.

Now we check if our hand holding  count is bigger then zero.

If so we start by dividing our delta movement by  the number of hands that is holding a hand hold.

If only one hand is holding a  hand hold this count will be 1 and our delta will be just  the movement of that hand.

If both hands are holding a  hand hold our count will be two and our delta ends up being the  average of the movement of both hands.

Now we simply subtract this delta movement from  the global position of our origin node. This moves the player in the opposite  direction of our hand movement.

To keep our hands locked on our hand  holds we need to move the hand anchors for any hand holding a hand  hold by adding our delta.

We also reset our fall velocity here.

If we are not holding any hand holds  were going to apply our fall logic.

Here we simply increase our  fall velocity by our gravity, and then apply our velocity to our Y position.

If our Y becomes 0 we hit  the ground and stop falling. Im not detecting here if our  player has falled to their death.

Finally for each hand that is holding a hand hold, we store their current positions so we can  use them to calculate our deltas next frame.

And that is the whole solution to  implement a climbing mechanic in VR.

Thank you for watching and especially a thank  you to all my patrons and Youtube members who have stuck by me this year.  If you want to support my work, please consider becoming a patron or a member.

You can follow me on twitter for more  regular updates of what Im working on.

Please leave a like on the  video if you enjoyed the content and let me know in the comment  whether you enjoyed this format.

Until next time

Bastiaan Olij: Godot VR Climbing - AR/VR Development