这期视频讲了如何使用 用户自定义事件实现状态机。
由于实现功能使用了大量的 if-else 语句,整个 step 事件显得特别乱,而other事件里的 user event 事件可以解决这个问题。
/// @description Move towards the player event_user(state_);
在 step 事件里调用 user event 事件,然后把相关的代码写入 user event 事件里即可。
// states MOVEMENT_ = 0; ATTACK_ = 1; HIT_ = 2; state_ = MOVEMENT_;
在 create 事件里添加如上代码,用于切换状态,下面逐一讲解 MOVEMENT_ , ATTACK_, HIT_三个状态。
/// @description Movement State // Move force var dir = point_direction(x, y, o_player.x, o_player.y); hspeed_ = lengthdir_x(speed_, dir); vspeed_ = lengthdir_y(speed_, dir); move(); // Push force move_push_(); if !place_meeting(x, y, o_enemy) { hspeed_push_ = lerp(hspeed_push_, 0, .1); vspeed_push_ = lerp(vspeed_push_, 0, .1); } // Death if health_ < 0 { instance_destroy(); } if distance_to_object(o_player) < 48 { state_ = ATTACK_; }
MOVEMENT_ 事件就是我们之前写过的移动代码,不做过多讲解。当与玩家的距离小于48时,切换为 ATTACK_ 状态。
/// @description Attack State if distance_to_object(o_player) >= 48 { state_ = MOVEMENT_; }
ATTACK_ 状态还没有完善(具体内容在下一节),当距离大于等于48时,切换为 MOVEMENT_ 状态,以便再次移动。
/// @description Take damage // Push force move_push_(); hspeed_push_ = lerp(hspeed_push_, 0, .1); vspeed_push_ = lerp(vspeed_push_, 0, .1); if point_distance(0, 0, hspeed_push_, vspeed_push_) < 1 { state_ = MOVEMENT_; }
HIT_ 事件使得敌人在被击中时产生击退效果,这个事件要在与子弹的碰撞事件中调用。
state_ = HIT_; var dir = other.direction; hspeed_push_ = lengthdir_x(8, dir); vspeed_push_ = lengthdir_y(8, dir);
dir 的值直接调用子弹的即可,然后做类似之前敌人互相碰撞的处理。
值得一提的是 HIT_ 事件里,切换为 MOVEMENT_ 状态的判断条件很奇葩,效果是当 hspeed_push_ 和 vspeed_push_ 小于1,触发语句。
经过这样的处理后,我们可以直接在对象的窗口里定义和脚本差不多的东西,显得结构较为紧凑,而不是之前那样分散。