CloverSean,2012Monster的BGE系列之二BlenderGameEngine脚本指南BlenderGameEngine脚本指南原作者:Prof. Monster ( BlenderArtists论坛 )翻译:CloverSean(email:sinclover@gmail.com)介绍游戏逻辑是游戏中行为的规则。游戏逻辑通过这些方式来定义:·BGE环境隐式提供的逻辑,例如:2·场景管理·渲染·输入管理·动画系统·以及其他·通过以下方式定义的逻辑块:·GUI·Python你的Python脚本代码会成为BGE游戏循环中的⼀一部分。我推荐你首先阅读⼀一下“BGE游戏循环指南”.你要通过Python控制器来使用脚本代码。这意味着你的代码将会成为⼀一个controller的组成部分。BGE使用这种方式把脚本代码融入到逻辑当中。BGE希望⼀一个控制器能够尽可能快速运行,这就意味着你的代码最好不要无谓地浪费计算机的处理时间,或者完全占用游戏循环而不跳出。Section1大家好!这⼀一篇是对Blender游戏引擎当中使用Python脚本的简要介绍。指南的目的是教你如何在BGE中使用Python脚本,并且避免⼀一些典型的问题。这篇指南不会教你怎样使用Python。如果你想要学习Python语言,请阅读相关教程。(例如.ByteOfPython)当你为BGE书写Python脚本的时候,推荐你把Blender的PythonAPI打开参考。你可以在文档。请注意:BGE不支持叫做bpy的Blender内置API。当你在Blender里面刚刚开始游戏项目时可以使用,但是最后当游戏完成时,脚本当中不应当仍然包含相关的调用。3没有必要使用Python代码来模拟⼀一个逻辑块,因为编译之后的逻辑块总是比Python代码更快⼀一些。4Section2分类Python控制器和其他所有控制器都拥有同样的地位,就是说它也是从触发器中获取输入,激活或者停止激活相应的促动器。例如:当⼀一个按键按下时激活⼀一段动画。Python控制器的行为同时也像是⼀一个促动器。它可以不通过额外链接的促动器直接更改游戏的状态。例如你可以通过脚本让BGE把⼀一个对象放置到另⼀一个位置。有⼀一点很重要就是,尽管Python控制器拥有和其他的促动器⼀一样的行为,但是它并不是和那些促动器⼀一起运行。取而代之,这个特殊的控制器同其他所有控制器⼀一起运行。这个不同之处虽然很小但是非常重要。你可以像这样在逻辑编辑器当中添加⼀一个Python控制器:不要忘记给你的Python控制器添加⼀一个或者多个触发器。5在Python控制器里面选择模块模式:Section3Python控制器Python控制器拥有两个模式:·脚本模式(默认)·模块模式模块模式相比起脚本模式有很多优势:·Python脚本文件可以内置也可以存放在blend文件外·Python代码会通过提前编译使得运行速度有少许提升·Python代码可以用Python经典的模块方式来组织·你可以通过不同的入口使用同⼀一个Python文件(可以更好的组织代码)·可以在模块级别进行初始化·很容易将⼀一段脚本模式的代码转换成模块模式因为⼀一些历史原因脚本模式仍然是默认的模式,但是我建议仅仅使用模块模式。6Section4Python文件在你完成Python控制器的设置之前,你需要⼀一个Python文件。创建这个文件最简单的方法就是打开内置的文本编辑器,然后创建⼀一个新的文本块。或者你可以在当前工程的blend文件目录下创建⼀一个新的文本文件,并且更改这个文件的扩展名为“.py”最好这个文件的名称可以很容易让人联想到它的功能。较好的文件命名:·enemyBehavior.py·mouse.py·findObject.py·actionManager.py·selector.py·sceneManager.py不好的文件命名:·main.py·python.py·process.py·execute.py·do.py·perform.pyPython模块就是⼀一个包含了代码的Python文件,以“.py”作为扩展名。创建⼀一个BGE能够调用的模块,你需要定义⼀一些入口供BGE调用。BGE所需要的入口是⼀一些函数,这些函数可以拥有最多⼀一个参数:假如这个函数拥有⼀一个参数(不管它叫什么),BGE就会把这个参数赋予当前控制器的引用。上面这些代码就构成了你的第⼀一个Python模块。把它放到⼀一个Python文件当中去,例如叫做execise.py7Section5Python模块在Python控制器里面通过下面的格式写入脚本代码的入口:modualName.entryPointName模块的名字当中不包含.py以及括号,但是可以包含代码包(python的概念之⼀一)的名字。在我们的例子当中这样写:exercise.printControllerName8Section6脚本入口启动你的游戏(在3DView当中按下P键),Python控制器就会在被所连接的触发器触发时执行。[译者注]为了看到结果,windows用户请打开systemconsole(HelpToggleSystemConsole)Mac用户请在⼀一开始使用Terminal打开Blender,这时结果会显示在Terminal当中。Linux未测试--这时候你应该可以在输出窗口看见:恭喜,你已经运行了第⼀一个BGE的Python脚本代码。执行脚本代码BGE是怎样运行这个脚本模块的呢?在调用这个模块的时候,BGE通知Python解释机载入这个模块。这⼀一过程包括:·脚本模块编译成为字节码(如果还没有编译的话)·执行脚本模块自身的代码·就是没有任何缩进的代码·这些代码仅仅会执行⼀一遍!每⼀一次执行Python控制器的时候:Python解释机调用在脚本的模块中,以函数的形式写成的BGE脚本入口。这次调用会向入口传入当前控制器的引用作为参数。(图片见下页)9Section7他是如何工作的调用Python的模块允许你执行自定义的逻辑过程。你几乎可以做⼀一个单独的Python应用所能做的任何事。这⼀一点非常强大,但是你真正需要做的是和BGE之间的交互。因此BGE为你提供了⼀一个叫做API的接口。你在脚本中的任何命令都不会直接通过Python运行,而是告诉BGE来执行你所需要的动作。BGEAPI我们继续看⼀一些需要用到的重要对象。第⼀一个是你几乎能够在每⼀一个脚本代码里面看到的对象,当前的控制器(⼀一般命名为“cont”)。请记住你可以用任意多的控制器调用同⼀一段脚本代码。当前的控制器就是正在执行这⼀一段代码的那⼀一个。你可以获得所有连接在这个controller上面的逻辑块:·所连接的触发器·所连接的促动器让我们把这些逻辑块都输出在控制台当中:10Section8你会得到以下结果:当前控制器在其余每⼀一个控制器当中,你的代码都会首先计算所连接的触发器。有⼀一个经常被问到的问题说:“为什么按⼀一次按键,我的代码会执行两次?”这个问题的答案很简单:“因为控制器会在每⼀一次触发的时候执行,这并不意味着触发器是否为正”换句话说,你的代码必须关心触发器的状态。当前的控制器会提供给你⼀一组触发器,你必须自己选择正确的那⼀一个。请记住用户可能改变逻辑块的顺序,你可以通过名字来选择制定的触发器。11Section9当前连接的触发器如果你希望你的代码像⼀一个AND控制器⼀一样执行,你可以这么写:如果你希望像⼀一个OR控制器的话:除了状态和触发之外,触发器还提供了更多的数据。这些通常是非常复杂的数据,以至于简单的控制器不可能处理。比如nearsensor提供了⼀一组被检测到的对象,message触发器则提供了⼀一组收到的消息。你可以通过Python代码获取这些数据。从BGEAPI当中你可以看看那些能够从触发器所获取的数据。12Section10求值数据完成了触发器的求值之后,你的代码就可以开始处理促动器了。这时候你需要知道是否⼀一个连接着的促动器是:·激活的·未激活的·或者仍旧是以前的状态和触发器相似,你可以获得⼀一组促动器。可以用过名字来索引这些促动器:控制器向促动器发送⼀一个激活标志:控制器向促动器发送⼀一个取消激活的标志:如果促动器的状态不改变就什么都不做。注意,当⼀一个促动器同时收到了激活与取消激活的消息(例如有多个控制器同时连接这它),这个促动器会仅仅响应激活指令。13Section11当前连接的促动器如果你希望⼀一次性激活所有连接着的促动器:如果你想⼀一次性取消所有促动器的激活状态:你只能激活或者取消那些连接着的促动器的状态。所有连接的促动器每⼀一个逻辑块都有配置数据。这些数据是你通过GUI来设置的。你也可以通过Python脚本来获取这些数据。我的建议是,只有在你需要配置那些在游戏开始之前无法得知的数据时,再使用这种方法来更改。例如,如果你想要追踪⼀一个动态添加的对象。然而TrackTo促动器并不知道所添加的对象,它将会等待到游戏开始之后(这个对象通常是在隐藏层里面未激活的对象)在设置这个对象。这意味着你必须要:·给这个对象识别标志·通过识别标志来更新这个TrackTo促动器14Sample:给对象制定标示使用标示索引对象阅读BGE的API来获得更多关于触发器和促动器的脚本接口。配置数据很多情况下在当前的控制器中获取对象是很重要的。不过你可以很容易的获得这个对象的引用:所有的逻辑块都有⼀一个拥有者。这是因为触发器和促动器并不需要属于同⼀一个对象。⼀一个游戏对象提供了非常多的数据,包括位置、父对象、子对象等等。除此之外游戏对象还允许许许多多的操作,例如有位置更改,重新连接父子对象等等。有⼀一些操作会被立即执行,例如位移。其他有⼀一些会放进BGE的执行队列中,之后在合适的时间里在执行。和促动器所不同的地方在于,所有的执行操作都仅仅执行⼀一次(⼀一帧就是⼀一次游戏循环)。如果你的操作需要在⼀一段时间内执行,即不只1帧的话,那你就需要在这⼀一段时间里,自己驱动自己的代码来持续执行。你可以在BGE的API文档的KX_GameObject部分里找到BGE游戏对象所拥有的全部属性。当前的游戏对象15现在你知道怎样在你的脚本模块中添加BGE入口了,而且也知道了怎么在BGE的逻辑中调用这些接口。如果你能够给BGE的入口设置⼀一个参数那就更好了。这些参数被称为这个游戏对象的“属性”。用户可以用特别的数据来配置这些属性。Python控制器可以不通过属性触发器(PropertySensor)而直接读取这些属性(请看下⼀一页)。你的代码可以读取对象的属性:入口参数属性不仅仅只是⼀一个用来配置的参数而已,你的代码可以在运行时修改这些属性,添加或者删除。你可以把他们当做是游戏对象的持久数据。如果没有显式删除的话,他们将和所属的游戏对象⼀一同创建和删除。用户根本就不需要看到他们。那些在运行时创建出来的参数是内部属性。请注意,内部属性不能被属性触发器监听。加入你的代码因为KeyError而出错,属性可能不会被创建出来这里有三种方法避免这样的错误:·在使用之前用in来测试是否存在·使用“try:..except”来处理KeyError异常·使用get()方法来获得属性备注:get()方法总是能够返回⼀一个值。如果这个属性没有被创建出来那它就不会被添加成为属性。这时候get()方法就会返回⼀一个默认值:get(propertyName,defaultValue)如果没有指定默认值,将返回None。如果你设置⼀一个默认值,请使用⼀一种简单的类型。因为不管你是否使用这个默认值总是会被创建出来,而这会占用时间和内存。16属性通过赋值就可以更改⼀一个属性。当前值会被覆盖。获取属性BGE允许你同时拥有多个相互独立的场景。有时候就需要从当前游戏对象所在的场景中获得⼀一些数据。现在我们离开已知的控制器的世界,不管什么原因,总之控制器和游戏对象都不知道他们所处的场景。这时候我们就需要得到