过年摸了一个假期的鱼,是时候写一写近期慢吞吞地学习的新内容了:
在Dev_log_1中,我曾经很粗浅地通过检测按键情况来直接修改目标的x,y坐标值,藉此来完成人物移动。但是随后,当我需要实现目标和房间的图块之间的碰撞时,我发现这样判定人物移动的逻辑会使得图块碰撞的检验十分冗杂。
因此,后来我参考了许多其他作者做出的案例,我决定对人物移动的结算机制进行优化:
首先,生成两个变量: hspd 和 vspd (即Horizontal Speed和Vertical Speed)
hspd = (keyboard_check(vk_right) - keyboard_check(vk_left)) * 4;
vspd = (keyboard_check(vk_down) - keyboard_check(vk_up)) * 4;
if (hspd > 0)
{
sprite_index = spr_player_right;
image_speed = 0.5;
}
if (hspd < 0)
{
sprite_index = spr_player_left;
image_speed = 0.5;
}
if (vspd > 0)
{
sprite_index = spr_player_down;
image_speed = 0.5;
}
if (vspd < 0)
{
sprite_index = spr_player_up;
image_speed = 0.5;
}
x += hspd ;
y += vspd ;
//两个变量都为0时,不播放移动动画
if !((hspd)
|| (vspd)
|| (-hspd)
|| (-vspd))
{
image_speed = 0;
}
使用这两个新变量来控制人物移动和碰撞判定,可以使得每个if函数内无需单独判定目标x,y值的变化。并且后续的碰撞判定后,如需使目标无法穿透某些图块,只需在满足条件时将这两个变量归0即可。
然后,我新建了一个Layer,命名为Layer_CMusk(Collision Musk)。
这个图层使用的tile仅有一个纯色的图块:
CMusk使用的图块素材
它的存在意义是将整个房间里所有涉及到碰撞的图块收束在这个Layer里,使用时直接将这个CMusk的深度调低,在所有可见的图层下,然后将这个紫色的图块覆盖在需要判定的其他图层图块上即刻,例如:
CMusk的使用,判定目标与墙壁贴图的碰撞
用CMusk覆盖墙壁贴图
当然,房间内的不可穿越障碍物亦可将CMusk覆盖在其上,这样未来假如我加入了新的Layer用来放屋内装饰物,其他一些障碍物,即可无需将目标分别与不同的layer来判断碰撞,只需与CMusk判断即可。
然后检测目标与图块之间是否发生碰撞,我自定义了一个脚本tile_meeting:
var obj_top ,obj_bot ,obj_left, obj_right ,collide_map ,meeting;
obj_top = argument0;
obj_bot = argument1;
obj_left = argument2;
obj_right = argument3;
collide_map = layer_get_id(argument4);
meeting = tilemap_get_at_pixel(collide_map ,obj_right ,obj_top)
||
tilemap_get_at_pixel(collide_map ,obj_right ,obj_bot)
||
tilemap_get_at_pixel(collide_map ,obj_left ,obj_top)
||
tilemap_get_at_pixel(collide_map ,obj_left ,obj_bot);
return(meeting);
值得一提的是GMS2中函数引用外部变量,需要先定义Argument,假设我定义了一个叫做A的函数,需引用两个外部变量,则其调用时应该为A(Argument0,Argument1),这个脚本显然判断碰撞的依据是目标贴图的四个顶点是否在发生移动后接触到了目标图块。所以当目标素材的贴图大小比图块大时,图块可能会从目标中间穿过去。我使用的人物贴图是3248的尺寸,图块默认尺寸4848,因此不会出现这种情况。
后面的事就很容易理解了:
if tile_meeting(bbox_top,bbox_bottom,bbox_left+hspd,bbox_right+hspd,"Layer_CMusk")
{
hspd=0;
}
if tile_meeting(bbox_top+vspd,bbox_bottom+vspd,bbox_left,bbox_right,"Layer_CMusk")
{
vspd=0;
}
碰撞检定为真时,速度改为0。
此外,多数时候我不希望目标可以穿过没有墙壁的房间边缘到达房间外面,我希望确保目标总是在房间内,这时可以将CMusk围绕着房间途一周,亦可使用clamp函数来确保x,y的范围:
x=clamp(x,sprite_width,room_width);
y=clamp(y,sprite_height,room_height-sprite_height);
网友评论