Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Can't create fixed shotgun spread

Discussion in 'Scripting' started by trdfhht, May 14, 2022.

  1. trdfhht

    trdfhht

    Joined:
    Apr 6, 2021
    Posts:
    4
    I have been trying to make bullets spread out in a non-random way when shooting, similar to TF2's competitive mode, where all the bullets go in 3 straight horizontal lines, and form a square. (here is an example of it) With my current script, they all go in straight lines when the player is looking at a 90 degree angle, but spread diagonally when looking at a bigger or smaller angle. (the bullets go in a vertical line at 180 degrees)

    Here is an example of the problem : https://imgur.com/a/uKeAQFk The main holdup seems to be that my script doesn't properly take account of the player's y rotation when spreading out the bullets. No matter what I try, it never seems to....

    The script :
    Code (CSharp):
    1.  public GameObject bullethole;
    2.     private float NextTimeToFire = 0f;
    3.     List<Vector3> s = new List<Vector3>();
    4.     public int currentAmmo = 4;
    5.     public float firerate = 0.625f;
    6.     public float reloadTime = 0.6f;
    7.     public float timer;
    8.     public float damage = 6f;
    9.     public Vector3 direction;
    10.     public Vector3 spread;
    11.     public float range;
    12.     public Camera cam;
    13.  
    14.     void Start()
    15.     {
    16.     //this is a list of predetermined spread positions
    17.         s.Add(new Vector3(0, 0));
    18.         s.Add(new Vector3(0, 0.05f));
    19.         s.Add(new Vector3(0, -0.05f));
    20.         s.Add(new Vector3(0.05f, 0));
    21.         s.Add(new Vector3(0.05f, 0.05f));
    22.         s.Add(new Vector3(0.05f, -0.05f));
    23.         s.Add(new Vector3(-0.05f, 0, 0));
    24.         s.Add(new Vector3(-0.05f, 0.05f));
    25.         s.Add(new Vector3(-0.05f, -0.05f));
    26.     }
    27.  
    28.     void Update()
    29.     {
    30.         if (currentAmmo == 0)
    31.         {
    32.             timer += Time.deltaTime;
    33.  
    34.             if (timer >= reloadTime)
    35.             {
    36.                 timer = 0;
    37.                 currentAmmo = 4;
    38.             }
    39.         }
    40.  
    41.         if (Input.GetButtonDown("Fire1") && currentAmmo != 0 && Time.time >= NextTimeToFire)
    42.         {
    43.             NextTimeToFire = Time.time + firerate;
    44.             for (int i = 0; i < s.Count; i++)
    45.             {
    46.           //for each predetermined spread position in the list, shoot
    47.                 RaycastHit hit;
    48.                 spread = transform.TransformDirection(s[i]);
    49.                 Vector3 direction = spread + cam.transform.forward;
    50.           //convert the spread to world space and add it to the look direction
    51.  
    52.                 if (Physics.Raycast(cam.transform.position, direction, out hit))
    53.                 {
    54.                     GameObject hole = Instantiate(bullethole, hit.point + new Vector3(0, 0, 0.3f), Quaternion.LookRotation(-hit.normal));
    55.                     Destroy(hole, 5f);
    56.                     Health target = hit.transform.GetComponent<Health>();
    57.  
    58.                     if (target != null)
    59.                     {
    60.                         target.TakeDamage(damage);
    61.                     }
    62.                 }
    63.  
    64.                 if (i == 10)
    65.                 {
    66.                     currentAmmo -= 1;
    67.                 }
    68.             }
    69.         }
    70.     }
    If someone can find a solution to this it would be a godsend....
     
    Last edited: May 14, 2022
  2. Peeling

    Peeling

    Joined:
    Nov 10, 2013
    Posts:
    404
    Code (CSharp):
    1.                 spread = transform.TransformDirection(s[i]);
    2.                 Vector3 direction = spread + cam.transform.forward;
    If transform and cam.transform are not pointing the same direction...
     
  3. trdfhht

    trdfhht

    Joined:
    Apr 6, 2021
    Posts:
    4
    It doesn't seem to change if the line is
    Code (CSharp):
    1. spread = cam.transform.TransformDirection(s[i]);
    I already tried that =(
     
    Last edited: May 15, 2022
  4. Peeling

    Peeling

    Joined:
    Nov 10, 2013
    Posts:
    404
    If you can share the project or a part of it, I can take a look. If you use the same transform to rotate the spread AND add its forward direction, that will definitely produce the right result - there must be something else going on that isn't visible in that chunk of code.

    Incidentally, instead of adding the camera transform forward, you could just put 1f as the third element in all the spread constructors. That will have the same effect.

    Also:
    Code (CSharp):
    1.                 if (i == 10)
    2.                 {
    3.                     currentAmmo -= 1;
    4.                 }
    ...what?
     
  5. trdfhht

    trdfhht

    Joined:
    Apr 6, 2021
    Posts:
    4
    Here is the project : https://www.mediafire.com/file/354149kxvpl510y/My+project+(1).7z/file though I can basically guarantee that there is nothing else going that isn't visible in that chunk of code. I tried your suggestion and as expected it sadly produced the same result than adding cam.transform.forward... As for this part :
    Code (CSharp):
    1.  if (i == 10)
    2.      {
    3.          currentAmmo -= 1;
    4.       }
    I don't get what's weird about it, it just removes one ammo when the last bullet (the tenth one) is spawned. You can move that line here though to save an if statement.
    Code (CSharp):
    1.  if (Input.GetButtonDown("Fire1") && currentAmmo != 0 && Time.time >= NextTimeToFire)
    2.         {
    3.             NextTimeToFire = Time.time + firerate;
    4.             currentAmmo -= 1;
     
    Last edited: May 16, 2022
  6. Peeling

    Peeling

    Joined:
    Nov 10, 2013
    Posts:
    404
    I thought that's what it meant, but when you see something out of place like that it makes you doubt yourself: "If it's just supposed to happen at the end of the loop, why not just put it after the loop? What am I missing"

    Also, it won't work because i will never be equal to 10 (or 9, for that matter)
     
  7. Peeling

    Peeling

    Joined:
    Nov 10, 2013
    Posts:
    404
    Your project is working fine. I swapped out the bullethole quad for a sphere (easier than fixing the z-fighting to see what's going on) and got this:
    Capture1.PNG Capture2.PNG Capture3.PNG

    Don't forget that it will only look like an even spread from the place you fired it from. If you move after firing, it will no longer look even:
    upload_2022-5-16_10-3-18.png

    EDIT: Oh, and you had two gun scripts in the scene.
     
    Last edited: May 16, 2022
  8. trdfhht

    trdfhht

    Joined:
    Apr 6, 2021
    Posts:
    4
    Well I honestly don't know what to do anymore, I can very obviously see that it does not look straight, even when not moving. You can see proof of this here :
    Thanks for the help.
     
  9. Peeling

    Peeling

    Joined:
    Nov 10, 2013
    Posts:
    404
    It's an optical illiusion caused by the perspective and varying visual size of the bulletholes.See what happens if I put a green dot in the middle of each:
    upload_2022-5-17_0-21-42.png

    To convince yourself, replace the black circle quad with a 0.1 scale black sphere - ideally with a material that doesn't z-read, so that the whole of the sphere is always visible.