找到一个角度来发射弹丸以到达特定点 [英] Find an angle to launch the projectile at to reach a specific point

查看:72
本文介绍了找到一个角度来发射弹丸以到达特定点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,Dani 在他的新视频中 ->《做游戏,但我只有3天》(https://youtu.be/S7Dl6ATRK2M) 制造了一个有弓箭的敌人(在 5:39).我试图重新创建它,但没有运气......我也找不到他使用的网站......今天我发现了这个 https://physics.stackexchange.com/questions/56265/how-获得所需的角度的射弹通过一个给定的点.它工作得很好,但如果目标很远,它仍然会出现问题,而且它也不那么准确.到目前为止的代码是

So, Dani in his slightly new video -> "Making a Game, But I Only Have 3 Days" (https://youtu.be/S7Dl6ATRK2M) made a enemy which has a bow and arrow (at 5:39). I tried to recreate that but had no luck... I also can't find the website that he used... Today I found this https://physics.stackexchange.com/questions/56265/how-to-get-the-angle-needed-for-a-projectile-to-pass-through-a-given-point-for-t. It worked very well but still had problems if the target was far away and also it wasn't as accurate. The code so far is

float CalculateAngle()
    {
        float gravity = Physics.gravity.magnitude;
        float deltaX = targetPositionMod.x - currentPosition.x;
        float deltaY = targetPositionMod.y - currentPosition.y;
        float RHSFirstPart = (velocity * velocity) / (gravity * deltaX);
        float RHSSecondPart = Mathf.Sqrt(
                ((velocity * velocity) * ((velocity * velocity) - (2 * gravity * deltaY)) 
                                / (gravity * gravity * deltaX * deltaX))
                                                - 1);
        float tanθ = RHSFirstPart - RHSSecondPart;
        float angle = Mathf.Atan2(tanθ, 1) * Mathf.Rad2Deg;
        if (angle < 0) return angle;
        return -angle;
    }

-angle 是因为当 x 旋转为负 (Unity) 时,前向轴开始指向上方.也许这没有按预期工作的原因是我不太擅长这种物理(部分原因是我只有 14 岁).也许问题出在代码上,也可能出在公式上.任何帮助表示赞赏.

The -angle is because the forward axis starts points up when the x-rotation is negative (Unity). Maybe the reason of this not working as intended is that I am not that good at this kind of Physics (Part of that is me being only 14). Maybe the problem is in the code, maybe it is the formula. Any help is appreciated.

谢谢...

Archer 类是:

using UnityEngine;
using System;
public class Archer : MonoBehaviour
{
    [SerializeField] float velocity = default;
    [SerializeField] Transform target = default;
    [SerializeField] GameObject arrowPrefab = default;
    [SerializeField] float coolDown = default;
    Vector3 targetPositionMod;
    Vector3 currentPosition;
    Vector3 targetPosition;
    float countDown = 0f;

    void Start()
    {
        countDown = coolDown;
        UpdateVariables();
    }

    void Update()
    {
        UpdateVariables();
        SetAngle();
        ShootBullet();
    }
    
    void UpdateVariables()
    {
        currentPosition = transform.position;
        targetPositionMod = Mod(target.position);
        targetPosition = target.position;
        targetPosition.x /= 10;
        targetPosition.y /= 10;
        targetPosition.z /= 10;
        countDown -= Time.deltaTime;
    }

    void SetAngle()
    {
        Vector3 direction = targetPosition - currentPosition;
        Quaternion lookRotation = Quaternion.LookRotation(direction);
        Vector3 rotation = lookRotation.eulerAngles;
        rotation.x = (float) CalculateAngle();
        transform.rotation = Quaternion.Euler(rotation.x, rotation.y, 0f);
    }

    void ShootBullet()
    {
        if (!(countDown <= 0f)) return;
        countDown = coolDown;
        GameObject arrow = Instantiate(arrowPrefab, transform.position, transform.rotation);
        Rigidbody Rigidbody = arrow.GetComponent<Rigidbody>();
        Rigidbody.AddForce(transform.forward * velocity, ForceMode.Impulse);
    }

    double CalculateAngle()
    {
        double gravity = Physics.gravity.magnitude;
        double deltaX = targetPositionMod.x - currentPosition.x;
        double deltaY = targetPositionMod.y - currentPosition.y;
        double RHSFirstPart = (velocity * velocity) / (gravity * deltaX);
        double RHSSecondPart = Math.Sqrt(
                (((velocity * velocity) * ((velocity * velocity) - (2 * gravity * deltaY)) 
                                / (gravity * gravity * deltaX * deltaX))
                                                - 1));
        double tanθ = RHSFirstPart - RHSSecondPart;
        double angle = Math.Atan2(tanθ, 1) * Mathf.Rad2Deg;
        if (angle < 0) return angle;
        return -angle;
    }
    
    Vector3 Mod(Vector3 Vec)
    {
        if (Vec.x < 0) Vec.x -= 2 * Vec.x;
        if (Vec.y < 0) Vec.y -= 2 * Vec.y;
        if (Vec.z < 0) Vec.z -= 2 * Vec.z;
        Vec.x /= 10;
        Vec.y /= 10;
        Vec.z /= 10;
        return Vec;
    }
}

推荐答案

好的,正如我所见,您从 StackExchange 中实现的公式是正确的,但您必须记住两件事:

Ok, as I can see, your implementation of formula from StackExchange is right, but you have to remember two things:

  1. 在 unity 中有一个 3D 世界,所以水平距离不仅仅是 pos1.x - pos2.x,而是Mathf.Sqrt(deltaX * deltaX + deltaZ * deltaZ),其中 deltaX = targetPositionMod.x - currentPosition.xdeltaZ = targetPositionMod.z - currentPosition.z
  2. 在计算机实现中,您没有 100% 的数学准确度,因此可能会因为计算准确度而出现一些问题.它可能对远距离产生影响.您可以尝试使用 double 而不是 float 或找到反正切函数的另一种实现(我认为,这真的很有帮助).但是只有在第一个没有帮助的情况下才尝试这个(第二个)建议.它更难实现,并且会稍微减慢计算速度.
  1. In unity there is a 3D world, so horizontal distance is not just pos1.x - pos2.x, but Mathf.Sqrt( deltaX * deltaX + deltaZ * deltaZ ), where deltaX = targetPositionMod.x - currentPosition.x and deltaZ = targetPositionMod.z - currentPosition.z
  2. In computer implementation you have no 100% accuracy of math, so some problems can appear because of computational accuracy. And it can have affect on big distances. You can try to use double instead of float or find another implementation for arctangent function (I think, this can really help). But try this (second) advice only if first didn't help. It's harder to implement and it slows computations a bit.

这篇关于找到一个角度来发射弹丸以到达特定点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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