Physics and Interaction

In this post, I share the challenges and lessons I've faced while implementing physics and interactions in my first video game using Unreal Engine 5. Through various trials, errors, and adjustments, I explain how I solved collision issues and came up with a provisional solution using only blueprints, avoiding the need for C++ for now, to achieve the arcade-style gameplay I’m aiming for.

Marc Camps

10/11/20248 min read

As you may know, this is my first video game, and I'm also a novice in Unreal Engine. By now, I have learned quite a bit, and I believe it's the best option for my game, although not all solutions are as obvious as I would like.

Before considering whether all objects interacted correctly in terms of physics, I created a "character" and started programming the garbage collection gameplay. I did this first because it seemed like a complex task to develop, as it involves using "inverse kinematics." However, it wasn't.

Now, in hindsight, I think I should have started by analyzing how the different game elements interact in terms of physics. When I created the first NPC, I based it on a "Pawn," and that's when I realized that it couldn't interact correctly with the player (character) when they collided or when colliding with other floating objects. This is where my confusion began since I hadn't learned certain basic concepts about "characters," "pawns," and their physical interactions. Additionally, I started creating the player with a "character" somewhat arbitrarily, which added to my confusion.

I expected the physics to react as expected simply "because the elements exist in a physical world."

I’ve spent quite a bit of time stuck on this issue. I've gone through countless forums, websites, YouTube videos, courses, experiments, and experienced severe sanity loss until I finally understood everything. Now, I’ve come up with a solution that, for now, works for my prototype.

Before diving into the details, let's set the context to understand the problem and then the solution I applied.

Desired Gameplay

This is an isometric spaceship game where the goal is to clean Earth's orbit of space debris while dodging and defending yourself from enemy attacks, meteors, and other events.

Therefore, it is necessary for the player and NPCs to be able to collide with each other or with any inert object floating in space. The result of these collisions should cause both objects to react by pushing each other, complying with the "action-reaction" principle.

It doesn't have to be a perfect simulation, as it would make the game too difficult, so I’ve simplified a few things. For example, movement is limited to the XY plane, and physics doesn’t function in three dimensions. Additionally, I aim for simple controls, distancing the game from a realistic simulation.

Even so, there will be many collisions, so physics is crucial and must work properly.

Problems Encountered with Physics

First, let's look at the different elements Unreal offers to create the game.

Blueprints Based on "Character"

These blueprints offer many functionalities and could apparently be a good option for two reasons:

  • They allow pushing physical objects in the environment.

  • You can easily configure the player’s movement using the "Character Movement Component."

However, I ended up discarding this option because, although the "Character" has many functionalities, most of them are not useful for my game:

  • It requires a "Skeletal mesh," and not all my NPCs need one. I could hide it, but why have an unused object?

  • It forces a vertical capsule-shaped collision, while my objects are usually horizontally elongated spaceships. Enabling per-poly collision isn't an optimal option due to the high computational cost.

  • I tried using sub-objects to achieve a collision shape more similar to the spaceship, but it didn't work well, as the collision object must be the "root" of the blueprint. Additionally, the "Character Movement Component" stops the spaceship based on the primary collision.

  • The "Character Movement Component" has too many options and complexity for what I need.

I've tried some pretty strange things with sub-objects, trying to achieve a custom collision but only got unpredictable results. It's better not to force the "character" and use it for what it's intended: for example, creating a vertical humanoid character in an action game. It definitely doesn’t work for me.

Blueprints Based on "Pawn"

"Pawn" blueprints are much simpler than "Character" blueprints and, therefore, much more customizable. Since they are practically empty when created, there is a lot of room to configure them as needed. Additionally, like with the "Character," you can configure a controller that takes control of the "Pawn," whether it be AI or a player.

I created a "pawn," assigned it a "skeletal mesh," an appropriate collision, the FloatingPawnMovement component, and a camera.

Then, I drew a few lines in the Event Graph to get it to move, but when the pawn collides with a floating object...

Boom, it's like hitting a reinforced concrete wall.

The "Pawn" movement works similarly to the "Character," based on collisions with the "root" object of the blueprint. However, it doesn’t seem to have the ability to push other objects through physics, as the movement component is simpler.

I tried manually programming the push effect for each collision by applying "AddImpulse" to the floating object, but it was taking too long. So, I started looking for an intermediate option between using an almost-empty "Pawn" and an overly complex "Character."

Physics-Based "Pawn" Movement

If I activate the "Simulate Physics" option on the root of the blueprint, I can program a physics-based system to move both the player and the NPCs. In this case, when they collide with a physical object, they push it normally.

The problem with this system is that it creates overly complex gameplay, moving away from the arcade style I want for the game. Also, the time I would save by not programming the push mechanics on collisions would be spent developing the pawn’s movement.

The Right Solution: Custom Movement Controller for "Pawn"

From what I've seen in forums and documentation, the best solution for my case seems to be modifying an existing movement component for "Pawns" and adding the physics functionality that "Character" has. This would involve using C++ and digging into Unreal Engine's code.

I think I will eventually do this, but first, I want to make sure the effort will be worth it. My priority now is to see if the project is viable with a prototype built as simply as possible, so for now, I've discarded this option.

It’s also worth noting that it's possible to create a movement component from scratch, which offers endless possibilities, although this would involve even more effort.

My Odd Solution for the Prototype

The general idea for my prototype is to create blueprints of type "Actor," which we'll call "physics colliders," that will wrap around "Pawn" blueprints for both the NPCs and the player. The "Actor" will handle collisions with physical objects, while the "Pawn" will have its own collision system to prevent it from passing through walls or other "Pawns."

The "Physics Colliders"

Since I always try to maximize code reuse, I use inheritance in everything I do, and this is no exception.

First, I create a blueprint of type "Actor" that I call "BP_Base_PhysicsCollision." This will wrap around the "Pawn" and handle collisions that involve pushing other physical objects, like space debris.

It’s important to remember that space debris will be fairly simple actors, with the "Simulate Physics" option enabled on their "root" object.

For this to work, both the player pawn and the NPC pawns must be able to spawn and move their "physics collider." To do this, I implemented a public event in "BP_Base_PhysicsCollision" that assigns the "Pawn’s" transformation (position, rotation, and scale). Since this blueprint is the base, this event is present in all blueprints that inherit from it.

The "Pawn" will spawn this actor at its own position when the game starts (in the "Begin Play" event) and then update its position and rotation in every "Tick" using "SetTransform."

"BP_Base_PhysicsCollision" will be the base blueprint for the different types of collision each pawn will have. For example, for the player, I will have "BP_Player_PhysicsCollision," which inherits from "BP_Base_PhysicsCollision" and contains the necessary collision objects.

Similarly, each NPC will have its own "physics collision" based on the same structure:

  • Player => BP_Player => BP_Player_PhysicsCollider

  • NPC => BP_NPC_Satellite => BP_NPC_Satellite_PhysicsCollider

  • NPC => BP_NPC_Enemy01 => BP_NPC_Enemy01_PhysicsCollider

Within each "physics collision," we will place the collision objects that best fit, whether it's a "static mesh" or one or more collision shapes. Always keep in mind that the more complex the collision, the more computational power will be needed to calculate them, so it’s important not to overdo it with excessively complex collisions.

The "Pawns"

All "Pawns" must manage their "physics collision," which is a common behavior among them, whether it's the player or an NPC. For this reason, I created the base blueprint "BP_Base_PhysicsPawn," from which the player’s pawn and all the NPC pawns derive.

This blueprint spawns its "physics collision" at the same position and rotation as the pawn when the game starts (in the "Begin Play" event). Then, in each "Tick" event, it updates the position and rotation of the "physics collision" thanks to the common logic implemented in the base blueprint.

Additionally, it contains the "Floating Pawn Movement Component" and a static mesh called "Pawn Collision," which are common to all pawns.

Here, "PawnCollision" will prevent the pawn from passing through walls or other pawns, but it won’t handle collisions with floating objects—that’s the job of the "PhysicsCollision."

There are public configuration variables, including one to select which "PhysicsCollision" class we want to use for detecting collisions with physical objects, and another for which "static mesh" we want to use to detect collisions with other pawns and walls. The static mesh must be a highly simplified version of the mesh used to define the appearance of the pawn.

From here, I have the "BP_Player," which is the player pawn where the movement logic is implemented via the controls. This blueprint inherits from "BP_Base_PhysicsPawn," and it’s important to call the "Begin Play" and "Tick" events from the base blueprint to execute the common logic.

In the "Class Defaults" section, we can select the pawn’s collision mesh and the class that should be used for "Physics Collision."

Collision Channels

At this point, I put everything into motion, and… it doesn’t work. The "BP_Player" should move, but it doesn’t. This is because, with one object inside another, there is a collision conflict.

To solve this, I added a new collision preset to the project configuration called "ExceptPhysicsCollision." This preset blocks all collisions except those of the "Physics Body" type and assigns the "Pawn" type to the object where it’s applied. On the other hand, all collisions of the "Physics Collision" actors have been assigned the "Physics Body" type using the "Physics Actor" preset.

This way, the pawns ignore the physics bodies that form the blueprint surrounding them, allowing them to move freely.

Conclusion

After much experimentation, this is the solution I implemented for my prototype, which has allowed me to move forward in development without overcomplicating things. The idea is, later on, to dive deeper into creating a custom movement component in C++ for the final game. For now, this blueprint-based solution is more than enough to validate the gameplay and physics I’m aiming for.