mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-25 11:26:37 +00:00 
			
		
		
		
	refactor pathfinding code in AiWander: use AiPackage::pathTo, reuse AiPackage::ObstacleCheck
This commit is contained in:
		
							parent
							
								
									b304e98568
								
							
						
					
					
						commit
						0793e4a80e
					
				
					 5 changed files with 31 additions and 33 deletions
				
			
		|  | @ -68,7 +68,8 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr | ||||||
|     { |     { | ||||||
|         bool wasShortcutting = mIsShortcutting; |         bool wasShortcutting = mIsShortcutting; | ||||||
|         bool destInLOS = false; |         bool destInLOS = false; | ||||||
|         mIsShortcutting = shortcutPath(start, dest, actor, &destInLOS); // try to shortcut first
 |         if (getTypeId() != TypeIdWander) // prohibit shortcuts for AiWander
 | ||||||
|  |             mIsShortcutting = shortcutPath(start, dest, actor, &destInLOS); // try to shortcut first
 | ||||||
| 
 | 
 | ||||||
|         if (!mIsShortcutting) |         if (!mIsShortcutting) | ||||||
|         { |         { | ||||||
|  | @ -139,8 +140,10 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur | ||||||
|     MWWorld::Ptr door = getNearbyDoor(actor); // NOTE: checks interior cells only
 |     MWWorld::Ptr door = getNearbyDoor(actor); // NOTE: checks interior cells only
 | ||||||
|     if (door != MWWorld::Ptr()) |     if (door != MWWorld::Ptr()) | ||||||
|     { |     { | ||||||
|         if (!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() |         // note: AiWander currently does not open doors
 | ||||||
|                 && door.getCellRef().getLockLevel() <= 0 && door.getClass().getDoorState(door) == 0) { |         if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() | ||||||
|  |                 && door.getCellRef().getLockLevel() <= 0 && door.getClass().getDoorState(door) == 0) | ||||||
|  |         { | ||||||
|             MWBase::Environment::get().getWorld()->activateDoor(door, 1); |             MWBase::Environment::get().getWorld()->activateDoor(door, 1); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -70,8 +70,6 @@ namespace MWMechanics | ||||||
|         unsigned short mIdleAnimation; |         unsigned short mIdleAnimation; | ||||||
|         std::vector<unsigned short> mBadIdles; // Idle animations that when called cause errors
 |         std::vector<unsigned short> mBadIdles; // Idle animations that when called cause errors
 | ||||||
| 
 | 
 | ||||||
|         PathFinder mPathFinder; |  | ||||||
|          |  | ||||||
|         AiWanderStorage(): |         AiWanderStorage(): | ||||||
|             mTargetAngleRadians(0), |             mTargetAngleRadians(0), | ||||||
|             mTurnActorGivingGreetingToFacePlayer(false), |             mTurnActorGivingGreetingToFacePlayer(false), | ||||||
|  | @ -87,7 +85,7 @@ namespace MWMechanics | ||||||
|      |      | ||||||
|     AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat): |     AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat): | ||||||
|         mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat) |         mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat) | ||||||
|       , mStoredInitialActorPosition(false) |       , mStoredInitialActorPosition(false), mIsWanderDestReady(false) | ||||||
|     { |     { | ||||||
|         mIdle.resize(8, 0); |         mIdle.resize(8, 0); | ||||||
|         init(); |         init(); | ||||||
|  | @ -252,7 +250,7 @@ namespace MWMechanics | ||||||
|         if ((wanderState == Wander_MoveNow) && mDistance) |         if ((wanderState == Wander_MoveNow) && mDistance) | ||||||
|         { |         { | ||||||
|             // Construct a new path if there isn't one
 |             // Construct a new path if there isn't one
 | ||||||
|             if(!storage.mPathFinder.isPathConstructed()) |             if(!mPathFinder.isPathConstructed()) | ||||||
|             { |             { | ||||||
|                 if (mAllowedNodes.size()) |                 if (mAllowedNodes.size()) | ||||||
|                 { |                 { | ||||||
|  | @ -290,7 +288,7 @@ namespace MWMechanics | ||||||
| 
 | 
 | ||||||
|     void AiWander::returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos) |     void AiWander::returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos) | ||||||
|     { |     { | ||||||
|         if (!storage.mPathFinder.isPathConstructed()) |         if (!mPathFinder.isPathConstructed()) | ||||||
|         { |         { | ||||||
|             ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); |             ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); | ||||||
| 
 | 
 | ||||||
|  | @ -298,10 +296,11 @@ namespace MWMechanics | ||||||
|             ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); |             ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); | ||||||
| 
 | 
 | ||||||
|             // don't take shortcuts for wandering
 |             // don't take shortcuts for wandering
 | ||||||
|             storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell()); |             mPathFinder.buildSyncedPath(start, dest, actor.getCell()); | ||||||
| 
 | 
 | ||||||
|             if (storage.mPathFinder.isPathConstructed()) |             if (mPathFinder.isPathConstructed()) | ||||||
|             { |             { | ||||||
|  |                 mIsWanderDestReady = true; | ||||||
|                 storage.mState = Wander_Walking; |                 storage.mState = Wander_Walking; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -371,7 +370,7 @@ namespace MWMechanics | ||||||
|         float duration, AiWanderStorage& storage, ESM::Position& pos) |         float duration, AiWanderStorage& storage, ESM::Position& pos) | ||||||
|     { |     { | ||||||
|         // Are we there yet?
 |         // Are we there yet?
 | ||||||
|         if (storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) |         if (mIsWanderDestReady && pathTo(actor, mPathFinder.getPath().back(), duration, DESTINATION_TOLERANCE)) | ||||||
|         { |         { | ||||||
|             stopWalking(actor, storage); |             stopWalking(actor, storage); | ||||||
|             storage.mState = Wander_ChooseAction; |             storage.mState = Wander_ChooseAction; | ||||||
|  | @ -414,34 +413,21 @@ namespace MWMechanics | ||||||
| 
 | 
 | ||||||
|     void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos) |     void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos) | ||||||
|     { |     { | ||||||
|         // turn towards the next point in mPath
 |         if (mObstacleCheck.isEvading()) | ||||||
|         zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); |  | ||||||
| 
 |  | ||||||
|         MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor); |  | ||||||
|         if (mObstacleCheck.check(actor, duration)) |  | ||||||
|         { |         { | ||||||
|             // first check if we're walking into a door
 |             // first check if we're walking into a door
 | ||||||
|             if (proximityToDoor(actor)) // NOTE: checks interior cells only
 |             if (proximityToDoor(actor)) // NOTE: checks interior cells only
 | ||||||
|             { |             { | ||||||
|                 // remove allowed points then select another random destination
 |                 // remove allowed points then select another random destination
 | ||||||
|                 mTrimCurrentNode = true; |                 mTrimCurrentNode = true; | ||||||
|                 trimAllowedNodes(mAllowedNodes, storage.mPathFinder); |                 trimAllowedNodes(mAllowedNodes, mPathFinder); | ||||||
|                 mObstacleCheck.clear(); |                 mObstacleCheck.clear(); | ||||||
|                 storage.mPathFinder.clearPath(); |                 mPathFinder.clearPath(); | ||||||
|                 storage.mState = Wander_MoveNow; |                 storage.mState = Wander_MoveNow; | ||||||
|             } |             } | ||||||
|             else // probably walking into another NPC
 | 
 | ||||||
|             { |  | ||||||
|                 // TODO: diagonal should have same animation as walk forward
 |  | ||||||
|                 //       but doesn't seem to do that?
 |  | ||||||
|                 mObstacleCheck.takeEvasiveAction(movement); |  | ||||||
|             } |  | ||||||
|             mStuckCount++;  // TODO: maybe no longer needed
 |             mStuckCount++;  // TODO: maybe no longer needed
 | ||||||
|         } |         } | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             movement.mPosition[1] = 1; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         // if stuck for sufficiently long, act like current location was the destination
 |         // if stuck for sufficiently long, act like current location was the destination
 | ||||||
|         if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset
 |         if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset
 | ||||||
|  | @ -564,11 +550,12 @@ namespace MWMechanics | ||||||
|         ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos)); |         ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos)); | ||||||
| 
 | 
 | ||||||
|         // don't take shortcuts for wandering
 |         // don't take shortcuts for wandering
 | ||||||
|         storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell()); |         mPathFinder.buildSyncedPath(start, dest, actor.getCell()); | ||||||
|         storage.mPathFinder.buildPath(start, dest, actor.getCell()); |  | ||||||
| 
 | 
 | ||||||
|         if (storage.mPathFinder.isPathConstructed()) |         if (mPathFinder.isPathConstructed()) | ||||||
|         { |         { | ||||||
|  |             mIsWanderDestReady = true; | ||||||
|  | 
 | ||||||
|             // Remove this node as an option and add back the previously used node (stops NPC from picking the same node):
 |             // Remove this node as an option and add back the previously used node (stops NPC from picking the same node):
 | ||||||
|             ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; |             ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; | ||||||
|             mAllowedNodes.erase(mAllowedNodes.begin() + randNode); |             mAllowedNodes.erase(mAllowedNodes.begin() + randNode); | ||||||
|  | @ -624,7 +611,8 @@ namespace MWMechanics | ||||||
| 
 | 
 | ||||||
|     void AiWander::stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage) |     void AiWander::stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage) | ||||||
|     { |     { | ||||||
|         storage.mPathFinder.clearPath(); |         mPathFinder.clearPath(); | ||||||
|  |         mIsWanderDestReady = false; | ||||||
|         actor.getClass().getMovementSettings(actor).mPosition[1] = 0; |         actor.getClass().getMovementSettings(actor).mPosition[1] = 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -850,6 +838,7 @@ namespace MWMechanics | ||||||
|         , mRepeat(wander->mData.mShouldRepeat != 0) |         , mRepeat(wander->mData.mShouldRepeat != 0) | ||||||
|         , mStoredInitialActorPosition(wander->mStoredInitialActorPosition) |         , mStoredInitialActorPosition(wander->mStoredInitialActorPosition) | ||||||
|         , mStartTime(MWWorld::TimeStamp(wander->mStartTime)) |         , mStartTime(MWWorld::TimeStamp(wander->mStartTime)) | ||||||
|  |         , mIsWanderDestReady(false) | ||||||
|     { |     { | ||||||
|         if (mStoredInitialActorPosition) |         if (mStoredInitialActorPosition) | ||||||
|             mInitialActorPosition = wander->mInitialActorPosition; |             mInitialActorPosition = wander->mInitialActorPosition; | ||||||
|  |  | ||||||
|  | @ -130,9 +130,9 @@ namespace MWMechanics | ||||||
|                                   const PathFinder& pathfinder); |                                   const PathFinder& pathfinder); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| //             ObstacleCheck mObstacleCheck;
 |  | ||||||
|             float mDoorCheckDuration; |             float mDoorCheckDuration; | ||||||
|             int mStuckCount; |             int mStuckCount; | ||||||
|  |             bool mIsWanderDestReady; | ||||||
| 
 | 
 | ||||||
|             // constants for converting idleSelect values into groupNames
 |             // constants for converting idleSelect values into groupNames
 | ||||||
|             enum GroupIndex |             enum GroupIndex | ||||||
|  |  | ||||||
|  | @ -93,6 +93,11 @@ namespace MWMechanics | ||||||
|         return mWalkState == State_Norm; |         return mWalkState == State_Norm; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     bool ObstacleCheck::isEvading() const | ||||||
|  |     { | ||||||
|  |         return mWalkState == State_Evade; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /*
 |     /*
 | ||||||
|      * input   - actor, duration (time since last check) |      * input   - actor, duration (time since last check) | ||||||
|      * output  - true if evasive action needs to be taken |      * output  - true if evasive action needs to be taken | ||||||
|  |  | ||||||
|  | @ -33,6 +33,7 @@ namespace MWMechanics | ||||||
|             void clear(); |             void clear(); | ||||||
| 
 | 
 | ||||||
|             bool isNormalState() const; |             bool isNormalState() const; | ||||||
|  |             bool isEvading() const; | ||||||
| 
 | 
 | ||||||
|             // Returns true if there is an obstacle and an evasive action
 |             // Returns true if there is an obstacle and an evasive action
 | ||||||
|             // should be taken
 |             // should be taken
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue