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 + -
显示快捷键?