Project Introduction: based on a variety of open-source Library (ogre, opensteer, Newton, raknet, openal) Game Engine projects, the project is currently under development in version 2.0, the main task is to greatly improve the overall framework of the previous version, establish a robust exception and runtime error handling mechanism, and reconstruct the frameworks of various subsystems, this article is written based on the author's practice of restructuring the AI subsystem.
Design motivation:
1. Low Degree of abstraction. To introduce any new type of things, you must add the corresponding individual or group class and group manager.
2. High coupling between different individuals. It is embodied in the relationship between individuals with a certain relationship, such as the relationship between tracing and tracing. Among them, the status of one type of individual A is directly interfered by the status of another type of individual B (B forces the state change of A by setting a type of sign of ), this is clearly contrary to natural rules and good principles. According to the object-oriented design philosophy, an object should be cohesive as much as possible. That is to say, the object should have its own ability to control all its statuses and changes, if necessary, provide some information (such as location information ).
3. Low flexibility. To add, delete, and update functions, you must modify the code of each individual type.
Design Concept:
1. For design defects with a low degree of abstraction, extract all existing classes and combine them. In addition, the configuration files are dynamically classized during runtime (that is, dynamically determine the type of the created object based on the configuration file and creation parameters, such as Tiger and deer ). All of them are to be extracted and combined, rather than intersection, so that they can form a configuration file rather than code (that is, inheritance) to have classes.
2. By refining the interaction between AI objects, a role-based relationship abstraction is obtained. In this design, each object has one or more roles that interest it. The role Manager manages the role-Object List (1 ). When an object is created, it registers itself to the global role Manager based on its role. When needed, an object can search for the role object it is interested in the role manager, obtain its parameters, and update its status based on the calculated values. As shown in sequence 2.
Figure 1
Figure 2 example sequence diagram (the deer State update process is omitted)
Implementation:
1. the individual abstract class cindividual of AI maintains the intelligence of the individual. It is a subclass of opensteer: simplevehicle and ogre: userdefinedobject.
2. cindividualwrapper, an individual abstract packaging class of AI, is responsible for the visual performance of objects and plays a packaging role on cindividual. It is a friend of cindividual.
3. The role manager template class crolesmanager is implemented as follows:
000001 class cindivi dual;
000002
000003/** global role Manager
000004 @ author %0v (groov0v.luo@gmail.com)
000005
000006 manage the list of objects corresponding to the role
000007 */
000008
000009 template <typename T>
000010 class crolesmanager
000011 {
000012 public:
000013 ~ Crolesmanager ()
000014 {
000015 roleregistrymapiter ITER;
000016 Trav (m_roleregistrymap, ITER)
000017 {
000018 safe_delete (ITER-> second );
000019}
000020}
000021
000022/*** Add the object pointer to the list corresponding to the role ID
000023 */
000024 void add (unsigned int roleid, T * pobj)
000025 {
000026 roleregistrymapiter iter = m_roleregistrymap.find (roleid );
000027 if (ITER! = M_roleregistrymap.end ())
000028 ITER-> second-> push_back (pobj );
000029 else
000030 {
000031 STD: List <t *> * listptr = new STD: List <t *>;
000032 listptr-> push_back (pobj );
000033 m_roleregistrymap.insert (make_pair (roleid, listptr ));
000034}
000035}
000036
000037/*** remove an object from the role list
000038 */
000039 void remove (unsigned int roleid, T * pobj)
000040 {
000041 roleregistrymapiter iter = m_roleregistrymap.find (roleid );
000042 if (ITER! = M_roleregistrymap.end ())
000043 ITER-> second-> erase (pobj );
000044}
000045
000046/** return the list of objects of the specified role
000047 */
000048 STD: List <t *> * getobjlist (unsigned int roleid)
000049 {
000050 roleregistrymapiter iter = m_roleregistrymap.find (roleid );
000051 if (ITER! = M_roleregistrymap.end ())
000052 return ITER-> second;
000053 else
000054 return NULL;
000055}
000056 PRIVATE:
000057/*** role-object Registry
000058 */
000059 stdext: hash_map <unsigned int, STD: List <t *> m_roleregistrymap;
000060 typedef typename stdext: hash_map <unsigned int, STD: List <t *> * >:: iterator roleregistrymapiter;
000061 };
000062
000063 # define g_rolesmanager DMF: globe_instance <crolesmanager <cindividual>: instance ()
000064
4. Configure the script (using tinyxml for reading/saving ):
000001 <aiobjects>
<Object name = "tiger"> 000002
000003 <roles>
000004 <role name = "tracer" id = "0"/>
000005 </roles>
000006 <disroles>
000007 <disrole name = "betracer" id = "1"/>
000008 </disroles>
000009 <numericparams>
000010 <Param name = "sight_distance" value = "1200"/>
000011 <Param name = "pursuit_distance" value = "800"/>
000012 <Param name = "attack_distance" value = "200"/>
000013 <Param name = "pai_straight_time" value = "2.5"/>
000014 <Param name = "pai_time" value = "10.0"/>
000015 <Param name = "idle_time" value = "2.5"/>
000016 <Param name = "pursuit_time" value = "15"/>
000017 <Param name = "pai_speed" value = "20"/>
000018 <Param name = "pursuit_speed" value = "100"/>
000019 <Param name = "attack_speed" value = "120"/>
000020 <Param name = "move_speed" value = "50"/>
000021 <Param name = "length" value = "35"/>
000022 <Param name = "energy" value = "100"/>
000023 <Param name = "steer_force" value = "200"/>
000024 <Param name = "steer_max_speed" value = "150"/>
000025 <Param name = "steer_raduis" value = "25"/>
000026 <Param name = "wandre_jitter" value = "100"/>
000027 <Param name = "wandre_raduis" value = "50"/>
000028 <Param name = "energy_des" value = "20"/>
000029 </numericparams>
000030 <stringparams>
000031 <Param name = "placeholdermatname" value = "goofplaceholdertiger"/>
000032 <Param name = "placeholdermeshname" value = "soundnode. mesh"/>
000033 <Param name = "type" value = "gametigerobject"/>
000034 <Param name = "meshfile" value = "dire_cat.mesh"/>
000035 </stringparams>
000036 <animationstates>
000037 <state ID = "0" name = "cpause1"/>
000038 <state ID = "3" name = "crun"/>
000039 <state ID = "-1" name = "cwalk"/>
000040 </animationstates>
000041 </Object>
000042 <object name = "deer">
000043 <roles>
000044 <role name = "betracer" id = "1"/>
000045 </roles>
000046 <disroles>
000047 <disrole name = "tracer" id = "0"/>
000048 </disroles>
000049 <numericparams>
000050 <Param name = "pai_speed" value = "20"/>
000051 <Param name = "run_speed" value = "120"/>
000052 <Param name = "idle_time" value = "8.0"/>
000053 <Param name = "pai_time" value = "8.0"/>
000054 <Param name = "energy" value = "100"/>
000055 <Param name = "length" value = "35"/>
000056 <Param name = "pai_straight_time" value = "1.5"/>
000057 <Param name = "run_distance" value = "600"/>
000058 <Param name = "safe_distance" value = "820"/>
000059 <Param name = "steer_force" value = "200"/>
000060 <Param name = "steer_max_speed" value = "150"/>
000061 <Param name = "steer_raduis" value = "25"/>
000062 <Param name = "wandre_raduis" value = "50"/>
000063 <Param name = "wandre_jitter" value = "40.0"/>
000064 <Param name = "energy_des" value = "20"/>
000065 </numericparams>
000066 <stringparams>
000067 <Param name = "placeholdermatname" value = "goofplaceholderdeer"/>
000068 <Param name = "placeholdermeshname" value = "soundnode. mesh"/>
000069 <Param name = "type" value = "gamedeerobject"/>
000070 <Param name = "meshfile" value = "deer. mesh"/>
000071 </stringparams>
000072 <animationstates>
000073 <state ID = "0" name = "creadyl"/>
000074 <state ID = "6" name = "crun"/>
000075 <state ID = "-1" name = "cwalk"/>
000076 </animationstates>
000077 </Object>
<Object name = "bird"> 000078
000079 ......
000080 </Object>
000081 <object name = "Butterfly">
000082 ......
000083 </Object>
000084 </aiobjects>