lua 游戏架构 之 游戏 AI (五)ai_autofight_find_way
这段Lua脚本定义了一个名为 `ai_autofight_find_way` 的类,继承自 `ai_base` 类。
lua 游戏架构 之 游戏 AI (一)ai_base-CSDN博客文章浏览阅读238次。定义了一套接口和属性,可以基于这个基础类派生出具有特定行为的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_way` 类**:
- 使用 `class` 关键字定义了 `ai_autofight_find_way` 类,并继承自 `BASE`(即 `ai_base`)。
3. **构造函数 (`ctor`)**:
- 构造函数接受一个 `entity` 参数,并设置 `_type` 属性为 `eAType_AUTOFIGHT_FIND_WAY`,表示自动战斗中寻找路径的行为。
- 初始化 `_target` 为 `nil`,用于后续存储找到的目标。
4. **`IsValid` 方法**:
- - 这个方法用于验证AI是否应该寻找路径。它首先检查实体是否开启了自动战斗(`_AutoFight`),是否死亡或无法攻击。
- - 检查实体的行为,如果处于准备战斗或禁止攻击状态,则返回 `false`。
- - 计算警报范围 `radius`,可能基于实体的属性或世界配置。
- - 根据不同的地图类型和条件,确定是否需要寻找路径。
5. **`OnEnter` 方法**:
- 当AI组件进入激活状态时执行。根据当前地图类型和条件,计算目标位置并使实体移动到该位置。
6. **`OnLeave` 方法**:
- 当AI组件离开激活状态时执行。当前实现中直接返回 `true`。
7. **`OnUpdate` 方法**:
- 每帧调用,用于更新AI状态。如果基类的 `OnUpdate` 方法返回 `true`,则当前方法也返回 `true`。
8. **`OnLogic` 方法**:
- 逻辑更新方法,如果基类的 `OnLogic` 方法返回 `true`,则当前方法返回 `false`,表示只执行一次。
9. **创建组件函数**:
- `create_component` 函数用于创建 `ai_autofight_find_way` 类的新实例,传入一个实体和一个优先级。
代码中的一些关键点:
- - `IsDead()`:检查实体是否死亡。
- - `CanAttack()`:检查实体是否可以攻击。
- - `GetPropertyValue(ePropID_alertRange)`:获取实体的警报范围属性。
- - `game_get_world()`:获取游戏世界配置。
- - `Test(eEBPrepareFight)` 和 `Test(eEBDisAttack)`:检查实体的行为状态。
- - `MoveTo()`:移动到指定位置。
这个脚本为游戏中的AI提供了一个自动战斗中寻找路径的基础框架,可以根据具体游戏的需求进行扩展和修改。以下是一些具体的逻辑处理:
- - 根据不同的地图类型(如 `g_BASE_DUNGEON`、`g_ACTIVITY` 等),AI的行为可能会有所不同。
- - 计算与目标的距离,并根据距离决定是否移动。
- - 考虑地图上的特定点(如物品掉落点、怪物刷新点)来决定移动路径。
- - 使用 `vec3_dist` 函数计算两个位置之间的距离,并根据距离决定是否移动到该位置。
整体而言,这个类的目的是在自动战斗模式下,根据游戏世界的当前状态和配置,为AI实体找到合适的移动路径。
重点解释一下 OnEnter:
function ai_autofight_find_way:OnEnter()if BASE.OnEnter(self) thenlocal entity = self._entity;local radius = entity:GetPropertyValue(ePropID_alertRange);local logic = game_get_logic();local world = game_get_world();if world then-- 如果世界配置中有自动战斗半径,则使用该值if world._cfg.autofightradius thenradius = world._cfg.autofightradius;end-- 根据不同的地图类型执行不同的逻辑if world._mapType == g_BASE_DUNGEON or world._mapType == g_ACTIVITY or ... then-- 检查所有掉落物品,如果物品处于激活状态,则移动到该物品位置for k,v in pairs(world._ItemDrops) doif v and v:GetStatus() == eSItemDropActive thenlocal _pos = logic_pos_to_world_pos(v._curPos);entity:MoveTo(_pos);return false; -- 移动到物品位置后,退出函数endend-- 如果地图类型是开放区域,并且有怪物刷新点或当前活动区域if world._openType == g_FIELD then-- 寻找一个有活着的怪物的刷新点local _pos = nil;local isfind = false;for k1,v1 in pairs(world._curArea._spawns) dofor k2,v2 in pairs(v1._monsters) doif not v2:IsDead() thenisfind = true;break;endendif isfind then_pos = v1._cfg.pos;break;endend-- 如果没有找到有活着的怪物的刷新点,使用第一个刷新点的位置if not _pos then_pos = world._curArea._spawns[1]._cfg.pos;end-- 计算实体当前位置到刷新点或地图增益点的距离local dist = vec3_dist(entity._curPos,world_pos_to_logic_pos(_pos));local mindist = dist;-- 寻找最近的地图增益点for k,v in pairs(world._mapbuffs) doif v and v:GetStatus() == 1 thenlocal distbuff = vec3_dist(v._curPos,entity._curPos);if distbuff < mindist and distbuff < db_common.droppick.AutoFightMapbuffAutoRange thenmindist = distbuff;_pos = logic_pos_to_world_pos(v._curPos);endendend-- 移动实体到计算出的位置entity:MoveTo(_pos);end-- 其他地图类型的逻辑...elseif world._mapType == g_FIELD or world._mapType == g_Life then-- 对于其他地图类型,寻找最近的地图增益点并移动实体-- ...endendreturn false; -- 如果没有找到目标位置或执行了移动逻辑,则返回falseendreturn false; -- 如果没有调用基类的OnEnter或基类返回false,则返回false
end
在 OnEnter 方法中,首先调用基类的 OnEnter 方法,如果它返回 false,则直接返回 false。如果基类的 OnEnter 方法返回 true,则继续执行以下逻辑:
- 获取实体的警报范围
radius。 - 检查游戏世界配置,如果存在自动战斗半径配置,则使用该配置值覆盖实体的警报范围。
- 根据当前的地图类型,执行不同的逻辑来寻找目标位置。例如:
- 如果是
g_BASE_DUNGEON、g_ACTIVITY等地图类型,会检查所有物品掉落点,寻找激活的物品并移动到该位置。 - 如果是开放区域(
g_FIELD),会寻找有活着的怪物的刷新点或最近的地图增益点,并移动实体到该位置。
- 如果是
- 使用
vec3_dist函数计算实体当前位置到目标位置的距离,并根据这个距离来确定是否移动实体。 - 如果找到目标位置,则调用
entity:MoveTo(_pos)方法移动实体到该位置,然后返回false退出函数。 - 如果没有找到目标位置或不满足移动条件,则返回
false。
整体而言,OnEnter 方法的目的是确定AI在自动战斗模式下应该移动到哪个位置,并执行移动操作。
全部代码实现:
----------------------------------------------------------------
module(..., package.seeall)local require = requirelocal BASE = require("logic/entity/ai/ai_base").ai_base;------------------------------------------------------
ai_autofight_find_way = class("ai_autofight_find_way", BASE);
function ai_autofight_find_way:ctor(entity)self._type = eAType_AUTOFIGHT_FIND_WAY;self._target = nil;
endfunction ai_autofight_find_way:IsValid()local entity = self._entity;if not entity._AutoFight thenreturn false;endif entity:IsDead() or not entity:CanAttack() thenreturn false;endif entity._behavior:Test(eEBPrepareFight) thenreturn false;endif entity._behavior:Test(eEBDisAttack) thenreturn false;endlocal radius = entity:GetPropertyValue(ePropID_alertRange);local world = game_get_world();if world thenif world._cfg.autofightradius thenradius = world._cfg.autofightradius;endlocal target = entity._alives[2][1]; -- 敌方if entity._alives[3][1] then--中立local trap = entity._alives[3][1];if trap.entity and trap.entity._traptype == eSTrapActive thentarget = entity._alives[3][1]; endendif target thenif target.dist < radius thenif target.entity._groupType == eGroupType_N and target.dist > db_common.droppick.AutoFightMapbuffAutoRange thenelsereturn false;endendelseif world._mapType == g_TOURNAMENT thenreturn false;endendif world._mapType == g_BASE_DUNGEON or world._mapType == g_ACTIVITY or world._mapType == g_FACTION_DUNGEON or world._mapType == g_TOWER or world._mapType == g_WEAPON_NPC or world._mapType == g_RIGHTHEART or world._mapType == g_ANNUNCIATE or world._mapType == g_FIGHT_NPC or world._mapType == g_Pet_Waken thenif world._openType == g_FIELD thenif #world._spawns == 0 and not world._curArea then return falseendelselocal spawnID = math.abs(g_game_context:GetDungeonSpawnID())if spawnID == 0 thenreturn falseendlocal dist = nil;if spawnID ~= 0 thenspawnPointID = db_spawn_area[spawnID].spawnPoints[1]_pos = db_spawn_point[spawnPointID].posdist = vec3_dist(entity._curPos,world_pos_to_logic_pos(_pos))if dist and dist < 100 thenreturn falseend endendelseif world._mapType == g_FIELD or world._mapType == g_Life thenif entity._PVPStatus ~= g_PeaceMode thenreturn false;endlocal dist = vec3_dist(entity._curPos,entity._AutoFight_Point)if dist < radius thenreturn false;endlocal value = g_game_context:getAutoFightRadius()if value and value == g_OneMap thenreturn false;endelse -- TODOreturn false;endendreturn true;
endfunction ai_autofight_find_way:OnEnter()if BASE.OnEnter(self) thenlocal entity = self._entity;local radius = entity:GetPropertyValue(ePropID_alertRange)local logic = game_get_logic();local world = game_get_world();if world thenif world._cfg.autofightradius thenradius = world._cfg.autofightradiusendif world._mapType == g_BASE_DUNGEON or world._mapType == g_ACTIVITY or world._mapType == g_FACTION_DUNGEON or world._mapType == g_TOWER or world._mapType == g_WEAPON_NPC or world._mapType == g_RIGHTHEART or world._mapType == g_ANNUNCIATE or world._mapType == g_FIGHT_NPC or world._mapType == g_Pet_Waken thenfor k,v in pairs(world._ItemDrops) doif v and v:GetStatus() == eSItemDropActive thenlocal _pos = logic_pos_to_world_pos(v._curPos)entity:MoveTo(_pos)return false;endendif world._openType == g_FIELD thenif #world._spawns > 0 or world._curArea thenlocal _pos = nil;local isfind = falsefor k1,v1 in pairs(world._curArea._spawns) dofor k2,v2 in pairs(v1._monsters) doif not v2:IsDead() thenisfind = true;break;endendif isfind then_pos = v1._cfg.pos;break;endendif not _pos then_pos = world._curArea._spawns[1]._cfg.posend--local _pos = world._curArea._spawns[1]._cfg.poslocal dist = vec3_dist(entity._curPos,world_pos_to_logic_pos(_pos))local mindist = distfor k,v in pairs(world._mapbuffs) doif v and v:GetStatus() == 1 thenlocal distbuff = vec3_dist(v._curPos,entity._curPos)if distbuff < mindist and distbuff < db_common.droppick.AutoFightMapbuffAutoRange thenmindist = distbuff_pos = logic_pos_to_world_pos(v._curPos)endendendentity:MoveTo(_pos)endelselocal _pos = nillocal spawnID = math.abs(g_game_context:GetDungeonSpawnID())local dist = 99999999999;if spawnID ~= 0 thenspawnPointID = db_spawn_area[spawnID].spawnPoints[1]_pos = db_spawn_point[spawnPointID].posdist = vec3_dist(entity._curPos,world_pos_to_logic_pos(_pos)) endlocal mindist = distlocal isspawn = truefor k,v in pairs(world._mapbuffs) doif v and v:GetStatus() == 1 thenlocal distbuff = vec3_dist(v._curPos,entity._curPos)if distbuff < mindist and distbuff < db_common.droppick.AutoFightMapbuffAutoRange thenmindist = distbuffisspawn = false;_pos = logic_pos_to_world_pos(v._curPos)endendendif mindist < 150 and isspawn and g_game_context:GetDungeonSpawnID() < 0 theng_game_context:SetDungeonSpawnID(0);_pos = nil;endif _pos thenentity:MoveTo(_pos)endendelseif world._mapType == g_FIELD or world._mapType == g_Life thenfor k,v in pairs(world._mapbuffs) doif v and v:GetStatus() == 1 thenlocal distbuff = vec3_dist(v._curPos,entity._AutoFight_Point)if distbuff < radius and distbuff < db_common.droppick.AutoFightMapbuffAutoRange thenlocal _pos = logic_pos_to_world_pos(v._curPos)entity:MoveTo(_pos)return false;endendendendendreturn false;endreturn false;
endfunction ai_autofight_find_way:OnLeave()if BASE.OnLeave(self) thenreturn true;endreturn false;
endfunction ai_autofight_find_way:OnUpdate(dTime)if BASE.OnUpdate(self, dTime) thenreturn true;endreturn false;
endfunction ai_autofight_find_way:OnLogic(dTick)if BASE.OnLogic(self, dTick) thenreturn false; -- only one frameendreturn false;
endfunction create_component(entity, priority)return ai_autofight_find_way.new(entity, priority);
end
相关文章:
lua 游戏架构 之 游戏 AI (五)ai_autofight_find_way
这段Lua脚本定义了一个名为 ai_autofight_find_way 的类,继承自 ai_base 类。 lua 游戏架构 之 游戏 AI (一)ai_base-CSDN博客文章浏览阅读238次。定义了一套接口和属性,可以基于这个基础类派生出具有特定行为的AI组件。例如&…...
vue3+openLayers点击标记事件
<template><!--地图--><div class"distributeMap" id"distributeMap"></div> </template> <script lang"ts" setup> import { onMounted, reactive } from "vue"; import { Feature, Map, View }…...
深入分析 Android ContentProvider (三)
文章目录 深入分析 Android ContentProvider (三)ContentProvider 的高级使用和性能优化1. 高级使用场景1.1. 数据分页加载示例:分页加载 1.2. 使用 Loader 实现异步加载示例:使用 CursorLoader 加载数据 1.3. ContentProvider 与权限管理示例࿱…...
养宠浮毛异味双困扰?性价比高的宠物空气净化器推荐
家里养了两只银渐层,谁懂啊!一下班打开家门就看到家里飘满了猫浮毛雪,空气中还传来隐隐约约的异味。每天不是在吸毛的路上,就是在洗猫砂盆的路上,而且空气中的浮毛还很难清理干净,这是最让人头疼的问题。 …...
maven项目容器化运行之3-优雅的利用Jenkins和maven使用docker插件调用远程docker构建服务并在1Panel中运行
一.背景 在《maven项目容器化运行之1》中,我们开启了1Panel环境中docker构建服务给到了局域网。在《maven项目容器化运行之2》中,我们基本实现了maven工程创建、远程调用docker构建镜像、在1Panel选择镜像运行容器三大步骤。 但是,存在一个问…...
docker 打包orbbec
docker pull humble容器 sudo docker run -it osrf/ros:humble-desktop docker 启动容器 sudo docker run -u root --device/dev/bus/usb:/dev/bus/usb -it -v /home/wl:/share --name wl4 osrf/ros:humble-desktop /bin/bash新开一个终端 查看本地存在的容器:…...
无涯·问知财报解读,辅助更加明智的决策
财报解读就像是给公司做一次全面的体检,是理解公司内部运作机制和市场表现的一把钥匙,能够有效帮助投资者、分析师、管理层以及所有市场参与者判断一家公司的健康程度和发展潜力。 星环科技无涯问知的财经库内置了企业年报及财经类信息,并对…...
【Apache Doris】数据副本问题排查指南
【Apache Doris】数据副本问题排查指南 一、问题现象二、问题定位三、问题处理 本文主要分享Doris中数据副本异常的问题现象、问题定位以及如何处理此类问题。 一、问题现象 问题日志 查询报错 Failed to initialize storage reader, tablet{tablet_id}.xxx.xxx问题说明 查…...
【HarmonyOS】关于鸿蒙消息推送的心得体会(二)
【HarmonyOS】关于鸿蒙消息推送的心得体会(二) 前言 推送功能的开发与传统功能开发还是有很大区别。首先最大的区别点就在于需要多部门之间的协同,作为鸿蒙客户端开发,你需要和产品,运营,以及后台开发一起…...
零基础入门:创建一个简单的Python爬虫管理系统
摘要: 本文将手把手教你,从零开始构建一个简易的Python爬虫管理系统,无需编程基础,轻松掌握数据抓取技巧。通过实战演练,你将学会设置项目、编写基本爬虫代码、管理爬取任务与数据,为个人研究或企业需求奠…...
【Node.js基础04】node.js模块化
一:什么是模块化 在Node.js中,每个文件都可视为一个独立的模块。模块化提高了代码的复用性,按需加载,具有独立的作用域 二:如何实现多个文件间导入和导出 1 CommonJS标准(默认)-导入和导出 …...
数据库——单表查询
一、建立数据库mydb8_worker mysql> use mydb8_worker; 二、建立表 1.创建表 mysql> create table t_worker(department_id int(11) not null comment 部门号,-> worder_id int(11) primary key not null comment 职工号,-> worker_date date not null comment…...
dsa加训
refs: OI Wiki - OI Wiki (oi-wiki.org) 1. 枚举 POJ 2811 熄灯问题 refs : OpenJudge - 2811:熄灯问题 如果要枚举每个灯开或者不开的情况,总计2^30种情况,显然T。 不过我们可以发现:若第i行的某个灯亮了,那么有且仅有第i行和第…...
SpringBoot源码(1)ApplicationContext和BeanFactory
1、调用getBean方法 SpringBootApplication public class SpringBootDemoApplication {public static void main(String[] args) {ConfigurableApplicationContext applicationContext SpringApplication.run(SpringBootDemoApplication.class, args);applicationContext.get…...
CANoe编程实例--TCP/IP通信
1、简介 本实例将使用目前常用的开发工具C#来开发服务器端,以CANoe端作为客户端。服务器端和客户端,通过TCP/IP连接,实现数据交换。 首先在服务器端建立一个监听Socket,自动创建一个监听线程,随时监听是否有客户端的连…...
Neuron协议网关的北向应用插件开发
目录 概述 指令处理层开发 应用层开发 .open .close .init .uninit .start .stop .setting .request 插件设置文件 适配华为的思路 概述 最近研究了一段时间的Neuron协议网关,前面的博文也提到它虽然能够把数据发到华为的IoT平台上…...
【BUG】已解决:You are using pip version 10.0.1, however version 21.3.1 is available.
You are using pip version 10.0.1, however version 21.3.1 is available. 目录 You are using pip version 10.0.1, however version 21.3.1 is available. 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#…...
electron-builder打包vue2项目不显示element-ui图标
1、使用版本 vue ^2.6.14element-ui ^2.15.14vue-cli-plugin-electron-builder 2.1.1 2、解决办法 1) 如果是简单的图标可以使用图片代替(这种对于elementui组件的图标还是不会显示) 2)在vue.config.js配置 const { defineCon…...
controller层-请求格式为json-请求方法为get
前置条件 get请求映射,内容和PostMapping一致,需要请求参数更换为get数据 请求过程:用户请求--初始化DispatcherServlet及对接和分发用户请求--controller--service 用户请求:http://ip:port/user/getinfo 请求方法:ge…...
【Linux】网络通信基础:应用层协议、HTTP、序列化与会话管理
文章目录 前言1. 应用层自定义协议与序列化1.1 什么是应用层?1.2 再谈 "协议"1.3 序列化 和 反序列化 2. HTTP 协议3. 认识 URL(统一资源定位符)4. urlencode和urldecode5. HTTP 协议请求与响应格式5.1 HTTP 请求5.2 HTTP 响应 6. HTTP 的方法6.1 GET 方法…...
HFSS仿真结果怎么看?以T型波导为例,读懂S参数与电场动态图
HFSS仿真结果深度解析:从S参数到电场动态图的实战指南当你第一次在HFSS中完成T型波导仿真后,面对满屏的曲线和彩色云图,是否感到既兴奋又困惑?那些起伏的S参数曲线究竟告诉你什么信息?电场图中跳跃的颜色又代表怎样的物…...
rk35xx 通过recovery升级问题
Firefly 的 recovery 库是一个核心组件,它构建了一个独立的微型 Linux 系统,专门用于在设备主系统之外执行高可靠性的固件升级。简单来说,它的工作流程是:主系统通过命令触发,将升级指令写入特定分区并重启;…...
文件-语言-系统:基础IO-2.0——IO重定向接口,语言层缓冲区,系统级缓冲区。内核级分析!
bit::Shadow✧(≖ ◡ ≖✿ 目录 重定向接口dup2() ">" ">>" "<" 函数原型 输出重定向1和2的使用 文件描述符表 ./a.out运行: "./a.out >"默认重定向是fd 1 合并标准输入输出 缓冲区 什么是缓冲…...
光轮智能 谢晨 访谈总结机器人仿真数据产业
光轮智能 谢晨 访谈总结机器人仿真关于创始人关于数据数据金字塔数据痛点仿真数据的重要性仿真数据的质量b站链接地址公司官网关于创始人 清华物理;哥伦比亚金融;英伟达智驾仿真;小鹏智驾仿真;现为光轮智能CEO 关于数据 数据的…...
AI圈内火热的Agent、MCP、Skill、CLI是啥?用装修房子讲透,看完秒懂
本文用装修房子的比喻,详细解释了AI领域的四个核心概念:Agent如同会自主规划任务的私人助理;MCP是AI与外部工具数据的统一接口,类似USB-C;Skill是指导AI按标准操作执行的手册;CLI则是不依赖图形界面的命令行…...
百度深度学习研究院的“叛将“,带着一颗芯片改变了中国智能驾驶——地平线余凯,从ImageNet冠军到征程出货1000万
大家好,我是写代码的篮球球痴。这篇文章跟我自己有点关系——我开的是理想汽车。理想的智驾系统 AD Pro,搭载的就是地平线征程 5 芯片。2026 年 1 月理想 AD Pro 4.0 推送,基于单颗征程 6M 实现了城市 NOA——这是行业里第一个用单颗 128TOPS…...
终极指南:用D2DX让《暗黑破坏神2》在现代电脑上焕发新生
终极指南:用D2DX让《暗黑破坏神2》在现代电脑上焕发新生 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 还在为经…...
claude code用户如何迁移到taotoken解决封号与token不足问题
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Claude Code 用户如何迁移到 Taotoken 解决封号与 Token 不足问题 应用场景类,针对 Claude Code 用户常遇封号与 Token…...
收藏|2026年大模型算法岗崛起!程序员小白入门高薪赛道全攻略
前些年,算法岗位一直稳居技术圈高薪行列,无数程序员争相入局,也成为计算机专业毕业生求职首选方向。 伴随大模型技术飞速迭代落地,行业就业格局迎来重大变革。如今含金量最高、人才缺口最大、长期发展潜力顶尖的岗位,已…...
【C++】零基础入门 · 第 4 节:循环结构(while、for、do-while)
上一节我们学习了条件判断,这一节来学习循环结构。循环让程序能够重复执行某段代码,直到满足特定条件为止。C 提供了三种循环语句:while、for 和 do-while。 1. while 循环:先判断后执行 while 循环在每次执行前先检查条件&#x…...
