groundmovetype.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,843 行 · 第 1/4 页
CPP
1,843 行
#include "StdAfx.h"
#include "groundmovetype.h"
#include "Map/Ground.h"
#include "Sim/Misc/QuadField.h"
#include "Map/ReadMap.h"
#include "Sim/Misc/LosHandler.h"
#include "Game/GameHelper.h"
#include "myMath.h"
#include "LogOutput.h"
#include "Sim/Units/UnitHandler.h"
#include "Sync/SyncTracer.h"
#include "Rendering/UnitModels/3DOParser.h"
#include "Sim/Units/COB/CobInstance.h"
#include "Sim/Units/COB/CobFile.h"
#include "Sim/Misc/Feature.h"
#include "Sim/Misc/FeatureHandler.h"
#include "Sim/Units/UnitDef.h"
#include "Sound.h"
#include "Sim/Misc/RadarHandler.h"
#include "Sim/Path/PathManager.h"
#include "Game/Player.h"
#include "Game/Camera.h"
#include "Sim/Units/CommandAI/CommandAI.h"
#include "Mobility.h"
#include "MoveMath/MoveMath.h"
#include "Sim/Misc/GeometricObjects.h"
#include "Sim/Weapons/Weapon.h"
#include "Sim/Weapons/WeaponDefHandler.h"
#include "Game/SelectedUnits.h"
#include "Rendering/GroundDecalHandler.h"
#include "ExternalAI/GlobalAIHandler.h"
#include "mmgr.h"
CR_BIND_DERIVED(CGroundMoveType, CMoveType, (NULL));
CR_REG_METADATA(CGroundMoveType, (
CR_MEMBER(baseTurnRate),
CR_MEMBER(turnRate),
CR_MEMBER(accRate),
CR_MEMBER(wantedSpeed),
CR_MEMBER(currentSpeed),
CR_MEMBER(deltaSpeed),
CR_MEMBER(deltaHeading),
CR_MEMBER(oldPos),
CR_MEMBER(oldSlowUpdatePos),
CR_MEMBER(flatFrontDir),
CR_MEMBER(pathId),
CR_MEMBER(goal),
CR_MEMBER(goalRadius),
CR_MEMBER(waypoint),
CR_MEMBER(nextWaypoint),
CR_MEMBER(etaWaypoint),
CR_MEMBER(etaWaypoint2),
CR_MEMBER(atGoal),
CR_MEMBER(haveFinalWaypoint),
CR_MEMBER(terrainSpeed),
CR_MEMBER(requestedSpeed),
CR_MEMBER(requestedTurnRate),
CR_MEMBER(currentDistanceToWaypoint),
CR_MEMBER(avoidanceVec),
CR_MEMBER(restartDelay),
CR_MEMBER(lastGetPathPos),
CR_MEMBER(pathFailures),
CR_MEMBER(etaFailures),
CR_MEMBER(nonMovingFailures),
CR_MEMBER(moveType),
CR_MEMBER(floatOnWater),
CR_MEMBER(moveSquareX),
CR_MEMBER(moveSquareY),
CR_MEMBER(nextDeltaSpeedUpdate),
CR_MEMBER(nextObstacleAvoidanceUpdate),
CR_MEMBER(lastTrackUpdate),
CR_MEMBER(skidding),
CR_MEMBER(flying),
CR_MEMBER(skidRotSpeed),
CR_MEMBER(dropSpeed),
CR_MEMBER(dropHeight),
CR_MEMBER(skidRotVector),
CR_MEMBER(skidRotSpeed2),
CR_MEMBER(skidRotPos2),
CR_ENUM_MEMBER(oldPhysState),
CR_MEMBER(mainHeadingPos),
CR_MEMBER(useMainHeading),
CR_RESERVED(64),
CR_POSTLOAD(PostLoad)
));
const unsigned int MAX_REPATH_FREQUENCY = 30; //The minimum of frames between two full path-requests.
const float ETA_ESTIMATION = 1.5f; //How much time the unit are given to reach the waypoint.
const float MAX_WAYPOINT_DISTANCE_FACTOR = 2.0f; //Used to tune how often new waypoints are requested. Multiplied with MinDistanceToWaypoint().
const float MAX_OFF_PATH_FACTOR = 20; //How far away from a waypoint a unit could be before a new path is requested.
const float MINIMUM_SPEED = 0.01f; //Minimum speed a unit may move in.
static const bool DEBUG_CONTROLLER=false;
std::vector<int2> (*CGroundMoveType::lineTable)[11] = 0;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CGroundMoveType::CGroundMoveType(CUnit* owner)
: CMoveType(owner),
accRate(0.01f),
turnRate(0.1f),
baseTurnRate(0.1f),
// maxSpeed(0.2f),
wantedSpeed(0),
moveType(0),
oldPos(owner?owner->pos:float3(0,0,0)),
oldSlowUpdatePos(oldPos),
flatFrontDir(1,0,0),
deltaSpeed(0),
deltaHeading(0),
skidding(false),
flying(false),
dropHeight(0),
skidRotSpeed(0),
floatOnWater(false),
skidRotVector(UpVector),
skidRotSpeed2(0),
skidRotPos2(0),
pathId(0),
goal(0,0,0),
goalRadius(0),
waypoint(0,0,0),
nextWaypoint(0,0,0),
etaWaypoint(0),
etaWaypoint2(0),
terrainSpeed(1),
atGoal(false),
haveFinalWaypoint(false),
requestedSpeed(0),
requestedTurnRate(0),
currentDistanceToWaypoint(0),
currentSpeed(0),
avoidanceVec(0,0,0),
restartDelay(0),
lastGetPathPos(0,0,0),
pathFailures(0),
etaFailures(0),
nonMovingFailures(0),
nextDeltaSpeedUpdate(0),
nextObstacleAvoidanceUpdate(0),
oldPhysState(CSolidObject::OnGround),
lastTrackUpdate(0),
mainHeadingPos(0,0,0),
useMainHeading(false)
{
if (owner){
moveSquareX=(int)owner->pos.x/(SQUARE_SIZE*2);
moveSquareY=(int)owner->pos.z/(SQUARE_SIZE*2);
} else {
moveSquareX = 0;
moveSquareY = 0;
}
}
CGroundMoveType::~CGroundMoveType()
{
if(pathId)
pathManager->DeletePath(pathId);
if(owner->myTrack)
groundDecals->RemoveUnit(owner);
}
void CGroundMoveType::PostLoad()
{
//HACK:Initializing path after load
if (pathId) {
pathId = pathManager->RequestPath(owner->mobility->moveData, owner->pos, goal, goalRadius,owner);
}
}
void CGroundMoveType::Update()
{
//Update mobility.
owner->mobility->maxSpeed = maxSpeed;
if(owner->transporter) {
return;
}
if(OnSlope()
&& (!floatOnWater || ground->GetHeight(owner->midPos.x, owner->midPos.z) > 0))
{
skidding = true;
}
if(skidding){
UpdateSkid();
return;
}
//set drop height when we start to drop
if(owner->falling) {
UpdateControlledDrop();
return;
}
if (owner->stunned) {
owner->cob->Call(COBFN_StopMoving);
owner->speed = ZeroVector;
}
if (!owner->stunned) {
#ifdef DIRECT_CONTROL_ALLOWED
if (owner->directControl) {
waypoint = owner->pos+owner->frontdir * 100;
waypoint.CheckInBounds();
if (owner->directControl->forward) {
wantedSpeed = maxSpeed * 2;
SetDeltaSpeed();
owner->isMoving = true;
owner->cob->Call(COBFN_StartMoving);
} else {
wantedSpeed = 0;
SetDeltaSpeed();
owner->isMoving = false;
owner->cob->Call(COBFN_StopMoving);
}
short deltaHeading = 0;
if (owner->directControl->left) {
deltaHeading += (short) turnRate;
}
if (owner->directControl->right) {
deltaHeading -= (short) turnRate;
}
ENTER_UNSYNCED;
if (gu->directControl == owner)
camera->rot.y += deltaHeading * PI / 32768;
ENTER_SYNCED;
ChangeHeading(owner->heading + deltaHeading);
} else
#endif
if (pathId || currentSpeed > 0.0f) {
// TODO: Stop the unit from moving as a reaction on collision/explosion physics.
// Initial calculations.
currentDistanceToWaypoint = owner->pos.distance2D(waypoint);
if (pathId && !atGoal && gs->frameNum > etaWaypoint) {
etaFailures += 10;
etaWaypoint = INT_MAX;
if (DEBUG_CONTROLLER)
logOutput.Print("eta failure %i %i %i %i %i", owner->id, pathId, !atGoal, currentDistanceToWaypoint < MinDistanceToWaypoint(), gs->frameNum > etaWaypoint);
}
if (pathId && !atGoal && gs->frameNum > etaWaypoint2) {
if (owner->pos.distance2D(goal) > 200 || CheckGoalFeasability()) {
etaWaypoint2 += 100;
} else {
if (DEBUG_CONTROLLER)
logOutput.Print("Goal clogged up2 %i", owner->id);
Fail();
}
}
// Set direction to waypoint.
float3 waypointDir = waypoint - owner->pos;
waypointDir.y = 0;
waypointDir.Normalize();
// Has reached the waypoint? (=> arrived at goal)
if (pathId && !atGoal && haveFinalWaypoint && (owner->pos - waypoint).SqLength2D() < SQUARE_SIZE * SQUARE_SIZE * 2) {
Arrived();
}
//-- Steering --//
// Apply obstacle avoidance.
float3 desiredVelocity = /* waypointDir / */ ObstacleAvoidance(waypointDir);
if(desiredVelocity != ZeroVector){
ChangeHeading(GetHeadingFromVector(desiredVelocity.x, desiredVelocity.z));
} else {
SetMainHeading();
}
if (nextDeltaSpeedUpdate <= gs->frameNum) {
wantedSpeed = pathId? requestedSpeed: 0;
// If arriving at waypoint, then need to slow down, or may pass it.
if (!owner->commandAI->HasMoreMoveCommands()
&& currentDistanceToWaypoint < BreakingDistance(currentSpeed) + SQUARE_SIZE) {
wantedSpeed = std::min((float) wantedSpeed, (float) (sqrt(currentDistanceToWaypoint * -owner->mobility->maxBreaking)));
}
wantedSpeed *= max(0.0f, std::min(1.0f, desiredVelocity.dot(owner->frontdir) + 0.1f));
SetDeltaSpeed();
}
} else {
SetMainHeading();
}
if (wantedSpeed > 0 || currentSpeed > 0) {
currentSpeed += deltaSpeed;
float3 tempSpeed = flatFrontDir * currentSpeed;
owner->pos += tempSpeed;
float wh;
if (floatOnWater) {
wh = ground->GetHeight(owner->pos.x, owner->pos.z);
if (wh == 0)
wh =- owner->unitDef->waterline;
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
// need this to stop jitter when falling
if (!(owner->falling || flying)) {
owner->pos.y = wh;
}
}
}
if (owner->pos != oldPos) {
// these checks must be executed even when we are stunned
TestNewTerrainSquare();
CheckCollision();
float wh;
if (floatOnWater) {
wh = ground->GetHeight(owner->pos.x, owner->pos.z);
if (wh == 0)
wh=-owner->unitDef->waterline;
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
if (!(owner->falling || flying))
owner->pos.y = wh;
owner->speed = owner->pos-oldPos;
owner->midPos = owner->pos + owner->frontdir * owner->relMidPos.z + owner->updir * owner->relMidPos.y + owner->rightdir * owner->relMidPos.x;
oldPos = owner->pos;
if (groundDecals && owner->unitDef->leaveTracks && (lastTrackUpdate < gs->frameNum - 7) &&
((owner->losStatus[gu->myAllyTeam] & LOS_INLOS) || gu->spectatingFullView)) {
lastTrackUpdate = gs->frameNum;
groundDecals->UnitMoved(owner);
}
} else {
owner->speed = ZeroVector;
}
}
void CGroundMoveType::SlowUpdate()
{
if(owner->transporter){
if(progressState == Active)
StopEngine();
return;
}
//If got too far away from path, then need to reconsider.
if(progressState == Active && etaFailures>8) {
if(owner->pos.distance2D(goal)>200 || CheckGoalFeasability()){
if(DEBUG_CONTROLLER)
logOutput.Print("Unit eta failure %i",owner->id);
StopEngine();
StartEngine();
} else {
if(DEBUG_CONTROLLER)
logOutput.Print("Goal clogged up %i",owner->id);
Fail();
}
}
//If the action is active, but not the engine and the
//re-try-delay has passed, then start the engine.
if(progressState == Active && !pathId && gs->frameNum > restartDelay) {
if(DEBUG_CONTROLLER)
logOutput.Print("Unit restart %i",owner->id);
StartEngine();
}
owner->pos.CheckInBounds(); //just kindly move it into the map again instead of deleteing
float wh; //need the following if the ground change height when unit stand still
if(floatOnWater){
wh = ground->GetHeight(owner->pos.x, owner->pos.z);
if(wh==0)
wh=-owner->unitDef->waterline;
} else {
wh = ground->GetHeight2(owner->pos.x, owner->pos.z);
}
if (!(owner->falling || flying))
owner->pos.y=wh;
if(!(owner->pos==oldSlowUpdatePos)){
oldSlowUpdatePos=owner->pos;
int newmapSquare=ground->GetSquare(owner->pos);
if(newmapSquare!=owner->mapSquare){
owner->mapSquare=newmapSquare;
loshandler->MoveUnit(owner,false);
if(owner->hasRadarCapacity)
radarhandler->MoveUnit(owner);
// owner->UnBlock();
// owner->Block();
}
qf->MovedUnit(owner);
owner->isUnderWater=owner->pos.y+owner->height<1;
}
}
/*
Sets unit to start moving against given position with max speed.
*/
void CGroundMoveType::StartMoving(float3 pos, float goalRadius) {
StartMoving(pos, goalRadius, maxSpeed*2);
}
/*
Sets owner unit to start moving against given position with requested speed.
*/
void CGroundMoveType::StartMoving(float3 moveGoalPos, float goalRadius, float speed)
{
#ifdef TRACE_SYNC
tracefile << "Start moving called: ";
tracefile << owner->pos.x << " " << owner->pos.y << " " << owner->pos.z << " " << owner->id << "\n";
#endif
if(progressState == Active) {
StopEngine();
}
//Sets the new goal.
goal = moveGoalPos;
goalRadius = goalRadius;
requestedSpeed = min(speed, maxSpeed*2);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?