Friday 17.6 | Back Critical Strike

Platformer Prototype

Adding a critical strike marker for enemies when they're facing away from the player. Needs some fixing still because of a small detour during the day.

Shader Execute/Critical Strike Mark

First I simply created a world canvas with a radial fill for the timer and a simple cross graphic. The idea was to first run the timer and then activate the graphic and notify the character scripts that this enemy can be critically striked. Everything looked pretty good but I just got a tingle that it could look amazing actually on the back of the enemy.

NotUsedShaderExecuteMark

Well I "somehow" got it working and looking great, but when actually playing the mark was way too small in my opinion (could be a sick shirt graphic though). Since there's no good way of making it noticeably larger, I scrapped the material for now. It really wouldn't even make a big difference, because of the viewing angle always being favourable for the canvas.

ExecuteMark

Day's Work

"Execute" probably going to get renamed to critical strike

  • Imported running attack
  • Enemy
    • Execute timer
    • Sound when able to execute
    • Sound when the strike hits
    • Fading in and out
  • Character
    • Execute
      • Disable player movement when executing
      • Weapon effects

Wednesday 15.6 & Thursday 16.6 | Combat

Platformer Prototype

I got a little excited when I got the combat actually playable and worked on it for 13 hours on Wednesday. So yeah, today I'm just gonna write this and take it easy. On Wednesday though, the combat started to look and feel pretty good already. I'll still have to mess around with the camera, figure out how to visualize the enemy's health and add a lot of things, but that's gonna be after getting the stealth mechanic working and seeing how it all plays out.

Kicking to Keep Player at Attacking Range

I had trouble keeping the player at a hittable range. The problem wasn't only that the enemy wouldn't hit but more that the enemy got "pushed" when trying to move back to the hittable range. It probably could've worked with some precise movement, but that means a lot of time for polishing. I thought a more interesting way to keep the player at a distance would be a kick.

Kick

This seemed like a great idea but still required some coding for the push. In the end I decided that this wouldn't be an obstacle for adding it because the pushing code would probably get used a lot in the future. Currently the actual push is just roughly timed and the strength over time is controlled with an animation curve and I don't think that that's going to be changing because it really might not even matter.

The kick ended up being a great and time efficient way of preventing the player from drilling the enemy's shins to dust.


Weapon Swinging and Impact Sounds

I also got some great sounds in, thanks to Eponn on FreeSound.org. The WeaponInfo ScriptableObject has a list for swinging sounds and impact sounds (per weapon of course). Then when swinging I just get a random one different from the previous and play it with the help of an AudioSource pool.


Download Audiosource pool Script

I thought AudioSource pooling can be useful in any project, so if you wanna save a couple minutes on writing one, download this. AudioSourcePool (Isn't optimized or anything)


About the weird attacking behaviour code

I decided to disable behaviour tree evaluating totally while the enemy is dead or disabled. After this I got almost all of the functionality out of the EnemyBehaviour and into the behaviour tree nodes.


GlobalCombatManager

Work Done

  • Player now takes damage and reacts too
    • Player's movement and angular speed controllable when attacking
    • "Character" script for holding the player's state and everything associated (IDamageable, Stats, Reacting to hits)
  • Refactoring and better segmenting a lot of Character Controller code => More readable, easier to debug, easier to add more functionality
  • Global Combat Manager for easy testing/balancing of combat
    • Holds parameters for combat such as
      • Threshold of damage after which an enemy or player reacts (the animation)
      • Movement and angular speed when attacking
  • Enemy
    • Modified primary attack animation to always hit when straight ahead (swung to the side before)
    • Kicking
      • When player gets too close the enemy kicks him
      • Meant adding a pushing mechanic to the character controller
        • Did with Vector3 PushVelocity
        • When PushVelocity is not zero, override the normal movement loop
  • Very simple Player hp and enemy hp UI
  • Weapon
    • OnSwing animation event to play swing sounds
    • Hit & Swing sounds (Thanks to Eponn on FreeSound.org)
    • Hit and getting hit haptics
  • AudioSource pool with main method: PlaySoundAtPosition()
    • This method finds an available audiosource from the pool, if on eis not found it gets instantiated

Tuesday 14.6 | Enemy Combat

Platformer Prototype

Adding basic functionality for enemy combat. I will probably be refining and adding effects to this for the rest of the week.

Behaviour Tree & Enemy Script Relationship

I implemented the combat state management system pretty weird. I have some functionality in the behaviour tree nodes and some in the EnemyBehaviour script (driven by the behaviour tree though). I have some concerns but first, here's roughly how chasing and attacking works at the moment.

Behaviour Tree Chasing/Attacking Node

Pseudocode:

	if (PlayerInAttackRange && IsFacingPlayer)
		enemy.state = EnemyBehaviour.EnemyState.Attacking;
		
	else
	{
		enemy.state = EnemyBehaviour.EnemyState.Chasing;

		// If target in range but not facing it turn it
		if (PlayerInAttackRange)
			RotateTowardsPlayer();

		navMeshAgent.SetDestination(playerPosition);
	}

EnemyBehaviour (Main enemy script)

Pseudocode:

	Update()
	{
		switch (state)
		{
			case EnemyState.Patrolling:
				Patrolling();
			case EnemyState.Chasing:
				Chasing();
			case EnemyState.Inspecting:
				Inspecting();
			case EnemyState.Attacking:
				Attacking();
			case EnemyState.Dead:
				break;
		}
	}

I did this partly because I found it easy to implement the attacking loop fully in the EnemyBehaviour. I'm worried that this might cause issues when implementing the stealth and such, but I'll have to look into it tomorrow and decide how I'm going to approach this.

SecondaryAttack CoolGuyStats

Day's Work

  • Enemy combat
    • "Guard" Behaviour Tree
      • Attacking/Chasing sets the EnemyBehaviour state to Chasing and Attacking
    • EnemyBehaviour
      • Enum EnemyState
      • Frequency of secondary attacks determined by ScriptableObject EnemyStats
      • Attack speed corresponds to animation length
        • Animation length has to be 2s
        • Animation speed is 2 and changed with "Attack Speed" parameter
    • Secondary attack animation
    • Small fixes

Monday 13.6 | Animated Enemy

Platformer Prototype

Adding an animated enemy around which I will be building the enemy functionality hopefully within this week. As much as possible is yoinked from the player systems. Today I got the enemy's basic patroling movement and hit reaction working.

Enemy Animator System

I'll implemented enemy animations with a single Animator Controller and just change the animations within it using Animator Override Controllers.

EnemyCoolGuy

Reacting to hits

I use a blend tree for changing the reaction direction. In the code I have an Enum that has the type of reactions and I use this when setting reactions, making the code a lot more readable.

EnemyCoolGuy

Day's Work

  • Enemy
    • Import "Cool Guy" as enemy
      • Old model I got from sketchfab some time ago (Heavily optimized)
      • Animations from mixamo
      • Model Machete
    • Reacting to damage (Only gut atm other animations I got were from left and right and I'm going to be implementing those tomorrow)
    • Set up everything ready for attacking
      • Use the Weapon Manager that the player also uses (Just less detection points)
      • EnemyBehaviour (The script every enemytype script will inherit from)
      • CoolGuy (The enemytype specific script, atm empty)
      • Animator
        • Stolen from player
        • Using Animator Override Controller as a animator controller prefab
      • Patrolling is the same as what the old enemies' had
  • Fixed bug with player's attack cooldown

Friday 10.6 | Combo Attack

Platformer Prototype

Today's task was to add combo attacks and do minor fixes all around the combat system. Now I will probably be switching focus to enemy combat. I think If I were to continue adding to the combat system, I would find a lot to be useless after adding the enemy combat system. After getting the enemy combat system up and running I will probably see the bigger picture clearer.

Combo Attack

On the code side I'm just checking for the attack input when 60% of the attack's cooldown has passed. If input is given a "Combo" boolean parameter on the animator is set to true which I use to disable the "Any State" transitions.

ComboAttacksAnimator
  • Sword Trail fixed
  • Attacking while rolling removed
  • Combo attacks
    • Animator based implementation (Script is only used to control a combo boolean)
    • Needs testing (Minimal, No polishing)
    • Reworked code for attacking to fit comboing
  • New attack animation for primary attack combo

Thursday 9.6 | Platformer Camera

Platformer Prototype

Today was almost all about implementing an actual platformer camera into the project. Other than that I just added a trail to the sword.

Platformer Camera

I started to notice that I had to fully control the camera which isn't what platformers are about and thought I could fix this before going deeper into combat. I played a couple of old platformers and realized that I was essentially using a 3rd person shooter camera. I knew all along it wasn't the right kind of camera but didn't realise the right one would make such a big difference.

CinemachineFreeLookCamera

Before this I started with fiddling around with the Cinemachine Virtual Camera but didn't seem to find the right one for the job. So I looked into it a bit more and found out that Cinemachine has the right camera but just not within the virtual camera (has like a thousand settings itself), which I quess is made for 3rd and 1st person shooters. The right camera was the "free look" camera with the orbit mode "simple follow with world up", which wants to stay in place(world space) while looking at the player at a specified distance.

Sword Trail

I added a sword trail with the help of a useful tutorial I found on Youtube. For turning it off and on again I use the emission module's RateOverTimeMultiplier, setting it to 0 and back to original when attacking. In need of some polishing effort though.

SwordTrail

Day's Work

  • Implementing the Cinemachine Free Look Camera
    • Input from new input system
    • Cinemachine collider using the smoothed "pull to player" method
    • Smoothing camera height with platform snapping (When grounded or climbing snap player follow transforms target height to players height, Not used in video because in my opinion maybe not needed for this kind of platformer, but time will tell)
  • Sword trail
    • Particle system trail
    • Controlled by weapon manager StartDealingDamage and StopDealingDamage functions

Tuesday 7.6 & Wednesday 8.6 | Melee Combat

Platformer Prototype

Tuesday stretched a little longer than I would've wanted to. A lot got done on the detection and damage system though. Wednesday I spent on making minor fixes all around and getting the attacks to feel more responsive.

Damage & Detection System

Detection

Detection system got a lot of new stuff including:

  • 2 ways for detecting hits
    • SphereOverlap
    • Raycasts back and forward

Sphere Overlap is used to find clean hits and raycasts are used find hits where the blade has gone through the player in one frame (collision detection therefore missing it).

Damage

I had a couple of ideas for the damage system, one being calculating the damage for every detection point and the other being velocity based attacks. The first one felt nice but is a total pain to implement thanks to the complexity. The velocity on the other hand made the hits feel random.

Finally I ended up with a per point calculations with position of the points scaling the damage linearly (Closer to the tip deals more damage). The point closest to the handle dealing 1/10 (amount of points) the damage and the very tip dealing full damage.

This damage also scales the effects which are up next.

Effects

For every detection point that has hit there is a ParticleSystem instantiated or placed from pool. I created an empty object and a "MonoBehaviour" to hold and manage these, called "ParticleSystemPool", which does the following:

  • Instantiates new ParticleSystems when needed
  • Places them
  • Scales bursts based on damage
  • Plays the effects

Using "Any State" Transitions for Responsive Attacking

AnimatorAttackAnyState

Rolling Fixed

Switched from using root motion to just locking the direction and adding some speed. Can't see a difference and feels a 100 times better. Before even the smoothed camera got weird because the root motion was so jittery.

Pictures

WeaponManagerEditor

WeaponManager Editor


SwordEditor

SwordEditor


WeaponTypeScriptableObject

WeaponType ScirptableObject


AttackAnimationEvents

Attack Animation Events


Work Done

  • Hit detection system
    • Now has 2 ways for detecting
      • SphereOverlap (After which a raycast is used to determine the point where effects are played from)
      • Raycasts back and forward
    • A lot of polishing and debugging
  • Damage System (Calculated per detection point)
    • Blade position based damage (Closer to the tip deals more damage)
    • (Wednesday) Offset the impact of position based damage to get true max damage of weapon (Still has small bug)
    • Animation events start and stop the damage dealing and hit detection
  • Hit effects (ParticleSystems only, per detection point)
    • "ParticleSystemPool" which holds the particle systems
      • Instantiates when needed
      • Places the effects
      • Scales bursts depending on damage
      • Plays the effects
  • Weapon system
    • "Weapon Manager" on player which holds "WeaponBehaviour equippedWeapon"
    • "Sword" is on the weapon and derives from "WeaponBehaviour"
    • "WeaponBehaviour" holds the parent of the blade line parent and a ScriptableObject "WeaponType"
    • "WeaponType" Holds the weapon's max damage and attack speed (only max damage is implemented as of now)
  • Fixed rolling (Wednesday)
    • No more root motion because it made the character go through walls
  • Fixed attack timings (Wednesday)
    • Transitions come from "Any State" state so it doesn't matter if asomething else is playing but cooldown is off

Monday 6.6 | Combat, Melee Hit Detection

Platformer Prototype

Starting on this week's focus combat with melee hit detection. Creating a sword with a line acting as the damage dealing section. Raycast based hit detection script for it.

Detection Points Distribution

I created a script that distributes given amount of points on a line constructed of empties. In the video the "detection points" are drawn as spheres on the sword.

SwordLinePointsVisualized

Spheres in the picture visualize the line's points.

Raycasting

The position of the "detection points" are saved for the next frame. Then a raycast is shot towards the last frames position, detecting a possible hit. In the video the red rays mean no hit and green ones mean hit.

Day's Work

  • Blender
    • Second attack animation modified to make sword movement look "realistic"
    • Importing only actions in the NLA strips to accelerate iterating
    • Sword modeled
  • Weapon script
    • Distributing points on a line
    • Ray shooting from those points to their old positions
    • Gizmo spheres
  • "Enemy" physics layer

Friday 3.6 | More Climbing Animations

Platformer Prototype

Continuing yesterday's animating and animator work. Adding a ledge grab animation, trying new things with the animator layers and minor fixing overall.

Root Bone Problems

Trying different things with the animator, but still having the problem of the character floating on the wall because of the root bone being a deform one. I will be looking into this over the weekend, the solution hopefully not being to manually animate a new non-deform root bone to every animation.

WallGap

Animator Layers

Sharing states among more animator layers for clarity. Minor flaw being the lack of blending between jumping and grabbing the wall.

ClimbingLayer MovementLayer
  • Climbing
    • Ledge grabbing animation
    • Snapping to ledge
    • Slipping gets faster with time
    • Climbing added to a new layer in animator
    • Fixed bug when climbing indoors and hitting roof
    • Other minor fixes

Thursday 2.6 | Climbing Animations

Platformer Prototype

After yesterday's coding I took this day a little more chill and did some animating and unity animator work.

Animations in Unity

Looking pretty janky at the moment, but almost everything is going to get polished.

Blender IK Exporting Problems

I didn't find good animations from mixamo so I had to make them. So I added inverse kinematics to my rig to do them in a timely manner and it's also beneficial for any probable animating in the future. IK turned out to be a problem when exporting the animations. I thought Blender would add keyframes to the constrained bones automatically when exporting, but this wasn't the case, I only got the old Unity rig to animate the root bone.

FastIK

After a "little bit" of googling I found out about "baking actions" which saved the day. This feature creates a new action and basically creates keyframes for the constrained bones every "Frame Step".

ActionBaking ActionBakingMenu

Today's Work

  • Blender
    • IK added to rig
    • Leap animation
    • Slipping animation
  • Unity
    • Climbing Animations imported
    • States added to a messy animator
    • Animator parameter handling added to climbing code