十四:在世界中投放NPC/Monster
Space的cell创建完毕之后, 引擎会调用base上的Space实体, 告知已经获得了cell(onGetCell),那么我们确认cell部分创建好了之后就可以开始投放NPC出生点了。
(注意:这里并不是直接将NPC/Monster创建出来,而是先在对应的位置创建了一个出生点, 出生点的好处是可以根据一定规则, 当NPC/Monster在某区域减少的时候
可以在合适的时候将其创建出来,例如:一群怪被玩家清理掉了,半小时后怪刷出。)

onGetCell添加了一个刷出生点的定时器, 我们不能一次性创建出所有的出生点,因为数量可能很多, 使用定时器分批创建。

  1. scripts/base/space.py:
  2. def onGetCell(self):
  3. """
  4. KBEngine method.
  5. entity的cell部分实体被创建成功
  6. """
  7. self.addTimer(0.1, 0.1, SCDefine.TIMER_TYPE_SPACE_SPAWN_TICK)

复制代码

出生点的数据(实体类型、坐标、朝向等)是通过配置文件给出的,script/data/d_spaces_spawns.py与script/data/spawnpoints/xinshoucun_spawnpoints.xml 关于这2个配置的由来可以参考配置章节

  1. kbengine_demos_assets\scripts/base/space.py:
  2. def spawnOnTimer(self, tid, tno):
  3. """
  4. 出生怪物
  5. """
  6. if len(self.tmpCreateEntityDatas) <= 0:
  7. self.delTimer(tid)
  8. return
  9. datas = self.tmpCreateEntityDatas.pop(0)
  10. if datas is None:
  11. ERROR_MSG("Space::onTimer: spawn %i is error!" % datas[0])
  12. KBEngine.createBaseAnywhere("SpawnPoint",
  13. {"spawnEntityNO" : datas[0], \
  14. "position" : datas[1], \
  15. "direction" : datas[2], \
  16. "modelScale" : datas[3], \
  17. "createToCell" : self.cell})

复制代码

SpawnPoint实体被创建出来之后,其构造函数中会调用API接口创建实体的cell部分

  1. kbengine_demos_assets\scripts/base/spawnpoint.py:
  2. class SpawnPoint(KBEngine.Base, GameObject):
  3. def __init__(self):
  4. self.createCellEntity(self.createToCell)

复制代码

SpawnPoint的cell部分会在当前位置根据自身被创建时所给予的参数信息来创建出真正的NPC/Monster

  1. kbengine_demos_assets\scripts/base/spawnpoint.py:
  2. def spawnTimer(self, tid, tno):
  3. datas = d_entities.datas.get(self.spawnEntityNO)
  4. if datas is None:
  5. ERROR_MSG("SpawnPoint::spawn:%i not found." % self.spawnEntityNO)
  6. return
  7. params = {
  8. "spawnID"    : self.id,
  9. "spawnPos" : tuple(self.position),
  10. "uid" : datas["id"],
  11. "utype" : datas["etype"],
  12. "modelID" : datas["modelID"],
  13. "modelScale" : self.modelScale,
  14. "dialogID" : datas["dialogID"],
  15. "name" : datas["name"],
  16. "descr" : datas.get("descr", ''),
  17. }
  18. e = KBEngine.createEntity(datas["entityType"], self.spaceID, tuple(self.position), tuple(self.direction), params)

复制代码

 
十五:Monster的AI(移动、攻击、思考)
Monster继承了一系列的接口, 每种接口对应于不同的功能。
(注意:这里使用的继承而没有用组件的原因是目前的设计def定义的远程方法只能与entity是同一个层的,可以理解为entity.xxx一级的属性,如果是组件形式则entity.component.xxx方法是无法被远程调用到的。
一定要使用组件形式也可以, 继承这些接口之后,在接口模块中实现组件, 如果有需要远程调用的接口则通过接口层向组件中转发)

  1. class Monster(KBEngine.Entity,    // 每个实体都必须从引擎基本实体类型继承出来,这样引擎才可以维护,并拥有一些API特性
  2. NPCObject,
  3. Flags,                                          // 一个管理标记信息的模块,标记如: 正在交易中、正在xx。
  4. State,                                         // 状态模块, 主状态例如:死亡、活着。子状态例如:闲置状态、战斗状态
  5. Motion,                                       // 关于移动的封装
  6. Combat,                                    // 关于战斗公式、战斗属性等等的封装
  7. Spell,                                          // 技能释放、buff/debuff维护等
  8. AI):                                            // 智能思考模块

复制代码

移动实体:
    scripts/cell/Motion.py                randomWalk : 随机走动, 通常用于怪物闲置状态时的走动
              backSpawnPos: 返回出生点,如果怪物被引诱至较远距离,则返回到出生时的点,避免被玩家带到别处。
              gotoEntity: 移动到目标实体的位置。
              gotoPosition:移动到目标坐标点     实体继承与这个功能模块之后,实体就可以调用相关方法来移动了, 例如:monster.randomWalk()。 这些移动函数都是二次封装的,里面调用了引擎所提供的底层API函数来实现。
思考与攻击:
这里思考模块做的比较简单,只是添加了一个定时器以一定频率执行一些流程, 这些流程根据状态区分, 例如:怪物主状态为活着, 子状态为战斗时, 流程中(onThinkFight)会不断检查自己敌人列表的敌人,
根据敌人的情况决定是否攻击或者追击。 当距离敌人较远时使用“self.gotoPosition(entity.position, attackMaxDist - 0.2)”移动到离敌人较劲的可攻击距离, 当可攻击距离时对目标释放一个技能“self.spellTarget(skillID, entity.id)”

需要注意的是,  服务端上怪物成千上万, 而AI是比较耗的,如果只有一个玩家在线, 显然大量的怪物是不需要开启AI思考来白白耗掉CPU的, 这里有一个优化方法。
只有在玩家视野范围内的怪物才激活AI思考:

  1. def onWitnessed(self, isWitnessed):
  2. """
  3. KBEngine method.
  4. 此实体是否被观察者(player)观察到, 此接口主要是提供给服务器做一些性能方面的优化工作,
  5. 在通常情况下,一些entity不被任何客户端所观察到的时候, 他们不需要做任何工作, 利用此接口
  6. 可以在适当的时候激活或者停止这个entity的任意行为。
  7. @param isWitnessed        : 为false时, entity脱离了任何观察者的观察
  8. """
  9. INFO_MSG("%s::onWitnessed: %i isWitnessed=%i." % (self.getScriptName(), self.id, isWitnessed))
  10. if isWitnessed:
  11. self.enable()

复制代码

KBEngine简单RPG-Demo源码解析(3)的更多相关文章

  1. 使用.Net Core + Vue + IdentityServer4 + Ocelot 实现一个简单的DEMO +源码

    运行环境 Vue 使用的是D2admin: https://doc.d2admin.fairyever.com/zh/ Github地址:https://github.com/Fengddd/Perm ...

  2. springmvc运行流程简单解释(源码解析,文末附自己画的流程图)

    首先看一下DispatcherServlet结构: 观察HandlerExecutionChain对象的创建与赋值,这个方法用来表示执行这个方法的整条链. 进入getHandler方法: 此时的变量h ...

  3. 动画 ---Animejs 简单使用与源码解析

    Anime是什么 Anime有什么用 Anime是作何做的 requireAnimationFrame() engine(){ // 处理让多个帧运动起来 ​ play() ​ step()} ani ...

  4. Android 开源项目源码解析(第二期)

    Android 开源项目源码解析(第二期) 阅读目录 android-Ultra-Pull-To-Refresh 源码解析 DynamicLoadApk 源码解析 NineOldAnimations ...

  5. Mybatis源码解析-DynamicSqlSource和RawSqlSource的区别

    XMLLanguageDriver是ibatis的默认解析sql节点帮助类,其中的方法其会调用生成DynamicSqlSource和RawSqlSource这两个帮助类,本文将对此作下简单的简析 应用 ...

  6. Caffe2源码解析

    写在前面 上一篇文章对Caffe2中的core模块进行了简单拆解Caffe2源码解析之core,本篇给出其它模块的拆解,目的是大致了解每个模块的内容和目标,进一步理解Caffe2的整体框架.内容不多, ...

  7. KBEngine简单RPG-Demo源码解析(1)

    一:环境搭建1. 确保已经下载过KBEngine服务端引擎,如果没有下载请先下载          下载服务端源码(KBEngine):              https://github.com ...

  8. 简单理解 OAuth 2.0 及资料收集,IdentityServer4 部分源码解析

    简单理解 OAuth 2.0 及资料收集,IdentityServer4 部分源码解析 虽然经常用 OAuth 2.0,但是原理却不曾了解,印象里觉得很简单,请求跳来跳去,今天看完相关介绍,就来捋一捋 ...

  9. 使用CEF(三)— 从CEF官方Demo源码入手解析CEF架构与CefApp、CefClient对象

    在上文<使用CEF(2)- 基于VS2019编写一个简单CEF样例>中,我们介绍了如何编写一个CEF的样例,在文章中提供了一些代码清单,在这些代码清单中提到了一些CEF的定义的类,例如Ce ...

  10. 实现简单的手写涂鸦板(demo源码)

    在一些软件系统中,需要用到手写涂鸦的功能,然后可以将涂鸦的结果保存为图片,并可以将"真迹"通过网络发送给对方.这种手写涂鸦功能是如何实现的了?最直接的,我们可以使用Windows提 ...

随机推荐

  1. TDE: Transparent Data Encryption brief introduction

    1. What is TDE? Briefly speaking, TDE is used to encrypted data. 2. The benifits: Belows are come fr ...

  2. jmeter IP欺骗功能实现

    使用过loadrunner的同学,应该都了解有个IP欺骗功能,jmeter遇到类似需求怎样实现呢? 环境:windows7,jdk1.8,jmeter3.1 使用IP欺骗功能前提是本地有多个可用IP, ...

  3. javaWeb学习总结(11)- 监听器(Listener)在开发中的应用

    监听器在JavaWeb开发中用得比较多,下面说一下监听器(Listener)在开发中的常见应用 一.统计当前在线人数 在JavaWeb应用开发中,有时候我们需要统计当前在线的用户数,此时就可以使用监听 ...

  4. Microsoft Azure IoTHub Serials 1 - 使用Android设备与Azure IoTHub进行交互

    Azure IoTHub的目标是为物联网的应用场景提供方便的设备接入,完成消息的发送和接收(C2D和D2C).经过持续不断的努力,目前Azure IoTHub已经支持多种操作系统设备的接入,包括And ...

  5. php优化代码技巧

    1. 如果一个方法可静态化,就对它做静态声明.速率可提升至 4 倍. 2. echo 比 print 快. 3. 使用 echo 的多重参数(译注:指用逗号而不是句点)代替字符串连接. 4. 在执行 ...

  6. 一步一步实现基于GPU的pathtracer(一):基础

    出于3D计算机图形学和图形渲染方面的个人兴趣,脑子里便萌生出了自己实现一个渲染器的想法,主要是借助pathtracing这种简单的算法,外加GPU加速来实现,同时也希望感兴趣的朋友们能够喜欢,也欢迎提 ...

  7. Python-快速排序

    算法思想:快速排序运用了分而治之的思想,即在所选数组中选择一个基准(任选一个都可以),以改基准为基础,将小于该基准的元素都移动基准的左边,大于该基准的数据都移动到右边,然后对左右两边进行递归处理.同样 ...

  8. SQL SERVER大话存储结构(6)_数据库数据文件

            数据库文件有两大类:数据文件跟日志文件,每一个数据库至少各有一个数据文件或者日志文件,数据文件用来存储数据,日志文件用来存储数据库的事务修改情况,可用于恢复数据库使用.     这里分 ...

  9. [Leetcode] Binary tree Zigzag level order traversal二叉树Z形层次遍历

    Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to ...

  10. kali高速更新源以及主题修改方法

    文章不小心删了~这是我以前写的文章了了.实用性较强,所以现在补回来! 安装完kali之后,需要对软件进行一次整体更新:apt-get update & apt-get upgrade 但是,先 ...