Free interactive fish Flutter engine series - skeletal animation articles

Author: Busy fish technology - Xiao dust

Skeletal animation is a multi-frame animation is achieved by controlling skeletal parameter mode, different from the bulk GIF incoherent and a sequence of frames, skeletal animation has good flexibility and fluidity. Currently skeletal animation has been extensively used in games and animation, great one substituent frame of the animation trend, Candy interactive engine support for skeletal animation of nature is an essential part.

Starting from the tool

Interactive animation is a very important part, through animation just right often can give the user more fresh experience. Because animation is a need for highly collaborative work and UED, UED face of endless change parameters, choose a handy tool becomes critical, after all, who do not want to knock open the code in the happy time UED come looking for you adjust animation parameters. The current industry reference tool chain system, and choose a set of tools for us is a better choice.

pic1

Look at the official recommendation had been Flutter skeletal animation tool Flare, its advantage lies in support for Flutter is more complete. But the problem is that this set of tools for designers unfamiliar, but .flr format is a new format is not universal, so in the end we gave up this plan.

In line with the Group's existing interactive tool chain, we look into the front end of the field, egrets engine (Egret) is a minor celebrity in the front area of ​​the game engine, its supporting tool system includes DragonBone (skeletal animation), Feather (particle animation) and so on. This interactive tool in the field has been used for many years for a designer is better to get started. The biggest problem using this system is not on the Flutter corresponding implementation, but the document its products very well, so we chose to resolve and achieve the appropriate Runtime on Flutter.

Basics

To skeletal animation production is bound to have a basic understanding of the first skeletal animation itself, detailing skeletal animation can refer DragonBone official tutorial for a few skeleton key concepts we must first be understood.

  • Skeleton (Armature): is a collection of skeletal bones, skeleton comprising at least one bone.
  • Bone (Bone): bone skeletal animation is a fundamental part of parent-child relationship exists between the bones, the father of transformation will affect the children. General rotation of the bone, zoom, pan, etc. can transform animation.
  • Slot (Slot): Slot is a picture container bridge and pictures of bones. A plurality of slots can be mounted skeleton, bones can be regarded as a parent node slots, bone transformation will affect the slot.
  • Display object (DisplayData): objects are usually displayed as a picture. A socket may have a plurality of display objects, but there is only one is shown, the frame may be formed by modifying the animation object is currently displayed.

As the name suggests "skeleton" is the core component of skeletal animation, precisely because of this, imitating a skeleton of biological design, so designers can adjust the parameters of bone, so that the role made rich and natural motion. We want to render skeletal animation certainly not out of the game Candy system to complete, along with our first question was born, the core component of skeletal animation "skeleton" in the end what should play a role in Candy in it?

Rendering skeleton

Questions 1. What is the role each of the bones in Candy is?

The article also mentioned Candy game system is composed of four elements:

  • Game: Game category, is responsible for managing the entire game, Scene management and load management and scheduling various subsystems.
  • Scene: game scene class, responsible for game scenes each game object management.
  • GameObject: game object class, the smallest unit of game objects in the game world, the game world in any body is GameObject.
  • Component: class game component, the ability to represent attributes of game objects, such as SpriteComponent represent wizard component, it represents the ability to draw sprites.

Because bone is a tree structure that contains the parent-child relationship, but also GameObject a tree, we naturally think of each of the bones is a GameObject each slot is the corresponding Component. Because when drawing objects in the drawing must be covered at the top, so the tree structure to draw the biggest problem - the order drawn between father and son is certain. Draw the following sequence diagram of the body -> clothes -> cloak, or clothes -> Gloves -> body, no matter what kind of obviously wrong.


TB1fBqbwxn1gK0jSZKPXXXvUXXa-1150-752.png

Our solution is to pat Fengyun tree as a list, we put each slot (Slot) both as a GameObject, and sorted according to Zorder, then we will eventually get a sorted list of slots, in order to render according to the list of slots at render time.


TB12BeewuL2gK0jSZFmXXc7iXXa-836-742.png

This approach will bring a new issue, location information data slots are relative data, when rendered in the use of the tree structure is not a problem, but now after pat, how to determine the location of the rendering of it?

Question 2. How to position information in the bones and the location information corresponding to the final rendering

Because the bones are relative parameter values, the benefits of this is that when the parent bone to change the position of child bone will naturally be affected parent bone of changing positions. So in fact the problem is how to put the relative value becomes absolute value, we can get this done by some mathematical calculation, the specific principle does not explain in this deployment. In Flutter by a custom Transform class and encapsulates a transformation function corresponding to the coordinate conversion can be achieved, so that advantage can be overloaded so that the respective operators doing the animation and used.

Solves both problems, in fact, we already know how to render a skeleton. Candy implement this architecture diagram below skeletal animation, which is divided into three parts.


TB1IWUIu7L0gK0jSZFxXXXWHVXa-1342-930.png

Layer Parser: Considering the skeletal animation editor There are many available in the market to be compatible with different editors, we added the layers of different analytical product layer generated by the editor, into our pre relatively common skeletal structure data.

Data layer: Data layer is a relatively common skeletal data, internal data, including bones, socket data, display object data, animation data and other data through the skeleton we can finally know what should be rendered. Since we first compatible editor is Dragonbone, so the definition of these data attributes mostly in reference to the definition of Dragonbone here is not will unfold for each attribute a.

Render layer: a backbone is an independent GameObject, skeleton corresponding to each of sockets of a sub GameObject. Skeleton bones play a secondary role in the calculation rendering coordinates, we calculate the absolute coordinates to use when rendering through the bone and fill the slot belongs to the corresponding TransformComponent in. Finally, shows the objects in the picture using SpriteComponent rendered to the correct position.

Animation achieve

骨骼动画其实是由每一根骨骼的多个属性动画复合而成的,简单骨骼动画针对每一根骨骼及插槽其实可以拆分为以下几个动画:

  • 骨骼(插槽)的位移动画
  • 骨骼(插槽)的旋转动画
  • 骨骼(插槽)的缩放动画
  • 插槽的透明度动画

这些简单动画都可以归纳为补间动画,我们只需要在游戏每一次Update的时候将对应的属性值改变,自然就形成了动画的效果。那么每一个时刻的值应该是多少呢?这就需要一个插值器来告诉我们,Flutter的Animation对于插值器提供了很好的支持,回忆一下使用Animation的时候,是不是通过每一次触发刷新了之后从Animation中取出value值来赋值到相应的地方,同理使用在这也是一样的。

因为骨骼动画会有很多的关键帧,所以这里使用了Flutter中的一种特殊的Animation——TweenSequence。TweenSequence 可以传入一个 List<TweenSequenceItem<T>> items 每一个TweenSequenceItem都可以设置一个补间动画和相应的权重。在保证每一个骨骼的动画总帧数相同的情况下,可以直接使用每两个关键帧之间包含的帧数作为权重,相应的前一关键帧帧的值则为起始值,后一帧关键帧的作为终止值。举个例子:

///Transform2 为自己定义的一个数据结构,只要重载了相应的运算符,一样可以被Animation所使用
TweenSequenceItem<Transform2> _parseTransformAnimation(
  TransformFrame cur,
  TransformFrame next, {
    int duration,
  }) {
  if (cur != null && next != null && cur.duration != null) {
    final Animatable<Transform2> tween = Tween<Transform2>(
      begin: cur.transForm,
      end: next.transForm,
    );
    if ((cur.duration != null && cur.duration > 0) ||
        (duration != null && duration > 0)) {
      return TweenSequenceItem<Transform2>(
        tween: tween,
        weight:
        duration == null ? cur.duration?.toDouble() : duration.toDouble(),
      );
    }
  }
  return null;
}

动画效果

这里以闲鱼币中的捞鱼小人为例子(可以通过 “闲鱼首页 -> 右上角签到图标” 进入闲鱼币池塘进行体验)

性能表现

我们使用干净的Demo工程渲染多个上图中的小人进行测试,测试机型:iPhoneXs。

骨骼数量能一定程度上也能衡量动画的复杂度(还与变换次数相关),可以发现大于1000根骨骼时性能开始出现衰减,并随着骨骼数量的增加逐渐明显,在3000根骨骼以上时出现明显卡顿。这一性能已经完全可以满足App中内嵌中小型游戏的需求(其中内存增加问题会在后续的性能篇中进行阐述)

现状和展望

目前Candy已经实现了对基础骨骼动画、粒子动画、属性动画的支持,并且已经在闲鱼币业务中落地使用,后续会应用在更多的场景之中。随着场景的增加,我们面临的挑战也就越来越多。

动画赋能App

An App must not have a lot of game content, we realize that animation is only used if in fact landed in the game scene scene will be very limited, so we will be part of the package Candy animation engine for Widget, can naturally make Flutter App seamless animation.

The ability to support more animation

Lottie is a popular favorite designers, and students to develop a way for Lottie support we have already begun to develop, and then wait for the completion of share.

Upgrading from an interactive animation

Interactive is a combination of animation made with traditional animation biggest difference is that there needs to be interactive interactivity, different interactions occur when users want to switch to a different animation, this means that we need to have organized various animations the relationship between the ability. This is a very complete system, you need to have the appropriate tools and logical layout side logic to achieve the dynamic choreography, we currently are working with the students in the group of front-end interactive panel reuse existing front-end tool chain, but the front-end ratio since Flutter has a natural advantage in terms of dynamic logic, so we want to combine leisure fish team Fass and Flutter-dx to build this system. After completing the article will have to share our approach and mentality with you, and we also welcome to explore together, the collision more spark.

Guess you like

Origin yq.aliyun.com/articles/747521