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`,用于后续存储找到的目标。

4. **`IsValid` 方法**:

  •    - 这个方法用于验证AI是否应该寻找目标。它首先检查实体是否开启了自动战斗(`_AutoFight`),是否死亡或无法攻击。
  •    - 计算警报范围 `filterdist`,可能基于实体的属性或世界配置。
  •    - 检查实体的预命令类型,如果是点击移动或摇杆移动,则返回 `false`。
  •    - 检查实体的当前技能 `_curSkill`,根据技能类型(伤害、诅咒、祝福)和相关逻辑来确定目标。

5. **`OnEnter` 方法**:
   - 当AI组件进入激活状态时执行。如果已经找到目标 `_target`,则根据当前技能设置目标或移动到目标位置。

6. **`OnLeave` 方法**:
   - 当AI组件离开激活状态时执行。清除目标 `_target`。

7. **`OnUpdate` 方法**:
   - 每帧调用,用于更新AI状态。如果基类的 `OnUpdate` 方法返回 `true`,则当前方法也返回 `true`。

8. **`OnLogic` 方法**:
   - 逻辑更新方法,如果基类的 `OnLogic` 方法返回 `true`,则当前方法返回 `false`,表示只执行一次。

9. **创建组件函数**:
   - `create_component` 函数用于创建 `ai_autofight_find_target` 类的新实例,传入一个实体和一个优先级。

代码中的一些关键点:

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

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

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

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


 

  • 27
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值