Search Unity

Rifle Accuracy w/ transform.Rotate

Discussion in 'Scripting' started by DayyanSisson, Nov 21, 2011.

  1. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    I'm trying to make my rifle less accurate if the person is looking down a scope, and obviously more accurate when the player looks down the sights. I've been searching all over the forums and Unity Answers for a solution to this like FPS Gun Accuracy Gun Accuracy with Random Range (which unfortunately are in JavaScript), but nothing I've tried has worked, or has gotten errors. The bullet has a script attached to it, controlling it's speed and other non-relevant information, and, it's rotation is based off the gun's shootpoint's rotation. I was thinking that I could change accuracy by changing the shootpoint's rotation very slightly ever time the player fires a bullet, making each bullet have a slightly different rotation. When the player looks down the sights, the amount the rotation changes is lowered, therefore making it more accurate. It should work, but I have no idea how to change the shootpoint's rotation. I thought the that I would have it's rotation in update, and then add a random range to it like this :
    Code (csharp):
    1.  
    2. accuracyModifier = Random.Range(minAccuracy, maxAccuracy);
    3. primarySP.rotation = Quaternion(1 + accuracyModifier, 1 + accuracyModifier, 1 + accuracyModifier);
    But, that wouldn't work, because the rotation wouldn't always be 1, so I'm absolutely confused. I can't change the direction of the bullet because it's controlled by another script. Here's the script I use on the rifle (doesn't have accuracy modifiers) :

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. [ExecuteInEditMode]
    5. [AddComponentMenu("Void Runners/Weapons/Guns/Assault Rifle")]
    6.  
    7. public class AssaultRifle : MonoBehaviour {
    8.  
    9.     public bool on = true;
    10.  
    11.     public string rifle;
    12.  
    13.     public float fireRate = 0.2F;
    14.     public int clips = 5;
    15.     public int roundsPerClip = 30;
    16.     static public int clipsLeft;
    17.     static public int roundsInClip;
    18.  
    19.     public GameObject round;
    20.     //public AudioClip shot;
    21.  
    22.     private Transform primarySP;
    23.     private Transform gun;
    24.  
    25.     private float nextFire = 0.0F;
    26.  
    27.     private bool reloading = false;
    28.     private float bulletSpeed;
    29.  
    30.     void Awake () {
    31.  
    32.        if(!on) return;
    33.  
    34.        gun = transform;
    35.        primarySP = gun.Find("PSP");
    36.        rifle = gun.name;
    37.     }
    38.  
    39.     void Start () {
    40.  
    41.     clipsLeft = clips;
    42.     roundsInClip = roundsPerClip;
    43.     }
    44.  
    45.     void Update () {
    46.  
    47.        if(!on) return;
    48.  
    49.        bool hasFiredPrimary = false;
    50.        bool canFire = clipsLeft >= 0;
    51.        reloading = false;
    52.  
    53.        if(clipsLeft <= 0){
    54.          clipsLeft = 0;
    55.        }
    56.  
    57.        if(Input.GetMouseButton(0)  Time.time > nextFire  canFire  roundsInClip > 0){
    58.         nextFire = Time.time + fireRate;
    59.         hasFiredPrimary = true;
    60.         Instantiate(round, primarySP.position, primarySP.rotation);
    61.          //animation.Play("Firing");
    62.          //audio.PlayOneShot(shot);
    63.     }
    64.  
    65.      if(hasFiredPrimary){
    66.          roundsInClip--;
    67.      }
    68.  
    69.        if(roundsInClip == 0  clipsLeft > 0){
    70.          reloading = true;
    71.          Invoke("ReloadAmmo", 3);
    72.          //animation.Play("Reload");
    73.        }
    74.     }
    75.  
    76.     void ReloadAmmo () {
    77.  
    78.     roundsInClip = roundsPerClip;
    79.     if(reloading){
    80.     clipsLeft --;
    81.     }
    82.     }
    83.  
    84.     void OnTriggerEnter (Collider collider) {
    85.  
    86.        if(collider.CompareTag(rifle)){
    87.          roundsInClip += 15;
    88.          clipsLeft += 0;
    89.        }
    90.     }
    91. }
    I wasn't sure how to implement my strategy, and since everything I tried didn't work, I posted the clean version of the script.

    Edit

    Okay, I made some progress regarding this. I used transform.Rotate, to rotate to shootpoint, but the problem is that it rotates, but then it doesn't go back to it's original rotation. How should I do that? Here's the script modifications :

    Code (csharp):
    1. if(Input.GetMouseButton(0)  Time.time > nextFire  canFire){
    2.                nextFire = Time.time + fireRate;
    3.                hasFiredPrimary = true;
    4.                Instantiate(round, primarySP.position, primarySP.rotation);
    5.           AccuracyModifier();
    6.           animation.Play("Firing");
    7.           audio.PlayOneShot(shot);
    8.            }
    And later on...

    Code (csharp):
    1. void AccuracyModifier () {
    2.  
    3.        float x = Random.Range(minAccuracy, maxAccuracy);
    4.        float y = Random.Range(minAccuracy, maxAccuracy);
    5.        float z = Random.Range(minAccuracy, maxAccuracy);
    6.  
    7.        primarySP.Rotate(x,y,z);
    8.     }
    I have no idea how to set it back to it's original rotation. I can't set it's original rotation using the Start void because it takes the starting rotation. I know that in-between each shot, I want the rotation to go back the way it was based on how it would be before AccuracyModifier() took place.
     
  2. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    A simple solution (I don't have Unity with me currently, so no freebie code for you, sorry) is to have information passed to the projectile when you instantiate it. Eg, it's muzzlevelocity, that, contains it's velocity as well as it's heading (using the power of vectors).

    So, inside your bullet, you'll have it's muzzle velocity (a Vector3 that, when the bullet is instantiated, is passed it's velocity vector), where, on update, is having it's muzzlevelocity added to it's transform.position * time.deltatime. <- this will make the projectile move in the direction it was shot and have a constant velocity in that direction.

    With the rifle, you'll want to get the rifle's forward vector (aka, the direction I assume the rifle is facing) and then you simply add the AccuracyModifier() result to the muzzlevelocity, which, will cause it to have a "spread".

    ^ Doing the above, means you have nothing permanently rotated, so thus, no need to reset the object's rotation again.

    It's a bit much of a read, but tomorrow (in 12 hours or so) I'll be able to answer any questions you have. Just be sure to reply to this post so the email in my inbox reminds me.

    Good luck!

    p.s the AccuracyModifier function needs to be in the rifle, not the bullet, and needs to return a vector3 containing those 3 values.
     
  3. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    So the rifle, when instantiating the bullet, has to give the bullet it's velocity. I tried doing that in my code. For instance, I made this :

    Code (csharp):
    1. bullet = Instantiate(round, primarySP.position, primarySP.rotation) as Transform;
    2.  
    3. bullet.Translate(Vector3.forward * speed);
    Just to make it move, and it says the referenced object is not set to an instance of an object. Which means I can't do it. So I'm not sure how to do that.:confused:
     
  4. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    Just so you know, I'm working on a solution for you right now.
     
  5. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    Okay, I've created two scripts for you that you can do with what you like.

    This is the weapon script. it fires a prefab projectile and is simpler than the projectile's script because it doesn't have to account for much, just spread.

    PHP:
    using UnityEngine;
    using System.Collections;

    /// <summary>
    /// created by Markus Davey 22/11/2011
    /// Basic weapon script
    /// Skype: Markus.Davey
    /// Unity forums: MarkusDavey
    /// </summary>


    public class weaponScript MonoBehaviour 
    {
        
    // public
        
    public float projMuzzleVelocity// in metres per second
        
    public GameObject projPrefab;
        public 
    float RateOfFire;
        public 
    float Inaccuracy;
        
        
    // private
        
    private float fireTimer;
        
        
    // Use this for initialization
        
    void Start () 
        {
            
    fireTimer Time.time RateOfFire;
        }
        
        
    // Update is called once per frame
        
    void Update () 
        {
            
    Debug.DrawLine(transform.positiontransform.position transform.forwardColor.red);
            if (
    Time.time fireTimer)
            {
                
    GameObject projectile;
                
    Vector3 muzzlevelocity transform.forward;
                
                if (
    Inaccuracy != 0)
                {
                    
    Vector2 rand Random.insideUnitCircle;
                    
    muzzlevelocity += new Vector3(rand.xrand.y0) * Inaccuracy;
                }
                
                
    muzzlevelocity muzzlevelocity.normalized projMuzzleVelocity;
                
                
    projectile Instantiate(projPrefabtransform.positiontransform.rotation) as GameObject;
                
    projectile.GetComponent<projectileScript>().muzzleVelocity muzzlevelocity;
                
    fireTimer Time.time RateOfFire;
            }
            else
                return;
        }
    }
    and the projectile script that has a few fancy things in there for some on-a-whim experimentation I had when I made it. The script can account for gravity by setting "isBallistic" to true, as well as accounting for drag. The drag value is how many metres per second would the projectile lose, per second, so use a small, positive number for that.

    PHP:
    using UnityEngine;
    using System.Collections;

    /// <summary>
    /// created by Markus Davey 22/11/2011
    /// Basic projectile script
    /// Skype: Markus.Davey
    /// Unity forums: MarkusDavey
    /// </summary>

    public class projectileScript MonoBehaviour 
    {
        public 
    Vector3 muzzleVelocity;
        
        public 
    float TTL;
        
        public 
    bool isBallistic;
        public 
    float Drag// in metres/s lost per second.
        
        // Use this for initialization
        
    void Start () 
        {
            if (
    TTL == 0)
                
    TTL 5;
            print(
    TTL);
            
    Invoke("projectileTimeout"TTL);
        }
        
        
    // Update is called once per frame
        
    void Update () 
        {
            if (
    Drag != 0)
                
    muzzleVelocity += muzzleVelocity * (-Drag Time.deltaTime);
            
            if (
    isBallistic)
                
    muzzleVelocity += Physics.gravity Time.deltaTime;
            
            if (
    muzzleVelocity == Vector3.zero)
                return;
            else
                
    transform.position += muzzleVelocity Time.deltaTime;
            
    transform.LookAt(transform.position muzzleVelocity.normalized);
            
    Debug.DrawLine(transform.positiontransform.position muzzleVelocity.normalizedColor.red);
        }
        
        
    void projectileTimeout()
        {
            
    DestroyObject(gameObject);
        }
        
    }
    Hope this solves your problem.

    p.s The spread value has no real sense of measurement, just put in values as you see fit.

    p.p.s The projectile script has no collision detection.
     
  6. UnLogick

    UnLogick

    Joined:
    Jun 11, 2011
    Posts:
    1,745
  7. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    I don't have access to Unity at the moment, and I really appreciate you doing this for me. I can fix the projectile collision problem and that's fine. As I'm going to be integrating your code with mine so it works as I like it, how should I give you credit? Since I'm going to edit the projectile script to my needs, and the weapon script being integrated into my code, the split between is going to be half and half. Would you like to get credit for the script? (By you putting up this script, it's technically public domain. So if you want it to be private just PM me.) I'll post here if it doesn't work.

    Edit, didn't see that it got on the wiki..... nevermind.
     
  8. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    I'm willing to improve upon the weapon script, by adding a reload function, and by optimizing it. I can even add a grenade launcher part to it. As for the projectile script, I can add collision, and I can optimize it further and you can post that on the wiki.
     
  9. All_American

    All_American

    Joined:
    Oct 14, 2011
    Posts:
    1,528
    You would want the accuracy to be better whilst looking through the scope not the ironsights. When your aiming with either you should use a breath function.
     
  10. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    If I put it on the wiki, chances are that it will be beginners taking the script, so it's better that we don't give them a complete shooting script, so that they have room to learn. As for things like iron sights vs. scopes, we can make it that if they have iron sights, they accuracy is increased if using them, but if they have a scope, it's increased even further. I'll work on that.
     
  11. sacredgeometry

    sacredgeometry

    Joined:
    Dec 5, 2009
    Posts:
    55
    I asked this in your answers thread but didnt get a response , so I will ask again. Its purely from curiousity. Are you using collisions/instances to determine hit information? I only ask because if you endeavour to create realistic guns this is not the best or most efficient way of doing this.

    If the bullets approach enough of a speed they could completely skip over the targets collider providing a non hit on a dead hit in terms of accuracy.
     
  12. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    Glad to be of service. Be sure to ask me if you have any questions.
     
  13. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    I actually realize this (sorry I didn't answer on UnityAnswers). I suppose raycasting would work to check hit info. Also, there's a rigidbody on the bullet, so we can set to collision detection to Continuous, or to Continuous Dynamic.
     
  14. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    There's no point in doing this, raycasting ahead of the projectile is the ONLY way to do it, because it's lighter, and simpler.
     
  15. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    Here's the projectile with collision. It's been slightly optimized :

    PHP:
    /// <summary>
    /// created by Markus Davey 22/11/2011
    /// Basic projectile script
    /// Skype: Markus.Davey
    /// Unity forums: MarkusDavey
    /// </summary>

    /// <summary>
    /// Dayyan Sisson 23/11/2011
    /// Projectile Script w/ Collision
    /// Unity Forums : nighthawx349
    /// Unity Answers : nighthawx349
    /// </summary>

    [RequireComponent(typeof(Rigidbody))]

    public class 
    Projectile MonoBehaviour 
    {
        public 
    Vector3 muzzleVelocity;
        
        public 
    float TTL;
        
        public 
    bool isBallistic;
        public 
    float Drag;
        
        public 
    GameObject dirtHit;
        public 
    GameObject woodHit;
        public 
    GameObject waterHit;
        public 
    GameObject metalHit;
        public 
    GameObject concreteHit;
        public 
    GameObject enemyHit;
        
        public 
    int damage 10;
        
        private 
    Transform bullet;
        
        public 
    string enemy;
        
        
    void Awake () {
            
            
    bullet transform;
        }
        
        
    void Start () 
        {
            if (
    TTL == 0)
                
    TTL 2;
            
    Invoke("ProjectileTimeout"TTL);
        }
        
        
    void Update () 
        {
            if (
    Drag != 0)
                
    muzzleVelocity += muzzleVelocity * (-Drag Time.deltaTime);
            
            if (
    isBallistic)
                
    muzzleVelocity += Physics.gravity Time.deltaTime;
            
            if (
    muzzleVelocity == Vector3.zero)
                return;
            else
                
    bullet.position += muzzleVelocity Time.deltaTime;
            
    bullet.LookAt(bullet.position muzzleVelocity.normalized);
            
    Debug.DrawLine(bullet.positionbullet.position muzzleVelocity.normalizedColor.red);
        }
        
        
    void ProjectileTimeout()
        {
            
    DestroyObject(gameObject);
        }
        
        
    void OnCollisionEnter (Collision collision) {
            
            if(
    collision.gameObject.CompareTag("Dirt")){
        
    Instantiate(dirtHittransform.positiontransform.rotation);
        }
            if(
    collision.gameObject.CompareTag("Wood")){
        
    Instantiate(woodHittransform.positiontransform.rotation);
        }
            if(
    collision.gameObject.CompareTag("Water")){
        
    Instantiate(waterHittransform.positiontransform.rotation);
        }
            if(
    collision.gameObject.CompareTag("Metal")){
        
    Instantiate(metalHittransform.positiontransform.rotation);
        }
            if(
    collision.gameObject.CompareTag("Concrete")){
        
    Instantiate(concreteHittransform.positiontransform.rotation);
        }
            
            if(
    collision.gameObject.CompareTag(enemy)){
        
    collision.collider.gameObject.SendMessage("ApplyDamage"damageSendMessageOptions.DontRequireReceiver);
        
    Instantiate(enemyHittransform.positiontransform.rotation);
        }
            
    Destroy(gameObject);
        }
        
    }  
    You can update this on the wiki so it has the updated version. If there are any problems you see, just post on this thread.
     
  16. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    As opposed to using collision detection w/ rigidbody, or colliders in general? As for being simpler, you would have to set up the raycast, set up a bool to check if it hit something, and then if the bool is true, instantiate sparks (if hit metal). It would also have to check the tag of what it hit. As for collision, it just has to check for the tag.
     
    Last edited: Nov 23, 2011
  17. sacredgeometry

    sacredgeometry

    Joined:
    Dec 5, 2009
    Posts:
    55
    Im lost, what difference would that be if there is no collision detected whatsoever?

    For collision detection on a projectile to work I think you would either need a particularly large (ideally volumetric) collision detection method or would have to use raycasting on the projectile as stated and that would mean less accurate hits without some seriously convoluted code to sort it out. This is true because it still suffers the same problem as just using a collider in that the source (i.e. projectile) essentially teleporting through the target.
     
  18. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    That's not what this thread says. Apparently raycasting can take the place of collision detection but unfortunately, I feel that would slow down the computer. Let's say you have 30 AI's on each side, and every frame they fire one bullet. After two frames, there are 60 raycasts, and after three there 90, and after 10 frames, you have 300 raycasts. I think that would make a huge performance hit. About the rigidbody though, on the same question it states that it would help.
     
  19. sacredgeometry

    sacredgeometry

    Joined:
    Dec 5, 2009
    Posts:
    55
    You wouldnt (traditionally) put raycasting on the projectiles you would put them on each player, there is no need.
     
    Last edited: Nov 23, 2011
  20. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    Are we talking about the same thing? I think I was confused by your question. If we're talking about what I'm talking about, then that raycasting technique wouldn't work for slower projectiles, or lets say, for projectiles with physics like drag and gravity applied to them. Because if you shoot, and then move your player, therefore moving your raycast, it would detect collision away from the actual point of collision.
     
  21. sacredgeometry

    sacredgeometry

    Joined:
    Dec 5, 2009
    Posts:
    55
    Im not sure, what I am saying is that the physics collision system built into unity cant handle realistic projectiles of any speed approaching a rifle. Its a simple thing to demonstrate, stick a ball (radius=1) with a ridged body onto a cube 10x1x10 now in the viewfinder rotate the cube, you will notice how little speed it takes to make the cube clip straight through the sphere. This is what is going to happen to your bullet, its going to be a matter of luck wether or not it detects the impact of your bullet. Therefor using colliders will never work, you need to use either a combination of a raycast from the players position with it or just a raycast (someone correct me if i am wrong here).

    As far as I know the best solution would be to use a little bit of projectile maths in place of the inbuilt physics solver (not sure but there might even be functions built into unity which does this for you) and instead of using a bullet prefab with a ridged body component on it, effect the transforms you get from raycastHit information.

    For example in the problem you are mentioning, you could store the data in an array of transforms so that for every bullet shot, it takes an on surface point transform, passes it through a function with effects it with various variables ie wind, bullet speed variation etc and the effects of gravity and returns a new transform which can then be used to determine wether or not it would have hit the player.

    If anyone reading this is more experienced with FPS mechanics and would like to expand or correct this then that would be amazing, i am just mainly talking from experience of other things and theorising.
     
    Last edited: Nov 23, 2011
  22. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    Okay, I totally agree with what you're saying. I kind of confused your question. I've actually had problems with this, as when I had a semi-automatic weapon and I would have an enemy that didn't move. I would fire once, and it instantiated the sparks (enemy was a bot), but without even moving the cursor, or changing anything in the scene itself, I would fire again, and it passed right through it and collided with the ground behind him. That's a problem I would need to fix. As said, anyone with knowledge of potential problems that might arise when making an FPS, or at least knows how to fix them, posting here would be appreciated.
     
  23. sacredgeometry

    sacredgeometry

    Joined:
    Dec 5, 2009
    Posts:
    55
    Considering the reason for it, its nothing you can overcome whilst relying only on collision data from colliders. This is why all for the advice i have heard on creating guns (especially realistic ones) is to use raycasting and to only use geometry if you want to see the projectile in game. Using raycasting and maths gives you much more control and options over what your game is doing and much more accuracy.

    I just wanted to make sure you understood why it was doing it, so as long as you know why then you can understand the limitations of the system and start to think of ways to work around it if none of the solutions i have mentioned appeal to you.
     
  24. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    Thanks for bringing this to my attention. Now that I think of it, I don't need to see my bullets. So as for raycasting, would I create a raycast with velocity. I've been hearing that this is better. How would I write the raycast. I know basic raycasting, but raycast bullets? That I'm not so sure of. And also, the accuracy of the bullets is based on the projectile script, and if I use raycast bullets, this system wouldn't work.

    Edit

    I'm actually now seeing the reality of the situation, and I realize that my bullets have to move twice as fast they're going. So I increased their velocity, and before, I could kill all my test enemies with more than a clip to spare, but now, I'm out of ammo and I only killed 1 enemy. I used 200 bullets to kill one enemy because almost 100 of the bullets didn't detect collision.
     
    Last edited: Nov 23, 2011
  25. sacredgeometry

    sacredgeometry

    Joined:
    Dec 5, 2009
    Posts:
    55
    You are thinking about it slightly wrongly, you wouldnt need to make a raycast bullet as such.

    Think of raycasting as determining where the gun hits. By default it will be "dead on" as if it were a laser gun, this is not what you are after so what you can do is ascertain where and if the bullet hits.

    By grabbing the transform information off the point (in RaycastHIt) you can then effect it with random movement to simulate randomness with a bias in a wind direction if applicable.

    To effect it with gravity you could grab the distance between the ray origin and the target and also the gun angle relative to the y-axis an use projectile maths. Then you could test this new transform with the target to see if it would still hit.

    http://en.wikipedia.org/wiki/Trajectory

    http://en.wikipedia.org/wiki/Trajectory_of_a_projectile
     
    Last edited: Nov 23, 2011
  26. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    As said earlier, I'm not the most advanced programmer, and I have a basic understanding of raycasts, so how would I make the rifle slightly inaccurate. Maybe changing the rotation of the raycast slightly everytime a shot is fired. Also, is it one continuous raycast that checks for collision based on fire rate, or is a new raycast casted based on fire rate? Maybe some code would help. Sorry if that's asking too much.
     
  27. sacredgeometry

    sacredgeometry

    Joined:
    Dec 5, 2009
    Posts:
    55
    you could use random.range() and add that to the x, y and z of the vector three the point data returns.
    Ill add some code now give me a sec.
     
  28. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    Another question, is this better for performance?
     
  29. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    I'm afraid I don't understand what you mean. Are you suggesting that a player be raycasting to all projectiles? Or a spherecast? I'd still say that a projectile raycasting ahead the distance it will travel in the next frame is the better solution.
     
  30. sacredgeometry

    sacredgeometry

    Joined:
    Dec 5, 2009
    Posts:
    55
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class BasicGunTargetting: MonoBehaviour {
    5.    
    6.     protected RaycastHit Hit;
    7.     public float rayLength = 25.0f;
    8.     public int randomRangeEffector = 3;
    9.    
    10.     // UPDATE
    11.     void Update () {
    12.         // Calls the Raycast every frame (Allways On)
    13.         Physics.Raycast(this.gameObject.transform.position,
    14.                                 Vector3.forward,
    15.                                 out Hit,
    16.                                 rayLength);
    17.        
    18.        
    19.         // If there is a collider hit with the ray and you press spacebar then it will print the original point position and the new effected one.
    20.         if(Hit.collider != null  Input.GetButtonDown("Jump")){
    21.             print("Original Vector3: " + Hit.point.ToString());
    22.             print("Altered Vector3: " + randomHit(Hit.point).ToString());
    23.         }
    24.        
    25.        
    26.     }
    27.    
    28.     // Takes a Vector3 effects it with a random range in the x, y and z axis and returns the effected Vector3
    29.     Vector3 randomHit(Vector3 originalVector3){            
    30.             return new Vector3(originalVector3.x + Random.Range(-randomRangeEffector, randomRangeEffector),
    31.                                 originalVector3.y + Random.Range(-randomRangeEffector, randomRangeEffector),
    32.                                 originalVector3.z + Random.Range(-randomRangeEffector, randomRangeEffector));
    33.     }
    34. }
    35.  

    Put this on a cube (without a collider) and stick another cube (with a collider) in front of it (Positive z direction).

    Hit Space bar and it will print two vectors for each hit, one will stay static (the original position) the second will be the random value which will be altered within the range set in the variable.

    To further improve this you could make it automatically takes the distance from the player to the target and multiply it to the randomRangeEffector before adding it to the final returned Vector
     
    Last edited: Nov 23, 2011
  31. sacredgeometry

    sacredgeometry

    Joined:
    Dec 5, 2009
    Posts:
    55
    No not to all projectiles just to the target (i.e. one raycast from the player to the target), your method would work but the performance hit would me massive over just calculating the trajectory from a single raycast.

    Oh and you would still suffer from the problem of accuracy.
     
    Last edited: Nov 23, 2011
  32. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    If your game has very fast projectiles, then you would raycast from where the player is to wherever it's shooting, but if you have projectiles that go at realistic speeds, you'll raycast from the projectile's centre to the point the projectile will travel to in the next frame. You don't need to calculate trajectory, because it is very doubltful that you will miss a target due to a change in pitch in the projectile.

    The performance hit on these projectiles are very minimal, because very little is being done with them. in my case, you'd do this:

    pseudocode:

    Code (csharp):
    1.  
    2. void checkcollision()
    3. {
    4.     physics.raycast(transform.position, transform.position + (transform.forward * muzzleVelocity.magnitude) * Time.deltaTime);
    5. }
    6.  
     
  33. sacredgeometry

    sacredgeometry

    Joined:
    Dec 5, 2009
    Posts:
    55
    so is the performance hit of hundreds of rays on screen minimal? Thats good to know. A realistic speed puts it at 25meters of variance per frame btw, so unless the bad guys are pretty hench its a big variance.
     
  34. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    After some simple benchmarking, I can run 1500 projectiles, what are guided onto the target at once before affecting FPS.

    If you used a realistic muzzle velocity (in this case, 786 m/s, the muzzle velocity of the M24), the raycast is 12.8 metres ahead of the projectile. The ballistic variance of the next frame will have literally no consequence unless you're shooting at a target going 1 m/s slower, then it would appear to have teleported the bullet 12.8 metres into the target the next frame, but hey, that's all relative velocities, and super complex mumbojumbo.
     
  35. sacredgeometry

    sacredgeometry

    Joined:
    Dec 5, 2009
    Posts:
    55
    http://hypertextbook.com/facts/1999/MariaPereyra.shtml

    depends on the rifle i was working with worst case scenario. Well if there is no performance hit then thats fine, I was always told it was a relatively expensive thing to do but if its not then thats all fine.

    Surely this is still FPS and bullet speed dependent, and could cause problems at lower fps and higher bullet speeds, no?
     
  36. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    in a typical online fps, projectile hit detection would be done server side, and if the server's fps is low, then yes, it may cause problems, but not like anyone would care, because everything is super laggy because the server cannot keep up.

    in singleplayer, everything is calculated on the one box, and so yes, it could be pretty bad if you were lagged out, but if you were aiming at your target and it cast well ahead of the projectile, you can just safely assume it hit that target.

    Also, to add ballistics support to the raycast, you can simply add gravity to the raycast values, thus it will account of bullet drop a little better.

    edit:

    further benchmarking: With guidance off (aka, just a normal projectile) you can have 1700 running at once before any FPS drop :)
     
    Last edited: Nov 23, 2011
  37. sacredgeometry

    sacredgeometry

    Joined:
    Dec 5, 2009
    Posts:
    55
    Maybe its just me but I don't like the idea of anything being frame rate dependent it just feels cheap if you can break elements of the core game play mechanic that easily. That said if thats as little as the performance hit is then Thats great news for the OP.

    EDIT: You could extend the ray to adjust based on the current average frame rate i guess.

    Thats really interesting, how does adding gravity to a raycasts values work inside Unity?
     
    Last edited: Nov 23, 2011
  38. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258

    Basically, you just add Physics.gravity to the forward vector.

    Also, with regards to the projectile collision checking, you want to do that (if you're using raycasts at least) before you move the projectile. So, basically, it's the very first thing you do.
     
    Last edited: Nov 23, 2011
  39. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    So as for the performance drop, how much FPS did it go down when you noticed it? I think in my case, I would probably have 1000 projectiles out there at a time, but I would still like to know the performance drop.
     
  40. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    Is there a way to calculate how far ahead to put the raycast based on speed?
     
  41. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    Actually, nevermind. I see it's in the code you posted above.
     
  42. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    Okay, so I tried using raycasts on the bullets and sometimes, I end up shooting myself. I'm not sure what the problem is here :

    Code (csharp):
    1. Physics.Raycast(bullet.position, Vector3.forward, out hit, rayLength);
    2.        
    3.         if(hit.collider.gameObject.CompareTag("Human") || hit.collider.gameObject.CompareTag("Droid")){
    4.                 hit.collider.gameObject.SendMessage("ApplyDamage", damage, SendMessageOptions.DontRequireReceiver);
    5.                 Instantiate(enemyHit, transform.position, transform.rotation);
    6.                 Destroy(gameObject);
    7.             }
    I killed myself eventually testing this (in game, don't worry), and so did my enemies. What did I do wrong here? (This is on the bullet.
     
  43. msleeper

    msleeper

    Joined:
    Feb 14, 2011
    Posts:
    86
    I don't understand why you need physical bullets at all. This would be a complete non-issue if you didn't bother with that.
     
  44. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    We need physical bullets for the accuracy script. I myself don't understand how to do it any other way. Please enlighten me.
     
  45. msleeper

    msleeper

    Joined:
    Feb 14, 2011
    Posts:
    86
    Instead of doing an Instantiate, fire a ray. If you're worried about bullet drop off or something of that nature, then don't, because 99.99999999% of games don't either. In fact unless a game goes out of it's way to say it has trajectory physics or is a bullet trajectory sim, then it doesn't care about bullet trajectory.

    As far as randomized accuracy, look into Random.Range and add it to the player's orientation. You'll need to play around with values to figure out how accurate on inaccurate you want it to be.

    EDIT
    To clarify, I mean by "add it to your player's orientation" is to fire the ray using the player's direction as the ray direction. Then add a small randomized range to that.
     
    Last edited: Nov 24, 2011
  46. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    instant firing of rays is the least realistic approach, and is uber tacky.
     
  47. msleeper

    msleeper

    Joined:
    Feb 14, 2011
    Posts:
    86
    I can't think of a single major title that does it otherwise. Anything on the Source engine, anything on UDK, anything in the id Tech engines... Half-Life, Gears of War, Rage... all of the bullets in those games use hitscan instant firing.
     
  48. MarkusDavey

    MarkusDavey

    Joined:
    Jun 3, 2011
    Posts:
    258
    I'ma stick to my projectiles thanks :)

    Larger scale games like BF3 would be using projectiles like mine.
     
    Last edited: Nov 24, 2011
  49. msleeper

    msleeper

    Joined:
    Feb 14, 2011
    Posts:
    86
    You're right, the newer Battlefield games don't use hitscan - and they suffer from severe hit registration issues when played over network.

    Do whatever works best for your situation, but shot for shot, hitscan bullets will always require less processing and lead to less issues (IE, this thread).
     
  50. DayyanSisson

    DayyanSisson

    Joined:
    Aug 4, 2011
    Posts:
    623
    I pretty much figured out how to get the raycast shooting working except for one thing. How do I instantiate lets say.... blood splatter, where the raycast hits? Here's the code I use to shoot and check collision :

    Code (csharp):
    1. if(fullAuto){
    2.             if(Input.GetMouseButton(0)  Time.time > nextFire  canFire){
    3.                 nextFire = Time.time + fireRate;
    4.                 roundsInClip--;
    5.                 Physics.Raycast(primarySP.position, gun.forward, out hit, effectiveRange);
    6.                 Debug.DrawRay(primarySP.position, gun.forward * effectiveRange, Color.red);
    7.                 animation.Play("Firing");
    8.                 audio.PlayOneShot(shot);
    9.                 CheckCollision();
    10.             }
    11.         }
    And for collision :

    Code (csharp):
    1. if(hit.collider.gameObject.CompareTag("Human") || hit.collider.gameObject.CompareTag("Droid")){
    2.                 hit.collider.gameObject.SendMessage("ApplyDamage", damage, SendMessageOptions.DontRequireReceiver);
    3.                 Instantiate(enemyHit, hit.collider.gameObject.transform.position, hit.collider.gameObject.transform.rotation);
    4.             }
    Well that works well..... almost. I can't instantiate "enemyHit" where the ray hits, it will instantiate enemyHit in the middle of whatever object it hits. So lets say I shoot the head of an enemy, the blood splatter appears in his chest. How do I instantiate the collision where the raycast hit?