GameMaker Studio 2

创建于:2017-04-19

创建人: dougen

190 信息 1082 成员
游戏开发工具 GameMaker Studio 2 的讨论小组

论GameMakerStudio对象实例的执行顺序(二)

BloveStorm 2017-10-04

一、继承

严格来说这部分内容并不属于对象实例执行顺序范畴内,但由于在后面章节会涉及到此功能,所以我们先做个铺垫。

说到继承,就要提到父与子这两种角色。当一个对象有一个父对象时,它可以继承其所有事件与代码内容。而这个对象就是这个父的子。当然子也可以有自己的子,但一个子不能有多个父。所以继承关系我们可以想象为树状结构即可。

Image title

正常情况下,一个对象(子)继承另一个对象(父),而子为空时(无任何事件),子将继承父的所有事件以及其事件内的代码(除spritevisiblesolidpersistentphysicsdepth等)。

子可以设置父所没有的事件,相当于青出于蓝而胜于蓝。而当子创建了一个其父所拥有的事件时,子将不继承父在本事件里的代码。除非子在本事件的代码里写上event_inherited()函数,他将继承父的在本事件的所有内容。

关于继承的功能,这里举个简单的例子。

假设有对象obj_Aobj_Bobj_C三个对象。obj_Bobj_C都继承obj_A

obj_A对象的代码如下:

    Create事件:

       n = 10;

    Step事件:

       n += 5;

obj_B对象的代码如下:

    End Step事件:

       n += 3;

obj_C对象的代码如下:

    Create事件:

       n = 5;   //不继承obj_Acreate事件里的代码。

    Step事件:

       event_inherited();//obj_Astep事件里的代码n += 5;

       n += 2;

结果:

    在本帧结束时,obj_An10create事件)到15step事件)。

    obj_Bn10(继承obj_Acreate事件)到15(继承obj_Astep事件),再到18end step事件)。

    obj_Cn5create事件的代码。它没有继承obj_Acreate事件里的代码)到10(继承obj_Astep事件里的代码),同时再到12step事件的代码)。

 

二、with函数

with函数的参数可以为对象(可为父),也可以为某特定实例id。其功能是在指定对象的所有实例或某一特定实例,即刻执行with里面的代码(对每个实例内生效)。

   功能看似简单,但实际上可能会很复杂。我们来分析一位网友的with问题。

假设只有一个对象obj_A。我们事先在房间编辑器创建obj_A的三个实例a1a2a3Id从小到大(即为执行顺序):a1 -> a2 -> a3

obj_A对象的代码如下:

      Create事件:

                time = 0;

                n = 0;

    Step事件:

                with obj_A

                       {

                         if keyboard_check_pressed(vk_space) && time = 0

                         time += 1;

                       }

                  if time = 1

                       {

                         n -= 5;

                         time = 0;

                        }

结果:

    a1n-10a2n-10;但a3n-5

 

问题分析:

我们按照实例的执行顺序,来详细分析下。

vk_space键按下的那一帧开始算起。由于vk_space键只按一下,所以第二帧不会执行keyboard_check_pressed(vk_space)

第一帧a1step事件:

   a1with代码,导致a1a2a3time都为1

   a1执行with下面代码后,此时a1time0n-5

第一帧a2step事件:

   a2with代码,导致a1time1(此时a2a3的time也为1)

   a2执行with下面代码后,此时a2time0n-5

第一帧a3step事件:

   a3with代码,导致a2的time1

   注意,a1并不执行其with下面代码!原因是a1time1

   a3执行with下面代码后,a2time0n-5

至此第一帧结束。此时a1time1n-5a2time1n-5a3time0n-5

 

第二帧a1step事件:

   由于a1time1,所以执行了n -= 5

a1最终time0n-10

第二帧a2step事件:

   由于a2time1,所以执行了n -= 5

a2最终time0n-10

 第二帧a3step事件:

   由于a3time0,所以什么都不执行;

a3最终time0n-5

 

以上结果是两帧后的结果。也就是说,当你在一帧里按下虚拟按键vk_space后,通过两帧才执行完成。

至此,网友的问题分析结束。当然,我们不推荐用with来玩嵌套。但如果你能分析清楚这个问题,那么with应该难不倒你了。

 

关于with还需要注意的是,如果with后面为父对象,那么父与其子都将执行with里面的代码。

举个简单例子。

假设有对象obj_Aobj_Bobj_Cobj_D四个对象。obj_Bobj_C都继承obj_A

obj_D对象的代码如下:

    Step事件:

          with obj_A

                {

                 n += 10;

                }

结果:

    所有obj_Aobj_Bobj_C的实例中,变量n都将加10

 

如果我们只想让obj_A的实例中变量n增加10,可以将代码写成:

      with obj_A

                {

                 If object_index = obj_A

                 {

                  n += 10;

                 }

                }

 

三、碰撞函数与事件

本质上碰撞事件与其他非draw事件在执行规则方面是相同的。但由于碰撞事件与碰撞函数的区别,以及碰撞多个实例的执行顺序问题,这部分内容我们还得拿出来单独讨论。

其实碰撞事件与碰撞函数还是有很大区别的。

1、碰撞函数以instance_place为例(与碰撞事件最为相像),在碰撞代码处只执行一次。也就是说,当本对象实例碰撞多个目标对象的实例时,在一帧里碰撞函数只会检测其中的一个实例(根据实例执行顺序决定)。并且根据实例的执行顺序逻辑,每帧都只会碰撞检测这个实例,除非改变被碰撞检测对象实例的执行顺序。

我们假设个场景。如果在本帧开始时,执行碰撞函数的实例,同时与多个被检测对象的实例碰撞时,碰撞函数只会检测id最小的(或在房间编辑器里Instance Order修改的实例顺序优先的)实例(与实例所属对象的object_index无关!)。然后再执行碰撞函数下面的其他代码。

举个简单例子。

假设有对象obj_Aobj_B两个对象。对象obj_A有一个实例id:100000;对象obj_B有两个实例:id:100001id:100002

obj_A对象的代码如下:

    Create事件:

                n = 0;

    Step事件:

                var temp;

                temp = instance_place(x,y,obj_B); //只检测id小者

                if temp

                 n = temp.n;

obj_B对象的代码如下:

    Create事件:

                n = id;

结果:

当实例id:100000obj_A)同时碰撞id:100001obj_B)与id:100002obj_B)两个实例时,id:100000n100001

 

2、而对于执行碰撞事件的实例,同时与多个被检测对象的实例碰撞时,碰撞事件将执行多次。其次数是被检测对象与之碰撞实例个数的总和。例如,当一个执行碰撞事件的实例,同时与被检测对象5个实例同时碰撞时,碰撞事件将执行5次。检测被撞对象实例的执行顺序,与对象实例执行顺序规则相同(遵循对象object_index与id规则)。

举个简单例子。

假设有对象obj_Aobj_B两个对象。对象obj_A有一个实例id:100000;对象obj_B有两个实例:id:100001id:100002

obj_A对象的代码如下:

    Create事件:

                n = 0;

    与obj_Bcollision事件:

                n = other.n;     //执行两次

obj_B对象的代码如下:

    Create事件:

                n = id;

结果:

当实例id:100000obj_A)同时碰撞id:100001obj_B)与id:100002obj_B)两个实例时,id:100000n先为100001,然后变为100002

 

四、speed相关问题

原本这部分内容应该放到【论GameMakerStudio事件的执行顺序】来讨论。但由于需要理解两个实例的执行顺序,所以我认为放到里较为合适。

首先我们举例来了解与分析问题。

假设有对象obj_Aobj_B两个对象。每个对象各有一个实例。这两个实例的精灵图片为64x64的正方形图片(中心点居中)。我们在房间编辑器里预先创建两个实例,并且让两个实例左右(obj_A在左,obj_B在右)无缝连接起来(两者x坐标差值为64)。

obj_A对象的代码如下:

    Step事件:

                x = obj_B.x-64;

obj_B对象的代码如下:

    Create事件:

                hspeed = 10;

结果:

    游戏在执行过程中,你会发现obj_Aobj_B的两个实例间有个10像素的缝隙。

分析:

    其实原因是在于speed属性和step事件的特点。当对象以speed属性(包括hspeedvspeed属性)进行移动时,只有在step事件结束时(所有实例都执行完step事件)才会改变其实例的坐标。上面例子中object_B的实例,只有当所有实例执行完step事件后,才会执行x += 10hspeed = 10的结果)。

所以在object_Astep实例里的x = obj_B.x-64代码中的obj_B.x,其实并没有执行hspeed = 10的结果。也可以理解为object_A一直在跟随object_B上一步的坐标。

 

要想避免这个情况发生,我们可以将object_Astep事件变成end step事件。

obj_A对象的代码如下:

    End step事件:

                x = obj_B.x-64;

或者我们干脆删除object_A中所有事件,object_B中不应用hspeed属性,在object_Bstep事件里用坐标移动自己与跟随者。

obj_B对象的代码如下:

    Step事件:

                x += 10;

                obj_A.x = x;

 

至此,对象实例的执行顺序讨论完毕。由于对象实例的执行顺序远远比想象的复杂的多,所以这次讨论绝对不可能涵盖所有可能性。要完善这部分内容,还需要大家多多提出建议。如果可能,我们会再做出一次专题性讨论。

(转发自:原日志地址
 

加入 indienova

  • 建立个人/工作室档案
  • 建立开发中的游戏档案
  • 关注个人/工作室动态
  • 寻找合作伙伴共同开发
  • 寻求线上发行
  • 更多服务……
登录/注册