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

2D Aiming

Discussion in '2D' started by Tomiino, Feb 17, 2020.

  1. Tomiino

    Tomiino

    Joined:
    Feb 17, 2020
    Posts:
    2
    So I've been recently making simple 2D game, but after movement was made, i got stuck on aiming. I have clear vision of what I want to do, but somehow nothing works. I've tried several tutorials but I have like zero idea why stuff isn't working how it should. I made gif (attached files) of my vision. Is there anyone, who can push me and show me easy way, how to do it? Even after tons of tutorials or forum threads, I couldnt make it work. I just want simple script, what takes position of the mouse, pictured as crosshair, and after that it will show certain sprite what equals to that position.

    I'd be grateful for any advice and suggestions.!
     

    Attached Files:

    • aim.gif
      aim.gif
      File size:
      64.3 KB
      Views:
      631
    Last edited: Feb 17, 2020
  2. Cornysam

    Cornysam

    Joined:
    Feb 8, 2018
    Posts:
    1,353
    This is a great tutorial i used:


    As for creating a crosshair, just look that up on YouTube or Google as well and it should be pretty easy.
     
    MisterSkitz likes this.
  3. Tomiino

    Tomiino

    Joined:
    Feb 17, 2020
    Posts:
    2
    I'm already acquainted with this exact tutorial, but I'm not rotating the hand-object. I'm trying to make an animation, where sprites are changing by degrees depending on the mouse position. I need to figure out how to change sprites by degrees. The animation has 18 sprites and changes in 22.5 degrees.
     
  4. Cornysam

    Cornysam

    Joined:
    Feb 8, 2018
    Posts:
    1,353
    Hmmm okay. I dont know exactly and I am sure there are some great programmers out there that know the code behind it but my guess is:
    -Create a circle (using gizmos or whatever) that is a the center of your rotation point
    -Determine what the degree of the circle is depending on your mouse position, probably by using a raycast
    -Determine the animation used by the angle/degree (if mousePositionAngle > 0 && mousePositionAngle < 20... then do animation 1 or whatever)

    You may also use coordinates on the screen or something. I am really not sure but maybe my bullet points sparks an idea or something. Check out this forum that may help with finding coords or angles:
    https://answers.unity.com/questions/759542/get-coordinate-with-angle-and-distance.html
     
  5. MisterSkitz

    MisterSkitz

    Joined:
    Sep 2, 2015
    Posts:
    833
    You want to look into hinge joints. These allow rotations from a fixed point within an animation. This works amazing with the 2D Animation package you can import into unity for free! As long as your fire-point is a child object of the animated arm, you should't even need to alter the rotation of the fire point. However, if you do, that's relatively simple to accomplish.

    Just another free hint. There is no such thing as a "simple script". All scripts are simple, just not at first. You'll see as your understanding of the language increases. ;)
     
    Cornysam likes this.
  6. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    Hi @Tomiino,

    I would go programmatical way instead of trying to hack this with objects, joints, raycasts and so on. Although there's nothing wrong with that approach either.

    The approach you seem to have used is not ideal, as you will never get far if you are looking for a tutorial for a specific problem. Since you already have a clear vision (your reference animation) it should be now easy to split the whole thing into separate problems which you solve one by one. Here's an overview what I would do:

    1. Figure out your current mouse position.

    2. Convert the mouse position to world space position (there's other ways of doing this too.) Either project the position to a plane or set the ScreenToWorldPoint z-value to the distance between your main Camera and the character object. Use your Google-fu to search tutorials and answers on this topic, there's plenty of those out there.

    3. Figure out the angle between the weapon position and the cursor position projected to the world space. You can use arc tangent calculation to do this. Again, there's lots of information available.

    4. Now that you have the angle, you probably should make it so that it's in 0-360 range, so first convert it from radians to the degrees and then adjust it so that it's on the positive side.

    5. Then you just need to normalize it to a range. The range being the sprite frame count you have, i.e. 0 - 17 if you have 18. frames. Search for how to normalize a value to a desired range.

    6. Now set up a system which just changes the sprites in your character's SpriteRenderer based on the frame value that is derived from your angle. You could have your sprites in a List, for example. Then just select the index according to the frame number.

    7. You should have a sprite which changes based on the aim angle.

    I've done things similar to this approach and it should work just fine. There's then less dependency on all sorts of rigs built in Editor that can break easily. Now you would only need a weapon position which you could extract from an empty object you have placed in your character object's hierarchy.
     
  7. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,802
    I wrote this script for another thread where someone wanted their top-down 2D character to look at the mouse using sprites instead of rotation:

    If you put this on a gameobject with a SpriteRenderer, and supply it with your sprites added counterclockwise, starting with east, it will just work. It's not optimized and will run every frame even if there's no change.

    I also commented the living crap out of it so hopefully it helps you learn something. It's pretty much what @Olmi described.

    Code (CSharp):
    1. using UnityEngine;
    2. // this attribute guarantees that this GameObject will have a SpriteRenderer
    3. // if there isn't one, one will be added when DirectionalSprite is added.
    4. [RequireComponent(typeof(SpriteRenderer))]
    5. public class DirectionalSprite : MonoBehaviour
    6. {
    7.     [Header("Add sprites in counter-clockwise order starting with east")]
    8.     // array of sprites added in the inspector
    9.     public Sprite[] directionSprites;
    10.  
    11.     // references to components
    12.     private SpriteRenderer _spriteRenderer;
    13.     private Camera _mainCamera;
    14.  
    15.     // called once when this component is first created
    16.     private void Awake()
    17.     {
    18.         // get the SpriteRenderer component on this GameObject.
    19.         // This can return null if there isn't one,
    20.         // but we know there is one because of RequireComponent
    21.         _spriteRenderer = GetComponent<SpriteRenderer>();
    22.  
    23.         // get the main camera in the scene
    24.         _mainCamera = Camera.main;
    25.     }
    26.  
    27.     // called every frame the game renders
    28.     private void Update()
    29.     {
    30.         // get the current direction
    31.         Vector2 directionTowardsMouse = GetDirectionTowardsMouse();
    32.  
    33.         // update the sprite
    34.         UpdateSpriteDirection(directionTowardsMouse);
    35.     }
    36.  
    37.     // calculates and returns the direction from this GameObject to the mouse
    38.     private Vector2 GetDirectionTowardsMouse()
    39.     {
    40.         // convert player position to screen position (pixel coordinates)
    41.         Vector2 from = _mainCamera.WorldToScreenPoint(transform.position);
    42.  
    43.         // mouse position is already in screen space
    44.         Vector2 to = Input.mousePosition;
    45.  
    46.         // difference in positions, imagine this vector
    47.         // as an arrow starting at `from`, ending at `to`
    48.         Vector2 positionalDifference = to - from;
    49.  
    50.         // normalizing the vector shortens it to 1 unit (represents only direction)
    51.         // ie. right=(1,0), down=(0,-1), diagonal up&right (0.707, 0.707)
    52.         return positionalDifference.normalized;
    53.     }
    54.  
    55.     // calculates which sprite to select based on the given direction
    56.     private void UpdateSpriteDirection(Vector2 direction) {
    57.         // divide a circle into slices for each sprite to represent
    58.         float sliceAngle = 360f / directionSprites.Length;
    59.  
    60.         // calculate the direction's angle (-180 to 180 range)
    61.         float currentAngle = Mathf.Rad2Deg * Mathf.Atan2(direction.y, direction.x);
    62.  
    63.         // offset the angle by half a slice to center the slices
    64.         // ie. when facing perfectly right, that's the center of a slice, not an edge
    65.         currentAngle += sliceAngle * 0.5f;
    66.  
    67.         // put the angle range between 0 and 360 instead of -180 to 180
    68.         currentAngle = Mathf.Repeat(currentAngle, 360);
    69.  
    70.         // get an index for which slice the direction is pointing
    71.         int sliceIndex = Mathf.FloorToInt(currentAngle / sliceAngle);
    72.  
    73.         // set the sprite using that index (assuming sprites are in the array in counter clockwise order)
    74.         _spriteRenderer.sprite = directionSprites[sliceIndex];
    75.     }
    76. }
     
  8. MisterSkitz

    MisterSkitz

    Joined:
    Sep 2, 2015
    Posts:
    833
    Or could just use a hinge joint and access the mouse point position and determine the distance from the to the bullet spawn position and have the angle set like that. Could even flip the spite, if needed based of the mouse position so the player is always facing the enemy. Animations might get hairy depending on the setup but generally would still be easier than 90% of what you suggested to a newbie coder, in my opinion.