Search Unity

Help with GetButtonDown/Up and Quaternion rotations

Discussion in 'Scripting' started by omgapotato, Sep 27, 2014.

  1. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20
    GetButtonDown problem:
    Error: http://puu.sh/bPBrU/a2cc9a4bd1.png
    Code: https://gist.github.com/

    If you look at the screen shot then the Debug.Logs I placed in my code, you'll see that it only partially does my methods. The logs are only called once except for Debug.Log(power) except I have a log before that that prints nothing. I'm very confused by this. I suspect that it may be conflicting with an asset I downloaded.

    Quaternion rotations problem:
    Error:
    (watch cursor)
    Code: https://gist.github.com/

    Whenever I fire, the projectiles sometimes go straight down or up. It's especially bad on the left side. I'm pretty sure I have something wrong in my code but not entirely sure what.
     
  2. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    There seems to be no code when using the link, it's just empty.
    As for 'ButtonDown' problem, this will only trigger once until you press the button again. There's also the method GetButton which may fit your needs. (Since i can't see the code, i can't really guess what you're trying to achieve).

    As for the rotation problem, it looks a bit like collision conflicts with the player. Do you spawn the objects 'within' the player?
     
  3. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20
    Forgot to create the gist.
    https://gist.github.com/anonymous/7d553b4229e0371c3f7f
     
  4. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Not only power is called several times. The others as well, there's a counter which says it has been logged 12 times each, they're just stacked.
    I assume you want to increase the power value until you release the button, don't you?
     
  5. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20
    Yeah that's what I want to do.
     
  6. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Then you could use GetKey which will return true as long as the key is hold down.
    The reason why the current script doesn't work is the AND, since GetButtonDown() will return true only once you pressed it, it won't return true while holding it.

    Or, if you want to keep working with (the slightly more complicated) version, you have to change the first AND (&&) to OR ( || ) and test whether buttonDown is true or not. That should actually have the same effect.
     
  7. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20

    Don't worry about that bool. I just tried that to see if it would make a difference. I'll try your solution.
     
  8. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20
    Hey your solution worked. It's working but is GetButtonUp still the correct method to use?
     
  9. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Yes, it should be fine.
     
  10. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20
    Thanks man. Lotta help. One question. For the life of me, I can't figure out how to draw a line in the direction of my cursor relative to my model. I can shoot projectiles in the correct direction. Just can't draw the line.
     
  11. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    So you want to draw a line (ingame, or just for debugging?) from the player's position to the
    a) 'screen' in world space (actually from your player to the camera, hitting the mouse pos)
    b) hitposition as if you casted a ray from the mouse and hit something in the world space
    c) just like b, but aligned with one of the players axis (e.g. x-axis in your scene / point in the same xy-plane of your player ).
     
  12. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20

    http://puu.sh/bPY4B/9338a1d0ce.png. I want the line to be able to follow the mouse cursor(star). Basically a line along the X plane angled in the direction of Z. For now, this is for debugging purposes but I eventually want to add a "laser sight". I can't believe I couldn't find a video but if you ever played Gunster, they had a laser sight that pointed from the character's gun to your cursor relative to the player.
     
  13. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    'Angled in the direction of Z' confused me a bit (you may add some more details), thus i made the following for now:

    Code (CSharp):
    1.     public Transform visualizationPrefab;
    2.     public bool visualize;
    3.     private Vector3 newWorldPos;
    4.  
    5.     void Update()
    6.     {
    7.         Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    8.         RaycastHit rayCastHit;
    9.         if (Physics.Raycast(ray, out rayCastHit, 100f)) //
    10.         {
    11.             newWorldPos = AdjustMousePositionInWorld(rayCastHit.point);
    12.             if(visualize && visualizationPrefab)
    13.                 visualizationPrefab.position = newWorldPos;
    14.         }
    15.    
    16.         Debug.DrawLine(transform.position, newWorldPos, Color.red);
    17.     }
    18.  
    19.     private Vector3 AdjustMousePositionInWorld(Vector3 hitPoint)
    20.     {
    21.         float z_CameraPlayerDistance = transform.position.z - Camera.main.transform.position.z;
    22.         Vector3 newMousePositionInWorld = hitPoint - Camera.main.transform.position;
    23.         newMousePositionInWorld /= newMousePositionInWorld.z;
    24.         newMousePositionInWorld *= z_CameraPlayerDistance;
    25.         return Camera.main.transform.position + newMousePositionInWorld;
    26.     }
    Note that it looks as if the end of the line was slightly offset in the editor window (due to camera angles in game view). Therefore i added a public gameobject which you can use for visualization (just assign it in the inspector and check visualize).
     
  14. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20
    Sorry it was really confusing for me to visualize and explain it.

    Holy crap man you're awesome. That's pretty much what I want. The only thing is I wish for it to infinitely go in the direction of the cursor but that's ok. I'm a bit new to unity, could you explain your code?
     
  15. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Add or replace the Debug.DrawLine:

    Code (CSharp):
    1. Vector3 rayDirection = (newWorldPos - transform.position) * 20; // or mult by a higher value for longer rays
    2. Debug.DrawRay(transform.position, rayDirection, Color.green);
    Any special line or everything?
     
  16. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20
    "Any special line or everything?" I'm sorry I don't understand your question but this is exactly what I want.
     
  17. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    My bad, should not have written in down there. I was asking if you need some specific lines to be explained or actually most of it. Sometimes i just can't say things exactly the way i want, it's not my native language. :p
     
  18. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20

    Ok let me see.

    I don't really understand what you mean by the visualization. What do I put there as an object?

    I mainly don't understnd lines 9-16 and the new code you gave me. I assume rayDirection calculates a vector based on the position of my gameobject and the cursor but what does "*20" do? And DrawRay draws a line in the direction of rayDirection from my gameobject.
     
  19. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    rayDirection describes the direction of the ray.
    Let's say you're at position P1(10,5,4) and you want to go to P2(20,2,9) you can calculate how much you have to move in each direction of a 3dimensional space.
    Target position - start position => P2-P1 = D(20-10,2-5,9-4) = D(10,-3,5). Now you know where you have to go in order to reach P2. Go 10 in x direction, -3 in y direction, 5 in z direction.
    This applies to pretty much everything, also rays, because you either need to know where the target is, or you need at least the direction.
    If you know the direction, you can multiply x,y,z by the same amount and you will still move into the same direction, just a different distance.

    I hope that's comprehensible.

    I'll post the commented version, if you got any further problems with it just let me know.
    Code (CSharp):
    1. public Transform visualizationPrefab;
    2.     public bool visualize;
    3.     private Vector3 newWorldPos;
    4.  
    5.     void Update()
    6.     {
    7.         // create a ray from mouse position on the screen to the world
    8.         Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    9.         // variable to store the information that we will receive from the upcoming raycast
    10.         RaycastHit rayCastHit;
    11.         // the raycast -  returns false is nothing was hit, true when you hit something
    12.         if (Physics.Raycast(ray, out rayCastHit, 100f)) //
    13.         {
    14.             // calling my own function here in order to make the code easier to read
    15.             newWorldPos = AdjustMousePositionInWorld(rayCastHit.point);
    16.  
    17.             // if we want to visualize it and our prefab is not set to NULL
    18.             // NOTE: you should set the prefab's layer to 'IgnoreRaycast', i forgot to mention it in my post
    19.             if(visualize && visualizationPrefab)
    20.                 visualizationPrefab.position = newWorldPos; // assign the return value to the visualization prefab
    21.         }
    22.         // draw a line
    23.         Debug.DrawLine(transform.position, newWorldPos, Color.red);
    24.         // get the direction of the ray (target pos - start pos) and multiply it
    25.         // you'll receive the same directional vector with another magnitude (length)
    26.         Vector3 rayDirection = (newWorldPos - transform.position) * 20;
    27.         // draw the new ray with fake infinite length
    28.         // the difference: DrawLine takes start + end position, DrawRay takes start and direction
    29.         Debug.DrawRay(transform.position, rayDirection, Color.green);
    30.     }
    31.  
    32.     // method that takes the hitpoint from the raycast, which we will need for another calculation, returns the desired position
    33.     private Vector3 AdjustMousePositionInWorld(Vector3 hitPoint)
    34.     {
    35.         // we need the z distance from the camera to the player (targetpos.z - startpos-z)
    36.         // in order to adjust the length of the ray that we've casted
    37.         float z_CameraPlayerDistance = transform.position.z - Camera.main.transform.position.z;
    38.         // this is actually named incorrect, we actually get the directional vector from camera to the hitpoint
    39.         Vector3 newMousePositionInWorld = hitPoint - Camera.main.transform.position;
    40.         // shorten it, so that the z value is 1, that's why we divide the whole vector by the z value
    41.         newMousePositionInWorld /= newMousePositionInWorld.z;
    42.         // now multiply by the actual z distance from camera to player (in the end just the principle 'rule of three')
    43.         newMousePositionInWorld *= z_CameraPlayerDistance;
    44.         // since we've got a directional vector and do not want to use it as a position, we need to add the cameras transform.position
    45.         return Camera.main.transform.position + newMousePositionInWorld;
    46.     }
    EDIT As for the Transform, e.g. you can assign a cube with the layer 'Ignore Raycast' and check the checkbox 'visualize' of the script, the cube will then move to the position where the actual ray ended (the one which is not fake-infinite).
     
    Last edited: Sep 27, 2014
  20. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20
    No that's perfect. Very thorough explanation. Need more dudes like you. A lot more math than I expected. Been awhile since I've dealt with vectors but now it all makes sense.
     
    Suddoha likes this.
  21. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    I edited the post in order to answer your question about what object to assign to the public variable. Just in case you haven't tried it yet.
     
  22. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20
    Ah I see. Alright thanks.,
     
  23. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20
    Sorry I'm back again. So the ray cast was working fine until I tried to move the camera out. It just points to (0,0,0)

    Error:http://puu.sh/bTnyd/4db3630520.jpg

    It gets the cursor location just fine but the raycast is really wack.


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class MageFire : MonoBehaviour {
    5.  
    6.     public GameObject fireBallProjectile;
    7.     public GameObject lighteningProjectile;
    8.     private bool isFireBall = true;
    9.     private bool isLightening = false;
    10.  
    11.     public float fireRate = 0.5F;
    12.     private float nextFire = 0.0F;
    13.     public float power = 0.0F;
    14.     private Vector3 mousePos;
    15.     public GameObject mageArm;
    16.  
    17.     private float downTime; //internal time from when the key is pressed
    18.     private bool isHandled = false;
    19.     private float waitTime = 1.0f; //wait time befor reacting
    20.     private bool buttonDown = false;
    21.  
    22.     //guys test code to make ray cast line
    23.     public Transform visualizationPrefab;
    24.     public bool visualize;
    25.     private Vector3 newWorldPos;
    26.  
    27.     // Cooldowns
    28.     private bool isLighteningCooldown;
    29.     private bool isFireBallCooldown;
    30.     public float fireBallCooldown;
    31.     public float lighteningCooldown;
    32.  
    33.     private float fireBallWait;
    34.     private float lighteningWait;
    35.  
    36.     // Use this for initialization
    37.     void Start () {
    38.    
    39.     }
    40.  
    41.     // Update is called once per frame
    42.     void Update () {
    43.         RaycastHit hit;
    44.  
    45.         //guys test code to make raycast line
    46.         Vector3 mousePos = Input.mousePosition;
    47.         mousePos.z = 60;
    48.         Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    49.         Debug.Log (ray);
    50.         RaycastHit rayCastHit;
    51.         if (Physics.Raycast(ray, out rayCastHit, 100f)) //
    52.         {
    53.             newWorldPos = AdjustMousePositionInWorld(rayCastHit.point);
    54.             Debug.Log(newWorldPos);
    55.             if(visualize && visualizationPrefab)
    56.                 visualizationPrefab.position = newWorldPos;
    57.         }//end if
    58.         Vector3 rayDirection = (newWorldPos - transform.position) * 20;
    59.         Debug.DrawRay(transform.position, rayDirection, Color.green);
    60.  
    61.         Debug.DrawLine(transform.position, newWorldPos, Color.red);
    62.         //end guys test code
    63.  
    64.         //my code
    65.         //Calculate Angle for shooting
    66.         mousePos = Camera.main.WorldToScreenPoint (transform.position);
    67.         Vector3 dir = Input.mousePosition - mousePos;
    68.         float angle = Mathf.Atan2 (dir.y, dir.x) * Mathf.Rad2Deg;
    69.         transform.rotation = Quaternion.AngleAxis (angle, Vector3.forward);
    70.         Quaternion q = Quaternion.AngleAxis (angle, Vector3.forward);
    71.         Vector3 fire = new Vector3 (q.eulerAngles.x, 0, 0);
    72.  
    73.         if (Input.GetKey (KeyCode.Alpha1)) {
    74.             isFireBall = true;
    75.             isLightening = false;
    76.         } else if (Input.GetKey(KeyCode.Alpha2)) {
    77.             isLightening = true;
    78.             isFireBall = false;
    79.         }
    80.  
    81.         // If left mouse button is pressed or held down
    82.         if (Input.GetKey("mouse 0"))
    83.         {
    84.             ButtonDown();
    85.         }//end if
    86.         // If left mouse button is released
    87.         if (Input.GetButtonUp("Fire1") && buttonDown == true)
    88.         {
    89.             ButtonUp();
    90.         }//end if
    91.  
    92.  
    93.  
    94.     }
    95.  
    96.     private void ButtonDown(){
    97.         buttonDown = true;
    98.         Debug.Log(buttonDown);
    99.         Debug.Log("A key or mouse click has been detected");
    100.         if (isLightening) {
    101.             ButtonUp();
    102.         }//end if lightening
    103.  
    104.         if (power <= 30) {
    105.             power += Time.deltaTime * 50;
    106.         }
    107. //        if (power <= 50) {
    108. //            power += Time.deltaTime * 50;
    109. //        }else{
    110. //            ButtonUp();
    111. //        }//end if power fireball
    112.  
    113.     }
    114.  
    115.     private void ButtonUp(){
    116.  
    117.         nextFire = Time.time + fireRate;
    118.  
    119.         if (isFireBall && isFireBallCooldown == false) {
    120.             isFireBallCooldown = true;
    121.             GameObject crateClone = Instantiate (fireBallProjectile, transform.position, transform.rotation) as GameObject;
    122.             crateClone.rigidbody.velocity = transform.TransformDirection (new Vector3 (20 +power, 0, 0));
    123.             Debug.Log (power);
    124.             Destroy(crateClone, 5);
    125.             StartCoroutine(simulateFireBallCooldown());
    126.         }//end if Fireball logic
    127.  
    128.         if (isLightening && isLighteningCooldown == false) {
    129.  
    130.             isLighteningCooldown = true;
    131.  
    132.             //test
    133.             Vector3 rotationVector = transform.rotation.eulerAngles;
    134.             rotationVector.z = 90;
    135.             transform.rotation = Quaternion.Euler(rotationVector);
    136.  
    137.             GameObject crateClone = Instantiate (lighteningProjectile, newWorldPos, transform.rotation) as GameObject;
    138.             crateClone.rigidbody.velocity = transform.TransformDirection (new Vector3 (-60*power, 0, 0));
    139.             Debug.Log (power);
    140.             Destroy(crateClone, .3f);
    141.  
    142.             StartCoroutine(simulateLighteningCooldown());
    143.         }//end if Lightening logic
    144.  
    145.         power = 0;
    146.         buttonDown = false;
    147.  
    148.     }
    149.  
    150.     private Vector3 AdjustMousePositionInWorld(Vector3 hitPoint)
    151.     {
    152.         float z_CameraPlayerDistance = transform.position.z - Camera.main.transform.position.z;
    153.         Vector3 newMousePositionInWorld = hitPoint - Camera.main.transform.position;
    154.         newMousePositionInWorld /= newMousePositionInWorld.z;
    155.         newMousePositionInWorld *= z_CameraPlayerDistance;
    156.         return Camera.main.transform.position + newMousePositionInWorld;
    157.     }
    158.  
    159.     private IEnumerator simulateFireBallCooldown(){
    160.         fireBallWait = fireBallCooldown;
    161.         for (var x = 1; x < fireBallCooldown; x++) {
    162.             fireBallWait--;
    163.             yield return new WaitForSeconds(1);
    164.         }//end for
    165.         isFireBallCooldown = false;
    166.         fireBallWait = 0;
    167.     }
    168.  
    169.     private IEnumerator simulateLighteningCooldown(){
    170.         lighteningWait = lighteningCooldown;
    171.         for (var x = 1; x < lighteningCooldown; x++) {
    172.             lighteningWait--;
    173.             yield return new  WaitForSeconds(1);
    174.         }//end for
    175.         isLighteningCooldown = false;
    176.         lighteningWait = 0;
    177.  
    178.     }
    179.  
    180.     void OnGUI () {
    181.         string cooldownDisplay = fireBallWait.ToString ();
    182.         GUI.Box (new Rect (0,Screen.height - 75,100,25), "Fire Ball:");
    183.         GUI.Box (new Rect (0,Screen.height - 50,100,50), cooldownDisplay);
    184.         cooldownDisplay = lighteningWait.ToString ();
    185.         GUI.Box (new Rect (100,Screen.height - 75,110,25), "Lightning:");
    186.         GUI.Box (new Rect (100,Screen.height - 50,110,50), cooldownDisplay);
    187.     }
    188.  
    189. }
    190.  
    P.S.: I know it's really inefficient code :). Still trying to get used to Unity. Or making scripts rather.









    EDIT: Ok I changed the distance value in Physics.raycast and it works now. I'm assuming you have to increase the distance of the raycast according to the screen?
     
    Last edited: Sep 30, 2014
  24. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Have you tried to add an overall background object that the raycast can hit? You can deactivate its renderer if you don't want it to be visible.
     
  25. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20

    I increased the distance of the raycast and it's making the ray to the cursor but now it's very inconsistent.
    Whenever my cursor goes to the top, it freezes, then when I come back down from the opposite side, it continues as normal.

    Video:
     
  26. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    I'll have a look at it tomorrow. I'm pretty tired and have to test it by myself.
    Is it only in the video or do you move the mouse in editor window when experiencing the problem? You should only expect correct rays when the mouse is in the game view, because that's where the position is taken from.

    But let me think about it tomorrow. I need some sleep to solve that. xD
     
  27. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20
     
  28. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20
    Alright Thanks. I'm guessing it has something to do with the camera position. Or is there a limit to the sky?

    Here's a full screen example:
     
  29. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824

    I've actually used a method which should work in almost all, if not all, cases. I justed tested my script again and everything works just fine. I can move the camera further away, rotate it in any direction and it does what i expect.

    Have you tried the suggestion i had written yesterday? I wasn't sure you had added an invisible collider in the background, and it was pretty hard to guess what's going on there when you only see the rays pointing in weird directions in the scene view. But the new video appears to show that there's nothing you can hit in the background.

    In order to make this work even when your mouse does not point at any object in your scene, you need a huge collider in the background which the ray can hit if there's nothing else.
    It kinda looks like you haven't added one, as soon as the mouse moves higher over the hills, the objects stop following, i assume that's because the raycast doesn't hit. You really have to make sure that everything that can be seen in the viewport also has some kind of background with colliders.
     
  30. omgapotato

    omgapotato

    Joined:
    Sep 24, 2014
    Posts:
    20

    Ahhhhh I missed that comment. It's been a long weekend. Added an invisible box collider and it works just fine. Perfectly responsive. Before, It did indeed stop right at the hills. Very awesome. Thanks for the help, again.
     
    Suddoha likes this.