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. Dismiss Notice

Tough rotations problem. Not really sure where to even start.

Discussion in 'Scripting' started by Not_Sure, Oct 30, 2021.

  1. Not_Sure

    Not_Sure

    Joined:
    Dec 13, 2011
    Posts:
    3,541
    I'm wanting to apply forward velocity to projectiles in an FPS relative to the velocity of the player ONLY in that direction.

    Make sense?

    So if the player is moving at 1 mps on x and 1 mps on y (so 1.4 mps total) and they fire a rocket straigh along x I want to add 1 mps to the rocket, but if the rocket is shot straight forward to the players movement I want the rocket to add 1.4 mps.

    The reason I want to do this is to 1) make sure the player cant shoot themselves no matter how fast they are going and 2) give players bonus damage as a reward for moving fast.

    Any advice?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    Technically speaking if you are going 1.4m/s in any direction and fire the rocket in ANY direction, the relative velocities are always simply added together.

    In the case of your example above, if you were going 1.4 northeast and the rocket is fired at 10m/s to the right (on x), it would be going 11 on x and 1 on the y... that's how physics frames of reference work.

    If you want alternate behavior that cancels non-axial motion out, keep in mind that isn't how real physics work, but you can achieve this by projecting your movement vector onto the proposed initial rocket direction. Vector3.Project() can help you with this.

    You probably want to just use layers for this and inhibit checking between the player and player projectile layers. See the physics collision matrix for how to do this.
     
    Not_Sure likes this.
  3. Not_Sure

    Not_Sure

    Joined:
    Dec 13, 2011
    Posts:
    3,541
    Yeah, I know it's not true to physics, I'm really just wanting to make it game-a-fide.

    I do love me some Tribes, but it's not the experience I'm attempting to make.

    And I know I can tweak the layers, but I also don't want to shoot a rocket, then have it go backwards relative to the player.

    I am unfamiliar with Vector3.Project(), I'll give it a looksie.

    Thanks again Kurt! Always a big help!
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    If the player is moving at a constant speed and launches the rocket at a relative constant speed away, the rocket will ALWAYS go away from the player, unless either:

    - the rocket slows down

    - the player speeds up.

    The latter can happen if you shoot the rocket standing still, then run after it. Fun player run speeds often exceed game rocket flight speeds, as unrealistic as that is.

    In reality, rockets generally gather speed as they go, until the boost motor runs out.

    But a lot of games have them travel at constant speed after launch, since it's easier to lead targets that way.

    This isn't a huge stretch since most man-portable or crew-served rockets are "blasted" out of the launcher by a super-short boost charge that burns out before the nozzle of the rocket leaves the tube, to avoid scorching your face skin off.

    But almost all rockets then ignite the main boost motor as soon as the weapon is downrange enough to avoid blasting you with flame.

    So it is pop, coast, whoosh, coast on wings to target usually. The main motors usually only burn for a second or three, then it coasts.
     
    Not_Sure likes this.
  5. Not_Sure

    Not_Sure

    Joined:
    Dec 13, 2011
    Posts:
    3,541
    Yeah, but I'm thinking more Quake than CoD.

    I'm not wanting to just add the player's velocity because I dont want to bog down gameplay by forcing the player to account for drift in aiming.
     
  6. ubbelito

    ubbelito

    Joined:
    Sep 24, 2018
    Posts:
    23
    You can use something like the code below. This will allow negative speed (so a player backing up would fire slower projectiles than one running forward). No effect from running sideways relative to the aim direction.

    Code (CSharp):
    1. static Vector3 ComputeProjectileVelocity(Vector3 aimDirection, float projectileVelocity, Vector3 playerVelocity)
    2. {
    3.     return aimDirection.normalized * projectileVelocity + Vector3.Project(playerVelocity, aimDirection);
    4. }
     
    Not_Sure likes this.
  7. Not_Sure

    Not_Sure

    Joined:
    Dec 13, 2011
    Posts:
    3,541
    This is a slight problem for me. I'm definitely wanting to only apply it if it's positive.
     
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    Dot the velocity with your rocket forward vector, if the dot is negative, use Vector3.zero instead of your velocity.

    https://docs.unity3d.com/ScriptReference/Vector3.Dot.html
     
    Not_Sure likes this.
  9. Not_Sure

    Not_Sure

    Joined:
    Dec 13, 2011
    Posts:
    3,541
    Dang, I guess I need to study up on my Vector3's. Thanks guys!
     
    Kurt-Dekker likes this.
  10. Not_Sure

    Not_Sure

    Joined:
    Dec 13, 2011
    Posts:
    3,541
    I'm sorry, I'm still struggling with this. It doesn't seem to be applying.

    Here's what I wrote:

    Code (CSharp):
    1.     void Awake()
    2.     {
    3.         if (player == null)
    4.         {
    5.             player = GameObject.Find("Player");
    6.             playerRigidbody = player.GetComponent<Rigidbody>();
    7.             playerCamera = GameObject.Find("/Player/Neck/Camera");
    8.         }
    9.         startPoint = transform.position;
    10.         drift = Vector3.Project(playerRigidbody.velocity, playerCamera.transform.eulerAngles);
    11.     }
    Drift is added on the movement update.

    Code (CSharp):
    1. transform.position += (((transform.forward * velocity) + drift) * Time.deltaTime);
     
    Last edited: Oct 31, 2021
  11. ubbelito

    ubbelito

    Joined:
    Sep 24, 2018
    Posts:
    23
    I think you want to assign drift as

    Code (csharp):
    1. drift = Vector3.Project(playerRigidbody.velocity, playerCamera.transform.forward);
    2. if (Vector3.Dot(playerRigidbody.velocity, playerCamera.transform.forward) < 0) drift = Vector3.zero;
     
    Not_Sure likes this.
  12. Not_Sure

    Not_Sure

    Joined:
    Dec 13, 2011
    Posts:
    3,541
    It doesn't seem to be consistently adding the drift, and I'm still out running my bullets still when I get up to 50 mps.

    Here's my whole code.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Projectile : MonoBehaviour
    6. {
    7.     public bool instant;
    8.  
    9.     public float initialJump;
    10.     public float velocity;
    11.     public float range;
    12.     public float dropOffRange;
    13.  
    14.     public float damage;
    15.     public float bonusSpeed;
    16.  
    17.     Vector3 drift;
    18.  
    19.     Vector3 startPoint;
    20.     Vector3 lastPoint;
    21.  
    22.     GameObject player;
    23.     Rigidbody playerRigidbody;
    24.     GameObject playerCamera;
    25.     Vector3 playerAimDirection;
    26.  
    27.     // Start is called before the first frame update
    28.     private void Start()
    29.     {
    30.     }
    31.  
    32.     void Awake()
    33.     {
    34.         if (player == null)
    35.         {
    36.             player = GameObject.Find("Player");
    37.             playerRigidbody = player.GetComponent<Rigidbody>();
    38.             playerCamera = GameObject.Find("/Player/Neck/Camera");
    39.         }
    40.         startPoint = transform.position;
    41.         drift = Vector3.Project(playerRigidbody.velocity, playerCamera.transform.forward);
    42.         //if (Vector3.Dot(playerRigidbody.velocity, playerCamera.transform.forward) < 0) drift = Vector3.zero;
    43.     }
    44.  
    45.     private void OnEnable()
    46.     {
    47.         startPoint = transform.position;
    48.     }
    49.  
    50.     // Update is called once per frame
    51.     void Update()
    52.     {
    53.        
    54.         if(!instant){
    55.             transform.position += (((transform.forward * velocity) + drift) * Time.deltaTime);
    56.         } else {
    57.            
    58.         }
    59.  
    60.         if (Vector3.Distance(startPoint, transform.position) > range)
    61.         {
    62.             gameObject.SetActive(false);
    63.         }
    64.         lastPoint = transform.position;
    65.     }
    66.     /*public Vector3 ComputeProjectileVelocity(Vector3 aimDirection, float projectileVelocity, Vector3 playerVelocity)
    67.     {
    68.         return aimDirection.normalized * projectileVelocity + Vector3.Project(playerVelocity, aimDirection);
    69.     }*/
    70. }
    71.  
     
  13. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    If your player can accelerate to a higher speed than the rocket AFTER the rocket launch, this will always be true.

    Is that what is happening?
     
  14. Not_Sure

    Not_Sure

    Joined:
    Dec 13, 2011
    Posts:
    3,541
    It looks like I'm going faster than my bullets immediately. They start off not going my speed.
     
  15. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    You don't have to rely on this. We have
    Debug.Log()
    technology at your fingertips.
     
  16. ubbelito

    ubbelito

    Joined:
    Sep 24, 2018
    Posts:
    23
    One obvious issue with the solution is that bullets fired by a stationary player will have drift = 0, so the player can then start running and outrun (possibly? how fast is the player?) the bullets.

    If a running player does not transfer speed to the bullets, you should examine the value of drift.
    Code (csharp):
    1. Debug.Log
    as @Kurt-Dekker proposes is a really good suggestion for this.

    Example:
    Code (csharp):
    1. Debug.Log($"{playerRigidbody.velocity} {playerCamera.transform.forward} {drift}");
     
  17. Not_Sure

    Not_Sure

    Joined:
    Dec 13, 2011
    Posts:
    3,541
    I will have to take a break for now so I can do some work work. Thanks for your help guys, I’ll re-post when I can circle back around to it.

    oh, and my player has the potential of going somewhere around 350 m/s. Lol. Otherwise known as the speed of sound.

    but that’s only with the grappling hook, running is about 15 and Bunny hopping is about 20.
     
  18. Not_Sure

    Not_Sure

    Joined:
    Dec 13, 2011
    Posts:
    3,541
    Well it just occurred to me that using rigidbody.velocity is out of the question because how I made my character controller.

    I'm going to need to track the player's movement independently and use that.
     
  19. Not_Sure

    Not_Sure

    Joined:
    Dec 13, 2011
    Posts:
    3,541
    Needed to step away from it, but I got it.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class TestGun : MonoBehaviour
    6. {
    7.     public bool automatic;
    8.     public bool clip;
    9.     bool canFire;
    10.  
    11.     public GameObject shot;
    12.     public float accuracy;
    13.     public float accuracyRecovery;
    14.     float curretAccuaracy;
    15.     Vector3 drift;
    16.     public float delay;
    17.     public float clipSize;
    18.     public float reloadTime;
    19.  
    20.     public List<GameObject> ammoPool;
    21.     public int initialPool;
    22.     GameObject playerCamera;
    23.  
    24.     public int bulletCount;
    25.  
    26.     Vector3 position;
    27.  
    28.     // Start is called before the first frame update
    29.     void Start()
    30.     {
    31.         playerCamera = GameObject.Find("/Player/Neck/Camera");
    32.         canFire = true;
    33.         ammoPool = new List<GameObject>();
    34.         GameObject tmp;
    35.         position = transform.position;
    36.         bulletCount = initialPool;
    37.         for (int i = 0; i < initialPool; i++)
    38.         {
    39.             tmp = Instantiate(shot);
    40.             tmp.SetActive(false);
    41.             ammoPool.Add(tmp);
    42.         }
    43.     }
    44.  
    45.     // Update is called once per frame
    46.     void Update()
    47.     {
    48.         if (Input.GetButton("PrimaryFire") && canFire && automatic)
    49.         {
    50.             Fire();
    51.         }
    52.  
    53.         if (Input.GetButtonDown("PrimaryFire") && canFire && !automatic)
    54.         {
    55.             Fire();
    56.         }
    57.         position = transform.position;
    58.     }
    59.  
    60.     public GameObject PullFromPool() {
    61.         GameObject tmp;
    62.         for (int i = 0; i < ammoPool.Count; i++){
    63.             if (!ammoPool[i].activeInHierarchy) return ammoPool[i];
    64.             if (i == ammoPool.Count - 1)
    65.             {
    66.                 tmp = Instantiate(shot);
    67.                 ammoPool.Add(tmp);
    68.                 bulletCount += 1;
    69.                 return ammoPool[ammoPool.Count - 1];
    70.             }
    71.         }
    72.         return null;
    73.     }
    74.  
    75.     void CanFire() { canFire = true; }
    76.  
    77.     void Fire()
    78.     {
    79.         drift = (transform.position - position) * (1 / Time.deltaTime);
    80.         GameObject tempBullet;
    81.         tempBullet = PullFromPool();
    82.         tempBullet.transform.rotation = /*playerCamera.*/transform.rotation;
    83.         tempBullet.transform.position = /*playerCamera.*/transform.position;
    84.         Projectile myProjectile = tempBullet.GetComponent<Projectile>();
    85.         drift = Vector3.Project(drift, transform.forward);
    86.         if (Vector3.Dot(drift, playerCamera.transform.forward) < 0) drift = Vector3.zero;
    87.         myProjectile.drift = drift;
    88.         tempBullet.SetActive(true);
    89.         canFire = false;
    90.         Invoke("CanFire", delay);
    91.     }
    92. }
    93.  
    Thanks again!

    Now I need to make it frame independent. I’m only able to shoot as fast as the frames per second, but I’ll get it.
     
    Last edited: Nov 1, 2021