mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-02 03:15:43 +08:00
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:
@ -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.
|
||||
}
|
||||
|
||||
// ...
|
||||
```
|
||||
|
||||
@ -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 {
|
||||
|
||||

|
||||
|
||||
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(
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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.
|
||||
///
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user