GameMaker Studio 2

创建于:2017-04-19

创建人: dougen

190 信息 1080 成员
游戏开发工具 GameMaker Studio 2 的讨论小组
妹控的藤藤@GameMaker Studio 2 的内容(查看所有内容
[GMS2分享与求助]place_meeting和physics_test_overlap的差异

由于正在制作一个需要调用物理引擎平台跳跃游戏,尝试把非物理引擎下的平台跳跃系统重写进物理引擎下

在写状态机的时候遇到了place_meeting和physics_test_overlap的差异引起的问题

帮助手册的“Collision Checking”页面里的“Physics Collisions”标签下写到“When using the build in physics, the above collision functions are not guaranteed to work for physics enabled instances. This is mainly due to the fact that these instances no longer use the majority of the regular built in variables (instead, physics enabled instances have their own set of variables) and neither do they use the collision mask or bounding box, as they use fixtures instead. ”,简单来说就是因为物理object会使用fixture而非collision masks或bounding box,因此place_meeting等常用的Collision Checking命令无法很好地运行,实际强行使用也确实会出现一些运行不正常的情况(没有保存不正常例子的gif)

因此在使用物理引擎的情况下要进行Collision Checking,手册中仅提到了使用physics_test_overlap

单独建了一个实验室工程来说明问题

*以下代码中的obj_StaticParent指的就是蓝色方块

Image title


如上图所示,当使用代码

if physics_test_overlap(phy_position_x,phy_position_y+1,0,obj_StaticParent)

phy_speed_y = 0;

来判断白色方块是否站在蓝色方块上方时,由于右边方块与右侧的蓝色方块发生接触,physics_test_overlap的返回值为true,因此触发了phy_speed_y = 0,而左边的白方块则正常落到蓝色方块上后才触发phy_speed_y = 0

Image title


如上图,而如果用

if place_meeting(x,y+1,obj_StaticParent)

yspeed = 0;

来写判断白色方块是否在蓝色方块的上方,则会不会因为白色方块右侧紧贴蓝色方块而触发yspeed = 0,仅在下方接触到蓝色方块后触发yspeed = 0

Image title


同理在水平方向上,如上图

当使用

if physics_test_overlap(phy_position_x+1,phy_position_y,0,obj_StaticParent)

phy_speed_x = 0;

来判断白色方块是否在右侧碰撞到蓝色方块时,下面的白色方块会因为接触到了在下方的蓝色方块而返回true,进而phy_speed_x被赋值为0

Image title


如上图,如使用

if place_meeting(x+1,y,obj_StaticParent)

xspeed = 0;

来判断白色方块是否在右侧碰撞到了蓝色方块时,不会因为下方接触到了蓝色方块而返回true,能够正常使用

由以上实验可以判断出,physics_test_overlap命令会判断两个实例的fixture是否会“接触”,即fixture和fixture紧贴着而没有任何像素发生重合也会判断为true,

而place_meeting则会判断两个实例的collision masks或bounding box是否会“重合”,即两个实例仅collision masks或bounding box发生了重合才会返回true,否则即使是两个实例相距0像素紧贴在一起,返回值也会是false

这就是我发现的两个命令的差异

以下就是我遇到的问题

我原本写状态机的时候使用

if place_meeting(x,y+1,obj_StaticParent)

MyState = myState = playerstate.onGround;

来实现当玩家控制的object站在地面上(即判断下方1像素的位置是obj_StaticParent)则让状态机进入onGround状态

我在物理系统中替换成

if physics_test_overlap(phy_position_x,phy_position_y+1,0,obj_StaticParent)

MyState = myState = playerstate.onGround;

Image title


这种左右侧紧贴着墙壁的状态也会被认为是onGround,即使下方根本没有接触到obj_StaticParent

同理判断左右是否贴墙的时候也会受到上下影响

由于我没有系统的学过编程,除了对代码不熟悉以外更重要的就是缺乏程序员思维,这让我在遇到这个问题以后是在想不出变通解决之道,希望大佬不吝赐教

[求助]GMS2的物理引擎是否是“连续”的?

题目表述的不是特别清楚,我用下面一张图来解释一下我的疑问

Image title


上图中room启动了物理引擎,白色和蓝色方块均为物理物体

白色方块最初的移动和跳跃分别通过调整phy_speed_x和phy_speed_y来实现

在跳跃起来后通过physics_pause_enable(true)命令来暂停物理引擎

之后通过调整白色方块的坐标来实现移动

再使用physics_pause_enable(false)来取消物理引擎的暂停效果后,可以看到白色方块会回到暂停的位置,保持暂停时的运动状态继续运动

如果尝试不修改整个room的物理状态,而是通过phy_active来关闭白色方块本身的物理状态,则如下图

Image title


白色方块在空中使用phy_active = false来离开物理计算

但这时修改白色方块的坐标(即修改x和y值)无法使白色方块移动

使用phy_active = true后白色方块保持之前的物理状态进行运动

由以上一个实验我产生了一个疑问,GMS2的物理引擎是否必须是“连续”的?

在阅读物理引擎的官方文档里,发现对物理的介绍提到过一句“Normally for a physics simulation to work, it must be continuous and cannot be stopped and started, or have instances suddenly moved from one place to another in the room.”

是否这就意味着我无法在游戏的部分过程中使用物理引擎来简化一些复杂运动的代码量(比如使用钩锁钩住移动的天花板,还可以调整钩锁长度的单摆运动),而部分简单运动则使用坐标相关代码?

我原本打算制作一个平台跳跃游戏,角色可以使用钩锁钩住墙壁或天花板来做单摆运动越过障碍,我也尝试过使用圆的方程来还原,勉强能够实现单摆运动,但如果钩住的天花板会移动,以及钩锁的长度可以在单摆运动中变化,按我现在的能力不用物理引擎还真写不出来,于是想到了在钩锁部分使用物理引擎来简化计算的方法,结果就像上图那样难以实现

我也尝试过纯粹使用物理引擎来写这个游戏,而且由于碰撞检测不再需要自己写代码,代码量减少了很多,然而……

Image title


Image title



由于使用了物理引擎后会计算object在碰撞后的角速度,或者站在悬崖边上时向下掉落的角速度(即使角度阻尼值写得很大也无法避免),如果加载画好的人物sprite就会变得很诡异

Image title


我也尝试过使用draw命令来避免人物sprite角度乱动的状态,但是由于物理引擎还是会计算站在悬崖边上时object向下落的情形,当站的过于靠边的情况下还是会出现运动轨迹诡异的情况

Image title


在尝试了很久也阅读了游戏的帮助文档以后确实找不到解决办法,因此想要请问各位大佬,GMS2里是否确实无法让物理引擎“不连续”?

关于GMS2的Joint的若干问题求助

我在room中创建了一个控制object“obj_Control”,并建立了一个Create事件,代码如下


var instA = instance_create_layer(200, 150, "Instances", obj_Floor);

var instB = instance_create_layer(50, 200, "Instances", obj_Circle);

r = sqrt(power(instA.x-instB.x,2)+power(instA.y-instB.y,2));

var jointA = physics_joint_rope_create(instA, instB, instA.x, instA.y, instB.x, instB.y, r, true);


即在room中创建了实例A和实例B并通过Joint将两者连接在一起,这一步运作是正常的,运行后实例A和B被创建并被正确连接

之后我遇到两个问题

问题1:删除joint

如果我在Create时间结尾加入命令physics_joint_delete(joint)来删除Joint,即下方


var instA = instance_create_layer(200, 150, "Instances", obj_Floor);

var instB = instance_create_layer(50, 200, "Instances", obj_Circle);

r = sqrt(power(instA.x-instB.x,2)+power(instA.y-instB.y,2));

var jointA = physics_joint_rope_create(instA, instB, instA.x, instA.y, instB.x, instB.y, r, true);

physics_joint_delete(jointA);


房间在创建的同时joint会被删除,实例A、B不会相互连接

但如果我给obj_Control添加“按下P键事件”,并输入代码


physics_joint_delete(jointA);


在运行后会提示无法读取jointA的变量因此发生错误,我也无法实现“按下P后删除Joint”的目的


___________________________________________

############################################################################################

FATAL ERROR in

action number 1

of Key Press Event for P-key Key

for object obj_Control:

Variable obj_Control.jointA(100009, -2147483648) not set before reading it.

at gml_Object_obj_Control_KeyPress_80 (line 8) - physics_joint_delete(jointA);

############################################################################################

--------------------------------------------------------------------------------------------

stack frame is

gml_Object_obj_Control_KeyPress_80 (line 8)


想要知道出现这种问题的原因是什么,我想要实现“按下P后删除Joint”的目标应该怎么做?

问题2 修改joint参数

与问题1类似,我无法通过在按下按键P事件中添加代码来操纵joint,而如果我在obj_Control的Create代码末尾增使用physics_joint_set_value函数修改joint参数的代码,比如修改Rope joint的最长长度,代码如下:


var instA = instance_create_layer(200, 150, "Instances", obj_Floor);

var instB = instance_create_layer(50, 200, "Instances", obj_Circle);

r = sqrt(power(instA.x-instB.x,2)+power(instA.y-instB.y,2));

var jointA = physics_joint_rope_create(instA, instB, instA.x, instA.y, instB.x, instB.y, r, true);

physics_joint_set_value(jointA, phy_joint_max_length, r+10);


在运行后会发现实例A和实例B没有成功被连接,删除physics_joint_set_value函数后一切正常,想要知道这是什么原因?

加入 indienova

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