diff --git a/doc/examples/layers/.gitignore b/doc/examples/layers/.gitignore new file mode 100644 index 000000000..4be785f38 --- /dev/null +++ b/doc/examples/layers/.gitignore @@ -0,0 +1,49 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages + +android +ios +macos +web diff --git a/doc/examples/layers/.metadata b/doc/examples/layers/.metadata new file mode 100644 index 000000000..97cd56733 --- /dev/null +++ b/doc/examples/layers/.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: 9d58a87066d1da98eb06826918e4b90cc76ae0ef + channel: master + +project_type: app diff --git a/doc/examples/layers/README.md b/doc/examples/layers/README.md new file mode 100644 index 000000000..7b2476580 --- /dev/null +++ b/doc/examples/layers/README.md @@ -0,0 +1,3 @@ +# layers + +Simple project to showcase the layer feature of Flame diff --git a/doc/examples/layers/assets/images/bomb_ptero.png b/doc/examples/layers/assets/images/bomb_ptero.png new file mode 100644 index 000000000..fa4ddadc8 Binary files /dev/null and b/doc/examples/layers/assets/images/bomb_ptero.png differ diff --git a/doc/examples/layers/assets/images/sprites.png b/doc/examples/layers/assets/images/sprites.png new file mode 100644 index 000000000..3a608d1f9 Binary files /dev/null and b/doc/examples/layers/assets/images/sprites.png differ diff --git a/doc/examples/layers/lib/main.dart b/doc/examples/layers/lib/main.dart new file mode 100644 index 000000000..e9c348679 --- /dev/null +++ b/doc/examples/layers/lib/main.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart' hide Animation; +import 'package:flame/game.dart'; +import 'package:flame/sprite.dart'; +import 'package:flame/spritesheet.dart'; +import 'package:flame/animation.dart'; +import 'package:flame/layer.dart'; +import 'package:flame/flame.dart'; + +import 'dart:ui'; + +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + + await Flame.util.fullScreen(); + + final sprite = await Sprite.loadSprite('sprites.png'); + + await Flame.images.load('bomb_ptero.png'); + final spriteSheet = SpriteSheet( + imageName: 'bomb_ptero.png', + textureWidth: 48, + textureHeight: 32, + columns: 4, + rows: 1); + + final animation = spriteSheet.createAnimation(0, stepTime: 0.2, to: 3); + runApp(LayerGame(sprite, animation).widget); +} + +class LayerGame extends Game { + Sprite sprite; + Animation animation; + Layer layerWithDropShadow; + Layer animationLayerWithDropShadow; + Layer layerWithoutDropShadow; + + LayerGame(this.sprite, this.animation) { + layerWithDropShadow = Layer()..preProcessors.add(ShadowProcessor()); + animationLayerWithDropShadow = Layer() + ..preProcessors.add(ShadowProcessor()); + + layerWithoutDropShadow = Layer(); + + layerWithoutDropShadow.beginRendering(); + layerWithDropShadow.beginRendering(); + + sprite.renderRect( + layerWithoutDropShadow.canvas, const Rect.fromLTWH(50, 50, 200, 200)); + sprite.renderRect( + layerWithDropShadow.canvas, const Rect.fromLTWH(50, 50, 200, 200)); + + layerWithoutDropShadow.finishRendering(); + layerWithDropShadow.finishRendering(); + } + + @override + void update(double dt) { + animation.update(dt); + } + + @override + void render(Canvas canvas) { + layerWithoutDropShadow.render(canvas); + layerWithDropShadow.render(canvas, y: 250); + + animationLayerWithDropShadow.beginRendering(); + animation.getSprite().renderRect(animationLayerWithDropShadow.canvas, + const Rect.fromLTWH(0, 0, 150, 100)); + animationLayerWithDropShadow + ..finishRendering() + ..render(canvas, x: 100, y: 600); + } + + @override + Color backgroundColor() => const Color(0xFF38607C); +} diff --git a/doc/examples/layers/pubspec.yaml b/doc/examples/layers/pubspec.yaml new file mode 100644 index 000000000..bde3559af --- /dev/null +++ b/doc/examples/layers/pubspec.yaml @@ -0,0 +1,27 @@ +name: layers +description: Simple project to showcase the layer feature of Flame + +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +version: 1.0.0+1 + +environment: + sdk: ">=2.7.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + flame: + path: ../../../ + + cupertino_icons: ^0.1.3 + +dev_dependencies: + flutter_test: + sdk: flutter + +flutter: + uses-material-design: true + assets: + - assets/images/sprites.png + - assets/images/bomb_ptero.png diff --git a/lib/layer.dart b/lib/layer.dart new file mode 100644 index 000000000..84fc213e7 --- /dev/null +++ b/lib/layer.dart @@ -0,0 +1,71 @@ +import 'dart:ui'; + +class Layer { + List preProcessors = []; + List postProcessors = []; + + Picture _picture; + + PictureRecorder _recorder; + Canvas _canvas; + + void render(Canvas canvas, {double x = 0.0, double y = 0.0}) { + if (_picture == null) { + return; + } + + canvas.save(); + canvas.translate(x, y); + + preProcessors.forEach((p) => p.process(_picture, canvas)); + canvas.drawPicture(_picture); + postProcessors.forEach((p) => p.process(_picture, canvas)); + canvas.restore(); + } + + Canvas get canvas { + assert(_canvas != null, + 'Layer is not ready for rendering, call beginRendering first'); + return _canvas; + } + + void beginRendering() { + _recorder = PictureRecorder(); + _canvas = Canvas(_recorder); + } + + void finishRendering() { + _picture = _recorder.endRecording(); + + _recorder = null; + _canvas = null; + } +} + +abstract class LayerProcessor { + void process(Picture pic, Canvas canvas); +} + +class ShadowProcessor extends LayerProcessor { + Paint _shadowPaint; + + final Offset offset; + + ShadowProcessor({ + this.offset = const Offset(10, 10), + double opacity = 0.9, + Color color = const Color(0xFF000000), + }) { + _shadowPaint = Paint() + ..colorFilter = + ColorFilter.mode(color.withOpacity(opacity), BlendMode.srcATop); + } + + @override + void process(Picture pic, Canvas canvas) { + canvas.saveLayer(Rect.largest, _shadowPaint); + canvas.translate(offset.dx, offset.dy); + canvas.drawPicture(pic); + canvas.restore(); + } +}