欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用行为树方式实现AI

程序员文章站 2022-01-22 10:03:31
...

 

最近苦于思考怎么去加强AI

之前都是在代码里面根据各种情况去写代码

简单的逻辑还好说,复杂的情况实在是让人受不了

一大堆的这种业务逻辑代码自己都看晕了

 

后来想用行为树的方式去实现AI

找了几个行为树编辑器最后找到了这个:http://behavior3js.guineashots.com

还可以在线编辑,很符合我的需求

 

添加各种节点后导出json 然后我来解析.需要做的是实现你添加节点的方法

 

用一个Blackboard 传递属性给下一个节点,记录公共变量

 

--------------

具体点的用法说明:

这里面分为复合节点(顺序节点,选择节点), 条件节点,装饰节点,行为节点

 

我用起来的话这几个就够了

条件节点,装饰节点,行为节点 这几个是需要你去添加并且实现自己业务逻辑的

复合节点不需要变动了.

 

复合节点没什么逻辑.就是顺序调用子节点的返回结果(成功或者失败)

 

条件节点 这个也很简单.和行为节点有点相识,都是没有子节点的.然后用来做一些基础判断 返回(成功或者失败)

 

行为节点 也很简单,就是最终需要执行的操作.这里直接调用你原本的业务代码就行

 

装饰节点 的作用就是计算一些数值,然后这个数值存储到Blackboard  传递到下一个节点去

下一个节点可以利用上一个节点传递的值.

 

装饰节点不做判断逻辑. 这个交给条件节点.多个装饰节点串联起来最终进行简单的true false 或者数字比较判断

 

我在里面实现了个循环节点,有些操作是需要循环判断的,这里有点不同的是 一般用到循环节点,上个节点会传入 list. 这里会在循环的时候 把里面的元素传入到子节点里面去

 

 

解析代码:

 

@PostConstruct
	public void init() throws IOException, InstantiationException,
			IllegalAccessException {

		FileSystemResource f = new FileSystemResource("config/ai/ddz_ai.txt");

		File file = f.getFile();

		String str = FileUtils.readFileToString(file, "utf-8");

		BehaviorTree tree = JSON.parseObject(str, BehaviorTree.class);

		JSONObject jsonObject = JSON.parseObject(str);

		initClass();

		JSONObject array = jsonObject.getJSONObject("nodes");

		for (Object j : array.values()) {

			JSONObject json = (JSONObject) j;

			String id = json.getString("id");

			map.put(id, json);
		}


		rootNode = parse(jsonObject.getString("root"));

	}

	BaseNode rootNode;

	BaseNode parse(String root) throws InstantiationException,
			IllegalAccessException {
		JSONObject obj = map.get(root);

		String name = obj.getString("name");
		Class clazz = clazzs.get(name);
		if (clazz == null) {
			logger.error("不存在节点:{}", name);
		}
		BaseNode node = JSON.toJavaObject(obj, clazz);

		if (node.getChild() != null && node instanceof Decorator) {
			Decorator decorator = (Decorator) node;
			decorator.setChildNode(parse(node.getChild()));
		}

		if (node.getChildren() != null && node instanceof Composite) {

			Composite composite = (Composite) node;
			List<BaseNode> list = new ArrayList<BaseNode>();

			for (String nodeId : node.getChildren()) {
				list.add(parse(nodeId));
			}

			// 按照y值 升序排序保证执行顺序
			Collections.sort(list, new Comparator<BaseNode>() {
				@Override
				public int compare(BaseNode o1, BaseNode o2) {

					if (o1.getDisplay().getY() > o2.getDisplay().getY()) {
						return 1;
					} else if (o1.getDisplay().getY() < o2.getDisplay().getY()) {
						return -1;
					}
					return 0;
				}

			});

			composite.setChildrenNodes(list);

		}
		node.setChild(null);
		node.setChildren(null);
		return node;
	}

	public void initClass() {

		add(new Priority());
		add(new Sequence());
		//
		add(new CallAction());
		add(new NotCallAction());
		add(new RobAction());
		add(new NotRobAction());
		add(new PlayCardAction());
		add(new PassAction());
		add(new FilterAction());

		add(new SuccessAction());
		//
		add(new EqualCondition());
		add(new FalseCondition());
		add(new GreaterCondition());
		add(new LessCondition());
		add(new TrueCondition());

		add(new CompareCondition());

		//

		add(new IsLordDecorator());

		add(new BaseChooseCardDecorator());

		add(new CanPlayCardDecorator());
		add(new GetCardTypeDecorator());
		add(new GetCardTypeNameDecorator());

		add(new GetHandCardKindDecorator());
		add(new GetCardValueDecorator());
		add(new GetGameStatusDecorator());
		add(new GetLordCardNumDecorator());
		add(new GetNextHandCardNumDecorator());
		add(new GetStartCardDecorator());

		add(new GetStartCardDecorator());
		add(new IfLessLordCardDecorator());
		add(new IfMustPlayDecorator());

		add(new IfSuppressedDecorator());
		add(new LoopDecorator());
		add(new SelfHandCardNumDecorator());

	}

	public void add(BaseNode baseNode) {
		clazzs.put(baseNode.getName(), baseNode.getClass());
	}

 

 

 

 

 

 

上传了 代码和脚本.可以看看怎么去编辑逻辑 让逻辑跑通

 

  • ai.zip (22.1 KB)
  • 下载次数: 16