lua 游戏架构 之 游戏 AI (四)ai_autofight_find_target

定义一个名为 `ai_autofight_find_target` 的类,继承自 `ai_base` 类。

lua 游戏架构 之 游戏 AI (一)ai_base-CSDN博客文章浏览阅读237次。定义了一套接口和属性,可以基于这个基础类派生出具有特定行为的AI组件。例如,可以创建追逐敌人的AI、巡逻的AI或使用特定策略的AI等,都继承自这个基础类https://blog.csdn.net/heyuchang666/article/details/140624481?spm=1001.2014.3001.5502

这个类用于处理游戏中AI自动战斗中寻找目标的逻辑。以下是对代码的具体解释:

  1. **引入基类**: 使用 `require` 函数引入 `ai_base` 类,作为基础类。

  2. **定义 `ai_autofight_find_target` 类**: 使用 `class` 关键字定义了 `ai_autofight_find_target` 类,并继承自 `BASE`(即 `ai_base`)。

  3. **构造函数 (`ctor`)**:

    • 构造函数 `entity` 游戏实体,并设置 `_type` 属性为 `eAType_AUTOFIGHT_FIND_TARGET`,表示自动战斗中寻找目标的行为。
    • 初始化 `_target` 为 `nil`,用于后续存储找到的目标。
  1. **`IsValid` 方法**:
    • 这个方法用于验证AI是否应该寻找目标。它首先检查实体是否开启了自动战斗(`_AutoFight`),是否死亡或无法攻击。
    • 计算警报范围 `filterdist`,可能基于实体的属性或世界配置。
    • 检查实体的预命令类型,如果是点击移动或摇杆移动,则返回 `false`。
    • 检查实体的当前技能 `_curSkill`,根据技能类型(伤害、诅咒、祝福)和相关逻辑来确定目标。
  1. **`OnEnter` 方法**:
  • 当AI组件进入激活状态时执行。如果已经找到目标 `_target`,则根据当前技能设置目标或移动到目标位置。
  1. **`OnLeave` 方法**:
  • 当AI组件离开激活状态时执行。清除目标 `_target`。
  1. **`OnUpdate` 方法**:
  • 每帧调用,用于更新AI状态。如果基类的 `OnUpdate` 方法返回 `true`,则当前方法也返回 `true`。
  1. **`OnLogic` 方法**:
  • 逻辑更新方法,如果基类的 `OnLogic` 方法返回 `true`,则当前方法返回 `false`,表示只执行一次。
  1. **创建组件函数**:
  • `create_component` 函数用于创建 `ai_autofight_find_target` 类的新实例,传入一个实体和一个优先级。

代码中的一些关键点:

    • `IsDead()`:检查实体是否死亡。
    • `CanAttack()`:检查实体是否可以攻击。
    • `GetPropertyValue(ePropID_alertRange)`:获取实体的警报范围属性。
    • `game_get_world()`:获取游戏世界配置。
    • `GetEnmities()`:获取实体的敌对列表。
    • `GetRadius()`:获取实体的半径。
    • `MoveTo()`:移动到指定位置。
    • `SetTarget()`:设置目标实体。

这个脚本为游戏中的AI提供了一个自动战斗中寻找目标的基础框架,可以根据具体游戏的需求进行扩展和修改。

Lua 复制代码
----------------------------------------------------------------

local require = require

local BASE = require("logic/entity/ai/ai_base").ai_base;


ai_autofight_find_target = class("ai_autofight_find_target", BASE);
function ai_autofight_find_target:ctor(entity)
	self._type		= eAType_AUTOFIGHT_FIND_TARGET;
	self._target	= nil;
end

function ai_autofight_find_target:IsValid()
	local entity = self._entity;
	if not entity._AutoFight then
		return false;
	end
	if entity:IsDead() or not entity:CanAttack() then
		return false;
	end
	
	local filterdist = entity:GetPropertyValue(ePropID_alertRange)
	local world = game_get_world();
	if world._cfg.autofightradius then
		filterdist = world._cfg.autofightradius
	end
	local r1 = entity:GetRadius();
	if entity._PreCommand == ePreTypeClickMove or entity._PreCommand == ePreTypeJoystickMove then
		return false;
	end	

	if entity._curSkill then
		local target = nil;
		local ignoreDist = false;
		local stype = entity._curSkill._cfg.type;
		if stype == eSE_Damage or stype == eSE_DBuff then -- 伤害、诅咒
			if entity._forceAttackTarget and not entity._forceAttackTarget:IsDead() then
				ignoreDist = true;
				target = entity._forceAttackTarget;
			else
				local enmities = entity:GetEnmities();
				if enmities then
					local enmity = enmities[1];
					if enmity then
						ignoreDist = true;
						target = enmity;
					end
				end
					
				if not target or target._groupType == eGroupType_N then
					
					local tentity = nil
					local mapType = game_get_map_type();
					for i,v in ipairs(entity._alives[2]) do
						local r2 =  entity._alives[2][i].entity:GetRadius();
						local radius = r1 + r2;	
						if radius then
							if mapType then
								if mapType == g_ARENA_SOLO or mapType == g_TAOIST then
									break;
								end
							end
							
							if entity._alives[2][i].dist < entity._curSkill._range + radius then
								tentity = entity._alives[2][i];
								if entity._alives[2][i+1] and entity._alives[2][i+1].dist then
									if tentity.dist <  entity._alives[2][i+1].dist then
										tentity = entity._alives[2][i+1];
									else
										tentity = entity._alives[2][i];
									end
								else
									tentity = entity._alives[2][i];
									break;
								end
							else
								if v.entity:GetEntityType() == eET_Player and v.dist > filterdist then
									if entity._alives[2][i+1] and entity._alives[2][i+1].dist < filterdist then
										tentity = entity._alives[2][i+1];
										break;	
									end
								else
									tentity = entity._alives[2][i-1];
									break;	
								end
							end		
						end
					end
					
					if entity._groupType == eGroupType_O then
						
						local nentity = tentity or entity._alives[2][1] or entity._alives[3][1]
						if target and nentity and nentity.entity and nentity.entity._groupType ~= eGroupType_N  then
							target = nentity.entity;
						elseif not ignoreDist then
							target = tentity or entity._alives[2][1];
							if entity._alives[3][1] then
								local trap =  entity._alives[3][1];
								if trap.entity and trap.entity._traptype == eSTrapActive then
									target = entity._alives[3][1];			
								end
							end
						
							if nentity and nentity.entity._groupType == eGroupType_N and nentity.dist > db_common.droppick.AutoFightMapbuffAutoRange then
								target = nil;
								return false;
							end
						end
					else
						target = tentity or entity._alives[2][1] -- 敌方
					end
				end
			end
		elseif stype == eSE_Buff then -- 祝福
		
			if entity._target and entity._target._guid == entity._guid then
				return false;
			end 
			self._target = entity;
			
			return true;
		end

		if target then
			if ignoreDist then
				if not (target:GetEntityType() == eET_Pet and (not entity._enmities or #entity._enmities <= 0)) then
					self._target = target;
				end

				if not entity._target or entity._target:IsDead() then
					return true;
				end
	
				return target._guid ~= entity._target._guid;
			else
				local r2 = target.entity:GetRadius();
				local radius = r1 + r2;
				if target.dist < filterdist + radius then
					
					if not (target.entity:GetEntityType() == eET_Pet and (not entity._enmities or #entity._enmities <= 0)) then
						self._target = target.entity;
					end
					if not entity._target or entity._target:IsDead() then
						return true;
					end
					if target.dist < entity._curSkill._range + radius then
						return false;
					end
					return target.entity._guid ~= entity._target._guid;
				end
			end
		end
	end

	return false;
end

function ai_autofight_find_target:OnEnter()
	if BASE.OnEnter(self) then
		local entity = self._entity;
		--log("ai_autofight_find_target")
		entity._behavior:Clear(eEBGuard);

		if self._target then
			if entity._curSkill then
				entity:SetTarget(self._target);
			else
				entity:MoveTo(self._target._curPos);
			end
		end

		return true;
	end

	return false;
end

function ai_autofight_find_target:OnLeave()
	if BASE.OnLeave(self) then
		self._target = nil;

		return true;
	end

	return false;
end

function ai_autofight_find_target:OnUpdate(dTime)
	if BASE.OnUpdate(self, dTime) then
		return true;
	end

	return false;
end

function ai_autofight_find_target:OnLogic(dTick)
	if BASE.OnLogic(self, dTick) then
		return false; -- only one frame
	end

	return false;
end

function create_component(entity, priority)
	return ai_autofight_find_target.new(entity, priority);
end
相关推荐
剑盾云安全专家8 分钟前
AI助力PPT创作:从手动到智能,打造高效演示
人工智能·powerpoint
AI视觉网奇33 分钟前
Stable Diffusion 3 部署笔记
人工智能·笔记·stable diffusion
咯咯咯伦1 小时前
AI无限生成《黑神话:悟空》最火四妹!(整合包)
人工智能
roman_日积跬步-终至千里1 小时前
【人工智能基础】机器学习基础
人工智能·机器学习
机器之心2 小时前
吴恩达出手,开源最新Python包,一个接口调用OpenAI等模型
人工智能·后端
牙牙要健康2 小时前
【深度学习】【RKNN】【C++】模型转化、环境搭建以及模型部署的详细教程
c++·人工智能·深度学习
TsingtaoAI2 小时前
数据挖掘/深度学习-高校实训解决方案
人工智能·深度学习·数据挖掘·实训平台·ai实训课程·高校ai实训·高校实训
没了对象省了流量ii2 小时前
11.9K Star!强大的 Web 爬虫工具 FireCrawl:为 AI 训练与数据提取提供全面支持
前端·人工智能·爬虫
Byyyi耀3 小时前
Claude Opus MetaPrompt 系统详解
人工智能
qq_273900233 小时前
pytorch torch.Tensor.item() 方法介绍
人工智能·pytorch·python·深度学习