找到一个角度和速度来发射弹丸以到达特定点

问题描述

我正在尝试制造能射击Unity中3D世界中目标的大炮...我有一个LaunchConfig枚举->

public enum LauncherConfig
{
    CalculateNone = 0,CalculateAngle = 1,CalculateVelocity = 2,CalculateBoth = 3
}

选择CalculateAngle时,用户可以输入弹丸的“初始速度”,并且必须计算弹丸到达目标所需的发射角度。 与CalculateVelocity相同。 CalculateNone允许用户输入两个值,而CalculateBoth 则计算两个值。

我使用什么方程式计算值以便它们对齐,即选择CalculateAngle时,计算出的速度应使弹丸看起来自然地从枪管中出来。与CalculateBoth相同,应计算角度,以使计算出的速度将弹丸海峡发射出枪管,而不发射任何其他方向。

我有我的当前位置(Vector3),目标位置(Vector3)。 计算出的角度将影响加农炮的x轴旋转。 y旋转已经与目标对齐,因此它面向目标;

这是课程的代码

using System;
using UnityEngine;

public class Launcher : MonoBehaviour
{
    [SerializeField] private LauncherSettings settings = default;
    [SerializeField] private Transform target = default;
    private Transform partToRotateY;
    private Transform partToRotateX;
    private Transform projectileSpawnPosition;
    private float x;
    private float y;
    private Vector3 velocity;

    private void Awake()
    {
        partToRotateX = transform.GetChild(0);
        partToRotateY = transform.GetChild(1);
        projectileSpawnPosition = partToRotateX.GetChild(0);
        settings.inputController = new InputActions.Launcher();
        settings.inputController.Automatic.Launch.performed += _ => Shoot();
    }

    private void Update()
    {
        CalculateVelocity();
        CalculateAngle();
        LookAtTarget();
        Shoot();
    }
    
    private void OnEnable()
    {
        settings.inputController.Enable();
    }

    private void OnDisable()
    {
        settings.inputController.Disable();
    }

    private void LookAtTarget()
    {
        Vector3 direction = target.position - transform.position;
        Quaternion lookRotation = Quaternion.LookRotation(direction);
        y = lookRotation.eulerAngles.y;
        Quaternion rotationY = Quaternion.Euler(0f,y,0f);
        Quaternion rotationX = Quaternion.Euler(-x,0f);
        partToRotateY.rotation = Quaternion.Slerp(partToRotateY.rotation,rotationY,Time.deltaTime * settings.rotationSpeed);
        partToRotateX.rotation = Quaternion.Slerp(partToRotateX.rotation,rotationX,Time.deltaTime * settings.rotationSpeed);
    }

    private float nextTimeToFire = 0f;
    
    private void Shoot()
    {
        nextTimeToFire -= Time.deltaTime;
        if (!(nextTimeToFire <= 0f)) return;
        nextTimeToFire = 1 / settings.fireRate;
        var rb = Instantiate(settings.projectilePrefab,projectileSpawnPosition.position,Quaternion.identity).GetComponent<Rigidbody>();
        rb.velocity = velocity;
    }

    private void CalculateAngle()
    {
        if (settings.launcherConfig == LauncherConfig.CalculateVelocity ||
            settings.launcherConfig == LauncherConfig.CalculateNone)
        {
            x = Mathf.Clamp(settings.launchAngle,-20f,80f);
        }
        else
        {
            var position = target.position;
            var position1 = transform.position;
            var dist = Math.Sqrt(Mathf.Pow((position.x - position1.x),2) + Mathf.Pow((position.y - position1.y),2));
            var a = Physics.gravity.y * Mathf.Pow((float) dist,2) / (2 * Mathf.Pow(velocity.magnitude,2));
            var b = (float) -dist;
            var c = position.z - position1.z + a;
            x = (float) Math.Atan2(QuadraticRoot(a,b,c),1);
            Debug.Log(x);
        }
    }

    private void CalculateVelocity()
    {
        if (settings.launcherConfig == LauncherConfig.CalculateAngle ||
            settings.launcherConfig == LauncherConfig.CalculateNone)
        {
            velocity = partToRotateX.forward * settings.velocity;
        }
        else
        {
            float h;
            if (settings.launcherConfig == LauncherConfig.CalculateBoth && settings.calculateMaxHeight)
            {
                h = Mathf.Abs(target.position.y - partToRotateX.position.y * settings.maxHeightMultiplier);
            }
            else
            {
                h = settings.maxHeight;
            }

            var position = partToRotateX.position;
            var position1 = target.position;
            var gravity = Physics.gravity.y;

            var displacementY = position1.y - position.y;
            var displacementXZ = new Vector3 (position1.x - position.x,position1.z - position.z);
            var time = Mathf.Sqrt(-2*h/gravity) + Mathf.Sqrt(2*(displacementY - h)/gravity);
            var velocityY = Vector3.up * Mathf.Sqrt (-2 * gravity * h);
            var velocityXZ = displacementXZ / time;

            velocity = velocityXZ + velocityY * -Mathf.Sign(gravity);
        }
    }
    
    private double QuadraticRoot(double a,double b,double c){
        double D = Math.Pow(b,2) - (4 * a * c);
        return (-b + Math.Sqrt(D)) / (2 * a);
    }
}

LauncherSettings类...

using Attributes.DrawIf;
using Attributes.DrawIfAndOr;
using UnityEngine;

[CreateAssetMenu]
public class LauncherSettings : ScriptableObject
{
    public InputActions.Launcher inputController;
    public LauncherConfig launcherConfig = LauncherConfig.CalculateVelocity;
    public GameObject projectilePrefab = default;
    public float rotationSpeed = 5f;
    public float fireRate = 5f;
    [DrawIfAndOr(nameof(launcherConfig),LauncherConfig.CalculateAngle,LauncherConfig.CalculateNone)]
    public float velocity = 200f;
    [DrawIfAndOr(nameof(launcherConfig),LauncherConfig.CalculateVelocity,LauncherConfig.CalculateNone)]
    public float launchAngle = 0f;
    [DrawIf(nameof(launcherConfig),LauncherConfig.CalculateBoth)]
    public bool calculateMaxHeight = true;
    [DrawIf(nameof(calculateMaxHeight),false)]
    public float maxHeight;
    [DrawIf(nameof(calculateMaxHeight),true)]
    public float maxHeightMultiplier = 5f;
}

DrawIfDrawIfAndOr是在第一个参数等于另一个参数的情况下将检查符隐藏在检查器中的属性。您可以完全忽略它们。速度的计算公式为 塞巴斯蒂安·拉格(https://www.youtube.com/channel/UCmtyQOKKmrMVaKuRXz02jbQ)的运动方程式(E03:球问题)(https://youtu.be/IvT8hjy6q4o)。角度的计算是从我对另一个问题(Find an angle to launch the projectile at to reach a specific point)的回答中得出的。

感谢您的帮助... 谢谢...

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)