We’re back in Day 14. I finally solved the pesky problem from Day 13 where the Knight refuses to get pushed back when we shoot at him.
Afterwards, I decided to get some sound effects to make the game a little livelier.
Without delay, let’s get started!
Adding Player Hit Effects - Part 2
As you might recall, we last ended up trying to push back the Knight when we shoot them by changing the Knight’s velocity, however the Knight continues to run forward.
The Problem
After a long investigation, it turns out that Brute running animation that I used naturally moves your character’s position forward.
The Solution
After finally searching for unity animation prevents movement, I found the answer on StackOverflow.
In the animator, disable Apply Root Motion and then we must apply the movement logic ourselves (which we already are).
Writing the Knock Back Code
Once we have our Root Motion disabled. We’re relying on our code to move our knight.
The first thing we need to do is update our PlayerShootingController
script to call the knock back code:
using UnityEngine;
public class PlayerShootingController : MonoBehaviour
{
public float Range = 100;
public float ShootingDelay = 0.1f;
private Camera _camera;
private ParticleSystem _particle;
private LayerMask _shootableMask;
private float _timer;
void Start () {
_camera = Camera.main;
_particle = GetComponentInChildren<ParticleSystem>();
Cursor.lockState = CursorLockMode.Locked;
_shootableMask = LayerMask.GetMask("Shootable");
_timer = 0;
}
void Update ()
{
_timer += Time.deltaTime;
if (Input.GetMouseButton(0) && _timer >= ShootingDelay)
{
Shoot();
}
}
private void Shoot()
{
_timer = 0;
Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
RaycastHit hit = new RaycastHit();
if (Physics.Raycast(ray, out hit, Range, _shootableMask))
{
print("hit " + hit.collider.gameObject);
_particle.Play();
EnemyHealth health = hit.collider.GetComponent<EnemyHealth>();
EnemyMovement enemyMovement = hit.collider.GetComponent<EnemyMovement>();
if (enemyMovement != null)
{
enemyMovement.KnockBack();
}
if (health != null)
{
health.TakeDamage(1);
}
}
}
}
The biggest change is that we get our EnemyMovement
script and then call KnockBack()
which we haven’t implemented yet.
Once we have this code in, we need to implement KnockBack()
inside our EnemyMovement
script. Here’s what it looks like:
using UnityEngine;
using UnityEngine.AI;
public class EnemyMovement : MonoBehaviour
{
public float KnockBackForce = 1.1f;
private NavMeshAgent _nav;
private Transform _player;
private EnemyHealth _enemyHealth;
void Start ()
{
_nav = GetComponent<NavMeshAgent>();
_player = GameObject.FindGameObjectWithTag("Player").transform;
_enemyHealth = GetComponent<EnemyHealth>();
}
void Update ()
{
if (_enemyHealth.Health > 0)
{
_nav.SetDestination(_player.position);
}
else
{
_nav.enabled = false;
}
}
public void KnockBack()
{
_nav.velocity = -transform.forward * KnockBackForce;
}
}
I know this was a one liner for KnockBack()
, but there was a lot of work involved to get to this point.
Here’s how the code works:
- When our shooting code hits the enemy, we call
KnockBack()
which sets the velocity to be the direction behind the knight, making the illusion of being pushed back. - This is only temporary as our Nav Mesh Agent will come back and move our Knight towards the player in the next
Update()
- Here’s how
KnockBackForce
effects the velocity
- At
1
, the knight stays in place when you shoot <1
, the knight gets slowed down >1
, the knight gets pushed back
Adding Sound Effects
Now that we finally solved the knockback problem, we moved on to the next thing.
At this point, playing the game seems dull. Do you know what could make things a little bit more interesting? Sound effects!
I went back to the Unity Asset Store to find sound effect assets specifically:
- Player shooting sound
- Player walking sound
- Player hit sound
- Enemy hit sound
- Enemy running sound
- Enemy attack sound
Randomly searching on Unity, I found the Actions SFX Vocal Kit which contains everything we need. Fantastic!
Once we have finished downloading and importing the SFX into our Unity project, we’ll start using them.
Adding Enemy Hit Sound Effects
Adding the Script
The first thing we’re going to do is that we need to add our Male_Hurt
audio clips to our Knight.
Normally, we need to add an Audio Source component for our Knight. However, before that, let’s step back and think: what sounds do our knight need to play?
- Hit sound
- Walking sound
- Attack sound
If we were to add an Audio Source component to the Knight Object and use that to play the sound, what will happen is that one sound will immediately be replaced by the other one. We don’t want that.
What we could do is create multiple AudioSources components and then manually attach them to our script, however that’s not very scalable if we ever decided that we needed more types of sounds.
Instead, I found this great way to add multiple audio sources on a single GameObject.
The idea is that instead of manually creating multiple components and then attaching them to a script component, why not create the component in code?
Here’s what I did:
using UnityEngine;
using UnityEngine.AI;
public class EnemyMovement : MonoBehaviour
{
public float KnockBackForce = 1.1f;
public AudioClip[] WalkingClips;
public float WalkingDelay = 0.4f;
private NavMeshAgent _nav;
private Transform _player;
private EnemyHealth _enemyHealth;
private AudioSource _walkingAudioSource;
private float _time;
void Start ()
{
_nav = GetComponent<NavMeshAgent>();
_player = GameObject.FindGameObjectWithTag("Player").transform;
_enemyHealth = GetComponent<EnemyHealth>();
SetupSound();
_time = 0f;
}
void Update ()
{
_time += Time.deltaTime;
if (_enemyHealth.Health > 0)
{
_nav.SetDestination(_player.position);
if (_time > WalkingDelay && _animator.GetCurrentAnimatorStateInfo(0).IsName("Run")))
{
PlayRandomFootstep();
_time = 0f;
}
}
else
{
_nav.enabled = false;
}
}
public void KnockBack()
{
_nav.velocity = -transform.forward * KnockBackForce;
}
}
There’s a lot of code that was added in, but I tried to separate them as much as I can to easy to understand pieces.
Here’s the flow:
- In
Start()
, we instantiate our new private
fields, specifically our new variables:
_walkingAudioSource
: our AudioSource
for our steps _time
: to track how long the enemy steps take
- We call
SetupSound()
from Start()
and create a new instance of an AudioSource
that will only appear when the game starts and we set the volume to 0.2f
- In
Update()
, we add logic to play the stepping sound whenever it has been 0.2
seconds and if we’re still in the running animation.
- Note: In
GetCurrentAnimatorStateInfo(0)
, the 0
refers to index 0
layer, which I’m not really sure why, but that’s what people use. From there, we can check which state the knight is in.
- In
PlayRandomFootstep()
, we randomly choose the walking sound clips that we downloaded and play them.
Once we have all of this, we need to add the audio clips in.
Go to EnemyMovement
script attached to the Knight
and then under Walking Clips, change the size
to 4
. We can do this because Walking Clips is an array of clips.
Then, add in Footstep01-04
into each spot. Make sure that Walking Delay is set to 0.4
if it’s not already.
Run the game and you’ll see that the enemy makes running sounds now!
If you’re using a different animation, you might have to change the Walking Delay to match the animation, but on the high level, that’s what you must do!
Whenever the knight attacks us, the sound will stop and whenever the knight resumes running after us (with the help of some shooting knockback), the running sound will resume!
Conclusion
Today on Day 14, we found the problem with the knight knockback had something to do with the root animation we used.
After disabling it, we can start adding our knockback code without any problems.
With the knock back implemented, the next thing that we added was sound effects. We found some assets in the Unity store and then we added them to our enemy, where for the first time, we created a component via code.
My concern at this point is what happens when we start spawning a lot of knights? Will that create an unpleasant experience?
Either way, come back tomorrow for Day 15, where I decided I’m going to add the enemy hit sound and the player shooting sound.
Day 13 | 100 Days of VR | Day 15
Home
CodeProject
The post Day 14: Finish Attacking the Enemy and Walking Sounds In Unity appeared first on Coding Chronicles.