using UnityEngine;
using TMPro;
public class ProjectileGun : MonoBehaviour
{
// audio
public AudioSource Audio;
public AudioClip GunShotSFX;
public AudioClip ReloadSFX;
// bullet
public GameObject bullet;
// bullet force
public float shootForce, upwardForce;
// Gun stats
public float timeBetweenShooting, spread, reloadTime, timeBetweenShots;
public int magazineSize, bulletsPerTap;
public bool allowButtonHold;
int bulletsLeft, bulletsShot;
// recoil
public Rigidbody playerRb;
public float recoilForce;
// bools
bool shooting, readyToShoot, reloading;
// Reference
public Camera fpsCam;
public Transform attackPoint;
// graphics
public TextMeshProUGUI ammunitionDisplay;
// bug fixing
public bool allowInvoke = true;
private void Awake()
{
// make sure magazine is full
bulletsLeft = magazineSize;
readyToShoot = true;
}
private void Update()
{
MyInputs();
// set ammo display, if it exists
if (ammunitionDisplay != null)
{
ammunitionDisplay.text = "Ammo: " + (bulletsLeft / bulletsPerTap + " / " + magazineSize / bulletsPerTap);
}
}
private void MyInputs()
{
// check if allowed to hold down button and take corresponding input
if (allowButtonHold) shooting = Input.GetKey(KeyCode.Mouse0);
else shooting = Input.GetKeyDown(KeyCode.Mouse0);
// reloading
if (Input.GetKeyDown(KeyCode.R) && bulletsLeft < magazineSize && !reloading)
{
Reload();
}
// reload automatically when trying to shoot without ammo
if (readyToShoot && shooting && !reloading && bulletsLeft <= 0)
{
Reload();
}
// shooting
if (readyToShoot && shooting && !reloading && bulletsLeft > 0)
{
// set bullets shot to 0
bulletsShot = 0;
Shoot();
Audio.PlayOneShot(GunShotSFX);
}
}
public void Shoot()
{
readyToShoot = false;
// find the exact hit position using a raycast
Ray ray = fpsCam.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0));
RaycastHit hit;
// check if ray hits something
Vector3 targetPoint;
if (Physics.Raycast(ray, out hit))
{
targetPoint = hit.point;
}
else
{
targetPoint = ray.GetPoint(75); // just a point far away from the player
}
// calculate direction from attackPoint to targetPoint
Vector3 directionWithoutSpread = targetPoint - attackPoint.position;
// calculate spread
float x = Random.Range(-spread, spread);
float y = Random.Range(-spread, spread);
// calculate new direction with spread
Vector3 directionWithSpread = directionWithoutSpread + new Vector3(x, y, 0); // just add spread to last direction
// instantiate bullet/projectile
GameObject currentBullet = Instantiate(bullet, attackPoint.position, Quaternion.identity);
// rotate bullet to shoot direction
currentBullet.transform.forward = directionWithSpread.normalized;
// add force to bullet
currentBullet.GetComponent<Rigidbody>().AddForce(directionWithSpread.normalized * shootForce, ForceMode.Impulse);
currentBullet.GetComponent<Rigidbody>().AddForce(fpsCam.transform.up * upwardForce, ForceMode.Impulse);
bulletsLeft--;
bulletsShot++;
// invoke resetShot function (if not already invoked)
if (allowInvoke)
{
Invoke("ResetShot", timeBetweenShooting);
allowInvoke = false;
// add recoil to player
playerRb.AddForce(-directionWithSpread.normalized * recoilForce, ForceMode.Impulse);
}
// if more than one bulletPerTap make sure to repeat shoot function
if (bulletsShot < bulletsPerTap && bulletsLeft > 0)
{
Invoke("Shoot", timeBetweenShots);
}
}
private void ResetShot()
{
readyToShoot = true;
allowInvoke = true;
}
private void Reload()
{
reloading = true;
Invoke("ReloadFinished", reloadTime);
Audio.PlayOneShot(ReloadSFX);
}
private void ReloadFinished()
{
bulletsLeft = magazineSize;
reloading = false;
}
}
Preview:
downloadDownload PNG
downloadDownload JPEG
downloadDownload SVG
Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!
Click to optimize width for Twitter