将抓取物理从处理转换为统一以获取不同的结果 [英] Translated grapple physics from Processing to Unity to get different results

查看:91
本文介绍了将抓取物理从处理转换为统一以获取不同的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

tl; dr 将我的游戏从处理移到Unity.即使基本上已复制/粘贴,但通过手动更改播放器速度来进行抓取的代码也无法正常工作.

tl;dr Moving my game from Processing to Unity. Code responsible for grappling by manually changing the player's velocity doesn't work even though it's basically copy/pasted.

我在整个夏天都在处理我的一个项目,而上周我决定将其转换为Unity.

Hi, I've been working on a project of mine over the summer on Processing, and last week I decided to translate it over to Unity.

我遇到的问题是抓斗/绳索物理.基本上应该将玩家保持在一个圆圈内(由绳索的端点和绳索的长度组成).当游戏者落入该圆的外部时,其位置将移回该圆的边缘,并且将游戏者的速度设置为该圆的切线.

What I'm having a problem with is the grapple/rope physics. It's supposed to essentially keep the player inside a circle (made by the endpoint of the rope and the length of the rope). When the player falls outside of this circle, the player's position is moved back to the edge of the circle and the player's velocity is set to tangent of the circle.

摆动时减少绳子的长度应该可以加快速度. (请参见浮点数)

Decreasing the length of the rope while swinging is supposed to speed you up. (See Floating Point)

在处理中,它如上所述完全可以正常工作,但是当我基本上将代码复制/粘贴到一个统一代码中时,它失去的动力就太快了(总是最终以玩家开始的另一侧以相同的角度停下来).这是两者的代码(在每个物理框架上运行):

On Processing, it works perfectly just as described above, but when I basically copy/pasted the code into unity it loses momentum too quickly (always ends up stopping at the same angle on the other side the player started on). Here is the code for both (run on each physics frame):

(我还制作了一些图像来描述两个版本产生的运动)

(I've also made some images to describe the motion that both versions produce)

(警告:错误和多余)

物理更新:

exists = (endPoint != null);
if(lgth<=0) lgth = 1;
if(exists) {
  currentLength = phs.position.dist(endPoint);
  if(currentLength > lgth) {
    float angle = getAngle(endPoint, phs.position);
    phs.addPosition(abs(currentLength - lgth), angle);
    float angleBetween = getAngle(phs.position, endPoint);
    PVector relativeVelocity = new PVector(phs.velocity.x + phs.position.x, phs.velocity.y + phs.position.y);
    float displacement = angleBetween - 90;

    Line l1 = lineFromTwoPoints(relativeVelocity, endPoint);
    Line l2 = lineFromAngle(phs.position, displacement);
    PVector pointToLerpTo = intersection(l1, l2);
    if(pointToLerpTo!=null) {
      phs.velocity.x = pointToLerpTo.x-phs.position.x;
      phs.velocity.y = pointToLerpTo.y-phs.position.y;
    }
    else phs.velocity.mult(0);
  }
}

当玩家缩短绳索时,速度会提高:

when the player shortens the rope, speed increases:

if(exists) {
  float newLgth = lgth-d;
  float distance = getDistance(phs.position, endPoint);
  if(distance > newLgth) {
    float ratio = (distance-newLgth)/lgth;
    phs.velocity.setMag(phs.velocity.mag()*(1+ratio));
  }
  lgth = newLgth;
}

处理中的动作(良好)

玩家通过在绳索圆的左边缘向下移动开始.不会失去速度,并且会持续多次旋转,直到重力将其放慢.

以上两个代码块都在同一位置的FixedUpdate()下处理(问题部分似乎是速度部分)

both code blocks from above are handled in the same place here, under FixedUpdate() (problematic part seems to be the velocity section)

distance = Vector2.Distance(transform.position, endpoint);
if(connected && distance > length) {
    //lerp position -> endpoint// keep gameObject within length of the rope
    float posLerpAmount = (distance - length) / distance;
    transform.position = Vector2.Lerp(transform.position, endpoint, posLerpAmount);

    //'lerp' velocity -> endpoint// keep the velocity locked to the tangent of the circle around the endpoint
    Vector2 relativeVelocity = GetComponent<Rigidbody2D>().velocity + (Vector2)transform.position;
    Line l1 = Geometry.LineFromTwoPoints(relativeVelocity, endpoint);
    Line l2 = Geometry.LineFromAngle(transform.position, Geometry.GetAngle(endpoint, transform.position) - 90);
    if(!Geometry.AreParallel(l1, l2)) {
        Vector2 pointToLerpTo = Geometry.Intersection(l1, l2) - (Vector2)transform.position;
        GetComponent<Rigidbody2D>().velocity = pointToLerpTo;
    }
    else GetComponent<Rigidbody2D>().velocity = new Vector2(0, 0);

    //increases the magnitude of the velocity based on how far the rope moved the object's position
    float ratio = (distance - length) / length;
    GetComponent<Rigidbody2D>().velocity *= 1 + ratio;

    distance = length;
}

来自Unity的运动(错误)

玩家通过在绳索圆的左边缘向下移动开始.通过重力获得一点点速度,然后将始终在其开始的另一侧停止45度(与开始速度无关),然后缓慢回落到圆的底部.

如果有人需要我解释Geometry类(直线,交点),那么我可以,但是我认为这基本上是不言而喻的.否则,我想我会尽力而为.预先感谢您的帮助.

If anyone needs me to explain the Geometry class (lines, intersections) then I can, but I think it's mostly self-explanatory. Otherwise, I think I explained this the best I could. Thanks in advance for any help.

(而且,StackOverflow不允许我添加Unity2d标签,所以我想我必须适应Unity3d)

(also, StackOverflow isn't letting me add the Unity2d tag so I guess I gotta settle for Unity3d)

推荐答案

我发现Rigidbody2D.velocity.magnitude不是 ,它每次物理更新都会使对象移动多远.这就是造成此问题的原因,因为处理代码基于每次更新时直接将速度添加到位置的速度.

I found out that Rigidbody2D.velocity.magnitude is not how far the object moves every physics update. This is what was causing the issue, because the Processing code was based off the velocity being added directly to the position every update.

要解决此问题,我所做的是使用相同的几何形状,但是将速度缩放为实际使用"了多少速度的百分比(通常行进实际速度矢量的2%).

To fix this, what I did was do the same geometry, but scale the velocity to the % of how much of the velocity was actually 'used' (it usually travels 2% of the actual velocity vector).

这是Unity中的最终代码:(这一次我显示填充FixedUpdate(),其中不相关的部分已删除)

Here is the final code in Unity: (this time I'm showing the fill FixedUpdate(), with the irrelevant parts removed)

float lastMagnitude;
Vector2 lastPosition;
void FixedUpdate() {
    float velocityMoved = Vector2.Distance(lastPosition, transform.position) / lastMagnitude;
    Debug.Log(velocityMoved * 100 + "%"); //this is usually 2%

    bool shortenedRope = false;
    if(Input.GetButton("Shorten Rope")) {
        shortenedRope = true;
        length -= ropeShortenLength;
    }

    distance = Vector2.Distance(transform.position, endpoint);
    if(connected && distance > length) {
        //lerp position -> endpoint// keep gameObject within length of the rope
        float posLerpAmount = (distance - length) / distance;
        transform.position = Vector2.Lerp(transform.position, endpoint, posLerpAmount);

        //'lerp' velocity -> endpoint// keep the velocity locked to the tangent of the circle around the endpoint
        Vector2 adjustedVelocity = rigidbody.velocity * velocityMoved;
        Vector2 relativeVelocity = adjustedVelocity + (Vector2)transform.position;
        Line l1 = Geometry.LineFromTwoPoints(relativeVelocity, endpoint);
        Line l2 = Geometry.LineFromAngle(transform.position, Geometry.GetAngle(endpoint, transform.position) - 90);
        if(!Geometry.AreParallel(l1, l2)) {
            Vector2 pointToLerpTo = Geometry.Intersection(l1, l2) - (Vector2)transform.position;
            rigidbody.velocity = pointToLerpTo;
            rigidbody.velocity /= velocityMoved;
        }
        else rigidbody.velocity = new Vector2(0, 0);

        //'give back' the energy it lost from moving it's position
        if(shortenedRope) {
            float ratio = (distance - length) / length;
            rigidbody.velocity *= 1 + ratio;
        }

        distance = length;
    }
    lastPosition = transform.position;
    lastMagnitude = rigidbody.velocity.magnitude;
}

最近了解到,最好使用Time.deltaFixedTime代替我制作的velocityMoved变量,因为已经计算了Time.deltaFixedTime.

Recently learned that it is better to use Time.deltaFixedTime instead of the variable I made velocityMoved, since Time.deltaFixedTime is already calculated.

这篇关于将抓取物理从处理转换为统一以获取不同的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆