Expanding on the “Complete” Physics Platformer Kit

After discovering everything that the Complete Physics Platformer kit has to offer, I knew the time would come that I would have to emphasize the “starter kit” aspect of it and expand on its functionality. Although the kit offers the essentials such as movement, jumping, enemies with basic AI, health system, and a coin collectible all integrated with the physics system in Unity, any platforming game since the mid-90’s has offered more. Be it wall jumping, ground pounding, powerups, or even just swimming, these are all items that I eventually wanted to add to this starter kit.

Wall Kicks Will Work

I knew the logic behind how I wanted to approach this right from the start. Specifically I would use the ‘grab box’ already attached to the player (used to determine when the player can pick an item up) and if it was touching an object with the ‘Wall’ tag, it would let the player perform the wall jump. Being fairly new to C#, translating this logic to in to code proved to be quite intimidating at first. After combing through Google search results, most notably Unity Answers and forum posts, I dove in and began to implement the code. Line by line, the logic began to come together. The most difficult part was working with the rotation, specifically rotating the player 180 degrees after jumping off of the wall. Eventually I found the transform.RotateAround function which allowed me to do just that; rotating around the Vector3.up axis.

Playing around with this in game, the fact that the player would always rotate around 180 degrees from the point of the jump began to annoy me. If the player jumped at the wall at a 45 degree angle, they would turn around 180 degrees, ending up back the point which they originally approached the wall from. Besides being inconvenient it is also quite unrealistic, and for that matter not fun. Using Super Mario Sunshine as an example, when the player jumps in to a flat wall they “stick” to it and slide down it; during this time they can also jump off of it. I decided to use this mechanic to both imitate that feel and resolve the incorrect jump angle when the wall was approached from anywhere except straight-on. So I modified the logic which I was applying to the grab box trigger volume so that when the player was in the air and the grab box was touching an object tagged “Wall”, the player rotation would be set to match that of the wall and their air rotation speed would be greatly reduced (simulating the sticking). Now when the jump button was pressed, the 180 degree rotation away from the wall would match with what was expected to be seen.

I was quite happy with this, until I rediscovered the wall jumping mechanics used after playing Super Mario 64 again. For the few of you who haven’t played it, in this game there was no wall “sticking”, rather you needed to execute the wall jump the moment after colliding with a flat wall. At which point you would jump away from the wall at the perfect reflected angle; so if approached from a 45 degree angle, you would jump away at the “reflected” angle. This felt much better to me as sticking to the walls just seemed to slow things down, so I got to work updating the wall jump. I removed the “sticking” aspect of it and essentially re-implemented the old wall jump system. After hours of research, I soon found that reflecting a Raycast was the solution. After “kicking” off of the wall, I would execute the Raycast and take the Vector3.reflect from it to rotate my players transform.forward to match it. After which I would apply a force to their transform.forward (so that they would always jump “forward” after the rotation was applied) to create the wall jump I had hoped to implement from the very beginning.

P-P-P-Power up!

Besus-Powerups01I soon decided that my game needed a “gimmick” of sorts, to make it feel like more than just a barebones platforming game, so I started to brainstorm what would be fun. Moving more quickly, being more powerful, transforming, and just playing with the physics in general came to mind. It just so happened that I recently decided to migrate my primary collectibles from “power cubes” to “power cards” so I decided to roll the power-up system in to these cards as well. Upon collecting one of the power-up cards, the player would be transformed in to a different variation of the primary character. Many of the models included with the ‘Lenzo’ character asset set the tone for my choices of power-ups, originally deciding that I wanted to use the Astronaut, the Diver, the Firefighter, and the Ninja. My original plan for these power-ups was as follows:

  • Astronaut – Reduce the scene gravity allowing the player and other rigidbodies to fall much more slowly and jump far higher.
  • Diver – Increase the player move speed while underwater.
  • Firefighter – Allows the player to pass through fire (to reach new areas) which would otherwise normally kill them instantly.
  • Ninja – Move much faster, both on the ground and in the air.

After implementing all but the Firefighter, my attention diverted to another mechanic I had considered implementing from the start…

Absolutely Smashing

Besus-GroundSlam01One item that Mario 64, Banjo-Kazooie, and even Crash Bandicoot shared was a ground pound/butt stomp, and with good reason; it’s fun to smash down on things. When I first began working with this starter kit, I had no problem creating the motion of the ground pound (by simply applying a negative jump force to the player), but creating the mechanics was something I shied away from once I began to realize the complexity that was involved. Turns out however that this wasn’t nearly as complex as originally thought – partially in thanks to DanielSnd on the Unity forums. Within the official release thread for the Complete Physics Platformer Kit, Daniel had contributed multiple scripts to expand on the default functionality. Unfortunately for me, many of these were items I had already added to the kit on my own, but among them was one which created a punching functionality. It worked by toggling a trigger box on and off, and when activated it would apply damage to whatever was in the active trigger box. So I applied this logic to the player model, only instead of the trigger box being in-front of the player, it was under them. Upon ground slamming, I would activate the trigger box and apply a negative force to the player’s Y-axis. To add a bit of flair to it, I added a delay before the negative force is applied to the player so that they wold be “frozen” in the air allowing me to play a flip animation (similar to Mario 64 and Banjo-Kazooie). It was then that I added the necessary code to the “Health” and “DealDamage” scripts so that some objects could be flagged to only be destroyed by the new ground slam ability; everything else would take a set amount of damage.

A Whole New View

Besus-FP01One feature of platforming games that often goes under-appreciated is the first-person/close-up camera view enabling the player to freely look around the level from their current position. The logic behind this was quite simple: update the camera offset position to ‘0, 0, 0’ (to be right where the player is) and hide the player model as to not obstruct the view. On button press, the camera offset would update and the player renderer would be disabled (and vice versa for exiting the view). The controls were the more mysterious part, but after opening up the first-person controller script included with Unity I would have the code necessary to allow the player to freely look around.

Versatile and Fancy Jumps

Shortly in to playing with the kit, I found myself hitting the jump button again in the air. As the kit was coded to work like Super Mario 64 (where 3 successive jumps will gradually get higher), I knew I had to revert this to a double-jump system. This logic proved simplest of all, requiring only an integer to track the number of available jumps (a bool would also have worked but I wanted the ability to add additional air-jumps if needed). Basically the code came down to:

if (player is not grounded and they push the jump button)
Jump again;
Subtract from the double-jump integer

When they land: add back to the double-jump integer

Besus-DiveJump01In addition to this, I always liked the long-jump from Super Mario 64 so I implemented one here as well. Basically it was just a jump with more “forward” force than vertical force. The more in-depth logic came in my control scheme needed to execute this. As I wanted to keep the number of primary buttons to a minimum, the dive jump as it came to be would be executed by holding down the “grab” button and while held down, if jump was pressed it would execute this jump. The dive-jump itself came from the awkwardness of watching the player “shoot” forward when doing this (as a force was being applied to propel them forward). It was after creating the long jump animation and seeing it in-game that I felt something fancier would look better. After quickly creating a dive-jump and roll animation, I knew that I had made the right choice. So I cleaned up the animation and it has remained ever since.

Doing the Michael Phelps

Although the kit contained basic water functionality (specifically buoyancy and drag applied to rigidbodies in the water), it’s not too often that you find someone walking underwater. Although the base water functionality allowed for some fun water-based situations and puzzles, the ability to actually swim would open up far more possibilities (and felt much more natural). Little did I know just how extensive this implementation would be…

Swimming01I only knew the basics getting in to this; turn off gravity when the player gets in the water and animate them appropriately. As the standard controls would not work here, the next headache was going to be updating the controls. Being that the player is underwater and gravity is now off, I felt the most-natural controls would be to control them like an airplane and apply a force to them while holding (or pressing) a button. The force part was easy; the airplane-style controls were not. This is where I was introduced to the joy of Quaternions. Before I knew too much, I was trying to directly modify the rotation which quickly got me nowhere. After putting the Quaternion in to a Debug.Log statement, I saw why this did not work. After the savior that is Unity Answers shed light on how to correctly modify these, I had the movement working near-perfectly: set a Vector3 using the axis input to control the vertical direction and then modify the eularAngle to rotate the player in the horizontal direction. Except now when the player entered the water, they always faced to the 0, 0, 0 eularAngle. They could still control fine, but not facing the direction at which they entered would be unacceptable. So to remedy this, I grabbed their eularAngle upon entry and added it the transform.eularAngle statement controlling their rotation.

Besus-Swimming01Shortly thereafter, I decided to go for the Banjo-Kazooie approach to swimming whereby they swim on the surface until told to dive under it (at which point the camera would position itself behind the player and revert the controls). This was just a matter of retaining the default controls while on the surface using the depth variable (collider.extents – RigidbodyInTheWater.transform.position) already present in the default Water script of the platformer kit. It was here where I would apply a very small force both above and below the player to keep them on the surface until told to dive, at which point I would apply a large force to push them under. This worked surprisingly well after tweaking the values and resolving some bugs that came as a result of this.

Of course this also meant that the player would no longer be able to grab object while in the water, so I remedied that by reverting the player controls back to the standard ones as soon as they grabbed something underwater (basically restoring the way that the Water script originally worked in the kit). This allowed me to retain some of the original puzzles and challenges that I had planned around the water physics all while giving the water a more natural feel.

TLDR version: it was a lot of work and required a considerable amount of bug-squashing, but I am more than happy with the end result.

Kick, Punch, It’s All In The Mind

Besus-Kick01Well more like just kick. Another thing most (if not all) platforming games have in common is a melee attack. As I already had the mechanics needed for this in the ground slam ability, it was just a matter of moving the “attack” box to the front of the player (instead of below like in the ground slam) and activating it on button press. Of course I needed to add an animations to this and prevent the player from being able to continuously attack (so I flag a bool ‘attacking’ true while they are attacking and flip it back when they are finished) but I wasn’t content with just one animation. So to remedy this and make animations flow more smoothly, I use a different attack animation depending on if the player is moving or not. The attack can be done both on the ground and in the air, so of course the same movement logic applies to both when the player is running/standing and jumping/jumping-forward.

The Utility Belt

With the player moves and abilities established, it was time to move on to fun environmental functions. I didn’t really have any of these in mind upon starting this project in Unity, so I created them as the ideas came to me while play-testing. Originally they were being created within PlayMaker, however as I began to get more comfortable with programming in C#, I soon found myself not knowing how to create these actions in PlayMaker while I knew exactly how I could do it in C#. After abandoning C# and converting my (few) existing PlayMaker functions to C#, I moved on to creating the following:

  • Explosive Box – Breaking boxes was fun as-is; breaking boxes that explode and as a result, break other boxes is even more fun. I knew that the logic needed here was to apply the damage to the health script of all items caught in the “blast radius”. So after some Googling (leading to Unity Answers and Forum posts), I found the “rigidbody.AddExplosionForce” function and used that to not only push the rigidbody in the “explosion radius” but to “Deal Damage” (platformer kit script/function) to everything in said radius to create the effect I was hoping to achieve. Spawning the explosion GameObject was just a matter of adding the explosion prefab to the “Spawn on Death” area of the health script attached to the breakable box.Besus-ExplosiveBox01
  • Enemy Projectiles – The basic enemies are no more intelligent than Goomba’s from the Mario Bros series and don’t offer much variety. So to offer a bit more challenge, I created a projectile script. In this script I have two different projectile options: homing projectile or straight-fire projectile. The homing projectile obviously follows the player for a set amount of time (adjusted by a public float) and then destroys itself. The straight-fire projectile travels at a higher speed but only travels to the location which the player is at when the projectile is Instantiated. And of course all of these projectiles are destroyed upon colliding with a programmed set of tags (walls, water, etc) as would be expected.
  • Falling Platforms – Another staple of nearly every platformer. I decided to create two different types within my script: one would drop out from the player at  high rate after a set amount of time and the other would continue to fall while the player was standing on it and then rise back up when they were not on it. I would change the color of the platform to give a visual cue to let the player know of the imminent or continuous drop. Resetting the platform was just a matter of setting the transform.position back to a “startingPosition” Vector3 holding the (you guessed it) starting transform.position.

Besus-Platform01

  • Rotating Platforms – Again two different varieties here. The first rotates the platform at a constant rate (on the set axis) while the other (far more complex) is a timed rotation, rotating the platform after a set amount of time by a set number of degrees. Creating the timed rotation script gave me the opportunity to work with everyone’s favorite: Quaternions. Luckily I had been playing with these in another (now abandoned) script and for my swimming functionality (above), so I knew how I had to go about this. The key here to anyone dealing with modifying rotations is to modify the eularAngles using a Vector3, adding the rotation amount to the particular eularAngle axis which you want to modify.
  • Button Activators – Inspired by Portal, a game with pushable and moveable items needs to have buttons to place these objects on to activate (or trigger) different things. I created a simple button from two cubes and animated it to move down upon being triggered by a tag entering the trigger and vice versa upon said item leaving the trigger area (if the button can be toggled on and off). I would then modify this base button script to accommodate whatever function I wanted it to trigger in a given scene. Ironically I wound up using single-press buttons more often than buttons than can be toggled on and off.

Player moves, check. Gameplay elements, check. With the Physics Platforming Starter Kit expanded/expanding to levels I never thought I could achieve, it is now just a matter of fighting-off the feature creep brought on by my desire to create more abilities/features/functions.

I detail this (and more) in my video development blog series:

Tagged . Bookmark the permalink.

One Response to Expanding on the “Complete” Physics Platformer Kit

Leave a Reply