Gah - a solution with more questions. – EntropicLqd
Legacy:An AI Concept
Disclaimer: This page represents an idea for a proposed way of coding some particular functionality / behavior in UnrealScript. It does not represent the way that UT / UT2003 / UT2004 actually do things in the normal game engine.
Contents
Introduction
I'm going to generalize for a minute briefly and explain that in a game "world," any and every object has a behaviour. Even if it's as simple as a cup or as complex as monster. Each behaviour can be more eaisily comprehended if split up into two categories:
- General Behaviour
- Specific Behaviour
General Behaviours are behaviours that all objects of a certain type know. With Unreal, most monsters general behaviour is located in their parent class. For example the Skaarj:
class Skaarj extends ScriptedPawn; //some behavioural code
ScriptedPawn is the Skaarj's parent class, and defines general behaviour for all instances of itself. And down the heirarchy:
class SkaarjWarrior extends Skaarj; //some behavioural code
Where Skaarj is the parent class and contains general behaviour code for all instances of itself. SkaarjWarrior now has the behaviour defined in Skaarj, general, and it's own behaviour for doing more "specific to it" things, specific. This concept is old and for new coders, is called inheritance. (If your one of those newer coders, I'd suggest reading a tutorial on Object Oriented Programming before you continue).
The New Pattern
Before I actually show how to implement the new patten, I'd like to explain what it does, and if you should use it.
What does it do?
I can best show you what it does by using an example. Most of it is pseudo code, but it gets the point across ;).
Basically, the pattern creates a class structure for creating GENERAL TYPES of monsters with specific behaviours. It allows you to make one class for every general type of monster, one behaviour for every general type of behaviour, and allow both to be used in eachother.This requires two new classes, class Behaviour, and class Creature:
class Behaviour extends ScriptedPawn; //an instance of every sub-class of behaviour will need to be here(eventually)
class Creature extends ScriptedPawn; //Every variable that a subclass of Creature needs will go here(eventually)
Note that I say 'general' several times in that paragraph. The classes NEED to be general. Example: Say I wanted to create a new brute that can crouch and hide behind boxes, shoot missles and machine guns, and talk to the player. To do this, I could create a general 'Creature' class called newBrute and a general 'Behaviour' classes called Hiding:
class newBrute extends Creature;
class Hiding extends Behaviour;
Notice that it isin't 'HidngBehindBoxes', or 'BruteWarrior' extending Brute. They are both general names and both general classes. newBrute will define more specific functions for instances of itself and Hiding will define functions for hiding. All sub-classes of Behaviour are abstract, or only contain functions that make up an interface. Let us map out what needs to be in each class:
- newBrute
- UseMachineGun()
- UseMissileLauncher()
- CheckWeaponStates()
- CheckHealthState()
- SeePlayer()
- Hiding
- CheckForBox()
- CheckForShadows()
- HideBehindNearestBox()
- HideBehindNearestShadow()
(By no means are these complete, they are just for the sake of the example)
A redefinition of Creature:
// same class as before just added on to class Creature extends ScriptedPawn; var Behaviour _behaviour;
Now that we have mapped out what will be needed for the newBrute and Hiding, we will continue to define states:
- newBrute
- TalkingToPlayer
- Firing
- Idling
- Hiding
- TalkingToPlayer
- A state for calling functions that send logs to players.
- Firing
- A state that calls firing functions and plays animations.
- Idling
- A state that checks ammo and checks which weapons can be used.
- HidingBehindBox
- A state for using the _behaviour instance for calling the 'Hiding' interface.
No states will be needed for Hiding, for it is abstract.
//The same class as above, just added on to class newBrute extends Creature; //--------------------------------------------------- // Functions //--------------------------------------------------- function UseMachineGun() { //code } function UseMissileLauncher() { //code } function CheckWeaponStates() { //code } function CheckHealthState() { //code } function SeePlayer(actor SeenPlayer) { //code } //------------------------------------------------------------- // States //------------------------------------------------------------- state TalkingToPlayer { Begin: //code } state Firing { Begin: //code } state Idling { Begin: //code } state Hiding { Begin: //code }
// same class as above, just added on to class Hiding extends Behaviour; //------------------------------------ // Functions //------------------------------------ function CheckForBoxes() { //code } function CheckForShadows() { //code } function HideBehindNearestBox(Creature _creature) { //code } function HideBehindNearestShadow(Creature _creature) { //code }
Now the Behaviour class can be modified:
//same class as above, just added on to class Behaviour extends ScriptedPawn; var Hiding _hiding; // an instance of the Hiding class
Now the _behaviour instance can be used in newBrute to access 'Hiding' interface.
class newBrute extends Creature; var actor player; //--------------------------------------------------- // Functions //--------------------------------------------------- function UseMachineGun() { //code } function UseMissileLauncher() { //code } function CheckWeaponStates() { //code } function CheckHealthState() { if(self.health <= 50) { GotoState('Hiding'); } } function SeePlayer(actor Seenplayer) { SeenPlayer = player; } //------------------------------------------------------------- // States //------------------------------------------------------------- state TalkingToPlayer { Begin: //code } state Firing { Begin: //code } state Idling { Begin: //code } state Hiding { Begin: behaviour._hiding.HideBehindBox(self); CheckHealthState(); }
Is It For Me
Well, thats not really an easy question to awnser. But here are somethings to check over. If you can awnser yes to these questions I would try the concept, just to see what can be gotten out of it, explore it.
- Am I making a mod where I want to include my own models and meshes?
- Is my mod large enough to be doing all this work for just a few monsters?
- Am I going to be adding a lot of new features with AI?
- Will I be making new weapons and items in my mod?
- If my mod is multiplayer, is this system appropriate?
The Concept Extended (More Advanced)
Semi-Abstract Classes
I like to call Creature and Behaviour 'semi-abstract classes' because they aren't really abstract, they contain variables and functions just like any other class. They become semi-abstract because they are basically interfaces for accessing multiple interfaces.
Sub-whatta?
I like to define these terms in this way:
- Sub-Behavioural classes
- Any class that inherits 'Behaviour' a sub-behavioural class.
- Sub-Creature classes
- Any class that inherits 'Creature' a sub-creature class.
Polymorphism
Many elements of the pattern will be polymorphic. Hence the terms semisub-polymorphic, sub-polymorphic, and semi-abstract polymorphic. A behavioural trigger which can be called by the creature could use polymorphism by having the creature call the trigger placed somewhere in some map, and having it call some interface to change that creatures behaviour, all at runtime. More on this will be added later.
Conclusion
The pattern can be used on anything, not just AI, just with a little change insystem. Weapons, items, etc. all have behaviours... One could write general classes for every type of item or weapon or whatever and provide interfaces through behaviour and '_Item' instead of Creature, or _Weapon. Remember, it's just a concept, a theory, don't live by it... Much is untested. Take it and expand it... find ways to make it better.
Cory Vogel 2002
fusion815@cox.net
Questions?
email me :)
Related Topics
- Artificial Intelligence – Super Topic for all AI (custom or stock)
Discussion
Foogod: I added the disclaimer at the top, because the way these pages are linked from Artificial Intelligence could confuse some people into thinking this is an explanation of the way that the UT-based games actually do things.
Ghost3021:fixed a typo, "just a some monsters? is now "for just a few monsters?". ;)
SuperApe: I hope Cory doesn't mind; I took out a lot of unecessary spacing in the code and text of this page.