There comes a point in time with every feature that I need to stop working on it and move on to other things - one such feature recently was my capstone game Planetary Planter's movement system. When working on this feature it felt like I was constantly learning new things and solutions, so I decided to take some extra time on the side to explore mechanics I was interested in that wouldn't fit into the game itself for various reasons such as animation work.
I decided to focus my efforts on three main features: wall running, ledge grabbing, and sliding, all three of which I've never invested the time in implementing them before. First I worked on easily the most intimidating, that being wall running. My first thought was to use Unity's OnCollisionEnter/Stay/Exit functions, and it gave me much better results than expected. I suspected that limiting myself to these functions was surely going to hurt me in the long run, but in my implementation I never found myself regretting this decision.
My first goal was to translate the current velocity of the player to become parallel to the wall when jumping at the wall at an acute enough angle. Getting the detection for jumping at the wall to trigger the wallrun code was simple enough, utilizing the dot product between the XZ velocity and the normal of the wall and comparing to an angle requirement variable to prevent head on collisions from triggering a wallrun. For the wallrunning itself, that was a bit trickier to figure out, as I initially attempting to use cross products to adjust velocity to become parallel with the wall, but eventually I stumbled upon Vector3.ProjectOnPlane which helped massively with all aspects of this experiment.
OnCollisionEnter is simply initializing the wallrun.
OnCollisionStay is where the actual velocity calculation happens.
Next is sliding. I adjusted my already existing slope detection code to instead return a vector3 based on the angle of the slope while in the sliding state. Additionally, I gave the crouch sliding state a higher max speed value than normal running and its own drag value so it can keep its momentum as you'd expect a slide to do, and also limited the player's control on velocity during the slide.
For implementation, I used a raycast to detect the normal of the slope, and calculated another dot product to create a speed multiplier for the slide. I then used that variable and Vector3.ProjectOnPlane to calculate the force to return to my Integrate function.
Ledge grab detection went smoothly as well. Every frame I call GrabLedge() and use a raycast positioned in front and above the player to search for level enough surfaces to grab onto. I also gave the ledge grabbing state its own movement logic to allow for shuffling along ledges by using Vector3.ProjectOnPlant again. From the ledge, the player has the option to jump up just high enough to reach the surface they were hanging onto, or to input a direction away from the ledge (or more accurately, close enough to the ledge's wall normal) to drop downwards.
Ledge grab implementation. I used the position of the top of the ledge detection raycast and the player's position to ensure that when ledge grabbing, the Y position is consistent every time you grab any given ledge.
Ledge shuffle implementation in my Move() function.
Again, these mechanics don't make much sense to implement in Planetary Planter due to the ramifications they have on level design as well as animation work that needs to be done, but I'm still quite satisfied with how everything turned out and what I learned as a result (Dot products are incredibly useful!).
コメント