⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 attackgroup.cpp

📁 这是整套横扫千军3D版游戏的源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
		vector<float3> enemyPositions;
		enemyPositions.reserve(numEnemies);

		// make a vector with the positions of all enemies
		for (int i = 0; i < numEnemies; i++) {
			if( unitArray[i] != -1) {
				const UnitDef* enemy_ud = ai->cheat->GetUnitDef(unitArray[i]);
				float3 enemyPos = ai->cheat->GetUnitPos(unitArray[i]);

				// store enemy position if unit not cloaked and not an aircraft
				if (ai->cb->GetUnitDef(unitArray[i]) != NULL && this->CloakedFix(unitArray[i]) && !enemy_ud->canfly) {
					// TODO: remove currently cloaked units
					// TODO: remove units not reachable by my unit type and position
					enemyPositions.push_back(enemyPos);
				}
			}
		}

		// if ALL units are cloaked or aircraft, get their positions anyway
		if (enemyPositions.size() == 0) {
			for (int i = 0; i < numEnemies; i++) {
				if (unitArray[i] != -1) {
					float3 enemyPos = ai->cheat->GetUnitPos(unitArray[i]);
					enemyPositions.push_back(enemyPos);
				}
			}
		}

		// find path to general enemy position
		pathToTarget.clear();
		float costToTarget = ai->pather->FindBestPath(&pathToTarget, &groupPosition, lowestAttackRange, &enemyPositions);

		if (costToTarget < 0.001f && pathToTarget.size() <= 2) {
			// cost of zero means something is in range, isShooting will take care of it
			isMoving = false;
		}
		else {
			isMoving = true;
			this->pathIterator = 0;
		}
	}
	else {
		// attempt to path back to base if there are no targets
		// KLOOTNOTE: this branch is now purposely never taken
		// (might not be the best idea to leave units lingering
		// around however)
		return;
        pathToTarget.clear();
		float3 closestBaseSpot = ai->ah->GetClosestBaseSpot(groupPosition);
		float costToTarget = ai->pather->FindBestPathToRadius(&pathToTarget, &groupPosition, THREATRES * 8, &closestBaseSpot);

		// TODO: GetKBaseMeans() for support of multiple islands/movetypes
		// TODO: this doesn't need to be to radius

		if (costToTarget == 0 && pathToTarget.size() <= 2) {
			isMoving = false;

			if (ai->ah->DistanceToBase(groupPosition) > 500) {
				// we could not path back to closest base spot
			}
		}
		else {
			isMoving = true;
			this->pathIterator = 0;
		}
	}

	if (!isShooting && !isMoving) {
		// no accessible enemies and we're idling
	}
}



bool CAttackGroup::NeedsNewTarget() {
	return (defending && !isShooting && !isMoving);
}

void CAttackGroup::ClearTarget() {
	this->isMoving = false;
	this->defending = true;
	this->attackPosition = ZEROVECTOR;
	this->attackRadius = 0.0f;
	this->pathToTarget.clear();
	// to avoid getting a new target the first frame after arrival
	this->isShooting = true;
}




// called from CAttackHandler::Update()
void CAttackGroup::Update(int frameNr) {
	int frameSpread = 30;
	unsigned int numUnits = units.size();

	if (!numUnits) {
		// empty attack group, nothing to update
		return;
	}

	float3 groupPosition = GetGroupPos();

	if (groupPosition == ERRORVECTOR)
		return;


	// this part of the code checks for nearby enemies and does focus fire/maneuvering
	if ((frameNr % frameSpread) == ((groupID * 4) % frameSpread)) {
		isShooting = false;

		// get all enemies within attack range
		float range = highestAttackRange + 100.0f;
		int numEnemies = ai->cheat->GetEnemyUnits(unitArray, groupPosition, range);

		if (numEnemies > 0) {
			// select one of the enemies
			int enemySelected = SelectEnemy(numEnemies, groupPosition);

			// for every unit, pathfind to enemy perifery (with personal range - 10) then
			// if distance to that last point in the path is < 10 or cost is 0, attack

			if (enemySelected != -1) {
				AttackEnemy(enemySelected, numUnits, range, frameSpread);
			}
		}
	}


	if (pathToTarget.size() >= 2) {
		// AssignToTarget() was called for this group so
		// we have an attack position and path, just move
		// (movement may be slow due to spreading of orders)
		if (!isShooting && isMoving && (frameNr % 60 == (groupID * 5) % frameSpread)) {
			MoveAlongPath(groupPosition, numUnits);
		}
	} else {
		// find something to attack within visual and radar LOS if AssignToTarget() wasn't called
		if ((defending && !isShooting && !isMoving) && (frameNr % 60 == groupID % 60)) {
			FindDefenseTarget(groupPosition, frameNr);
		}
	}
}




int CAttackGroup::SelectEnemy(int numEnemies, const float3& groupPos) {
	int enemySelected = -1;
	float shortestDistanceFound = FLT_MAX;
	float temp;

	for (int i = 0; i < numEnemies; i++) {
		// my range not considered in picking the closest one
		// TODO: is it air? is it cloaked?
		bool b1 = ((temp = groupPos.distance2D(ai->cheat->GetUnitPos(unitArray[i]))) < shortestDistanceFound);
		bool b2 = (ai->cheat->GetUnitDef(unitArray[i]) != NULL);
		bool b3 = CloakedFix(unitArray[i]);
		bool b4 = ai->cheat->GetUnitDef(unitArray[i])->canfly;

		if (b1 && b2 && b3 && !b4) {
			enemySelected = i;
			shortestDistanceFound = temp;
		}
	}

	return enemySelected;
}


void CAttackGroup::AttackEnemy(int enemySelected, int numUnits, float range, int frameSpread) {
	float3 enemyPos = ai->cheat->GetUnitPos(unitArray[enemySelected]);
	assert(CloakedFix(unitArray[enemySelected]));
	isShooting = true;

	for (unsigned int i = 0; i < numUnits; i++) {
		int unit = units[i];
		const UnitDef* udef = ai->cb->GetUnitDef(unit);

		// does our unit exist and is it not currently maneuvering?
		if (udef && (ai->MyUnits[unit]->maneuverCounter-- <= 0)) {
			// TODO: add a routine finding best (not just closest) target
			// TODO: in some cases, force-fire on position
			// TODO: add canAttack
			ai->MyUnits[unit]->Attack(unitArray[enemySelected]);

			// TODO: this should be the max-range of the lowest-ranged weapon
			// the unit has assuming you want to rush in with the heavy stuff
			assert(range >= ai->cb->GetUnitMaxRange(unit));

			// SINGLE UNIT MANEUVERING: testing the possibility of retreating to max
			// range if target is too close, EXCEPT FOR FLAMETHROWER-EQUIPPED units
			float3 myPos = ai->cb->GetUnitPos(unit);
			float maxRange = ai->ut->GetMaxRange(udef);
			float losDiff = (maxRange - udef->losRadius);
		//	float myRange = (losDiff > 0.0f)? (maxRange + udef->losRadius) * 0.5f: maxRange;
			float myRange = (losDiff > 0.0f)? maxRange * 0.75f: maxRange;

			bool b5 = udef->canfly;
			bool b6 = myPos.y < (ai->cb->GetElevation(myPos.x, myPos.z) + 25);
			bool b7 = (myRange - UNIT_MIN_MANEUVER_RANGE_DELTA) > myPos.distance2D(enemyPos);

			// is it air, or air that's landed
			if (!b5 || (b6 && b7)) {
				bool debug1 = true;
				bool debug2 = false;

				vector<float3> tempPath;

				// note 1: we don't need a path, just a position
				// note 2: should avoid other immediate friendly units and/or immediate enemy units + radius
				// maybe include the height parameter in the search? probably not possible
				// doesn't this mean pathing might happen every second? outer limit should harsher than inner
				float3 unitPos = ai->cheat->GetUnitPos(unitArray[enemySelected]);
				float dist = ai->pather->FindBestPathToRadius(&tempPath, &myPos, myRange, &unitPos);

				if (tempPath.size() > 0) {
					float3 moveHere = tempPath.back();
					dist = myPos.distance2D(moveHere);

					// TODO: Penetrators are now broken
					// is the position between the proposed destination and the
					// enemy higher than the average of mine and his height?
					float v1 = ((moveHere.y + enemyPos.y) / 2.0f) + UNIT_MAX_MANEUVER_HEIGHT_DIFFERENCE_UP;
					float v2 = ai->cb->GetElevation((moveHere.x + enemyPos.x) / 2, (moveHere.z + enemyPos.z) / 2);
					bool losHack = v1 > v2;
					float a = (float) UNIT_MIN_MANEUVER_TIME / frameSpread;
					float b = (dist / ai->MyUnits[unit]->def()->speed);
					float c = ceilf(max(a, b));

					// assume the pathfinder returns correct Y values
					// REMEMBER that this will suck for planes
					if (dist > max((UNIT_MIN_MANEUVER_RANGE_PERCENTAGE * myRange), float(UNIT_MIN_MANEUVER_DISTANCE)) && losHack) {
						debug2 = true;
						ai->MyUnits[unit]->maneuverCounter = int(c);
						ai->MyUnits[unit]->Move(moveHere);
					}
				}
				if (debug1 && !debug2) {
					// pathfinder run but path not used?
				}
			}
			else if (!udef->canfly || myPos.y < (ai->cb->GetElevation(myPos.x, myPos.z) + 25)) {
				// this unit is an air unit
			}
		}
		else {
			// OUR unit is dead?
		}
	}
}






// give move orders to units along previously generated pathToTarget
void CAttackGroup::MoveAlongPath(float3& groupPosition, int numUnits) {
	const int maxStepsAhead = 8;
	int pathMaxIndex = (int) pathToTarget.size() - 1;
	int step1 = min(pathIterator + maxStepsAhead / 2, pathMaxIndex);
	int step2 = min(pathIterator + maxStepsAhead, pathMaxIndex);
	float3 moveToHereFirst = pathToTarget[step1];
	float3 moveToHere = pathToTarget[step2];

	// if we aren't there yet
	if (groupPosition.distance2D(pathToTarget[pathMaxIndex]) > GROUP_DESTINATION_SLACK) {
		// TODO: give a group the order instead of each unit
		for (unsigned int i = 0; i < numUnits; i++) {
			int unit = units[i];

			if (ai->cb->GetUnitDef(unit) != NULL) {
				// TODO: when they are near target, change this so they eg. line up
				// while some are here and some aren't, there's also something that
				// should be done with the units in front that are given the same
				// order+shiftorder and skittle around back and forth meanwhile if
				// the single unit isn't there yet
				if (ai->cb->GetUnitPos(unit).distance2D(pathToTarget[pathMaxIndex]) > UNIT_DESTINATION_SLACK) {
					ai->MyUnits[unit]->Move(moveToHereFirst);

					if (moveToHere != moveToHereFirst) {
						ai->MyUnits[unit]->MoveShift(moveToHere);
					}
				}
			}
		}

		// if group is as close as the pathiterator-indicated target
		// is to the end of the path, increase pathIterator

		pathIterator = 0;
		float3 endOfPathPos = pathToTarget[pathMaxIndex];
		float groupDistanceToEnemy = groupPosition.distance2D(endOfPathPos);
		float pathIteratorTargetDistanceToEnemy = pathToTarget[pathIterator].distance2D(endOfPathPos);
		int increment = maxStepsAhead / 2;

		while (groupDistanceToEnemy <= pathIteratorTargetDistanceToEnemy && pathIterator < pathMaxIndex) {
			pathIterator = min(pathIterator + increment, pathMaxIndex);
			pathIteratorTargetDistanceToEnemy = pathToTarget[pathIterator].distance2D(endOfPathPos);
		}

		pathIterator = min(pathIterator, pathMaxIndex);
	}
	else {
		// group thinks it has arrived at the destination
		this->ClearTarget();
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -