逼真的 BOAT/SHIP 运动和旋转 (2d)

Posted

技术标签:

【中文标题】逼真的 BOAT/SHIP 运动和旋转 (2d)【英文标题】:Realistic BOAT/SHIP movement and rotation (2d) 【发布时间】:2017-01-10 19:05:19 【问题描述】:

我想通过逼真的运动和旋转将我的船移动到我点击的位置:

(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前进。旋转船,使其可以接近目的地。 (如果您边移动边转动,旋转的精确算法将是问题中最难解决的部分。) 【参考方案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;
    

当然,IEnumerator 的调用方式如下:

StartCoroutine(TurnShip(new Vector3(12f, 1f, 23f));

注意几点:

    这是伪代码,我没有测试过它,所以只要知道让它工作取决于你,我只是为你提供正确的路径。

    李>

    方法开头的所有变量都是全局变量,所以在你喜欢的地方声明它们。

【讨论】:

非常感谢您详细的回答,我会尽力使其正常工作并尽快回复您 无论我尝试什么(使用或不使用 Vector3),它都会告诉我:“静态成员 `UnityEngine.Vector3.forward' 不能通过实例引用访问,而是使用类型名称来限定它”,我的代码: RigidBody.AddForce(new Vector3(targetPosition.x, targetPosition.y, targetPosition.z).forward * speed * Time.deltaTime); forward 是一个静态字段。要调用forward,您只能这样做:Vector3.forward 我只是再次尝试,没有用我的目标 Vector3 替换“transform.forward”,我没有任何错误,但是船没有移动,也没有改变轴,这里是代码:float speed = 150f; Rigidbody2D rb = GetComponent&lt;Rigidbody2D&gt;(); Transform transform = GetComponent&lt;Transform&gt;(); rb.AddForce(transform.forward * speed * Time.deltaTime);我当然禁用“运动学”并且质量为 1 把速度设为150000000,看看有没有区别。它可能只是移动得非常缓慢【参考方案2】:

我在这里使用了一个名为 target 的变换,只需单击鼠标将其替换为 Vector。

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:i.imgur.com/EO37TVq.gif 只需操作 Vector3 newDir 例如Vector3 zRotOnly = new Vector3(0,0,newDir.y),或者你的游戏使用的任何轴方向。 我明白了,但是当我这样做时,它确实只会改变 Z 轴,但会改变“位置”而不是“旋转”Vector3 newDir = Vector3.RotateTowards(transform.forward, targetDir, step, 0.0f); Vector3 zRotOnly = new Vector3 (0, 0, newDir.y); transform.rotation = Quaternion.LookRotation(zRotOnly);【参考方案3】:

声明

    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,他帮助了我并花了很多时间试图找出解决方案。

【讨论】:

以上是关于逼真的 BOAT/SHIP 运动和旋转 (2d)的主要内容,如果未能解决你的问题,请参考以下文章

苹果运动图形软件Apple Motion 5.4.2 MacOSX 中文/英文/多语言破解版

Cocos2D 与 iOS6 错误旋转

第223期软件苹果运动图形软件Apple Motion 5.4.2 MacOSX 中文/英文/多语言破解版

Cocos2d-x怎样控制动作速度

Swift SpriteKit:创建逼真的 2D 驾驶体验

视觉SLAM三维空间刚体运动的描述