现实的船只移动和旋转(2D)

5
我希望将我的船移动到我点击的位置,但要实现逼真的运动和旋转:

enter image description here

(http://i.imgur.com/Pk8DOYP.gif)

这是我的代码(附加到我的船游戏对象上):

基本上,当我点击某个位置时,它会移动船直到它到达我最初点击的点(我为您简化了我的代码)。

using UnityEngine;
using System.Collections;


public class BoatMovement : MonoBehaviour {

    private Vector3 targetPosition;

    private float speed = 10f;
    private bool isMoving;


    void Update(){

        if (!isMoving && Input.GetMouseButton (0)) {

            targetPosition = Camera.main.ScreenToWorldPoint (Input.mousePosition);
            isMoving = true;
        } 


        if (isMoving) {
            moveToPosition ();
        }
    }

    void  moveToPosition() {


        transform.position = Vector3.MoveTowards (transform.position, new Vector3(targetPosition.x, targetPosition.y, 0f), speed * Time.deltaTime);

        if (transform.position.x == targetPosition.x && transform.position.y == targetPosition.y) {
            isMoving = false;
        }

    }
}

经过一番研究和尝试,我并没有找到想要实现的方法。感谢您的帮助。

那么,你应该做的第一件事就是沿着飞船的 transform.forward 前进。旋转飞船以便接近目的地。(如果你在移动时进行转向,则旋转的确切算法将是解决问题最困难的部分。) - Serlite
3个回答

1

这个问题有两个部分,它们应该完全分开,并且在任何时候一个方程式的等式都不会干扰另一个方程式的等式。

第一个是船的前进运动,可以通过两种方式实现:

如果您正在使用刚体

void Propel()
{
    float speed = 150f;
    RigidBody rb = GetComponent<RigidBody>();
    Transform transform = GetComponent<Transform>();
    rb.AddForce(transform.forward * speed * Time.deltaTime); // <--- I always forget if its better to use transform.forward or Vector3.forward. Try both
}

如果没有刚体。
void Propel()
{
    float speed = 150f;
    Transform transform = GetComponent<Transform>();
    transform.Translate(transform.forward * speed * Time.deltaTime, Space.World);
}

现在第二步是转向船只,这也可以通过两种方式实现:

使用刚体

IEnumerator TurnShip(Vector3 endAngle)
{
    float threshold = Single.Epsilon;
    float turnSpeed = 150f;
    RigidBody rb = GetComponent<RigidBody>();
    while (Vecotr3.Angle(transform.forward, endAngle) > threshold)
    {
        rb.AddTorque(transform.up * turnSpeed * Time.deltaTime);
        yield return null;
    }
}

没有刚体。
IEnumerator TurnShip(Vector3 endAngle)
{
    float threshold = Single.Epsilon;
    float turnSpeed = 150f;
    float step = turnSpeed * Time.deltaTime;
    while (Vector3.Angle(transform.forward, endAngle) > threshold)
    {
        newDir = Vector3.RotateTowards(transform.forward, endAngle, step);
        transform.rotation = Quaternion.LookRotation(newDir);
        yield return null;
    }
}

当然,IEnumerators 被这样调用:
StartCoroutine(TurnShip(new Vector3(12f, 1f, 23f));

需要注意的几点:

  1. 这是伪代码,我没有测试过任何内容,所以要让它工作取决于你,我只提供正确的路径。

  2. 方法开头的所有变量都应该是全局变量,因此请在您认为合适的地方声明它们。


非常感谢您详细的回答,我会尽快尝试让它工作并与您联系。 - Owow
无论我尝试什么(使用Vector3或不使用),它都告诉我:“无法使用实例引用访问静态成员UnityEngine.Vector3.forward,请改用类型名称进行限定”,我的代码如下:RigidBody.AddForce(new Vector3(targetPosition.x, targetPosition.y, targetPosition.z).forward * speed * Time.deltaTime); - Owow
forward是一个静态字段。要调用forward,你只能这样做:Vector3.forward - maraaaaaaaa
我刚刚尝试了一下,没有用我的目标Vector3替换"transform.forward",没有出现任何错误,但是船没有移动,也没有改变任何轴,这是代码:float speed = 150f; Rigidbody2D rb = GetComponent<Rigidbody2D>(); Transform transform = GetComponent<Transform>(); rb.AddForce(transform.forward * speed * Time.deltaTime); 我当然禁用了"is kinematic"并且质量为1。 - Owow
将速度设置为150000000,看看是否有区别。可能只是移动得非常缓慢。 - maraaaaaaaa
显示剩余4条评论

0

我在这里使用了一个名为target的转换器,只需将其替换为从鼠标点击获取的向量即可。

public Transform target;

private void Update()
{

    transform.position += transform.forward * Time.deltaTime;
    Vector3 targetDir = target.position - transform.position;
    float step = Time.deltaTime / Mathf.PI;
    Vector3 newDir = Vector3.RotateTowards(transform.forward, targetDir, step, 0.0f);
    transform.rotation = Quaternion.LookRotation(newDir);

}

关键在于RotateTowards函数以及根据当前位置计算每帧要朝向的新向量。
如果你的船有某种旋转速度属性,那么修改名为step的浮点数以适应。如果它们有速度属性,则使用一些乘数修改transform.position += transform.forward * Time.deltaTime。
我猜你会想要加入一些条件来停止移动和旋转,也许可以使用协程。

好的,看起来它正在工作!!但是我如何只旋转Z轴?因为我在2D中(从俯视图,就像我的例子),这是实际发生的GIF:http://i.imgur.com/EO37TVq.gif - Owow
只需操作 Vector3 newDir,例如 Vector3 zRotOnly = new Vector3(0,0,newDir.y),或者根据您的游戏使用的轴方向进行调整。 - Absinthe
我明白了,但是当我这样做时,它确实只会改变Z轴,而不是“位置”而是“旋转”。 Vector3 newDir = Vector3.RotateTowards(transform.forward, targetDir, step, 0.0f); Vector3 zRotOnly = new Vector3 (0, 0, newDir.y); transform.rotation = Quaternion.LookRotation(zRotOnly); - Owow

0

声明

    private Vector3 targetPosition;
    private float targetDistance;

然后在你的移动开始时,执行:

    targetPosition = Camera.main.ScreenToWorldPoint (Input.mousePosition);
    targetDistance = Vector3.Distance(targetPosition, transform.position);

在移动时调用此函数:(例如在您的更新循环中)

    turnSpeed = 0.062f * targetDistance;
    moveSpeed = 35f * targetDistance;

    //Important /!\ : you need to add Linear drag on your rigidbody or it will keep adding
    RigidBody.AddForce(transform.up * moveSpeed * Time.deltaTime); 

    var newRotation = Quaternion.LookRotation (transform.position - targetPosition, Vector3.forward);
    newRotation.x = 0f;
    newRotation.y = 0f;
    transform.rotation = Quaternion.Slerp (transform.rotation, newRotation, Time.deltaTime * turnSpeed);

最后,将线性阻力值添加到刚体中(1就可以了)。

感谢maksymiuk的帮助,他花费了很多时间来寻找解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接