# 使用零件编程 ## 内置函数 现在我们已经把零件通过挂接到预设的方式,在场景中实例化了,下面我们可以进行零件的编程了。 当然,你也可以先进行零件的编程,再进行他的挂接和实例化。 我们找到上一步创建的零件的文件夹,然后双击打开ChatPart.py,这里把他的代码粘贴在下方。 你可以发现,在零件的代码中,我们已经为你生成了总计6个内置函数,这些函数就是零件代码的逻辑入口。 ```python # -*- coding: utf-8 -*- from Preset.Model.PartBase import PartBase from Preset.Model.GameObject import registerGenericClass @registerGenericClass("ChatPart") class ChatPart(PartBase): def __init__(self): super(ChatPart, self).__init__() self.name = "Chat" def InitClient(self): pass def InitServer(self): pass def TickClient(self): pass def TickServer(self): pass def DestroyClient(self): pass def DestroyServer(self): pass ``` 他们分别是这些逻辑的入口: - \_init\_:零件初始化时,一般仅在此声明变量 - InitClient:零件实例的客户端初始化时 - InitServer:零件实例的服务端初始化时 - TickClient:零件实例的客户端每帧调用 - TickServer:零件实例的服务端每帧调用 - DestroyClient:零件实例的客户端销毁时 - DestroyServer:零件实例的服务端销毁时 直接在脚本里重写这些函数就可以在这些时机执行对应的逻辑。 ## 零件python编程 接下来,我们使用零件来实现一个简单的逻辑,我们在聊天栏输入“摧毁”时,摧毁这个零件的父预设实例。 当一个实例被摧毁时,挂接在他下面的所有实例也会跟着摧毁,所以,在这种情况下展览台预设下的。 代码如下,由于我们只用到服务端的初始化和销毁时,所以我们可以把其他的内置函数删除。 可以看到,我们在InitServer里监听了ServerChatEvent事件,当系统(我的世界)里发生玩家的聊天框输入时,会调用零件的OnServerChat函数。 然后我们在OnServerChat函数中判断,如果玩家输入的是摧毁,就摧毁父预设。 ```python def InitServer(self): import mod.server.extraServerApi as serverApi self.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "ServerChatEvent", self, self.OnServerChat) def DestroyServer(self): import mod.server.extraServerApi as serverApi self.UnListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), "ServerChatEvent", self, self.OnServerChat) def OnServerChat(self, args): # 生成掉落物品 # 当我们输入的信息等于摧毁时,摧毁父节点 if args["message"] == "摧毁": self.GetParent().Destroy() ``` > 当前我们已经支持在文件头 import 大部分库/文件。 > > 如果产生了报错,可以在使用时 import。 ## 使用Mod开发包测试结果 点击编辑器右上角的运行,进行本作品的开发测试。 ![instance008](./images/instance008.png) > 使用0.16.12(7月15日更新),或者更高版本的MC Studio新建的作品,只能使用1.23或更高版本的开发包进行开发测试 在运行的开发包中可以看到场景中的2个实例。 ![coding007](./images/coding007.png) 按回车调出指令窗,输入:摧毁,此时只有一个展览台实例被摧毁了,但两个展览台是都应该被摧毁的。 MC的事件机制是当一个事件的函数执行完毕时,才会发送下一个事件,而我们在执行的过程中进行了事件的反监听,导致了这一问题。 所以我们修改一下代码,让删除父节点的行为在事件触发的下一帧执行。 在资源管理器里找到Chat零件的文件夹,然后右键空白处,选择打开当前文件夹,我们在Windows的资源管理器内创建一个新的python文件,命名为coroutineMgrGas.py,然后将如下代码复制进去(此部分代码涉及的知识点较深,可以先按步骤操作): ```python # -*- coding: utf-8 -*- import time # 这个类的作用是延迟执行给定的函数 # 使用参考每个具体使用的地方,yield 正数为时间,负数为帧数 class CoroutineMgr(object): coroutines = {} globalEnd = [] addCoroutines = {} @classmethod def StartCoroutine(cls, iter): cls.addCoroutines[iter] = 0 return iter @classmethod def StopCoroutine(cls, iter): cls.globalEnd.append(iter) @classmethod def Tick(cls): if cls.addCoroutines: for c,v in cls.addCoroutines.iteritems(): cls.coroutines[c] = v cls.addCoroutines = {} if cls.globalEnd: for c in cls.globalEnd: if cls.coroutines.get(c): del cls.coroutines[c] cls.globalEnd = [] ended = [] for c, v in cls.coroutines.iteritems(): try: if v < 0: v += 1 cls.coroutines[c] = v if v == 0 or (v > 0 and time.time() >= v): newv = c.next() if newv > 0: newv = newv + time.time() cls.coroutines[c] = newv except StopIteration: ended.append(c) for c in ended: del cls.coroutines[c] ``` 然后修改ChatPart.py的代码如下: ```python from coroutineMgrGas import CoroutineMgr …… def TickServer(self): CoroutineMgr.Tick() def OnServerChat(self, args): # 生成掉落物品 # 当我们输入的信息等于摧毁时,摧毁父节点 if args["message"] == "摧毁": CoroutineMgr.StartCoroutine(self.DelayDestroy()) def DelayDestroy(self): yield -1 self.GetParent().Destroy() ``` 现在我们再进行开发测试,可以看到现象正常了! ![coding008](./images/coding008.png) ## 使用属性面板修改零件 我们在资源管理器中点击Chat.part,可以在他的属性面板中发现它的两个配套文件。除了在ChatPart.py里编程之外,我们还可以利用ChatPartMeta.py将ChatPart.py中的变量暴露到编辑器的属性面板中。 点击配套文件右侧的小图标可以直接打开它。 ![coding003](./images/coding003.png) 首先,我们先改造一下ChatPart.py,将“摧毁”作为一个变量使用。 ```python def __init__(self): super(ChatPart, self).__init__() self.name = "Chat" self.message = "摧毁" def OnServerChat(self, args): if args["message"] == self.message: ...... ``` 改造后的零件在使用上与之前没有什么区别,接下来,我们打开ChatPartMeta.py,这里面已经自动帮我们写好了一些必要的代码,我们在这个文件中键入1行代码,整体效果如下: ```python @sunshine_class_meta class ChatPartMeta(PartBaseMeta): CLASS_NAME = "ChatPart" PROPERTIES = { "message": PStr(group="默认", text="信息"), } ``` 然后返回编辑器,我们可以发现,Chat.part的属性面板中增加了我们自己定义的“信息”变量。 ![coding004](./images/coding004.png) 接下来,我们在舞台上找到Chat零件,分别把两个展览台预设的Chat零件的信息更改为“左”和“右”,然后保存并重新点击运行进行开发测试。 ![image-20210710145051437](./images/coding005.png) 我们打开聊天窗口,输入:右。 这次,只有右边的展览台实例被删除了! ![coding006](./images/coding006.png)