iT邦幫忙

2021 iThome 鐵人賽

DAY 27
0

flame SpriteComponent

看著團隊挑戰的成員寫了一篇 從零開始的8-bit迷宮探險!Swift SpriteKit 遊戲開發實戰,那我們今天就來挑戰看看怎麼在 flutter 上開發遊戲好了。

flame 介紹

這是一套在 Flutter 上的 2D 遊戲引擎。

目前穩定版本是 0.29.4,不過預發佈版本已來到 flame 1.0.0-releasecandidate.14,兩邊的語法寫法不大相同,研究前請注意一下。

在官網上文件尚不完整,建議參考awesome-flame上的教學文章。

套件設定

pubspec.yaml 加入套件設定

dependencies:
  ...
  flame: ^1.0.0-releasecandidate.14
  ...

遊戲開發

想起以前在研究 Cocos Creator 時的 星星 遊戲,想說試著用 flame 來開發看看,我們從 cocos-creator GitHub 上可以取得圖片素材。

遊戲相關設定

import 'package:flutter/material.dart';
import 'package:flame/flame.dart';
import 'package:flame/game.dart';

void main() async {
  // 確認 Flutter 已剛成初始化綁定動作
  WidgetsFlutterBinding.ensureInitialized();

  // 設定全屏以及橫向顯示
  Flame.device.fullScreen();
  Flame.device.setLandscape();

  runApp(const StarsApp());
}

目前 1.0.0 的語法,需使用 GameWidget 帶入 game 參數。

class StarsApp extends StatelessWidget {
  const StarsApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Stars',
      theme: ThemeData.dark(),
      home: Scaffold(body: GameWidget(game: StarGame())),
    );
  }
}
import 'package:flame/game.dart';

class StarGame extends FlameGame {
  // 取得 App 畫面寬高
  final double screenWidth = MediaQueryData.fromWindow(window).size.width;
  final double screenHeight = MediaQueryData.fromWindow(window).size.height;

  @override
  Future<void> onLoad() async {
      // TODO
  }
}

圖片設定

與 Flutter 在使用圖片方式一樣,在 pubspec.yamlassets 定義圖片來源。

flutter:
  uses-material-design: true
  assets:
    - assets/images/

StarGame 屬性定義會使用到的圖片設定

  static const _assetsImages = [
    'purple_moster.png',
    'background.jpg',
    'ground.png',
    'star.png'
  ];

使用 FlameGameimages 戴入

  Future<void> onLoad() async {
    await images.loadAll(_assetsImages);
  }

SpriteComponent

我們使用 SpriteComponent 定義 Sprite 內容,這個 Component 提供 sizeposition 參數可對應畫面上的設定。

class SpriteComponent extends PositionComponent with HasPaint {
  /// The [sprite] to be rendered by this component.
  Sprite? sprite;

  /// Creates a component with an empty sprite which can be set later
  SpriteComponent({
    Vector2? position,
    Vector2? size,
    int? priority,
    this.sprite,
    Paint? paint,
  }) : super(
          position: position,
          size: size ?? sprite?.srcSize,
          priority: priority,
        ) {
    if (paint != null) {
      this.paint = paint;
    }
  }
  • 背景精靈元件設定

使用 SpriteComponent 來設定背景圖片,從 size 指定元件的寬高

import 'package:flame/components.dart';
import 'star_game.dart';

class Background extends SpriteComponent {
  Background(StarGame _game)
      : super(
          sprite: Sprite(
            _game.images.fromCache('background.jpg'),
          ),
          size: Vector2(_game.screenWidth, _game.screenHeight),
        );
}

使用 addComponent 新增至畫面上

  Future<void> onLoad() async {
    await images.loadAll(_assetsImages);
    final background = Background(this);
    add(background);
  }
  • 地面精靈元件設定
import 'package:flame/components.dart';
import 'star_game.dart';

class Ground extends SpriteComponent {
  final double _height = 100;
  final StarGame _game;
  Ground(this._game)
      : super(sprite: Sprite(_game.images.fromCache('ground.png'))) {
    size = Vector2(_game.screenWidth, _height);
    position = Vector2(0, _game.screenHeight - _height);
  }
}
  • 怪獸精靈元件設定
import 'package:flame/components.dart';
import 'star_game.dart';

class Moster extends SpriteComponent with Hitbox, Collidable {
  late final StarGame _game;
   Moster(this._game)
      : super(
          sprite: Sprite(_game.images.fromCache('purple_moster.png')),
          size: Vector2(64, 64),
        ) {
    x = 200;
    y = _originY = _game.screenHeight - _game.ground.height - height / 2;
    anchor = Anchor.center;
  }

今日成果

flame_start

程式碼


上一篇
Flutter體驗 Day 26-bloc
下一篇
Flutter體驗 Day 28-flame JoystickComponent
系列文
Flutter / Dart 跨平台App開發體驗30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言