Very easy and simple "Doom like" sprite based character

This tutorial is in response to this thread, I recorded a video but I stopped half-way the editing process because I had other priorities but I thought I could show some captures of my graph to help anybody wanting to have actors using sprites and different angles, just like in Doom or Duke Nukem 3D.

The end result is “something” like this:

And I say “something” because as I’ll show, I made some changes to what I had back when I recorded that to make all the angle calculations only on the XY plane ignoring the Z coordinates.

For this method I created a project using the First Person template and imported the Third Person template using the Add New button and Add Feature or Content Pack. I did this to use the mannequin to make some character sprites.

If you already have sprites you don’t need to do this, just use either the FP or TP template and use the existing character class.

I copied the character to a new folder and renamed it to BP_Character.

But before doing anything inside the character create 2 Enums, one is for the 8 Angles and the other one is for States, which will be very useful to have a pseudo Animation State Machine using Switch and Select Nodes.

Here is ECharacterState:

And this is EFlipbookAngle:

You also need to make Flipbooks out of the sprites.

Now it’s time to open BP_Character and do the thing.

Remove the Skeletal Mesh, add a Flipbook Component and insert the Flipbook for the Front Angle, like this:

Having that Flipbook helps a lot to correct the scale.

Now add 3 Variables, 2 Arrays of the Paper Flipbook type and 1 of the ECharacterState type:​

If you want it all clean and tidy you could create a Struct and put everything inside, but being a short simple tutorial this is enough.

Put your Flipbooks in the Arrays, I followed an anticlockwise order like in Doom:

Let’s make the Character make use of all these resources and change to the proper Angle and Flipbook when needed.

Create a new function called CalculateFlipbookAngle, open it and add a Local Variable of the EFlipbookAngle type:

Now copy the Inputs and Output of the picture:

For the function I’ll show you all the nodes in different images, just copy it and I’ll explain how it works later:

Basically it’s vector math, you need 2 vectors, one is made from the location of the actor and where is looking forward and the second one is formed by the direction existing between this actor and the player.

When you calculate the arccosine of the dot product of the normalization of these vectors you’ll get an angle which will tell if the player is on the front or front-left, back, etc after being compared with different angles.

And once you know the angle, the function outputs it and in this case I set it to rotate the Flipbook Component to make it face the player. Depending on the design of your game you may not need this.

Let’s continue, create another function called GetAngleFlipbookFromArray and open it. This is pretty much self-explanatory, copy the image:​

What it does is take a Flipbook from an Array Index depending on the angle and outputs it.

And now we can use these 2 functions on the Event Graph:

Every Tick it calculates where is the player, depending on the actual State it Selects the appropriate Flipbook Array and it sets the Flipbook Component with the necessary individual Flipbook.

And that’s it!

You can see that I made it change the state whenever I hit the character with my projectile. It’s a simple way to showcase how you can scale this up to a more complex Animation State Machine. Just add more states to the Enum, more Flipbooks and with this and intelligently putting SetCharacterState nodes it will just work.

I hope it was helpful, I’ll post an update when I finish the video I mentioned at the beginning.


Thanks, fyi your pics are not working…

It should work now and I added a drawing showing the basic math behind the large function.

Wow very nice tutorial I appreciate your time in explaining this.
Thank you for a full in depth tutorial.

No problem, when I get some free time I’ll finish the video, I recorded a couple of extra techniques that are difficult to explain with text and images.

@ . Are you still planning to release what you have sofar on Patreon with early access on your demo and scripts ?
I’d love to look closer into how your doing all this in the editor even if its not all polished up yet.

Tomorrow I’m launching an IndieGoGo campaign and I decided that the 1$ tier will have as a reward access to the project files.

I started yesterday doing some cleanning up but I don’t think I’ll add comments.

My plan is to keep working on it until the campaign finishes and upload whatever I have to a private page on

After that I’ll think about the Patreon, has integration now with them so I could create another private page where I could upload regular updates plus a private Discord channel and all that good stuff.

OK that’s cool and good lucky with the campaign. I just Backed it :slight_smile: I hope you get plenty of other backers to reach your goal.
I’ve been playing around more and got a pretty good sprite following me around now for a test but the only problem is it locks to me like glue haha. In doom the enemy seems to walk more random towards you so u see some angles not just front on. Any idea how to make pawn walk a bit more zigzag towards u like in doom ?

HAHA Thank you!

In Doom the AI will walk towards you and randomly zig-zag when approaching. If it collides with anything it will choose a random direction and move towards that for a while. There’re some slight variations depending on the monster but that’s basically it.

I know 3 ways to simulate similar behavior and I implemented one:

Create 4 Custom Events, one for chasing the player, another one to attack, other to go to random points and the last one will be used as a reference for a Timer that will be looping.
I will call this one CalculateBehavior and put a SwitchOnInt node after it.
You have 3 behaviors so you’ll need at least 3 execution pins coming out the Switch node.
Now connect a RandomIntegerInRange with a 0 and a 2.
And connect the 3 behaviors to the Switch output pins.

Connect a SetTimerFunctionByName to EventBeginPlay, write CalculateBehavior as the desired function, put 1 as the time and check Looping.

If everything is correct, when you start the game the pawn will randomly perform one of the 3 actions every second.

Let’s say that you want a more aggressive enemy. Add more pins to the Switch and up the higher value to match the outputs and put more attacks after those pins.
This way instead of having a 33.33% chance of attacking you’re changing the odds to attack more.

And how to make the enemy walk randomly? With the GetRandomPointInNavigableRadius node.

Use this and you will laugh in satisfaction for your creation, maybe even shout IT’S ALIVE!, who knows? :rolleyes:

It will look something like this:

The other 2 ways are more complicated, one uses the GetRandomPointInNavigableRadius node but the center will be located on some point between the enemy and the player and offset to the side. And to calculate the coordinates you use vector math.

I’ve been thinking about using this for melee monsters.

With the third variation you need to deliberatelly make the pawn rotate towards the direction you want (with more vector math) and then make it move with (I think) an AddMovementInput node.

This is something I might use with flying enemies.

Hope that helps.

EDIT: Actually, I just watched the video and it shows the Graph and all the nodes, some things are wrong and some nodes are deprecated but it will give you a good visual idea.

Thanks I’ll take a look at the video. Cheers

I love your passion for this. I also share everything you stand for. Especially Doomlike, COOP. I dont understand why there are so few games made without coop.
I am working on DarkForces remake WITH Coop. Thats so fun. But i only do it for fun and proof of concept. Nothing is really optimized. But it works over steam and LAN.
One option i like to give you. Your sprites always look at Camera. But the oldschool Doom engine turned all Sprites orthogonal to Camera Rotation. this means, if you stand between to Sprites, your Blueprint turns both Sprites left and right in Front of you to your camera. This looks like a “V”. I found a simple option, so the sprites dont do this and behave like odschool doom.
here is the pic:

the left ammo pack is facing the same angle than the right ammo and the rifle to the right.
here is the Blueprint:

the Z is added by 90, because my flipbooks always are set standard with rotation 0 in the viewport of the blueprintclass. you can change it if you have a rotation other than 0 as standard of your flipbook in your object class.

Yes this is why I started all this, there are quite a lot of people out there wanting a doomlike coop experience. Maybe I’m wrong, in that case the market will speak.

A Dark Forces Remake and with coop? That sounds awesome!

Thanks for those Blueprints, I was waiting to change mine with some shaders right on the materials in the future, I’ll implement them this weekend.

A cool. I also tried to understand the material function to rotate sprites in the math examples. But i didn’t understand that. Couldn’t get the logic. I wish you much luck and power to keep the work on going. I will make a video of my Dark Forces Coop to show the status. But i paused now quite a while. Power ran out :slight_smile: I think because my blueprints are really messy :). Did you test Multiplayer on Steam? I tested it with a friend over the standard free DevApp ID and the movement was laggy. Perhaps a dedicated solution would be better? Didn’t research further. I think it is the p2p connection thats was lagging over Steam and not running a fast dedicated server? Multiplayer was also the hardest part till now for me. Very difficult to debug errors. It took me Days to sync a simple door opening on Client and Server including a switch which reactis to the door. There are no easy tutorials. And another tip: Test every single small implementation also against multiplayer AND NOT only local. I learned that in unreal editor there are often no real behaviors like over real LAN test or Steam test. Many errors came only with real LAN test and Steam test.

I hope i will get power for this again. It makes so fun to develop. I understand you completely.

WOOOOOW, that’s fantastic man.

I haven’t tested Steam just LAN and it works without a hitch and you’re right I’ve found that some things that work fine using PIE don’t work using the standalone or packaged versions, so you have to export the thing and test it that way, and still it may don’t work over the Internet using WAN or Steam.

It’s a tricky subject and another reason why I’m doing this, people should have it easier, if someone else has done the hard work for you, you can focus on just customizing the logic and add your assets.

Seriously sprite-based shooters look amazing with UE4, just look at those storm troopers, aren’t they cute? HAHAHA

hihihi. yes i love the troopers too. thanks alot! and the automatic engine features with the sprites are so great. i was so excited, when the sprites did shadows with dynamic light. haha. happy like a child. cool. your work is so nice for others. thats right. really nice of you thanks! have a nice evening! I use the “screenpercentage” command like a retro filter. you can switch it on or off. Just an idea for you in your menus :wink: eanouph said with niceeeee!!!1111 :wink:

For that I have planned to use this effect:

And with a 256 color palette LUT in a Post Process effect for the ultimate old-school experience :slight_smile:

Yeah it works, thank you @huibuh, I’ve been playing around with the materials but I still can’t figure out a way to replicate the same thing there, I’ll let it go for now.

My projectiles look weird using this so I’ll keep it how I had it with FindLookAtRotation and I prefer the characters without sprites facing the camera all the time, that’s 3 ways to represent sprites on screen and it looks great.

I don’t like using Tick, I put a Timer instead, this is the Graph:

I followed your examples and explanation but I get error about the flipbook object or component. I’m not sure which it should be as there is 3 types of things paper flipbook to chose from. Should Every flipbook variable be a a normal paper flipbook or a component or object ?.

Thank in advance for any help

What does the error say?

If by variables you mean the arrays, those are like this:


And it’s the same for the function pins with the exception of the one named FlipbookComponent.