主世界战斗攻击?

我确实让它成功运行了!现在,我之前提到的所有四个动作都能基本正常运作。

关于这一系列事件,我唯一剩下的问题——回到 A-冲刺指令——我假设我可以将防止护盾指令在冲刺过程中生成在玩家体内的代码,应用到 Z-攻击上吗?Z-攻击在玩家快速移动时也会严重滞后。唯一的区别是,Z-攻击需要使攻击碰撞体从玩家内部明显向前移动。

是的,思路相同,只是去掉了那一个图块的偏移量。直接在方块事件中读取玩家的位置和方向,在与方向匹配的图块上放置碰撞体,然后让现有的“向前一步”指令执行可见的移动:

◆控制开关: #0181 攻击中 = 开
◆播放音效: Blow1
◆控制变量: AtkX = 玩家地图X坐标
◆控制变量: AtkY = 玩家地图Y坐标
◆控制变量: AtkDir = 玩家朝向
◆条件分支: AtkDir = 2
  ◆设置事件位置: 攻击碰撞体, ({AtkX},{AtkY}), 下
◆分支结束
◆条件分支: AtkDir = 4
  ◆设置事件位置: 攻击碰撞体, ({AtkX},{AtkY}), 左
◆分支结束
◆条件分支: AtkDir = 6
  ◆设置事件位置: 攻击碰撞体, ({AtkX},{AtkY}), 右
◆分支结束
◆条件分支: AtkDir = 8
  ◆设置事件位置: 攻击碰撞体, ({AtkX},{AtkY}), 上
◆分支结束
◆设置移动路线: 攻击碰撞体 (跳过, 等待)
  : 透明关闭
  : 图像: MH VitalAttacks1(2)
  : 速度: 6
  : 向前一步

与你现有的做法相比,有两点变化。位置信息直接从当前的“玩家地图X”和“玩家地图Y”读取,而不是使用BPlayer变量;朝向信息则来自“设置事件位置”指令中的朝向字段,而不是等待碰撞体自身的转向逻辑(之前导致了一帧的延迟)。在运行过程中,“玩家地图X”和“玩家地图Y”已经是玩家即将踏入的图块坐标,因此在最高速度下,拳头的起始位置会略微超前于角色精灵,而不是滞后,这正是我们希望出现的偏差方向。

它确实还是稍微落后于玩家一点,但实际上我觉得我无所谓。它缩短了射程,并且优先确保在启用加速时更加谨慎——如果我之后不喜欢这样,我会回来反馈,如果我自己搞不定怎么修复的话。就目前而言,我对这个效果很满意。

我打算看看能不能把这里的代码改造一下,让护盾也跟随玩家滑动,而不是瞬间出现在玩家面前。

成功了!不过有个问题:我希望敌人被护盾持续弹开,但敌人只被弹开一次后,护盾就好像失去了碰撞检测,敌人可以直接穿过去。你知道这是为什么吗?

我还发现另一件事:在尝试让 S-ram 与敌人事件互动时,它根本无法造成伤害。我理解原因;敌人事件的代码设定为在与攻击碰撞接触时受到伤害,但我不确定如何在 ATTACKING 开启、ATTACK TYPE=2 且玩家与其接触时,让敌人事件受到伤害。

护盾之所以只反弹一次,是因为有自开关 B 的防御机制。它在受到攻击后开启,并且只有在“正在攻击”状态关闭时的 Else(否则)分支中才会清除。而在 X 倒下期间,“正在攻击”状态一直为 ON,所以第一次反弹后,敌人会跳过命中判定,直到你松开按键。能够穿透敌人也是同样的原理。攻击碰撞设置了“穿透”属性,因此它从未物理阻挡过任何东西,反弹是唯一阻止敌人的机制。

既然护盾应该捕捉每一次接触,我建议只对其他攻击类型设置 B。在“攻击类型 = 1”条件上勾选“创建 Else 分支”,并将 B 行移入其中:

◆条件分支:攻击类型 = 1
  (你的反弹逻辑,保持不变)
:否则
  ◆控制自开关:B = ON
◆分支结束

移除护盾的防御应该是安全的,因为反弹路线中设置了“等待”。循环无法在后退步骤完成前再次检查,而到那时敌人已经离开了护盾所在的格子。

对于冲撞(ram),碰撞检测停留在冲撞开始的位置,因为其跟随逻辑仅在“正在攻击”状态为 OFF 时运行。玩家也无法走进敌人的格子,因此敌人从未与任何物体对齐。如果在攻击类型为 2 时,让敌人检查玩家前方的格子会怎样?在你的两个“命中 X”和“命中 Y”行之后立即添加以下内容:

◆条件分支:攻击类型 = 2
  ◆控制变量:命中 X = 玩家地图 X
  ◆控制变量:命中 Y = 玩家地图 Y
  ◆控制变量:命中方向 = 玩家方向
  ◆条件分支:命中方向 = 2
    ◆控制变量:命中 Y += 1
  ◆分支结束
  ◆条件分支:命中方向 = 4
    ◆控制变量:命中 X -= 1
  ◆分支结束
  ◆条件分支:命中方向 = 6
    ◆控制变量:命中 X += 1
  ◆分支结束
  ◆条件分支:命中方向 = 8
    ◆控制变量:命中 Y -= 1
  ◆分支结束
◆分支结束

“命中方向”是另一个自变量。下面的比较以及 B 防御保持原样,因此冲撞每对每个敌人只造成一次命中。冲撞的伤害和击退效果应放在你其他逻辑旁边的“攻击类型 = 2”分支中。

我写了下面的代码,但它不起作用。无论玩家是否接触到敌人,都不会造成伤害或击退效果。有时玩家完全无法移动,这让我觉得两个事件都在检查它们所在图块前方的碰撞,并因此提前终止了执行。

进展非常顺利。自从你帮忙打下了基础后,我已经能够完全独立完成几次额外的攻击了,对此我感激不尽。我想很快就能完成了。

我尝试添加一个“攻击类型 3”,让敌人在原地冻结,以便玩家持续对其攻击,但仅当玩家停止攻击时才结束。然而,就像护盾一样,敌人只受到一次攻击,然后继续前行。有什么想法吗?

更新:我了解到,在这个代码块中添加“否则:开启事件自变量 B”命令实际上会破坏护盾持续弹开的能力,这让我感到非常困惑。

遇到了另一个问题。玩家可以使用的一种潜在攻击是对场上的每个敌人造成一次弱伤害。

然而,该攻击会瞬间杀死所有敌人。我认为这是因为代码每帧都在运行,导致敌人每帧都受到伤害,但我无法找出停止这种情况的方法。

这是我目前的代码。有什么想法吗?

敌人代码。如你所见,它被放在了检查攻击碰撞的代码之外,因为在这种攻击中不需要它。

玩家攻击代码。ATKdir 相关内容在这里是多余的,可以忽略。

(另外,带有图片的视觉效果不会超出屏幕范围)

  1. 从缩进来看,ATTACK TYPE = 2 的代码块似乎被错误地放到了你其他攻击类型旁边的命中检测逻辑内部。该检测逻辑是与“攻击碰撞体(Attack collision)”进行比较的,而该碰撞体停留在冲锋开始时的位置,因此条件永远无法通过,导致其中的代码(包括新的位置设置行)都不会执行。这部分逻辑需要拆分为两部分。位置设置部分(三个控制变量和四个命中方向分支)应放在读取攻击碰撞体 X 和 Y 值的两行代码之后、If: SV: AtkCol X = SV: My X 判断之前。而关于 HP、快照(snap)和击退的处理,则应像其他攻击类型一样,放在命中检测内部独立的 ATTACK TYPE = 2 分支中。

玩家无法移动是因为敌人阻挡了步骤执行。事件(Events)会阻挡玩家,如果冲锋开始时正前方有一个事件,Skip 会迅速跳过步骤,导致玩家原地不动。

  1. 在 ATTACK TYPE 分支后的每一个 Else 都会捕获所有其他类型。因此,我上一篇文章中类型 1 的 Else B ON 也会在类型 3 命中时触发,这就是为什么它只被命中一次的原因。你在类型 3 中添加的 Else 会在盾牌命中时触发,这正是导致偏转(deflect)失效的原因。我建议移除这两个 Else,在所有类型分支之后、仍处于命中检测内部的地方,当攻击既不是类型 1 也不是类型 3 时,统一设置 B 开关为 ON:
◆If: ATTACK TYPE ≠ 1
  ◆If: ATTACK TYPE ≠ 3
    ◆Control Self Switch: B = ON
  ◆End
◆End
  1. 即死效果来源于敌人 Else 分支中的“设置玩家移动路线”。一个事件同时只能持有一条强制路线,因此每次敌人受击都会用新的 30 帧等待路线替换攻击的 1 帧等待路线。攻击的“等待完成”永远无法结束,ATTACK TYPE 始终保持在 4,导致每次循环敌人都会持续受到 25 点伤害直到死亡。环境攻击变量(Ambient Attack variable)只是在每次循环时在 0 和 1 之间切换,从而间隔伤害,但并不能阻止伤害持续发生。

B 开关已经处理了“仅一次”的逻辑,所以我建议移除环境攻击变量和玩家路线,像其他攻击一样设置 B 开关:

◆If: ATTACK TYPE = 4
  ◆Control Variables: #0189 SV: This event HP -= 25
  ◆Play SE: Blow1 (90, 150, 0)
  ◆Set Movement Route: This Event
    : Blend Mode: Additive
    : Wait: 30 frames
    : Blend Mode: Normal
  ◆Control Self Switch: B = ON
◆End

这部分代码需要保留在“自身开关 B 为 OFF”的检测内部,从缩进来看它目前似乎就在那里。

移动图片(Move Picture)位于那个卡住的等待之后,所以图片也是延迟开始显示的。它们的目的地也是 (0,0),即它们最初显示的位置,因此它们会在原地淡出而不是滑动。如果你希望它们离开屏幕,请将移动图片中的 X 或 Y 设置为超出屏幕边缘的位置。

由于这些都涉及敌人的同一部分循环逻辑,以下是结合上述三项修改后,整个命中检测部分预期的样子。括号内的内容是你现有的、未更改的代码:

◆Loop
  (your attack logic, unchanged)
  ◆If: ATTACKING is ON
    ◆If: Self Switch B is OFF
      ◆Control Variables: #0192 SV: AtkCol X = Map X of Attack collision
      ◆Control Variables: #0193 SV: AtkCol Y = Map Y of Attack collision
      ◆If: ATTACK TYPE = 2
        ◆Control Variables: #0192 SV: AtkCol X = Map X of Player
        ◆Control Variables: #0193 SV: AtkCol Y = Map Y of Player
        ◆Control Variables: #0221 Hit Dir = Direction of Player
        ◆If: Hit Dir = 2
          ◆Control Variables: #0193 SV: AtkCol Y += 1
        ◆End
        ◆If: Hit Dir = 4
          ◆Control Variables: #0192 SV: AtkCol X -= 1
        ◆End
        ◆If: Hit Dir = 6
          ◆Control Variables: #0192 SV: AtkCol X += 1
        ◆End
        ◆If: Hit Dir = 8
          ◆Control Variables: #0193 SV: AtkCol Y -= 1
        ◆End
      ◆End
      ◆Control Variables: #0194 SV: My X = Map X of This Event
      ◆Control Variables: #0195 SV: My Y = Map Y of This Event
      ◆If: ATTACK TYPE = 4
        ◆Control Variables: #0189 SV: This event HP -= 25
        ◆Play SE: Blow1 (90, 150, 0)
        ◆Set Movement Route: This Event
          : Blend Mode: Additive
          : Wait: 30 frames
          : Blend Mode: Normal
        ◆Control Self Switch: B = ON
      ◆End
      ◆If: SV: AtkCol X = SV: My X
        ◆If: SV: AtkCol Y = SV: My Y
          ◆If: ATTACK TYPE = 0
            (your punch hit, unchanged)
          ◆End
          ◆If: ATTACK TYPE = 1
            (your shield bounce, no Else)
          ◆End
          ◆If: ATTACK TYPE = 2
            ◆Control Variables: #0189 SV: This event HP -= 25
            ◆Control Variables: #0194 SV: My X = Math.round(this.character(0)._realX)
            ◆Control Variables: #0195 SV: My Y = Math.round(this.character(0)._realY)
            ◆Set Event Location: This Event, ({SV: My X},{SV: My Y})
            ◆Set Movement Route: This Event (Skip, Wait)
              (your knockback route, unchanged)
          ◆End
          ◆If: ATTACK TYPE = 3
            (your freeze hit, no Else)
          ◆End
          ◆If: ATTACK TYPE ≠ 1
            ◆If: ATTACK TYPE ≠ 3
              ◆Control Self Switch: B = ON
            ◆End
          ◆End
        ◆End
      ◆End
    ◆End
  : Else
    ◆Control Self Switch: B = OFF
  ◆End
  (your HP 0 check and Break Loop, unchanged)
◆Repeat Above

哇,这真的非常有帮助!我之前担心细节太多会漏掉什么,非常感谢。我已经全部实现了,目前的情况如下:

1:Ram 仍然无法对敌人造成伤害。我认为可能是玩家在接触到敌人之前就被检测前方事件的逻辑阻止了。我进行了相当彻底的测试,它确实从未造成伤害。

2:攻击类型 3 肯定更接近我想要的效果,敌人在受到伤害时会暂停,但当暂停指令结束后,它们有机会再次移动。有什么方法可以阻止这种情况吗?我希望在玩家使用特定招式期间,敌人能一直卡在玩家面前。

3:"每次敌人攻击"这个功能也差不多了,但如果玩家不小心多次按下 Z 键来触发招式,视觉特效会一直停留在屏幕上,并且玩家必须按下方向键才能清除特效并恢复操作。

这个系统已经非常接近完成了,我真的无法用言语表达我的感谢。

  1. 在我猜测移动逻辑之前,现在 RAM 设置的 ATTACK TYPE 值是多少?当你通过 MOVING ATTACK HANDLER 进行连线时,你将其设置为 3,而敌方事件块是与 2 进行比较的。如果情况仍然如此,那么位置判断行永远不会执行,敌方会一直检查停泊状态的攻击碰撞。

如果它已经是 2 了,你能再贴一次敌方事件块吗?我想看到的是,三个控制变量和四个 Hit Dir 分支是位于 If: SV: AtkCol X = SV: My X 之上,还是仍然包含在它内部。

快速判断哪一半失败的方法是:在 If: ATTACK TYPE = 2 的位置块内部暂时放置一个播放音效(Play SE)指令。如果在 RAM 期间你听到了音效,说明敌方读取了正确的图块,问题是下方的比较逻辑有误。如果没听到,说明敌方根本没执行到那一步,问题出在类型值或事件块的位置上。

  1. 与盾牌导致玩家冻结的技巧相同。一个重复的强制移动路线会让角色静止不动,并阻止其自主移动,只要路线重复执行就会一直有效。在类型 3 的攻击中设置它,并使用第二个自我开关(Self Switch)来标记该敌方处于“被控制”状态,然后在攻击结束时释放一次。你可以选择任意未使用的字母,我这里用 C 表示。

  2. 将触发条件设为 ATTACKING 为 OFF,这样在第一次攻击仍在运行时,第二次按键会被忽略。这个逻辑要放在攻击的公共事件(Common Event)中,而不是敌方事件中:

◆If: ATTACKING is OFF
  ◆If: Script: Input.isTriggered("ok")
    (your type 4 attack, unchanged)
  ◆End
◆End

箭头键部分让我觉得第二次按键是在第一个路线仍在运行时强制为玩家设置了一个路线,这又回到了“一次只能执行一个路线”的问题。TurnInPlace 只会干扰来自并行事件的玩家路线。如果守卫状态没有清除它,就把这个攻击像你对 RAM 做的那样移入自动执行(Autorun)事件中,它的表现就会和 RAM 一样。

以下是包含所有内容的完整敌方命中部分。括号内的内容是你现有的内容,未作更改:

◆Loop
  (your attack logic, unchanged)
  ◆If: ATTACKING is ON
    ◆If: Self Switch B is OFF
      ◆Control Variables: #0192 SV: AtkCol X = Map X of Attack collision
      ◆Control Variables: #0193 SV: AtkCol Y = Map Y of Attack collision
      ◆If: ATTACK TYPE = 2
        ◆Control Variables: #0192 SV: AtkCol X = Map X of Player
        ◆Control Variables: #0193 SV: AtkCol Y = Map Y of Player
        ◆Control Variables: #0221 Hit Dir = Direction of Player
        ◆If: Hit Dir = 2
          ◆Control Variables: #0193 SV: AtkCol Y += 1
        ◆End
        ◆If: Hit Dir = 4
          ◆Control Variables: #0192 SV: AtkCol X -= 1
        ◆End
        ◆If: Hit Dir = 6
          ◆Control Variables: #0192 SV: AtkCol X += 1
        ◆End
        ◆If: Hit Dir = 8
          ◆Control Variables: #0193 SV: AtkCol Y -= 1
        ◆End
      ◆End
      ◆Control Variables: #0194 SV: My X = Map X of This Event
      ◆Control Variables: #0195 SV: My Y = Map Y of This Event
      ◆If: ATTACK TYPE = 4
        ◆Control Variables: #0189 SV: This event HP -= 25
        ◆Play SE: Blow1 (90, 150, 0)
        ◆Set Movement Route: This Event
          : Blend Mode: Additive
          : Wait: 30 frames
          : Blend Mode: Normal
        ◆Control Self Switch: B = ON
      ◆End
      ◆If: SV: AtkCol X = SV: My X
        ◆If: SV: AtkCol Y = SV: My Y
          ◆If: ATTACK TYPE = 0
            (your punch hit, unchanged)
          ◆End
          ◆If: ATTACK TYPE = 1
            (your shield bounce, no Else)
          ◆End
          ◆If: ATTACK TYPE = 2
            ◆Control Variables: #0189 SV: This event HP -= 25
            ◆Control Variables: #0194 SV: My X = Math.round(this.character(0)._realX)
            ◆Control Variables: #0195 SV: My Y = Math.round(this.character(0)._realY)
            ◆Set Event Location: This Event, ({SV: My X},{SV: My Y})
            ◆Set Movement Route: This Event (Skip, Wait)
              (your knockback route, unchanged)
          ◆End
          ◆If: ATTACK TYPE = 3
            (your freeze hit damage, unchanged)
            ◆Set Movement Route: This Event (Repeat)
              : Wait: 1 frame
            ◆Control Self Switch: C = ON
          ◆End
          ◆If: ATTACK TYPE ≠ 1
            ◆If: ATTACK TYPE ≠ 3
              ◆Control Self Switch: B = ON
            ◆End
          ◆End
        ◆End
      ◆End
    ◆End
  : Else
    ◆Control Self Switch: B = OFF
    ◆If: Self Switch C is ON
      ◆Set Movement Route: This Event
        : Wait: 1 frame
      ◆Control Self Switch: C = OFF
    ◆End
  ◆End
  (your HP 0 check and Break Loop, unchanged)
◆Repeat Above

在类型 3 的路线中,勾选了“重复移动”(Repeat Movement),并且关闭了“等待完成”(Wait for Completion)。下方的释放路线两个选项都关闭,所以它只运行一帧,然后结束,敌方恢复正常。有一点需要注意:任何强制施加给该敌方的其他路线都会替换冻结效果,所以如果击退动作落在被控制的敌方身上,会提前使其恢复自由。

1-你知道我说过那些小事总是让我抓狂吧?确实如此——RAM完全没有设置攻击类型。我将其设为2,现在RAM运行完美了。谢谢,哎呀。

3-“攻击所有敌人”现在完全按照我的预期工作了!

不过,第2点,“敌人在受到多次攻击时必须保持静止”的事件仍有问题。当玩家对敌人造成类型3伤害时,敌人会受伤并闪烁一次,然后变得完全静止,无法移动或再受到伤害,即使攻击碰撞体仍然覆盖在它身上,或者它受到其他攻击。

(自我开关D是我剩下的唯一开关,所以已将其更改为那个。)

很高兴第1和第3点已经解决了!

关于第2点,如果它停止响应所有操作,而不仅仅是攻击碰撞,我认为循环本身已经停止运行,而不是类型3分支中的某个东西误触发。敌方全体攻击根本不检查攻击碰撞,所以如果你尝试过这一点,只要循环仍在运行,它就应该能命中。我的猜测是它卡在了某个永远无法完成的等待上。

我没看到的部分是循环顶部的攻击逻辑。里面是否有勾选了“等待”的“设置移动路线:本事件”,特别是带有“步数”且“无法移动时跳过”的类型?类型3的命中总是将敌人固定在玩家正前方,所以我怀疑它在卡住时发动攻击,试图移动到玩家所在的格子,然后无限重试该步骤。这可以解释为什么只有类型3会出现这种情况,因为它是唯一将敌人保持在玩家旁边的命中方式。

如果没有发现类似的情况,这里有一种方法可以找到它停止的位置。地图上只放一个敌人,在循环中插入几个这样的检查点,按顺序编号,一个在顶部附近,一个在攻击逻辑之后,一个在命中部分之后,一个在“重复以上”之前:

◆控制变量:#0XXX 循环测试 = 1

进行试玩测试,命中类型3,等待它变得无反应,然后按F9并检查“循环测试”。你看到的数字是它通过的最后一个检查点,所以它卡住的命令就在那个命令和下一个命令之间。

这是带有检查点和你的D开关的整个循环。括号中的部分是您的现有内容,未更改:

◆循环
  ◆控制变量:#0XXX 循环测试 = 1
  (你的攻击逻辑,未更改)
  ◆控制变量:#0XXX 循环测试 = 2
  ◆条件分支:攻击中 为 ON
    ◆条件分支:自身开关 B 为 OFF
      ◆控制变量:#0192 变量: 攻击碰撞 X = 攻击碰撞的地图 X
      ◆控制变量:#0193 变量: 攻击碰撞 Y = 攻击碰撞的地图 Y
      ◆条件分支:攻击类型 = 2
        ◆控制变量:#0192 变量: 攻击碰撞 X = 玩家的地图 X
        ◆控制变量:#0193 变量: 攻击碰撞 Y = 玩家的地图 Y
        ◆控制变量:#0221 命中方向 = 玩家的方向
        ◆条件分支:命中方向 = 2
          ◆控制变量:#0193 变量: 攻击碰撞 Y += 1
        ◆结束
        ◆条件分支:命中方向 = 4
          ◆控制变量:#0192 变量: 攻击碰撞 X -= 1
        ◆结束
        ◆条件分支:命中方向 = 6
          ◆控制变量:#0192 变量: 攻击碰撞 X += 1
        ◆结束
        ◆条件分支:命中方向 = 8
          ◆控制变量:#0193 变量: 攻击碰撞 Y -= 1
        ◆结束
      ◆结束
      ◆控制变量:#0194 变量: 我的 X = 本事件的地图 X
      ◆控制变量:#0195 变量: 我的 Y = 本事件的地图 Y
      ◆条件分支:攻击类型 = 4
        ◆控制变量:#0189 变量: 本事件 HP -= 25
        ◆播放音效:吹击1 (90, 150, 0)
        ◆设置移动路线:本事件
          : 混合模式:叠加
          : 等待:30帧
          : 混合模式:正常
        ◆控制自身开关:B = ON
      ◆结束
      ◆条件分支:变量: 攻击碰撞 X = 变量: 我的 X
        ◆条件分支:变量: 攻击碰撞 Y = 变量: 我的 Y
          ◆条件分支:攻击类型 = 0
            (你的拳击命中,未更改)
          ◆结束
          ◆条件分支:攻击类型 = 1
            (你的盾牌反弹,无 Else)
          ◆结束
          ◆条件分支:攻击类型 = 2
            ◆控制变量:#0189 变量: 本事件 HP -= 25
            ◆控制变量:#0194 变量: 我的 X = Math.round(this.character(0)._realX)
            ◆控制变量:#0195 变量: 我的 Y = Math.round(this.character(0)._realY)
            ◆设置事件位置:本事件, ({变量: 我的 X},{变量: 我的 Y})
            ◆设置移动路线:本事件 (跳过, 等待)
              (你的击退路线,未更改)
          ◆结束
          ◆条件分支:攻击类型 = 3
            ◆公共事件:伤害音效
            ◆控制变量:#0189 变量: 本事件 HP -= 25
            ◆设置移动路线:本事件 (等待)
              : 混合模式:叠加
              : 等待:30帧
              : 混合模式:正常
            ◆设置移动路线:本事件 (重复)
              : 等待:1帧
            ◆控制自身开关:D = ON
          ◆结束
          ◆条件分支:攻击类型 ≠ 1
            ◆条件分支:攻击类型 ≠ 3
              ◆控制自身开关:B = ON
            ◆结束
          ◆结束
        ◆结束
      ◆结束
    ◆结束
  : 否则
    ◆控制自身开关:B = OFF
    ◆条件分支:自身开关 D 为 ON
      ◆设置移动路线:本事件
        : 等待:1帧
      ◆控制自身开关:D = OFF
    ◆结束
  ◆结束
  ◆控制变量:#0XXX 循环测试 = 3
  (你的 HP 0 检查和跳出循环,未更改)
  ◆控制变量:#0XXX 循环测试 = 4
◆重复以上

一旦找到它,那四个“循环测试”行就可以移除了。

它在第 6 行停止,这是整个敌人事件中设置的最后一个变量。它 literally 是整页代码的最后一行。

(如果这有帮助的话,这些行并没有在循环命令中运行,只是告诉它如何赋值的代码位于自我开关条件分支内,并且该开关在完成自身设置后会自行开启,这样敌人就不会再次引用它。)

很好,这样范围缩小了很多。如果每次循环页面都能执行到最后一行,说明没有卡住。由于 ATTACKING 检查的 ON 分支负责造成伤害,而 Else 分支负责解除冻结,我怀疑在类型 3 命中后,整个代码块的两边分支是否都没有被执行到。

有两个问题。首先,顶部的 If: ATTACKING is ON 是位于页面的最顶层,还是嵌套在另一个分支中(比如你设置中的自开关分支或攻击逻辑中的某个部分)?从页面顶部到那一行的截图可以显示这一点。其次,DAMAGE SFX 里面是什么?这是我在类型 3 分支中尚未看到的部分。

为了查看一次循环实际执行到了多深,这里有一个相同思路的检查点,位于下一层,使用第二个变量,这样你的 Loop Test 行可以保持在原位。将 Hit Test 设置为 0 作为页面的第一行,然后将 1 设置为 If: ATTACKING is ON 内部的第一个动作,将 2 设置为 If: Self Switch B is OFF 内部的第一个动作,将 3 设置为 SV: AtkCol Y = SV: My Y 匹配内部的第一个动作,将 9 设置为 Else 的第一个动作。让敌人处于静止状态,走上前并按住盾牌(因为按住 X 时 ATTACKING 会保持为 ON),然后在仍然按住 X 的情况下按下 F9。

如果 Hit Test 为 0 且 Loop Test 为 6,表示循环结束且未触及 ATTACKING 检查的任何一边,说明上面的某些内容绕过了它。1 表示 B 卡在 ON。2 表示 B 正常但位置比较不匹配。3 表示完全进入且类型 3 分支本身有问题。9 表示将 ATTACKING 读取为 OFF 并运行了释放逻辑,这将指向释放路径。

以下是包含 Hit Test 行的整个命中部分。由于没有 Loop 命令,我已从列表中删除了 Loop 和 Repeat Above,因为并行重启会自动完成这项工作。括号内的部分是你现有的内容,未作更改:

◆控制变量: #0XXX Hit Test = 0
(你的设置分支和攻击逻辑,未更改)
◆如果: ATTACKING 为 ON
  ◆控制变量: #0XXX Hit Test = 1
  ◆如果: 自开关 B 为 OFF
    ◆控制变量: #0XXX Hit Test = 2
    ◆控制变量: #0192 SV: AtkCol X = 攻击碰撞的地图 X
    ◆控制变量: #0193 SV: AtkCol Y = 攻击碰撞的地图 Y
    ◆如果: ATTACK TYPE = 2
      ◆控制变量: #0192 SV: AtkCol X = 玩家地图 X
      ◆控制变量: #0193 SV: AtkCol Y = 玩家地图 Y
      ◆控制变量: #0221 Hit Dir = 玩家方向
      ◆如果: Hit Dir = 2
        ◆控制变量: #0193 SV: AtkCol Y += 1
      ◆结束
      ◆如果: Hit Dir = 4
        ◆控制变量: #0192 SV: AtkCol X -= 1
      ◆结束
      ◆如果: Hit Dir = 6
        ◆控制变量: #0192 SV: AtkCol X += 1
      ◆结束
      ◆如果: Hit Dir = 8
        ◆控制变量: #0193 SV: AtkCol Y -= 1
      ◆结束
    ◆结束
    ◆控制变量: #0194 SV: My X = 本事件的地图 X
    ◆控制变量: #0195 SV: My Y = 本事件的地图 Y
    ◆如果: ATTACK TYPE = 4
      ◆控制变量: #0189 SV: 本事件 HP -= 25
      ◆播放音效: Blow1 (90, 150, 0)
      ◆设置移动路线: 本事件
        : 混合模式: 加法
        : 等待: 30 帧
        : 混合模式: 正常
      ◆控制自开关: B = ON
    ◆结束
    ◆如果: SV: AtkCol X = SV: My X
      ◆如果: SV: AtkCol Y = SV: My Y
        ◆控制变量: #0XXX Hit Test = 3
        ◆如果: ATTACK TYPE = 0
          (你的拳击命中,未更改)
        ◆结束
        ◆如果: ATTACK TYPE = 1
          (你的盾牌反弹,无 Else)
        ◆结束
        ◆如果: ATTACK TYPE = 2
          ◆控制变量: #0189 SV: 本事件 HP -= 25
          ◆控制变量: #0194 SV: My X = Math.round(this.character(0)._realX)
          ◆控制变量: #0195 SV: My Y = Math.round(this.character(0)._realY)
          ◆设置事件位置: 本事件, ({SV: My X},{SV: My Y})
          ◆设置移动路线: 本事件 (跳过, 等待)
            (你的击退路线,未更改)
        ◆结束
        ◆如果: ATTACK TYPE = 3
          ◆公共事件: DAMAGE SFX
          ◆控制变量: #0189 SV: 本事件 HP -= 25
          ◆设置移动路线: 本事件 (等待)
            : 混合模式: 加法
            : 等待: 30 帧
            : 混合模式: 正常
          ◆设置移动路线: 本事件 (重复)
            : 等待: 1 帧
          ◆控制自开关: D = ON
        ◆结束
        ◆如果: ATTACK TYPE ≠ 1
          ◆如果: ATTACK TYPE ≠ 3
            ◆控制自开关: B = ON
          ◆结束
        ◆结束
      ◆结束
    ◆结束
  ◆结束
: Else
  ◆控制变量: #0XXX Hit Test = 9
  ◆控制自开关: B = OFF
  ◆如果: 自开关 D 为 ON
    ◆设置移动路线: 本事件
      : 等待: 1 帧
    ◆控制自开关: D = OFF
  ◆结束
◆结束
(你的 HP 0 检查,未更改)

和往常一样,这一切都非常巧妙,但我想暂时搁置这个特定的方法,因为它占用了大量的开发时间。我可以通过让敌人更快受到伤害来实现类似的效果,而且我还有很多其他攻击需要实现,包括伤害公式、属性等等。也许等系统其余部分完成后,我会再回来处理这个问题,但我认为目前最有效的时间利用方式是加快伤害的发生速度,觉得差不多就行了,然后继续推进——我会再告诉你的。

1-此操作的目的是将攻击碰撞体直接向前推进,直到其无法继续移动,然后将其移除并使其重新变为不可见。然而,当按下 S 键时,情况变成了这样:
玩家角色闪烁了一下,但没有任何反应。接着,当玩家按下任意方向键时,无论按下的是哪个方向,玩家都会向最初按下 S 键的反方向后退。随后,攻击碰撞体会跟随玩家移动,而不是向前移动。它仅在使用普通攻击或盾牌时才会消失。我感觉这是一个常见的问题,但我记不清该如何解决了,抱歉。

2-此攻击功能几乎达到了我想要的效果。它会让攻击碰撞体在竞技场中随机生成并移动,直到消失并重新变为不可见。有没有办法让玩家在此过程中能够移动?

3-关于之前提到的“移动冷却”讨论,我该如何实现当冷却时间结束且玩家现在可以听觉上感知到可以再次使用该技能时播放音效,而不是让玩家去猜测时间呢?我尝试过实现,但音效仅在玩家首次加载时以及玩家首次按下按钮时播放。

你对这些有什么想法吗?

冻结这个思路是合理的,当你想回来处理它时,它还会在那里。

  1. 我认为这是两个旧问题叠加导致的。玩家移动路线被强制从并行处理中调用,这涉及来自 RAM 的“原地转向”机制,因此“后退”步骤会等待箭头被按住。攻击碰撞路线也没有“等待”指令,因此“正在攻击”标志会在爆炸开始的同一帧被设为 OFF。当“正在攻击”为 OFF 时,碰撞的跟随逻辑接管控制权,并在每一帧强制执行其自身的路线,这导致爆炸在展开之前就被替换掉了。这也可能是爆炸仍然可见的原因,因为爆炸结束时的“透明 ON”指令从未被执行。

我尝试的方案是保留 RAM 中的形状逻辑,但仅用于后坐力。创建一个带有开关的自动运行公共事件,命名为“RecoilGo”,它只包含玩家移动路线,然后关闭自身:

◆Set Movement Route: Player (Skip, Wait)
  (你的后坐力路线,保持不变)
◆Control Switches: RecoilGo = OFF

然后,S 块(并行处理)会读取玩家的位置和朝向,与拳击动作的方式相同,并在爆炸路线上添加“等待”:

◆Control Switches: #0181 ATTACKING = ON
◆Control Variables: #0197 ATTACK TYPE = 5
◆Control Variables: AtkX = Map X of Player
◆Control Variables: AtkY = Map Y of Player
◆Control Variables: AtkDir = Direction of Player
(来自拳击的四个 AtkDir 分支)
◆Control Switches: RecoilGo = ON
◆Common Event: SCREENSHAKE MEDIUM
◆Set Movement Route: Attack collision (Skip, Wait)
  (你的爆炸路线,保持不变)
◆Control Switches: #0181 ATTACKING = OFF
◆Control Switches: #0182 MOVEMENT ATTACK = OFF

使用类型 5 是故意的。类型 2 会让每个敌人检查玩家前方的地砖,而不是攻击碰撞所在的位置,导致爆炸只能击中你正前方的区域。使用一个新的数字会经过正常的位置比较,因此只需要在敌人匹配块的拳击部分旁边加上“If: ATTACK TYPE = 5”,并保留爆炸应该执行的操作。此外,并行处理会等待直到爆炸完成,因此其他动作不会在此期间触发。

  1. 我在想这是否又是玩家移动路线的问题。如果这个块位于自动运行事件中,玩家会一直锁定直到最后一行,而在碰撞路线上设置“等待”意味着整个随机行走过程。如果它位于并行处理中,则与第 1 点中的“原地转向”机制相同。无论如何,我认为同样的拆分方法可以解决这个问题。让这个块将 RecoilGo 设为 ON,以替代其自身的玩家移动路线,并将其他所有内容保留在并行处理中。那里的“等待”仅暂停该事件,因此玩家可以在碰撞随机移动时保持控制权。SHRILL 音效可以移出路线,放在 RecoilGo 设为 ON 之前的“播放音效”指令中。如果你想让两次后坐力感觉不同,可以以相同的方式使用第二个自动运行事件。

  2. ActionCooldown 在动作就绪时为 0,并且在加速持续期间也保持为 0,因此检查“= 0”无法区分动作就绪、加速进行中以及冷却时间实际结束的那一刻。与 DashTimer 相同的修复方法:将音效放在递减指令内部,使其仅在数值变为 0 的那一帧触发。然后可以移除自我开关 C 的块:

◆If: ActionCooldown > 0
  ◆Control Variables: #0206 ActionCooldown -= 1
  ◆If: ActionCooldown = 0
    ◆Play SE: Maris Haven SFX/Fighting/BSFX STUTTER (100, 100, 0)
  ◆End
◆End