Hi, I'm Gary and I'm a game designer with over 10 years experience. Thanks for checking out my third person combat demo! With this prototype, I hope to prove out the fundamentals of a satisfying third person combat experience, with intuitive controls, behaviours and good UX.

I am going to cover what's in the demo in 2 parts. The first of which will cover design, while the second will be a more technical breakdown of how I created parts of this prototype. There's a lot here, but my hope is to fully breakdown each and every mechanic. You definitely don't have to read this, but if you do, I hope you enjoy my thought process! And I'd love to chat if anyone has anything they'd like to add or dispute!

Note: Press Enter/Start for a list of controls in-game. (I know, I know, it should be Escape on keyboard, but if you're playing full-screen, Escape takes you out of it, so Enter it is!)

Part 1: Character, Combat & Camera Design

I set out to achieve a similar feel to the Witcher 3 video game. This game feels absolutely fantastic to play, is buttery smooth, and super intuitive. I constantly found myself going back to check small, subtle things to see what happens in certain edge cases, and it impressed me every time how they handled it.

So, I'm going to give a breakdown of all the mechanics that be found in the prototype:

- Witcher 3-like basic movement + camera: The character generally faces the direction of left stick/WASD input, while the camera is manually controlled with right stick/mouse delta.

- Attacks: When attacking (left click/X), the character immediately turns to face the direction of the camera and attacks in that direction. The camera projects a vision cone that can detect enemies in a 120 degree angle, and if an enemy is in this cone when turning to attack, the character instead turns to face the enemy closest to the center of the camera (within the cone). This should feel super intuitive for players, with the game feeling like it knows what enemy you want to attack, even if the camera isn't directly pointing at it.

- Ability Movement: Whenever any ability is used (attacks, spells), there are 3 possible movement outcomes, depending on the position of the player, nearby enemies and the variables set on the ability itself. Let's start with 2 of the outcomes that come from ability variables. Each ability has "with target" and "no target" movement values. These are how far forward the player character will move when the ability is executed when you have a target, and when you do not, respectively. The 3rd outcome is that the player character is already close enough to its target, and so it will not move at all. If you have a target, but they are not immediately nearby, the nearest enemy within the "with target" value (while also within the enemy camera cone), will be chosen. While the player has a target, the ability picks the appropriate distance to move, using the rules outlined, and moves towards that target. Again, this should feel super intuitive, like the game knows who you're actually trying to target. If you have no nearby target, the player character moves the distance of the "no target" variable. (In the prototype, try having the player character facing away from an enemy, while attacking with the camera looking "near" an enemy.)

- Action Buffering: Attack, Cast Spell, Parry and Dodge can all be buffered. Buffer windows are determined based on events set in the animation itself, so it's very easy to edit. The buffer windows are set to start a short duration into the animation, to ensure that if you press one button a couple of times to make sure the action activates, it won't buffer another action unless you are constantly mashing the button. For example, I want to dodge, so I'm mashing the dodge button, but I don't want to dodge a second time, so I have enough time to react to the dodge animation starting, and then I stop pressing the button - because the buffer window hadn't opened, it won't buffer another dodge. If I want a second dodge, then once the buffer window opens, any press after that will buffer another dodge (or parry, or attack, etc. depending on input)

- Animation Cancelling: Many animations can be cancelled early. Just like with action buffering, within each animation you can set an animation cancel window. Once that threshold has been reached, any animation can end and go into another, and will happen automatically if an action is buffered. For example, if you just use the first attack in the combo (and nothing more), you'll notice it has some follow-through and wind-down time, but if you have the second attack buffered, as soon as the animation cancel threshold has been met, the second attack will start, allowing you to go straight into the second attack. This is even more noticeable if you animation cancel an attack with a dodge or parry! Animation cancelling is the key to smooth, free-flowing combat, and not feeling like the game is sluggish or unresponsive.

- Weapon Hitboxes: Weapon hitboxes are turned on/off via animation events. This simply turns the collider on/off on the weapon. There are other (and probably better) ways of doing this, I know, but this works well enough! Ideally I would also add a check to ensure if an enemy would've been struck in between attack frames, as hitboxes can jump around a bit based on the animation. Alternatively, you could move this onto the VFX itself, or have a bespoke hitbox setup, where you manually define where each hitbox is for any given frame (like how Super Smash Bros. does it). The hitboxes on the weapons are much bigger than you might expect, as is the enemy hurtbox (not the player hurtbox though, only the player gets the invisible design cheats!). This is to ensure that if it looks like an attack will connect, it actually does!

- Hitstop: Another variable defined in the ability data files. There is a duration and a definable curve, and utilising both of these can result in very different effects, for really selling impact. In the prototype, for example, check out the very minor hitstop on the attack combo, and compare that to the final combo attack, parrying an attack, or the whirlwind final slam hit. All of these use just these 2 variables to control all of these effects! Hitstop really emphasises hits, and helps you feel the "weight" of attacks, or really sells highlight moments, like some of the aforementioned. Additionally, hitstop when you take damage gives you a split second to assess the situation and figure out your next move.

- Parry: The player has a few frames during this animation where they can entirely prevent an enemy's attack, giving an extremely satisfying, Breath of the Wild-inspired slowdown effect, and allowing for a follow-up counterattack. This counterattack also seamlessly transitions into the combo attack. Of course, bonus points if you animation cancel your successful parry with an awesome follow-up spell… Also quick note that Unity's WebGL exporter absolutely gutted the lovely distortion effect on the successful parry block, and I can't figure out how to stop it doing that :(

- Dodge: A quick, responsive dodge that turns i-frames on/off based on, you guessed it, animation events. While i-frames are on, the player character will not register any attacks made against it.

- Super Armour: While we're on i-frames, Super Armour is another animation event driven flag. While a character has Super Armour, they can still be hit and take damage, but will shrug off hitstun and continue with their action. Most of the big abilities, like Whirlwind Assault and Frost Nova, gain Super Armour at a certain point to ensure that, past that point, the spell <i>will</i> complete. This does mean, though, that if you mistime it and the Super Armour does not activate in time, you can be knocked out of the animation and the spell will be cancelled. Similarly, enemy attacks gain Super Armour at a certain point. This is to ensure that the player can't just spam attacks through the enemy attacks, and gives parrying a great use here. In the ability data files, any ability can be set to ignore Super Armour, with the parry effect being the only thing to exist that does this. This flag ensures that the parry ability can go off even through Super Armour, causing them to stagger with a "heavy_hit" animation-on-hit.

- Spells & Mana: The player can pick 1 spell to be active from a choice of 6 through the spell wheel (see next section). Each spell serves a different purpose, and has its own mana cost. The mana bar at the bottom of the screen drains after using a spell, and refills completely after a few seconds of not consuming any mana. There is feedback when this refill happens (the bar shines white + sound effect), and for when you don't have enough mana (the bar flashes red + sound effect). I tried to give players a variety of interesting spell effects, ranging from a quick Fire Blast that is great for weaving in-between combo attacks (try: attack x3 -> Fire Blast -> repeat until out of mana -> finish with combo finisher; all of this animation cancels really nicely into itself.); the default spell, Whirlwind Assault, is an awesome, somewhat-cinematic experience of slicing all enemies; and some spells where you aim them, such as Lightning Bolt and Flame Thrower. The remaining spells are another cinematic-like spell, Frost Nova, which also slows enemy movement and attack speeds for a bit, and Embody: Air, a spell which buffs you for a bit, increasing your movement and attack speeds. Weaving attacks in mid-combo should feel very satisfying, and when you realise you can switch spells mid-combo, you can achieve some highlight-reel-worthy plays!

- Spell Wheel: Holding tab/left trigger brings up the spell wheel, and releasing dismisses it. Moving the cursor/left stick will pick one of the spells around the wheel, while also giving you a quick description of what it does, and a preview of how much mana it consumes (a light blue overlay on your mana bar). Time is slowed down to 10% while doing this, which gives a really natural feeling to selecting the spell, as well as a tiny bit of pressure if you are mid-combat. Witcher 3 does this (one of those small things I mentioned earlier that you don't even think about!) and I think it really works, rather than straight-up pausing time keeps you a little more immersed while navigating a menu.

- Cameras: There are 3 cameras in use for the prototype. The standard camera is in use while the player is normally moving around. It is slightly offset to the right of the player, giving that immersive feeling of embodying the character more. The second camera is the "cinematic/see-more" camera, which pulls back to give you a better view of your surroundings, and is more centered on the character - perfect for framing enemies caught in the Whirlwind Assault or Frost Nova spells. The final camera is the "aiming" camera (see next section). Abilities can also cause definable camera shake, for those even more impactful hits!

- Aiming: Lightning Bolt and Flamethrower are spells that, when used, transition you into an "aiming" state. The camera is now closer to the character, and resembles a third-person-shooter, over-the-shoulder style, and an aiming reticule appears in the center of the screen. Some trickery ensures that when launching a projectile, or using the flamethrower, they are angled towards the center of the camera, rather than the direction the character is actually facing (because of the severe offset that this camera now has from the character). It also replaces the standard attack button (left click/X) to now use the spell. You can cancel out of aiming through a variety of means - pressing the spell button again, dodging or parrying all work! When entering aim mode through the ability data, you can also choose to give the player a "temporary weapon" - this sheathes the sword on your back, and puts a new object of your choosing into the players had, with an offset and rotation. This is how the effect is achieved of the player character "holding" fire or lightning when aiming the respective spell. I think this really adds to the feeling of preparing to sling a lightning bolt, or channel the flamethrower, and that the power is literally at your finger tips! There's also a nice quality-of-life feature here, which is that if you swap from one aim spell to another, it doesn't transition out of aiming mode, it simply swaps what the active spell is, without having to "cast it" again (try casting Lightning Bolt and then switching to Flamethrower to see this). As a final note, spells that put you into aim mode only consume mana when they actively do their ability, rather than as soon as you press the button.

- Enemy Behaviour: The main focus of this prototype is mostly on player controls, so the enemies are pretty straightforward, but still fun and functional enough to test your combat skills on. They have an aggro range, and once aggro'd, they will start circling the player. Each enemy picks a random range (from a min/max range) and direction to circle the player, resulting in different offsets for each enemy. Occasionally, they will stop circling for a few seconds, to stare, (assumedly) menacingly at you, before going back to circling. Every so often, the game picks one enemy to approach the player - although, there is a 20% chance they'll queue up a second, different enemy to go after you a couple of seconds later! When an enemy is chosen, it sprints towards the player, and, once in range, performs its attack. If an enemy is interrupted by damage, if it hadn't reached the player yet, it will go back to chasing you. After finishing attacking, it resumes circling you at a new distance and direction.


Part 2: Technical Breakdown

Don't worry, this section won't be as long! I'll first preface by saying that I have been learning to code since around 2020, and I feel so much more confident in my coding abilities now. I genuinely love doing this! If it isn't obvious from the above, I love creating ability systems and making them user-friendly; I really feel like this is the designer in me showing through my coding. As a small disclaimer, I did use ChatGPT for some help with the more "mathsy" parts of this project, but otherwise it was all coded by myself. Oh, and special shoutout to the YouTube channel git-amend (https://www.youtube.com/@git-amend) who has some of the best tutorials I've ever come across, and for the animation event code I've been alluding to, because I cannot stand Unity's build in animation event system! I modified it to support playing sounds on the animation events too, rather than just executing methods.

- State Machine: The player and enemies run off the same state machine structure, just using different states. This easily allows me to enable/disable certain features in any given state, and what it takes for that state to move to another. For example, movement is locked while performing an ability (either they have their own movement, as mentioned above, or you don't move), so while you're in the "spell cast" state, the movement code is simply not called during that state's update tick.

- Ability System: A ScriptableObject-powered system that is really flexible. It's incredibly easy to set up a new ability, all you need is: the animation for it and the prefab it creates - putting this on the player's current spell will work just with those. I've already mentioned movement values in part 1, but each ability can also have its own damage, knockback and animation-on-use and animation-on-hit, hitstop time and curve. When using an ability, the animation-on-use is called for the user, and the SO data file is passed along the chain all the way to the receiver. This means that the same one data file contains all the information for the user and the receiver. When the receiver receives the call to take damage, they will use the values in the data file to react - for example, when taking damage, the animation-on-hit string could be "hit" for small damage, a quick react to being hit; or "heavy_hit" for large damage, playing a different, longer stumble animation - it all depends on what it says on the data file! Similarly, the damage taken is read from this, and how far the receiver should be knocked back. There's even a checkbox to make the target face the user when taking damage, which feels quite natural. Abilities can also give the user and/or target status effects. This is all very handy for quickly editing the various abilities and attacks.

Special thanks to Zacksly for the Button Icons and Controls! (Licensed under CC BY 3.0 - https://zacksly.itch.io)

Updated 1 day ago
Published 2 days ago
StatusPrototype
PlatformsHTML5
Rating
Rated 3.0 out of 5 stars
(1 total ratings)
AuthorGaryDesignDen
GenreAction
Made withUnity

Comments

Log in with itch.io to leave a comment.

not bad

the mouse lock it broken.