Welcome back to Day 16! Today we’re going to go fix some of the assets for the game.
Specifically, today I want to:
- Use a real gun asset
- Add the shooting effect back in
- Create code to trigger reloading
Do you know what that means?
We’re going to go back to the Unity asset store to find new assets! Let’s get started!
Setting Up a Real Gun Asset
I looked around for a gun asset and I found a great machine gun model to use!
I found this great looking Machine Guns asset.
After downloading and loading the asset into our Unity game, you’ll find the files in the FreeMachineGun
folder in the main project tab.
The first thing we should do is replace our cube with our gun asset.
In the folder FreeMachineGun
: FreeMachineGun
> Prefabs
we find MachineGun_00.
Drag the prefab into our hierarchy and make it a child of our Main Camera
game object, making it the child of our previous Gun
game object.
I made some configuration to my transform to make it fit here’s what I have, however you might have to eyeball it yourself.
- Position: (0.25, -0.5, 0.75)
- Rotation: (0. 90, 0)
You should have something like this:
I like how straightforward this is!
Setting up the Gun Animation to Run When We Shoot
Right now, when we left click, our gun will start shooting and spilling out ammos.
You might be thinking: “Wow! This model is amazing - it even has the shooting code done for me!”
Unfortunately, it isn’t that easy. What we’re seeing is the particle effect of the gun that we activate in our PlayerShootingController
.
You might also notice that after we shoot, our particle effect never stops either, that’s because in our code, we never had to stop our particle effect before.
Before we go in and fix this, let’s first understand the states to our animation.
For us to interact with the animation of a model, we must go to the Animator
tab to set animation states and transitions.
Select MachineGun_00
in the hierarchy pane and then go to the Animator
tab.
If the Animator tab isn’t available, you can find it in Window
> Animator
.
Here’s what we see.
We have 3 trigger
parameters to work with:
As for our state, we have 4 states:
Default
MachingGun_open
MachineGun_shoot
MachineGun_reload
Looking at our transitions…
In default
:
Shoot
transition to the MachineGun_shoot
DoOpen
transitions to MachineGun_open
DoReload
transitions to MachineGun_reload
In MachineGun_shoot
:
Shoot
transition back to default
DoOpen
transitions to MachineGun_open
DoReload
transitions to MachineGun_reload
In MachineGun_open
:
Shoot
transition to the MachineGun_shoot
DoOpen
transitions back to default
DoReload
transitions to MachineGun_reload
In MachineGun_reload
:
- After the animation time is finished, we transition to
default
Now that we understand how the trigger logic works, we can work on the shooting script.
Now I don’t know what the DoOpen
animation is for, however we don’t need it for the game in my mind. We just need to shoot and reload.
Creating the Code to Shoot
Now that we have the assets in place, we’re going to write the code to use it.
The first thing is that for some reason, I attached the PlayerShootingController
to the camera. I’m going to move that to our new MachineGun_00
game object.
If you created a new PlayerShootingController
, make sure the settings are:
- Range:
100
- Shooting Delay:
0.2
- Shot Sfx Clips:
Machine_Gunfire_01
Before going to the code, I had to think about the general cases that I would encounter for our animation to work.
It’s interesting to think about it, because we have 3 states that our gun can be in: default
, shooting
, and reloading
. Now imagine how much more complicated if we had to transition between even more!
When I first started coding, I just had the general case, press R to reload and then shoot.
However, there were problems where my code would put me in permanent shooting animation mode among many other things.
There were some that I had to encounter, here were the specific animation cases I had to consider:
- Hit reload while we’re not doing anything
- Hit reload while we’re shooting
- Shoot while we’re reloading
- Never let go of our mouse before we shoot, reload, and then hold on until after we’re done reloading
Without any further waiting, here’s our code:
using UnityEngine;
public class PlayerShootingController : MonoBehaviour
{
public float Range = 100;
public float ShootingDelay = 0.1f;
public AudioClip ShotSfxClips;
private Camera _camera;
private ParticleSystem _particle;
private LayerMask _shootableMask;
private float _timer;
private AudioSource _audioSource;
private Animator _animator;
private bool _isShooting;
private bool _isReloading;
void Start () {
_camera = Camera.main;
_particle = GetComponentInChildren<ParticleSystem>();
Cursor.lockState = CursorLockMode.Locked;
_shootableMask = LayerMask.GetMask("Shootable");
_timer = 0;
SetupSound();
_animator = GetComponent<Animator>();
_isShooting = false;
_isReloading = false;
}
void Update ()
{
_timer += Time.deltaTime;
if (Input.GetMouseButton(0) && _timer >= ShootingDelay && !_isReloading)
{
Shoot();
if (!_isShooting)
{
TriggerShootingAnimation();
}
}
else if (!Input.GetMouseButton(0))
{
StopShooting();
if (_isShooting)
{
TriggerShootingAnimation();
}
}
if (Input.GetKeyDown(KeyCode.R))
{
StartReloading();
}
}
private void StartReloading()
{
_animator.SetTrigger("DoReload");
StopShooting();
_isShooting = false;
_isReloading = true;
}
private void TriggerShootingAnimation()
{
_isShooting = !_isShooting;
_animator.SetTrigger("Shoot");
}
private void StopShooting()
{
_audioSource.Stop();
_particle.Stop();
}
private void Shoot()
{
_timer = 0;
Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
RaycastHit hit = new RaycastHit();
_audioSource.Play();
_particle.Play();
if (Physics.Raycast(ray, out hit, Range, _shootableMask))
{
print("hit " + hit.collider.gameObject);
EnemyHealth health = hit.collider.GetComponent<EnemyHealth>();
EnemyMovement enemyMovement = hit.collider.GetComponent<EnemyMovement>();
if (enemyMovement != null)
{
enemyMovement.KnockBack();
}
if (health != null)
{
health.TakeDamage(1);
}
}
}
public void ReloadFinish()
{
_isReloading = false;
}
private void SetupSound()
{
_audioSource = gameObject.AddComponent<AudioSource>();
_audioSource.volume = 0.2f;
_audioSource.clip = ShotSfxClips;
}
}
There’s been a lot of changes and addition to the code, but in general, here’s the flow:
- We created more variables to keep track of what state we’re in. Currently we’re using Booleans, however I think using Enums to represent our state might be a better idea, especially if we have more states to keep track of.
- In
Start()
, we initialize our new boolean states - In
Update()
, while we’re not reloading and we hit Shoot, if we haven’t started shooting, we’ll start our shooting animation in TriggerShootingAnimation()
and we’ll run our shooting logic in Shoot()
- Whenever we let go of our mouse, we’ll go to the
else
statement in Update()
and stop our shooting animation and run our stop shooting logic in StopShooting()
which stops our music and particle effect - A side note: In
Shoot()
, I started the particle effect when we hit something with the raycast, we want it to always run whenever we shoot. - In
Update()
when we want to reload, we press R and we’ll go into StartReloading(),
here we would trigger our reload animation to start and disable our shooting so the players can’t continue shooting. - We have a
public
function ReloadFinish()
that tells us we’re done reloading. We’re going to have to go to the animation for our machine gun and add an event to run this function whenever we’re done reloading.
So now that we have our code in place, let’s add the event into our reload animation to run our ReloadFinish()
code when the animation finishes.
To do that, select MachineGun_00
and select the Animation
tab.
If you don’t have the Animation
tab, you can open it by going to Window -> Animation.
Here’s what we will have at the end:
In the animation tab:
- Select
MachineGun_reload
as our animation - Go to frame
68
C
lick the add event button
below our frame number - Select
ReloadFinish()
as the function to run once we get to that frame
With all of this in place, we’ll be able to reload now when we hit R and then resume normal shooting controls after the animation ends.
Conclusion
There we go! Today, we added a real gun asset to replace our fake cube gun. As you can see, it wasn’t that bad and a lot of the things we did, we already learned from the Zombie Shooter tutorial we did at the end.
With our gun in place, we’re done now, right? WRONG!
Back when I was doing my Survival shooter post, Scouting Ninja commented to me on how shooting really works and it turns out that the raycast we create isn’t actually coming directly from the screen.
It’s coming from the muzzle of our gun to the middle of the screen.
Tomorrow, I’m going to investigate how to shoot a raycast from our gun muzzle instead of directly from our screen!
Until then, I’ll see you all in Day 17!
Day 15 | 100 Days of VR | Day 17
Home
CodeProject
The post Day 16: Using A Real Gun Model In Unity appeared first on Coding Chronicles.