diff --git a/CHANGELOG.md b/CHANGELOG.md index 169187714..efdea3ba4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [next] +- Svg support + ## [0.10.2] - Fixed some warnings and formatting diff --git a/doc/components.md b/doc/components.md index 6857c5dd1..aa3b33348 100644 --- a/doc/components.md +++ b/doc/components.md @@ -35,6 +35,7 @@ The `isHUD` method can be implemented to return true (default false) to make the There are also other implementations: * The `AnimationComponent` takes an `Animation` object and renders a cyclic animated sprite (more details about Animations [here](doc/images.md#Animation)) +* The `SvgComponent` takes an `Svg` object and renders the SVG on the game * The `ParallaxComponent` can render a parallax background with several frames * The `Box2DComponent`, that has a physics engine built-in (using the [Box2D](https://github.com/google/box2d.dart) port for Dart) @@ -57,6 +58,16 @@ If you have a spritesheet, you can use the `sequenced` constructor, identical to If you are not using `BaseGame`, don't forget this component needs to be update'd even if static, because the animation object needs to be ticked to move the frames. +## SvgComponent + +This component uses an instance of `Svg` class to represent a Component that has a svg that is rendered on the game: + +```dart + Svg svg = Svg('android.svg'); + SvgComponent android = SvgComponent.fromSvg(100, 100, svg); + android.x = 100; + android.y = 100; +``` ## Composed component @@ -87,8 +98,6 @@ class GameOverPanel extends PositionComponent with Resizable, ComposedComponent } ``` - - ## Parallax Component This Component can be used to render pretty backgrounds, by drawing several transparent images on top of each other, each dislocated by a tiny amount. diff --git a/doc/examples/svg/.gitignore b/doc/examples/svg/.gitignore new file mode 100644 index 000000000..07488ba61 --- /dev/null +++ b/doc/examples/svg/.gitignore @@ -0,0 +1,70 @@ +# 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 diff --git a/doc/examples/svg/.metadata b/doc/examples/svg/.metadata new file mode 100644 index 000000000..2746ae240 --- /dev/null +++ b/doc/examples/svg/.metadata @@ -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: f91df4abe1427fef8862c9e81b2e5af6fc05a67a + channel: dev + +project_type: app diff --git a/doc/examples/svg/README.md b/doc/examples/svg/README.md new file mode 100644 index 000000000..a3a0a6345 --- /dev/null +++ b/doc/examples/svg/README.md @@ -0,0 +1,3 @@ +# svg + +A sample Flame game showcasing hot to use Flame's SVG components diff --git a/doc/examples/svg/assets/android.svg b/doc/examples/svg/assets/android.svg new file mode 100644 index 000000000..1db6886aa --- /dev/null +++ b/doc/examples/svg/assets/android.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/doc/examples/svg/lib/main.dart b/doc/examples/svg/lib/main.dart new file mode 100644 index 000000000..880f05619 --- /dev/null +++ b/doc/examples/svg/lib/main.dart @@ -0,0 +1,35 @@ +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() => runApp(MyGame()); + +class MyGame extends BaseGame { + + Svg svgInstance; + SvgComponent android; + + MyGame() { + _start(); + } + + _start() async { + 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); + } + +} diff --git a/doc/examples/svg/pubspec.yaml b/doc/examples/svg/pubspec.yaml new file mode 100644 index 000000000..9f7405ac5 --- /dev/null +++ b/doc/examples/svg/pubspec.yaml @@ -0,0 +1,21 @@ +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 diff --git a/doc/images.md b/doc/images.md index 5ceb7d963..dda61aec3 100644 --- a/doc/images.md +++ b/doc/images.md @@ -39,6 +39,22 @@ You must pass the size to the render method, and the image will be resized accor The render method will do nothing while the sprite has not been loaded, so you don't need to worry. The image is cached in the `Images` class, so you can safely create many sprites with the same fileName. +## Svg + +Flame provides a simple API to render SVG images on 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: + +```dart + Svg svgInstance = Svg('android.svg'); + + final position = Position(100, 100); + final width = 300; + final height = 300; + + svgInstance.renderPosition(canvas, position, width, height); +``` + ## Flame.images The `Flame.images` is a lower level utility for loading images, very similar to the `Flame.audio` instance. diff --git a/lib/components/component.dart b/lib/components/component.dart index 9901ea574..a6c96396d 100644 --- a/lib/components/component.dart +++ b/lib/components/component.dart @@ -3,6 +3,7 @@ import 'dart:ui'; import 'package:flutter/painting.dart'; +import '../svg.dart'; import '../sprite.dart'; import '../position.dart'; import '../anchor.dart'; @@ -134,3 +135,26 @@ class SpriteComponent extends PositionComponent { @override void update(double t) {} } + +class SvgComponent extends PositionComponent { + Svg svg; + + SvgComponent.fromSvg(double width, double height, this.svg) { + this.width = width; + this.height = height; + } + + @override + render(Canvas canvas) { + prepareCanvas(canvas); + svg.render(canvas, width, height); + } + + @override + bool loaded() { + return svg != null && svg.loaded() && x != null && y != null; + } + + @override + void update(double t) {} +} diff --git a/lib/svg.dart b/lib/svg.dart new file mode 100644 index 000000000..85cf1ac52 --- /dev/null +++ b/lib/svg.dart @@ -0,0 +1,46 @@ +import 'dart:ui'; +import 'package:flutter_svg/flutter_svg.dart'; + +import 'flame.dart'; +import 'position.dart'; + +class Svg { + DrawableRoot svgRoot = null; + Size size; + + Svg(String fileName) { + Flame.assets.readFile(fileName).then((svgString) async { + this.svgRoot = await svg.fromSvgString(svgString, svgString); + }); + } + + /// Renders the svg on the [canvas] using the dimmensions provided on [width] and [height] + /// + /// If not loaded, does nothing + void render(Canvas canvas, double width, double height) { + if (!this.loaded()) { + return; + } + + svgRoot.scaleCanvasToViewBox(canvas, Size(width, height)); + svgRoot.draw(canvas, null); + } + + /// Renders the svg on the [canvas] on the given [position] using the dimmensions provided on [width] and [height] + /// + /// If not loaded, does nothing + void renderPosition(Canvas canvas, Position position, double width, double height) { + if (!this.loaded()) { + return; + } + + canvas.save(); + canvas.translate(position.x, position.y); + render(canvas, width, height); + canvas.restore(); + } + + bool loaded() { + return svgRoot != null; + } +} diff --git a/pubspec.yaml b/pubspec.yaml index af745e08d..ded6b650e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,6 +17,7 @@ dependencies: synchronized: ^1.5.1+1 tiled: ^0.2.1 convert: ^2.0.1 + flutter_svg: 0.12.0 dev_dependencies: flutter_test: