【问题标题】:Drag an object with touch and flick to throw it?通过触摸拖动对象并轻弹以将其扔掉?
【发布时间】:2015-10-11 01:07:27
【问题描述】:

我试图让用户通过触摸在屏幕上拖动对象并抬起手指以使对象朝它们移动的方向“飞走”。

这就是我正在尝试的。

    Vector3 touchPosition = Camera.main.ScreenToWorldPoint (Input.mousePosition);
    Vector3 newPosition = new Vector3 (touchPosition.x, touchPosition.y, transform.position.z);
    velocity = newPosition - transform.position;

    // User is dragging the object around
    if(Input.GetMouseButton(0)) {
        transform.position = Vector2.Lerp(transform.position, newPosition, Time.deltaTime * 25f);
    }

    // User lifts finger
    if (Input.GetMouseButtonUp (0)){
            transform.GetComponent<Rigidbody2D>().AddForce(velocity, ForceMode2D.Force); // Also tried with transform.GetComponent<Rigidbody2D>().velocity = velocity; and transform.position += velocity; // The later works but doesn't allow for physics later on
        }

使用这种方法,对象在拖动时似乎具有低帧速率。此外,当滑动/轻拂对象时,它并不总是保持正确的方向,而且它飞得很慢(我可能必须将它乘以与每秒更新次数相关的因子,但我不确定)。

知道如何使这项工作顺利进行吗?

编辑

我在轻弹对象时通过使用最后几帧的对象速度的平均值来校正方向,但是我仍然无法获得正确的速度。拖动时它​​的帧率仍然很低(这可以通过使用物理方法而不是直接写入位置来纠正吗?)

【问题讨论】:

  • 我在回答中添加了官方来源。

标签: unity3d physics


【解决方案1】:

您可以在拖动对象时计算速度,并在释放对象后继续应用它。

Vector3 velocity;
..
void Update() {  
    if(Input.GetMouseButton(0)){
        Vector3 touchPosition = Camera.main.ScreenToWorldPoint (Input.mousePosition);
        velocity = new Vector3 (touchPosition.x, touchPosition.y, transform.position.z) - transform.position;
    }
    transform.position += velocity;
}

编辑:

如果您希望您的对象在被拖动时仅受触摸位置的影响,您可以在刚体上设置isKinematic = true 并设置其位置 直接地。否则,您可以更新速度,使对象向触摸位置移动。 最后在 MouseButtonUp 上将速度设置为最后一帧的平均速度(如果拖动持续超过 10 帧,则最多为 10)。

..        
    private PositionQueue pastPositions; 
    void Awake(){
        pastPositions = new PositionQueue(10);
    }

    void Update(){
        Vector3 touchPosition = Camera.main.ScreenToWorldPoint (Input.mousePosition);
        Vector3 newPosition = new Vector3 (touchPosition.x, touchPosition.y, transform.position.z);

        if(Input.GetMouseButtonDown(0)){
            //transform.GetComponent<Rigidbody2D>().isKinematic=true;  
            pastPositions.Clear();
        }
        // User is dragging the object around
        if(Input.GetMouseButton(0)) {   
            pastPositions.Enqueue(newPosition);
            //transform.position = newPosition;                      
            //transform.position = Vector2.Lerp(transform.position, newPosition, Time.deltaTime * 25f);
            transform.GetComponent<Rigidbody2D>().velocity = (newPosition - transform.position) * 10;
        }
        if (Input.GetMouseButtonUp (0)){
            //transform.GetComponent<Rigidbody2D>().isKinematic = false;   
            velocity = (newPosition - pastPositions.Peek()) / pastPositions.Count;
            transform.GetComponent<Rigidbody2D>().velocity = velocity * 20; // Also tried with transform.GetComponent<Rigidbody2D>().velocity = velocity; and transform.position += velocity; // The later works but doesn't allow for physics later on
        }
    }
}

class PositionQueue{
    private Queue<Vector3> _queue;
    private int _maxSize;
    public int Count {
        get {
            return _queue.Count;
        }
    }
    public PositionQueue(int maxSize){
        _maxSize = maxSize;
        _queue = new Queue<Vector3>();
    }
    public void Enqueue(Vector3 v){
        if(_queue.Count>=_maxSize){
            _queue.Dequeue();
        }
        _queue.Enqueue(v);
    }
    public Vector3 Peek(){
        return _queue.Peek();
    }
    public void Clear(){
        _queue.Clear();
    }
}

【讨论】:

  • 嗨@plutoo 这似乎接近我想做的事情。我的主要问题是改变位置不会改变速度,这会导致事后知道物体在哪里移动并对其施加力。我试过 transform.GetComponent().velocity = velocity;在 Input.GetMouseButton(0) 内部,但它的移动速度似乎比实际应该慢。我需要将速度与某个特定变量相乘吗?
  • transform.position =new Vector3 (touchPosition.x, touchPosition.y, transform.position.z); inside if(Input.GetMouseButton(0)) 应该将对象保持在鼠标位置。在您可以使用来自velocityif(Input.GetMouseButtonUp(0)){ 的信息添加一些力或修改速度之后。这个想法是在您拖动对象时计算移动方向和强度(可能在多个帧上),然后在您释放时施加力。
  • 嗨@Pluto,这很接近我想要的。我设法获得了最后几帧物体的平均速度,以使其更可靠。我的问题是我不喜欢直接改变位置,我怎样才能对物体施加力或写入速度呢?
  • 我编辑了答案。我不确定您是想将对象传送到触摸位置还是在拖动时朝它移动。
  • 嗨@Pluto 我不明白为什么速度要乘以20。在我的测试中,保持物体速度的最佳方法是将其乘以30。我认为这是因为这是帧速率.会不会是错的?
【解决方案2】:

如果你的意思是通过“销毁”来“释放”它,请使用

gameObject.SetActive(false); //Or 
Destroy(gameObject);

如果你想保持它当前的移动速度:

rigidbody.velocity = new Vector3(x,y,z); //or alternatively:
rigidbody.AddRelativeForce (new Vector(x,y,z));

【讨论】:

  • 嗨@David 释放我的意思是举起手指。我想做的是让它保持抬起手指时的移动速度。问题是,由于我是直接改变位置,所以对象并没有真正的速度,所以我不知道该怎么做。
【解决方案3】:

您可以使用 Input.GetTouch(i) 中的信息根据手指移动来移动对象,然后应用速度。

根据手指移动移动和轻弹场景对象

[SerializeField] float speedMultiplier = 1f;

void Update() {

    for (var i = 0; i < Input.touchCount; i++) {

        Touch touch = Input.GetTouch(i);

        if (touch.phase == TouchPhase.Moved) {

            transform.position = touch.position;

        } else if (touch.phase = TouchPhase.Ended) {

            velocity = touch.deltaPosition.magnitude / touch.deltaTime * speedMultiplier;

        }

    }    

}

来源:http://docs.unity3d.com/ScriptReference/Input.GetTouch.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多