如何将子弹释放与射击动画联系在一起


15

假设您有一个想要发射子弹时要发生的动画。您如何将子弹显示在动画的结尾。我唯一能弄清楚的是知道动画的时间长度,并延迟设置项目符号位置并将其设置为活动状态,直到经过该时间量为止。我只是想知道这是否是最好的方法,其他人如何处理呢?

编辑:我认为我在正确表达问题时遇到麻烦。

我的问题


谢谢!你们所有人都有很多好主意,我喜欢使用回调的主意。我想我会尝试实现这一点,我真的不想依赖时间跟踪。
tp0w3rn 2011年

Answers:


8

从根本上讲,您处在正确的轨道上-您需要知道动画可以持续多长时间来执行此类操作。动画不仅仅是帧的集合,您还需要围绕它们的各种其他信息。例如,那里有几帧,动画会循环播放,它会播放多快(例如,每秒10动画帧或25或60动画帧?)。可以根据一些数据来定义每个动画,一些通用的动画代码可以查看并回放这些数据。您应该将动画部分封装在自己的代码中,该代码除了这些动画定义以及如何显示单个图像帧外什么都不知道。也就是说,有一个动画对象,您可以在屏幕上的特定位置加载,开始播放,停止播放以及告诉渲染。

一种灵活的方法是使用一种动画定义来封装这种信息。因此,与其说“动画X是所有这些帧,而是通过它们播放”,不如说有点复杂。

例如,具有某种模拟的数据格式

动画=
{
  {name =“ walk”,files =“ walk * .png”,frameCount =“ 12”,loop =“ true”},
  {name =“ fire” files =“ fire * .png” frameCount =“ 6”,
       事件= {
           {name =“ bulletLeavesGun”,frame =“ 4”,param1 =“ 43”,param2 =“ 30”}
       }
  }
}

因此,您的代码显示如下内容:

currentAnimation = animations.Get("fire");
currentAnimation.Play();

您可以通过动画代码回叫您(例如,由于动画已播放到特定帧而检测到新事件时,它会调用您的游戏代码来告知新事件)来检测事件,或者通过轮询动画如下:

List<Event> events = currentAnimation.EventsSinceLastCheck();
foreach (AnimationEvent event in events)
{
    if (event.name == "bulletLeavesGun")
    {
        Vector2 bulletPosition = new Vector2(event.param1, event.param2);
        Vector2 actualBulletPosition = new Vector2(
                 character.x + bulletPosition.x, 
                 character.y + bulletPosition.y);
        CreateBulletAt(actualBulletPosition);
    }
}

注意事项:

  • 动画代码应与游戏代码分开存在。您确实不希望您的游戏代码与动画回放的细节紧密联系。
  • 动画代码根据动画定义知道是否循环
  • 动画代码知道何时完成动画,并且可以回叫其他代码说:“嘿,刚刚完成的名为“ fire”的动画,您现在想做什么?
  • 动画代码对事件一无所知,除了事件具有名称和与之关联的任意数据(param1和param2)外
  • 动画代码知道它当前在哪个帧上,并且当它更改为新帧时,它可以检查并说:“哦,我现在在第4帧上,这意味着刚刚发生了名为“ fire”的事件,将其添加到我最近的活动清单,这样我就可以告诉任何询问它的人。

如果您不需要在动画中进行子弹发射,而只需完成一次,就可以在没有事件概念的情况下使用复杂得多的系统。但是,您仍然需要一个动画可以自己播放,知道它们有多长时间并且可以在动画完成时回调游戏代码的系统。


我不同意保持逻辑感知的动画(现在在第4帧,这意味着刚刚发生了名为“ fire”的事件)。动画应该是盲目的和愚蠢的。我不得不做一些服务器端逻辑,并从游戏中删除动画和UI,这是我不想再做的事情。我真的建议使用非常短且分段的动画,将它们与逻辑并行播放,让逻辑以逻辑定义的速度触发动画序列。永远不要对动画的状态进行逻辑测试。
郊狼

将动画分成几部分似乎是不必要的。我同意不轮询动画的状态,但这仍然是他的第一个建议。我不知道他是否意味着要使用一个独立的事件系统来将动画代码与游戏的其余部分(观察者模式)分离,但这就是我要这样做的方式。您所说的“逻辑”都不应该了解动画代码,反之亦然。
2011年

@土狼我想说的是,您正在混合两件事。是的,服务器端逻辑应该始终独立于视觉效果(因为您不想为了找出何时发射子弹而必须运行动​​画系统),但这并不能帮助您在客户端上构建动画系统。在客户端上,您绝对不希望视觉效果被盲目地奴役到服务器上,因为这看起来很糟糕-项目符号在奇数时出现并且与角色不同步,因为游戏和服务器之间存在滞后尖峰。没有理由不能同时拥有两者(续...)
MrCranky 2011年

@Coyote(续...),可以通过与视觉效果分离的服务器来驱动游戏。因此,子弹在服务器上的时间X发射,客户端通过立即开始播放动画来反映该动作,其中子弹发射视觉效果比子弹游戏性模拟落后了几帧。在视觉逼真度和游戏模拟之间需要做出各种折衷,因此说“动画应该是盲目的和愚蠢的”是天真的。有时,事件绝对需要与动画帧绑定,因为没有其他方法可以使事件看起来或听起来正确。
MrCranky 2011年

@Coyote实际上,现在我想到了,子弹发射是一个很糟糕的例子,主要是因为下面的thedaian给出了答案。射击应立即发生。一个更好的例子是角色着陆时触发尘埃VFX-服务器和客户端会在角色开始跳跃时进行同步,但视觉显示将留给客户端。当动画击中右脚踩到地面的帧时,将触发VFX事件。同样,如果需要在某个动画帧上做出是否分支到另一个动画的决定,则需要事件。
MrCranky 2011年

3

以某种方式,您必须等到动画完成后再在该点创建项目符号。

如果您确定动画速率是固定的,则只需设置一个计时器即可。作为一个较小的变体,您可以在项目符号内部添加代码,使其在出现和移动之前隐式等待一会儿。

根据您的开发平台,您可能具有某种动画更新功能或回调,可以让您在动画到达所需点的确切时间进行响应。例如,这就是我使用Flixel的方式。


1
Flixel的addAnimationCallback方法可用于触发实体。在回调函数中,您可以查看射击动画的当前帧是否为应创建项目符号实体的帧。如果是,则可以在屏幕上添加项目符号。
雪盲

2

直截了当的答案:假设您有一个要在播放器按下“开火”按钮时播放的动画,然后在播放完毕后弹出子弹。理想情况下,您应该避免对动画时间进行硬编码,并在动画完成时触发子弹(使用回调函数或其他方法,具体取决于您的平台)。我想不出其他任何不太复杂的方法。

替代游戏设计的答案:除非有确凿的充分理由,否则我将避免因按下“开火”按钮而让子弹出现而延迟。除非动画真的非常短(最大一两个帧,基本上是一个枪口的闪​​光),否则它将使触发按钮的响应变慢,并且只会使典型的玩家感到烦恼。即使您确实决定在子弹出来之前使用动画(基于回合的RPG和战术游戏也是这样做的可接受的理由),我仍会考虑在某处包括“关闭动画”选项,以允许如果玩家愿意,游戏可以更快地移动。


是的,不要让火反应缓慢。就像跳跃的常见问题一样。动画师大放异彩,但是玩家希望他们只要按下按钮就可以空降。
2011年

2

正如克兰基先生所说; 将动画和逻辑分开。

但最重要的是,逻辑必须仍然是主要部分。

  • 当按下开火按钮时,您应该在角色的状态(逻辑)下触发绘制“ 动作 ”。
  • 此动作应触发带有所有参数(生存时间等)的图形动画
  • 一旦平局动作完成,您就可以触发射击动作(根据武器的不同,可以射击一次或多次)
  • 该动作可以生成子弹并触发射击动画

请记住,从逻辑上控制UI是确保以后能够保留,重用和共享逻辑(新的渲染器,新的游戏,没有渲染器的服务器版本...)的唯一方法。


1

首先,我将使用事件系统(观察者模式?)来解耦代码段。这不仅用于动画,而且肯定适用于此。然后,动画代码可以简单地说出dispatchEvent(event),而代码的其他部分侦听该事件,而代码的任何一部分都不需要彼此了解。

现在,动画代码实际上需要引用事件分配器(通过依赖注入轻松完成),并且您需要具有一些XML或JSON,它们实际上定义了动画。就像是:

{
  animation: {
    name: shoot,
    length: 12,
    spritesheet: shoot.png
    event: {
      frame: 4,
      name: bulletLeavesGun,
    },
  },
}

加载动画时读入数据,并让动画代码在回放过程中将事件分发到该帧时调度该事件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.