Jump to content
  • entries
    13
  • comments
    80
  • views
    34,274

The Adventures of Ken & His Trusty NPCs


Road Kill Kenny

2,093 views

 Share

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

  • Upvote 3
 Share

1 Comment


Recommended Comments

I have finished the standard patrolling behavior for the mobile NPCs. I can now set up a mobile NPC in the editor and give it a pre-determined patrol pattern in the editor that utilizes the path finding grid that I made. That is all working well now.

 

Now it is on to the attacking behavior. I want the units to pause for about 0.7secs or so and simply look at the target before sounding the alarm and then pursuing the target. It will change to a retreat state if it looses too much hp and a seek state if it loses sight of the target. To facilitate these movements I added two new functionalities to the Controller Module including:

 

int TrackEntity(LE::TEntity tgt)

int ChaseEntity(LE::TEntity tgt, float proximity)

 

These functions will automatically track and chase the target entity from the character controller module without the behavior states having to do any more than just call these functions once to initiate the appropriate movements.

Link to comment
Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...