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
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

How to implement shooting with a character that doesn't actually rotate?

Discussion in '2D' started by FeniXD, Apr 3, 2018.

  1. FeniXD

    FeniXD

    Joined:
    May 16, 2017
    Posts:
    9


    Okay, so I'm relatively new to creating 2D projects in Unity

    The character currently uses an X and Y location based off the mouse to world point - character position.
    This is fed to my two blend trees to activate the animations accordingly.

    My question is, what is the best practice for implementing shooting? This would be a case of LookAt() if the character actually rotated, but its entirely sprite based.

    Note: I have tried manually updating the values of the position and rotation to instantiate the bullet, but for some reason the Z-axis needed 0 to shoot east and 90 to shoot west (I tried 180 and that also shot east). This method confused the hell out of me, so I just scrapped the idea. I have also tried using 8 individual pivots to update the position and rotation, but not sure how to get it to update them. Could I just add events to the animations themselves?

    Here is my code for my latest attempt, incomplete but was just to test the logic.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class BulletSpawn : MonoBehaviour
    6. {
    7.     //Bullet Prefab
    8.     [SerializeField]
    9.     GameObject bullet;
    10.  
    11.     //Gun fire rate
    12.     [SerializeField]
    13.     float fireRate;
    14.  
    15.     //Variable to store Fire rate + Time)
    16.     float updateTimer;
    17.  
    18.     //Player reference and player animator reference
    19.     GameObject playerFind;
    20.     Animator an;
    21.  
    22.     //Shoot directionals
    23.     [SerializeField]
    24.     GameObject northShot;
    25.     [SerializeField]
    26.     GameObject southShot;
    27.     [SerializeField]
    28.     GameObject eastShot;
    29.     [SerializeField]
    30.     GameObject westShot;
    31.  
    32.     //Shoot position and rotation
    33.     Vector3 shotPosition;
    34.     Quaternion shotRotation;
    35.  
    36.  
    37.     void Start()
    38.     {
    39.         playerFind = GameObject.FindGameObjectWithTag("Player");
    40.         an = playerFind.GetComponent<Animator>();
    41.     }
    42.  
    43.     void Update()
    44.     {
    45.         float xVal = Mathf.Clamp(an.GetFloat("MoveX"), -1.5f, 1.5f);
    46.         float yVal = Mathf.Clamp(an.GetFloat("MoveY"), -1.5f, 1.5f);
    47.  
    48.         if (yVal > 0)
    49.         {
    50.             shotPosition = northShot.transform.position;
    51.             shotRotation = northShot.transform.rotation;
    52.         }
    53.  
    54.         if (yVal < 0)
    55.         {
    56.             shotPosition = southShot.transform.position;
    57.             shotRotation = southShot.transform.rotation;
    58.         }
    59.  
    60.         if (xVal > 0)
    61.         {
    62.             shotPosition = eastShot.transform.position;
    63.             shotRotation = eastShot.transform.rotation;
    64.         }
    65.  
    66.         if (xVal < 0)
    67.         {
    68.             shotPosition = westShot.transform.position;
    69.             shotRotation = westShot.transform.rotation;
    70.         }
    71.     }
    72.  
    73.     void FixedUpdate()
    74.     {
    75.         if (Input.GetButton("Fire1") && Time.time > updateTimer)
    76.         {
    77.             updateTimer = Time.time + fireRate;
    78.             Instantiate(bullet, shotPosition, shotRotation);
    79.         }
    80.     }
    81. }
    The code for updating the position and rotation is far to primitive to work, it was just an idea I was trying. I was considering creating separate functions to update these and creating events on each animation direction, but it seemed a very heavy approach. (With 8 individual pivots attached to the player GameObject, with preset positions and rotation).

    Any help is greatly appreciated!
     
  2. Verdemis

    Verdemis

    Joined:
    Apr 27, 2013
    Posts:
    92
    I would get a direction vector from your player position to the crosshair. Then use this vector to spawn the bullet in a little distance to the player and send it in the same direction
     
    FeniXD likes this.
  3. FeniXD

    FeniXD

    Joined:
    May 16, 2017
    Posts:
    9
    That's a brilliant idea, only issue being that it needs to be one of 8 directions. Not a full 360 degree angle. Thank you for the idea though, I will play around with it and see what I can do.
     
  4. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Is this what you meant?
    Code (csharp):
    1. public class Test1 : MonoBehaviour {
    2.  
    3.     // Set an empty game object at position 0,0,0
    4.     // Modify these values while the script is running? (I used -1.5 , 0, or 1.5 )
    5.     public float xval;
    6.     public float yval;
    7.  
    8.     IEnumerator Start()
    9.     {
    10.         GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
    11.         Transform trans = go.transform;
    12.         WaitForSeconds wfs = new WaitForSeconds(.4f);
    13.         while (true)
    14.         {
    15.             trans.position = transform.position;
    16.             yield return wfs;
    17.             Vector3 dir = new Vector3(xval, yval, 0).normalized;
    18.             float time = 0;
    19.             while (time < 1f)
    20.             {
    21.                 trans.position += dir * Time.deltaTime * 4f;
    22.                 time += Time.deltaTime;
    23.                 yield return null;
    24.             }
    25.         }
    26.     }
    27. }
    I noticed you already have the values from the animation. If it's limited in the 8 directions, I think this code will work. Obviously I took some liberties in its design and it would require some small modifications for you ;)
     
    FeniXD likes this.
  5. FeniXD

    FeniXD

    Joined:
    May 16, 2017
    Posts:
    9
    Literally just seen this. I will check it out. Thank you very much for the help, will report back asap!
     
  6. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Please remember that this is just a demo ... try it to see if it's in line with what you want, then adapt it for your game ;)
     
    FeniXD likes this.
  7. FeniXD

    FeniXD

    Joined:
    May 16, 2017
    Posts:
    9
    After many hours of playing with it, I could only manage to get your solution to shoot north east and south west (clearly my lack of understanding).

    I have been reading up on how to work out the angles between the mouse position and the player position and have so far come up with this (which seems to be working)

    Code (CSharp):
    1.     void Update()
    2.     {
    3.         //mouse
    4.         Vector2 mPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    5.  
    6.         //player
    7.         Vector2 pPos = playerFind.transform.position;
    8.  
    9.         Vector2 difference = pPos - mPos;
    10.         float sign = (pPos.y < mPos.y) ? -1.0f : 1.0f;
    11.         float angleDif = Vector2.Angle(Vector2.right, difference) * sign;
    12.  
    13.         if (angleDif < -70 && angleDif > -120)
    14.         {
    15.             shotPosition = northShot.transform.position;
    16.             shotRotation = northShot.transform.rotation;
    17.         }
    18.  
    19.         if (angleDif > 70 && angleDif < 120)
    20.         {
    21.             shotPosition = southShot.transform.position;
    22.             shotRotation = southShot.transform.rotation;
    23.         }
    24.  
    25.     }
    26.  
    27.     void FixedUpdate()
    28.     {
    29.         if (Input.GetButton("Fire1") && Time.time > updateTimer)
    30.         {
    31.             updateTimer = Time.time + fireRate;
    32.             Instantiate(bullet, shotPosition, shotRotation);
    33.  
    34.         }
    35.     }
    I have only tested north and south at the moment, but will follow up tomorrow. 02:45am and my brain has melted from deciphering the maths.

    Note: I am currently updating the position and rotation with empty game objects for simplicity, but I will make note of the values and manually set them in the script rather than having 8 (possibly 16) game objects attached to the character.

    Thank you so much for your help. Even though I ended up using a different solution, your solution got me thinking differently.
     
  8. FeniXD

    FeniXD

    Joined:
    May 16, 2017
    Posts:
    9
    Thank you for the suggestion. I originally lacked the understanding to do this, but it ended up being the solution when I figured out how to use the Vector2.Angle. Thank you!
     
  9. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I thought with xval and yval set to -1.5, 0, or 1.5 .. my script would give you the 8 directions.
    If you ran the code I posted, and change the inspector values to be 2 of those values it should have moved the spawned cube that way.

    However, in the end, if you find something that works, it's all good. :) Usually there is more than 1 way to do something. :)

    You're welcome, by the way.