动画精灵

动画精灵DFSpriteAnimation,在游戏里动画精灵是用的最多的了,因为游戏里很多物件都是动态的,在2d游戏里动态的图像我们用序列帧实现。

Texturepacker是游戏开发中常用的开发工具,可以将零散的序列帧图片组合成一张整图,并用plist或者json记录每个序列帧小图的位置和尺寸。

动画精灵内有加载Texturepacker游戏资源的函数,如果你的数据格式和我使用的不一样可以参照源码进行修改实现。

下面我们看下这个解析是如何实现的:

首先我定义了一个Map,用于存放全部的动画帧,并且map的key是这个动画的名称:

/// 这个动画的全部帧
Map<String, List<DFImageSprite>> frames = HashMap<String, List<DFImageSprite>>();

下面是解析代码:

  /// 将plist转换Json后读取精灵
  /// {
  /// 	"frames": {
  /// 		"idle_00000.png":
  ///     {
  /// 	       "frame": "{{929,291},{76,110}}",
  /// 	       "offset": "{-19,24}",
  ///          "rotated": true
  ///      }
  ///   }
  /// }
  static Future load(String src, String plist) async {
    DFSpriteAnimation spriteAnimation = DFSpriteAnimation(stepTime: 100, loop: true);

    DFAnimation.sequence.forEach((element) {
      spriteAnimation.frames[element] = [];
    });

    ui.Image image = await DFAssetsLoader.loadImage(src);
    Map jsonMap = await DFAssetsLoader.loadJson(plist);

    final jsonFrames = jsonMap['frames'] as Map;

    jsonFrames.forEach((key, value) {
      final map = value as Map;

      bool rotated = false;
      if (map['rotated'] != null) {
        rotated = map['rotated'] as bool;
      }

      final frame = map['frame'] as String;
      final offset = map['offset'] as String;
      List frameText = frame.replaceAll("{{", "").replaceAll("},{", ",").replaceAll("}}", "").split(",");
      List offsetText = offset.replaceAll("{", "").replaceAll("}", "").split(",");

      DFRect frameRect = DFRect(double.parse(frameText[0]), double.parse(frameText[1]), double.parse(frameText[2]),
          double.parse(frameText[3]));
      DFOffset frameOffset = DFOffset(double.parse(offsetText[0]), double.parse(offsetText[1]));

      /// 如果是旋转的参数也修改一下
      if (rotated) {
        frameRect = DFRect(double.parse(frameText[0]), double.parse(frameText[1]), double.parse(frameText[3]),
            double.parse(frameText[2]));
        frameOffset = DFOffset(double.parse(offsetText[1]), double.parse(offsetText[0]));
      }
      //print("frameSize:" + frameRect.toString());
      //print("frameOffset:" + frameOffset.toString());

      DFImageSprite sprite = DFImageSprite(
        image,
        offset: frameOffset,
        rect: frameRect,
        rotated: rotated,
        scale: 0.6,
      );

      //idle_00000.png
      String actionText = "idle_";
      String action = DFAnimation.IDLE;
      if (key.contains("idle_")) {
        actionText = "idle_";
        action = DFAnimation.IDLE;
      } else if (key.contains("run_")) {
        actionText = "run_";
        action = DFAnimation.RUN;
      } else if (key.contains("attack_")) {
        actionText = "attack_";
        action = DFAnimation.ATTACK;
      } else if (key.contains("casting_")) {
        actionText = "casting_";
        action = DFAnimation.CASTING;
      } else if (key.contains("dig_")) {
        actionText = "dig_";
        action = DFAnimation.DIG;
      }

      String keyNumber = key.replaceAll(actionText, "").replaceAll(".png", "");
      if (keyNumber.startsWith("000")) {
        spriteAnimation.frames[action + DFAnimation.UP]?.add(sprite);
      }
      if (keyNumber.startsWith("100")) {
        spriteAnimation.frames[action + DFAnimation.UP_RIGHT]?.add(sprite);
        spriteAnimation.frames[action + DFAnimation.UP_LEFT]?.add(sprite);
      }
      if (keyNumber.startsWith("200")) {
        spriteAnimation.frames[action + DFAnimation.RIGHT]?.add(sprite);
        spriteAnimation.frames[action + DFAnimation.LEFT]?.add(sprite);
      }
      if (keyNumber.startsWith("300")) {
        spriteAnimation.frames[action + DFAnimation.DOWN_RIGHT]?.add(sprite);
        spriteAnimation.frames[action + DFAnimation.DOWN_LEFT]?.add(sprite);
      }
      if (keyNumber.startsWith("400")) {
        spriteAnimation.frames[action + DFAnimation.DOWN]?.add(sprite);
      }
    });

    return spriteAnimation;
  }

通过上面的解析数据的方法,我们将动画数据都整理好了,这是游戏中如果需要控制某个时刻显示哪个动画,就比较简单了,可以通过动画的名称进行播放了。

控制动画开始播放,代码如下:

///自动播放玩家第一个动画
this.play(action: DFAnimation.IDLE, direction: DFAnimation.DOWN);




版权所有,违者必究,欢迎转载请注明出处。