taairmovetype.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,048 行 · 第 1/2 页
CPP
1,048 行
wantedHeight = gah;
} else {
h = pos.y - ground->GetHeight(pos.x, pos.z);
wantedHeight = -2;
}
UpdateAirPhysics();
if (h <= 0) {
SetState(AIRCRAFT_LANDED);
pos.y = gah;
}
}
void CTAAirMoveType::UpdateHeading()
{
if (aircraftState == AIRCRAFT_TAKEOFF && !owner->unitDef->factoryHeadingTakeoff) {
return;
}
short& heading = owner->heading;
short deltaHeading = wantedHeading - heading;
if (forceHeading) {
deltaHeading = forceHeadingTo - heading;
}
if (deltaHeading > 0) {
heading += deltaHeading > (short int) turnRate ? (short int) turnRate : deltaHeading;
} else {
heading += deltaHeading > (short int) (-turnRate) ? deltaHeading : (short int) (-turnRate);
}
}
void CTAAirMoveType::UpdateBanking(bool noBanking)
{
SyncedFloat3 &frontdir = owner->frontdir;
SyncedFloat3 &updir = owner->updir;
float wantedPitch = 0;
if (aircraftState == AIRCRAFT_FLYING && flyState == FLY_ATTACKING && circlingPos.y < owner->pos.y) {
wantedPitch = (circlingPos.y - owner->pos.y) / circlingPos.distance(owner->pos);
}
currentPitch = currentPitch * 0.95f + wantedPitch * 0.05f;
frontdir = GetVectorFromHeading(owner->heading);
frontdir.y = currentPitch;
frontdir.Normalize();
float3 rightdir(frontdir.cross(UpVector)); //temp rightdir
rightdir.Normalize();
float wantedBank = 0.0f;
if (!noBanking) wantedBank = rightdir.dot(deltaSpeed)/accRate*0.5f;
float limit=min(1.0f,goalPos.distance2D(owner->pos)*0.15f);
if(wantedBank>limit)
wantedBank=limit;
else if(wantedBank<-limit)
wantedBank=-limit;
//Adjust our banking to the desired value
if (currentBank > wantedBank)
currentBank -= min(0.03f, currentBank - wantedBank);
else
currentBank += min(0.03f, wantedBank - currentBank);
// Calculate a suitable upvector
updir = rightdir.cross(frontdir);
updir = updir * cos(currentBank) + rightdir * sin(currentBank);
owner->rightdir = frontdir.cross(updir);
}
void CTAAirMoveType::UpdateAirPhysics()
{
float3& pos = owner->pos;
float3& speed = owner->speed;
if (!((gs->frameNum + owner->id) & 3)) {
CheckForCollision();
}
float yspeed = speed.y;
speed.y = 0;
float3 delta = wantedSpeed - speed;
float dl = delta.Length();
if (delta.dot(speed) > 0) {
// accelerate
if (dl < accRate) {
speed = wantedSpeed;
} else {
speed += delta / dl * accRate;
}
} else {
// break
if (dl < decRate) {
speed = wantedSpeed;
} else {
speed += delta / dl * decRate;
}
}
speed.y = yspeed;
float h = pos.y - max(ground->GetHeight(pos.x, pos.z),
ground->GetHeight(pos.x + speed.x * 40, pos.z + speed.z * 40));
if (h < 4) {
speed.x *= 0.95f;
speed.z *= 0.95f;
}
float wh = wantedHeight;
if (lastColWarningType == 2) {
const float3 dir = lastColWarning->midPos - owner->midPos;
const float3 sdir = lastColWarning->speed - speed;
if (speed.dot(dir + sdir * 20.0f) < 0.0f) {
if (lastColWarning->midPos.y > owner->pos.y) {
wh -= 30;
} else {
wh += 50;
}
}
}
float ws;
if (h < wh) {
ws = altitudeRate;
if (speed.y > 0 && (wh - h) / speed.y * accRate * 1.5f < speed.y)
ws = 0;
} else {
ws = -altitudeRate;
if (speed.y < 0 && (wh - h) / speed.y * accRate * 0.7f < -speed.y)
ws = 0;
}
if (speed.y > ws) {
speed.y = max(ws, speed.y - accRate * 1.5f);
} else {
// let them accelerate upward faster if close to ground
speed.y = min(ws, speed.y + accRate * (h < 20? 2.0f: 0.7f));
}
pos += speed;
}
void CTAAirMoveType::UpdateMoveRate()
{
int curRate;
// currentspeed is not used correctly for vertical movement, so compensate with this hax
if ((aircraftState == AIRCRAFT_LANDING) || (aircraftState == AIRCRAFT_TAKEOFF)) {
curRate = 1;
}
else {
float curSpeed = owner->speed.Length();
curRate = (int) ((curSpeed / maxSpeed) * 3);
if (curRate < 0)
curRate = 0;
if (curRate > 2)
curRate = 2;
}
if (curRate != lastMoveRate) {
owner->cob->Call(COBFN_MoveRate0 + curRate);
lastMoveRate = curRate;
}
}
void CTAAirMoveType::Update()
{
float3& pos = owner->pos;
SyncedFloat3& rightdir = owner->rightdir;
SyncedFloat3& frontdir = owner->frontdir;
SyncedFloat3& updir = owner->updir;
float3& speed = owner->speed;
// This is only set to false after the plane has finished constructing
if (useHeading) {
useHeading = false;
SetState(AIRCRAFT_TAKEOFF);
}
// Allow us to stop if wanted
if (wantToStop)
ExecuteStop();
float3 lastSpeed = speed;
if (owner->stunned) {
wantedSpeed = ZeroVector;
UpdateAirPhysics();
} else {
#ifdef DIRECT_CONTROL_ALLOWED
if (owner->directControl) {
DirectControlStruct* dc = owner->directControl;
SetState(AIRCRAFT_FLYING);
float3 forward = dc->viewDir;
float3 flatForward = forward;
flatForward.y = 0;
flatForward.Normalize();
float3 right = forward.cross(UpVector);
float3 nextPos = pos + speed;
wantedSpeed = ZeroVector;
if (dc->forward)
wantedSpeed += flatForward;
if (dc->back)
wantedSpeed -= flatForward;
if (dc->right)
wantedSpeed += right;
if (dc->left)
wantedSpeed -= right;
wantedSpeed.Normalize();
wantedSpeed *= maxSpeed;
if (!nextPos.CheckInBounds()) {
speed = ZeroVector;
}
UpdateAirPhysics();
wantedHeading = GetHeadingFromVector(flatForward.x, flatForward.z);
} else
#endif
{
if (reservedPad) {
CUnit* unit = reservedPad->GetUnit();
float3 relPos = unit->localmodel->GetPiecePos(reservedPad->GetPiece());
float3 pos = unit->pos + unit->frontdir * relPos.z + unit->updir * relPos.y + unit->rightdir * relPos.x;
if (padStatus == 0) {
if (aircraftState != AIRCRAFT_FLYING && aircraftState != AIRCRAFT_TAKEOFF)
SetState(AIRCRAFT_FLYING);
goalPos = pos;
if (pos.distance2D(owner->pos) < 400) {
padStatus = 1;
}
} else if (padStatus == 1) {
if (aircraftState != AIRCRAFT_FLYING)
SetState(AIRCRAFT_FLYING);
flyState = FLY_LANDING;
goalPos = pos;
reservedLandingPos = pos;
wantedHeight = pos.y - ground->GetHeight(pos.x, pos.z);
if (owner->pos.distance(pos) < 3 || aircraftState == AIRCRAFT_LANDED) {
padStatus = 2;
}
} else {
if (aircraftState != AIRCRAFT_LANDED)
SetState(AIRCRAFT_LANDED);
owner->pos = pos;
owner->AddBuildPower(unit->unitDef->buildSpeed / 30, unit);
owner->currentFuel = min(owner->unitDef->maxFuel, owner->currentFuel + (owner->unitDef->maxFuel / (GAME_SPEED * owner->unitDef->refuelTime)));
if (owner->health >= owner->maxHealth - 1 && owner->currentFuel >= owner->unitDef->maxFuel) {
airBaseHandler->LeaveLandingPad(reservedPad);
reservedPad = 0;
padStatus = 0;
goalPos = oldGoalPos;
SetState(AIRCRAFT_TAKEOFF);
}
}
}
// Main state handling
switch (aircraftState) {
case AIRCRAFT_LANDED:
UpdateLanded();
break;
case AIRCRAFT_TAKEOFF:
UpdateTakeoff();
break;
case AIRCRAFT_FLYING:
UpdateFlying();
break;
case AIRCRAFT_LANDING:
UpdateLanding();
break;
case AIRCRAFT_HOVERING:
UpdateHovering();
break;
case AIRCRAFT_CRASHING:
break;
}
}
}
// Banking requires deltaSpeed.y = 0
deltaSpeed = speed - lastSpeed;
deltaSpeed.y = 0;
// Turn and bank and move
UpdateHeading();
UpdateBanking(aircraftState == AIRCRAFT_HOVERING); // updates dirs
owner->midPos = pos + frontdir * owner->relMidPos.z + updir * owner->relMidPos.y + rightdir * owner->relMidPos.x;
// Push other units out of the way
if (pos != oldpos && aircraftState != AIRCRAFT_TAKEOFF && padStatus == 0) {
oldpos = pos;
if (!dontCheckCol && collide) {
vector<CUnit*> nearUnits = qf->GetUnitsExact(pos, owner->radius + 6);
vector<CUnit*>::iterator ui;
for (ui = nearUnits.begin(); ui != nearUnits.end(); ++ui) {
if ((*ui)->transporter)
continue;
float sqDist = (pos-(*ui)->pos).SqLength();
float totRad = owner->radius + (*ui)->radius;
if (sqDist < totRad * totRad && sqDist != 0) {
float dist = sqrt(sqDist);
float3 dif = pos - (*ui)->pos;
dif /= dist;
if ((*ui)->mass >= 100000 || (*ui)->immobile) {
pos -= dif * (dist - totRad);
owner->midPos = pos + owner->frontdir * owner->relMidPos.z + owner->updir * owner->relMidPos.y + owner->rightdir * owner->relMidPos.x;
owner->speed *= 0.99f;
} else {
float part = owner->mass / (owner->mass + (*ui)->mass);
pos -= dif * (dist - totRad) * (1 - part);
owner->midPos = pos + owner->frontdir * owner->relMidPos.z + owner->updir * owner->relMidPos.y + owner->rightdir * owner->relMidPos.x;
CUnit* u = (CUnit*) (*ui);
u->pos += dif * (dist - totRad) * (part);
u->midPos = u->pos + u->frontdir * u->relMidPos.z + u->updir * u->relMidPos.y + u->rightdir * u->relMidPos.x;
float colSpeed = -owner->speed.dot(dif) + u->speed.dot(dif);
owner->speed += dif * colSpeed * (1 - part);
u->speed -= dif * colSpeed * (part);
}
}
}
}
if (pos.x < 0) {
pos.x += 0.6f;
owner->midPos.x += 0.6f;
} else if (pos.x > float3::maxxpos) {
pos.x -= 0.6f;
owner->midPos.x -= 0.6f;
}
if (pos.z < 0) {
pos.z += 0.6f;
owner->midPos.z += 0.6f;
} else if (pos.z > float3::maxzpos) {
pos.z -= 0.6f;
owner->midPos.z -= 0.6f;
}
}
}
void CTAAirMoveType::SlowUpdate(void)
{
if (aircraftState != AIRCRAFT_LANDED && owner->unitDef->maxFuel > 0)
owner->currentFuel = max(0.f, owner->currentFuel - (16.f / GAME_SPEED));
if (!reservedPad && aircraftState == AIRCRAFT_FLYING && owner->health < owner->maxHealth * repairBelowHealth) {
CAirBaseHandler::LandingPad* lp = airBaseHandler->FindAirBase(owner, owner->unitDef->minAirBasePower);
if (lp) {
AddDeathDependence(lp);
reservedPad = lp;
padStatus = 0;
oldGoalPos = goalPos;
}
}
UpdateMoveRate();
// Update LOS stuff
int newmapSquare = ground->GetSquare(owner->pos);
if (newmapSquare != owner->mapSquare) {
owner->mapSquare = newmapSquare;
float oldlh = owner->losHeight;
float h = owner->pos.y - ground->GetApproximateHeight(owner->pos.x, owner->pos.z);
owner->losHeight = h + 5;
loshandler->MoveUnit(owner, false);
if (owner->hasRadarCapacity)
radarhandler->MoveUnit(owner);
owner->losHeight = oldlh;
}
qf->MovedUnit(owner);
owner->isUnderWater = (owner->pos.y + owner->model->height < 0);
}
//Returns true if indicated position is a suitable landing spot
bool CTAAirMoveType::CanLandAt(float3 pos)
{
if (dontLand)
return false;
if (!autoLand)
return false;
if (pos.x < 0 || pos.z < 0 || pos.x > float3::maxxpos || pos.z > float3::maxzpos)
return false;
float h = ground->GetApproximateHeight(pos.x, pos.z);
if ((h < 0) && !(owner -> unitDef -> floater || owner -> unitDef -> canSubmerge))
return false;
float3 tpos = owner->pos;
owner->pos = pos;
int2 mp = owner->GetMapPos();
owner->pos = tpos;
for (int z = mp.y; z < mp.y + owner->ysize; z++) {
for (int x = mp.x; x < mp.x + owner->xsize; x++) {
CObject* o = readmap->groundBlockingObjectMap[z * gs->mapx + x];
if (o && o != owner) {
return false;
}
}
}
return true;
}
void CTAAirMoveType::ForceHeading(short h)
{
forceHeading = true;
forceHeadingTo = h;
}
void CTAAirMoveType::SetWantedAltitude(float altitude)
{
if (altitude == 0) {
wantedHeight = orgWantedHeight;
} else {
wantedHeight = altitude;
}
}
void CTAAirMoveType::CheckForCollision(void)
{
if (!collide) return;
SyncedFloat3& pos = owner->midPos;
SyncedFloat3 forward = owner->speed;
forward.Normalize();
float3 midTestPos = pos + forward * 121;
std::vector<CUnit*> others = qf->GetUnitsExact(midTestPos, 115);
float dist = 200;
if (lastColWarning) {
DeleteDeathDependence(lastColWarning);
lastColWarning = 0;
lastColWarningType = 0;
}
for (std::vector<CUnit*>::iterator ui = others.begin(); ui != others.end(); ++ui) {
if (*ui == owner || !(*ui)->unitDef->canfly)
continue;
SyncedFloat3& op = (*ui)->midPos;
float3 dif = op - pos;
float3 forwardDif = forward * (forward.dot(dif));
if (forwardDif.SqLength() < dist * dist) {
float frontLength = forwardDif.Length();
float3 ortoDif = dif - forwardDif;
// note: the radius is multiplied by two since we rely on aircraft having small spheres (see unitloader)
float minOrtoDif = ((*ui)->radius + owner->radius) * 2 + frontLength * 0.05f + 5;
if (ortoDif.SqLength() < minOrtoDif * minOrtoDif) {
dist = frontLength;
lastColWarning = (*ui);
}
}
}
if (lastColWarning) {
lastColWarningType = 2;
AddDeathDependence(lastColWarning);
return;
}
for (std::vector<CUnit*>::iterator ui = others.begin(); ui != others.end(); ++ui) {
if (*ui == owner)
continue;
if (((*ui)->midPos - pos).SqLength() < dist * dist) {
lastColWarning = *ui;
}
}
if (lastColWarning) {
lastColWarningType = 1;
AddDeathDependence(lastColWarning);
}
return;
}
void CTAAirMoveType::DependentDied(CObject* o)
{
if (o == reservedPad) {
reservedPad = 0;
SetState(AIRCRAFT_FLYING);
goalPos = oldGoalPos;
}
if (o == lastColWarning) {
lastColWarning = 0;
lastColWarningType = 0;
}
CMoveType::DependentDied(o);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?