Ciocomo Trombetta
Ciocomo Trombetta

Reputation: 47

Why my gameObjects are not dragged and snap?

I am making a simple puzzle game in Unity. I have two objects and two targets.- I wrote script to drag my objects to their target location. I want my objects to snap at a different locations. My code is not letting me drag the game object as I wanted. I can only move one of the objects even if I move it. I can't drag it. It just appears at target position after a second it jumps to other object's target location.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class moveObject : MonoBehaviour
{    
    [SerializeField] private Transform objectPosition;/// target position

    private Vector3 initialPosition; ///objects return position if placed wrong

    private float deltaX, deltaY; 

    public static bool correctPosition; /// lock item if it is snapped to true location

    public float snapdifficulty; /// snapping range  

    void Start()
    {
        initialPosition = transform.position;        
    }

    void Update()
    { 
        if (Input.touchCount > 0 && !correctPosition)
        {
            Touch touch = Input.GetTouch(0);
            Vector2 touchPos = Camera.main.ScreenToWorldPoint(touch.position);
            Ray raycast = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
            RaycastHit raycastHit;

            switch (touch.phase)
            {
                case TouchPhase.Began:   
                    if (Physics.Raycast(raycast, out raycastHit))
                    {
                        if (raycastHit.collider.name == this.name)

                        {
                            deltaX = touchPos.x;
                            deltaY = touchPos.y;

                        }
                    }
                    break;

                case TouchPhase.Moved:
                    if (Physics.Raycast(raycast, out raycastHit))
                    {
                        if (raycastHit.collider.name == this.name)
                        {
                            Debug.Log("move " + " " + this.name);
                            transform.position = new Vector3(touchPos.x = deltaX, touchPos.y = deltaY, initialPosition.z);
                        }
                    }
                    break;

                case TouchPhase.Ended:      
                    if (Mathf.Abs(transform.position.x - objectPosition.position.x) <= snapdifficulty
                        && Mathf.Abs(transform.position.y - objectPosition.position.y) <= snapdifficulty)
                    {
                        transform.position = new Vector3(objectPosition.position.x, objectPosition.position.y, initialPosition.z);
                        correctPosition = true;
                    }
                    else
                    {
                        transform.position = new Vector3(initialPosition.x, initialPosition.y, initialPosition.z);
                    }
                    break;
            }
        }
    }
}

Upvotes: 0

Views: 93

Answers (1)

derHugo
derHugo

Reputation: 90813

You are passing

transform.position = new Vector3(touchPos.x = deltaX, touchPos.y = deltaY, initialPosition.z);

in

case TouchPhase.Moved:
    if (Physics.Raycast(raycast, out raycastHit))
    {
        if (raycastHit.collider.name == this.name)
        {
            Debug.Log("move " + " " + this.name);
            transform.position = new Vector3(touchPos.x = deltaX, touchPos.y = deltaY, initialPosition.z);
        }
    }
    break;

which makes your object stick to the initial position where the touch started until you reach the TouchPhase.Ended case.

I guess what you rather would want is store the initial Delta:

private Vector2 initialDelta;

and set it in

case TouchPhase.Began:   
    if (Physics.Raycast(raycast, out raycastHit))
    {
        if (raycastHit.collider.name == this.name)
        {
            initialDelta = transform.position - touchPos;
        }
    }
    break;

And then later use this Delta to position the object

case TouchPhase.Moved:
    if (Physics.Raycast(raycast, out raycastHit))
    {
        if (raycastHit.collider.name == this.name)
        {
            Debug.Log("move " + " " + this.name);
            transform.position = touchPos + initialDelta + Vector3.forward * initialPosition.z;
        }
    }
    break;

In general

I would not let every object handle the raycast! This is pretty expensive.

Rather put your script on one single controller object in the scene and additionally store which object you hit.

You can then put all your moveable objects into a special Layer and filter your Raycast to only hit this specific layer.

Something like e.g.

// Set via the Inspector
public LayerMask raycastLayers;

private Transform currentlyDraggedObject;

and then get it in

case TouchPhase.Began:   
    if (Physics.Raycast(raycast, out raycastHit, layermask = (int)raycastLayers))
    {
        currentlyDraggedObject = raycastHit.transform;
        initialDelta = currentlyDraggedObject.position - touchPos;

        // Your component would now only store and provide public the target position
        objectPosition = currentlyDraggedObject.GetComponent<Moveable>().objectPosition;   
    }
    break;

and then later do the manipulation on the dragged object

case TouchPhase.Moved:
    if (currentlyDraggedObject)
    {
        Debug.Log("move " + " " + currentlyDraggedObject.name);
        currentlyDraggedObject.position = touchPos + initialDelta + Vector3.forward * initialPosition.z;
    }
    break;

case TouchPhase.Ended:   
    if(currentlyDraggedObject)
    {   
        if (Mathf.Abs(currentlyDraggedObject.position.x - objectPosition.position.x) <= snapdifficulty
            && Mathf.Abs(currentlyDraggedObject.position.y - objectPosition.position.y) <= snapdifficulty)
        {
             currentlyDraggedObject.position = new Vector3(objectPosition.position.x, objectPosition.position.y, initialPosition.z);
            correctPosition = true;
        }
        else
        {
            currentlyDraggedObject.position = new Vector3(initialPosition.x, initialPosition.y, initialPosition.z);
        }
    currentlyDraggedObject = null;
    }
    break;

Typed on smartphone but I hope the idea gets clear

Upvotes: 2

Related Questions