Search Unity

Instantiating a projectile object in front of the player

Discussion in 'Scripting' started by pdrummond, Aug 8, 2005.

  1. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    Hi everyone,

    I'm sure this is really easy, but I've been going mad trying to get it to work. I have a top-down shooter where the player controls a spaceship. I can instantiate new projectile objects and destroy them after a few seconds so the scene doesn't fill up with unnecessary objects, but I can't get the projectile to appear directly in front of the player ship. What's the best way to specify a point 20 units in front of the player ship, whatever the rotation of the ship currently is?

    At the moment I'm instantiating the projectile at x,y,z + 20 which means it's only in front of the player ship if it's pointing straight up. I tried nesting the object which gets instantiated as the projectile inside the player object, so that it would pick up the rotation of its parent and be in the correct position when created. This worked fine but I had problems when it came to destroying the object, so had to go back to this method. In the long run I think it will be easier if the projectile objects are kept outside of the player ship, so I need to get this working.

    Any tips are much appreciated.

    Here's the main player script:

    Code (csharp):
    1.  
    2. /*Publicly declared variables.*/
    3.  
    4. /*Reference to the ship*/
    5. var theShip : Transform;
    6.  
    7. /*For movement.*/
    8. var shipMass = 0.5;
    9. var shipDrag = 1;
    10. var shipAngularDrag = 1;
    11. var targetSpeedForce = 100;
    12. var rotationSpeed = 0.1;
    13.  
    14. /*Shields and strength. Shields absorb explosions and collisions. When they reach zero the strength of the ship is used. When this reaches zero the ship is destroyed.*/
    15. var shields = 100;
    16. var strength = 50;
    17.  
    18. /*For firing.*/
    19. var mainGunProjectile : GameObject;
    20.  
    21. function Start() {
    22. /*Assign mass, drag etc. to ship.*/
    23. theShip.rigidbody.mass = shipMass;
    24. theShip.rigidbody.drag = shipDrag;
    25. theShip.rigidbody.angularDrag = shipAngularDrag;
    26. /*Freeze ship rotation so it isn't affected by physics. This makes the ship a lot easier to control.*/
    27. theShip.rigidbody.freezeRotation = true;
    28. }
    29.  
    30. function FixedUpdate() {
    31. /*If forward or back controls are used.*/
    32. if (Input.GetAxis("Vertical")) {
    33.     accelerate();
    34.     }
    35.    
    36. /*If left or right controls are used.*/
    37. //if (Input.GetAxis("Horizontal")) {
    38.     turn();
    39. //  }
    40. }
    41.  
    42. function Update() {
    43. /*Fire a projectile if the user holds the mouse button down.*/
    44. if (Input.GetMouseButton(0)) {
    45.     /*Instantiate a projectile, placing it at the correct position. This needs work.*/
    46.     var projectileOriginX = theShip.transform.position.x;
    47.     var projectileOriginY = theShip.transform.position.y;
    48.     var projectileOriginZ = theShip.transform.position.z + 20;
    49.    
    50.     var projectile : GameObject = Instantiate(mainGunProjectile, Vector3(projectileOriginX, projectileOriginY, projectileOriginZ), theShip.transform.rotation);
    51.     /*Set the projectile moving.*/
    52.     projectile.rigidbody.velocity = theShip.transform.TransformDirection (Vector3.forward * 200);
    53.     /*Destroy the projectile after the specified number of seconds. This stops the scene filling up with hundreds of projectiles and frees up resources.*/
    54.     Destroy(projectile, 2);
    55.     }
    56.  
    57. /*Keep the ship from moving up or down.*/
    58. if (theShip.transform.position.y != 0) {
    59.     theShip.transform.position.y = 0;
    60.     }
    61. }
    62.  
    63. function accelerate() {
    64. /*Use the value of the 'Vertical' virtual axis to create the 'speed' variable. This means we use the forward and back controls, getting a positive or negative value depending on which is selected. Positive if we want to go forward, negative for back.*/
    65. var speed = Input.GetAxis("Vertical");
    66. /*Create the 'theForce' variable by multiplying 'speed' * 'targetSpeedForce'. This will give us a positive or negative value we can use when add movement.*/
    67. var theForce = speed * targetSpeedForce;
    68.  
    69. /*Add forward force to the ship.*/
    70. theShip.rigidbody.AddRelativeForce(Vector3.fwd * theForce);
    71. }
    72.  
    73. function turn() {
    74. /*Get the mouse x delta and multiply it by rotationSpeed to get the rotation angle we should apply to the ship.*/
    75. var rotation = Input.GetAxis("Horizontal") * rotationSpeed;
    76.  
    77. /*Rotate the ship around the vertical axis.*/
    78. theShip.transform.RotateAround(Vector3.up, rotation);
    79. }
    80.  
     
  2. Jonathan Czeck

    Jonathan Czeck

    Joined:
    Mar 17, 2005
    Posts:
    1,713
    You want to use transform.TransformPoint(Vector3.fwd * 20) . This converts local coordinates (a vector 20 units forward of the object) to world space which you would pass to Instantiate().

    file:///Applications/Unity/Documentation/ScriptReference/Transform.html#TransformPoint

    HTH,
    -Jon
     
    CystemCV likes this.
  3. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    Excellent. It works. Thanks for that.
     
  4. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    I've got my projectile working nicely now, but it would be useful if I could make sure it picks up the forward velocity of the player ship when it's fired. Otherwise there's a chance the player could catch up with their own shots.

    I've tried getting the forward velocity of the ship (theShip.rigidbody.velocity.z), adding this to a set value, then assigning the result to the velocity of the projectile, but it doesn't seem to make any difference. No doubt I'm making a silly mistake somewhere. Can anyone help out?

    Code (csharp):
    1.  
    2. function fire() {
    3. /*Instantiate a projectile, placing it at the correct position. We use transform.TransformPoint(Vector3.fwd * 500) to convert the local coordinate 20 units in front of the ship to world space coordinates for the instantiate function.*/
    4. var projectile : GameObject = Instantiate(mainGunProjectile, theShip.transform.TransformPoint(Vector3.fwd * 400), theShip.transform.rotation);
    5. /*Set the projectile moving.*/
    6. /*Need to add ship velocity to the projectile so the player doesn't catch up with their own shots.*/
    7. var shipVelocity = theShip.rigidbody.velocity.z;
    8. var projectileVelocity = shipVelocity + 300;
    9. projectile.rigidbody.velocity = theShip.transform.TransformDirection(Vector3.forward * projectileVelocity);
    10. /*Destroy the projectile after the specified number of seconds. This stops the scene filling up with hundreds of projectiles and frees up resources.*/
    11. Destroy(projectile, 1);
    12. }
    On a related note, how can I limit the forward speed of my player ship? I borrowed code from the car demo script and got the following. It sort of works, but is rather jerky. Any tips for refining it are appreciated.

    Code (csharp):
    1.  
    2. /*If the ship is going fast give it higher drag to slow it down.*/
    3. if (theShip.rigidbody.velocity.sqrMagnitude > 500) {
    4.     theShip.rigidbody.drag = shipDragFast;
    5.     }
    6. /*Else apply normal drag.*/
    7. else {
    8.     //theShip.rigidbody.drag = shipDragSlow;
    9.     }
    10.  
     
  5. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Code (csharp):
    1.  
    2. var projectileVelocity = theShip.rigidbody.velocity;
    3. projectileVelocity += theShip.transform.TransformDirection (Vector3.fwd * 10);
    4.  
     
  6. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    Thanks for that.
     
  7. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    This is probably a dumb request, but I'm tired and finding it hard to concentrate now. :cry:

    I have an object which has a function called accelerate().

    Code (csharp):
    1.  
    2. function accelerate() {
    3. thisObject.rigidbody.AddRelativeForce(Vector3.fwd * accelerationForce);
    4. }
    5.  
    At appropriate moments I call this function to make the object shoot forward. Unfortunately it crawls along really slowly. I've made the drag and mass zero to rule them out and am a bit stumped. Is my code to make the object move wrong? If so, can anyone suggest a replacement?
     
  8. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    If you are only calling it once in a while, the acceleration period is only one physical time step.

    You will have to apply the acceleration force every physical time step in FixedUpdate as long as you want to continue the acceleration.
     
  9. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    The condition is met for a longer period than that and I'm not mixing direct translations and physics. I think I may have worked out what was wrong as I've got the object moving in a more sensible manner now.

    Thanks for all your help. No doubt I'll come up with something else to bother you with soon. :wink:
     
  10. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    Would you consider rotating an object using 'transform.RotateAround(Vector3.up, rotation)' and moving it using 'rigidbody.AddRelativeForce(Vector3.fwd * theForce)' to be mixing translation and physics behaviour? If so, what would be a better way to rotate the object using physics commands?
     
  11. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    I told you I'd think of something else to pester you with...

    How would I limit the number of projectiles the player is firing? At the moment I've set a lifetime on the instantiated projectiles so the scene doesn't fill up with them, but it would be nice to limit the actual firing rate. At the moment the player seems to fire as many as the computer can generate. Things soon slow down.

    I've had a look at coroutines and yield, but don't really know what I'm doing yet. Any tips would be appreciated.
     
  12. Jonathan Czeck

    Jonathan Czeck

    Joined:
    Mar 17, 2005
    Posts:
    1,713
    Keep a DelayBetweenFiring float variable public so you can modify that in the inspector. Then keep a private delayToFire and initilize that to zero at start.

    Then do something like this in your Update function:

    delayToFire -= Time.deltaTime;

    Then right where you check to see if the firing key is pressed down..

    if (Input.GetButton("Fire1") delayToFire < 0)
    {
    delayToFire = DelayBetweenFiring;
    // fire a projectile
    }

    Of course there are zillions of ways to do this, but this is one.

    -Jon
     
  13. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    Looks good. I was thinking of something like that but you've saved me the effort. I've got to the point where thinking hurts.

    Cheers.
     
  14. nmceri

    nmceri

    Joined:
    Aug 4, 2005
    Posts:
    56
    I'm also attempting the same sort of thing, but this went a little over my head I think.
    I'm trying something like this.

    Code (csharp):
    1. var delayBetweenFiring = 5;
    2. var delayToFire = delayBetweenFiring;
    3.  
    4. function Update () {
    5.  
    6.    delayToFire -= Time.deltaTime;
    7.  
    8.    if (delayToFire < 0) {
    9.       delayToFire = delayBetweenFiring;
    10.       //shoot the projectile
    11.    }
    12. }
    What am I missing?
     
  15. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    delayBetweenFiring is type inferred to a integer instead of a float value.
    When you subtract Time.deltaTime from it, it can't decrease the value because it will always round Time.deltaTime to an integer.

    so instead of writing
    var delayBetweenFiring = 5;
    just write
    var delayBetweenFiring = 5.0;


    When declaring variables make sure the type is declared to the type you want to use later in the script.
    Code (csharp):
    1.  
    2. var delayBetweenFiring = 5;
    3. // is the same as
    4. var delayBetweenFiring : int = 5;
    5.  
    Code (csharp):
    1.  
    2. var delayBetweenFiring = 5.0;
    3. // is the same as
    4. var delayBetweenFiring : float = 5.0;
    5.  
     
  16. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    D'oh! I'd never have worked this out. Thanks for the tip.
     
  17. nmceri

    nmceri

    Joined:
    Aug 4, 2005
    Posts:
    56
    I would have never got that either.
    I think I had a somewhat related question not long ago and never really realized it. These 2 types seem much more clear to me now. Thank you.
     
  18. nmceri

    nmceri

    Joined:
    Aug 4, 2005
    Posts:
    56
    I'm getting a System.NullReferenceException error when i run i script similar to what we are talking about here.
    The script itself works perfectly aside from this null reference error when i run. The larger problem comes when i build the game and it hangs when i shoot a bullet for the first time.

    Code (csharp):
    1.  
    2. var bullet : GameObject;
    3. var turret : Transform;
    4. var delayBetweenFiring = 0.5;
    5. var delayToFire = delayBetweenFiring;
    6.  
    7. function Update () {
    8.  
    9. delayToFire -= Time.deltaTime;
    10.  
    11.     if ( Input.GetKey ("left ctrl")){
    12.         if (delayToFire < 0){
    13.        
    14.         delayToFire = delayBetweenFiring;
    15.         var projectile : GameObject = Instantiate (bullet, Vector3(turret.position.x, turret.position.y, turret.position.z), turret.rotation);
    16.         projectile.rigidbody.velocity = Vector3.forward * 200;
    17.         Destroy(projectile, 2.5);
    18.  
    19.         }
    20.     }
    21. }
    22.  
    I'm using beta 2. I Can't recall, but I believe I was getting this error in 1 also.
    Is there something i should be doing differently?
     
  19. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    Which line do you get the null reference error in?

    Did you remember to attach objects to the bullet and turret variables?
     
  20. nmceri

    nmceri

    Joined:
    Aug 4, 2005
    Posts:
    56
    I've got this one figured out. At some point i accidentally dragged the script onto another object. Is there a way to see which objects the script is on?
     
  21. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    Yes just do a Debug.Log("used here!", gameObject) in the Awake method, and the console will print a reference to each object when you hit run.