The Adventures of Ken & His Trusty NPCs
NPCs, whether they be ally or enemy, are a very important component for many games and a large portion of a game's game play is highly dependant on the things that NPCs do, they way they behave and, if they are enemies, the way that they try to kill you. Therefore, it is vital that your NPCs, their associated behaviours and AI are done well so as to compliment game play rather than detract from it. If these factors are not 'fit for purpose' then the player will see right through the NPCs and the game will become just another game rather than a world the player can immerse themselves into. This doesn't mean the NPCs have to be human perfect, as I said before, it simply has to be 'fit for purpose'.
With this in mind I set out to firstly create my NPC classes. I had a few attempts before I got it right. Firstly I decided to make a fixed enemy NPC like a turret because I thought it would be easier than a mobile enemy for the first one. I had an idea that there would be two main types of enemies including both fixed and mobile enemies and I made base classes for each of them. The FixedEnemy class was then derived into a unique fixed enemy classes depending on the type of enemy. The FixedEnemy class also inherited from my standard Finite State Machine (FSM) class so that it could handle states of behaviour easily. Following this I created a whole bunch of behaviours that I thought would be necessary in different situations. Different behaviours could easily be slotted in to make many enemies that could behave differently if necessary. The system worked well for the fixed enemy and you can see my original blog on this part of the process here: http://www.leadwerks...a-new-frontier/
After this was completed I decided to leave NPCs an AI while I worked on my new level system and level editor. I have now completed most of the editor and am re-visiting the NPCs and began creating that MobileEnemy class that I had planned. However, when I finished writing the class declaration I found that it was almost exactly the same as the FixedEnemy class. By a force of habit I had made the FixedEnemy class so flexible to the point where there was no need for two separate base classes. This was a good thing but it got me thinking and after a good 10 minutes of pondering I found that my previous thinking was rather flawed. Why were my base classes just for 'enemies' and why did I think that splitting them into fixed and mobile variants was a good idea. Evidently I had already made the class flexible enough to handle any NPC.
As a result of this pondering I went on to make a pure NPC base class that inherited from the FSM class and then was derived into any unique NPC that I wanted whether enemy, ally or neutral. It was mostly just the FixedEnemy class with a different name but there were a few minor changes. This was much cleaner and I liked it. However, there was a bit of a problem. The underlying difference between a mobile NPC and a fixed NPC is that mobile NPCs require a controller for movement. I didn't want to clog up fixed NPCs with controller code that they wouldn't use and I didn't want to create new controller code for every single unique derived NPC that needed one. To solve this I thought back to how my character animator class works where each character has an animator object within it and the animator object handles all animations automatically. In the same modular fashion I created a controller mod that could be attached to any AI driven NPC in the game that requires a character controller. This class would live within the unique derived NPC classes, if applicable, and would be able to handle all the annoying movement code necessary for a lot of things. It is almost like a wrapper for the LE character controller which makes it more automated. The major functionality that I gave the module includes:
SetTurnToAngle(float angle)
SetTurnToFace(LE::TVec3 facePos)
SetMoveToPoint(LE::TVec3)
SetPathToPoint(LE::TVec3)
I was actually rather proud of this module as it is not only code that is re-used a lot it also re-uses a lot of code within itself very well. For example the SetPathToPoint() function simply works by managing the calling of SetMoveToPoint() and SetTurnToFace() functions in a structured manner so that the controller will move from one node to the next in a path. Even the SetMoveToPoint uses the SetTurnTo Face() function to first turn to face the direction that the controller is to move.
With that out of the way I just had to continue to create behaviours for mobile NPCs. I found that my previous method of having slotted behaviours still worked very well and I made no changes there. The behaviours were given access to the NPC modules so that it could call the relevant functions to get the NPC to do what the behaviour decided it should do.
Now that that is all out of the way I am working on the games Alert System. Basically it is like an alarm system where if the player gets seen then an alarm gets set and all NPC's in the immediate area will know your location. This of course means stealth and in terms of stealth the mechanics is 95% with the NPCs further compounding how important NPCs are.
Hope you enjoyed my stories. Sorry no more video's for you guys until official announcment
-
3
1 Comment
Recommended Comments