I’m going to cover the functions of the player character, including my custom arm swing implementation, the climb up, the BPI climbable interface and how it fits into the player pawn and it’s parent. Plus some other smaller related things.
The arm swing starts in begin play, I just set the movement mode to be arm swing as the parent pawn has many different movement modes and I don’t want them to be doing anything.
Then I set up two timers to calculate the amount of arm movement. The first runs at 0.05s and calculates the change in position of both hands over that period. The second runs every 0.3s and gets an average of the changes in position over this period, the goal being to smooth out the movement of the player so it is less jittery. Without this the player would slow down as their hand get to the top of their swing and go faster mid swing. Then to the right I set up some initial values for these functions.
In the first function ‘Calculate Arm Swing Amount’ I simply get the change in z position, then store the current position ready for the function to run again. I do this for both hands.
In the second function ‘Calculate Arm Swing Average Over Time’ I take the stored values add them to a total, calculate the average and then reset the values ready for next time it’s run. I do this for both hands.
At the start of the event tick I check if the player is climbing. Then if they are holding anything and finally I check to see if both of the hands are moving enough (this lets you reach out with one hand without moving by accident).
After that I do a check to see if the player is close to an edge.
If they are close to an edge then I adjust the calculation for the speed so they move a bit slower, this helps stop the player accidentally running off an edge and helps them to swap between running and climbing sections with less frustrations.
Finally I add movement input to the player with the speed as the scale value and the direction as an average of where the player is looking and the direction of the hands from the head.
The climb up takes the player from being on a wall to on top of the wall. The player initiates a climb up by getting to the top of the wall and then bringing their hands to their hips as they would in real life. If the player is climbing I run a series of checks on the event tick to see if they are ready for a climb up.
The first check is to see if the players hands are both lower than the headset.
Then I check with a sphere trace to see if an object is in front of the player to make sure they are at the top of the wall.
Then I do a trace down in front of the player to get the location I’m going to move them to.
Finally I move the player to their new location using two timelines, the first moves them up to the correct height and the second moves them forward. I do this to give the feeling of climbing up and over and to prevent the player clipping through any obstacles.
Thumb stick adjustments
Here I overwrite the parent stick stuff and let the player adjust their position using either of the thumb sticks (when not arm swinging or climbing), this is so they can have some fine control if they reach for something but are just out of range.
This interface is used to call events on objects when the player interacts with them either by overlapping with grip being possible or gripping. There are events for the left and right hand. In the event graph for the player pawn you can find where they are called.
Gripping events are called from two functions ‘ReleaseGrip’ and ‘InitClimbing’ both are inherited from the parent.
I have created a release grip function and added it to the parent here, the function does nothing on the parent but is implemented in the child.
Here you can see that when the function is called it takes the hand and calls the appropriate event if the gripped object implements the interface.
Init climbing is a function that already exists in the parent. In the child I added some of my own code and then do the parent function stuff. Here I make a temp array of the overlapped objects.
And then get the closest one to the centre of the overlap sphere.
I then take the closest object and call the grip event.
Finally I run the parent function.
There are a few additional changes that I have made to the parent class. The first you can see here I make sure that the player can only climb on things that implement the interface.
Here I added some code to allow physics objects to be climbed on if they contain the component tag ‘ForceClimb’.
Arm length calibration
The calibration uses a separate child pawn that can’t move and a calibration map that has instructions for the player. In the ‘Steam_VR_Player_Controller’ I have updated the spawn logic to check to see if the player has been calibrated. First I check if the player is in the calibration map already and if they are then I spawn the calibration pawn. Then if they are not on that map I check if they have already calibrated. If calibrated I spawn them as the regular child pawn. If they are not I save the map they were on, load them into the calibration map and then spawn the calibration pawn.
In the calibration pawn the arm length is calculated when the player presses a grip button. They can then proceed by pressing a face button. The arm length and calibration status is saved in a save game object. The map they were previously on is then loaded.