refactor: Game is now a class, not a mixin (#1751)

This simple refactor allows us to write class MyGame extends Game, instead of a more awkward class MyGame with Game. However, using ... with Game still continues to work, so no changes necessary for the users.
This commit is contained in:
Pasha Stetsenko
2022-06-25 14:32:32 -07:00
committed by GitHub
parent 20f169cadb
commit 5225a4ebd5
20 changed files with 54 additions and 57 deletions

View File

@ -152,13 +152,16 @@ calling certain camera methods yourself. Let's say we have the following game st
want to add the camera functionality:
```dart
class YourGame with Game {
class YourGame extends Game {
Camera? camera;
@override
Future<void> onLoad() async {}
@override
void render(Canvas canvas) {}
@override
void update(double dt) {}
}
```
@ -166,8 +169,7 @@ class YourGame with Game {
We first create a new camera instance on load and assign our game as the reference:
```dart
// ...
@override
Future<void> onLoad() async {
camera = Camera();
@ -179,19 +181,16 @@ We first create a new camera instance on load and assign our game as the referen
// Rest of your on load code.
}
// ...
```
The camera can also be made aware of which position to follow, this is an optional feature as you
can also use the camare for just moving,snapping or shaking.
can also use the camera for just moving,snapping or shaking.
To do this the `Camera` class provides multiple methods for it but let's showcase the simplest one
and that is the `followVector2`:
```dart
// Somewhere in your code.
// Somewhere in your code:
camera?.followVector2(
yourPositionToFollow,
worldBounds: yourWorldBounds, // Optional to pass, it will overwrite the previous bounds.
@ -202,28 +201,22 @@ Now that the camera is created and it is aware of both the world bounds and the
follow, it can be used to translate the canvas in the render method:
```dart
// ...
@override
void render(Canvas canvas) {
camera?.apply(canvas); // This will apply the camera transformation.
// Rest of your rendering code.
}
// ...
```
The only thing left to do is to call the `update` method on the `Camera` so it can smoothly follow
your given position:
```dart
// ...
@override
void update(double dt) {
camera?.update(dt);
// Rest of your update code.
}
// ...
```

View File

@ -41,10 +41,12 @@ main() {
}
```
**Note:** If you instantiate your game in a build method your game will be rebuilt every time the
```{note}
If you instantiate your game in a build method your game will be rebuilt every time the
Flutter tree gets rebuilt, which usually is more often than you'd like. To avoid this, you can
instead create an instance of your game first and reference it within your widget structure, like
it is done in the example above.
```
To remove components from the list on a `FlameGame` the `remove` or `removeAll` methods can be used.
The first can be used if you just want to remove one component, and the second can be used when you
@ -123,7 +125,7 @@ class MyGame extends FlameGame with SingleGameInstance {
![Game low-level API](../images/game_mixin.png)
The `Game` mixin is a low-level API that can be used when you want to implement the functionality of
The `Game` class is a low-level API that can be used when you want to implement the functionality of
how the game engine should be structured. `Game` does not implement any `update` or
`render` function for example.
@ -133,13 +135,15 @@ called from the `GameWidget` (or another parent) when the game is loaded + mount
called after `onLoad`) is called every time it is added to a new parent. `onRemove` is called when
the class is removed from a parent.
**Note**: The `Game` mixin allows for more freedom of how to implement things, but you are also
```{note}
The `Game` class allows for more freedom of how to implement things, but you are also
missing out on all of the built-in features in Flame if you use it.
```
An example of how a `Game` implementation could look like:
```dart
class MyGameSubClass with Game {
class MyGameSubClass extends Game {
@override
void render(Canvas canvas) {
// ...
@ -151,7 +155,7 @@ class MyGameSubClass with Game {
}
}
main() {
void main() {
final myGame = MyGameSubClass();
runApp(
GameWidget(

View File

@ -2,7 +2,7 @@ import 'package:flame/extensions.dart';
import 'package:flame/game.dart';
import 'package:flame/parallax.dart';
class NoFCSParallaxExample with Game {
class NoFCSParallaxExample extends Game {
static const String description = '''
This examples serves to test the Parallax feature outside of the Flame
Component System (FCS), use the other files in this folder for examples on

View File

@ -4,7 +4,7 @@ import 'package:flame/palette.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
class NoFlameGameExample with Game, KeyboardEvents {
class NoFlameGameExample extends Game with KeyboardEvents {
static const String description = '''
This example showcases how to create a game without the FlameGame.
It also briefly showcases how to act on keyboard events.

View File

@ -5,9 +5,9 @@ export 'src/extensions/vector2.dart';
export 'src/game/camera/camera.dart';
export 'src/game/camera/viewport.dart';
export 'src/game/flame_game.dart';
export 'src/game/game.dart';
export 'src/game/game_widget/game_widget.dart';
export 'src/game/mixins/fps_counter.dart';
export 'src/game/mixins/game.dart';
export 'src/game/mixins/has_draggables.dart';
export 'src/game/mixins/has_hoverables.dart';
export 'src/game/mixins/has_tappables.dart';

View File

@ -7,7 +7,7 @@ import 'package:flame/src/components/component_set.dart';
import 'package:flame/src/components/mixins/coordinate_transform.dart';
import 'package:flame/src/components/position_type.dart';
import 'package:flame/src/game/flame_game.dart';
import 'package:flame/src/game/mixins/game.dart';
import 'package:flame/src/game/game.dart';
import 'package:flame/src/gestures/events.dart';
import 'package:flame/src/text/text_paint.dart';
import 'package:flutter/painting.dart';

View File

@ -1,5 +1,5 @@
import 'package:flame/src/events/interfaces/multi_drag_listener.dart';
import 'package:flame/src/game/mixins/game.dart';
import 'package:flame/src/game/game.dart';
import 'package:flutter/gestures.dart';
import 'package:meta/meta.dart';

View File

@ -1,6 +1,6 @@
import 'package:flame/src/events/flame_game_mixins/has_draggable_components.dart';
import 'package:flame/src/events/interfaces/multi_drag_listener.dart';
import 'package:flame/src/game/mixins/game.dart';
import 'package:flame/src/game/game.dart';
import 'package:flame/src/gestures/events.dart';
import 'package:flutter/gestures.dart';

View File

@ -1,6 +1,6 @@
import 'package:flame/src/events/flame_game_mixins/has_tappable_components.dart';
import 'package:flame/src/events/interfaces/multi_tap_listener.dart';
import 'package:flame/src/game/mixins/game.dart';
import 'package:flame/src/game/game.dart';
import 'package:flame/src/gestures/events.dart';
import 'package:flutter/gestures.dart';

View File

@ -4,7 +4,7 @@ import 'package:flame/src/events/flame_game_mixins/has_tappable_components.dart'
import 'package:flame/src/events/messages/position_event.dart';
import 'package:flame/src/events/messages/tap_cancel_event.dart';
import 'package:flame/src/events/messages/tap_up_event.dart';
import 'package:flame/src/game/mixins/game.dart';
import 'package:flame/src/game/game.dart';
import 'package:flame/src/gestures/events.dart';
import 'package:flutter/gestures.dart';

View File

@ -1,7 +1,7 @@
import 'package:flame/extensions.dart';
import 'package:flame/src/events/messages/position_event.dart';
import 'package:flame/src/events/messages/tap_down_event.dart';
import 'package:flame/src/game/mixins/game.dart';
import 'package:flame/src/game/game.dart';
import 'package:flame/src/gestures/events.dart';
import 'package:flutter/gestures.dart';

View File

@ -4,7 +4,7 @@ import 'package:flame/src/components/component.dart';
import 'package:flame/src/extensions/vector2.dart';
import 'package:flame/src/game/camera/camera.dart';
import 'package:flame/src/game/camera/camera_wrapper.dart';
import 'package:flame/src/game/mixins/game.dart';
import 'package:flame/src/game/game.dart';
import 'package:flame/src/game/projector.dart';
import 'package:meta/meta.dart';

View File

@ -10,11 +10,11 @@ import 'package:meta/meta.dart';
/// This gives access to a low-level game API, to not build everything from a
/// low level `FlameGame` should be used.
///
/// Add this mixin to your game class and implement the [update] and [render]
/// methods to use it in a `GameWidget`.
/// Flame will deal with calling these methods properly when the game's widget
/// is rendered.
mixin Game {
/// You can either extend this class, or add it as a mixin.
///
/// Methods [update] and [render] need to be implemented in order to connect
/// your class with the internal game loop.
abstract class Game {
final images = Images();
final assets = AssetsCache();

View File

@ -1,5 +1,5 @@
import 'package:flame/src/game/game.dart';
import 'package:flame/src/game/game_loop.dart';
import 'package:flame/src/game/mixins/game.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart' hide WidgetBuilder;
//ignore_for_file: unnecessary_non_null_assertion

View File

@ -2,9 +2,9 @@ import 'dart:async';
import 'package:flame/extensions.dart';
import 'package:flame/input.dart';
import 'package:flame/src/game/game.dart';
import 'package:flame/src/game/game_render_box.dart';
import 'package:flame/src/game/game_widget/gestures.dart';
import 'package:flame/src/game/mixins/game.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';

View File

@ -1,6 +1,6 @@
import 'package:flame/events.dart';
import 'package:flame/src/events/flame_drag_adapter.dart';
import 'package:flame/src/game/mixins/game.dart';
import 'package:flame/src/game/game.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';

View File

@ -1,5 +1,5 @@
import 'package:flame/src/components/component.dart';
import 'package:flame/src/game/mixins/game.dart';
import 'package:flame/src/game/game.dart';
/// Mixin that declares a [Game] class as a singleton.
///

View File

@ -1,4 +1,4 @@
import 'package:flame/src/game/mixins/game.dart';
import 'package:flame/src/game/game.dart';
import 'package:flame/src/gestures/events.dart';
import 'package:flutter/gestures.dart';

View File

@ -1,5 +1,5 @@
import 'package:flame/extensions.dart';
import 'package:flame/src/game/mixins/game.dart';
import 'package:flame/src/game/game.dart';
import 'package:flutter/gestures.dart';
/// [EventPosition] converts position based events to three different coordinate

View File

@ -10,7 +10,7 @@ import 'package:oxygen/oxygen.dart';
/// [OxygenGame] should be extended to add your own game logic.
///
/// It is based on the Oxygen package.
abstract class OxygenGame with Game {
abstract class OxygenGame extends Game {
late final FlameWorld world;
OxygenGame() {