C# 找到发射弹丸的角度和速度,以达到特定点
我正在尝试制作一门大炮,它可以在统一的3D世界中射击目标。。。我有一个C# 找到发射弹丸的角度和速度,以达到特定点,c#,unity3d,physics,projectile,C#,Unity3d,Physics,Projectile,我正在尝试制作一门大炮,它可以在统一的3D世界中射击目标。。。我有一个LaunchConfigenum-> public enum LauncherConfig { CalculateNone = 0, CalculateAngle = 1, CalculateVelocity = 2, CalculateBoth = 3 } 当选择CalculateAngle时,用户可以输入弹丸的初始速度,并且必须计算弹丸到达目标所需的发射角度。 同样适用于Calculate
LaunchConfig
enum->
public enum LauncherConfig
{
CalculateNone = 0,
CalculateAngle = 1,
CalculateVelocity = 2,
CalculateBoth = 3
}
当选择CalculateAngle
时,用户可以输入弹丸的初始速度,并且必须计算弹丸到达目标所需的发射角度。
同样适用于CalculateVelocity
。
calculateOne
允许用户输入两个值,CalculateBoth
计算两个值
我应该使用什么方程式来计算这些值,以便它们对齐,即,当选择CalculateAngle
时,计算的速度应该使弹丸看起来自然地从枪管中出来。对于CalculateBoth
,应计算角度,以便计算出的速度将弹丸发射出枪管,而不是任何其他方向
我有我的当前位置(矢量3),目标位置(矢量3)。
计算的角度将影响加农炮的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);
}
}
如果第一个参数等于另一个,则DrawIf
和DrawIfAndOr
是在inspector中隐藏变量的属性。你可以完全忽略它们。速度的计算是通过
Sebastian Lague()在他的运动学方程中(E03:球问题)()。角度的计算是根据对我的另一个问题()的回答得出的
感谢您的帮助。。。
谢谢…我的演算有点生疏,但是vtcos(ang)=x。所以我假设你知道v是初速。T是飞行所花费的时间(您可以用总距离来定义以简化)。x是你降落的地方。所以你可以得到ang=arcos(vt/x)或者我认为是这样。摩擦力为0的情况就这样了。等等。。。那么您想根据起点和终点来确定轨迹?加农炮要改变强度和角度吗?如果是这样的话,我制作了一个Trajection类,可以使用起点、终点和最大高度确定抛物线路径,如果你愿意,我会发送一个链接(在另一个StackOverflow线程上)@1MangomMaster1是的,这基本上就是我想要的,但是这些值可以改变,就像我想把大炮的角度增加两倍,然后计算速度,同样的速度,如果我想让它有两倍的速度,角度也应该改变…你可以确定高度,就像我说的,你有起点,所以我想你可以搞乱起点和高度来得到角度,从那里它会做弧到终点检查我提供的解决方案,我把我做的代码的图像,这是一种解决办法,但它工作得非常好,所以我想这是好的,而且,我在那里添加了一个图片中没有的修复,所以请注意。
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;
}