简体   繁体   中英

How can I drag any object around with the mouse without holding the mouse left button down?

I want that once the clicking on the object one time then I will be able to drag the object around with the mouse without holding down the left mouse button. Then next time making one click on the mouse left button it will drop the object.

Now I must hold down the mouse left button.

using System;
using System.Collections;
using UnityEngine;

namespace UnityStandardAssets.Utility
{
    public class DragRigidbody : MonoBehaviour
    {
        const float k_Spring = 50.0f;
        const float k_Damper = 5.0f;
        const float k_Drag = 10.0f;
        const float k_AngularDrag = 5.0f;
        const float k_Distance = 0.2f;
        const bool k_AttachToCenterOfMass = false;

        private SpringJoint m_SpringJoint;


        private void Update()
        {
            // Make sure the user pressed the mouse down
            if (!Input.GetMouseButtonDown(0))
            {
                return;
            }

            var mainCamera = FindCamera();

            // We need to actually hit an object
            RaycastHit hit = new RaycastHit();
            if (
                !Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition).origin,
                                 mainCamera.ScreenPointToRay(Input.mousePosition).direction, out hit, 100,
                                 Physics.DefaultRaycastLayers))
            {
                return;
            }
            // We need to hit a rigidbody that is not kinematic
            if (!hit.rigidbody || hit.rigidbody.isKinematic)
            {
                return;
            }

            if (!m_SpringJoint)
            {
                var go = new GameObject("Rigidbody dragger");
                Rigidbody body = go.AddComponent<Rigidbody>();
                m_SpringJoint = go.AddComponent<SpringJoint>();
                body.isKinematic = true;
            }

            m_SpringJoint.transform.position = hit.point;
            m_SpringJoint.anchor = Vector3.zero;

            m_SpringJoint.spring = k_Spring;
            m_SpringJoint.damper = k_Damper;
            m_SpringJoint.maxDistance = k_Distance;
            m_SpringJoint.connectedBody = hit.rigidbody;

            StartCoroutine("DragObject", hit.distance);
        }


        private IEnumerator DragObject(float distance)
        {
            var oldDrag = m_SpringJoint.connectedBody.drag;
            var oldAngularDrag = m_SpringJoint.connectedBody.angularDrag;
            m_SpringJoint.connectedBody.drag = k_Drag;
            m_SpringJoint.connectedBody.angularDrag = k_AngularDrag;
            var mainCamera = FindCamera();
            while (Input.GetMouseButton(0))
            {
                var ray = mainCamera.ScreenPointToRay(Input.mousePosition);
                m_SpringJoint.transform.position = ray.GetPoint(distance);
                yield return null;
            }
            if (m_SpringJoint.connectedBody)
            {
                m_SpringJoint.connectedBody.drag = oldDrag;
                m_SpringJoint.connectedBody.angularDrag = oldAngularDrag;
                m_SpringJoint.connectedBody = null;
            }
        }


        private Camera FindCamera()
        {
            if (GetComponent<Camera>())
            {
                return GetComponent<Camera>();
            }

            return Camera.main;
        }
    }
}

Instead of

while(Input.GetMouseButton(0))

use

while(!Input.GetMouseButtonDown(0))

Then you still have to catch whether you maybe are already dragging and skip in this case the begining of a drag.

Eg with a book like

bool isDragging;

private void Update()
{
    if(!Input.GetMouseButtonDown(0) || isDragging) return;

    ...

}

private IEnumerator DragObject()
{
    isDragging = true;

    ...

    while(!Input.GetMouseButtonDown(0))
    {
        ...
    }

    ...


    isDragging = false;
}

Further note: Usage of Camera.main or even worse GetComponent repeatedly is quite inefficient. Rather store the result once and reuse it:

// If possible already reference it via the Inspector!
[SerializeField] private Camera mainCamera;

// Or get and store it once 
private void Awake ()
{
    FetchComponents ();
}

// Little pro tip ;)
// using this you can already in the Inspector click on the context menu 
// and click on "FetchComponents"
// this way you don't have to sear for it manually
// and additionally you can see if it works as expected
[ContextMenu (nameof(FetchComponents))]
private void FetchComponents ()
{
    if(!mainCamera) mainCamera = GetComponent<Camera>();
    if(!mainCamera) mainCamera = Camera.main;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM