Simple implementation of the C ++ version behavior tree, simple implementation of js Tree Structure

Source: Internet
Author: User

Simple implementation of the C ++ version behavior tree, simple implementation of js Tree Structure

If you want to repost this article, please strictly follow the following format to indicate the source and author's source: Ghost (in fact, they are all one person ..) The behavior tree is a simple and clear method for organizing business logic. I will not repeat his advantages. Because of the needs of the project, a very simple behavior tree is implemented to meet our needs. The reason for simplicity is that I have not implemented many control nodes, but only three nodes that implement the most basic business. You can modify other control nodes that you find useful. Let's briefly talk about the nodes I implemented: Basic Nodes, single nodes, list nodes, select nodes, sequence nodes, and reverse nodes. These nodes are divided into relatively Basic Nodes and business nodes. Basic Nodes include: Basic Nodes, single nodes, and list nodes. The primary function of a basic node is to define the most basic call method and how to save the subnode. Business nodes include select nodes, ordered nodes, and anti-nodes. Their Inheritance relationships are as follows: Basic Nodes are the most basic nodes; single nodes and list nodes inherit from basic nodes; select nodes and sequence nodes inherit from list nodes; the anti-node is inherited from a single node. To briefly describe the role of each node. Basic Nodes: 1. invoke function. When called, true or false are returned. 2. destroy function, when a node is released, it recursively releases all subnodes and subnodes attached to the node. 3. It sets and obtains the Describe function, this function is used to print the structure description of AITree. 4. It is used to set and obtain the Name. It is used to print the list nodes of recursive description when printing the Name Description and call of AITree: 1. contains an ordered subset list. You can add or retrieve a single referenced node from the subset list: 1. contains a subset node. You can set and obtain a subset node and select a node: 1. When called, if there is no subset node, the system will directly return false. 2. When called, the system will execute previously and later. If any subset node returns true, the loop is terminated, returns true directly. 3. If no subset node returns true, the system returns false ordered nodes. 1. When called, if no subset node exists, false is directly returned. 2. During the call, the previous and subsequent operations are performed in sequence. If false is returned for any subset node, the loop is terminated. false is returned directly. 3. If no subset node returns false, the return value is true: 1. When called, if no subset node exists, false is directly returned. 2. If a subset node exists, a subset node is called, and the result is reversed and returned. After these nodes are implemented, most of the functions can be implemented to show the result. (The hand is relatively defective, and there are no tools around, so use the text to represent it) first, let's briefly explain what the figure means. The first is the node name. It is written during injection, either in Chinese or in English. It doesn't matter. After all, it is only used here. The second parameter is the description of the current instance. If it is used to help you understand the tree, then let us briefly explain what the logic means. This is the logic of a pet. If there is a gold coin nearby, he will pick it up; if there is no gold coin, and it has not been found for a long time and has not returned to the master for a long time, then return to the host, or else you can just walk around. In fact, this logic is really simple, if it is written in a normal way. It will judge the conditions between various States and then perform various jumps. This can be achieved, but later maintenance may be more difficult, if you use the configuration behavior tree is relatively simple, you only need to add a new branch or remove the original branch. The logic is also clearer. Then I will briefly explain how to expand my own things in my gadgets. 1. Add a new enumeration in AITreeNodeType, which is mainly used to determine the Id used for injection (as to what is injection for a while). 2. Then inherit basic nodes, generally, it is better to inherit the three most basic ones. The most common one is AINodeBase. Then we will use AINodeBase as an example. 3. Then implement virtual bool invoke (int level = 0, bool isLog = false); method, level indicates the number of layers of calls starting from the root node. Generally, when used as a Log, there are several spaces in the front. isLog indicates whether to print the Log, you can ignore these two parameters. Of course, you 'd better follow the conventions of these two parameters to implement the corresponding functions. Of course, I don't have any opinions if you don't comply with them. 4. Add a Private static AINodeRegister <Class Name> reg to the class. Then write AINodeRegister <Class Name> AINodeReleaseSkill: reg (NodeId, NodeName) in the Cpp file ); to implement the injection. The first parameter is the Id you obtained before, and the second parameter is the corresponding node name, which may not be the class name. However, we recommend that you use the class name, only when searching, you may find a code that is more intuitive.
// Return to class AINodeGotoOwnerSide: public AINodeBase {private: static AINodeRegister <AINodeGotoOwnerSide> reg; public: virtual bool invoke (int level = 0, bool isLog = false );};
AINodeRegister<AINodeGotoOwnerSide> AINodeGotoOwnerSide::reg(ANT_GOTO_OWNER_SIDE, "AINodeGotoOwnerSide");bool AINodeGotoOwnerSide::invoke(int level, bool isLog){    return rand() % 100 > 20;}
After talking about the tired extension, we should simply talk about what is injection. Simply put, I wrote a public help function to accept the Id and a function pointer to create a node, then, store them in the dictionary. When you need to call them, I will look for the previously injected function pointer from the dictionary and call it to give you an instance. As to why do we need to write a static AINodeRegister generic class, it is because static initialization will be initiated when the real program is started. By applying this feature, we can set it during initialization, the content to be initialized is injected into the memory. In fact, the main logic is basically the same. There are also some other aspects, such as how to handle tree assembly. It would be very troublesome to write references between them one by one. In addition, when this structure is used to process the business logic, the business content will be divided into different places, and debugging may also become a problem. After the association between IDs and types is implemented, you can use the description type to create classes. The final implementation is as follows:
AINodeDescribe des [] = {AINodeDescribe (1, 0, ANBT_SELECT, "Root Node"), AINodeDescribe (2, 1, ANBT_SEQUENCE, "Whether to pick up a gold coin determining node "), AINodeDescribe (5, 2, ANT_RELEASE_SKILL, "whether there are gold coins nearby"), AINodeDescribe (6, 2, Baidu, ""), ainodescribe (3, 1, anbsequt_ence, "whether to return to the judgment node of the master"), AINodeDescribe (7, 3, ANT_RELEASE_SKILL, "haven't seen gold coins for a long time"), AINodeDescribe (8, 3, ANT_PICKING_UP_COINS, "Haven't been back to the master for a long time"), AINodeDescribe (9, 3, ANT_PICKING_UP_COINS, "Back to the execution node of the master"), AINodeDescribe (4, 1, ANT_PICKING_UP_COINS, "Nothing to visit"),}; int desCount = sizeof (des)/sizeof (ainodescribe); vector <AINodeDescribe> des_vtr; for (int I = 0; I <desCount; ++ I) {des_vtr.push_back (des [I]);} AINodeBase * rootNode = AINodeHelper: sharedHelper ()-> CreateNodeTree (des_vtr );
During initialization, AINodeDescribe accepts four parameters: current Id, parent node Id, specific type of the Tree node created by the current node, and description of the current node instance. If the parent node is 0, it will be returned as the root node. Otherwise, NULL will be returned directly, and all nodes applied for will cause memory leakage. At the beginning, you can write all the parameters to the file and initialize them through the file. However, it does not matter if I write it directly for demonstration purposes, but when you are using it, I recommend you write a method to read the file configuration, which will be better. (Because you can organize the logic of this section and directly create an editor for planning to organize the corresponding content .) By the way, you may describe this file according to your own ideas, but the actual execution result may be different from your ideas. You can perform the following operations for verification:
Cout <"\ n state structure organization chart \ n" <endl; AINodeHelper: sharedHelper ()-> printAITree (rootNode ); cout <"\ n state structure organization chart \ n" <endl;
The output result is that there is still a problem in the top figure, that is, the debugging problem. It is impossible for me to place a breakpoint in so many contents, which is no different from the downstream. Therefore, we need to print the running results of each node. My processing is as follows:
For (int I = 0; I <10; ++ I) {cout <"call tree Start" <endl; rootNode-> invoke (0, true ); cout <"call tree end" <endl ;}
The first parameter of invoke indicates the session bit of the most basic node, and the second parameter indicates whether to print the Log. If you do not want to debug it, do not enter either of the two parameters. Finally, let's talk about the project address http://git.oschina.net/anxin1225/AiTreeTest. Maybe this description is not very clear, you can leave a message for me, I try to give you answers

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.