动画和逻辑

时间:2009-03-25 08:36:46

标签: animation

我的问题不一定特定于任何平台或API,但更具体针对动画之间的代码交互。

游戏就是一个很好的例子。假设玩家死了,并且在移除对象之前必须完成死亡动画。对于许多情况来说,这是典型的,在这种情况下,某些动画必须在继续执行通常会遵循的动作之前完成。你会怎么做呢?

我的问题是关于动画的控制和逻辑。您如何设计一个能够驱动动画但同时实现自定义行为的系统?

通常出现的问题是游戏逻辑和动画数据变得相互依赖。也就是说,动画必须回调代码或以某种方式包含动画序列持续时间的元数据。更常见的问题是,当一个动画必须触发一些其他代码时,比如在1.13之后产生一个自定义精灵,这往往会导致代码和动画的深度嵌套。带有计时器的炸弹就是逻辑和动画的例子,两者都互动,但我想让它们尽可能分开。

但是你会做些什么来保持动画和代码两个不同的东西?

最近我一直在尝试mgrammar,我想,DSL可能是最好的选择。这将允许动画或动画制作者以一种可能安全的方式表达某些事物,然后进入内容管道......

7 个答案:

答案 0 :(得分:5)

解决方案取决于你想要的游戏玩法。如果游戏玩法是100%代码驱动的,则动画由实体的状态(状态驱动的动画)驱动。如果是图形/动画驱动,动画长度决定实体在该状态下的长度(动画驱动状态)。

后者在商业生产环境中通常更灵活,因为设计师可以说“我们需要更短的死亡目标”并且它会得到协商。但是当你有非常精确的规则或像物理学这样的模拟系统时,状态驱动的动画可能更好。对于一般情况,没有100%正交和清洁的解决方案。

有助于防止混乱的一件事是考虑游戏AI模式:

游戏AI通常被实现为某种形式的有限状态机,可能是多个状态机或以某种方式分层(最常见的划分是具有低级别动作/转换的高级脚本格式)。

在低级别你可以说“在hitreact状态,播放我的hitreact anim直到它完成,然后从高级逻辑中找出要继续的状态。”在高层次上,有很多方法可以用来定义逻辑,但是像“接近/攻击/撤退”这样的简单重复循环是一种很好的开始方式。

这有助于保持两种行为 - 计划的活动和对新事件的反应 - 过于混合。同样,它在实践中并不总是以这种方式解决,原因与有时您希望代码驱动数据或相反的原因相同。但那是你的AI。这里没有一般的解决方案!

答案 1 :(得分:1)

你的敌人需要有多个状态。活着和死都是不够的。活着,死亡和死亡可能是。您的敌人处理循环应检查其状态并执行不同的操作:

if(state == alive and hp == 0)
{
   state = dying
   currentanimation = animation(enemy_death)
   currentanimation.play()
}
elseif(state == dying and currentanimation.isPlaying == true)
{
    // do nothing until the animation is finished.
    // more efficiently implemented as a callback.
}
elseif(state == dying and currentanimation.isPlaying == false)
{
    state = dead
    // at this point either the game engine cleans up the object, or the object deletes itself.
}

答案 2 :(得分:0)

我想我真的没有看到问题。

如果你有一些回调嵌套我可以看到为什么事情可能难以理解,但如果你只有一个回调所有动画事件和一个更新功能开始动画,那么很容易遵循代码。 / p>

那么通过分离它们会得到什么?

答案 3 :(得分:0)

我认为你应该将渲染与游戏逻辑分开。

您至少有两种不同的对象:

  • 持有单位数据(生命值,位置,速度,力量等)和逻辑的实体(如何移动,如果命中用完,会发生什么......)。
  • 它的表现形式,即精灵,颜色,附着在它上面的粒子,声音,等等。表示可以访问实体数据,因此它知道位置,生命点等。
  • 如果实体可以直接由人或AI控制(如汽车模拟中的汽车),也许是控制器。

是的,听起来像是模型 - 视图 - 控制器架构。有很多相关资源,请参阅JorritRouwé的this article from deWiTTERSThe Guerrilla Guide to Game Code,了解游戏特定的示例。

关于你的动画问题:对于一个垂死的单位,当模型更新它的实体并且发现它没有更多的生命值时,它可以设置一个标志来说它已经死了并从游戏中移除实体(并从内存中移除) 。然后,当View更新时,它会读取标志并启动垂死的动画。但是由于实体对象应该消失,因此很难确定存储此标志的位置。

在我谦逊的恕我直言中有一个更好的方法。当您的实体死亡时,您可以向注册到属于此特定实体的UnitDiedEvent的所有侦听器发送事件,然后从游戏中删除该实体。实体表示对象正在侦听该事件,其处理程序启动垂死动画。当动画结束时,最终可以删除实体表示。

observer design pattern在这里很有用。

答案 4 :(得分:0)

对于我为解决这个问题而做的几场比赛,我创建了两个动画类

asyncAnimation - 用于火灾和遗忘类型动画

syncAnimation - 如果我想在返回控件之前等待动画解析

由于游戏通常有一个主循环,它看起来像这个C#风格的伪代码

while(isRunning) 
{

   renderStaticItems();
   renderAsyncAnimations();

   if (list_SyncAnimations.Count() > 0)
   {
       syncAnimation = list_SyncAnimations.First();
       syncAnimation.render();

       if (syncAnimation.hasFinished()) 
       {
           list_SyncAnimations.removeAt(0); 
           // May want some logic here saying if
           // the sync animation was 'player dying' update some variable
           // so that we know the animation has ended and the
           // game can prompt for the 'try again' screen
       }

   }
   else
   {
       renderInput();
       handleOtherLogic(); // Like is player dead, add sync animation if required.
   }
}

所以代码所做的是维护一个需要在继续游戏之前解决的同步动画列表 - 如果你需要等待几个动画,只需将它们叠加起来。

此外,查看命令模式或提供同步动画何时完成处理逻辑的回调可能是一个好主意 - 它实际上是你想要的方式。

至于你的“Spawn at sec 1.13”,也许SyncAnimation类应该有一个可覆盖的.OnUpdate()方法,它可以做一些自定义逻辑(或调用脚本)

这取决于您的要求。

答案 5 :(得分:0)

动画可以调用您提供的回调函数,或者将通用事件发送回代码。它不需要任何东西,它保留了代码中的所有逻辑。只需注入回调或在创建动画时连接事件。

答案 6 :(得分:0)

我尽可能地避免儿童动画中的回调。动画应表明它们已完成,动画完成所采取的动作应从应用程序的控制器级别调用。

在Actionscript中,这是事件调度/侦听的美妙之处 - 控制器对象可以创建动画,然后为动画在完成时调度的事件分配处理程序。

我在Flash项目中使用了这个模式,它有助于保持代码独立性,远远优于回调。

特别是如果你编写扩展Event的自定义事件对象来携带你需要的那种信息。例如带有localX,localY,stageX和stageY的MouseEvent。我使用一个名为NumberEvent的自定义来在我的应用程序周围广播任何类型的数字信息。

在actionscript控制器对象中:

var animObj:AwsomeAnim = AwsomeAnim();
animObj.start();
animObj.addEventListener(AwsomeAnim.COPLETE,_onAnimFinish);

function _onAnimFinish():void
{
    // actions to take when animation is complete here
}

在自定义事件不存在的javascript中。我只是在动画对象中有一个布尔变量,并在控制器的计时器上检查它。

在javascript控制器对象中:

var animObj = new animObj();// among other things must set this.isComplete = false
animObj.start();

function checkAnimComplete()
{
    if(animObj.isComplete == true)
    {
        animCompleteActions();

    }else{
        setTimeout(checkAnimComplete,300);
    }
}
checkAnimComplete();


function animCompleteActions()
{
    // anim complete actions chere
}