抛物线轨迹计算
不同输入情况下的抛物线有不同计算方式。为了保证飞行时间的一致,水平初速度和起点两个参数是任何情况下都需要的。
三、示例代码
void UParabolicMovementComponent::InitComputeParams()
{
//无目标时
if (!bHasTarget)
{
// 指定出射角度时计算方法
// FQuat quat = UpdatedComponent->GetComponentQuat() * FQuat(Rotation);
// DirHorz = quat.Rotator().Vector();
// float Theta = DirHorz.Z / DirHorz.Size2D();
// VerticalSpeed = HorzSpeed * tan(Theta);
// DirHorz.Z = 0;
//指定最大高度时计算方法
DirHorz = UpdatedComponent->GetComponentRotation().Vector();
DirHorz.Z = 0;
DirHorz.Normalize();
//若无目标则默认G=980.0f
VerticalSpeed = FMath::Sqrt(2 * Gravity * MaxHeight);
}
//有目标时
else
{
DirHorz = GetTargetPosition() - GetHostPosition();
float HeightDist = DirHorz.Z;
DirHorz.Z = 0;
float Dist = DirHorz.Size();
DirHorz.Normalize();
TotalTime = Dist / HorzSpeed;
VerticalSpeed = (2.0f * (MaxHeight + FMath::Sqrt(MaxHeight*MaxHeight - MaxHeight*HeightDist))) / TotalTime;
Gravity = VerticalSpeed * VerticalSpeed / (2.0f * MaxHeight);
//VerticalSpeed = HeightDist / TotalTime + .5f * Gravity * TotalTime;
}
CurrentTime = 0;
StartPos = GetHostPosition();
Velocity = DirHorz * HorzSpeed + FVector::UpVector * VerticalSpeed;
UpdateComponentVelocity();
}
//计算当前时刻所在位置
void UParabolicMovementComponent::ComputeMovement(float DeltaTime, FVector& OutMoveDelta)
{
CurrentTime += DeltaTime;
if(bHasTarget)
{
if (CurrentTime >= TotalTime)
{
CurrentTime = TotalTime;
bStop = true;
}
}
float CurrentVertSpeed = VerticalSpeed - Gravity * CurrentTime;
float fVertDist = .5f * (VerticalSpeed + CurrentVertSpeed) * CurrentTime;
OutMoveDelta = StartPos + CurrentTime * HorzSpeed * DirHorz + fVertDist * FVector::UpVector - GetHostPosition();
Velocity = DirHorz * HorzSpeed + FVector::UpVector * CurrentVertSpeed;
//OutNewRotation = Velocity.Rotation().Quaternion();
}
导弹线轨迹计算
物体以某个初速度方向出发后,先保持稳定线性速度,以一定角速度向目标点旋转,当速度方向和自身-目标方向的夹角小于一定角度后,速度方向立刻改为自身-目标方向,进行直线加速。
示例代码
void UMissleMovementComponent::InitComputeParams()
{
Dir = (UpdatedComponent->GetComponentQuat() * Rotation.Quaternion()).Rotator().Vector();
Dir.Normalize();
Velocity = Dir * StartSpeed;
CurrentSpeed = StartSpeed;
UpdateComponentVelocity();
}
void UMissleMovementComponent::ComputeMovement(float DeltaTime, FVector& OutMoveDelta)
{
float MinDist = GetMinimalDistance();
static const float fLimit = (float)cos(FMath::DegreesToRadians(LimitDegree));
FVector vDir;
vDir = GetTargetPosition() - GetHostPosition();
float fLeft = vDir.Size();
vDir.Normalize();
float fDist = CurrentSpeed * DeltaTime;
if (fDist >= fLeft)
{
fDist = fLeft;
bStop = true;
}
float fAngle = Velocity.GetSafeNormal() | vDir;
//如果小于最小距离;或者角度相近,使用直线
if (fLeft < MinDist || fAngle > fLimit)
{
CurrentSpeed += LinearAcc * DeltaTime;
OutMoveDelta = vDir * fDist;
Velocity = vDir * CurrentSpeed;
}
else
{
OutMoveDelta = Velocity * DeltaTime;
FVector vUp = Velocity ^ vDir;
vUp.Normalize();
FQuat q(vUp, RotationSpeed * DeltaTime);
Velocity = q.RotateVector(Velocity);
}
//OutNewRotation = Velocity.ToOrientationQuat();
//OutNewRotation = Velocity.Rotation().Quaternion();
}
float UMissleMovementComponent::GetMinimalDistance()
{
float d = 2.0f * StartSpeed / RotationSpeed;
return d;
}