Flutter Flame教程7 --Images图片

4,033 阅读5分钟

Images


如果你正在使用Component组件,做一些简单的东西,你可能不需要这些类。相反的,请使用SpriteComponent和AnimationComponent。

你必须要有一个合适的文件结构,并将这些文件添加到pubspec.yaml文件中,正如如上所说。 必须是PNG文件,可以有透明度。

Sprite


Flame提供了Sprite类来表示一张图片的一部分(或者整张图片)。

你可以通过给fromImage构造函数传递一个预加载的Image来创建Sprite,或者你可以传递文件名称给无参构造函数来异步加载图片。

比如,如下会创建传递文件锁表示的整张图片的精灵,自动跟踪它的加载:

    Sprite player = Sprite('player.png');

你也可以指定原始图片的坐标来决定精灵的位置;允许你使用精灵表单来减少在内存中图片的数量;比如:

    Sprite playerFrame = Sprite('player.png', x = 32.0, width = 16.0);

x,y默认值是0.0,width和height默认值是null(意味着它会使用原图片的整个宽度/高度).

Sprite有一个loaded方法,返回图片是否被加载,和render方法,允许你将图片渲染到Canvas:

    Sprite block = Sprite('block.png');
    
    //在你的render方法中
    block.render(canvas, 16.0, 16.0);//canvas, width, height

你必须传递大小给render方法,图片会相应地调整大小。

当精灵没有被加载的时候,渲染方法什么都不做,所以你不需要担心。图片在Images类中缓存,所以你可以用相同的文件名字创建多个精灵。

Sprite类中的所有渲染方法都可以在可选的命名参数overridePaint上接收Paint实例,该参数将覆盖该渲染调用的当前Sprite实例。

精灵也可以作为小组件使用,只需要使用Flame.util.spriteAsWidget.

精灵作为小组件的更完整的例子在这里查看.

Svg


Flame提供了在游戏中渲染SVG图片的简单API。 只需要导入'package:flame/svg.dart'包中的Svg类就可以使用,并像如下代码一样在画布上渲染它:

    Svg svgInstance = Svg('android.png');
    final position = Position(100,100);
    final width = 300;
    final height = 300;
    
    svgInstance.renderPosition(canvas, position, width, height);

Flame.images

Flame.images是加载图片的更底层的工具,和Flame.audio实例类似。

Flutter有一系列与图片相关的类型,将所有内容正确的从本地资源转换为可以再画布上绘制的图像是一个小麻烦。这个类允许你获得一个可以使用drawImageRect方法绘制到画布上的图像。

它根据文件名称自动缓存任何图片,所以你可以安全地调用多次。

加载和绘制图片,你可以使用load方法,就像这样:

    import 'package:flame/flame.dart';
    
    Image image = await Flame.images.load('player.png');
    
    Flame.images.load('player.png').then((Image image){
        var paint = Paint()..color = Color(0xFFFFFFFF);
        var rect = Rect.fromLTWH(0.0, 0.0, image.width.toDouble(),image.height.toDouble());
        canvas.drawImageRect(image, rect, rect, paint);
    });

加载和清除缓存的方法与Audio类的方法一样:load,loadAll,clear,clearAll。图片加载时返回一个Future.

像Audio一样,你也可以初始化你自己的Images实例(每个实例分享不同的缓存):

    Image image = await Images().load('asd');

Animation


Animation类帮助你创建精灵的循环动画。

你可以传递大小相等的精灵列表和stepTime(即移动到下一帧需要多少秒)来创建Animation:

    Animation a = Animation.spriteList(sprites, stepTime: 0.02);

动画创建之后,你需要在你的游戏实例中调用update方法来渲染当前帧的精灵,比如:

    class MyGame extends Game{
        Animation a;
        
        MyGame() {
            a = Animation(...);
        }
        
        void update(double dt) {
            a.update(dt);
        }
        
        void render(Canvas c) {
            a.getSprite(0.render(c);
        }
    }

更好的生成精灵列表的替代方法是使用sequenced构造函数:

    const amountOfFrames = 8;
    Animation a = Animation.sequenced('player.png', amountOfFrames, textureWidth: 16.0, textureHeight: 16.0);

在其中传递文件名,帧数和精灵列表会根据4个可选参数自动拆分。

  • textureX: 在原始图像的x位置开始(默认是0)
  • textureY:
  • 在原始图像的y位置开始(默认是0)
  • textureWidth: 每帧的宽度(默认是null,也就是精灵表的全宽)
  • textureHeight:每帧的高度(默认是null,也就是精灵表的全高)
  • destroyOnFinish:一个bool值,表示当动画结束时,AnimationComponent是否应该被销毁

所以比如说,我们有一个8帧的player动画,它们在一行中。所以如果player高度也是16像素,那么精灵表单就是12816,包含8个1616帧。

这个构造函数使得使用精灵表单创建动画非常容易。

如果你使用Aseprite动画,Flame提供了Aseprite 动画的JSON数据支持,为了使用这个特性,你需要导入精灵表单的JSON数据,并使用类似如下的代码:

    Animation animation = await Animation.fromAsepriteData(
        "chopper.png",
        "./assets/chooper.json"
    );

注意:Flame不支持修建精灵表,所以如果你用这种方式导出你的精灵表,它会有修建的大小,而不是原始的精灵大小

动画在创建之后有update和render方法;render渲染当前帧,update在内部时钟上滴答滴答地更新帧。

动画在内部AnimationComponent中正常使用,但是又徐国动画的自定义组件也可以被创建。

动画也可以作为组件,只需要使用Flame.util.animationAsWidget即可。

使用动画作为组件的完整例子请查看这里

FlareAnimation


Flame提供了Flare动画的简单包装类,这样你就可以在Flame游戏中使用了。

查看如下有关如何使用此包装器的代码块:

class MyGame extends Game {
    FlareAnimation flareAnimation;
    bool loaded = false;
    
    MyGame() {
        _start();
    }
    
    void _start() async {
        flareAnimation = await FlareAnimation.load("assets/FLARE_FILE.flr");
        flareAnimation.updateAnimation("ANIMATION_NAME");
        
        flareAnimation.width = 306;
        flareAnimation.height = 228;
        
        loaded = true;
    }
    
    @override
    void render(Canvas canvas) {
        if (loaded) {
            flareAnimation.render(canas, x: 50, y: 50);
        }
    }
    
    @override
    void update(double dt) {
        if(loaded) {
            flareAnimation.update(dt);
        }
    }
}

FlareAnimation通常被使用在FlareComponent中,这样BaseGame会自动调用renderupdate.你可以看Flare的完整例子.

SpriteSheet 精灵表单


精灵表单是大图像,上面有多个具有相同精灵的帧,是组织和保存动画的一种很好的方式。Flame提供了一种处理精灵表单的很简单的工具类,有了它你可以加载精灵表单图片,并从中提取动画。以下是例子:

import 'package:flame/spritesheet.dart';

final spritesheet = SpriteSheet(
    imageName: 'spritesheet.png',
    textureWidth: 16,
    textureHeight: 16,
    columns: 10,
    rows: 2,
);

final animation = spritesheet.createAnimation(0, stepTime: 0.1);

现在你可以直接使用动画或者在动画组件中使用。

你也可以通过使用getSprite方法,获取精灵表单中的单个帧:

spritesheet.getSprite(0, 0);

你可以在这里查看SpriteSheet类完整示例。