Merge pull request #411 from flame-engine/develop

0.24.0 RC
This commit is contained in:
Erick
2020-07-02 20:02:15 -03:00
committed by GitHub
25 changed files with 115 additions and 281 deletions

View File

@@ -1,5 +1,11 @@
# CHANGELOG # CHANGELOG
## 0.24.0
- Outsourcing SVG support to an external package
- Adding MemoryCache class
- Fixing games crashes on Web
- Update tiled dependency to 0.6.0 (objects' properties are now double)
## 0.23.0 ## 0.23.0
- Add Joystick Component - Add Joystick Component
- Adding BaseGame#markToRemove - Adding BaseGame#markToRemove

View File

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

View File

@@ -1,11 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 105">
<g fill="#97C024" stroke="#97C024" stroke-linejoin="round" stroke-linecap="round">
<path d="M14,40v24M81,40v24M38,68v24M57,68v24M28,42v31h39v-31z" stroke-width="12"/>
<path d="M32,5l5,10M64,5l-6,10 " stroke-width="2"/>
</g>
<path d="M22,35h51v10h-51zM22,33c0-31,51-31,51,0" fill="#97C024"/>
<g fill="#FFF">
<circle cx="36" cy="22" r="2"/>
<circle cx="59" cy="22" r="2"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 471 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -1,8 +1,7 @@
import 'package:flame/game.dart'; import 'package:flame/game.dart';
import 'package:flame/flame.dart'; import 'package:flame/flame.dart';
import 'package:flame/svg.dart';
import 'package:flame/position.dart'; import 'package:flame/position.dart';
import 'package:flame/components/component.dart' show SvgComponent; import 'package:flame/components/component.dart';
import 'package:flame/components/mixins/resizable.dart'; import 'package:flame/components/mixins/resizable.dart';
import 'package:flame/text_config.dart'; import 'package:flame/text_config.dart';
@@ -16,12 +15,12 @@ void main() async {
myGame.start(); myGame.start();
} }
class AndroidComponent extends SvgComponent with Resizable { class AndroidComponent extends SpriteComponent with Resizable {
static const int SPEED = 150; static const int SPEED = 150;
int xDirection = 1; int xDirection = 1;
int yDirection = 1; int yDirection = 1;
AndroidComponent() : super.fromSvg(100, 100, Svg('android.svg')); AndroidComponent() : super.square(100, 'android.png');
@override @override
void update(double dt) { void update(double dt) {
@@ -49,7 +48,7 @@ class AndroidComponent extends SvgComponent with Resizable {
} }
class MyGame extends BaseGame { class MyGame extends BaseGame {
final fpsTextConfig = const TextConfig(color: const Color(0xFFFFFFFF)); final fpsTextConfig = TextConfig(color: const Color(0xFFFFFFFF));
@override @override
bool debugMode() => true; bool debugMode() => true;

View File

@@ -18,4 +18,4 @@ dev_dependencies:
flutter: flutter:
assets: assets:
- assets/android.svg - assets/images/android.png

View File

@@ -16,8 +16,7 @@ void main() {
} }
class MyGame extends BaseGame with TapDetector { class MyGame extends BaseGame with TapDetector {
final TextConfig fpsTextConfig = final TextConfig fpsTextConfig = TextConfig(color: const Color(0xFFFFFFFF));
const TextConfig(color: const Color(0xFFFFFFFF));
final paint = Paint()..color = const Color(0xFFE5E5E5E5); final paint = Paint()..color = const Color(0xFFE5E5E5E5);
final List<String> _animations = ["Stand", "Wave", "Jump", "Dance"]; final List<String> _animations = ["Stand", "Wave", "Jump", "Dance"];

View File

@@ -43,7 +43,7 @@ class MyGame extends BaseGame {
final Random rnd = Random(); final Random rnd = Random();
final StepTween steppedTween = StepTween(begin: 0, end: 5); final StepTween steppedTween = StepTween(begin: 0, end: 5);
final trafficLight = TrafficLightComponent(); final trafficLight = TrafficLightComponent();
final TextConfig fpsTextConfig = const TextConfig( final TextConfig fpsTextConfig = TextConfig(
color: const Color(0xFFFFFFFF), color: const Color(0xFFFFFFFF),
); );

View File

@@ -1,70 +0,0 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# Visual Studio Code related
.vscode/
# Flutter/Dart/Pub related
**/doc/api/
.dart_tool/
.flutter-plugins
.packages
.pub-cache/
.pub/
/build/
# Android related
**/android/**/gradle-wrapper.jar
**/android/.gradle
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
# iOS/XCode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!**/ios/**/default.mode1v3
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages

View File

@@ -1,10 +0,0 @@
# 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: f91df4abe1427fef8862c9e81b2e5af6fc05a67a
channel: dev
project_type: app

View File

@@ -1,3 +0,0 @@
# svg
A sample Flame game showcasing hot to use Flame's SVG components

View File

@@ -1,11 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 105">
<g fill="#97C024" stroke="#97C024" stroke-linejoin="round" stroke-linecap="round">
<path d="M14,40v24M81,40v24M38,68v24M57,68v24M28,42v31h39v-31z" stroke-width="12"/>
<path d="M32,5l5,10M64,5l-6,10 " stroke-width="2"/>
</g>
<path d="M22,35h51v10h-51zM22,33c0-31,51-31,51,0" fill="#97C024"/>
<g fill="#FFF">
<circle cx="36" cy="22" r="2"/>
<circle cx="59" cy="22" r="2"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 471 B

View File

@@ -1,38 +0,0 @@
import 'package:flame/game.dart';
import 'package:flame/svg.dart';
import 'package:flame/position.dart';
import 'package:flame/components/component.dart' show SvgComponent;
import 'package:flutter/material.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
final game = MyGame();
runApp(game.widget);
}
class MyGame extends BaseGame {
Svg svgInstance;
SvgComponent android;
MyGame() {
_start();
}
void _start() {
svgInstance = Svg('android.svg');
android = SvgComponent.fromSvg(100, 100, svgInstance);
android.x = 100;
android.y = 100;
add(android);
}
@override
void render(Canvas canvas) {
super.render(canvas);
svgInstance.renderPosition(canvas, Position(100, 200), 300, 300);
}
}

View File

@@ -1,21 +0,0 @@
name: svg
description: Flame sample for using SVG images
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
flame:
path: ../../../
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
assets:
- assets/android.svg

View File

@@ -19,8 +19,7 @@ TextConfig tiny = regular.withFontSize(12.0);
class MyTextBox extends TextBoxComponent { class MyTextBox extends TextBoxComponent {
MyTextBox(String text) MyTextBox(String text)
: super(text, : super(text, config: tiny, boxConfig: TextBoxConfig(timePerChar: 0.05));
config: tiny, boxConfig: const TextBoxConfig(timePerChar: 0.05));
@override @override
void drawBackground(Canvas c) { void drawBackground(Canvas c) {

View File

@@ -33,8 +33,7 @@ class GameWidget extends StatelessWidget {
} }
class RenderedTimeComponent extends TimerComponent { class RenderedTimeComponent extends TimerComponent {
final TextConfig textConfig = final TextConfig textConfig = TextConfig(color: const Color(0xFFFFFFFF));
const TextConfig(color: const Color(0xFFFFFFFF));
RenderedTimeComponent(Timer timer) : super(timer); RenderedTimeComponent(Timer timer) : super(timer);
@@ -58,8 +57,7 @@ class MyBaseGame extends BaseGame with TapDetector, DoubleTapDetector {
} }
class MyGame extends Game with TapDetector { class MyGame extends Game with TapDetector {
final TextConfig textConfig = final TextConfig textConfig = TextConfig(color: const Color(0xFFFFFFFF));
const TextConfig(color: const Color(0xFFFFFFFF));
Timer countdown; Timer countdown;
Timer interval; Timer interval;

View File

@@ -68,7 +68,9 @@ See example [here](/doc/examples/sprite_batch).
Flame provides a simple API to render SVG images in your game. Flame provides a simple API to render SVG images in your game.
To use it just import the `Svg` class from `'package:flame/svg.dart'`, and use the following snippet to render it on the canvas: Svg support is provided by the `flame_svg` external package, be sure to put it on your pubspec to use it
To use it just import the `Svg` class from `'package:flame_svg/flame_svg.dart'`, and use the following snippet to render it on the canvas:
```dart ```dart
Svg svgInstance = Svg('android.svg'); Svg svgInstance = Svg('android.svg');

View File

@@ -4,7 +4,6 @@ import 'dart:ui';
import 'package:flutter/painting.dart'; import 'package:flutter/painting.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import '../svg.dart';
import '../sprite.dart'; import '../sprite.dart';
import '../position.dart'; import '../position.dart';
import '../anchor.dart'; import '../anchor.dart';
@@ -205,23 +204,3 @@ class SpriteComponent extends PositionComponent {
return sprite != null && sprite.loaded() && x != null && y != null; return sprite != null && sprite.loaded() && x != null && y != null;
} }
} }
class SvgComponent extends PositionComponent {
Svg svg;
SvgComponent.fromSvg(double width, double height, this.svg) {
this.width = width;
this.height = height;
}
@override
void render(Canvas canvas) {
prepareCanvas(canvas);
svg.render(canvas, width, height);
}
@override
bool loaded() {
return svg != null && svg.loaded() && x != null && y != null;
}
}

View File

@@ -15,7 +15,7 @@ class TextBoxConfig {
final double timePerChar; final double timePerChar;
final double dismissDelay; final double dismissDelay;
const TextBoxConfig({ TextBoxConfig({
this.maxWidth = 200.0, this.maxWidth = 200.0,
this.margin = 8.0, this.margin = 8.0,
this.timePerChar = 0.0, this.timePerChar = 0.0,
@@ -46,11 +46,13 @@ class TextBoxComponent extends PositionComponent with Resizable {
TextBoxConfig get boxConfig => _boxConfig; TextBoxConfig get boxConfig => _boxConfig;
TextBoxComponent(String text, TextBoxComponent(
{TextConfig config = const TextConfig(), String text, {
TextBoxConfig boxConfig = const TextBoxConfig()}) { TextConfig config,
_boxConfig = boxConfig; TextBoxConfig boxConfig,
_config = config; }) {
_boxConfig = boxConfig ?? TextBoxConfig();
_config = config ?? TextConfig();
_text = text; _text = text;
_lines = []; _lines = [];
text.split(' ').forEach((word) { text.split(' ').forEach((word) {

View File

@@ -27,8 +27,8 @@ class TextComponent extends PositionComponent {
_updateBox(); _updateBox();
} }
TextComponent(this._text, {TextConfig config = const TextConfig()}) { TextComponent(this._text, {TextConfig config}) {
_config = config; _config = config ?? TextConfig();
_updateBox(); _updateBox();
} }

27
lib/memory_cache.dart Normal file
View File

@@ -0,0 +1,27 @@
import 'dart:collection';
/// Simple class to cache values on the cache
///
class MemoryCache<K, V> {
final LinkedHashMap<K, V> _cache = LinkedHashMap();
final int cacheSize;
MemoryCache({this.cacheSize = 10});
void setValue(K key, V value) {
if (!_cache.containsKey(key)) {
_cache[key] = value;
while (_cache.length > cacheSize) {
final k = _cache.keys.first;
_cache.remove(k);
}
}
}
V getValue(K key) => _cache[key];
bool containsKey(K key) => _cache.containsKey(key);
int get size => _cache.length;
}

View File

@@ -1,51 +0,0 @@
import 'dart:ui';
import 'package:flutter_svg/flutter_svg.dart';
import 'flame.dart';
import 'position.dart';
class Svg {
DrawableRoot svgRoot;
Size size;
Svg(String fileName) {
Flame.assets.readFile(fileName).then((svgString) async {
svgRoot = await svg.fromSvgString(svgString, svgString);
});
}
/// Renders the svg on the [canvas] using the dimensions provided on [width] and [height]
///
/// If not loaded, does nothing
void render(Canvas canvas, double width, double height) {
if (!loaded()) {
return;
}
svgRoot.scaleCanvasToViewBox(canvas, Size(width, height));
svgRoot.draw(canvas, null);
}
/// Renders the svg on the [canvas] on the given [position] using the dimensions provided on [width] and [height]
///
/// If not loaded, does nothing
void renderPosition(
Canvas canvas,
Position position,
double width,
double height,
) {
if (!loaded()) {
return;
}
canvas.save();
canvas.translate(position.x, position.y);
render(canvas, width, height);
canvas.restore();
}
bool loaded() {
return svgRoot != null;
}
}

View File

@@ -4,6 +4,7 @@ import 'package:flutter/material.dart' as material;
import 'position.dart'; import 'position.dart';
import 'anchor.dart'; import 'anchor.dart';
import 'memory_cache.dart';
/// A Text Config contains all typographical information required to render texts; i.e., font size and color, family, etc. /// A Text Config contains all typographical information required to render texts; i.e., font size and color, family, etc.
/// ///
@@ -52,10 +53,13 @@ class TextConfig {
/// For proper fonts of languages like Hebrew or Arabic, replace this with [TextDirection.rtl]. /// For proper fonts of languages like Hebrew or Arabic, replace this with [TextDirection.rtl].
final TextDirection textDirection; final TextDirection textDirection;
final MemoryCache _textPainterCache =
MemoryCache<String, material.TextPainter>();
/// Creates a constant [TextConfig] with sensible defaults. /// Creates a constant [TextConfig] with sensible defaults.
/// ///
/// Every parameter can be specified. /// Every parameter can be specified.
const TextConfig({ TextConfig({
this.fontSize = 24.0, this.fontSize = 24.0,
this.color = const Color(0xFF000000), this.color = const Color(0xFF000000),
this.fontFamily = 'Arial', this.fontFamily = 'Arial',
@@ -93,6 +97,7 @@ class TextConfig {
/// However, you probably want to use the [render] method witch already renders for you considering the anchor. /// However, you probably want to use the [render] method witch already renders for you considering the anchor.
/// That way, you don't need to perform the math for yourself. /// That way, you don't need to perform the math for yourself.
material.TextPainter toTextPainter(String text) { material.TextPainter toTextPainter(String text) {
if (!_textPainterCache.containsKey(text)) {
final material.TextStyle style = material.TextStyle( final material.TextStyle style = material.TextStyle(
color: color, color: color,
fontSize: fontSize, fontSize: fontSize,
@@ -108,7 +113,10 @@ class TextConfig {
textDirection: textDirection, textDirection: textDirection,
); );
tp.layout(); tp.layout();
return tp;
_textPainterCache.setValue(text, tp);
}
return _textPainterCache.getValue(text);
} }
/// Creates a new [TextConfig] changing only the [fontSize]. /// Creates a new [TextConfig] changing only the [fontSize].

View File

@@ -1,6 +1,6 @@
name: flame name: flame
description: A minimalist Flutter game engine, provides a nice set of somewhat independent modules you can choose from. description: A minimalist Flutter game engine, provides a nice set of somewhat independent modules you can choose from.
version: 0.23.0 version: 0.24.0
homepage: https://github.com/flame-engine/flame homepage: https://github.com/flame-engine/flame
dependencies: dependencies:
@@ -11,9 +11,8 @@ dependencies:
path_provider: ^1.6.0 path_provider: ^1.6.0
box2d_flame: ^0.4.6 box2d_flame: ^0.4.6
synchronized: ^2.1.0 synchronized: ^2.1.0
tiled: ^0.5.0 tiled: ^0.6.0
convert: ^2.0.1 convert: ^2.0.1
flutter_svg: ^0.18.0
flare_flutter: ^2.0.1 flare_flutter: ^2.0.1
meta: ^1.1.8 meta: ^1.1.8

View File

@@ -0,0 +1,31 @@
import 'package:test/test.dart';
import 'package:flame/memory_cache.dart';
void main() {
group('MemoryCache', () {
test('basic cache addition', () {
final cache = MemoryCache<int, String>();
cache.setValue(0, 'bla');
expect(cache.getValue(0), 'bla');
});
test('contains key', () {
final cache = MemoryCache<int, String>();
cache.setValue(0, 'bla');
expect(cache.containsKey(0), true);
expect(cache.containsKey(1), false);
});
test('cache size', () {
final cache = MemoryCache<int, String>(cacheSize: 1);
cache.setValue(0, 'bla');
cache.setValue(1, 'ble');
expect(cache.containsKey(0), false);
expect(cache.containsKey(1), true);
expect(cache.getValue(0), null);
expect(cache.getValue(1), 'ble');
expect(cache.size, 1);
});
});
}