3D Platformer Template is a group of Blueprints made for classic platformer mechanics in a 3D environment. The custom movement Actor Component can be added to any Pawn. In addition to the movement Actor Component, there are blueprints for basic pickups, mines, mine spawner, jumpers and spikes. The three enemy types are examples of pawns that use the Platformer Actor Component to move around
This component uses the default gravity and physics collisions but will set the velocity and rotation of the pawn manually which should give certain non-physical movement aesthetics very characteristic of platformers
AC_PlatformerMovement assumes three important things: that the actor that you’re adding it to is a Pawn and that the component doing the physics and movement is RootComponent, and that it’s a Sphere or Box Primitive Components (I’m currently looking for a workaround for capsules)
This component uses the default gravity and physics collisions but will set the velocity and rotation of the pawn manually so the Physical Material should always be frictionless as in PhysicsSetup
Another important consideration to have is that this Actor Component is not extended from PawnMovementComponent as that class not accessible to Blueprints, so using this component in a serious and large project with hundreds of pawns will have to be refactored in C++ for good performance. The nativization feature may be a workaround to this
There are two important Pawns in this template (BP_PlayerPawn and BP_Enemy) that implement AC_PlatformerMovement, both are ready to use, but in case you want to use your own class, this setup should be done before the component works as intended:
- Add a Sphere or Box Primitive Component as Root Components to your Pawn. Their collision type should be set as Pawn or Enemy if not a player.
- Add a AC_PlatformerMovement component. In case you need to do the Physics setup manually elsewhere, copy the contents of the function PhysicsSetup in this component.
- Call SetTraceVector on AC_PlatformerMovement, this will set a line trace that will look for the ground. Extend it slightly beyond the collision component so the pawn doesn’t lose traction too fast in odd geometry, like loops.
- In the component’s details, set your WalkableObjects types if necessary (default is WorldStatic, WorldDynamic and PhysicsBody)
- Feed your Forward and Right inputs to the SetInput function
AC_PlatformerMovement Public Variables
WalkableObjects: Walkable Object types. Even invisible objects will be walked on if they respond to line traces
Debug: this will show ForwardForce and Friction lines, the line trace that detects the ground and various strings about the state of the pawn
UsesGravity: do not change during play
DriftMultiplier: 0 is when velocity is always turned to the Pawn’s ForwardVector. 1 is when velocity only updates when any force is made. Used when walking on surfaces like Ice
StaticFriction: Friction coeficient when stopped. Make sure ForwardForce can win against this to start moving. These are not physically accurate
KineticFriction: Friction coeficient when moving
AirKineticFriction: KineticFriction in air
AirStaticFriction: Static friction in air
StaticFrictionSpeed: Below this speed it’s applied the Static coefficient, else applied the Kinetic. Setting a high value to this prevents the pawn from sliding down in slopes although ForwardForce will have to be tweaked accordingly.
MaxSpeed: the maximum speed. default is 6000 cm/s (216 Km/h)
ForwardForce: force made forward and backward
YawForce: not a physical force but it’s the rate at which the Pawn turns
FastRotInterp: this is an interpolation rate for pawn rotations done when on ground (if too low, the pawn won’t rotate fast enough to do loops)
SlowRotInterp: this is an interpolation rate for pawn rotations done when in air
BrakingMultiplier: fraction of ForwardForce that will be used for Braking. Higher will brake faster
JumpForce: force for jumps
AirControl: coeficient for player control when on air. Usually below 1.0
MinAttackTime: the shortest duration of any jump attack (in general you want this lower or same as other attack types)
HomingAttackForce and DashAttackForce: how fast to home in on enemy during this attack type
HomingAttackDuration and DashAttackDuration: the shortest duration of this attack type
ForwardInput and RightInput: usually you will want to use SetInput function and feed your inputs, but I kept them exposed in case you want to set them separately for AI pawns
RightInputInterpSpeed: an interpolator float to help with hard camera rotations when yaw-ing. Go as high as possible
Important Functions in AC_PlatformerMovement
GetInputYaw: Calculates the necessary yaw to turn the pawn. Not necessary to be called from the outside
GetInAir: this pure function gets if the pawn is on the ground or in the air. Useful for Animation BPs
GetAttackState: this pure function will get the current EAttackState: NotAttacking, Jumping, HomingIn or Dash
GetGroundNormal: this pure function gets the normal of the ground. 0,0,1 when in air
GetVelocityToAdd: Delta velocity every tick of the movement component (reset to 0 at every start of tick and gets added with every velocity calculation during Tick)
SetInput: Feed the forward and right inputs to this function
SetTraceVector and GetTraceLine: the first function takes a vector in local space. The second calculates its world position to detect the ground
SetFrictionCoef, Ice and Underwater: calculates the friction coeficients. You want one of these for every surface type in your game and add it to the Velocity calculation graph
SetHomingTarget: feed a collision component to this (from an enemy, a jumper or anything you want) to set it as Homing Target then use the SetAttackState function to set the state to HomingIn
SetAttackState: sets to NotAttacking, Jumping, HomingIn or Dash. Always do a SetHomingTarget before setting to HomingIn
Bonk: Adds a physical impulse with a direction vector and force float. The jump event calls this function
DrawDebug: draws force lines, velocity, in air, attack state and homing target vector. You can delete debug things in shipping builds. Search blueprints for the bool Debug
There are two important custom collision types:
Enemy: Set this to every enemy collision component instead of Pawn. In a boss with many collision components, only the root one should do the platformer movement, but all of them should be set to Enemy if they can be attacked (see the Jump and Hit events on BP_PlayerPawn)
Query: set this to every invisible collision component and fire overlap events
Other components should, in principle, not do collision or physics if the pawn is to use platformer movement
BPI_Interactables has two functions, Interact and Damage. In the example pawns, Interact is called on overlaps and Damage is called on hits. Implement BPI_Interactables on your pawns through Class Settings, then Call Interact or Damage (Message) to call them, and create the Events with the same name on the Actors that will respond.
See BP_PlayerPawn BP_Enemy and BP_Mine for examples of this, as mines will damage every pawn that implements the interface
The Platformer movement forces the Physical Material PM_Frictionless to be used so it can manually do rotations and velocity. So to do different surface types, it looks for different BPs of said surfaces. This isn’t perfect but it’s what’s currently implemented and should be changed in the future.
To add a new surface type:
- Make a BP with the surface (it can be a platform or any kind of WorldStatic or Dynamic actor to be walked on). See BP_Ice for example.
- in AC_PlatformerMovement, edit the SetSurface function and ESurfaces to add another surface type and look for the class of your new surface BP
- Duplicate the SetFrictionCoef function and edit the friction multipliers, drift, yaw and forward forces
- Add it to the CalculateVelocity graph like the others:
- Test it to see if the static friction isn’t preventing the Pawn from moving. If it’s moving too slow or not at all, lower the static friction, or add more ForwardForce or lower the static friction speed
Notice that in these functions I’ve used fractions of the default friction variables and left those variables intact. This is important to be able to set them back to defaults in the default surface and also that’s why there’s an internal yaw and forward. If you change the defaults for a pawn, you’d have to change the defaults for every pawn to have the same movement (you can still make a pawn class that only moves in a specific surface with different default friction variables).
- the pawn will stick to every surface if the trace vector detects it
- rarely, damaging hits on enemies will not fire
- no friction when descending in air (friction can be added now but it’s not behaving as expected)
- A debug pass needs to be done so the blueprint works well when nativized
- Needs a faster way to handle surfaces/mediums