CrazedFan Games
  1. Posts/

DevLog 0001 - Creating an Indie FPS in Unreal Engine 5: Character Movement and Introduction of a HUD using Blueprints

·10 mins

Hello, world. This post is the first of what, I hope, will be many entries into a DevLog where I’ll journal on my family, work, and endeavors to build and release an experience for you to play.

I’ll plan to post content in the following formula which aligns with my values:

  • Family
  • Accomplishment
  • Continuous Learning

First, a Family Update #

My wife has nearly healed up from surgery this week, and we expect her to return to work soon. My mother is adjusting well; it seems — as we all are — to the recent death of my father. My daughter has learned to open childproof lids on medicines at the healthy age of six.

For me, physical health has been poor this week. I took Thursday and Friday off to rest. I’ve been pushing too hard. I had worked 40 hours by the time I signed off on Wednesday, and my body let me know I needed to take a rest. I won’t go into details here other than to say: take care of yourself.

GameDev Accomplishments #

The last week has been productive:

  • Registered a domain calltomain.com, which reflects the main  entry point of many computer languages while allowing for some playful expression of ai within the word main. Thanks to my wife for helping me pluck something I said out of the air to find this name.
  • Registered a domain, crazedfan.gameswhich is the handle I’ve used since first getting online in the mid-1990s. “CrazedFan” has been my alias since joining Usenet in the early 90s, to leading the Abyss of Pandemonium total conversion for Quake in 1996-97 as a teenager, and playing all the games I’ve played. So CrazedFan Games is the perfect marquee.
  • Revised (again) a draft of the story for Call to Main. With each iteration, I recognize the story is getting more straightforward and more impactful. I won’t talk about the story much here, as I’d like it to be a surprise. Refining characters, motivations, cornerstones, and more will take quite a bit of work. Building a game takes a lot of time, and I’ll keep alternating on development and backstory.
  • Concept: Using Figma, I outlined the second complete draft of a world map and built out a mood board for several areas of the world. This latest iteration kept with the previous attempts and iterations. I’m satisfied with the outline and need to continue to iterate to refine.
  • Built significant confidence in using Unreal Engine 5 — I found some concept art and built it out this morning in Unreal. I’m still struggling with scale, but my vision blocked out well. Today was the first day I modeled something to my satisfaction in a very long time (20 years).

How do you set up a new blank project in Unreal Engine (UE5)? #

In recent weeks, I’ve made progress learning how to blockout levels within Unreal Engine 5. Now, I’ve set my goal on learning to establish raw game mechanics. However, I won’t effectively block out levels if I don’t understand how my player moves. Can they jump? Double jump? Jump far? Run fast?

Why create a blank project instead of basing things on the First-Person or Third-Person templates? Good question. I want to learn everything and avoid starting with bloated code or blueprints I don’t understand.

  1. Create a blank New Project
  2. Create a new folder in the Content Browser — Tip, you can Choose a Color to help you visually reference, which is helpful given all the content and restrictions in structure (some things want to be at the root of content.
  3. Create the following Blueprints where {Dir} is your choice to organize your content separate from default engine content or later third-party stuff you download:
    1. Game Mode Base as Content/{Dir}/Blueprints/BP_GameModeBase. A GameMode
    2. Player Controller as Content/{Dir}/Blueprints/BP_PlayerController
    3. HUD as Content/{Dir}/Blueprints/BP_HUD
    4. Character as Content/{Dir}/Character/BP_Character
  4. With 4 classes created, we need to modify the Project Settings -> Maps & Modes -> Selected GameMode to instruct Unreal Engine to use these entities:
    1. Set Default GameMode to your BP_GameModeBase
    2. Set Default Pawn Classto your BP_Character
    3. Set HUD Class to your BP_HUD
    4. Set Player Controller Class to BP_PlayerController

Personal Preferences for Playing in Editor (PIE): I suggest to set Play > Settings > Advanced Settings and enable “Game Gets Mouse Control”, change “New Window Position” to always center, and finally set the preference to open PIE (Play in Editor) to always open in a new window.

How do you make a character move in Unreal Engine (UE5)? #

At this point, we can play, but our camera will not move. We’ve started a blank project to have a clean slate free of code we won’t want in our game, which means we can’t do anything but render a world.

  1. Project Settings -> Engine > Inputwhere we’ll establish Bindings for Action Mappings. We’ll create several of these:
  2. Create the ActionMapping Jump and bind it to Space Bar
  3. Create the folioing AxisMappings
    1. MouseXand bind it to Mouse Xwith a 1.0 Scale
    2. MouseYand bind it to Mouse Ywith a -1.0Scale (unless an inverted motion is desired by the player)
    3. MoveForward and bind to W and S keys with a 1.0 scale for W and a -1.0 scale for S to allow backward movement
    4. MoveRightand bind to D and A keys with a 1.0scale for D and a -1.0 scale for A to allow left movement.
  4. Close Project Settings.

ActionMappings

With our bindings established, the time has come to configure our player controller.

  1. Open BP_PlayerController from the Content Browser by double-clicking on it and edit the blueprint – how you edit the blueprint may be different between Unreal Engine 4 and 5.
  2. Delete existing nodes – I observed Event BeginPlay and Event Tick.
  3. Create new nodes for the Mouse Inputs. Right-Click to create new nodes and search for and select InputAxis > Mouse X and Input Axis > Mouse Y events.
  4. Add new nodes for Add Yaw Input and Add Pitch Input and wire MouseX Yaw and Mouse Y to Pitch. Specifically, wire the MouseX Exec -> Add Yaw Input Exec and MouseX Axis Value -> Add Yaw Input Val. Do the same for the Mouse Y and Add Pitch Input.
  5. Select all four boxes and press the C key to wrap them in a comment box and name the box “Mouse Input.” You can customize the comment for quick visual reference by choosing a color or changing the font size. Some people have a preference to disable the option to Show Bubble When Zoomed.
  6. Save and then Compile your changes. You can configure a preference to Save and Compile on Success Only by expanding the options on the Compile button to save yourself time going forward.

BP\_PlayerController Blueprint

Now, we can enable the player to move within our world.

  1. Search for Use Controller Rotation Yaw in the settings of the blueprint and disable the option.
  2. Create a new Graph called “Movement” to organize behavior related to running, jumping, crouching, etc. The player blueprint can get complex over time, and I want to define clear domains.
  3. Create the following nodes
    1. InputAxis MoveForward and wire to Exec of a Add Movement Input node and the Axis Value to the Scale Value.
    2. InputAxis MoveRight and wire to the Exec of a second Add Movement Input node and the Axis Value to the Scale Value like the previous step. At this point, MoveForward should be wired to one node and MoveRight to another.
    3. Get Forward Vector and wire to the World Direction attribute of the Add Movement Input connected to the MoveForward node.
    4. Get Right Vector and wire to the World Direction attribute of the Add Movement Input connected to the MoveRight node.
    5. Create a Make Rotator node and wire it to the inputs of both the Get Forward Vector and Get Right Vector nodes.
    6. Create a Break Rotator node and wire the Z (Yaw) between the two.
    7. Create a Get Control Rotation node and wire the Return Value to the Rotation of the BReak Rotator node.
    8. Optionally, select all nodes and create a comment to remind you these nodes control the WASD Movement of your player.

WASD Movement

What is all this stuff for? First, lets discuss X, Y, and Z coordinates. These coordinates define three points in a world. If something has a higher X, Y, and Z value, then we know that point is farther right, forward, and higher in the world than another point. For example, the center of a world is probably X=0; Y=0; Z=0. If a point is X=10; Y=10; Z=10, we know it is ten units in all directions away from the center. If another point was X=-20; Y=-20; Z=-20, we know that point is 30 units away from the previous point. Let’s call one of these points the head and another a tail to establish a relationship between these points in space.

With a relationship between two points, we can establish a Vector. A Vector is a mathematical quantity describing two characteristics: direction and magnitude. For example, if we move the head and tail of a line anywhere else in the world, but the head and tail remain 30 units away on the X, Y, and Z-axis, then the vector’s position has changed, but the vector itself has not.

Anyway, this information might help a reader – including myself as I age and forget – to realize that we’ve created two events and bound them to keyboard input. Those events fire, triggering blueprint nodes to fetch vectors to drive player movement as the events fire.

Let’s get onto creating the ability to Jump. Create the following nodes:

  1. Create ActionEvent Jump and bind Pressed to a new Jump node and Released to a new Stop Jumping node.
  2. Optionally select and comment to group the jumping behavior.

Jump Action

Start a Heads Up Display (HUD) #

With player controls configured, let’s move on to our HUD where we’ll define a blueprint to render a small box in the center of our screen as we prepare for a reticle.

  1. Open BP_HUD from the Content Browser
  2. Create the following nodes: Event Receive Draw HUD and Draw Rect.
  3. Drag a wire from Event Receive Draw HUD > Size X and release the mouse button to pull up the new node list and type * or Multiply. Connect an outgoing wire to Draw Rect > Screen X and then set the multiplication to 0.5. Repeat for the Y attributes of the two nodes. This formula divides the width and height of the screen in half to find the center.
  4. Set the Screen W and Screen H values to 4 or another number of your preference. These values define the size of a rectangle rendered to the center of the screen. Choose 25 if you want to see a big rectangle.
  5. Optionally, wrap the nodes in a comment. I named mine Recticle. Save and Compile the Blueprint.
  6. Play in Editor (PIE) and observe.

Render a Box for a HUD

Outcome #

I’ve learned and documented how to use Unreal Engine 5 to create a new project from scratch, how to draw a rectangle to the HUD at the center of the screen, and how to move the player around in the world and jump. Unreal made this very easy using Blueprints. Soon, I’ll endeavor to control player behavior using C++ to enable me to have very good control over the player. Should they move the same speed when swimming in water? Will some textures slow the player? Will the player enter a resistance field that adds friction? Find out when Call to Main is published in the distant future.

Explanation of Terms and Entities #

What is a GameModeBase? #

A GameModeBase defines the game. It governs the rules, scores, governs actor existence in the game type, controls who may enter the game, etc. In a multiplayer context, the GameModeBase should only be deployed onto the Server to avoid cheating.

The engine chooses the GameMode actor in the following order:

  • The URL ?game={GameModeAlias}
  • GameMode Override defined within World Settings
  • DefaultGameMode entry set in the game’s Project Settings (which we established in the notes above).

GameModeBase References:

  • [Setting up a Game Mode] in Unreal Engine Documentation
  • [AGameModeBase] in Unreal Engine C++ API Reference

What are ActionMappings and AxisMappings? #

ActionMappings bind or map a specific button or keypress to an alias name that you can bind event-driven behavior. The outcome is that pressing, holding, releasing, etc., a button will trigger some game behavior. Like move forward or jump. AxisMappings are similar but communicate position information such as mouse movement. AxisMappings are continuously polled for a value — even if that value is 0 because you are not moving a controller.

ActionMapping References:

  • Input in Unreal Engine Documentation