c# - 找到一个角度和速度来发射弹丸以到达特定点
问题描述
我正在尝试制作一门可以射击 Unity 中 3D 世界中的目标的大炮...我有一个LaunchConfig
枚举->
public enum LauncherConfig
{
CalculateNone = 0,
CalculateAngle = 1,
CalculateVelocity = 2,
CalculateBoth = 3
}
选择时CalculateAngle
,用户可以输入弹丸的初始速度,并且必须计算弹丸需要发射的角度才能到达目标。对CalculateVelocity
.
CalculateNone
允许用户输入这两个值并CalculateBoth
计算这两个值。
What equations do I use to calculate the values so that they line up, ie when CalculateAngle
is selected the velocity calculated should be such that the projectile looks natural coming out of the barrel. 同样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, y, 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, 0, 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;
}
如果第一个参数等于另一个参数,则DrawIf
and是隐藏检查器中的值的属性。DrawIfAndOr
你可以完全忽略它们。速度的计算是由 Sebastian Lague ( https://www.youtube.com/channel/UCmtyQOKKmrMVaKuRXz02jbQ ) 在他的运动学方程 (E03: 球问题) ( https://youtu.be/IvT8hjy6q4o ) 中计算的。角度的计算来自我的另一个问题的答案(找到一个角度来发射射弹以达到特定点)。
任何帮助表示赞赏...谢谢...
解决方案
推荐阅读
- ios - 删除每个 UICollectionViewCell 之间的间距并将其移动到 UICollectionView 的外部单元格
- c++ - CMake Exported Lib - 在客户端应用程序中找不到包含/lib 路径
- python - 我无法定义我的矩阵来计算 spearman 相关矩阵 Python 3.6
- python - 如何从 python 中的 txt 文件中读取特定的列?
- javascript - 整理一个javascript对象数组
- sql - POSTGRES - 将参数值更改为相反
- android - 索引 10 处的非法字符 <">:C:\Android"\analytics.settings
- ios - 带有 AutoLayout 的 ScrollView 不起作用
- java - Servlets - Ajax 重定向到主页
- android - 底部导航查看所选项目上的文本样式