Skip to main content

KILL EVERYTHING IN SIGHT Sprint 2

  I began this sprint by working on implementing shooting behavior for our enemies. Currently my enemy AI was capable of navigating to the player and punching, but not firing projectiles from a distance. To this end, I needed a couple of new things: a projectile for the enemies to fire, a blackboard key containing the range at which the enemy will shoot the player, a BT task to call an enemy’s shoot function from within the BT, and then the shooting function itself within the enemy blueprint.


Firstly, I created the BT task so that I could call the enemy’s shooting function, this was almost entirely the same as the original melee task, just with a different function to call within the base enemy class. Second, I created a decorator that checks if a target actor is within a range defined by a blackboard key. Within the AI controller, I assigned a FiringRange key inside the blackboard based on the enemy data table I created last sprint. Finally, the last thing I needed was to create a function inside the enemy base to spawn a projectile and set its data table row. Very easy!


Behold! A glowing red orb


Initially, the projectile was a white ball with a collider, but I eventually changed it to be glowing red so it’s more visible against the environment. Within this projectile, I programmed the ability to read the enemy data table from an assigned row (to get the projectile’s damage and speed based on which enemy fired it), an ApplyDamage call on contact with the player character, and finally the ability to destroy itself upon contact with something solid.


The projectile was also always firing from the enemy’s center of mass, which was fine for prototyping, but later we would probably want the projectile to be spawned at the end of some sort of gun or appendage. For that, I added a SceneComponent (basically just a transform) to the base enemy called FiringPoint, and set the projectile to spawn from there. This way when we have the actual meshes, I can parent the firing point to a socket of the mesh so that it stays attached to whatever part it needs to spawn from!



With this, I was able to make the behavior tree for the medium enemy! He will stand still and fire at the player as long as they are within range, and if they get too close, he will stop firing and throw a punch. If the player leaves his range, he will chase them!


The heavy enemy essentially had the exact same behavior, just with different stats for health, firing rate, range, and damage, so creating him took no time at all. With this we had our three basic enemy types!


I adjusted the scale of each enemy to easily tell them apart


Now with proper enemies, we needed a way to actually defeat them. Another groupmate of mine had done the work necessary for the player shooting, so we discussed at our group meeting how we wanted to make these independent systems talk to each other. We agreed that Unreal’s built in ApplyDamage() functions would be easiest, so within the enemy I extended off of the OnAnyDamage event to lower his health.


The lead designer also wanted this game to have headshots like many traditional FPS titles, so I not only needed the enemy to receive damage, I needed it to know where it was hit. After doing some research on some different approaches to this, I decided on generating a physics asset for the mesh. 



The physics asset is essentially a group of colliders attached to certain bones of the mesh. Unreal will generate a pretty accurate one by default, so I only needed to adjust it slightly! This not only allowed me to differentiate between body parts, but it also meant that the shooting would feel more accurate, because shooting between the legs or in a gap in the mesh would not count as a hit.


However, here is where problems started to arise. The line trace used for the player shooting was generating multiple hits per enemy. One for the capsule collider used for the enemy’s physics, and then one or more depending on how many colliders of the physics asset were hit by the line. The first step of fixing this was somehow differentiating between the capsule and the physics asset of the enemy. For this, I created a new trace channel called “Hitscan”, which would be used for objects that should respond to any hitscan weapon shots. By default, I set this to overlap on every object (This is because line traces will stop after a blocking hit, a quirk unique to line traces I discovered!), then within the capsule I set it to ignore . After getting the OK from my fellow programmer to edit her shooting code (which was neatly isolated within an actor component and not the player blueprint, preventing a merge conflict), I changed the trace to only detect the Hitscan channel. Now the capsule collider was no longer being detected!


But the shooting wasn’t fixed yet, because if two physics asset colliders of the same mesh were detected by the trace, the damage would be applied twice. To fix this, I’d once again need to venture into the shooting component, and change the way that hits were detected.




Originally, all hits were checked for validity, and then added to an array of hit structs to be returned. The way I solved the double-hitting problem was by iterating through all hits, and keeping track of the actors that have already been hit. If a hit was on a new actor, it would be added to the array, and the actor would be added to a separate array of already hit actors. If it was not a new actor though, it would be ignored. Now the shooting was able to hit multiple targets with all of them taking the correct amount of damage!


Only one hit is counted (shown by my fellow programmer’s handy debug function)


The final thing I worked on this sprint was the enemy wave system. The designer wanted enemies to be spawned in when there were only N enemies remaining. To start off, I created a wave manager blueprint that would keep track of how many enemies were alive in the level. When enemies were spawned in, they would call a function within the wave manager to register themselves. Then upon death, they would be unregistered.



Next, when the enemy count got below a certain threshold, the wave manager needed to spawn new enemies. But which enemies would be spawned and where? To answer this question, I created a new actor blueprint called Enemy Spawnpoint.


Adjustable spawning radius


The Spawnpoint would have just a small amount of data. The radius of the area in which it can spawn enemies, a list of enemies that could be spawned there, and a cooldown min and max so that the enemies could spawn one at a time with some variance in the time between spawns (per the designer’s request). This will allow the level designer to have very fine control over which enemies can spawn and where. Currently, the wave manager will tell a spawnpoint to spawn, and the spawnpoint will pick randomly from its list of enemies. But in the future, I could change the wave manager to decide which enemy types to spawn, and those enemies will only spawn at spawnpoints that have said enemy in their list.


This spawnpoint can spawn light, medium, and heavy enemies


Next sprint, I’m excited to start working on some particle effects to enhance the player feedback of shooting, as well as further develop the wave system and implement 3D models for the enemies!


Comments

Popular posts from this blog

CAGD 373 Blog Post 4

This sprint I was assigned a modular set to create the basic interior rooms out of, with three different textures for the walls. (a Square Brick Texture, a Cement Texture, and a Metal Wall Texture) The actual modeling itself was as basic as it gets, I just made a few different shapes and sizes of wall along with a doorframe, with a couple floors and ceilings to complete the set. The interesting stuff this week was the textures, all of which I made in designer! The brick texture was probably the most complicated, and the one I’m most proud of. Starting with a brick generator, I used some gaussian spots to add some variance to the shape of bricks (using the spots to “cut out” chunks of the perfectly square bricks) and that worked pretty well! After that, I used a grainy looking noise map to fill in the black part of this mask to add in the noisy texture of mortar between bricks Next, to add some color variation to the bricks, I used a flood fill node, which was able to identify all the...

CAGD 370 Blog Post 5 - Final Sprint and Postmortem

  The Final Prototype is officially done! And this final sprint has definitely been the most intense yet. While not perfect, I’m very happy with the game that me and my team have made, and I feel a lot of motivation to start a brand new project! But before I get ahead of myself, it’s a great time to reflect on the last two weeks and this project as a whole. To start off our final sprint, I once again made adjustments to the pole vaulting. I made the impulse of the vault scale with how close you got to the pole, which meant that not only could the player not get an immense movement boost from a standstill, but also that there was now a “sweet spot” to aim for to get the most vertical height out of the vault. To help players seek out this sweet spot, I also took the time to create a charge-indicating progress bar next to the player that would fill up the closer they got to the sweet spot. The bar progressively fills as the player approaches the sweet spot After this, my lead de...

CAGD 373 Blog Post 5

  Judgement day nears! And sadly I don’t have too much to show for this week as finals in other classes have swallowed up most of my time. However with most of them finally out of the way I’m clear to focus all my time towards this project over these next couple of days! The real meat of my texturing work this week is this Exterior Trim Sheet. I tried to group together as many models with similar-ish materials as possible so that I could get textures applied efficiently. Here I’ve created a trim sheet consisting of metal, tree bark, wood, a beige stone texture that worked pretty well for the pipes, and a separate, rougher metal texture for the motors found just outside the facility doors. I spent a lot of time compiling a list of all the models in our project along with reference images, so that way I could organize them into texture sets based on similar materials/texturing needs This plan should help to really accelerate the texturing pipeline over the next couple of days, so t...