Flutter Flame 教程3 -- Components元件

我跑步前腳先著地發表於2020-05-04

Components元件


這個類表示了螢幕上的單一物件,可以是浮動的方塊或者旋轉的精靈。
基本抽象類有期望被實現的update和render方法。
中間的實現類PositionComponent 為Component類 新增了x,y,width,height和angle屬性,也包括一些有用的方法比如distance和angleBetween。
最常用的實現是SpriteComponent,可以用於建立Sprite(精靈):

    import 'package:flame/components/component.dart';
    Sprite sprite = Sprite('player.png');
    
    const size = 128.0;
    var player = SpriteComponent.fromSprite(size,size,sprite);
    
    // 螢幕座標
    player.x = ... //預設是0 
    player.y = ... // 預設是0
    player.angle = ... //預設是0
    
    player.render(canvas); //只有當圖片被載入,並且x,y,width,height引數不為空時,它才會被繪製
複製程式碼

在這個事件中,如果你想簡單的改變正在繪製的元件方向,你也可以在render(Canvas canvas)方法中使用renderFlipX和renderFlipY來旋轉任何會知道canvas的元件。對於所有的PositionComponent物件都有用,尤其適用於SpriteComponent和AnimationComponent。比如設定component.renderFlipX = true就可以翻轉橫向繪製。

每個Componeng都有一些你可以選擇使用的方法,它們被用於BaseGame類。如果你不使用BaseGame,你可以在自己的遊戲迴圈中使用這些方法。

每次螢幕重置大小,resize方法都會被呼叫。剛開始是通過add方法使得component被載入的。當螢幕重置大小的時候,你需要應用這些變化到元件的x,y,width和height,或者其他變化。你可以將這些變數開始應用到add方法,因為直到所有都設定好的時候,精靈才會被繪製。

destroy方法可以被實現成返回true,提醒BaseGame你的物件被標記為銷燬,而且在當前更新迴圈之後被移除。它將不再被繪製或者更新。

isHUD方法可以被實現為返回true(預設為false),使得BaseGame忽略這個element的camera。

onMount方法可以重寫以便為這個component執行初始化程式碼。當這個方法被呼叫的時候,BaseGame確保所有可以改變這個component行為的mixins都已經被處理過。

onDestroy方法可以被重寫,以便這個component在從遊戲中移除之前執行程式碼。

還有一些其他實現:

  • AnimationComponent接受一個Animation物件,並且繪製一個週期的動畫精靈(更多關於Animations的詳情請點選這裡
  • SvgComponent接受一個Svg物件,並在遊戲中繪製這個Svg
  • ParallaxComponent可以繪製許多幀的的一個並行背景
  • Box2DComponent,有一個內建的物理引擎(使用Dart版的Box2D)

Animation Component 動畫元件


這個元件使用Animation的一個例項,去展現一個可以執行一個週期動畫的精靈的元件。
下面的例子建立了簡單的三幀動畫:

    List<Sprite> sprites = [0,1,2].map((i) => new Sprite('player_${i}.png')).toList();
    this.player = AnimationComponent(64.0,64.0,new Animation.spriteList(sprites,stepTime:0.01));
複製程式碼

如果你有一張精靈表,你可以使用sequenced構造方法,等同於提供一個Animation類(在這一章中檢視更多詳情)

    this.player = AnimationComponent.sequenced(64.0,64.0,'player.png',2);
複製程式碼

如果你不使用BaseGame,就算這個元件是靜態的,也不要忘了去更新,因為這個動畫物件需要滴答滴答才能移動幀。

SvgComponent


這個元件使用Svg類的例項,這個例項有一個繪製到遊戲中的svg影像。

    Svg svg = Svg('android.svg');
    SvgComponent android = SvgComponent.fromSvg(100,100,svg);
    android.x = 100;
    android.y = 100;
複製程式碼

FlareAnimation Component


這個元件包裝了FlareAnimation的一個例項,它接受一個Flare動畫檔案的檔名稱,檔案中包含你想要使用的動畫。元件還可以接受繪製動畫的長度和高度。

    final fileName = "assets/Bob_Minion.flr";
    final animation = "Wave";
    final width = 306;
    final height = 228;
    
    FlareComponent flareAnimation = FlareComponent(fileName,aniamtion,width,height);
    flareAnimation.x = 50;
    flareAnimation.y = 240;
    add(flareAnimation);
複製程式碼

你可以使用updateAnimation去改變當前播放的動畫。

作為例項,請檢視這個原始檔.

Composed component 組合元件

一個幫助你將一個元件和另一個元件包裹在一起的mixin。通過層次結構對課件元件進行分組很有用。當實現的時候,使得每一項在它的components集合屬性中都能在同一種情況下更新和渲染。

例子展現了兩個元件的可見性是如何被一個包裝類處理的:

    class GameOverPanel extends PositionComponent with Resizable, ComposedComponent{
        bool visible = false;
        
        GameOverText gameOverText;
        GameOverButton gameOverButton;
        
        GameOverPanel(Image spriteImage):super(){
            gameOverText = GameOverText(spriteImage);
            gameOverButton = GameOverButton(spriteImage);
            
            components..add(gameOverText)..add(gameOverButton);
        }
        
        @override
        void render(Canvas canvas){
            if(visible){
                super.render(canvas);
            }
        }
    }
複製程式碼

Parallax Component 並行元件


這個元件可以通過繪製彼此之上的多個透明影像,來渲染漂亮的背景,每個都錯位一點。

這個基本原理是,當你觀察地平線並移動時,更近的物體似乎比更遠的物體移動的更快。

這個元件模擬了這種效果,建立了一種更有深度感的真實背景。

像這樣建立它:

    final images = [
        ParallaxImage("mountains.jpg"),
        ParallaxImage("forest.jpg"),
        ParallaxImage("city.jpg"),
    ];
    this.bg = ParallaxComponent(images);
複製程式碼

這樣建立了一個靜態背景,如果你想要移動的話,你需要設定命名可選引數baseSpeed和layerDelta。比如你想要在X軸上移動背景圖,並使影像離得更遠,你可以像這樣做:

    this.bg = ParallaxComponent(images, baseSpeed: Offset(50,0),layerDelta: Offset(20,0));
複製程式碼

你可以在任何時候設定baseSpeed和layerDelta。比如當你的任務跳躍或者你的遊戲加速的時候.

    this.bg.baseSpeed = Offset(100,0);
    this.bg.layerDelta = Offset(40,0);
複製程式碼

預設影像左下角對齊,在X軸上不斷重複,並且按比例縮放以便影像可以覆蓋螢幕高度。如果你想要修改這個屬性,比如你並不是在做一個邊緣滾動的遊戲,你可以為每一個ParallaxImage設定repeat、alignment和fill引數。

高階例子:

    final images = [
        ParallaxImage("stars.jpg", repeat: ImageRepeat.repeat, alignment: Alignment.center, fill:LayerFill.width),
        ParallaxImage("planets.jpg", repeat: ImageRepeat.repeatY, alignment: Alignment.bottomLeft, fill: LayerFill.none),
        ParallaxImage("dust.jpg", repeat: ImageRepeat.repeatX, alignment: Alignment.topRight, fill: LayerFill.height),
    ];
    this.bg = ParallaxComponent(images, baseSpeed: Offset(50,0),layerDelta: Offset(20,0));
複製程式碼
  • 在這個例子中,stars影像會在兩個軸中重複繪製,螢幕中間對齊,所以會縮放以適應螢幕寬度
  • planets圖片會在Y軸中重複,與螢幕左下角對齊,不縮放
  • dust圖片在X軸重複,右上角對齊,縮放以填充螢幕高度

一旦你設定了這些你需要的引數,就可以當做其他component去繪製ParallaxComponent了。

就像AnimationComponent一樣,儘管你的並行是靜態的,你必須呼叫這個component的update方法,它才能執行動畫。同時,也不要忘了將你的圖片新增到pubspec.yaml目錄中作為資原始檔,否則它們將無法被找到。

一個實現的例子,可以在示例目錄中找到。

Box2D Component


Flame與Flutter實現的Box2D有一個基本的整合。

一個box2d世界的所有概念被對映到Box2DComponent元件;每一個Body都應該是BodyComponent,並且直接被新增到Box2DComponent,而不是game list。

所以在你game list中,你有一個HUD和其他的非物理相關的元件,也可以有足夠多的Box2DComponents如果你喜歡的話(我猜通常是一個),然後新增你的物理實體到你的Components例項。當這個Component更新的時候,它會使用box2d物理引擎去正確的更新每一個子元件。

你可以檢視一個更完整的例子,這個例子是@feroult製作的WIP遊戲(請注意:它使用0.6.x版本的flame,但是相關Box2D api並沒有改變)。

Tiled Component


現在我們有一個Tiled 元件的非常基本的實現。這個API使用Tiled庫來解析地圖檔案和繪製可見圖層。

如何使用這個API可以在這裡找到.

Nine Tile Box Component 九宮格元件

九宮格元件使用格子精靈繪製的長方形。

這個格子精靈是3x3的格子,有9塊,表示4個角、4個邊以及中間一塊。

角被繪製到同一大小,邊在邊的方向上拉伸,中間的塊兩邊都拉伸。

通過使用這個,你可以獲得在任何大小上都擴充套件很好的box/rectangle.這對於製作皮膚、對話方塊、邊框非常有用。

你可以在例子 nine_tile_box中檢視更多如何使用的細節。

相關文章