Flutter/Flame Grundlagen

Über camera, viewports und viewfinder

Für mich war das grundsätzliche Verständnis, wie eine Camera, eine World, ein Viewport und ein Viewfinder in Flame zu behandeln sind, ein bisschen schwierig zu verstehen. Daher wollte ich dies nochmals zusammenfassen. Hier also ein kurzer Überblick über die grundsätzlichen Komponenten eines Flame-Games.

Die World-Klasse

Zunächst gibt es die World-Klasse, die alle Komponenten enthält, die sich in deiner Spielwelt befinden – beispielsweise der Player (SpriteComponent), der Background (Parallax) oder das Level (TiledComponent). Die World-Komponente kann an beliebiger Stelle gemountet werden, zum Beispiel direkt in der FlameGame-Klasse. Seit der Flame-Version 1.9 muss diese jedoch nicht mehr extra mit add hinzugefügt werden!

Die CameraComponent-Klasse

Die CameraComponent-Klasse ist jene Klasse, die auf die World „schaut“. Wenn die Welt also quasi zu groß für den Bildschirm ist, zeigt die CameraComponent-Klasse einen Teil der Welt. Die Welt existiert aber auch ohne Kamera! Es könnten auch mehrere Kameras auf die Welt schauen – an unterschiedlichen Positionen und unterschiedlichen Winkeln. Um das umzusetzen verwendet die CameraComponent-Klasse:

  • den Viewport: Das „Fenster“, mit dem die Kamera auf die Welt schaut. Dieses Fenster hat eine bestimmte Position und eine bestimmte Größe. Adden von Elementen in die Viewport-Klasse ist dann nützlich, wenn man HUD-Komponenten benötigt. Sie scheinen dann quasi „auf“ dem Fenster zu sein.
  • den Viewfinder: Dies entspricht dem „Ausschnitt“ der Spielwelt, den man „durch“ das Fenster (den Viewport) sieht, also die Position und das Zoom-Level. Komponenten, die dem Viewfinder als Child hinzugefügt werden, werden gerendert, als ob sie Teil der Welt wären (jedoch oben drauf). Genutzt wird das beispielsweise für Effekte oder andere Controller.

Seit Version 1.9 existiert eine Standard-CameraComponent mit dem Namen camera; ein adden ist daher in vielen Fällen nicht mehr nötig!

Beispiel: Viewport und Viewfinder

Im folgenden Beispiel schauen wir durch einen Viewport der Standard-Kamera camera auf die Standard-world – beide müssen nicht extra initiiert und geadded werden! Wir legen einen Rahmen über den Viewport und setzen ein Quadrat in die World, auf die wir durch den Viewport schauen.

class BackgroundTest extends FlameGame with SingleGameInstance {
  // world and camera already exists

  // set up a quare to put it in the world later
  final RectangleComponent rectangle =
      RectangleComponent.square(size: 20, position: Vector2(0, 0));

  // set up the color for the frame
  final Paint framePaint = Paint()
    ..style = PaintingStyle.stroke // this is for border
    ..strokeWidth = 2.0 // specifying border width
    ..color = Colors.white; // color of the border

  // initialize the frame; for now with zero, since we don't
  // have the sizes we need here
  RectangleComponent frame = RectangleComponent(
    size: Vector2.zero(),
    position: Vector2.zero(),
  );

  @override
  FutureOr<void> onLoad() {
    // set the frame to the correct size
    frame = RectangleComponent(
      size: camera.viewport.size,
      position: camera.viewport.position,
      paint: framePaint,
    );
    // add it on top of the viewport
    camera.viewport.add(frame);

    // add the square in the world
    world.add(rectangle);

    return super.onLoad();
  }

  @override
  void update(double dt) {
    rectangle.position += Vector2(100 * dt, 0);
    camera.moveBy(Vector2(100 * dt, 0));
    super.update(dt);
  }

  @override
  Color backgroundColor() => Color.fromARGB(255, 25, 48, 97);
}

Wenn wir nun jedoch das Quadrat in der world bewegen, verschwindet es aus dem Viewport:

  @override
  void update(double dt) {
    rectangle.position += Vector2(100 * dt, 0);
    super.update(dt);
  }

Klar könnten wir die Kamera mitschwenken – dann sieht man wiederum keine Bewegung:

rectangle.position += Vector2(100 * dt, 0);
camera.moveBy(Vector2(100 * dt, 0));

Ich kann aber auch das Quadrat ruhen lassen und nur die Kamera schwenken – es würde dann so aussehen, als ob das Quadrat nach links wandert, aber in Wahrheit wandert die Kamera nach rechts.

Komponenten im Hintergrund fixieren

Um Komponenten im Hintergrund der Welt zu fixieren (für vorne würde man sie ja einfach dem Viewport adden), bin ich noch auf der Suche nach einer Lösung. Dies funktioniert nicht mehr:

rectangle.positionType = PositionType.viewport;

Anscheinend handelt es sich um einen Fehler – eine Möglichzeit zur Zeit ist, den Hintergrund direkt in das Game zu adden – add(background) – und sich um onResize u. ä. selbst zu kümmern. Ich habe das soge macht, ob ein rotes Rechteck in den Hintergrund zu legen:

1. Erstellen einer neuen Klasse BackgroundBox mit einer Resize-Methode. position oder size brauchen wir nicht übergeben, da sie immer bei 0,0 beginnt und sich dem Game-Fenster anpasst.

import 'dart:async';
import 'dart:ui';

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

class BackgroundBox extends RectangleComponent with HasGameRef {
  BackgroundBox();

  // set up the color for the frame
  final Paint rectPaint = Paint()
    ..style = PaintingStyle.fill
    ..color = Colors.red;

  @override
  FutureOr<void> onLoad() {
    position = Vector2.zero();
    size = game.size;
    paint = rectPaint;
    return super.onLoad();
  }

  @override
  void onGameResize(Vector2 size) {
    this.size = game.size;
    super.onGameResize(size);
  }
}

Diese rufen wir in unserer Game-Klasse auf:

  // set up a background
  final BackgroundBox background = BackgroundBox();
    
  // add the background to the world
  add(background);

In einem weiteren Artikel werden wir uns ansehen, wie man diese BackgroundBox durch einen parallaxen Hintergrund ersetzt.

1 Stern2 Sterne3 Sterne4 Sterne5 Sterne (1)

Loading…
Avatar von manuel

AUTOR

manuel