Angle calculation for raycast shotgun weapon ?
Hello, i am doing quake-like fps weapons with completely editable characteristics, and i am trying to make a spray like for shotguns. The bullets are raycast and the script is attached on the gun. The shoot function is called on the controls script on the player. However, it fires on a straight line on the X axis and i cannot figure why. What i want is that the angle isn't that messed up and fires like a cone. Here's the script :
using UnityEngine; using UnityEngine.Networking;
public class GunScript : MonoBehaviour {
//Bullets characteristics
[SerializeField]
private LayerMask mask; // the masks for the raycast
private GameObject parentOfGun; //the player that carries the gun
private string weaponName = "Test Gun"; //The name of the gun that this script is attached
private float damage = 2.5f; //How much damage a bullet deals to another player
private int bulletsPerShot = 5; //Useful for shotguns : how much bullets are raycasted at any shot.
private float shotsPerSecond = 1; //How many times the gun is activated per second
private float range = 100; //The range of our bullets
private float dispersionAngle = 45; //The dispersion angle of our bullets,
[SerializeField]
private Transform bulletSpawnPoint; //The points where raycast bullets "appears"
private float countdownBeforeShooting = 0f; //Time before we can shoot again*
[SerializeField]
private GameObject[] impactBulletEffects; //List of all bullet impacts, order should be like in MaterialScript
private void Start() //Intialize our variables, like usual
{
if(bulletSpawnPoint == null) //We don't want to spawn something from nowhere, do we ?
{
Debug.LogError("GunScript : No bullet spawnpoint referenced!");
this.enabled = false;
}
dispersionAngle /= 360; // We fix to a usable dispersion
gameObject.name = weaponName; //Anything should have its own name, even chocolate bread should be named "Chocolatine" in France!
parentOfGun = GetComponentInParent<NetworkIdentity>().gameObject;
}
public void Shoot(GameObject shooter)
{
if (shooter != parentOfGun)
{
Debug.Log("The guy who used this function has tried to use someone else's gun? Is his client screwed up, or is he hacking ?");
}
else
{
if (countdownBeforeShooting <= 0)
{
GetComponent<AudioSource>().Play();
for (int i = 0; i < bulletsPerShot; i++)
{
RaycastHit _hit;
//Implementing bullet spread
Vector3 newDirectionToShoot = Vector3.Scale(new Vector3(Random.Range(-dispersionAngle, dispersionAngle) * Mathf.Cos(Random.Range(0, 2 * Mathf.PI)), Random.Range(-dispersionAngle, dispersionAngle) * Mathf.Sin(Random.Range(0, 2 * Mathf.PI)), 0),bulletSpawnPoint.transform.forward);
print(newDirectionToShoot);
Debug.DrawRay(bulletSpawnPoint.position, newDirectionToShoot, Color.red, 4);
if (Physics.Raycast(bulletSpawnPoint.position, newDirectionToShoot , out _hit, range, mask))
{
Debug.Log("We hit " + _hit.transform.name);
//We hit something
//Let's do the impact effect
Debug.Log(transform.forward);
GameObject impactObject = GetBulletImpact(_hit.transform.gameObject);
GameObject impactParticle = Instantiate(impactObject, _hit.point, Quaternion.Inverse(transform.rotation),_hit.transform);
Destroy(impactParticle, 5);
//Add damage to the guy
}
countdownBeforeShooting = 1 / shotsPerSecond;
}
}
}
}
private void Update() //This void fixes our countdown
{
countdownBeforeShooting -= Time.deltaTime;
}
GameObject GetBulletImpact(GameObject objectHit)
{
MaterialScript ms = objectHit.GetComponent<MaterialScript>();
if(ms != null)
{
int material = ms.material;
switch (material)
{
case 0: //meat
return impactBulletEffects[0];
break;
case 1: //sand
return impactBulletEffects[1];
break;
case 2: //metal
return impactBulletEffects[2];
break;
case 3: //stone
return impactBulletEffects[3];
break;
case 4: //wood
return impactBulletEffects[4];
break;
case 5: //water
return impactBulletEffects[5];
break;
default:
Debug.LogError(objectHit.name + " has no correct MaterialScript attached. However, a GunScript tried to access it");
return null;
break;
}
} else
{
Debug.LogError(objectHit.name + " has no MaterialScript attached. However, a GunScript tried to access it");
return null;
}
}
}
Answer by BytingWolf · Jun 16, 2018 at 09:46 AM
I've fixed my bug, the position of newDirectionOfShoot was messed up, now it should be fixed. Don't either make a too big dispersion :
(in the start function, divide the dispersion angle by 2 * Mathf.PI)
public void Shoot(GameObject shooter, Quaternion playerOrientation)
{
if (shooter != parentOfGun)
{
Debug.Log("The guy who used this function has tried to use someone else's gun? Is his client screwed up, or is he hacking ?");
}
else
{
if (countdownBeforeShooting <= 0)
{
GetComponent<AudioSource>().Play();
for (int i = 0; i < bulletsPerShot; i++)
{
RaycastHit _hit;
//Implementing bullet spread
// Generate a random XY point inside a circle:
Vector3 scatter = Random.insideUnitCircle * dispersionAngle;
scatter.z = 10; // circle is at 10 units
scatter = transform.TransformDirection(scatter);
Debug.Log("dispersion : " + scatter);
if (Physics.Raycast(bulletSpawnPoint.position, scatter , out _hit, range, mask))
{
//We hit something
//Let's do the impact effect
GameObject impactObject = GetBulletImpact(_hit.transform.gameObject);
GameObject impactParticle = Instantiate(impactObject, _hit.point, Quaternion.Inverse(transform.rotation),_hit.transform);
Destroy(impactParticle, 5);
//Add damage to the guy
}
countdownBeforeShooting = 1 / shotsPerSecond;
}
}
}
In: if (Physics.Raycast(bulletSpawnPoint.position, scatter , out _hit, range, mask
I notice that na$$anonymous$$g of variables is important - you are not handing down the scatter [amount], but the direction. A better na$$anonymous$$g would be to use 'directionPellet' etc, to accurate describe what the variable holds.
Your answer
Follow this Question
Related Questions
A few tips on FPS design. 0 Answers
Using waitforseconds to put delay between gunshots 1 Answer
How to restrict rotation? 0 Answers
My script doesnt work? 0 Answers
Basic FPS help! 2 Answers