taairmovetype.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,048 行 · 第 1/2 页
CPP
1,048 行
#include "StdAfx.h"
#include "TAAirMoveType.h"
#include "Sim/Misc/QuadField.h"
#include "Map/Ground.h"
#include "Sim/Misc/LosHandler.h"
#include "Sim/Misc/RadarHandler.h"
#include "Sim/Units/COB/CobFile.h"
#include "Sim/Units/COB/CobInstance.h"
#include "LogOutput.h"
#include "myMath.h"
#include "Matrix44f.h"
#include "Rendering/UnitModels/3DOParser.h"
#include "Game/Player.h"
#include "Sim/Units/UnitDef.h"
#include "Sim/Misc/GeometricObjects.h"
#include "Mobility.h"
#include "Sim/Units/UnitTypes/TransportUnit.h"
#include "Sim/Units/CommandAI/CommandAI.h"
CR_BIND_DERIVED(CTAAirMoveType, CMoveType, (NULL));
CR_REG_METADATA(CTAAirMoveType, (
CR_MEMBER(dontCheckCol),
CR_MEMBER(goalPos),
CR_MEMBER(oldpos),
CR_MEMBER(wantedHeight),
CR_MEMBER(orgWantedHeight),
CR_MEMBER(reservedLandingPos),
CR_MEMBER(circlingPos),
CR_MEMBER(goalDistance),
CR_MEMBER(waitCounter),
CR_MEMBER(wantToStop),
CR_MEMBER(wantedHeading),
CR_MEMBER(wantedSpeed),
CR_MEMBER(deltaSpeed),
CR_MEMBER(currentBank),
CR_MEMBER(currentPitch),
CR_MEMBER(turnRate),
CR_MEMBER(accRate),
CR_MEMBER(decRate),
CR_MEMBER(altitudeRate),
CR_MEMBER(breakDistance),
CR_MEMBER(dontLand),
CR_MEMBER(lastMoveRate),
CR_MEMBER(forceHeading),
CR_MEMBER(forceHeadingTo),
CR_MEMBER(maxDrift),
CR_MEMBER(lastColWarning),
CR_MEMBER(lastColWarningType),
CR_MEMBER(collide),
CR_MEMBER(repairBelowHealth),
CR_MEMBER(reservedPad),
CR_MEMBER(padStatus),
CR_MEMBER(oldGoalPos),
CR_MEMBER(autoLand),
CR_RESERVED(63)
));
CTAAirMoveType::CTAAirMoveType(CUnit* owner) :
CMoveType(owner),
aircraftState(AIRCRAFT_LANDED),
wantedHeight(80),
altitudeRate(3.0f),
currentBank(0),
// we want to take off in direction of factory facing
wantedHeading(owner? GetHeadingFromFacing(owner->buildFacing): 0),
wantToStop(false),
forceHeading(false),
dontCheckCol(false),
dontLand(false),
collide(true),
lastMoveRate(0),
waitCounter(0),
deltaSpeed(ZeroVector),
accRate(1),
breakDistance(1),
circlingPos(ZeroVector),
decRate(1),
flyState(FLY_CRUISING),
forceHeadingTo(wantedHeading),
goalDistance(1),
goalPos(owner? owner->pos:float3(0, 0, 0)),
oldGoalPos(owner? owner->pos:float3(0, 0, 0)),
turnRate(1),
wantedSpeed(ZeroVector),
lastColWarning(0),
lastColWarningType(0),
reservedLandingPos(-1, -1, -1),
maxDrift(1),
repairBelowHealth(0.30f),
padStatus(0),
reservedPad(0),
currentPitch(0),
autoLand(true)
{
if (owner) {
owner->dontUseWeapons = true;
}
}
CTAAirMoveType::~CTAAirMoveType(void)
{
if (reservedPad) {
airBaseHandler->LeaveLandingPad(reservedPad);
reservedPad = 0;
}
}
void CTAAirMoveType::SetGoal(float3 newPos, float distance)
{
// aircraft need some marginals to avoid uber stacking
// when lots of them are ordered to one place
maxDrift = max(16.0f, distance);
goalPos = newPos;
oldGoalPos = newPos;
forceHeading = false;
wantedHeight = orgWantedHeight;
}
void CTAAirMoveType::SetState(AircraftState newState)
{
if (newState == aircraftState)
return;
// Perform cob animation
if (aircraftState == AIRCRAFT_LANDED)
owner->cob->Call(COBFN_StartMoving);
if (newState == AIRCRAFT_LANDED)
owner->cob->Call(COBFN_StopMoving);
if (newState == AIRCRAFT_LANDED) {
owner->dontUseWeapons = true;
} else {
owner->dontUseWeapons = false;
}
aircraftState = newState;
// Do animations
switch (aircraftState) {
case AIRCRAFT_LANDED:
if (padStatus == 0) {
// don't set us as on ground if we are on pad
owner->physicalState = CSolidObject::OnGround;
owner->Block();
}
case AIRCRAFT_LANDING:
owner->Deactivate();
break;
case AIRCRAFT_HOVERING:
wantedHeight = orgWantedHeight;
wantedSpeed = ZeroVector;
// fall through...
default:
owner->physicalState = CSolidObject::Flying;
owner->UnBlock();
owner->Activate();
reservedLandingPos.x = -1;
break;
}
// Cruise as default
if (aircraftState == AIRCRAFT_FLYING || aircraftState == AIRCRAFT_HOVERING)
flyState = FLY_CRUISING;
owner->isMoving = (aircraftState != AIRCRAFT_LANDED);
waitCounter = 0;
}
void CTAAirMoveType::StartMoving(float3 pos, float goalRadius)
{
wantToStop = false;
owner->isMoving = true;
waitCounter = 0;
forceHeading = false;
switch (aircraftState) {
case AIRCRAFT_LANDED:
SetState(AIRCRAFT_TAKEOFF);
break;
case AIRCRAFT_TAKEOFF:
SetState(AIRCRAFT_TAKEOFF);
break;
case AIRCRAFT_FLYING:
if (flyState != FLY_CRUISING)
flyState = FLY_CRUISING;
break;
case AIRCRAFT_LANDING:
SetState(AIRCRAFT_TAKEOFF);
break;
case AIRCRAFT_HOVERING:
SetState(AIRCRAFT_FLYING);
break;
case AIRCRAFT_CRASHING:
break;
}
SetGoal(pos, goalRadius);
breakDistance = ((maxSpeed * maxSpeed) / decRate);
}
void CTAAirMoveType::StartMoving(float3 pos, float goalRadius, float speed)
{
StartMoving(pos, goalRadius);
}
void CTAAirMoveType::KeepPointingTo(float3 pos, float distance, bool aggressive)
{
wantToStop = false;
forceHeading = false;
wantedHeight = orgWantedHeight;
// close in a little to avoid the command AI to override the pos constantly
distance -= 15;
// Ignore the exact same order
if ((aircraftState == AIRCRAFT_FLYING) && (flyState == FLY_CIRCLING || flyState == FLY_ATTACKING) && ((circlingPos - pos).SqLength2D() < 64) && (goalDistance == distance))
return;
circlingPos = pos;
goalDistance = distance;
goalPos = owner->pos;
SetState(AIRCRAFT_FLYING);
if (aggressive) {
flyState = FLY_ATTACKING;
} else {
flyState = FLY_CIRCLING;
}
}
void CTAAirMoveType::ExecuteStop()
{
wantToStop = false;
switch (aircraftState) {
case AIRCRAFT_TAKEOFF:
SetState(AIRCRAFT_LANDING);
// trick to land directly
waitCounter = 30;
break;
case AIRCRAFT_FLYING:
if (owner->unitDef->DontLand()) {
goalPos = owner->pos;
SetState(AIRCRAFT_HOVERING);
} else if (dontLand || !autoLand) {
goalPos = owner->pos;
wantedSpeed = ZeroVector;
} else {
SetState(AIRCRAFT_LANDING);
}
break;
case AIRCRAFT_LANDING:
break;
case AIRCRAFT_LANDED:
break;
case AIRCRAFT_CRASHING:
break;
case AIRCRAFT_HOVERING:
break;
}
}
void CTAAirMoveType::StopMoving()
{
wantToStop = true;
forceHeading = false;
owner->isMoving = false;
wantedHeight = orgWantedHeight;
}
void CTAAirMoveType::Idle()
{
StopMoving();
}
void CTAAirMoveType::UpdateLanded()
{
float3& pos = owner->pos;
// dont place on ground if we are on a repair pad
if (padStatus == 0) {
if (owner->unitDef->canSubmerge)
pos.y = ground->GetApproximateHeight(pos.x, pos.z);
else
pos.y = ground->GetHeight(pos.x, pos.z);
}
owner->speed = ZeroVector;
}
void CTAAirMoveType::UpdateTakeoff()
{
float3 &pos = owner->pos;
wantedSpeed = ZeroVector;
wantedHeight = orgWantedHeight;
UpdateAirPhysics();
float h = 0.0f;
if (owner->unitDef->canSubmerge) {
h = pos.y - ground->GetApproximateHeight(pos.x, pos.z);
} else {
h = pos.y - ground->GetHeight(pos.x, pos.z);
}
if (h > orgWantedHeight * 0.8f) {
SetState(AIRCRAFT_FLYING);
}
}
// Move the unit around a bit.. and when it gets too far away from goal position it switches to normal flying instead
void CTAAirMoveType::UpdateHovering()
{
float driftSpeed = owner->unitDef->dlHoverFactor;
float3 dir = goalPos - owner->pos;
// move towards goal position if it's not immediately behind us when we have more waypoints to get to
if (aircraftState != AIRCRAFT_LANDING && (owner->commandAI->HasMoreMoveCommands() &&
dir.Length2D() < 120) && (goalPos - owner->pos).Normalize().distance(dir) > 1) {
dir = owner->frontdir;
}
wantedSpeed += float3(dir.x, 0.0f, dir.z) * driftSpeed * 0.03f;
// damping
wantedSpeed *= 0.97f;
// random movement (a sort of fake wind effect)
wantedSpeed += float3(gs->randFloat() - 0.5f, 0.0f, gs->randFloat() - 0.5f) * driftSpeed * 0.5f;
UpdateAirPhysics();
}
void CTAAirMoveType::UpdateFlying()
{
float3 &pos = owner->pos;
float3 &speed = owner->speed;
// Direction to where we would like to be
float3 dir = goalPos - pos;
owner->restTime = 0;
// don't change direction for waypoints we just flew over and missed slightly
if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() &&
dir.Length2D() < 100) && (goalPos - pos).Normalize().distance(dir) < 1) {
dir = owner->frontdir;
}
// are we there yet?
bool closeToGoal = (dir.SqLength2D() < maxDrift * maxDrift) && (fabs(ground->GetHeight(pos.x, pos.z) - pos.y + wantedHeight) < maxDrift);
if (flyState == FLY_ATTACKING)
closeToGoal = (dir.SqLength2D() < 400);
if (closeToGoal) {
// pretty close
switch (flyState) {
case FLY_CRUISING:
if (dontLand || (++waitCounter < 55 && dynamic_cast<CTransportUnit*>(owner)) || !autoLand) {
// transport aircraft need some time to detect that they can pickup
if (dynamic_cast<CTransportUnit*>(owner)) {
wantedSpeed = ZeroVector;
if (waitCounter > 60) {
wantedHeight = orgWantedHeight;
}
} else {
wantedSpeed = ZeroVector;
// SetState(AIRCRAFT_HOVERING);
}
} else {
wantedHeight = orgWantedHeight;
SetState(AIRCRAFT_LANDING);
}
return;
case FLY_CIRCLING:
// break;
waitCounter++;
if (waitCounter > 100) {
if (owner->unitDef->airStrafe) {
float3 relPos = pos - circlingPos;
if (relPos.x < 0.0001f && relPos.x > -0.0001f)
relPos.x = 0.0001f;
relPos.y = 0;
relPos.Normalize();
CMatrix44f rot;
rot.RotateY(1.0f);
float3 newPos = rot.Mul(relPos);
// Make sure the point is on the circle
newPos = newPos.Normalize() * goalDistance;
//Go there in a straight line
goalPos = circlingPos + newPos;
}
waitCounter = 0;
}
break;
case FLY_ATTACKING:{
if (owner->unitDef->airStrafe) {
float3 relPos = pos - circlingPos;
if (relPos.x < 0.0001f && relPos.x > -0.0001f)
relPos.x = 0.0001f;
relPos.y = 0;
relPos.Normalize();
CMatrix44f rot;
if (gs->randFloat() > 0.5f)
rot.RotateY(0.6f + gs->randFloat() * 0.6f);
else
rot.RotateY(-(0.6f + gs->randFloat() * 0.6f));
float3 newPos = rot.Mul(relPos);
newPos = newPos.Normalize() * goalDistance;
// Go there in a straight line
goalPos = circlingPos + newPos;
}
break;
}
case FLY_LANDING:{
break;
}
}
}
// not there yet, so keep going
dir.y = 0;
float realMax = maxSpeed;
float dist = dir.Length2D();
// If we are close to our goal, we should go slow enough to be able to break in time
// new additional rule: if in attack mode or if we have more move orders then this is
// an intermediate waypoint, don't slow down (FIXME)
/// if (flyState != FLY_ATTACKING && dist < breakDistance && !owner->commandAI->HasMoreMoveCommands()) {
if (flyState != FLY_ATTACKING && dist < breakDistance) {
realMax = dist / (speed.Length2D() + 0.01f) * decRate;
}
wantedSpeed = dir.Normalize() * realMax;
UpdateAirPhysics();
// Point toward goal or forward - unless we just passed it to get to another goal
if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) {
dir = circlingPos - pos;
} else if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() &&
dist < 120) && (goalPos - pos).Normalize().distance(dir) > 1) {
dir = owner->frontdir;
} else {
dir = goalPos - pos;
}
if (dir.SqLength2D() > 1) {
int h = GetHeadingFromVector(dir.x, dir.z);
wantedHeading = (h == 0)? wantedHeading: h;
}
}
void CTAAirMoveType::UpdateLanding()
{
float3& pos = owner->pos;
float3& speed = owner->speed;
// We want to land, and therefore cancel our speed first
wantedSpeed = ZeroVector;
waitCounter++;
// Hang around for a while so queued commands have a chance to take effect
if (waitCounter < 30) {
UpdateAirPhysics();
return;
}
if (reservedLandingPos.x < 0) {
if (CanLandAt(pos)) {
// found a landing spot
reservedLandingPos = pos;
goalPos = pos;
owner->physicalState = CSolidObject::OnGround;
owner->Block();
owner->physicalState = CSolidObject::Flying;
owner->Deactivate();
owner->cob->Call(COBFN_StopMoving);
} else {
if (goalPos.distance2D(pos) < 30) {
goalPos = goalPos + gs->randVector() * 300;
goalPos.CheckInBounds();
}
flyState = FLY_LANDING;
UpdateFlying();
return;
}
}
// We should wait until we actually have stopped smoothly
if (speed.SqLength2D() > 1) {
UpdateFlying();
return;
}
// We have stopped, time to land
float gah = ground->GetApproximateHeight(pos.x, pos.z);
float h = 0.0f;
// if aircraft submergible and above water we want height of ocean floor
if ((owner->unitDef->canSubmerge) && (gah < 0)) {
h = pos.y - gah;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?