简体   繁体   English

2D弹道预测(unity 2D)

[英]2D Projectile Trajectory Prediction(unity 2D)

using (unity 2019.3.7f1) 2d.使用(统一 2019.3.7f1)2d。 I have a player that moves around using a pullback mechanic and has a max power(like in Angry Birds).我有一个玩家使用回撤机制四处移动并且具有最大功率(例如在愤怒的小鸟中)。 I'm trying to draw a line(using a line renderer) that shows the exact path the player will go.我正在尝试绘制一条线(使用线渲染器),以显示玩家将 go 的确切路径。 I'm trying to make the line curve just like the player's path will.我试图让线条曲线就像玩家的路径一样。 so far I've only managed to make a straight line in a pretty scuffed way.到目前为止,我只设法以一种非常磨损的方式制作一条直线。 The known variables are the Jump Power and the player's position, there is no friction.已知变量为 Jump Power 和玩家的 position,没有摩擦。 and I believe gravity is a constant(-9.81).我相信重力是一个常数(-9.81)。 Also, I would like to have a variable that allows me to control the line's length.另外,我想要一个变量来控制线条的长度。 And, if possible, the line will not go through objects and would act as if it has a collider.而且,如果可能的话,这条线不会 go 穿过物体,而是会像有一个对撞机一样工作。

// Edit // 编辑

This is my current code.这是我当前的代码。 I changed The function so it would return the list's points because I wanted to be able to access it in Update() so it would only draw while I hold my mouse button.我更改了 function 所以它会返回列表的点,因为我希望能够在 Update() 中访问它,所以它只会在我按住鼠标按钮时绘制。

My problem is that the trajectory line doesn't seem to curve, it goes in the right angle but it's straight.我的问题是轨迹线似乎没有弯曲,它成直角但它是直的。 the line draws in the right direction and angle, but my initial issue of the line not curving remains unchanged.这条线以正确的方向和角度绘制,但我最初的线不弯曲问题保持不变。 If you could please come back to me with an answer I would appreciate it.如果你能请回来给我一个答案,我将不胜感激。

enter code here

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TrajectoryShower : MonoBehaviour
{
LineRenderer lr;
public int Points;


public GameObject Player;

private float collisionCheckRadius = 0.1f;

public float TimeOfSimulation;

private void Awake()
{
    lr = GetComponent<LineRenderer>();
    lr.startColor = Color.white;
}

// Update is called once per frame
void Update()
{
    if (Input.GetButton("Fire1"))
    {
        lr.positionCount = SimulateArc().Count;

        for (int a = 0; a < lr.positionCount;a++)
        {
            lr.SetPosition(a, SimulateArc()[a]);
        }
    }
    if (Input.GetButtonUp("Fire1"))
    {
        lr.positionCount = 0;
    }
}

private List<Vector2> SimulateArc()
{
    float simulateForDuration = TimeOfSimulation;
    float simulationStep = 0.1f;//Will add a point every 0.1 secs.

    int steps = (int)(simulateForDuration / simulationStep);
    List<Vector2> lineRendererPoints = new List<Vector2>();
    Vector2 calculatedPosition;
    Vector2 directionVector = Player.GetComponent<DragAndShoot>().Direction;// The direction it should go
    Vector2 launchPosition = transform.position;//Position where you launch from
    float launchSpeed = 5f;//The initial power applied on the player

    for (int i = 0; i < steps; ++i)
    {
        calculatedPosition = launchPosition + (directionVector * ( launchSpeed * i * simulationStep));
        //Calculate gravity
        calculatedPosition.y += Physics2D.gravity.y * (i * simulationStep);
        lineRendererPoints.Add(calculatedPosition);
        if (CheckForCollision(calculatedPosition))//if you hit something
        {
            break;//stop adding positions
        }

    }

    return lineRendererPoints;



}
private bool CheckForCollision(Vector2 position)
{
    Collider2D[] hits = Physics2D.OverlapCircleAll(position, collisionCheckRadius);
    if (hits.Length > 0)
    {
        for (int x = 0;x < hits.Length;x++)
        {
            if (hits[x].tag != "Player" && hits[x].tag != "Floor")
            {
                return true;
            }
        }

    }
    return false;
}

} }

This is basically a sum of 2 vectors along the time.这基本上是 2 个向量的总和。

You have your initial position (x0, y0), initial speed vector (x, y) and gravity vector (0, -9.81) being added along the time.您会同时添加初始 position (x0, y0)、初始速度矢量 (x, y) 和重力矢量 (0, -9.81)。 You can build a function that gives you the position over time:您可以构建一个 function,随着时间的推移为您提供 position:

f(t) = (x0 + x*t, y0 + y*t - 9.81t²/2) 

translating to Unity:

Vector2 positionInTime(float time, Vector2 initialPosition, Vector2 initialSpeed){
    return initialPosition + 
           new Vector2(initialSpeed.x * t, initialSpeed.y * time - 4.905 * (time * time);
}

Now, choose a little delta time, say dt = 0.25 .现在,选择一点增量时间,例如dt = 0.25

   Time |            Position
0) 0.00 |  f(0.00) = (x0, y0)
1) 0.25 |  f(0.25) = (x1, y1)
2) 0.50 |  f(0.50) = (x2, y2)
3) 0.75 |  f(0.75) = (x3, y3)
4) 1.00 |  f(1.00) = (x4, y4)
   ...  |         ...

Over time, you have a lot of points where the line will cross.随着时间的流逝,您将有很多线会交叉的点。 Choose a time interval (say 3 seconds), evaluate all the points between 0 and 3 seconds (using f ) and put your line renderer to cover one by one.选择一个时间间隔(比如 3 秒),评估 0 到 3 秒之间的所有点(使用f ),然后让你的线渲染器一个接一个地覆盖。

The line renderer have properties like width, width over time, color, etc. This is up to you.线渲染器具有宽度、随时间变化的宽度、颜色等属性。这取决于您。

Here's a simple way to visualize this.这是一种可视化的简单方法。

To create your line you want a bunch of points.要创建你的线,你需要一堆点。

  • The points represents the player's positions after being fired after X amount of time.这些点代表玩家在 X 时间后被解雇后的位置。
  • The position of each point is going to be: DirectionVector * (launch speed * time elapse) + (GravityDirection * time elapse^2)每个点的 position 将是:DirectionVector * (发射速度 * time elapse) + (GravityDirection * time elapse^2)
  • You can decide in advance how far you pre calculate the points by simulating X duration and choosing the simulation step(calculate a point every X amount of time)您可以通过模拟 X 持续时间并选择模拟步骤来提前决定预计算点的距离(每 X 时间计算一个点)
  • To detect collision each time you calculate a point you can do a small circle cast at that location.要在每次计算一个点时检测碰撞,您可以在该位置进行一个小圆圈投射。 If it hits something you can stop add new points.如果遇到问题,您可以停止添加新点。
private float collisionCheckRadius = 0.1f;
        private void SimulateArc()
        {
            float simulateForDuration = 5f;//simulate for 5 secs in the furture
            float simulationStep = 0.1f;//Will add a point every 0.1 secs.

            int steps = (int)(simulateForDuration/simulationStep);//50 in this example
            List<Vector2> lineRendererPoints = new List<Vector2>();
            Vector2 calculatedPosition;
            Vector2 directionVector = new Vector2(0.5f,0.5f);//You plug you own direction here this is just an example
            Vector2 launchPosition = Vector2.zero;//Position where you launch from
            float launchSpeed = 10f;//Example speed per secs.

            for(int i = 0; i < steps; ++i)
            {
                calculatedPosition = launchPosition + ( directionVector * (launchSpeed * i * simulationStep));
                //Calculate gravity
                calculatedPosition.y += Physics2D.gravity.y * ( i * simulationStep) *  ( i * simulationStep);
                lineRendererPoints.Add(calculatedPosition);
                if(CheckForCollision(calculatedPosition))//if you hit something
                {
                    break;//stop adding positions
                }
            }

            //Assign all the positions to the line renderer.
        }
        private bool CheckForCollision(Vector2 position)
        {
            Collider2D[] hits = Physics2D.OverlapCircleAll(position, collisionCheckRadius);
            if(hits.Length > 0)
            {
                //We hit something 
                //check if its a wall or seomthing
                //if its a valid hit then return true
                return  true;
            }
            return false;
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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