运动速度不在状态机中更新

Posted

技术标签:

【中文标题】运动速度不在状态机中更新【英文标题】:movementspeed not updating in a state machine 【发布时间】:2018-12-31 01:44:35 【问题描述】:

这一切都在 STEP 事件中。

我目前正在尝试为一些敌方 AI 创建我的第一个状态机。作为 gml 和 gamemaker studio 2 的新手,我的代码非常基础,因为我不知道如何实现内置函数。

在我的状态之一,即rush状态,敌人应该追赶玩家。我通过创造一些条件来做到这一点,如果玩家在敌人的左边,敌人就会向左跑。如果玩家向右,敌人就会向右跑。这在理论上是我编写的代码,但是当我进入游戏时,有时它会起作用,但随后会痉挛并走另一条路。

如果我的角色在圆圈中,它不会向玩家跑去而是跑开。如果我颠倒条件,这不会改变。

case  behaviour.rush:

    //radius in square
        if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
          
             //direction to face player
             if (behaviourState == behaviour.rush && playerObject.x           >.     warriorx) hsp = -4;
              else if (behaviourState == behaviour.rush &&     
  playerObject.x <= warriorx) hsp = 4;
            x = x + hsp;
         

    if (!point_in_circle(playerObject.x,playerObject.y,x,y,200))
    
        behaviourState = behaviour.idle;    
    

我的完整代码:

image_speed = 1;
vsp = vsp+grv;
Print(behaviourState);
if (hsp > 0) image_xscale = 3; else if (hsp < 0) image_xscale = -3; 

//animation
if (behaviourState == behaviour.idle) sprite_index =     tikiAxeWarriorIdle;
if (hsp == 2 || hsp == -2)sprite_index = tikiAxeWarriorWalk;

if (hsp == 4 || hsp == -4) sprite_index = tikiAxeWarriorRush;

if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
 
   Print("in circle");

Print(hsp);

switch(behaviourState)

    case behaviour.idle:
    
        //stand still
         if (alarm[1] <= 0) alarm[1] = room_speed * 4;

         if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
          
             behaviourState = behaviour.rush;
         
    

    case behaviour.wander:
    
        if (alarm[0] <= 0) alarm[0] = room_speed * 3;

        //move
        if (!place_meeting(x + hsp,y,wallObject)) 
        
            x = x + hsp;
        

        if (place_meeting(x + hsp,y,wallObject))//checking frame before.
           
            hsp = -hsp;
        

        //check for behaviour.rush.
        if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
         
            behaviourState = behaviour.rush;
        
    

    case  behaviour.rush:
    
        //radius in square
        if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
         
            //direction to face player
            if (behaviourState == behaviour.rush && playerObject.x > warriorx) hsp = -4;
            else if (behaviourState == behaviour.rush && playerObject.x <= warriorx) hsp = 4;
            x = x + hsp;
        

        if (!point_in_circle(playerObject.x,playerObject.y,x,y,200))
        
            behaviourState = behaviour.idle;    
        
    
    case behaviour.attack:
    
        //attack.   
        //if player is hit, he dies.
    

预期的结果是敌人“冲”向我的玩家位置,当超过时,面向另一个方向。如果我的玩家离开圈子,它应该会回到空闲状态。

【问题讨论】:

【参考方案1】:

hsp = -hsp 听起来对痉挛非常敏感。并且由于它会影响整个hsp,它也会影响place_meeting(x + hsp,y,wallObject) 部分。 我不马上知道解决方案,但我认为你应该看看那个部分。

我个人也更喜欢将您当前的hsp 拆分为两个变量:方向和速度,其中方向的值是1-1,速度类似于hsp,但返回一个正数价值。然后使用speed * direction 组合它们。 这样,您可以在不考虑方向的情况下计算速度,反之亦然。这也可能解决您当前遇到的冲突。

【讨论】:

【参考方案2】:

使用switch语句,我相信你需要添加“break;”在每个案例之间。

YoYo 文档here 有一些关于 switch 语句的好信息。现在,这可能无法使您的代码完全按照您的希望运行,但它会让您在实现目标时减少一个错误。

链接的相关部分指出:"...在第一个具有正确值的 case 语句之后继续执行,直到遇到 break 语句....break 不是必需的,并且如果没有 break 语句,则执行将继续执行下一个 case 语句的代码"

所以本质上,如果没有 break 语句,代码将从匹配当前值的 case 块开始,然后遍历它下面的所有 case 的代码,直到遇到“break;”。

这是您的代码在使用“break;”时的样子添加到正确的位置。

image_speed = 1;
vsp = vsp+grv;
Print(behaviourState);
if (hsp > 0) image_xscale = 3; else if (hsp < 0) image_xscale = -3; 

//animation
if (behaviourState == behaviour.idle) sprite_index =     tikiAxeWarriorIdle;
if (hsp == 2 || hsp == -2)sprite_index = tikiAxeWarriorWalk;

if (hsp == 4 || hsp == -4) sprite_index = tikiAxeWarriorRush;

if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
 
   Print("in circle");

Print(hsp);

switch(behaviourState)

    case behaviour.idle:
    
        //stand still
         if (alarm[1] <= 0) alarm[1] = room_speed * 4;

         if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
          
             behaviourState = behaviour.rush;
         
    
    break;
    case behaviour.wander:
    
        if (alarm[0] <= 0) alarm[0] = room_speed * 3;

        //move
        if (!place_meeting(x + hsp,y,wallObject)) 
        
            x = x + hsp;
        

        if (place_meeting(x + hsp,y,wallObject))//checking frame before.
           
            hsp = -hsp;
        

        //check for behaviour.rush.
        if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
         
            behaviourState = behaviour.rush;
        
    
    break;
    case  behaviour.rush:
    
        //radius in square
        if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
         
            //direction to face player
            if (behaviourState == behaviour.rush && playerObject.x > warriorx) hsp = -4;
            else if (behaviourState == behaviour.rush && playerObject.x <= warriorx) hsp = 4;
            x = x + hsp;
        

        if (!point_in_circle(playerObject.x,playerObject.y,x,y,200))
        
            behaviourState = behaviour.idle;    
        
    
    break;
    case behaviour.attack:
    
        //attack.   
        //if player is hit, he dies.
    
    break;

希望这会有所帮助!

另外,一个快速提示! 我在您的代码中注意到的一件事是您多次重复几个表达式。为了便于阅读,我建议尽可能将它们分配给变量。例如:

var in_circle = point_in_circle(playerObject.x,playerObject.y,x,y,200);

if in_circle 


if !in_circle 


【讨论】:

虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 Read this. 有道理!有机会我会尽快更新答案! 我会等待那一刻?

以上是关于运动速度不在状态机中更新的主要内容,如果未能解决你的问题,请参考以下文章

如何在反应中保持 Xstate 状态机中的状态?

verilog三段式状态机中的问题,第三个always

Unity/C#:如何在动画状态机中禁用组件

Verilog 三段式状态机中第三个always块的问题

在bgp 状态机中,哪几个状态是在建立了tcp 连接之后发生的

UML之状态机图