Final Major Project
Game Overview
Throughout my teens I clocked an unquestionable amount of hours playing Call of Duty: Black Ops Zombies. The endless survival aspect was an addictive trait for a game, as my friends and I would always try to best each other’s highest rounds or work together to achieve our own high scores. During my time at Parrs Wood High School I had always dreamt of transforming its terrain into a virtual playground to fight against the undead in similar fashion to what I had experienced in Black Ops Zombies. Parrs Wood Zombies is my first endeavour in bringing that dream to reality.
Parrs Wood Zombies is fundamentally a First-Person Shooter game, with the similar endless survival feature to that of Black Ops Zombies. Boasting a virtual recreation of a real-world geographical location, Parrs Wood Zombies is a coalescence of 3D modelling forged in Blender, and algorithmic programming engineered in Unreal Engine 4 (UE4).
Aims
- Successfully recreate a 1-1 rendition of a real-world geographical location
- Through Level Design, interpret the game world to reflect the zombie genre
- Create an endless game-mode including a progressive increase in difficulty upon each spawning wave of enemies
- Implement various weapons types in-game
Development Process
Level Design: Prototype
3D Data Capture
- I researched into various options for the 3D modelling of Parrs Wood High School, eventually discovering a tutorial by Nicko16. His tutorial outlines a method of capturing 3D data from Google Maps and importing it into Blender as a 3D model.
Nicko16‘s tutorial: https://www.youtube.com/watch?v=F_XsmoZJmG8
2. I downloaded both the MapsModelImport Blender plug-in – made by eliemichel, via GitHub, and RenderDoc, an open source frame debugger.
3. In Google Chrome, I changed the target to RenderDoc using the code below:
4. Using Google Maps via Google Chrome, RenderDoc was used to capture the 3D data from a satellite image of Parrs Wood High School. Via the MapsModelImporter, this data was then imported in Blender.
Blender
- As a newcomer to Blender, I took my time to grasp the basics by watching Blender’s online tutorials to understand and navigate its interface.
2. Following further tutorials by Nicko16, I cleaned up the model by trimming the map using edit mode, specifically, deleting vertices within the Mesh View. clean up mesh using baking (use tutorial and screenshots for guide)
3. To further clean up the mesh enough for it to be imported into Unreal, I attempted to bake the textures onto the 3D model via UV unwrapping. However, the baking process estimated 16 hours to complete, eventually, acknowledging this method as insufficient.
4. Upon this drawback, I decided to create a prototype model using the 3D rendered model of Parrs Wood as a template.
6. Using the Google Maps model, I mapped out the Level Design for Parrs Wood Zombies.
7. Adding cubes and planes where necessary, I utilised the knife tool to sculpt certain shapes and paths, extruding faces, edges and vertices. Filling faces in-between edges and vertices helped save a time. This entire process took a week to complete. The Blender file was exported as an FBX.
Note: For an accurate 1-1 rendition, I used imagery of Parrs Wood from personal photos and online sources (including Google and YouTube) to recreate areas where the Google Maps 3D model had low quality.
8. Due to my laptop’s inferior specs, I was unable to install Unreal Engine 5, and therefore, settled for Unreal 4.27.2, along with Xcode 13.2.
9. A number of errors occurred upon importing the FBX into Unreal 4: a) Certain errors messages appeared. b) Certain faces and planes were missing in UE4.
10. These errors were resolved by: a) Exporting faces via Shading, UV unwrapping faces, and merging vertices by distance. b) Recalculating normals inside and outside where necessary; simultaneously navigating through the UE4 map to identify which sections were missing (2 hour process).
11. Upon exporting the final FBX prototype, the scale of the 3D model was reduced to 0.6 along all axis, and the Player Starting Position was relocated.
Game Mechanics: Prototype
Character & Gun
- I downloaded my character assets from: https://smartpoly.gumroad.com/l/ZombieFPSFiles
2. In a new FPS Template Project, relevant folders were created to import assets, animations, materials and textures used to render the player’s arms.
3. Within the First Person Character Blueprint (BP_FPC), I deleted FPGun, VRgun; compiling and clearing error messages by deleting any related blueprints in order to implement my own weapons. The default FPMesh was switched out for the previously rendered arms rotated accordingly.
4. For the initial player animation: an Animation BlendSpace1D was created named “IdleWalkBS”, selecting the Arms_Skeleton as the mesh. Inserting both the Idle and Run animations to transition between them, renaming the Horizontal Axis to Speed with a maximum value of 600. Furthermore, an Animation Blueprint was created, and through the use of State Machines the engine could track the player’s speed to output the respective animation. This logic was implemented into the BP_FPC via selecting the Animation Blueprint as the AnimClass. The FirstPersonCharacterMesh was then adjusted to accommodate the camera view.
5. The Military Weapons Silver and Dark assets were downloaded and imported from the Unreal Engine Marketplace.
6. In the Arms_Skeleton, a “PistolSocket” was added to the right hand. The pistol was then implemented into the mesh, by adding a new mesh “PistolMesh” and adjusted using animation previews.
7. Further State Machine were added to accommodate aiming the pistol, each state had its own respective animation using an “IsAiming?” boolean variable to create circuit to determine whether player is aiming, using the RightClickMouseButton, in order to cycle through pistol animations.
8. In BP_FPC, the CharacterMovementComponent was used to down movement while aiming, with values of 200 when aiming and 600 when not.
9. An AnimationMontage was created for the AimFire and IdleFire animations using the LeftClickMouseButton as the trigger. By using a branch node within the BP_FPC, the engine would determine if the player is aiming, thus, playing the relative animation. The length of each animation was snipped to create more polished animations.
Zombie
- The ZombieGirl asset along with its respective animations were imported, and the relevant materials were adjusted.
2. A Character Blueprint “BP_Zombie” was created, adding the ZombieGirlMesh and adjusting the transform, rotation and scale accordingly.
3. A BlendSpace was created to play certain animations at specific speeds, along with an Animation Blueprint to hold and cycle between all zombie animations.
4. Within the BP_Zombie, logic was implemented for the zombie to chase the player. Changing the rotation orientation and maximum walk speed helped refine this. Navigation Mesh Bounds were implemented into the level to allow the zombie to move around.
5. For zombie to start running, I added a PawnSensingComponent to the BP_Zombie, to increase the zombie’s speed when close enough to the player
6. An Animation Montage was created for the ZombieAttack animation with logic to return the zombie to chasing the player upon each attack animation.
Weapon Damage
- The pre-existing template red crosshair was removed by disabling the HUD Blueprint within the FirstPersonGameMode Blueprint. I imported my own downloaded crosshair asset, and implemented it by creating a Widget Blueprint “BP_MainWidget” and anchoring it to the centre and rescaling it. The Widget was implemented into the scene via logic within the BP_FPC. The orientation of the pistol was the adjusted to line up with the cross hair.
2. Via FirstPersonCamera, both the WorldLocation and WorldRotation were used to set a centre point for line tracing which would act as the bullets for the pistol.
3. Within BP_FPC, damage was applied via the ApplyPointDamage logic, with a value of 25, used to register when a line trace hit a zombie.
4. Within BP_Zombie, a float variable “Health”, with a value of 100 (100HP), along with a PointDamage logic, subtracts any damage inflicted from Health variable. A print string helped show that this was active and working. Creating a Boolean “Death” would register when the zombie’s health is at 0. Logic was implemented to stop the zombie’s movement immediately, accompanied by a AnimationMontage for the Death animation which was set to play once, achieved by creating a MontageSection that would loop at the end of Death AnimationMontage.
5. Another AnimationMontage was created to showcase the ZombieHit animation, used when the zombie has taken damage. Within in the ZombieAnimation Blueprint, Bone Nodes were manipulated to allow this animation only to play from the waist up so the zombie’s legs would carry on walking when hit; and not slide along the floor. This was achieved by creating SavedPoseNodes, and recalling these CachedPoseNodes to play from the WaistUp and from the HipsDown.
6. Within the Project Settings, “HeadShot” and “BodyShot” surfaces were added to distinguish between shot types and relative damage infliction. Assigning these surfaces to Physical Materials allows them to be allocated to certain segments within the zombie’s Physics Asset. Reshaping the capsules to distinguish between the head and other body parts. Then, within BP_FPC, the HeadShot and BodyShot logic was implemented within the Line Trace logic.
7. By downloading the VFX Starter Pack from the Unreal Marketplace, Particle Effects could be emitted upon a zombie hit or an environment hit at the location of the line trace. This was achieved by adding the tag “Zombie” to BP_Zombie. A Blood Particle Effect would spawn when hitting a zombie and an Asphalt Particle Effect would spawn when hitting any other surface.
8. To fix a bug that would cause the player to collide with dead zombie’s mesh, logic was implemented to destroy the zombie’s mesh once dead.
Player Health, Player Damage, Health Regeneration & Blood Overlay
- A Float “Health” was also created for the player with a value of 100.
2. Within ZombieAttackMontage, a MontageNotify would register the collision of the zombie’s attack with the player, achieved by add SphereOverlap to the zombie’s hand. The zombie attack was set to inflict 25 damage to the player upon each hit.
3. In ZombieBPViewport, create ArrowComponent and move in front of Mesh. Damage logic was applied to BP_FPC , similar to that of the damage logic within BP_Zombie.
4. Within BP_MainWidget, an Image was created on the canvas, anchored to the full screen and reset offset, importing a BloodOverlayImage asset, set to hidden. An animation for this blood overlay was created and set to looping, changing Opacity from 0 to 1 and then back 0, creating a flashing effect. Implementing logic within this blueprint to hide or show this blood overlay dependant on the player’s health, a value of 50 was used.
5. Within BP_FPC, logic and conditions for health regeneration were implemented, if player health was less than 100, 5HP would be added every 5 seconds.
Pistol Ammo & Reloading
- Within BP_FPC, I created three integer variables: “CurrentAmmo”, “Total Ammo”, “MaxClipSize”, with of values of 8, 72, 8 , respectively. Setting the RButton as the trigger for reload, and creating an Animation Montage for the Reloading animation. Using a boolean variable and the necessary logic, the engine would stop the player from shooting when the Reloading animation was playing. Logic for ammo usage and ammo transfer from TotalAmmo to CurrentAmmo was implemented into BP_FPC. In addition to this, within BP_MainWidget, a representation of these ammo variables was created, binding the text to each variable.
2. In MainWidgetBP, create AmmoRepresentation in bottom right corner and create bindings to CurrentAmmo and TotalAmmo variables, respectively.
Zombie Game Mode
- A GameModeBase Blueprint “ZombieGameMode” was created with logic to spawn zombies, using the variables: CurrenRound, ZombieTotal, ZombiesLeft, setting up a basic multiplication for the number of zombies to spawn each round.
2. Using an array, a number of locations within the world were saved, and corresponding logic was implemented to divide the zombies equally between them. This logic would also track the number of zombies killed and, thus, the ZombiesLeft variable per round, along with a round increment upon successfully dispatching all zombies within a specific round. This logic included a short delay before destroying the zombie actor upon its death.
3. Within BP_MainWidget, a Round Icon was create and bound to CurrentRound variable. In addition to this, three animations were created: a GameStart animation, resembling the Black Ops Zombies round start UI, a RoundBuffer animation and a StartRound animation.
Death Screen
- Within BP_MainWidget, a DeathUI resembling to that of Black Ops Zombies death UI was created, by using the bind function, this UI would show the amount of rounds survived. The necessary logic was implemented to show this UI upon player death.
2. Within BP_FPC, I implemented logic to disable player input, controller, movement and widgets.
Ammo Pickup
- For the Ammo Pickup, I imported an AmmoCrate asset from QuixelBridge
2. An Actor Blueprint “BP_AmmoPickup” was created with a StaticMesh, SphereCollision and a RotatingMovementComponent. Within this blueprint, logic for player interaction and the subsequent destruction of this actor was implemented.
3. An array of world locations were used to store different spawn locations for the AmmoPickup, set to spawn at the start of each round, bar round 1.
4. Within BP_FPC, I set up the logic to replenish the player’s CurrentClip and TotalAmmo, clamping them to their maximum values.
Sounds
- For zombie sounds, I imported the previously downloaded ZombieSounds, created a SoundCue “AttackCue”, adding a RandomNode to randomly cycle between four different sounds upon each zombie attack.
2. I also added a SoundComponent to BP_Zombie, with Attenuation.
3. A PistolMagSound was added into the ammo logic for when pistol has no ammo, and the player tries to shoot.
Adding Parrs Wood
- To accommodate the imported map of PWHS, I updated the locations for both zombie and ammo pickup spawns.
2. BlockingVolumes were placed on the edge of the map to set the game boundaries. Along with an exponential increase to the Navigation Mesh Bounds.
3. In the Project Settings, I added an object channel in collisions and renamed it “Zombie”. So certain BlockingVolumes would act as passages for the zombies; blocking the players, these would host the zombie spawn locations. Setting the Camera to Ignore to allow shooting through these channels, and the Zombie to overlap (this was also done in BP_Zombie)
Main Menu
- For a prototype version of the Main Menu, I imported an in-game video and created a MediaPlayer, adding the video into it. A new material was created for newly made video, along with a new Main Menu Widget, inserting this material into an image on the Canvas Panel.
2. In the LevelBlueprint, I added a MediaPlayer Variable and added the MediaPlayer as the Default Value. Then creating the logic to play the video on BeginPlay
3. Within the MainMenuWidget, I created a simple title and buttons using the EventGraph to set up the buttons.
Game Mechanics: Main Build
Gun Revamp & Additional Weapons: Shooting
- I downloaded and imported the FPS Weapon Bundle from the Unreal Marketplace
2. Unfortunately, it deemed difficult to adapt the player arms and its animation to different guns, so I decided to delete the mesh completely, along with the Pistol_Mesh from BP_FPC
3. I created an Actor Blueprint “Weapon_Master”, adding a SkeletalMesh within it called “Gun”. From this class, I added a Child Class “Weapon_Pistol” and added the PistolSkeletalMesh, rotating it accordingly. I then duplicated Weapon_Pistol, making a class for each gun: “Weapon_Assault Rifle”, “Weapon_Shotgun” and “Weapon_Sniper”.
4. Within BP_FPC, I added a SceneComponent “WeaponPlacement” and made it child of camera, changing its location accordingly. Then, within the Event Graph, I created a function “EquipWeapon” with the input “WeaponClass” of type Weapon_Master and set up the necessary logic.
5. Within the Weapons Folder, I created an Enumeration Class “E_FireType”, adding two types: “SingleFire” and “Automatic”. Then within BP_WeaponMaster, I created a variable “FireType” of class E_FireType, changing Weapon_Pistol to a default value of SingleFire.
6. Within BP_FPC, I created a function “FireWeapon” and set up its logic along with the Event Graph logic.
7. In Weapon_Master, I added a vector variable “WeaponPlacementOffset” and adjusted each weapon accordingly to centre them.
Gun Revamp & Additional Weapons: Recoil
- Within BP_FPC, I created a CustomEvent “Recoil” and attached it to a TimeLine, and then set up the necessary logic for the timeline and recoil mechanic.
2. Within BP_WeaponMaster, I created three Float variables “recoilAmount, “recoilYaw” and “recoilLength”, setting the default values to 0.4, 0.15, 0.03 respectively, and then inserting them into the Recoil logic.
3. Within BP_FPC, I added a Float variable “previousPitch” and a Boolean variable “canResetPreviousPitch”; adding this to the “NoEdit” category. The previousPitch variables were then added to the FireWeapon function logic.
4. Within BP_FPC, I added a CustomEvent “PullDownRecoil” and set up the TimeLine and logic, then adding this logic to both the SingleFire and Automatic FireTypes.
5. In BP_WeaponMaster, I created a function “SetRecoilVariables”, implemented the necessary logic and variables. Following this, I created another function “RecoilAnimation” and set up its logic.
6. Within the BP_FPC, I created a RecoilAnimationTimeLine followed by the corresponding logic.
7. To test the Automatic FireType, within BP_WeaponMaster, I created a Float variable “fireRate” with a default value of 0.1. Then within Weapon_Pistol, I changed its FireType to Automatic.
8. Within BP_FPC in the FireWeapon function, I collapsed the SingleFire logic into a function “FireTrace”, then off the AutomaticNode I set up its logic and created a function “AutomaticFire” and within this function I then recalled the FireTrace function, adding logic to clear the timer on the LeftMouseButtonClick logic. I then implemented logic to t stop players shooting very fast with single shot, and collapsed this into a Macro “FireMacro”.
9. I then updated each weapon with unique values.
Gun Revamp & Additional Weapons: Bullet Spread
- Within BP_WeaponMaster, I added a Float variable “bulletSpread” and defaulted it to 250.
2. Within BP_FPC in the FireTrace function, I set up the necessary logic for BulletSpread.
3. I then updated each weapon with unique values.
Gun Revamp & Additional Weapons: ADS
- In Project Settings, I changed the Near Clip Plane to 0.1.
2. Within PistolSkeletalMesh, on the Root, I created a Socket “ADS_Socket”, and adjust it in the viewport to line with pistol’s iron sights.
3. Within BP_FPC Construction Script, I promoted the RelativeLocation of WeaponPlacement variable to a new variable “WeaponPlacementLocation” and set up its logic.
4. Within BP_FPC, I created two CustomEvents: “ADS” and “Un-ADS”, and set up the logic for ADS along with RightMouseButtonInput.
5. Within BP_WeaponMaster, I created two Float variables: “ADSFOV” and “ADSDistanceToCamera” with default values of 75 and 10, respectively. Then, updating the the logic within BP_FPC, with these variables.
6. Within BP_FPC in the FireTrace function, I added the ADS variable to stop bullet spread.
7.However, lining up the ADS with the iron sights did not work correctly for each gun, thus, I manually adjusted them by creating a Float variable “ADSHeight” and changed the value for each weapon.
Gun Revamp & Additional Weapons: Ammo
- In BP_WeaponMaster, I created two Integer variables: “CurrentClipAmmo” “MaxClipAmmo”, then within the Construction Script I set the CurrentClipAmmo to MaxClipAmmo to start with a full clip.
2. Within BP_FPC, I created variable of WeaponMasterClass “Ammo”, changing its type to Dictionary and its values as Integers, then adding MaxAmmo for each gun.
3. Within BP_FPC, I set up the logic for printing ammo. Then within the Fire Trace function, I set up the logic for shooting and ammo reduction, then implementing the logic within the DecrementClipAmmo function.
4. Within BP_WeapnMaster, I created a Float variable “ReloadTime”, defaulting it to 2.2.
5. Within BP_FPC, I created a function “Reload”, created its Logic, and then created a CustomEvent within the EventGraph called “ReloadAnimation”. Implementing a TimeLine and logic including using R as the input.
6. For better game feel, I implemented logic to return to shooting or ADS after reloading if the button is still pressed.
7. However, due to this new ammo logic, the previous ammo UI no longer shows the ammo values. To fix this, I decided to ditched Dictionary Ammo variable and create a new variable in BP_WeaponMaster “WeaponTotalAmmo” and swapping in for the GetTotalWeaponAmmo Function.
Gun Revamp & Additional Weapons: Weapon Switching
- Within BP_FPC, I created two CustomEvents: “UnEquipAnimation” and “EquipAnimation” and set up logic for each.
2. I then created a CustomEvent “CheckForWeapon” and created its logic, then updated the EquipWeapon function logic
3. A Boolean variable “CanShoot” was then added in BP_FPC, and inserted into the Shooting logic to stop shooting while switching weapon. Similarly, a “StopReloading” CustomEvent was created.
4. I then set up logic to prevent players from switching to the same weapon.
5. The Boolean variable “IsEquipping” prevents any of the gun mechanics to be carried out while the player is switching.
Gun Revamp & Additional Weapons: Aesthetics
- For Muzzle Flash: Within BP_WeaponMaster, I created a variable “MuzzleFlash” of type ParticleSystem with an ObjectReference and set the muzzle flash for each weapon with its corresponding effect. I also created a Rotator variable “MuzzleRotation” as some muzzle flashes emit in the wrong direction.
2. Within BP_FPC in the FireTrace function, I integrated the MuzzleFlash logic, and renamed all weapon muzzle bones to “b_gun_muzzleflash”.
3. For Weapon Sounds: Within BP_WeaponMaster, I created a variable “FireSound” of type SoundCue with an ObjectReference and set the sound for each weapon, and integrated the FireSound logic within the FireTrace function. Similarly a “ReloadSound” variable was created and implemented in the Reload logic.
4. I also downloaded a BulletHole image from google, creating a PNG format in Photoshop. I then created a material, and added it into the FireTrace logic.
5. For Weapon Sway: Within BP_FPC, I created a function “WeaponSway” and created InputFloat variable “DeltaTime”, two Rotator variables “Final Rotation” and “Initial Rotation” and a Float variable “MaxSwayDegree” defaulted at 2.5, and then set up the necessary logic.
6. I tried to create a scope for the Sniper, however, this deemed very difficult, therefore, I decided to purchase a Rifle Weapon asset from the Unreal Marketplace instead, and replaced the existing Sniper.
Zombie Revamp
- I imported the Romero (zombie) skin from Mixamo, having downloaded the Breathing Idle, Walking and ZombiePunch animations, editing the values to make them more zombie like.
2. Within the ZombieWalking animation, I edited arms to stick out and add keys to change the animation, repeating this process throughout animation, then copying and pasting the initial values to the end to loop the animation.
3. I created a Character Blueprint “AI_Zombie”, inserting the ZombieMesh, transforming and rotating accordingly.
4. I then created an AIBehaviourTree, BlackBoard and an AIControllerBlueprint.
5. In the AIBehaviourTree, I created two tasks: ChasePlayer and AttackPlayer, setting up the necessary logic for each. For the animations, a Blend Space, Montages and Blueprint were all created similar to the prototype build.
Health Revamp
- Within PHYS_Zombie, I edited the capsules to create hit boxes, and in AI Zombie’s Viewport, I change the Mesh Visibility to Block
2. Within AI_Zombie, I created a function “TakeDamage” and created three inputs: Amount (Float), Bone Name (Name), and Impact Point (Vector).
3. Within BP_FPC in FireTrace, I inserted the TakeDamage function logic to detect bone names.
4. For Health, I created ActorComponent Blueprint “BPC_Health”, creating two float variables “Current Health” and “Max Health”, and also two Float variables: “Remove Health” and “Add Health”, creating logic of each. Adding this health component to both the player and the zombie.
6. Within BP_WeaponMaster, I added a Float variable “Damage” and set the damage for each gun.
7. Within BPC_Health, I set up logic for a headshot multiplier and for death.
8. I also rewired the prototype player death logic into this Health component.
Damage Indicator
- Importing DamageIndicatorImage, I created a new Widget “BP_DamageIndicatorWidget”, added the image, created an Actor variable “Instigator” and a Player variable “Player”, making both instance editable, checking expose on spawn for both, then creating the necessary logic.
2. I then linked this Widget to the BP_MainWidget, and created a function “PlayerTakeDamage” within BP_FPC, and added it to AIZombie’s Event Graph.
3. An animation was created for the indicator to fade out for a more polished look.
Blood Screen & Camera Shake
- I imported new BloodScreen to show incremental damage the player has taken, to do this I created a material and set up the relevant texturing, and created a MaterialInstance
2. Within the BP_MainWidget, I added the BloodScreen and set up its necessary logic paired with the player’s health component.
3. For the Camera Shake: I created MatineeCameraShakeBP “BP_CameraShake”, edited class defaults and added this blueprint to the PlayerTakeDamage function. BP_FPC>PlayerTakeDamage
Round Revamp
- In Black Ops Zombies fashion, Call of Duty has a specific algorithm used for the increment in the amount of zombies spawned and their corresponding health upon each round. To Implement this algorithm a new Game Mode was created called “BP_PWZ”, and two Integer variables: “RoundNumber” and “MaxZombiesInLevel”, and a Float variable “TimeBetweenSpawn” were created. The necessary logic was implemented, also taken into consideration the maximum amount of zombies present in the world, maxed at 24 to sustain game performance.
Pause Menu & Main Menu
- Creating a Widget “BP_PauseMenu”, a Background Blur with a Z Order of -1 was added along with buttons; with their own logic.
- Similar logic and design was implemented into the MainMenuWidget.
- I added to the Zombie sound into the Main Menu as it sounds better than silence.
Control Scheme
A Control Scheme was created using assets from the following link: https://icons8.com/icon/set/computer-hardware/ios
- The assets were imported into Photoshop to create a PNG image, and then imported into UE4 to create a PauseMenuWidget.
Round Sounds
- Sounds for Player Death, Round Buffer and Round Start were exported from YouTube and implemented into BP_PWZ.
Font
The Zombie Treats font was downloaded and imported from the following link: https://www.dafont.com/zombietreats.font, and replaced all existing in-game text.
Level Design: Main Build
Blender Materials
- All materials for the Main Build 3D model were found on Quixel Bridge’s Surface Library. However, Blender’s Plug-In for Quixel Bridge did not work for me, therefore, I installed the Node Wrangler Add-On within Blender.
- By creating a new material and clicking [CTRL SHIFT T], I was able to import all the required texture files at 2K definition due to my laptop’s limited specs.
- Textures would stretch across the 3D model’s faces, therefore, utilising the Smart UV Project function and the Knife or Loop Cut tools in blender allowed the textures to rescale to the size of the face.
Asset Implementation
- Using Quixel Bridge’s Megascan Library, I was able to import various assets into the world within UE4. Assets were used to mark the world boundaries, for example: stone walls and sandbags, and also used as props.
Fog
- By adding an Exponential Height Fog into UE4 and setting it to volumetric, I was able to create a Fog Material, and subsequent Material Instance. Inserting this Material Instance into a Particle Effect allowed for a Local Volumetric Fog to produced. This Fog was placed around the world to mark the level boundaries and hide the edge of the world.
Playtesting & Feedback
Playtest #1: Prototype
Positive Feedback:
- Rounds intensify rapidly, difficulty arisen from increase in zombies makes for fun gameplay
- Player Arms and Pistol animations are fluid and realistic
- The world is recognisable as Parrs Wood High School, even as a prototype
- UI (round number and ammo) is helpful and clear
- Players enjoyed exploring to see how big the map really is
Negative Feedback:
- More guns, having just a pistol is boring and bland
- Some players felt lost without knowing the extent of the control layout
- The world needs more texture
- Zombie health does not increase as rounds increase, it is too easy to kill zombies even in the higher rounds
- Blood overlay is deceiving, players would prefer an incremental blood overlay to see how much damage they have received
- The game needs more sound, not just zombie growls
- Game crashes when reaching rounds 7+ (too many zombies)
- Zombies are really low quality, and some players do not like the idea of shooting female zombies
- Glitch found where if players shoot a zombie while they are hitting you, the zombie will freeze and not chase or attack the player anymore
Implementations #1
- Three more guns have been added, each with their own unique characteristics: recoil, weapon sway, fire type, fire sounds, reload sounds, etc.
- A Control Scheme UI has been added to both the Main Menu and the Pause Menu
- Zombie health increases incrementally upon each round with a pace tried and tested by Activision in Call of Duty (the use of their algorithm)
- New Blood Screen implemented, covers more of the screen and increments; gets more opaque the more damage the player has taken
- Round Buffer and Start sounds implemented, along with a Game Over music soundtrack
- A cap has been introduced for the amount of zombies able to spawn to sustain game performance
- New zombie models and animations of higher quality have been imported
- The use of an AI Behaviour Tree resolves the zombie freezing glitch
Playtest #2: Main Build (Game Mechanics)
Positive Feedback:
- New zombie animations are funny and a big improvement
- Different guns make the game feel like a real FPS game, each gun feels unique, and can be used tactically to get the player out of tough situations
- No performance issues
- Wait between rounds is perfect amount of time
- Players enjoy looking for ammo boxes when low on ammo, adds another element of survival
- Damage indicators are a great addition
- Player health representation is subtle, but players appreciate not knowing how much health they have, but that they aware if they are in imminent danger or not
- Recoil is a challenging feature when playing
- Players really like the particle effects
Negative Feedback
- The world is still empty and a bit bland, needs texture
- “What fun is it if I can’t play with my friends?”
- In higher rounds, killing zombies is a lot more difficult, but players feel like they do not have enough ammo or weapons to compensate
- Too much open space
- Glitch with ammo, when switching guns, clip ammo is replenished automatically
- The world still needs more sound
- Some players mentioned they would enjoy playing an actual character (seeing hands, hearing voices)
- World is too big for the amount of zombies there are
- Zombies are too slow, faster zombies would be more challenging
- Glitch with Round animations (delay, and Round Buffer noise is very loud and repeats a few times)
Implementations #2
- Textures have been added into the world, along with a few assets
- Fog has also been implemented to reduce the visible open space
- Weapon switch ammo glitch has been resolved by creating a Clip and Total Ammo variable in BP_FPC for each weapon and used to set ammo amounts when ammo is used. This logic was inserted into the Construction Script of each weapon to save and recall each variable.
Reflection
Parrs Wood Zombies has been both a personal aspiration and a gratifying milestone for me during my game design journey. Before deciding on this concept for my Final Major Project, I had every intention of working independently for my final semester, and had my eyes set on Level Design, as I believe these are two focal aspects of game design I had not yet tackled. It is for this reason I chose to write a thesis on the Level Design of Assassin’s Creed Syndicate and Watch Dogs: Legion, highlighting Ubisoft’s feat of virtually recreating real-world London. During my thesis, I recalled this lifelong idea to recreate my high school into a virtual world, and as of that moment it felt that the stars had aligned.
Similar to Ubisoft’s reconstruction of Ancient Greece in the development of Assassin’s Creed Odyssey, where they analysed and used digital elevation data from NASA and Google Earth to map out the terrain of their virtual world, I decided to utilise an appealing method of manipulating 3D geographical data into constructing a virtually identical rendition of Parrs Wood High School. However, I was quick to learn the limitations I would face using an outdated laptop, not adequate for any design work. Yet, the low quality 3D model achieved from my attempt of this method served as a perfect template to construct my own 3D model, and I have relished the process, furthermore, I am very pleased and proud with the result. I feel l have achieved what I set out to do to an extent.
Having worked with others on other projects throughout MA Games Design, I have always had an accessible support system surrounding me, and although that boasts its own benefits, I have had to push my design capabilities further on this project than I have ever had to before. Constructing 3D models, animations, game physics, and learning and understand blueprints, with that, I feel fulfilled with the degree of work I have produced for this project.
Having never used Unreal Engine before, I was faced with a multitude of problems on a daily basis, I felt that I have resolved most of the detrimental issues such as the new ammunition system not binding to the existing Widget UI, and creating a cap to limit the amount of zombies present in the level at any given time to prevent the engine from overloading and reducing performance. Regarding the solutions applied to resolve the ammunition errors, my peers have termed them as “dirty” fixes, and I wish to carry out a more competent way of addressing these issues for future projects.
Working on my own has had the disadvantage of a burdensome workload, as time management was key discipline to consider, I would regularly schedule deadlines for Level Design, Game Mechanics and Prototype builds; for Play Testing, in order to sustain an efficient pace in my work. Each deadline would typically be on a weekly basis, however, due to the extensive amount of tasks to complete, I saw that I would miss deadlines and was only able to produce two builds for playtesting. Unfortunately, the biggest drawback I have had throughout the entirety of this project is the performance of my laptop. Compiling shaders would take hours, UE4 would run on average at 10FPS, I found it difficult to gain any momentum between tasks.
A recurring bit of feedback I have received regarding the game world of Parrs Wood Zombies is how empty it is, that there is too much open space. I feel my attention has been diverted away from Level Design in recent weeks due to the extensive number of game mechanics needed to implemented, fixed or improved upon. However, I am keen to explore different methods of filling out a vast amount of open space, and this will be a focal point of my research going forward. I do not believe 3D assets to be the solution in this instance, only due to the restrictions posed by my laptop’s performance capabilities.
The only noticeable glitch I can seem to find at this moment in time is the Round Buffer. The engine is constantly checking to see how many zombies are left from those who have spawned. Upon killing the last enemy, the engine is still running its checks and is causing a short looping duration between rounds, affecting the Round Buffer animation and sounds; as it is playing the sound multiple times at once. I have yet to find a fix for this, but it is something to note down and discuss with my peers or other developers in the future.
Despite this, I have received a lot reassuring praise for Parrs Wood Zombies, and it is a project that I am confident to work on in the future; and look back at what I have achieved thus far, until I have successfully recreated the vision I had for this concept as a teenager.
In regards to future iterations there is an endless list of mechanics I would love to implement into Parrs Wood Zombies. Firstly being arms! I found it very difficult to animate arms when using multiple weapons, therefore decided to remove them entirely. More weapons is always a good option too, specifically, I would have liked to create a melee system, and the ability to purchase weapons in-game, similar to Black Ops Zombies, as I believe carrying four weapons at once is excessive and unrealistic. For this I would need to implement a points system, something that I have considered throughout this project, but I felt would take too much time to incorporate. One point made by a playtester which had been removed from the prototype and overlooked since, is the speed of zombies, I am fully aware and able to have implemented this as I have already done it once before, however I feel it is too late to be amended. The list could go on infinitely as the endless survival game genre leaves a lot of room for crazy and interesting concepts, but now that I have reached the end of my time at ual, going forward I wish to now merge all the disciplines of game design I have experienced, and create more multi-faceted games, that include a competent degree of elements such as Level Design, Narrative Design, Animation and Development. I wish to also improve on my ability to prototype more efficiently, a tall order for a perfectionist such as myself.