Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Question I'm having trouble getting a "low precision aim mode" working...

Discussion in 'Scripting' started by Kaktuspiratgames, Apr 3, 2024.

  1. Kaktuspiratgames

    Kaktuspiratgames

    Joined:
    Jul 3, 2018
    Posts:
    18
    Hey all!

    For I few days now I tried to find a solution for this, but it still doesn't work.

    I have an input method where you can tap anywhere on the screen, drag your finger/mouse in any direction and then move it around to manipulate the direction a ball will be launched in. It looks like this:


    In some situations especially on phones, it can be a bit tricky to get the exact aim direction you want. Moving the finger even very slightly can sometimes be too much. What I would like to have is an option to move the actual aim direction on the ball less than you move the finger/mouse. Kind of a "high precision mode". You click, draw the general direction for rough aim and then move the cursor around for fine tuning.

    What I have right now (Only the relevant snippets for focus):


    The variables I use:
    Code (CSharp):
    1. Vector2 aimPosition;
    2. Vector2 previousAimPosition;
    3. Vector2 dragStartPosition;
    This is set when the aim button is pressed:
    Code (CSharp):
    1. dragStartPosition = Input.mousePosition;
    2. previousAimPosition = Input.mousePosition;
    And I run this in update while the aim button is held down:
    Code (CSharp):
    1. float sensitivity = 1f;
    2. aimPosition = Vector2.Lerp(previousAimPosition, mousePos, sensitivity) - dragStartPosition;
    3. previousAimPosition = dragStartPosition + aimPosition;
    aimPosition should probably be called aimDirection. That is the value I pass to the ball.

    With sensitivity set to 1 it works like seen in the video.
    If I set it lower, then I almost get the behavior I want, except because of the Lerp the aim position slowly moves towards the cursor while holding the aim button down.
    I tried running all of it only when the mouse position changed since the last frame, but that results in some weird behavior as well. For example if I move the mouse in small circles on one spot the aim still slowly moves towards the cursor, instead of just mimicking the movement.

    Does anyone have an idea how I could approach this?
     
  2. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,154
    Well in my head fine-tuning should be angle-based. You do the coarse aiming by dragging across, then if you support multi-touch you maybe add another finger to slowly change the angle? For this you only track the up/down or left/right movement. Of course, from the UX perspective, maybe you could introduce a virtual button "Fine tuning" that the user needs to keep pressed (basically to keep a finger on) in order to access this functionality, so that it becomes clearer.
     
  3. Kaktuspiratgames

    Kaktuspiratgames

    Joined:
    Jul 3, 2018
    Posts:
    18
    Thank you for the suggestions! I would love to try out approaches like these. For that I need to make it work from the code side though.

    I think it might even be possible that the high precision mode will be the default. If you want to make a big change, you swipe in a different direction and precision aiming is done by keeping the finger down and moving it around.
     
  4. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,154
    Yeah well, what I meant for the code side of it, is to compute the angle of the original aim (you do this with
    atan2(dy, dx)
    ), then you can use the second mode of input to fine-tune (i.e. increment or decrement) this angle. So you don't really need to switch resolutions or what else you had in mind.

    To convert back from angle to direction you do
    new Vector2(cos(angle), sin(angle))


    I believe that kind of control would be the most intuitive and it's very easy to implement for a wide spectrum of devices, even devices that are grossly imprecise due to tech constraints.

    I can imagine other control mechanisms, of course, but I bet you'll encounter issues down the line. The most of this design lies in the UX department, it's not really a coding/scripting problem.
     
  5. Kaktuspiratgames

    Kaktuspiratgames

    Joined:
    Jul 3, 2018
    Posts:
    18
    What you described is similar to what some pool games do. They have a "wheel" that you can turn to increment the angle.
    That would work with the scripting you suggested. I'm not sure how that would translate to the control method I have in mind though. For me it actually is a scripting problem, since I already have a specific UX in mind that I'm struggling to make work on the code side.
    So if I would go with incrementing the angle, and stick with the input method I described I would somehow need to translate finger/mouse movement relative to the initial dragStartPosition to a change of angle of the aim. Do think that is necessary? It feels like what I have using vectors is just inches away from working like I want it to.
     
  6. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,154
    Ok let's work with this then. From this sentence I gather that you want something distance related (edit: or maybe I've misinterpreted it completely).

    So if you drag touch from some source to some destination, you observe the difference and if you normalize that you get the direction vector. Now the question is how to refine that input. If it's distance related, what exactly you want to happen by changing the distance? In many ways the angular resolution improves naturally with increasing distance between destination and source (edit: given that the circumference of an imaginary circle grows linearly with distance over a finite capacitor grid).

    You need to clarify this point because it's too much work for me to speculate.

    I need help with this sentence. Do you intend to separate behaviors in two parts? Is the cursor something that you show after you've already dragged the coarse direction (and let go)?
     
  7. Kaktuspiratgames

    Kaktuspiratgames

    Joined:
    Jul 3, 2018
    Posts:
    18
    I made another video that might help explain what I mean. I have the described behavior in place already.
    Aiming is done by clicking and then holding the left mouse button. The white dot in the footage represents the position where my cursor is when I click to start aiming. The "dragStartPosition". The white line that is rendered starts there and points towards the current position of the cursor. The direction that results from that is passed to the ball, normalized and then used for the trajectory simulation and shot direction when the ball is launched.
    You can see at the start of the video I do a few click and drag motions to quickly "draw" an aim direction. Towards the end I do that as well, but hold the aim button and move the cursor around to adjust the aim. This is also the part where I want to make the change. Right now the aim mimics the cursor movement. What I would like to do is move the aim less that the cursor is moved. For example lets say I click, drag straight to the right and then move the cursor straight up. Lets say the direction from the dragStart to the cursor is 1,1 now. Instead of the aim also having that same direction I would like it to have 1, 0.5
    So the inital click, drag would set the rough direction you want to shoot in and the moving around of the cursor while holding aim, would just be for the fine tuning of the shot, since big cursor movements have a much smaller effect on the final aim direction.
    The distance between dragStart and cursor would have no influence on the final aim initially. I thought about maybe scaling the sensitivity based on the distance, but I'm not sure if that might feel weird to control. For now I would be happy if it had a fixed sensitivity.
    Since my initial post I tried to add some kind of fake cursor that moves at half the rate of the actual cursor but couldn't make it work properly either. In the example above it would end up at 0.5, 0.5 which results in the same direction as 1,1. It would need to only reduce the mouse movement that doesn't move along the current aim direction for it to work. But maybe there is also a way better solution to achieve the same.

     
  8. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,154
    Ok, but how do you differentiate that initial click,drag input from the fine aiming mode that you do next? Do you lift the finger and then click,drag again?

    I can't really synchronize myself with how you have designed the UX.
    How do you delimit the modes of aiming?
     
  9. Kaktuspiratgames

    Kaktuspiratgames

    Joined:
    Jul 3, 2018
    Posts:
    18
    Okay so what I thought is this:
    You click and hold without moving the cursor. This is frame zero and at this point there is no aim direction set yet. Then you move the cursor to any direction while still holding the click, which would set the rough aim direction. This direction is now "locked in" as the rough direction you want to aim in and any cursor movement (while still holding the click) only slightly adjusts the aim now. Once you release the click the aim direction is kept. If you click again, the process starts from the beginning.
     
  10. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,154
    Ok I understand now, but this can't work as it is, because you're in the same input mode as long as you're touching. You can have a distance-based soft delimiter between two modes, but you need to configure that in such a way to be intuitive for the user.

    The problem is in this sentence
    If you haven't released the touch, how do you know that setting the direction was finished, in order to move onto fine-tuning?
     
  11. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,154
    And the distance-based soft delimiter would work by having a minimum range from the source, after which the direction is automatically set and input switches to fine-tuning on its own. That could work.

    To do that
    Code (csharp):
    1. int _dragMode;
    2. Vector2 _dragStart, _dragEnd;
    3. Vector2 _aimDirection;
    4.  
    5. void Update() {
    6.   const float LOCK_RANGE = 1f; // some minimum distance
    7.   const float FINE_TUNE_MULTI = .1f; // multiplier for fine tuning
    8.  
    9.   int count = ... // get touch count (for multi-touch)
    10.  
    11.   if(count == 0) {
    12.     if(_dragMode != 0) _dragMode = 0; // aborts aiming
    13.     // alternatively here you can check if the procedure is done and call something
    14.     return;
    15.   }
    16.  
    17.   Vector2 touch = touches[0]; // get first touch pos (this line is pseudocode)
    18.  
    19.   switch(_dragMode) {
    20.     case 1:
    21.       var diff = touch - _dragStart;
    22.       if(Vector2.Distance(diff) >= LOCK_RANGE) {
    23.         _aimDirection = diff.normalized;
    24.         _dragEnd = _dragStart + _aimDirection * LOCK_RANGE;
    25.         _dragMode = 2; // proceed with fine aiming
    26.       }
    27.       break;
    28.  
    29.     case 2:
    30.       var fineTune = (touch - _dragEnd) * FINE_TUNE_MULTI;
    31.       _aimDirection = (_dragEnd + fineTune - _dragStart).normalized;
    32.       break;
    33.  
    34.     default:
    35.       _dragStart = touch;
    36.       _dragMode = 1; // start coarse aiming
    37.       break;
    38.   }
    39. }
    Something like that.