The earliest solutions I had come up with for having deviation from perfect accuracy involved varying the direction up and down as well as left and right by a random number. While this worked (and it was on a much earlier project that I no longer have), it produced a square pattern. While I have figured out how to make the possible area a cone, I now cannot figure out how to get it to point in the appropriate direction.
float absDir = Random.value * Mathf.PI * 2;
float offShoot = Random.value * accuracy;
Vector3 Dir = new Vector3(Mathf.Cos(absDir) * offShoot,Mathf.Sin(absDir) * offShoot, 100);
Dir.Normalize();
RaycastHit wasShot;
if (Physics.Raycast(Muzzle.position, Dir, out wasShot, 1000.0f))
//Etc
I can’t multiply it by another Vector3, such as Muzzle.forward, and none of the Vector3 class functions look like they’d be of much use, either.
I extracted this from my scripts, it might not be what you want or work with your project, but I am sure it will help you in one way or another.
using UnityEngine;
using System.Collections;
public class Shotgun : MonoBehaviour {
//These 2 controls the spread of the cone
public float scaleLimit = 2.0f;
public float z = 10f;
//Shoots multiple rays to check the programming
public int count = 30;
void Update () {
for( int i = 0; i < count; ++i ) {
ShootRay();
}
}
void ShootRay() {
// Try this one first, before using the second one
// The Ray-hits will form a ring
float randomRadius = scaleLimit;
// The Ray-hits will be in a circular area
float randomRadius = Random.Range( 0, scaleLimit );
float randomAngle = Random.Range ( 0, 2 * Mathf.PI );
//Calculating the raycast direction
Vector3 direction = new Vector3(
randomRadius * Mathf.Cos( randomAngle ),
randomRadius * Mathf.Sin( randomAngle ),
z
);
//Make the direction match the transform
//It is like converting the Vector3.forward to transform.forward
direction = transform.TransformDirection( direction.normalized );
//Raycast and debug
Ray r = new Ray( transform.position, direction );
RaycastHit hit;
if( Physics.Raycast( r, out hit ) ) {
Debug.DrawLine( transform.position, hit.point );
}
}
}
This seems like a geometry problem where the center axis of the cone is where the player fires, i.e. the cross hairs, then you apply a random rotation to point that offset that direction. So, I would first tilt the center axis between zero and your max cone angle along a single axis perpendicular to the center. Then I would spin the result between zero and 360 degrees along the original center axis. So,
Quaternion GetRandomInsideCone(float conicAngle) {
// random tilt right (which is a random angle around the up axis)
Quaternion randomTilt = Quaternion.AngleAxis(Random.Range(0f, conicAngle), Vector3.up);
// random spin around the forward axis
Quaternion randomSpin = Quaternion.AngleAxis(Random.Range(0f, 360f), Vector3.forward);
// tilt then spin
return (randomSpin * randomTilt);
}
you can then do
// fire in direction with random 10 degree offset
Vector3 fireInDirection = new Vector3(3, 4, 5);
Vector3 fireInRandomDirection = GetRandomInsideCone(10) * fireInDirection;
// or rotate an object within the cone
Transform weapon = GetSomeTransform();
weapon.rotation = GetRandomInsideCone(conicAngle) * originalRotation;