简单帧动画的循环表达

Author: R.W.Flurando

Tags: guile, chickadee, 动画, 循环

前因

我一直在想啊,这个chickadee怎么做动画。

我说的不是它文档里那个用路径做的动画,而是一张张图片轮着放映的帧动画,就像小人动手动脚的走路一样。

倒霉的是,我一不知道怎么自己实现一个,二没有相关实现,三我没有Libera Chat帐号导致没法问人。

后来我看源代码和文档,欸,您猜怎么着?还真出现了animation动画这个关键词!

于是我仔细研究源代码(文档只标出签名,没有讲怎么用,就好像是自动的一样,事实上完全是手动档……)。

经过

明白之后,我知道了作者写的这个动画是针对Tiled导出的动态tile,就是组成地图的一部分。

那不就成了,直接给我要的动画弄好带动画tile的tileset板块集,然后用这个tile生成一个只有一格的“地图”,再画上这个地图不就成了嘛!

结果让人沮丧(机器音)的是,Tiled生成的tsx(tileset xml)和tmx(tilemap xml)都完全没法在chickadee中读取,直接报错。

我猜测是chickadee没跟上Tiled格式变化的版本。

行不通了,怎么办呢?

只剩下自己实现,虽然网上都说很简单,确实,如果只考虑原理的话。

问题在于如何实现啊,我在编程问题上又是完美主义,真的是举步维艰了。

众所周知,编程这种东西,不会靠什么?靠抄。

就在前天,我终于在编乎上找到了一个python实现,编乎最有用的一集要出现了嘛?NoNoNo,吹的天花乱坠,实际鸟用没有,写那个的人就没指望让你用,是我认识的编乎了。防御性编程的含中量还在上升,虽然我猜是AI策划的AI写的AI发的AI审核的AI点赞的AI评论的,但我不要你觉得,我要我觉得,这他妈就是防御性编程,恶心心。

后来我在Love2d网站上仔细看Animation的教程,虽然就一页,我操,真的精华。

这就是Lua社区的魅力,其实我之前还看过一次,但当时我还不确定chickadee没有2d帧动画支持,所以也没动力仔细研究。

这次,好家伙,硬是看明白了。这一把繠䴧大人和Love2d双mvp。

作为完全因水平有限,而深知在功能实现前千万不能自以为是提前优化的智慧体,吾必定化繁为简,自立门户!

说干就干,我还真写了个代码简易(但使用起来麻烦)的原始动画模块。

就是传入chickadee的texture图样,加上对应的duration时长,循环改变需要显示的图片变量即可。

当然也有开始动画和暂停动画以及重置动画的代码。

怎么说呢,基本功能是够了,但是明显还需要更高级集中的封装。不过暂时我不打算将这个模块封装,因为我不知道怎么做好,还是在项目里单立一个动画模块调用处理来试水吧。

感想

我做事是不给自己任何压力的,你敢信,这个动画怎么弄我卡了半年多。

不过当小向日葵开始在屏幕上摇摆,而且使用的内容有一定的抽象性且可复用,感觉非常好!

虽然今天第一天开学,新学期又是一堆屁用没有的琐事,但,至少在如何做帧动画的事情上,我是真明白原理了。实现?另谈啦。

实现

代码不给了,我都不好意思拿出手。

首先啊,我们得有一个能表示动画的结构,不妨就叫动画吧。

这个动画里需要有如下内容

  1. frame帧 是另一种结构,包含一个chickadee的texture图样和一个数字,这个数字表示这个图样持续的时间,英语里叫duration。 注意,这里需要的不是一个帧,而是一列表(顺序存储的一串数据)的一些帧。
  2. state状态 有且只有正在播放/暂停两种状态,我用编程里常见的真假来对应。
  3. current frame当前帧 这是一个指针(如果你的编程语言有指针概念)或者普通的变量(如果你的编程语言不含指针概念,事实上这时几乎所有变量都是指针) 我们需要这个当前帧来表示要展示的图样texture,这样我们就可以用普通的绘制texture的函数来展示动画,这个函数常被描述成绘制sprite精灵的,在任何2d游戏引擎和有绘制能力的共享代码集都一定会有。
  4. time内部时间 没有内部时间的话,我们很难知道要不要切换到下一帧。

这四个是必不可少的,但只有他们还不够。

我们需要能描述“下一帧”这个概念的东西,熟悉热门循环结构for (int i=0; ...; i++) {}的人肯定想到了,就是index序列号嘛!确实。

同时我们的内部时间和谁比较呢,只能和一堆duration的累加得到,这个累加是否要缓存作为一个单独变量并实时更新,自己权衡吧,反正我是缓存了,作为一个每次更新下一帧序列号时同步计算更新的变量存储。

至于内部时间怎么更新,你游戏循环的时候顺便同步一下变化的时间就行了。

那么我们还需要current frame当前帧吗,不需要,直接用序列号去frame列表里拿就是当前帧了。

总结一下,我们需要如下数据结构(伪代码)

(<animation>
  frame: (list
           (<frame> texture duration)
           (<frame> texture duration)
           ...
           (<frame> texture duration))
  state: true/false
  index: integer starting from 0
  time: internal time)

至于具体逻辑,什么时候加index,什么时候改state,按原理来就行。

就说到这里吧,我已经没什么好说的了,只能说二周目难度降低,不知道如何构建动画结构的时候是真的无从下手。