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

Question Add speed to bullet from Velocity Vector

Discussion in 'Scripting' started by SamSegal, May 29, 2022.

  1. SamSegal

    SamSegal

    Joined:
    May 29, 2022
    Posts:
    7
    Hi fellas,

    I've been trying to do something which seems quite simple for 3 days now.
    It's a simple project containing a space ship that flies in a 2d top down view.
    The space ship can shoot bullets from the tip of the ship.
    All I want to do is to add the relative velocity of said space ship to the bullet speed.
    Such as, if the ship flies forward - the bullet speed will increase a bit.
    If the ship flies backwards (in reverse, while still shooting forwards) the bullets speed will decrease.

    This can easily be solved using RigidBody2D and AddForce methods,
    but I opted to avoid using rigidbody for the ship's bullets - since I check between each frame
    if a bullet hits anything using a linecast, anyways, and to avoid dynamic objects knockback effect from the bullets.

    The way the bullet 'flies' is by this line in the update method:
    Vector2 NextPosition = transform.position + transform.rotation * Vector2.up * TravelSpeed;

    Very simple, current position, added it's fixed Travel Speed in the "up" direction which is matched to the rotation.

    I need to somehow to convert the Vector2D velocity the ship has to increase or decrease the bullet speed - again, based on the rotation difference between them. If the velocity has the same direction of the rotation - bullet speed increased. If velocity has 90 degrees to the rotation, bullet speed is not changed. and 180 decreases the bullet speed.


    Bullet always shoots in front of the ship, But the ship can move sideways and backwards.

    Currently, the ship will hit the bullets it shoots (and I'm happy with both ships and bullet speeds).
    Any help? I'm surely missing something here.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,954
    I don't even know what all is going on there, but this is super simple.

    If you have a Rigidbody2D on the ship:

    Code (csharp):
    1. Rigidbody2D shipRB;
    And you want to shoot a bullet in a direction of the ship's "UP" vector:

    Code (csharp):
    1. Vector3 bulletVelocity = shipRB.transform.up * BulletSpeed;
    That's it.

    If you want to add in a fraction of the ship's speed:

    Code (csharp):
    1. bulletVelocity += shipRB.velocity * ShipVelocityFractionToAdd;
    You might want to make
    ShipVelocityFractionToAdd
    equal to 1.0, or perhaps something more or less.
     
    SamSegal likes this.
  3. SamSegal

    SamSegal

    Joined:
    May 29, 2022
    Posts:
    7
    Thanks for replying so soon!

    This works for specific movement (ex. only moving forward). If the ship flies forward and strafes to either side, the bullets will also strafe instead of shoot forward with the ship.
    Something similar happens when the ship rotates (it can rotate, too)

    At the Start method of the bullet, the ONLY speed it should have is transform.up (which is parallel to shipRB.transform.up). Simply adding the ship velocity gives it speed in left or right direction, too, which is unwanted.

    What I want to accomplish is for that only UP speed to be increased or decreased based only on 1 thing:
    The ships velocity Forwards or Backwards, where Forwards it shipRB.transform.up (the direction the ship is pointing to).

    Consider this illustration:



    These are the simple cases, but if we solve those then combination of those should work, too.

    So far I tried using MathF.Cos on Vector2.Angle between the ship's velocity and the ship's rotation, but it did not work.
    I figured if both vectors had the same direction, the angle between them will be 0 degrees and so cos of that will be 1, and if the angle is 90 (i.e the ship looks up but strafes right) then cos will give 0 which won't add speed to the bullet.

    btw I know the work is done in Radians and not degrees, I use degrees here to simplify the scenario.

    The rotation vector could just be the rotation quaternion multiplied by vector.one I believe.

    If I have still failed to describe what I want to accomplish, let me know and I'll try to make a video demonstrating the current result vs. the required result.
     
  4. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    530

    Using cosine to calculate projection of speed in required direction sounds about right. Which means that either you have a mistake in your code executing this idea (incorrect API usage, reading velocity or direction from wrong place, not adding or adding something unnecessary in the forumula), or there is one more aspect that needs to taken into account. Try printing the intermediate values to console to make sure inputs and calculations are producing the thing you expect.

    Slightly more elegant approach for achieving the same thing would be to instead of going vectors -> angle -> vector to use the dot product for projecting velocity vector on forward vector. It doesn't matter in this case, but in general the trigonometry functions for calculating angle between vectors or sin/cos from angle are relatively expensive. Compared to that dot and cross product consists of only few multiplications and additions. Thinking in angles is more intuitive at first, but in many cases a lot of cases angle calculations can be avoided by appropriate dot and cross product usage.
     
    Kurt-Dekker and SamSegal like this.
  5. SamSegal

    SamSegal

    Joined:
    May 29, 2022
    Posts:
    7
    Brilliant! This is exactly what I was looking for! Thank you very much.
    Sadly, my limited academic experience did not cover this dot product between 2 vectors (or I might've missed it).
    Just taking that dot product and dividing it by a constant number to normalize it and it works great!

    You helped out a lot!
     
  6. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    530
    If I didn't make any math mistakes all 4 following versions should produce same result. haven't actually compiled so there might be some mixup of 2d and 3d vectors coming from some of Unity APIs. But those should be easy to resolve.

    Code (CSharp):
    1.  
    2. // ----------- 1 using cosine
    3. float angle = Vector2.Angle(transform.forward, shipVelocity);
    4. k = Mathf.cos(angle * Mathf.Deg2Rad)
    5. Vector2 extraVelocity = k *  transform.forward * shipVelocity.magnitude;
    6.  
    7. // ----------- 2 using dot
    8. float k = Vector2.dot(transform.forward, shipVelocity) / shipVelocity.magnitude;
    9. Vector2 extraVelocity = k *  transform.forward * shipVelocity.magnitude;
    10.  
    11. // ----------- 3 Unity has builtin properties for getting normalized vector
    12. float k = Vector2.dot(transform.forward, shipVelocity.normalized);
    13. Vector2 extraVelocity = k * transform.forward * shipVelocity.magnitude;
    14. // ----------- or even this. No need to normalize/divide by magnitude if you are going to multiply it back afterwards
    15. Vector2 extraVelocity = Vector2.dot(transform.forward, shipVelocity) * transform.forward;
    16.  
    The last version has additional benefit that it works correctly even when velocity is 0. First versions might need some if to check for velocity 0, because angle if one of the vectors is 0 is not well defined, and so is dividing by 0 needed for normalization.
     
    Last edited: May 30, 2022
  7. SamSegal

    SamSegal

    Joined:
    May 29, 2022
    Posts:
    7
    I ended up using
    Code (CSharp):
    1.         //PositionOffset will move the bullet in a fixed speed, considering the Ship Velocity too.
    2.         PositionOffset = transform.rotation * Vector2.up *
    3.                          (TravelSpeed + Vector2.Dot(ShipBody.velocity, ShipBody.transform.rotation * Vector2.one) /
    4.                          ShipVelocityDivider);
    Seems to be working fine, for every angle. Thanks for the help.
     
  8. markelrayes

    markelrayes

    Joined:
    Apr 15, 2023
    Posts:
    1
    Hey Sam,

    Do you mind sharing the whole code for this section? I have been struggling with the exact same problem you are having and I don't understand how you solved it.