Search code examples
c#unity-game-engineposition

Trigger when gameobject moves over a specific position


In my project I have a vertical number-dial with numbers between 0 and 9. I can drag and drop this dial up and down (x-position is locked). When I drop it, it checks its current position. If it is between two numbers, like 3 and 4, it will move (tween) to the number that is the closest.

I would like to play a click-sound everytime I pass one of the numbers, while I drag the dial, to make it feel like a locking system.

I tried to move the dial with Vector3.MoveTowards(curPos, toPos, speed); and in Update() I checked if my current position is equal to my trigger position. But as expected, this does not work. My object moves over the trigger position, but since it is never exactly equal to it, it does not trigger my click-sound.

Playing the sound when I drop the dial is no problem. But how do I do it while I drag it?


Solution

  • Here is my solution. If you attach this script to a gameobject (GO), the GO will move to the click-position. If it moves over one of the trigger positions (triggerPositions) on the y-axis, in this example y = 1, 2 or 5, the console returns "TRIGGER".

    It works like this, after clicking on the screen, we save the click position (toPos) and we save the current position (curPos). If the current position is unequal to the last position (lastPos), then we check if the GO moved over the trigger position by checking if the GO's last position is smaller than our trigger position (tp) AND is the trigger position smaller than our current position? (we also check the opposite case) THEN "TRIGGER!", because it passed the trigger position.

    We save our last position as our current position and then move the GO. Repeat.

    tp can be any flaot value. With my solution you can add as many trigger positions as you wish by adding or removing values to the array triggerPositions.

    using UnityEngine;
    
    public class MoveTowardsClick : MonoBehaviour
    {
        [SerializeField] private float speed = 0.1f;
        [SerializeField] private Vector2 toPos = new Vector2(0, 0);
    
        [SerializeField] private Vector2 curPos = new Vector2();
        [SerializeField] private Vector2 lastPos = new Vector2();
    
    
        private void Start()
        {
            curPos = transform.position;
            lastPos = curPos;
        }
    
        private void Update()
        {
            if (Input.GetMouseButtonDown(0))
            {
                toPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            }
    
            curPos = transform.position;
    
            if(curPos != lastPos)
            {
                float[] triggerPositions = new float[3] { 1, 2, 5 };
    
                foreach (float p in triggerPositions)
                {
                    if ((lastPos.y < p && p <= curPos.y) ||
                        (lastPos.y > p && p >= curPos.y))
                    {
                        // Do something when moving over trigger position
                        Debug.Log("TRIGGER!");
                    }
                }
            }
    
            lastPos = curPos;
    
             this.transform.position = Vector3.MoveTowards(curPos, toPos, speed);
            // or move with this.transform.position = toPos;
        }
    }