游戏算法-游戏AI行为树,python实现

news/2024/6/2 14:46:39 标签: python, 游戏, 算法, 游戏AI, 行为树

参考文章:Behavior trees for AI: How they work (gamedeveloper.com)

本文主要参考上述wei'zProject Zomboid 的开发者 Chris Simpson文章的概念,用伪代码实现代码例子

AI概述


    游戏AI是对游戏内所有非玩家控制角色的行为进行研究和设计,使得游戏内的单位能够感知周围环境,并做出相应的动作表现的技术。游戏AI作为游戏玩法的一大补充,在各种游戏中都有广泛的应用,比如可以和玩家交互聊天的NPC,按照特定规则寻路的怪物,与玩家进行战斗对抗的机器人等。

目前实现游戏AI的算法

有限状态机

AI行为树

还有其他比较少用的规则式AI,甚至神经网络等
 

行为树AI基本概念

        游戏行为树(Behavior Trees, BT)是一种用于游戏AI的设计模式。它通过模拟行为树来描述AI的行为和决策过程,以实现更加智能和自然的游戏AI。

游戏行为树由多个节点组成,每个节点代表一个行为或决策。它们按照特定的方式连接在一起,形成一个树状结构。在行为树中,根节点是AI的起点,通过遍历子节点来决策AI的行为。

节点有以下三种状态:

成功 success

失败 failure

运行 running

行为树节点有三种主要原型

组合控制节点 -Composite:

一种将多个子节点组合在一起的节点,用于实现复杂的行为和决策逻辑

主要包括

次序节点-Sequences:并行执行多个子节点,直到所有子节点都返回True或者任意一个子节点返回False为止

选择节点-Selector:按照顺序执行子节点,当某个子节点返回success时,停止执行并返回success

修饰节点-Decorator:

一种特殊的节点,它不执行具体的行为或决策,而是修饰其它节点的行为或决策

主要包括:

逆变节点-Inverter:它可以将子节点的结果倒转,比如子节点返回了 Failure,则这个修饰节点会向上返回 Success,以此类推。

重复节点-Repeater:重复执行其子节点指定的次数或者一直重复执行,直到其子节点返success或者failure

叶节点-Leaf:

树的最末端——叶子,就是这些 AI 实际上去做事情的命令或者是做一些判断

主要包括

条件节点-Condition:判断条件是否满足,如果满足则返回success,否则返回failure

行为节点-Action:执行某个具体的动作或行为,例如移动、攻击、使用技能等

节点表示

次序节点 ->Walk to Door (Success) ->次序节点(Running) ->Open Door (Success)  ->次序节点(运行中) ->Walk through Door (Success) ->次序节点(Running) ->Close Door (Success) ->次序节点(Running) -> 向次序节点的父节点返回 Success。

例如,考虑上一节中提到的逆变器装饰器:

在功能上与前面的示例相同,这里我们展示了如何使用逆变器来否定任何测试,从而为您提供一个 NOT 门。这意味着你可以大幅减少测试角色或游戏世界条件所需的节点数量。

三、伪代码实现

节点基类:

# 行为树节点基类
class BaseNode(object):
	def __init__(self):
		self.status = None  # 节点的执行结果: 成功 success 失败 failure 运行 running

	def execute(self, who):
		# 执行
		pass

叶子节点:行为节点

# 叶子节点-行为节点:吃食物
class EatFoodNode(BaseNode):
	def __init__(self, target):
		super(EatFoodNode).__init__()
		self.target = target  # 食物目标

	def execute(self, who):
		# 吃食物
		# who.eat_foot(self.target)
		self.status = "success"
# 叶子节点-行为节点:打开门
class OpenDoorNode(BaseNode):
	def __init__(self, target):
		super(OpenDoorNode).__init__()
		self.target = target  # 打开目标

	def execute(self, who):
		# 执行打开门动作
		# who.open_door(self.target)
		self.status = "success"

叶子节点:条件节点


# 叶子节点-条件节点:检查是否饥饿
class CheckHungryNode(BaseNode):
	def __init__(self, hungry_val):
		super(CheckHungryNode).__init__()
		self.hungry_val = hungry_val  # 生命值阈值

	def execute(self, who):
		# 检查生命值是否小于阈值
		if self.hungry_val > who.hungry_val:
			self.status = "success"
		else:
			self.status = "failure"


# 叶子节点-条件节点:检查是否有食物
class CheckHasFoodNode(BaseNode):
	def __init__(self, food):
		super(CheckHasFoodNode).__init__()
		self.food = food  # 目标食物

	def execute(self, who):
		# 检查目标距离是否小于最大距离
		if who.has_food(self.food):
			self.status = "success"
		else:
			self.status = "failure"
   
   # 叶子节点-条件节点:敌人是否在周围
class CheckEnemiesAroundNode(BaseNode):
	def __init__(self, enemies):
		super(CheckEnemiesAroundNode).__init__()
		self.enemies = enemies  # 敌人

	def execute(self, who):
		# 敌人是否在周围
		if who.AroundHasEnemies(self.enemies):
			self.status = "success"
		else:
			self.status = "failure"

组合控制节点:序列节点

# 组合控制节点:序列节点
class SequenceNode(BaseNode):
	def __init__(self, children):
		super(SequenceNode).__init__()
		self.children = children  # 子节点列表

	def execute(self, who):
		for child in self.children:
			child.execute(who)
			if child.status == "failure":
				self.status = "failure"
				return
		self.status = "success"



组合控制节点:选择节点

# 组合控制节点:选择节点
class SelectorNode(BaseNode):
	def __init__(self, children):
		super(SelectorNode).__init__()
		self.children = children

	def execute(self, who):
		for child in self.children:
			child.execute(who)
			if child.status == "success":
				self.status = "success"
				return
		self.status = "failure"

装饰节点:逆变节点

# 装饰节点,逆变节点
class NOT_DecoratorNode(BaseNode):
	def __init__(self, child):
		super(DecoratorNOT).__init__()
		self.child = child
	
	def execute(self, who):                      
		status = self.child.execute(who)
		if status == "success"
			self.status = "failure"
		elif status == "failure":
			self.status = "success"
			

例子一:

饥饿的时候,且有食物的时候,没有敌人在周围,就吃食物

# 角色对象
class Player(object):
	def __init__(self):
		self.hungry_val = 0  # 饥饿度
		self.food = "fish"  # 食物


def main():
	# 首先定义行为树的结构
	root = SequenceNode([
		# 饥饿的时候
		CheckHungryNode(50),
		# 有鱼时候
		CheckHasFoodNode("fish"),
		# 敌人不在周围
		NOT_DecoratorNode(CheckEnemiesAroundNode("李宏伟")),
		# 老墨吃鱼
		EatFoodNode("fish"),
	])
	
	who = Player()
	# 然后在主循环中执行行为树
	while True:

		# 执行行为树
		root.execute(who)

		# 根据行为执行结果更新状态
		if root.status == "success":
			who.hungry_val = random.randint(1, 100)
			who.food = random.randint(1, 100)
		# 等待一段时间后再次执行行为树
		time.sleep(1)

例子二:

	# 行为树的结构如下
	root = SequenceNode([
		WalkToDoor(),
		SelectorNode([
			OpenDoor(),
			SequenceNode([
					UnlockDoor(),
					OpenDoor("self"),
					]),
			SmashDoor(),
				]),
		WalkThroughDoor(),
		CloseDoor(),		
	])
	


http://www.niftyadmin.cn/n/189109.html

相关文章

【Hbase 02】Hbase超详细安装和注意问题点

本文主要讲一下Hbase的安装相关的内容 一、前提条件: 安装好hadoop、jdk、zookeeper等 Hadoop安装参考博主的另一篇文章: https://blog.csdn.net/Alex_81D/article/details/102964892 zookeeper安装参考这篇文章: https://blog.csdn.net/Alex_81D/article/details/128478508…

九龙证券|人工智能+国产软件+智慧城市概念股火了,欧洲资管巨头大举抄底

近一周组织调研个股数量有130多只,迈瑞医疗成为调研组织数量最多的股票。 证券时报数据宝统计,近一周组织调研公司数量有130多家。从调研组织类型来看,证券公司调研相对最广泛,调研80多家公司。 迈瑞医疗获超500家组织调研 迈瑞…

配置OBS存储功能、新搭建obs

通过应用开发环境与OBS(Object-based Storage Service)对接,实现对象或者Widget资产存储功能。 背景信息 对象存储服务(Object-based Storage Service,OBS)是一个基于对象的海量存储服务,为客…

小米万兆路由器里的Docker安装可道云(kodbox)私有网盘

小米万兆路由器里的Docker安装可道云 kodbox 私有网盘准备工作创建存储查看Docker Hub镜像信息拉取kodbox镜像和运行容器手机 app 访问 kodbox(Optional)其他小米2022年12月份发布了万兆路由器,里面可以使用Docker。 今天尝试在小米的万兆路由器里安装可道云(kodbox…

【Spring】AOP切入点表达式通知类型数据获取(二)

🚗SpringAOP学习第二站 🚩起始站:【Spring】AOP入门(一) 🚩本文已收录至专栏:Spring家族学习之旅 👍希望您能有所收获 一.切入点表达式 在上一篇的案例中我们发现切面表达式负责描述…

2023年最新自动化/控制保研夏令营预推免经验贴(清华/自动化所/浙大/上交)

本文起笔于2022年 2023年已启动夏令营/预推免项目: ----自动化研究所中科院自动化人工智能菁英班:中国科学院自动化研究所2023年“人工智能菁英班”项目申报通知 清华大学自动化系智能与网络化系统研究中心:清华大学自动化系智能与网络化系统研究中心2023年招生夏令营报名…

Android 9.0 系统关机动画的功能实现

1.前言 在系统9.0的系统rom定制化开发中,在系统中默认有开机动画功能,但是在关机动画方面功能不是很完善,如果只内置关机动画,会发现关机动画还没播放完 就关机了,所以需要在系统关机要等到关机动画播完才执行关机的动作,接下来就来分析关机流程,然后来实现这个功能 …

C语言 —— 函数(二)

C语言函数一、C语言函数执行流程二、C语言函数的嵌套调用例子:计算sum 1! 2! 3! ... (n-1)! n!三、C语言全局变量和局部变量3.1、全局变量(Global Variable)3.2、局部变量(Local Variable3.3、例子:长方体的长宽…