Portobelly Production Journal #1

Current state of the project

Movement

Splines

Portobelly is a side-scroller game with the majority of the player’s movement involves moving either left or right and occasionally jumping. To add more depth to the game along the Y axis, rather than locking the player to a two dimensional plane, I decided to use a spline that would allow the the player to move along the Y axis. My aim for this system is that adding movement along the Y axis would make the player feel less constrained in terms of movement.

Fig 1 - Splines can be chosen using the BP Sphere Ref variable. This will be the spline that the player moves along.

Fig 2 - Spline path example (top down view)

Fig 3 - Player moving along the example spline path

The main problem I’m having with this system is that to create a reference with the spline I have to manually select the spline I want to use, using the spline reference variable. Doing this will connect the player to the spline. The problem with this system is that it’s tedious to select the correct spline and attach it to the player and that the player has to be placed in the level so that I can connect them to the correct spline. This means I am unable to spawn the player in to the level so I may have to create a different system in the future to solve this issue.

Fig 4 - On BeginPlay move the player to the nearest point on the selected spline

The blueprints above set the players location to the closest point along the selected spline. The Z axis is not taken into account as I did not want the height of the spline to effect the players location.

Fig 5 - On EventTick the players location will be updated to the nearest point along the selected spline

This set of blueprints is attached to the event tick and controls the location of the player along the spline. Much like the last blueprint I have ignored the Z axis and it’s not connected to the spline as that would restrict the player from jumping. I plan to change this in the future as the EventTick event is performance intensive. I feel I could change this event to a timer which constrains the player to a plane rather than moving the the entire player location.

Fig 6 - Forward movement key bindings

Fig 7 - Horizontal movement along a spline using an InputAxis

The blueprint above allows the player to control their position along the selected spline with either “A“ and “D” or the left thumbstick X-Axis.

Rolling

Fig 8 - Belly rolling

Fig 9 - On EventTick the player rolls depending on the horizontal velocity

As the player moves across the environment the character (Belly), rolls along the environment. This process relies on an EventTick which maybe changed in the future as I want to avoid using EventTicks as much as possible. This blueprint could be replaced by a animation in the future as it would be less performance heavy as the current solution.

As the clip of Belly rolling shows, when the player changes direction the body of Belly snaps to a new rotation which needs to be fixed. Changing the rolling to an animation may solve this issue.

Jump

Fig 10 -  InputAction Jump blueprint

Fig 10 - InputAction Jump blueprint

Fig 11 - Set Jump Max Hold Time

Fig 12 - Small variable jump height

Fig 13 - Large variable jump height

Fig 14

The jump blueprint is fairly simple. When the jump button is pressed the player jumps and when the button is released the player stops jumping. I wanted the player to jump in this way because allowing the player to stop their jump at a set time rather than having a constant jump height gives the player more control over their jump ability. I also wanted the players jump max hold time to change so that the player could hold the jump button for different lengths of time which would result in different jump heights. in Super Mario Bros they use a variable jump height which allows Mario to perform small hops with a short press of the jump button, whereas, a long press of the jump button allows Mario to perform a long jump. This makes the Mario’s jump intuitive and prevents the player from being overwhelmed with too many different controls.


Belly’s Mask

The function behind Belly’s mask is that we did not have a way of displaying emotions on Belly so we decided to add a mask to the character so that we can change the eyes to display different emotions. For example, when Belly takes damage the eyes may change to display pain.

Fig 15 - Belly’s mask is attached to a spring arm

Fig 16 - This blueprint is attached to the forward movement input and sets the rotation of the Belly’s mask spring arm depending on the rotation of the left thumb-stick

The blueprint above controls the rotation of the Belly’s mask spring arm. Belly’s mask is attached to the end of this spring arm. I decided to use a spring arm because as shown below it is possible to apply lag to a spring arms rotation which gives a smooth rotation rather than the mask snapping to the set rotation. When creating this system I encountered an issue with the mask which involved the mask facing the wrong direction when the left thumb-stick moved left. To solve this issue I created an if statement that would check if the thumb-stick rotation was greater than -90 degrees AND less than 90 degrees. If this returned true, the spring arm would rotate 180 degrees along the X axis. If false, the spring arm would rotate 0 degrees along the X axis. The results of this process can be seen in the clip below.

Fig 17 - DegreesOfLeftThumbstick macro

Fig 18 - Mask spring arm rotation lag settings

Fig 19 - Belly’s mask rotating around it’s body based on the direction of the left thumb-stick

Fig 20 - This blueprint is attached to the shrink and expand input axis and controls the length of the spring arm based on the size of Belly

To keep the mask at the correct distance when changing size (as seen in the next section) from the centre of Belly’s body, I have used the scale of Belly along the X axis (all axis are the same so choosing a different axis would not make a difference) and multiplying the value by the length of the mask spring arm. This keeps the mask at the correct distance from the centre of the body.


Shrinking and Expanding

In Portobelly, you play as a sentient blob called Belly. One of it’s many abilities is being able to change size and with these changes of size Belly has different characteristics. These characteristics are the Belly’s speed, jump height, size, and air control.

Fig 21 - Size changing ability

Fig 22 - Key binding for the shrink and expand ability

Fig 23 - Shrink and expand input axis controlling the scale of the player

This blueprint allows the player to change the size of the mesh and the size of the capsule component with the triggers on the controller. The left trigger reduces the size of Belly and the right trigger increases Belly’s size. If the trigger is pressed all the way down the player will reach their maximum or minimum size. The main problem with this method is that if the player wanted to stay at a consistent size they would have to continue to hold down the trigger and this maybe inconvenient for the player. My solution to this issue would be a system that would remember the last size the player reached so that when the trigger is released the player does not return to it’s normal size. This would allow the player to easily adjust the size of Belly.

Fig 24 - Belly size small jump height

Fig 25 - Belly size normal jump height

Fig 26 - Belly size large jump height

Fig 27 - Max speed comparison between three different body sizes

Fig 28 - Blueprint controlling the max speed and jump velocity of the player depending on the size of the player

Fig 29 - Belly size small air control

Fig 30 - Belly size normal air control

Fig 31 - Belly size large air control

Fig 32 - Blueprint controlling the players air control depending on the size of the player

Air control is a variable that controls how much movement the player has whilst airborne. This variable has a maximum value of 1 (movement in the air is equal to walk speed) and a minimum value of 0 (the player is unable to move in the air). I setup a clamp value for the variable between 0.1 to 1 so that the player always have some level of air control at any size. I wanted to create “sluggish” feeling movement when the player is full size so I decided to give the player a low air control value whereas when the player is small they are able to manoeuvre easily through the air which will allow the player to land with precision.


Suction and Digestion Ability

Belly’s main form of attack will be the suction and digestion ability. The suction ability allows Belly to pull objects/enemies towards it’s location. When the object/enemy reaches a certain distance from the player the object will be consumed. During this state, Belly inflicts damage on the object/enemy until it runs out of health or is ejected from Belly’s body.

Fig 33 - Belly using the suction ability

Fig 34 - Suction cone setup. This cone has visibility disabled but I enabled it just for demonstration

Fig 35 - Temporary suction cone material

The suction cone represents the area that Belly is able to pull enemies towards itself. The cone is a temporary asset that will be changed for a suction particle effect later in production.

Fig 36 - Belly using the suction ability on a group of static meshes. The digestion ability only allows for one object to be digested at a time.

When Belly is absorbing a group of enemies, it pulls the entire group towards itself as long as they are within range. Only the first enemy will be absorbed until the enemy is digested or ejected from Belly and then it will absorb the next enemy.

Fig 37 - Absorb input action blueprint

Fig 38 - Absorb custom event

This absorb system applies a radial impulse with a negative strength to the enemy which pulls the enemy towards the player. This force is only applied to the enemies that are within the suction cone. This method only works for actors that have physics enabled so I had to create an if statement that checks if the enemies mesh is simulating physics. If this returns false, simulate physics will be set as true and the radial impulse will be applied.

This system only works for static meshes so in the future I will need to adapt the system so that it works for skeletal meshes as the enemies will be a skeletal mesh asset.

Fig 39 - Digestion radius

If the enemy enters the sphere collision above while the suction ability is active the first enemy/object will be absorbed and digested.

Fig 40 - Digestion queue blueprint

To allow the player to digest one object at a time, I created a custom event that checks if there is a current object in digestion. The DoOnce node prevents multiple objects from being digested and is reset when there is digested object (this is called first to make contact variable) is not valid. After the DoOnce node is completed the digestion timer is activated. This timer can be seen below.

Fig 41 - Digestion timer blueprints

Fig 42 - Digestion function

This function above applies damage to the object that has been absorbed and sets the visibility to false and attaches the object to Belly’s location. This gives the illusion of the object being absorbed. I decided to use a damage system for the digestion system because it’s built into the Unreal Engine and it’s much easier to keep track of the damage values compared to my previous system that was based on the length of time the object stayed within Belly.

Fig 43 - Event AnyDamage for the pickup up object blueprint.

Event AnyDamage checks when the player receives damage. If the objects current health is below or equal to zero the object will be destroyed.

Fig 44 - Belly ejecting an object during digestion

Fig 45 - Eject point

When I was testing the absorb ability I found that once an object had been absorbed the player was forced to digest/destroy the current object if they wanted to absorb another object. To combat this problem I added the ability which allowed Belly to eject the current absorbed object. This system allows the player to choose which object they want to absorb. The scene component attached to the mask is the ejection point for the absorbed objects. This ejection ability is activated when the player has absorbed an object and the player presses the absorb button.

Fig 46 - Eject function

This blueprint controls how the player ejects objects. It sets the world location of the picked up object to the ejection point (scene component attached to the mask). The digestion timer gets stopped so that damage no longer gets inflicted to the object when it has been ejected. An impulse is also set to the mesh of the picked up object which is directed in the direction of the mask. Finally the visibility is reset and the First to make contact variable is set to NULL.

Fig 47 - Reset visibility function

This blueprint makes the mesh of the picked up object visible when it has been ejected.


Dashing

To give the player more options in terms of movement, I decided to add a dash ability into the game. This dash ability also inflicts damage on enemies so that they will take less time to digest compared to their digest time at full health. The dash ability can be activated while on the ground or in the air. When the dash is performed in the air, Belly is able to travel further as there is less friction while airborne compared to the amount of friction on the ground.

Fig 48 - Belly dashing from the ground

Fig 49 - Belly dashing whilst airborne

Fig 50 - Input action Dash blueprint

The dash ability works using a charge effect which is activated when the player presses the dash button. As the player presses the dash button Belly will begin to build their dash strength. When the button is released, the player will perform a dash in the direction of the left thumb-stick at a set strength depending on how long the player held down the dash button.

Fig 51 - ChargeDash custom event

Fig 52 - DashRelease custom event

Fig 53 - DashAmountReset custom event

This dash reset custom event resets the number of dashes depending on whether the player has touched the ground. I had to create this system so that the player wasn’t able to dash infinitely through the air. This is an issue because it would allow the player to skip large portions on the game.

The next step with the dash ability would be to allow the dash ability to inflict damage on enemies.

 

Figures list

  1. Rees, O (2019). Splines can be chosen using the BP Sphere Ref Variable. [Offline]. [Accessed 14/01/2019].

  2. Rees, O (2019). Spline path example (top down view). [Offline]. [Accessed 14/01/2019].

  3. Rees, O (2019). Player moving along the example spline path. [Offline]. [Accessed 14/01/2019].

  4. Rees, O (2019). On BeginPlay move the player to the nearest point on the selected spline. [Offline]. [Accessed 14/01/2019].

  5. Rees, O (2019). On EventTick the players location will be updated to the nearest point along the selected spline. [Offline]. [Accessed 14/01/2019].

  6. Rees, O (2019). Forward movement key bindings. [Offline]. [Accessed 14/01/2019].

  7. Rees, O (2019). Horizontal movement along a spline using an InputAxis. [Offline]. [Accessed 14/01/2019].

  8. Rees, O (2019). Belly rolling. [Offline]. [Accessed 14/01/2019].

  9. Rees, O (2019). On EventTick the player rolls depending on the horizontal velocity. [Offline]. [Accessed 14/01/2019].

  10. Rees, O (2019). InputAction Jump blueprint. [Offline]. [Accessed 14/01/2019].

  11. Rees, O (2019). Set Jump Max Hold Time. [Offline]. [Accessed 14/01/2019].

  12. Rees, O (2019). Small variable jump height. [Offline]. [Accessed 14/01/2019].

  13. Rees, O (2019). Large variable jump height. [Offline]. [Accessed 14/01/2019].

  14. Bain567 (2007). Super Mario Bros. Gameplay Video. YouTube [Video]. 11 September. Available from: https://www.youtube.com/watch?v=w2NjUDfOp2o [Accessed 14/01/2019].

  15. Rees, O (2019). Belly’s mask is attached to a spring arm. [Offline]. [Accessed 14/01/2019].

  16. Rees, O (2019). This blueprint is attached to the forward movement input and sets the rotation of the Belly’s mask spring arm depending on the rotation of the left thumb-stick. [Offline]. [Accessed 14/01/2019].

  17. Rees, O (2019). DegreesOfLeftThumbstick macro. [Offline]. [Accessed 14/01/2019].

  18. Rees, O (2019). Mask spring arm rotation lag settings. [Offline]. [Accessed 14/01/2019].

  19. Rees, O (2019). Belly’s mask rotating around it’s body based on the direction of the left thumb-stick. [Offline]. [Accessed 14/01/2019].

  20. Rees, O (2019). This blueprint is attached to the shrink and expand input axis and controls the length of the spring arm based on the size of Belly. [Offline]. [Accessed 14/01/2019].

  21. Rees, O (2019). Size changing ability. [Offline]. [Accessed 14/01/2019].

  22. Rees, O (2019). Key binding for the shrink and expand ability. [Offline]. [Accessed 14/01/2019].

  23. Rees, O (2019). Shrink and expand input axis controlling the scale of the player. [Offline]. [Accessed 14/01/2019].

  24. Rees, O (2019). Belly size small jump height. [Offline]. [Accessed 14/01/2019].

  25. Rees, O (2019). Belly size normal jump height. [Offline]. [Accessed 14/01/2019].

  26. Rees, O (2019). Belly size large jump height. [Offline]. [Accessed 14/01/2019].

  27. Rees, O (2019). Max speed comparison between three different body sizes. [Offline]. [Accessed 14/01/2019].

  28. Rees, O (2019). Belly size small air control. [Offline]. [Accessed 14/01/2019].

  29. Rees, O (2019). Belly size normal air control. [Offline]. [Accessed 14/01/2019].

  30. Rees, O (2019). Belly size large air control. [Offline]. [Accessed 14/01/2019].

  31. Rees, O (2019). Blueprint controlling the players air control depending on the size of the player. [Offline]. [Accessed 14/01/2019].

  32. Rees, O (2019). Belly using the suction ability. [Offline]. [Accessed 14/01/2019].

  33. Rees, O (2019). Suction cone setup. This cone has visibility disabled but I enabled it just for demonstration. [Offline]. [Accessed 14/01/2019].

  34. Rees, O (2019). Temporary suction cone material. [Offline]. [Accessed 14/01/2019].

  35. Rees, O (2019). Belly using the suction ability on a group of static meshes. The digestion ability only allows for one object to be digested at a time. [Offline]. [Accessed 14/01/2019].

  36. Rees, O (2019). Absorb input action blueprint. [Offline]. [Accessed 14/01/2019].

  37. Rees, O (2019). Absorb custom event. [Offline]. [Accessed 14/01/2019].

  38. Rees, O (2019). Digestion radius. [Offline]. [Accessed 14/01/2019].

  39. Rees, O (2019). Digestion queue blueprint. [Offline]. [Accessed 14/01/2019].

  40. Rees, O (2019). Digestion timer blueprints. [Offline]. [Accessed 14/01/2019].

  41. Rees, O (2019). Digestion function. [Offline]. [Accessed 14/01/2019].

  42. Rees, O (2019). Event AnyDamage for the pickup up object blueprint. [Offline]. [Accessed 14/01/2019].

  43. Rees, O (2019). Belly ejecting an object during digestion. [Offline]. [Accessed 14/01/2019].

  44. Rees, O (2019). Eject point. [Offline]. [Accessed 14/01/2019].

  45. Rees, O (2019). Eject function. [Offline]. [Accessed 14/01/2019].

  46. Rees, O (2019). Belly dashing from the ground. [Offline]. [Accessed 14/01/2019].

  47. Rees, O (2019). Belly dashing whilst airborne. [Offline]. [Accessed 14/01/2019].

  48. Rees, O (2019). Input action Dash blueprint. [Offline]. [Accessed 14/01/2019].

  49. Rees, O (2019). ChargeDash custom event. [Offline]. [Accessed 14/01/2019].

  50. Rees, O (2019). DashRelease custom event. [Offline]. [Accessed 14/01/2019].

  51. Rees, O (2019). DashAmountReset custom event. [Offline]. [Accessed 14/01/2019].