feat:上传mcguide-开发指南部份
88
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/0-基础架构.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# 基础架构
|
||||
|
||||
在上一个课程我们已经学习了预设和零件的一些简单用法,并轻松制作出了一个炫酷的功能玩法。
|
||||
|
||||
这个课程将逐步为你介绍一些更深入的知识,包括预设系统的构成、各种内置预设以及如何使用预设编辑器组装各种炫酷的预设等。
|
||||
|
||||
|
||||
|
||||
## 构成
|
||||
|
||||
预设系统的基础数据结构体系如下图:
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
前两层是基础数据类型,从第三层开始着重介绍,PresetBase、PartBase、BoxData是组装自定义预设/零件的基础结构,
|
||||
|
||||
EntityObject、PlayerObject、EffectObject是对SdkInterface(SDK接口封装基类)的另一层封装,构建对不同种类预设对象的抽象,以接口的形式对外直接提供组件操作;
|
||||
|
||||
XXXPreset相关都是一些内置预设,是预设体系与我的世界游戏元素的结合。
|
||||
|
||||
|
||||
预设系统的目标是进一步降低我的世界开发者的使用门槛,通过简单的组装,修改自定义预设,更方便的架设自己的新世界。
|
||||
|
||||
## 基础数据类型
|
||||
|
||||
- **GameObject**
|
||||
|
||||
GameObject(游戏对象)是所有预设对象的基类,实现了序列化,存档,读取等功能。
|
||||
|
||||
- **SdkInterface**
|
||||
|
||||
SdkInterface(SDK接口封装基类)是对SDK接口封装的基类,将组件的操作以方法的形式暴露出来,外界直接调用即可,不必再走先创建对应组件再调用组件相关方法的步骤。
|
||||
|
||||
- **TransformObject**
|
||||
|
||||
TransformObject(变换对象)是拥有坐标变换属性的的游戏对象基类,包括位置变换、旋转变换、缩放变换等,是拥有确定位置信息数据的一类对象。
|
||||
|
||||
- **PresetBase**
|
||||
|
||||
PresetBase(预设基类)是所有预设的基类。预设是一类可以被直接放置在场景中的TransformObject(变换对象),并且预设下可以挂接其他TransformObject,可以通过这种方式对游戏逻辑进行简单的封装。
|
||||
|
||||
在编辑器中放置预设时,会生成预设的虚拟实例,在游戏中生成预设,会生成真实实例。
|
||||
|
||||
它也可以直接理解为空预设,实现了挂接子节点,属性修改,实例化,加载卸载与驱动自定义零件逻辑等功能。
|
||||
|
||||
- **PartBase**
|
||||
|
||||
PartBase(零件基类)是所有自定义零件的基类。将零件挂接在预设下,可以为预设赋予特定的逻辑和功能。
|
||||
|
||||
设计零件的初衷是为预设提供一些即插即用的代码型功能组件。
|
||||
|
||||
通过良好的设计,预设系统的大部分功能都可以通过自定义零件实现。
|
||||
|
||||
零件本身放进MOD里并不会生效,必须挂接到某个预设身上,并让这个预设在游戏中实例化才能生效。
|
||||
|
||||
- **BoxData**
|
||||
|
||||
BoxData(素材数据)与素材类似,可以挂接在预设下使用。
|
||||
|
||||
素材在编辑器中不会实际生成,而是虚拟实例化,可以重叠放置。
|
||||
|
||||
在虚拟实例化状态,素材的变换可以任意调整并进行预览。
|
||||
|
||||
只要运行一次,素材就会真实实例化,永久变成地图的一部分。
|
||||
|
||||
真实实例化后,素材不会因预设卸载或调用坐标变换相关API而发生变化,也不会因重启地图而重新加载,直至销毁。
|
||||
|
||||
销毁素材时,会尝试将素材数据内未发生过变化的方块替换为空气,部分特殊方块可能无法清除。
|
||||
|
||||
- **EntityObject**
|
||||
|
||||
EntityObject(实体对象)是对实体公共SDK组件使用的封装,为外层实体预设提供了面向实体对象的组件操作方式,将底层SDK接口另外做了一层封装,向开发者提供更加便捷的SDK组件调用方式;
|
||||
|
||||
开发者无需再走先创建对应组件再调用组件方法的流程,可直接调用对外提供的组件方法,提高了开发者的开发效率。
|
||||
|
||||
- **PlayerObject**
|
||||
|
||||
PlayerObject(玩家对象)是对玩家相关SDK组件使用的封装,为外层玩家实体预设提供了面向玩家对象相关的组件操作方法,与实体对象的差异在于,其只封装了与玩家对象相关的sdk方法。
|
||||
|
||||
|
||||
- **EffectObject**
|
||||
|
||||
EffectPreset(特效预设)是一类绑定特效资源的预设,设计思路与上述所述(实体对象)设计思路一致,为外层特效实体预设提供了面向特效对象相关的组件操作方法。
|
||||
115
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/1-组装预设.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# 预设组装
|
||||
|
||||
前面我们已经系统学习了预设系统的基础数据类型和各种内置预设,但它们能实现的功能效果仍旧非常有限。
|
||||
|
||||
这一小节将介绍如何利用预设编辑器来组装自己的自定义预设,并以变换动画特效与高级分裂牛为例来阐述制作过程。
|
||||
|
||||
|
||||
|
||||
## **挂接规则**
|
||||
|
||||
在前面的课程里,我们知道可以很方便的把预设、零件、素材挂到另一个预设底下,将它们组装到一起实现特定的功能。
|
||||
|
||||
但并非意味着万物皆可挂接,在组装自定义预设前,我们需要明确一下预设,零件,素材等各种游戏对象的挂接规则。
|
||||
|
||||
下表是挂接关系表,第一列表示父节点,第一行表示子节点,√表示可以挂接,无内容表示不能挂接
|
||||
|
||||
| | 空预设 | 所有内置预设 | 零件 | 素材 | 实体预设 | 特效预设 | 玩家预设 | 方块预设 | 界面预设 | 文字面板预设 |
|
||||
| ------------ | ------ | ------------ | ---- | ---- | -------- | -------- | -------- | -------- | -------- | ------------ |
|
||||
| 空预设 | √ | √ | √ | √ | | √ | | √ | √ | √ |
|
||||
| 所有内置预设 | | | | | | | | | | |
|
||||
| 零件 | | | | | | | | | | |
|
||||
| 素材 | | | | | | | | | | |
|
||||
| 实体预设 | | √ | √ | | | √ | | | √ | √ |
|
||||
| 特效预设 | | √ | √ | | | √ | | | √ | √ |
|
||||
| 玩家预设 | | √ | √ | | | √ | | | √ | √ |
|
||||
| 方块预设 | | √ | √ | | | √ | | | √ | √ |
|
||||
| 界面预设 | √ | √ | √ | | | √ | | | √ | √ |
|
||||
| 文字面板预设 | | √ | √ | | | √ | | | √ | √ |
|
||||
|
||||
|
||||
- 实体预设,玩家预设不能挂在其他预设下
|
||||
|
||||
- 零件、素材不可以单独存在
|
||||
|
||||
- 下面不可挂接任何东西
|
||||
- 零件可以挂在任意预设下(内置预设除外)
|
||||
- 素材可以挂在空预设下
|
||||
|
||||
- 所有内置预设(包括内置空预设、内置特效预设和内置文字面板预设)下无法挂接任何东西
|
||||
|
||||
- 这是由于当前不支持调整子预设的挂接关系
|
||||
|
||||
- 无法将预设挂接到自己或任意自己引用的预设底下(不能循环挂接)
|
||||
|
||||
- 内置预设的原理不同,不存在循环挂接的问题
|
||||
|
||||
|
||||
|
||||
## 模板预设
|
||||
|
||||
在创建预设菜单下,我们提供了一些制作好的模板预设,通过学习这些模板预设可以很好的理解预设的组装流程。
|
||||
|
||||
- **变换动画特效**
|
||||
|
||||
一个特效预设,挂接了一个变换动画零件
|
||||
|
||||
该特效会循环播放并循环上下移动
|
||||
|
||||
该零件自定义了持续时间,循环,关键帧等属性,通过修改这些属性,可以实现多种多样的变换动画
|
||||
|
||||
- **分裂猪**
|
||||
|
||||
一个生物预设,挂接了一个受伤分裂零件
|
||||
|
||||
当它受伤时会分裂出一个同样的生物,但不包括死亡
|
||||
|
||||
受伤分裂零件自定义了一个循环分裂属性,勾选该属性,则分裂出来的生物也具有受伤分裂特性
|
||||
|
||||
|
||||
|
||||
## 组装变换动画特效
|
||||
|
||||
前面我们已经使用过这个酷炫的特效了,它的制作过程非常简单,本质只是在特效预设上挂了一个功能型零件。
|
||||
|
||||
- 首先我们在预设编辑器,通过菜单栏=>创建预设=>特效预设来创建一个新的特效预设。
|
||||
|
||||

|
||||
|
||||
- 将特效预设的特效文件设为sfxFromEditor.json,此时已经可以预览到这个特效
|
||||
|
||||
如果你没有看到sfxFromEditor这个特效,可以通过创建预设=>模板预设=>变换动画特效来先创建出这个特效,这个过程会把它依赖的的特效等各种资源拷贝到你的组件里,你也可以选择自己已有的任意特效来进行后续的制作。
|
||||
|
||||
- 通过菜单栏=>创建零件=>模板零件我们可以很方便地添加一些现成的模板零件,它可以帮助我们学习零件的开发。
|
||||
|
||||

|
||||
|
||||
- 从模板零件中选取TransformAnimationPart进行创建,创建完成后资源管理器会自动跳转到该零件的目录内。
|
||||
|
||||
- 接着将TransformAnimationPart(变换动画零件)挂接到我们的特效预设底下,它就变成了变换动画特效。
|
||||
|
||||
|
||||
|
||||
## 组装高级分裂牛
|
||||
|
||||
前面我们已经使用过分裂猪这个预设,现在我们尝试制作一个分裂牛,并和刚才制作的变换动画特效结合起来。
|
||||
|
||||
- 首先通过菜单栏=>创建预设=>模板预设=>分裂猪来创建一个新的生物
|
||||
|
||||

|
||||
|
||||
- 在属性面板上,将其名称改为**带特效的分裂牛**,设置整体模板为牛,并依次点击**应用**和**刷新所有属性**按钮使之生效
|
||||
|
||||

|
||||
|
||||
- 将变换动画特效挂接到这个分裂牛预设上,并将其属性中的关键帧1改为下图所示
|
||||
|
||||

|
||||
|
||||
- 切换到关卡编辑器,放置几个分裂牛到场景中,并控制角色移动到分裂牛附近
|
||||
|
||||

|
||||
|
||||
- 点击保存,然后运行,现在可以看到这个带特效的分裂牛了,尝试去攻击它吧
|
||||
|
||||

|
||||
147
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/2-实例与属性.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# 实例与属性
|
||||
|
||||
前面我们已经学习了如何组装自己的自定义预设,来实现一些炫酷的功能玩法。
|
||||
|
||||
这一小节我们将介绍如何修改舞台内的自定义预设/零件属性,来给这些实例赋予不同的功能效果,这有助于指导我们进行后续的零件开发。
|
||||
|
||||
|
||||
|
||||
## 预设存档
|
||||
|
||||
当我们把预设拖进关卡编辑器时,会生成一个预设的虚拟实例,显示在舞台中。
|
||||
|
||||
新版关卡编辑器的保存默认只保存预设存档,也就是舞台上显示的所有预设实例,而非整个地图。
|
||||
|
||||
预设存档文件位于存档目录的presets.json。
|
||||
|
||||

|
||||
|
||||
实体预设需要保存到地图中才能生效,当你添加/删除了实体预设时,新版关卡编辑器的保存会触发地图的保存。
|
||||
|
||||
**特别注意**:
|
||||
|
||||
如果单独把预设存档拷贝到了另一个地图,这个存档里的实体预设会无法加载,需要重新用编辑器打开这个地图保存一次。
|
||||
|
||||
|
||||
|
||||
## 预设实例
|
||||
|
||||
预设的实例化分为虚拟实例化与真实实例化。在编辑器内放置的预设属于虚拟实例,在开发测试运行时,预设才会真实实例化。
|
||||
|
||||
虚拟实例可以进行重叠放置,不会因方块重叠而丢失数据,可以通过坐标变换属性/坐标轴拖柄任意调整它的位置,旋转与缩放。
|
||||
|
||||

|
||||
|
||||
**特别注意**:
|
||||
|
||||
素材一经真实实例化就会存入地图存档,**坐标变换的相关API都不再生效**。
|
||||
|
||||
|
||||
|
||||
## 修改实例属性
|
||||
|
||||
预设放置到舞台中之后,我们可以对预设及其子节点的属性进行编辑,让同种预设的不同实例展现不同的效果。
|
||||
|
||||
前面我们创建了一个变换动画特效,它的零件默认属性设置的是4s内循环上下移动,接下来我们通过属性修改,来制作一些不同类型的变换特效。
|
||||
|
||||
在场景中放置3个变换动画特效,分别命名为移动,旋转,缩放。
|
||||
|
||||

|
||||
|
||||
将旋转的简易变换动画零件的属性按下图修改:
|
||||
|
||||

|
||||
|
||||
将缩放的简易变换动画零件的属性按下图修改:
|
||||
|
||||

|
||||
|
||||
点击保存,然后运行,可以看到3个特效分别播放着不同的变换动画。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## 修改本体属性
|
||||
|
||||
预设实例的修改只会影响单个实例,如果希望将修改同时应用于所有实例,需要修改预设本体。
|
||||
|
||||
在预设实例上右键,可以定位该实例的本体所在资源管理器路径。
|
||||
|
||||

|
||||
|
||||
双击预设本体,即可打开预设本体进行编辑。
|
||||
|
||||
对预设本体的修改,先会应用到所有实例上,然后实例再应用实例上的修改。
|
||||
|
||||
这里我们将零件的名称进行了修改,并将关键帧1的缩放改为了(3.0, 3.0, 3.0)
|
||||
|
||||

|
||||
|
||||
回到关卡编辑器后,发现3个动效的子节点名称都被修改了,且原来未改动过关键帧1的《移动》预设的关键帧1已经应用了本体的缩放修改。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## 常加载
|
||||
|
||||
**常加载**属性表示该预设在加载完成后,即使所在的区块被卸载,它也不会被卸载。
|
||||
|
||||
它只能应用于基于空预设组装的预设,不适用与实体预设,特效预设等。
|
||||
|
||||
它的主要用途是使一些全局预设移除随区块加载和卸载的特性,避免它卸载后导致逻辑问题。
|
||||
|
||||
它常常与预加载一同使用。
|
||||
|
||||
**特别注意**:
|
||||
|
||||
常加载预设不被卸载并不意味着它关联的方块或地图元素不会被卸载,只是保证它的逻辑会继续驱动。
|
||||
|
||||
|
||||
|
||||
## 预加载
|
||||
|
||||
**预加载**属性表示该预设将在地图初始化时,在地图出生点位置创建一个该预设的实例。
|
||||
|
||||
它只能应用于基于空预设组装的预设,不适用与实体预设,特效预设等。
|
||||
|
||||
它的主要用途是制作**类似GameManager功能的全局管理型功能预设**,帮助我们制作**不依赖于舞台的AddOn功能玩法**。
|
||||
|
||||
这两个新版模板都使用了预加载属性来创建预设以进行功能初始化。
|
||||
|
||||

|
||||
|
||||
- 使用预加载属性前,需要先设定出生点,这个可以通过地图编辑器=>菜单栏=>出生点功能进行设置。
|
||||
|
||||

|
||||
|
||||
- 创建一个空预设,改名为GameManager,预加载通常与常加载一并使用,它不会产生坐标更新,将变换更新间隔设为0
|
||||
|
||||

|
||||
|
||||
- 创建一个空零件,挂接到GameManager预设上,修改零件的InitServer初始化函数为监听聊天事件
|
||||
|
||||
```python
|
||||
def InitServer(self):
|
||||
print(self.classType, "InitServer")
|
||||
import mod.server.extraServerApi as serverApi
|
||||
self.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "ServerChatEvent", self, self.OnServerChatEvent)
|
||||
|
||||
def OnServerChatEvent(self, args):
|
||||
playerId = args.get("playerId")
|
||||
print("OnServerChatEvent", playerId)
|
||||
import mod.server.extraServerApi as serverApi
|
||||
comp = serverApi.GetEngineCompFactory().CreateMsg(playerId)
|
||||
comp.NotifyOneMessage(playerId, "Hello, world", "§c")
|
||||
```
|
||||
|
||||
- 点击运行,输入聊天指令,刚编写的零件已经生效了
|
||||
|
||||

|
||||
|
||||
**特别注意**:
|
||||
|
||||
- 预加载预设也可以与舞台场景内的预设协同工作,预加载预设的创建时机要早于舞台预设
|
||||
- 存在多个预加载预设时,其加载顺序为预设文件名xxx.preset的字母序
|
||||
- 有少量事件的时机发生在预加载预设创建之前,会导致无法监听到,如房主的AddServerPlayerEvent
|
||||
99
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/3-生命周期.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# 预设生命周期
|
||||
|
||||
前面我们已经学习了如何使用预设的常加载与预加载等属性,但我们还不知道预设是怎么加载卸载的。
|
||||
|
||||
这一小节我们将介绍预设和零件的生命周期,我们应该如何管理MOD里的各种预设和零件,这有助于指导我们进行后续的零件开发。
|
||||
|
||||
|
||||
|
||||
## **服务端**与客户端实例
|
||||
|
||||
在前面学习MOD开发过程中,我们已经了解到服务端和客户端属于两个不同的容器,同样预设和零件的实例也分为服务端实例与客户端实例。
|
||||
|
||||
我们希望零件是一个轻量级的功能单位,如果每个零件都需要像system那样分别编写客户端系统类和服务端系统类,那样会显得非常臃肿。
|
||||
|
||||
因此我们支持在一个零件类里编写双端代码,当使用零件提供的双端API时,它会自动根据当前是客户端还是服务端返回相应的内容,如GetLevelId()。
|
||||
|
||||
如果需要import SDK中的服务端/客户端部分,需要将import代码放到函数内部,且函数命名需要带有Server/Client以进行区分。
|
||||
|
||||
下面以玩家基础属性零件为例:
|
||||
|
||||
```python
|
||||
def InitClient(self):
|
||||
logger.info("%s InitClient %s %s", self.classType, self.GetParent().GetPlayerId(), self.showName)
|
||||
import mod.client.extraClientApi as api
|
||||
nameComp = self.CreateComponent(str(self.GetParent().GetPlayerId()), 'Minecraft', 'name')
|
||||
nameComp.SetShowName(self.showName)
|
||||
|
||||
if self.GetParent().GetPlayerId() == api.GetLocalPlayerId():
|
||||
gameComp = self.CreateComponent(api.GetLevelId(), 'Minecraft', 'game')
|
||||
gameComp.SetNameDeeptest(not self.nameDeeptest)
|
||||
self.NotifyToServer("OnLoadSuccess", {'id': self.GetParent().GetPlayerId()})
|
||||
```
|
||||
|
||||
```python
|
||||
def InitServer(self):
|
||||
logger.info("%s InitServer %s", self.classType, self.GetParent().GetPlayerId())
|
||||
self.ListenSelfEvent('OnLoadSuccess', self, self.OnLoadSuccess)
|
||||
```
|
||||
|
||||
```python
|
||||
def OnLoadSuccess(self, data):
|
||||
logger.info("%s OnLoadSuccess %s", self.classType, self.GetParent().GetPlayerId())
|
||||
import mod.server.extraServerApi as api
|
||||
pComp = self.CreateComponent(data['id'], "Minecraft", "player")
|
||||
pComp.SetPlayerRespawnPos(tuple(self.spawnPos))
|
||||
...
|
||||
```
|
||||
|
||||
- 零件的客户端部分负责在初始化时,将父预设(即玩家)的ID通知服务端
|
||||
- 零件的服务端部分在初始化时,监听客户端事件,接收到登录玩家的ID时,设置该玩家的相关属性
|
||||
|
||||
关于零件的开发规范,详情可以查阅[零件开发规范](../12-深入理解零件/6-零件开发规范.md)。
|
||||
|
||||
关于双端实例的通讯与网络同步,我们提供了一些内置API,比如上面这个零件使用到的**NotifyToServer**与**ListenSelfEvent**,详情可以查阅[通讯与网络同步](../12-深入理解零件/3-通讯与网络同步.md)。
|
||||
|
||||
|
||||
|
||||
## 生命周期
|
||||
|
||||
预设系统的完整生命周期如下:
|
||||
|
||||

|
||||
|
||||
- 总是先加载服务端实例,再加载客户端实例
|
||||
- 服务端预设实例的坐标变换变更,添加删除素材、零件或子预设,卸载或销毁,都会广播通知所有客户端预设实例进行数据同步,而客户端的任何变更,都不会主动向服务器同步,需要显示调用请求服务端的相关API
|
||||
- 零件的InitServer/InitClient在预设初始化时调用一次
|
||||
- 零件的TickServer/TickClient在预设加载后每个逻辑帧调用一次
|
||||
- 零件的UnloadServer/UnloadClient在预设卸载时调用一次
|
||||
- 零件的DestroyServer/DestroyClient在预设销毁时调用一次
|
||||
|
||||
### 加载依赖
|
||||
|
||||
预设加载的前置条件是它的所有变换对象(TransformObject)依赖的区块全部加载完毕。
|
||||
|
||||
**特别注意**:
|
||||
|
||||
- 不建议构建需要依赖大量区块的大型预设,预设并不是适用来保存地形,城堡类的大型素材
|
||||
- 不建议设置预设的多个子节点到相距很远的位置,这也会导致预设依赖它们中间跨越的所有区块
|
||||
|
||||
实体预设在加载时,会与对应的实体进行绑定,因此它除了依赖区块加载,还依赖于实体的加载。
|
||||
|
||||
同理,玩家预设的加载依赖对应的玩家登陆。
|
||||
|
||||
客户端预设的加载还依赖于对应的服务端预设加载。
|
||||
|
||||
### 加载过程
|
||||
|
||||
预设加载过程分为四步:
|
||||
|
||||
- 根据预设文件ID获取预设文件,解析预设层次结构本体
|
||||
- 递归分析预设所依赖的素材,零件,子预设,实例化展开所有游戏对象,并构建游戏对象的父子关系
|
||||
- 应用预设/零件存档里的实例修改部分
|
||||
- 应用预设/零件层次结构的坐标变换
|
||||
|
||||
### 卸载与销毁
|
||||
|
||||
- 当预设的加载依赖不满足,且预设不具有常加载属性时,预设将被卸载。
|
||||
|
||||
- 在零件内主动对父预设进行销毁,不会立刻停止零件代码,父预设会继续完成当前帧所有子节点的逻辑,在当前帧的末尾完成销毁
|
||||
182
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/4-预设变换.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# 预设变换
|
||||
|
||||
## 坐标属性
|
||||
|
||||

|
||||
|
||||
如上图所示,预设属性中坐标变换有三类属性:位置,旋转,缩放。此三类属性都有(x,y,z)轴3个值。
|
||||
|
||||
**位置**: 设置预设在父节点坐标系的位置偏移,如果预设是根节点,则设置预设在世界坐标系的位置。
|
||||
|
||||
**旋转**: 设置预设在父节点坐标系的旋转欧拉角度。如果预设是根节点,则设置预设在世界坐标系下的旋转欧拉角。
|
||||
|
||||
**缩放**: 设置预设在父节点坐标系的缩放系数。如果预设是根节点,则设置预设在世界坐标系下的缩放系数。
|
||||
|
||||
|
||||
|
||||
**坐标的属性变换顺序**:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
如上参数所示,预设是按照当前所在坐标系,先进行**缩放**变换,然后进行**旋转**变换,然后进行位置**平移**变换。
|
||||
|
||||
**旋转变换**的顺序是先按**Z轴**旋转,再按**X轴**旋转,再按**Y轴**旋转。
|
||||
|
||||
各变换参考的坐标系都是当前所在父节点的坐标系(根节点则是世界坐标系),而不是自身的缩放和旋转变换后的坐标系。
|
||||
|
||||
|
||||
|
||||
## 预设变换操作
|
||||
|
||||
**鼠标拾取和选中**:
|
||||
|
||||

|
||||
|
||||
鼠标左键**单击**地图**场景中**的特效,生物,素材等预设,即可**选中**当前预设,进行相关操作。
|
||||
|
||||
鼠标左键**单击关卡编辑器**里的**舞台界面**中的预设列表项,或者**预设编辑器**里**层级界面**中的预设列表,也可以选中对应预设。
|
||||
|
||||
鼠标左键**双击**预设列表项则会**快速定位**到对应预设的位置。
|
||||
|
||||
|
||||
|
||||
在**预设编辑器**中,因为**根节点**没有坐标变换相关属性,因此**不能选中操作根节点**。
|
||||
|
||||

|
||||
|
||||
如生物预设,因为不能挂载在其他预设节点下面,因此不能在预设编辑器点击选中和操作。
|
||||
|
||||

|
||||
|
||||
特效预设可以挂载在预设节点之下,因此可以在预设编辑器下点击选中进行操作。
|
||||
|
||||
|
||||
|
||||
**切换操作模式**:
|
||||
|
||||

|
||||
|
||||
在当前选中预设时,按键盘数字键"**1**" "**2**" "**3**" 可以切换操作模式为**位置平移**,**旋转**和**缩放**操作模式。
|
||||
|
||||
 
|
||||
|
||||
**平移和缩放操作**:点击对应操作坐标轴,按住鼠标左键,移动鼠标方向,即可操作移动或拉伸预设。
|
||||
|
||||

|
||||
|
||||
**旋转操作**:点击对应操作坐标轴,按住鼠标左键,向**右下**移动**增加**旋转角度,向**左上**移动**减少**旋转角度。
|
||||
|
||||
注意,**旋转的顺序是ZXY轴**,因此旋转操作最终效果**由ZXY旋转角度的顺序**决定。
|
||||
|
||||
|
||||
|
||||
## 预设变换限制
|
||||
|
||||
预设操作因为MC的规则限制,
|
||||
|
||||
**素材预设变换限制:**
|
||||
|
||||
位置限制:素材方块对应坐标需为整数,对应非整数部分,舍去小数部分处理。
|
||||
|
||||
旋转限制:素材方块只能旋转90度的倍数角度,非90度倍数部分忽略,对于负角度按对应正方向角度处理。
|
||||
|
||||
如旋转300度,对应素材方块旋转270度。而旋转-40度,对应旋转320度,对应素材旋转270度。
|
||||
|
||||
同时一些方块如床等也有旋转方向的限制。
|
||||
|
||||
缩放现在: 素材缩放效果不会小于1个方块。
|
||||
|
||||
素材缩放最大值100,同时素材方块尺寸不能多于一千万个方块。素材尺寸太大会影响操作性能。
|
||||
|
||||
素材缩放尺寸的系数为负值,则当做正值处理。
|
||||
|
||||
**生物预设变换限制:**
|
||||
|
||||
旋转限制:生物旋转只支持Y轴,X和Z轴旋转只忽略。
|
||||
|
||||
缩放现在: 生物缩放最小值为0.1,同时缩放效果不会小于1个方块。
|
||||
|
||||
素材缩放最大值100,同时素材方块尺寸不能多于一千万个方块。素材尺寸太大会影响操作性能。
|
||||
|
||||
特效变换限制:
|
||||
|
||||
旋转限制:序列帧特效的旋转同时会受到**始终面向相机**的属性影响。
|
||||
|
||||
粒子特效的旋转同时会受到**特效方向**以及**粒子朝向模式**的影响。
|
||||
|
||||

|
||||
|
||||
 
|
||||
|
||||
|
||||
|
||||
## 预设变换API
|
||||
|
||||

|
||||
|
||||
**变换更新间隔(updateTransformInterval):**
|
||||
|
||||
用来控制游戏模式下预设及子节点的坐标变换(位置,旋转,缩放)更新间隔,默认值为2。 我的世界逻辑帧率为每秒30帧,建议对于非必要每帧更新的预设设置此值为合适值。
|
||||
|
||||
设置为0时,通过API设置预设的坐标变换都不会更新,因此其附加子节点也不会跟随更新。设置为1时,每帧更新。设置为2时,则每两帧更新一次。
|
||||
|
||||
如游戏模式下,生物预设挂载了一个特效预设为子节点。其中生物预设的变换更新间隔是0,则通过API控制生物预设或者游戏内AI或者操作逻辑移动了生物对象,其坐标变换也不会更新修改。因此其挂载的特效也不会有位置或者旋转的跟随变换。如果变换更新间隔为10,则每10帧同步更新一次坐标变换,同时也会更新其特效子节点的位置变换。
|
||||
|
||||
|
||||
|
||||
**Transform**:
|
||||
|
||||
Transform对象拥有**pos**(位置),**rotation**(旋转),**scale**(缩放)三个属性,都为**tulpe(x,y,z)**格式。
|
||||
|
||||
通过**AddOffset**,**AddRotation**,**AddScale**接口,传入对应tuple(x,y,z)参数,可在Transform当前属性基础上修改Transform对应的pos,rotation,scale属性。
|
||||
|
||||
通过**AddTransform**接口,传入一个Transform对象,可在Transform当前属性基础上同时修改Transform对应的pos,rotation,scale属性。
|
||||
|
||||
注意,Transform对象本身并没有关联父节点数据,同时也没关联其游戏内所在对象。
|
||||
|
||||
通过以上接口直接操作Transform的属性,并不会对游戏内关联对象产生坐标变换的更新。
|
||||
|
||||
|
||||
|
||||
**TransformObject**:
|
||||
|
||||
TransformObject对象关联了游戏种的生物,特效等象,同时关联其父节点和子节点。通过此对象API可以控制游戏对象和其子节点的在游戏中的坐标变换。
|
||||
|
||||
TransformObject的坐标变换属性有两个坐标参考系,一个是**WorldTransform**,对应的是**世界坐标系**下的坐标变换(位置,旋转,缩放)属性。一个是**LocalTransform**,对应的是其**父节点局部坐标系**下的坐标变换(位置,旋转,缩放)属性。当一个预设节点是根节点时,其WorldTransform和LocalTransform相等。
|
||||
|
||||
WorldTransform是由LocalTransform和父节点的局部坐标系转换得到,因此以下接口修改WorldTransform会转换成修改对应的LocalTransform属性。而修改LocalTransform即同时修改了WorldTransform属性。
|
||||
|
||||
**GetLocalTransform**接口:
|
||||
|
||||
获取当前TransformObject的Transform对象。此Transform属性对应的是其在父节点的局部坐标系下的坐标转换属性。本身为根节点则为世界坐标系下坐标转换属性。
|
||||
|
||||
**SetLocalTransform**接口:
|
||||
|
||||
传入一个Transform对象,设置其在父节点的局部坐标系下的坐标转换属性。本身为根节点则为世界坐标系下坐标转换属性。
|
||||
|
||||
获取和修改**LocalTransform**具体属性:
|
||||
|
||||
GetLocalPosition,SetLocalPosition,GetLocalRotation,SetLocalRotation,GetLocalScale,SetLocalScale分别获取和设置LocalTransform的pos(位置),rotation(旋转),scale(缩放)属性。
|
||||
|
||||
AddLocalOffset,AddLocalRotation,AddLocalScale分别增加LocalTransform的pos(位置),rotation(旋转),scale(缩放)属性值。可用来实现其在父节点局部坐标系下如按速度旋转或者移动的逻辑。
|
||||
|
||||
|
||||
|
||||
**GetWorldTransform**接口:
|
||||
|
||||
获取当前TransformObject的在世界坐标系下坐标转换属性。当其为根节点时,此值和GetLocalTransform一致。当其为子节点时,则由其LocalTransform和父节点的WorldTransform变换得到。
|
||||
|
||||
**SetWorldTransform**接口:
|
||||
|
||||
传入一个Transform对象,设置其在世界坐标系下转换属性。本身为根节点则和SetLocalTransform一致。其为子节点,则根据父节点的WorldTransform转换得到对应LocalTransform。
|
||||
|
||||
获取和修改**WorldTransform**具体属性:
|
||||
|
||||
GetWorldPosition,SetWorldPosition,GetWorldRotation,SetWorldRotation,GetWorldScale,SetWorldScale分别获取和设置**WorldTransform**的pos(位置),rotation(旋转),scale(缩放)属性。
|
||||
|
||||
AddWorldOffset,AddWorldRotation,AddWorldScale分别增加**WorldTransform**的pos(位置),rotation(旋转),scale(缩放)属性值。可用来实现其在世界坐标系下如按速度旋转或者移动的逻辑。
|
||||
|
||||
58
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/5-预设调试.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# 预设调试
|
||||
|
||||
前面我们已经学习了预设坐标变换的相关内容,这一小节我们将介绍如何在运行时调试MOD里的各种预设和零件。
|
||||
|
||||
|
||||
|
||||
## 添加调试器
|
||||
|
||||
通过预设编辑器=>菜单栏=>创建预设=>模板预设=>调试器可以内置一个预设调试器
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## 调试指令
|
||||
|
||||
该预设提供了如下指令:
|
||||
|
||||
- **preset server**
|
||||
|
||||
打印所有服务端预设概要信息
|
||||
|
||||

|
||||
|
||||
- **preset client**
|
||||
|
||||
打印所有客户端预设概要信息
|
||||
|
||||
- **preset server id**
|
||||
|
||||
打印服务端指定ID的预设概要信息
|
||||
|
||||

|
||||
|
||||
- **preset client id**
|
||||
|
||||
打印客户端指定ID的预设概要信息
|
||||
|
||||
- **preset server func**
|
||||
|
||||
在服务端执行调试器零件里的指定函数名称为func的函数,如preset server test
|
||||
|
||||
结合前面查询到的预设名称与ID,利用MCStudio的热更功能,可以在运行时对预设进行简单的调试
|
||||
|
||||
```python
|
||||
def test(self):
|
||||
# 替换你要调试的对象ID
|
||||
objId = 6
|
||||
print("test isClient: %s" % self.isClient)
|
||||
obj = self.GetManager().getGameObjectById(objId)
|
||||
if obj:
|
||||
# 写点调试代码
|
||||
print(obj.GetWorldPosition())
|
||||
```
|
||||
|
||||
- **preset client func**
|
||||
|
||||
在客户端执行调试器零件里的指定函数名称为func的函数
|
||||
0
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/README.md
Normal file
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625726982736.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625730517868.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625730585491.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625733206438.png
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625733280166.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625735741835.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625735833546.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625736191024.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625736721582.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625736938598.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625736968462.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625737797422.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625737856125.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625737920101.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625745022676.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625745091606.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625745206164.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625745231339.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625748565709.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625748639428.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625748680515.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/1625813374207.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/cow_effect.gif
Normal file
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 280 KiB |
|
After Width: | Height: | Size: 304 KiB |
|
After Width: | Height: | Size: 387 KiB |
|
After Width: | Height: | Size: 386 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 402 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 165 KiB |
|
After Width: | Height: | Size: 362 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 85 KiB |
BIN
mcguide/20-玩法开发/14-预设玩法编程/11-深入理解预设/images/move_rotate_scale.gif
Normal file
|
After Width: | Height: | Size: 2.6 MiB |