Merge pull request #476 from flame-engine/erick.syncing-0.0.27-to-v1

Synchronising 0.27.0 to v1
This commit is contained in:
Luan Nico
2020-09-27 15:43:05 -04:00
committed by GitHub
82 changed files with 604 additions and 155 deletions

View File

@ -7,6 +7,13 @@
- Remove Position class in favor of new Vector2 extension
- Remove Box2D as a dependency
## 0.27.0
- Improved the accuracy of the `FPSCounter` by using Flutter's internal frame timings.
- Adding MouseMovementDetector
- Adding ScrollDetector
- Fixes BGM error
- Adding Isometric Tile Maps
## 0.26.0
- Improving Flame image auto cache
- Fix bug in the Box2DGame's add and addLater method , when the Component extends BodyComponent and mixin HasGameRef or other mixins ,the mixins will not be set correctly

View File

@ -18,7 +18,7 @@ Put the pub package as your dependency by dropping the following in your `pubspe
```yaml
dependencies:
flame: ^0.26.0
flame: ^0.27.0
```
And start using it!

View File

@ -239,6 +239,26 @@ Currently we have a very basic implementation of a Tiled component. This API use
An example of how to use the API can be found [here](/doc/examples/tiled).
# Isometric Tile Map Component
This component allows you to render an isometric map based on a cartesian matrix of blocks and an isometric tileset.
A simple example on how to use it:
```dart
// creates a tileset, the block ids are automatically assigned sequentially starting at 0, from left to right and then top to bottom.
final tileset = await IsometricTileset.load('tileset.png', 32);
// each element is a block id, -1 means nothing
final matrix = [[0, 1, 0], [1, 0, 0], [1, 1, 1]];
add(IsometricTileMapComponent(tileset, matrix));
```
It also provides methods for converting coordinates so you can handle clicks, hovers, render entities on top of tiles, add a selector, etc.
A more in-depth example can be found [here](/doc/examples/isometric).
![An example of a isometric map with selector](images/isometric.png)
# Nine Tile Box Component
A Nine Tile Box is a rectangle drawn using a grid sprite.

View File

@ -4,7 +4,7 @@ description: A sample Flame project to showcase the SpriteAnimationWidget widget
version: 0.1.0
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Flame sample game showcasing animations features
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Flame sample for using Aseprite animations
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -3,7 +3,7 @@ description: Flame example application showcasing the audiopool class
version: 0.1.0
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -1,9 +1,11 @@
#!/bin/bash -xe
rm -rf */build
rm -rf */android
rm -rf */ios
rm -rf */web
rm -rf */macos
rm -rf */test
rm -rf */.dart_tool
shopt -s globstar
rm -rf **/build
rm -rf **/android
rm -rf **/ios
rm -rf **/web
rm -rf **/macos
rm -rf **/test
rm -rf **/.dart_tool

View File

@ -4,7 +4,7 @@ description: Flame sample for using debug features
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Flame sample game showcasing combined effects
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Flame sample game showcasing infinite effects
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Flame sample game showcasing the sequence effect
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: A Flame game showcasing the use of the effects api
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -0,0 +1,54 @@
import 'package:flutter/material.dart';
import 'package:flame/game.dart';
import 'package:flame/gestures.dart';
import 'package:flame/palette.dart';
import 'package:flame/extensions/vector2.dart';
import 'package:flame/extensions/offset.dart';
void main() {
final game = MyGame();
runApp(game.widget);
}
class MyGame extends Game with MouseMovementDetector {
static const SPEED = 200;
Vector2 position = Vector2(0, 0);
Vector2 target;
final Paint _blue = Paint()..color = const Color(0xFF0000FF);
bool _onTarget = false;
@override
void onMouseMove(event) {
target = event.localPosition.toVector2();
}
Rect _toRect() => Rect.fromLTWH(
position.x,
position.y,
50,
50,
);
@override
void render(Canvas canvas) {
canvas.drawRect(
_toRect(),
_onTarget ? _blue : BasicPalette.white.paint,
);
}
@override
void update(double dt) {
if (target != null) {
_onTarget = _toRect().contains(target.toOffset());
if (!_onTarget) {
final dir = (target - position).normalized();
position += dir * (SPEED * dt);
}
}
}
}

View File

@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
import 'package:flame/game.dart';
import 'package:flame/gestures.dart';
import 'package:flame/palette.dart';
import 'package:flame/extensions/vector2.dart';
import 'package:flame/extensions/offset.dart';
void main() {
final game = MyGame();
runApp(game.widget);
}
class MyGame extends Game with ScrollDetector {
static const SPEED = 200;
Vector2 position = Vector2(0, 0);
Vector2 target;
@override
void onScroll(event) {
target = position - event.scrollDelta.toVector2();
}
@override
void render(Canvas canvas) {
canvas.drawRect(
Rect.fromLTWH(
position.x,
position.y,
50,
50,
),
BasicPalette.white.paint,
);
}
@override
void update(double dt) {
if (target != null) {
final dir = (target - position).normalized();
position += dir * (SPEED * dt);
}
}
}

View File

@ -4,7 +4,7 @@ description: A flame game showcasing the use of gestures callbacks
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Flame sample game on using the go flutter desktop framework
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 7fc14a55af64462763d28abfb4e610086c6e0f39
channel: dev
project_type: app

View File

@ -0,0 +1,3 @@
# isometric
A Flame game showcasing how to use the Isometric Tile Map component.

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,86 @@
import 'package:flame/components/sprite_component.dart';
import 'package:flame/extensions/vector2.dart';
import 'package:flame/extensions/offset.dart';
import 'package:flame/flame.dart';
import 'package:flame/game.dart';
import 'package:flame/components/isometric_tile_map_component.dart';
import 'package:flame/gestures.dart';
import 'package:flame/sprite.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
const x = 500.0;
const y = 500.0;
const s = 64;
final topLeft = Vector2(x, y);
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final size = await Flame.util.initialDimensions();
final game = MyGame(size);
runApp(game.widget);
}
class Selector extends SpriteComponent {
bool show = false;
Selector(double s)
: super.fromSprite(s, s, Sprite('selector.png', width: 32, height: 32));
@override
void render(Canvas canvas) {
if (!show) {
return;
}
super.render(canvas);
}
}
class MyGame extends BaseGame with MouseMovementDetector {
IsometricTileMapComponent base;
Selector selector;
MyGame(Vector2 size) {
init();
}
void init() async {
final tileset = await IsometricTileset.load('tiles.png', 32);
final matrix = [
[3, 1, 1, 1, 0, 0],
[-1, 1, 2, 1, 0, 0],
[-1, 0, 1, 1, 0, 0],
[-1, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 0, 2],
[1, 3, 3, 3, 0, 2],
];
add(
base = IsometricTileMapComponent(tileset, matrix, destTileSize: s)
..x = x
..y = y,
);
add(selector = Selector(s.toDouble()));
}
@override
void render(Canvas canvas) {
super.render(canvas);
canvas.drawRect(
const Rect.fromLTWH(x - 1, y - 1, 3, 3),
Paint()..color = const Color(0xFFFF00FF),
);
}
@override
void onMouseMove(PointerHoverEvent event) {
if (base == null || selector == null) {
return; // loading
}
final screenPosition = event.position.toVector2();
final block = base.getBlock(screenPosition);
selector.show = base.containsBlock(block);
selector.setPosition(base.getBlockPosition(block) + topLeft);
}
}

View File

@ -0,0 +1,22 @@
name: isometric
description: Example of isometric tilemap using Flame
version: 0.1.0
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
flame:
path: ../../../
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
assets:
- assets/images/tiles.png
- assets/images/selector.png

View File

@ -4,7 +4,7 @@ description: A flame game showcasing the use of joystick
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Simple Flame project showcasing how to use the Keyboard events
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Flame sample for using the nine_tile_box feature
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Flame sample game showcasing the parallax features
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Flame sample game showcasing particle effects
version: 1.0.0
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Flame sample game showcasing animations features
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -3,7 +3,7 @@ description: Flame example application showcasing the audio features
version: 0.1.0
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Showcasing SpriteBatch features
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Flame sample game showcasing rendering 500 sprites
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Flame sample game showcasing spritesheet features
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: A sample Flame project that renders texts.
version: 0.1.0
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: Example app using Timer class
version: 1.0.0+1
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: A Flutter project showcasing Flame's widgets.
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

View File

@ -4,7 +4,7 @@ description: A Flame game showcasing how to use the WithWidgetsOverlay feature
version: 1.0.0+1
environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:

BIN
doc/images/isometric.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -4,6 +4,8 @@
Inside `package:flame/gestures.dart` you can find a whole set of `mixin`s which can be included on your game class instance to be able to receive touch input events. Below you can see the full list of these `mixin`s and its methods:
## Touch and mouse detectors
```
- TapDetector
- onTap
@ -68,11 +70,19 @@ Inside `package:flame/gestures.dart` you can find a whole set of `mixin`s which
- onReceiveDrag
```
Mouse only events
```
- MouseMovementDetector
- onMouseMove
- ScrollDetector
- onScroll
```
Many of these detectors can conflict with each other. For example, you can't register both Vertical and Horizontal drags, so not all of them can be used together.
It is also not possible to mix advanced detectors (`MultiTouch*`) with basic detectors as they will *always win the gesture arena* and the basic detectors will never be triggered. So for example, you can use both `MultiTouchDragDetector` and `MultiTouchDragDetector` together, but if you try to use `MultiTouchTapDetector` and `PanDetector`, no events will be triggered for the later.
Flame's GestureApi is provided byt Flutter's Gestures Widgets, including [GestureDetector widget](https://api.flutter.dev/flutter/widgets/GestureDetector-class.html) and [RawGestureDetector widget](https://api.flutter.dev/flutter/widgets/RawGestureDetector-class.html), you can also read more about Flutter's gestures [here](https://api.flutter.dev/flutter/gestures/gestures-library.html).
Flame's GestureApi is provided byt Flutter's Gestures Widgets, including [GestureDetector widget](https://api.flutter.dev/flutter/widgets/GestureDetector-class.html), [RawGestureDetector widget](https://api.flutter.dev/flutter/widgets/RawGestureDetector-class.html) and [MouseRegion widget](https://api.flutter.dev/flutter/widgets/MouseRegion-class.html), you can also read more about Flutter's gestures [here](https://api.flutter.dev/flutter/gestures/gestures-library.html).
## Example

View File

@ -226,7 +226,7 @@ game.add(
ParticleComponent(
particle: SpriteParticle(
sprite: Sprite('sprite.png'),
size: Position(64, 64),
size: Vector2(64, 64),
)
)
);

View File

@ -1,6 +1,7 @@
import 'package:flutter/services.dart' show rootBundle;
import 'dart:typed_data';
import 'package:flutter/services.dart' show rootBundle;
/// A class that loads, and cache files
///
/// it automatically looks for files on the assets folder

View File

@ -1,9 +1,10 @@
import 'dart:io';
import 'package:audioplayers/audioplayers.dart';
import 'package:flame/flame.dart';
import 'package:flutter/widgets.dart';
import 'flame.dart';
/// The looping background music class.
///
/// This class helps with looping background music management that reacts to
@ -43,7 +44,7 @@ class Bgm extends WidgetsBindingObserver {
///
/// It is safe to call this function even when a current BGM track is
/// playing.
void play(String filename, {double volume}) async {
Future<void> play(String filename, {double volume}) async {
volume ??= 1;
if (audioPlayer != null && audioPlayer.state != AudioPlayerState.STOPPED) {
@ -51,14 +52,11 @@ class Bgm extends WidgetsBindingObserver {
}
isPlaying = true;
audioPlayer = await Flame.audio.loopLongAudio(
filename,
volume: volume,
);
audioPlayer = await Flame.audio.loopLongAudio(filename, volume: volume);
}
/// Stops the currently playing background music track (if any).
void stop() async {
Future<void> stop() async {
isPlaying = false;
if (audioPlayer != null) {
await audioPlayer.stop();
@ -66,28 +64,28 @@ class Bgm extends WidgetsBindingObserver {
}
/// Resumes the currently played (but resumed) background music.
void resume() {
Future<void> resume() async {
if (audioPlayer != null) {
isPlaying = true;
audioPlayer.resume();
await audioPlayer.resume();
}
}
/// Pauses the background music without unloading or resetting the audio
/// player.
void pause() {
Future<void> pause() async {
if (audioPlayer != null) {
isPlaying = false;
audioPlayer.pause();
await audioPlayer.pause();
}
}
/// Prefetch an audio and store it in the cache.
/// Pre-fetch an audio and store it in the cache.
///
/// Alias of `FlameAudio.load();`.
Future<File> load(String file) => Flame.audio.load(file);
/// Prefetch a list of audios and store them in the cache.
/// Pre-fetch a list of audios and store them in the cache.
///
/// Alias of `FlameAudio.loadAll();`.
Future<List<File>> loadAll(List<String> files) => Flame.audio.loadAll(files);
@ -98,8 +96,8 @@ class Bgm extends WidgetsBindingObserver {
void clear(String file) => Flame.audio.clear(file);
/// Clears all the audios in the cache.
/// Alias of `FlameAudio.clearAll();`.
///
/// Alias of `FlameAudio.clearAll();`.
void clearAll() => Flame.audio.clearAll();
/// Handler for AppLifecycleState changes.
@ -110,13 +108,11 @@ class Bgm extends WidgetsBindingObserver {
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
if (isPlaying &&
audioPlayer != null &&
audioPlayer.state == AudioPlayerState.PAUSED) {
if (isPlaying && audioPlayer?.state == AudioPlayerState.PAUSED) {
audioPlayer.resume();
}
} else {
audioPlayer.pause();
audioPlayer?.pause();
}
}
}

View File

@ -50,7 +50,7 @@ abstract class Component {
/// If two components share the same priority, they will probably be drawn in the order they were added.
int priority() => 0;
/// Called when the component has been added and preperad by the game instance.
/// Called when the component has been added and prepared by the game instance.
///
/// This can be used to make initializations on your component as, when this method is called,
/// things like resize (and other mixins) are already set and usable.

View File

@ -0,0 +1,156 @@
import 'dart:ui';
import 'package:flame/components/position_component.dart';
import '../flame.dart';
import '../sprite.dart';
import '../extensions/vector2.dart';
/// This represents an isometric tileset to be used in a tilemap.
///
/// It's basically a grid of squares, each square has a tile, in order.
/// The block ids are calculated going row per row, left to right, top to
/// bottom.
///
/// This class will cache the usage of sprites to improve performance.
class IsometricTileset {
/// The image for this tileset.
final Image tileset;
/// The size of each square block within the image.
///
/// The image width and height must be multiples of this number.
final int size;
final Map<int, Sprite> _spriteCache = {};
IsometricTileset(this.tileset, this.size);
/// Compute the number of columns the image has
/// by using the image width and tile size.
int get columns => tileset.width ~/ size;
/// Compute the number of rows the image has
/// by using the image height and tile size.
int get rows => tileset.height ~/ size;
/// Get a sprite to render one specific tile given its id.
///
/// The ids are assigned left to right, top to bottom, row per row.
/// The returned sprite will be cached, so don't modify it!
Sprite getTile(int tileId) {
return _spriteCache[tileId] ??= _computeTile(tileId);
}
Sprite _computeTile(int tileId) {
final i = tileId % columns;
final j = tileId ~/ columns;
final s = size.toDouble();
return Sprite.fromImage(tileset, x: s * i, y: s * j, width: s, height: s);
}
/// Load a tileset based on a file name.
static Future<IsometricTileset> load(String fileName, int size) async {
final image = await Flame.images.load(fileName);
return IsometricTileset(image, size);
}
}
/// This is just a pair of int, int.
///
/// Represents a position in a matrix, or in this case, on the tilemap.
class Block {
/// x and y coordinates on the matrix
int x, y;
Block(this.x, this.y);
@override
String toString() => '($x, $y)';
}
/// This component renders a tilemap, represented by an int matrix, given a
/// tileset, in witch the integers are the block ids.
///
/// It can change the scale of each block by using the optional destTileSize
/// property.
class IsometricTileMapComponent extends PositionComponent {
/// This is the tileset that will be used to render this map.
IsometricTileset tileset;
/// The positions of each block will be placed respecting this matrix.
List<List<int>> matrix;
/// Optionally provide a new tile size to render it scaled.
int destTileSize;
IsometricTileMapComponent(this.tileset, this.matrix, {this.destTileSize});
/// This is the size the tiles will be drawn (either original or overwritten).
int get effectiveTileSize => destTileSize ?? tileset.size;
@override
void render(Canvas c) {
super.render(c);
final size = Vector2(
effectiveTileSize.toDouble(),
effectiveTileSize.toDouble(),
);
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
final element = matrix[i][j];
if (element != -1) {
final sprite = tileset.getTile(element);
final p = getBlockPositionInts(j, i);
sprite.renderRect(c, p.toRect(size));
}
}
}
}
/// Get the position in witch a block must be in the isometric space.
///
/// This does not include the (x,y) PositionComponent offset!
Vector2 getBlockPosition(Block block) {
return getBlockPositionInts(block.x, block.y);
}
Vector2 getBlockPositionInts(int i, int j) {
final s = effectiveTileSize.toDouble() / 2;
return cartToIso(Vector2(i * s, j * s)) - Vector2(s, 0);
}
/// Converts a coordinate from the isometric space to the cartesian space.
Vector2 isoToCart(Vector2 p) {
final x = (2 * p.y + p.x) / 2;
final y = (2 * p.y - p.x) / 2;
return Vector2(x, y);
}
/// Converts a coordinate from the cartesian space to the isometric space.
Vector2 cartToIso(Vector2 p) {
final x = p.x - p.y;
final y = (p.x + p.y) / 2;
return Vector2(x, y);
}
/// Get what block is at isometric position p.
///
/// This can be used to handle clicks or hovers.
Block getBlock(Vector2 p) {
final s = effectiveTileSize.toDouble() / 2;
final cart = isoToCart(p - position);
final px = cart.x ~/ s;
final py = cart.y ~/ s;
return Block(px, py);
}
/// Return whether the matrix contains a block in its bounds.
bool containsBlock(Block block) {
return block.x >= 0 &&
block.x < matrix.length &&
block.y >= 0 &&
block.y < matrix[block.x].length;
}
}

View File

@ -1,10 +1,10 @@
import 'dart:math';
import 'dart:ui';
import 'package:flame/components/joystick/joystick_component.dart';
import 'package:flame/components/joystick/joystick_events.dart';
import 'package:flame/gestures.dart';
import 'package:flame/sprite.dart';
import 'joystick_component.dart';
import 'joystick_events.dart';
import '../../gestures.dart';
import '../../sprite.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

View File

@ -1,13 +1,13 @@
import 'dart:ui';
import '../../extensions/vector2.dart';
import '../../game/base_game.dart';
import '../../gestures.dart';
import '../component.dart';
import '../mixins/has_game_ref.dart';
import 'joystick_action.dart';
import 'joystick_directional.dart';
import 'joystick_events.dart';
import '../component.dart';
import '../mixins/has_game_ref.dart';
import '../../game/base_game.dart';
import '../../gestures.dart';
import '../../extensions/vector2.dart';
mixin JoystickListener {
void joystickChangeDirectional(JoystickDirectionalEvent event);

View File

@ -1,13 +1,13 @@
import 'dart:math';
import 'package:flame/components/joystick/joystick_component.dart';
import 'package:flame/components/joystick/joystick_events.dart';
import 'package:flame/gestures.dart';
import 'package:flame/sprite.dart';
import 'package:flutter/material.dart';
import '../../extensions/offset.dart';
import '../../extensions/vector2.dart';
import '../../gestures.dart';
import '../../sprite.dart';
import 'joystick_component.dart';
import 'joystick_events.dart';
class JoystickDirectional {
final double size;

View File

@ -1,11 +1,11 @@
import 'dart:async';
import 'dart:ui';
import 'package:flame/extensions/vector2.dart';
import 'package:flame/extensions/rect.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart';
import '../extensions/vector2.dart';
import '../extensions/rect.dart';
import '../flame.dart';
import 'position_component.dart';

View File

@ -1,4 +1,5 @@
import 'dart:ui';
import './component.dart';
import '../time.dart';

View File

@ -1,10 +1,10 @@
import 'dart:math';
import 'package:flutter/animation.dart';
import 'package:meta/meta.dart';
import 'dart:math';
import '../extensions/vector2.dart';
import './effects.dart';
import 'effects.dart';
double _direction(double p, double d) => (p - d).sign;
double _distance(double a, double b) => (a - b).abs();

View File

@ -2,7 +2,7 @@ import 'package:flutter/animation.dart';
import 'package:meta/meta.dart';
import '../extensions/vector2.dart';
import './effects.dart';
import 'effects.dart';
double _direction(double p, double d) => (p - d).sign;
double _length(double a, double b) => (a - b).abs();

View File

@ -1,7 +1,7 @@
import 'package:meta/meta.dart';
import './effects.dart';
import '../components/position_component.dart';
import 'effects.dart';
class SequenceEffect extends PositionComponentEffect {
final List<PositionComponentEffect> effects;

View File

@ -15,6 +15,6 @@ extension OffsetExtension on Offset {
/// Creates a [Point] from the [Offset]
Point toPoint() => Point(dx, dy);
/// Creates a [Rect] starting in origo and going the [Offset]
/// Creates a [Rect] starting in origin and going the [Offset]
Rect toRect() => Rect.fromLTWH(0, 0, dx, dy);
}

View File

@ -15,10 +15,10 @@ extension Vector2Extension on Vector2 {
/// Creates a [Point] from the [Vector2]
Point toPoint() => Point(x, y);
/// Creates a [Rect] starting from [x, y] and going the [Vector2]
/// Creates a [Rect] starting from [x, y] and having size [to].
Rect toRect(Vector2 to) => Rect.fromLTWH(x, y, to.x, to.y);
/// Creates a [Rect] starting in origo and going the [Vector2]
/// Creates a [Rect] starting in origin and having size [to].
Rect toOriginRect() => Rect.fromLTWH(0, 0, x, y);
/// Linearly interpolate towards another Vector2

View File

@ -4,10 +4,10 @@ import 'package:audioplayers/audio_cache.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'flame_audio.dart';
import 'bgm.dart';
import 'images.dart';
import 'assets_cache.dart';
import 'bgm.dart';
import 'flame_audio.dart';
import 'images.dart';
import 'util.dart';
/// This class holds static references to some useful objects to use in your game.

View File

@ -1,9 +1,8 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:audioplayers/audio_cache.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/foundation.dart';
/// Handles flame audio functions
class FlameAudio {

View File

@ -1,10 +1,11 @@
import 'dart:ui';
import 'dart:math';
import 'dart:ui';
import "flame.dart";
import "package:flare_flutter/flare.dart";
import "package:flare_flutter/flare_actor.dart";
import "flame.dart";
@Deprecated("Use flame_flare package instead")
class FlareAnimation {
final FlutterActorArtboard _artboard;

View File

@ -1,39 +1,33 @@
import 'dart:math' as math;
import 'package:flutter/scheduler.dart';
import 'game/game.dart';
mixin FPSCounter on Game {
/// List of deltas used in debug mode to calculate FPS
final List<double> _dts = [];
const _maxFrames = 60;
const frameInterval =
Duration(microseconds: Duration.microsecondsPerSecond ~/ _maxFrames);
/// Returns whether this [Game] is should record fps or not
mixin FPSCounter on Game {
List<FrameTiming> _previousTimings = [];
@override
void onTimingsCallback(List<FrameTiming> timings) =>
_previousTimings = timings;
/// Returns whether this [Game] is should record fps or not.
///
/// Returns `false` by default. Override to use the `fps` counter method.
/// In recording fps, the [recordDt] method actually records every `dt` for statistics.
/// Then, you can use the [fps] method to check the game FPS.
@Deprecated('Flame is now using Flutter frame times, will be removed in v1')
bool recordFps();
/// This is a hook that comes from the RenderBox to allow recording of render times and statistics.
@override
void recordDt(double dt) {
if (recordFps()) {
_dts.add(dt);
}
}
/// Returns the average FPS for the last [average] measures.
///
/// The values are only saved if in debug mode (override [recordFps] to use this).
/// Selects the last [average] dts, averages then, and returns the inverse value.
/// So it's technically updates per second, but the relation between updates and renders is 1:1.
/// Returns 0 if empty.
/// Returns the FPS based on the frame times from [onTimingsCallback].
double fps([int average = 1]) {
final List<double> dts = _dts.sublist(math.max(0, _dts.length - average));
if (dts.isEmpty) {
return 0.0;
}
final double dtSum = dts.reduce((s, t) => s + t);
final double averageDt = dtSum / average;
return 1 / averageDt;
return _previousTimings.length *
_maxFrames /
_previousTimings.map((t) {
return (t.totalSpan.inMicroseconds ~/ frameInterval.inMicroseconds) +
1;
}).fold(0, (a, b) => a + b);
}
}

View File

@ -1,3 +1,3 @@
// Keeping compatible with earlier versions of Flame
export './game/game.dart';
export './game/base_game.dart';
export './game/game.dart';

View File

@ -1,7 +1,6 @@
import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flame/fps_counter.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart' hide WidgetBuilder;
import 'package:ordered_set/comparing.dart';
@ -12,6 +11,7 @@ import '../components/mixins/has_game_ref.dart';
import '../components/mixins/tapable.dart';
import '../components/position_component.dart';
import '../extensions/vector2.dart';
import '../fps_counter.dart';
import 'game.dart';
/// This is a more complete and opinionated implementation of Game.

View File

@ -2,8 +2,8 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart' hide WidgetBuilder;
import '../extensions/vector2.dart';
import 'game_render_box.dart';
import 'game.dart';
import 'game_render_box.dart';
/// This a widget to embed a game inside the Widget tree. You can use it in pair with [BaseGame] or any other more complex [Game], as desired.
///

View File

@ -1,15 +1,14 @@
import 'dart:ui';
import 'dart:async';
import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart' hide WidgetBuilder;
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import '../keyboard.dart';
import 'package:flutter/widgets.dart' hide WidgetBuilder;
import '../extensions/vector2.dart';
import '../keyboard.dart';
import 'widget_builder.dart';
/// Represents a generic game.
@ -45,8 +44,12 @@ abstract class Game {
void lifecycleStateChange(AppLifecycleState state) {}
/// Used for debugging
@Deprecated('Gets called for backward compatibility, will be removed in v1')
void recordDt(double dt) {}
/// Use for caluclating the FPS.
void onTimingsCallback(List<FrameTiming> timings) {}
/// Returns the game widget. Put this in your structure to start rendering and updating the game.
/// You can add it directly to the runApp method or inside your widget structure (if you use vanilla screens and widgets).
Widget get widget => builder.build(this);

View File

@ -6,8 +6,8 @@ import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart' hide WidgetBuilder;
import '../extensions/size.dart';
import 'game_loop.dart';
import 'game.dart';
import 'game_loop.dart';
class GameRenderBox extends RenderBox with WidgetsBindingObserver {
BuildContext context;
@ -16,6 +16,7 @@ class GameRenderBox extends RenderBox with WidgetsBindingObserver {
GameRenderBox(this.context, this.game) {
gameLoop = GameLoop(gameLoopCallback);
WidgetsBinding.instance.addTimingsCallback(game.onTimingsCallback);
}
@override
@ -54,6 +55,7 @@ class GameRenderBox extends RenderBox with WidgetsBindingObserver {
if (!attached) {
return;
}
// ignore: deprecated_member_use_from_same_package
game.recordDt(dt);
game.update(dt);
markNeedsPaint();

View File

@ -1,8 +1,8 @@
import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
import '../gestures.dart';
import '../components/mixins/tapable.dart';
import '../gestures.dart';
import 'embedded_game_widget.dart';
import 'game.dart';
@ -22,6 +22,9 @@ bool _hasAdvancedGesturesDetectors(Game game) =>
game is MultiTouchDragDetector ||
game is HasTapableComponents;
bool _hasMouseDetectors(Game game) =>
game is MouseMovementDetector || game is ScrollDetector;
class _GenericTapEventHandler {
void Function(int pointerId) onTap;
void Function(int pointerId) onTapCancel;
@ -204,6 +207,19 @@ Widget _applyBasicGesturesDetectors(Game game, Widget child) {
);
}
Widget _applyMouseDetectors(game, Widget child) {
return MouseRegion(
child: Listener(
child: child,
onPointerSignal: (event) =>
game is ScrollDetector && event is PointerScrollEvent
? game.onScroll(event)
: null,
),
onHover: game is MouseMovementDetector ? game.onMouseMove : null,
);
}
class WidgetBuilder {
Offset offset = Offset.zero;
@ -224,6 +240,10 @@ class WidgetBuilder {
widget = _applyAdvancedGesturesDetectors(game, widget);
}
if (_hasMouseDetectors(game)) {
widget = _applyMouseDetectors(game, widget);
}
return widget;
}
}

View File

@ -99,3 +99,11 @@ mixin ScaleDetector on Game {
void onScaleUpdate(ScaleUpdateDetails details) {}
void onScaleEnd(ScaleEndDetails details) {}
}
mixin MouseMovementDetector on Game {
void onMouseMove(PointerHoverEvent event) {}
}
mixin ScrollDetector on Game {
void onScroll(PointerScrollEvent event) {}
}

View File

@ -1,9 +1,9 @@
import 'dart:async';
import 'dart:convert' show base64;
import 'dart:typed_data';
import 'dart:ui';
import 'dart:convert' show base64;
import 'package:flame/flame.dart';
import 'flame.dart';
class Images {
Map<String, ImageAssetLoader> loadedFiles = {};

View File

@ -1,4 +1,5 @@
import 'package:flutter/services.dart';
import './game.dart';
mixin KeyboardEvents on Game {

View File

@ -1,7 +1,9 @@
import 'package:meta/meta.dart';
import 'dart:ui';
import 'package:meta/meta.dart';
import './processors.dart';
export './processors.dart';
abstract class Layer {

View File

@ -1,8 +1,8 @@
import 'dart:ui';
import 'package:flame/palette.dart';
import 'package:flame/sprite.dart';
import 'package:flame/extensions/vector2.dart';
import 'extensions/vector2.dart';
import 'palette.dart';
import 'sprite.dart';
/// This allows you to create a rectangle textured with a 9-sliced image.
///

View File

@ -1,17 +1,17 @@
import 'dart:math';
import 'dart:ui';
import 'package:flame/components/particle_component.dart';
import 'package:flame/particles/accelerated_particle.dart';
import 'package:flame/particles/moving_particle.dart';
import 'package:flame/particles/rotating_particle.dart';
import 'package:flame/particles/scaled_particle.dart';
import 'package:flame/particles/translated_particle.dart';
import 'package:flutter/animation.dart';
import 'package:flutter/foundation.dart';
import 'components/component.dart';
import 'components/particle_component.dart';
import 'particles/accelerated_particle.dart';
import 'particles/composed_particle.dart';
import 'particles/moving_particle.dart';
import 'particles/rotating_particle.dart';
import 'particles/scaled_particle.dart';
import 'particles/translated_particle.dart';
import 'time.dart';
/// A function which returns [Particle] when called

View File

@ -2,9 +2,9 @@ import 'dart:ui';
import 'package:flutter/foundation.dart';
import '../particle.dart';
import '../components/component.dart';
import '../extensions/vector2.dart';
import '../particle.dart';
class ComponentParticle extends Particle {
final Component component;

View File

@ -1,8 +1,9 @@
import 'dart:ui';
import 'package:flame/particle.dart';
import 'package:flutter/foundation.dart';
import '../particle.dart';
/// A single [Particle] which manages multiple children
/// by proxying all lifecycle hooks.
class ComposedParticle extends Particle {

View File

@ -3,8 +3,8 @@ import 'dart:ui';
import 'package:flutter/animation.dart';
import 'package:flutter/foundation.dart';
import '../particle.dart';
import '../components/mixins/single_child_particle.dart';
import '../particle.dart';
import '../particles/curved_particle.dart';
/// Statically offset given child [Particle] by given [Offset]

View File

@ -1,6 +1,5 @@
import 'dart:ui';
import 'dart:async';
import 'dart:ui';
import 'flame.dart';
import 'palette.dart';

View File

@ -1,9 +1,9 @@
import 'dart:ui';
import 'package:meta/meta.dart';
import 'sprite.dart';
import 'sprite_animation.dart';
import 'dart:ui';
/// Utility class to help extract animations and sprites from a spritesheet image
class SpriteSheet {
int textureWidth;

View File

@ -1,8 +1,9 @@
import 'dart:ui';
import 'package:flame/components/text_component.dart';
import 'package:flutter/material.dart' as material;
import 'anchor.dart';
import 'components/text_component.dart';
import 'memory_cache.dart';
import 'extensions/size.dart';
import 'extensions/vector2.dart';

View File

@ -1,9 +1,9 @@
import 'dart:async';
import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart';
import 'extensions/size.dart';
import 'extensions/vector2.dart';

View File

@ -1,10 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flame/sprite_animation.dart';
import 'dart:math';
import 'package:flutter/material.dart' hide Animation;
import 'package:flame/sprite_animation.dart';
import '../anchor.dart';
import './sprite_widget.dart';
import '../sprite_animation.dart';
import 'sprite_widget.dart';
/// A [StatefulWidget] that render a [SpriteAnimation].
class SpriteAnimationWidget extends StatefulWidget {

View File

@ -1,8 +1,10 @@
import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart' as widgets;
import 'package:meta/meta.dart';
import '../sprite.dart';
import 'dart:ui';
class _Painter extends widgets.CustomPainter {
final Image image;

View File

@ -1,7 +1,8 @@
import 'package:flutter/widgets.dart';
import '../sprite.dart';
import 'package:meta/meta.dart';
import '../sprite.dart';
class SpriteButton extends StatefulWidget {
final VoidCallback onPressed;
final Widget label;

View File

@ -1,10 +1,11 @@
import 'package:flame/widgets/animation_widget.dart';
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import 'dart:math';
import '../sprite.dart';
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart';
import '../anchor.dart';
import '../sprite.dart';
import 'animation_widget.dart';
/// A [StatefulWidget] that renders a still [Sprite].
///

View File

@ -1,6 +1,6 @@
name: flame
description: A minimalist Flutter game engine, provides a nice set of somewhat independent modules you can choose from.
version: 0.26.0
version: 0.27.0
homepage: https://github.com/flame-engine/flame
dependencies: