mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-02 20:13:50 +08:00
Merge branch 'develop' into v1.0.0
This commit is contained in:
10
CHANGELOG.md
10
CHANGELOG.md
@ -2,11 +2,15 @@
|
|||||||
|
|
||||||
## 1.0.0
|
## 1.0.0
|
||||||
- Move all box2d related code and examples to the flame_box2d repo
|
- Move all box2d related code and examples to the flame_box2d repo
|
||||||
|
|
||||||
## [next]
|
|
||||||
- Preventing some crashed that could happen on web when some methods were called
|
|
||||||
- Rename Animation to SpriteAnimation
|
- Rename Animation to SpriteAnimation
|
||||||
|
|
||||||
|
## 0.25.0
|
||||||
|
- Externalizing Tiled support to its own package `flame_tiled`
|
||||||
|
- Preventing some crashs that could happen on web when some methods were called
|
||||||
|
- Add mustCallSuper to BaseGame `update` and `render` methods
|
||||||
|
- Moved FPS code from BaseGame to a mixin, BaseGame uses the new mixin.
|
||||||
|
- Deprecate flare API in favor of the package `flame_flare`
|
||||||
|
|
||||||
## 0.24.0
|
## 0.24.0
|
||||||
- Outsourcing SVG support to an external package
|
- Outsourcing SVG support to an external package
|
||||||
- Adding MemoryCache class
|
- Adding MemoryCache class
|
||||||
|
|||||||
@ -18,7 +18,7 @@ Put the pub package as your dependency by dropping the following in your `pubspe
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
dependencies:
|
dependencies:
|
||||||
flame: ^0.24.0
|
flame: ^0.25.0
|
||||||
```
|
```
|
||||||
|
|
||||||
And start using it!
|
And start using it!
|
||||||
|
|||||||
@ -78,20 +78,56 @@ This component uses an instance of `Svg` class to represent a Component that has
|
|||||||
android.y = 100;
|
android.y = 100;
|
||||||
```
|
```
|
||||||
|
|
||||||
## FlareAnimation Component
|
## FlareActor Component
|
||||||
|
|
||||||
This component wraps an instance of the [FlareAnimation](/doc/images.md#FlareAnimation), it receives the filename of the Flare animation file, which animation from that file you want to use, and the `width` and `height` of the rendered animation.
|
*Note*: The previous implementation of a Flare integration API using `FlareAnimation` and `FlareComponent` has been deprecated.
|
||||||
|
|
||||||
|
To use Flare within Flame, use the [`flame_flare`](https://github.com/flame-engine/flame_flare) package.
|
||||||
|
|
||||||
|
This is the interface to use a [flare animation](https://pub.dev/packages/flare_flutter) within flame.
|
||||||
|
`FlareActorComponent` has almost the same API as of flare's FlareActor widget. It receives the animation filename (that are loaded by default with `Flame.bundle`),
|
||||||
|
it also can receive a FlareController that can play multiple animations and control nodes.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
final fileName = "assets/Bob_Minion.flr";
|
import 'package:flame_flare/flame_flare.dart';
|
||||||
final animation = "Wave";
|
|
||||||
final width = 306;
|
|
||||||
final height = 228;
|
|
||||||
|
|
||||||
FlareComponent flareAnimation = FlareComponent(fileName, animation, width, height);
|
// your implementation of FlareController
|
||||||
|
class WashingtonController extends FlareControls {
|
||||||
|
|
||||||
|
ActorNode rightHandNode;
|
||||||
|
|
||||||
|
void initialize(FlutterActorArtboard artboard) {
|
||||||
|
super.initialize(artboard);
|
||||||
|
|
||||||
|
// get flare node
|
||||||
|
rightHand = artboard.getNode('right_hand');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final fileName = 'assets/george_washington.flr';
|
||||||
|
final width = 1776;
|
||||||
|
final height = 1804;
|
||||||
|
final controller = WashingtonController(); //instantiate controller
|
||||||
|
|
||||||
|
FlareActorComponent flareAnimation = FlareActorComponent(
|
||||||
|
fileName,
|
||||||
|
controller: controller,
|
||||||
|
width: 306,
|
||||||
|
height: 228,
|
||||||
|
);
|
||||||
|
|
||||||
flareAnimation.x = 50;
|
flareAnimation.x = 50;
|
||||||
flareAnimation.y = 240;
|
flareAnimation.y = 240;
|
||||||
add(flareAnimation);
|
add(flareAnimation);
|
||||||
|
|
||||||
|
// to play an animation
|
||||||
|
controller.play('rise_up');
|
||||||
|
|
||||||
|
// you can add another animation to play at the same time
|
||||||
|
controller.play('close_door_way_out');
|
||||||
|
|
||||||
|
// also, get a flare node and modify it
|
||||||
|
controller.rightHandNode.rotation = math.pi;
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also change the current playing animation using the `updateAnimation` method.
|
You can also change the current playing animation using the `updateAnimation` method.
|
||||||
@ -139,9 +175,9 @@ Create it like this:
|
|||||||
|
|
||||||
```dart
|
```dart
|
||||||
final images = [
|
final images = [
|
||||||
ParallaxImage("mountains.jpg"),
|
ParallaxImage('mountains.jpg'),
|
||||||
ParallaxImage("forest.jpg"),
|
ParallaxImage('forest.jpg'),
|
||||||
ParallaxImage("city.jpg"),
|
ParallaxImage('city.jpg'),
|
||||||
];
|
];
|
||||||
this.bg = ParallaxComponent(images);
|
this.bg = ParallaxComponent(images);
|
||||||
```
|
```
|
||||||
@ -163,9 +199,9 @@ By default the images are aligned to the bottom left, repeated along the X-axis
|
|||||||
Advanced example:
|
Advanced example:
|
||||||
```dart
|
```dart
|
||||||
final images = [
|
final images = [
|
||||||
ParallaxImage("stars.jpg", repeat: ImageRepeat.repeat, alignment: Alignment.center, fill: LayerFill.width),
|
ParallaxImage('stars.jpg', repeat: ImageRepeat.repeat, alignment: Alignment.center, fill: LayerFill.width),
|
||||||
ParallaxImage("planets.jpg", repeat: ImageRepeat.repeatY, alignment: Alignment.bottomLeft, fill: LayerFill.none),
|
ParallaxImage('planets.jpg', repeat: ImageRepeat.repeatY, alignment: Alignment.bottomLeft, fill: LayerFill.none),
|
||||||
ParallaxImage("dust.jpg", repeat: ImageRepeat.repeatX, alignment: Alignment.topRight, fill: LayerFill.height),
|
ParallaxImage('dust.jpg', repeat: ImageRepeat.repeatX, alignment: Alignment.topRight, fill: LayerFill.height),
|
||||||
];
|
];
|
||||||
this.bg = ParallaxComponent(images, baseSpeed: Offset(50, 0), layerDelta: Offset(20, 0));
|
this.bg = ParallaxComponent(images, baseSpeed: Offset(50, 0), layerDelta: Offset(20, 0));
|
||||||
```
|
```
|
||||||
|
|||||||
19
doc/debug.md
19
doc/debug.md
@ -1,7 +1,20 @@
|
|||||||
## Debug features
|
# Debug features
|
||||||
|
|
||||||
|
## FPS counter
|
||||||
|
|
||||||
|
Flame provides the `FPSCounter` mixin for recording the fps, this mixin can be applied on any class that extends from `Game`. When applied you have to implemented the `recordFps` method and it should return `true` if you want to access the current fps by using the `fps` method`.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
class MyGame extends Game with FPS {
|
||||||
|
@override
|
||||||
|
bool recordFps() => true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## BaseGame features
|
||||||
|
|
||||||
Flame provides some features for debugging, these features are enabled when the method `debugMode` from the `BaseGame` class is overridden, and returning `true`. When it's enabled all `PositionComponent`s will be wrapped into a rectangle, and have its position rendered on the screen, so you can visually verify the component boundaries and position.
|
Flame provides some features for debugging, these features are enabled when the method `debugMode` from the `BaseGame` class is overridden, and returning `true`. When it's enabled all `PositionComponent`s will be wrapped into a rectangle, and have its position rendered on the screen, so you can visually verify the component boundaries and position.
|
||||||
|
|
||||||
In addition to the debugMode, you can also ask BaseGame to record the fps, that is enabled by overriding the `recordFps` method to return `true`, by doing so, you can access the current fps by using the method `fps`.
|
In addition to the debugMode, you can also ask `BaseGame` to record the fps(the `BaseGame` used the [FPSCounter](fps-counter) mixin). To enable it you have to override the `recordFps` method to return `true`, by doing so, you can access the current fps by using the method `fps`.
|
||||||
|
|
||||||
To see a working example of the debugging features, [check this example](/doc/examples/debug).
|
To see a working example of the debugging features of the `BaseGame`, [check this example](/doc/examples/debug).
|
||||||
|
|||||||
72
doc/examples/flare/.gitignore
vendored
72
doc/examples/flare/.gitignore
vendored
@ -1,72 +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
|
|
||||||
|
|
||||||
.flutter-plugins-dependencies
|
|
||||||
@ -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: 0ba67226ee62d6c9d663a6f8410fb4b2f1076046
|
|
||||||
channel: dev
|
|
||||||
|
|
||||||
project_type: app
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
# flare
|
|
||||||
|
|
||||||
Example game application showcasing how to use Flare animations on Flame.
|
|
||||||
|
|
||||||
Flare animation used for the example: https://www.2dimensions.com/a/kautuk/files/flare/bob-minion/preview
|
|
||||||
|
|
||||||
The `main.dart` is a more generic example, test most of the features as `main_component.dart` is a specific example for the `FlareComponent` class.
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,103 +0,0 @@
|
|||||||
import 'dart:ui';
|
|
||||||
import 'package:flame/gestures.dart';
|
|
||||||
import 'package:flame/game.dart';
|
|
||||||
import 'package:flame/flare_animation.dart';
|
|
||||||
import 'package:flame/components/flare_component.dart';
|
|
||||||
import 'package:flame/text_config.dart';
|
|
||||||
import 'package:flame/position.dart';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
|
||||||
|
|
||||||
final game = MyGame();
|
|
||||||
runApp(game.widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyGame extends BaseGame with TapDetector {
|
|
||||||
final TextConfig fpsTextConfig = TextConfig(color: const Color(0xFFFFFFFF));
|
|
||||||
|
|
||||||
final paint = Paint()..color = const Color(0xFFE5E5E5E5);
|
|
||||||
final List<String> _animations = ['Stand', 'Wave', 'Jump', 'Dance'];
|
|
||||||
int _currentAnimation = 0;
|
|
||||||
|
|
||||||
FlareAnimation flareAnimation;
|
|
||||||
bool loaded = false;
|
|
||||||
|
|
||||||
MyGame() {
|
|
||||||
_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool debugMode() => true;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onTap() {
|
|
||||||
cycleAnimation();
|
|
||||||
}
|
|
||||||
|
|
||||||
void cycleAnimation() {
|
|
||||||
if (_currentAnimation == 3) {
|
|
||||||
_currentAnimation = 0;
|
|
||||||
} else {
|
|
||||||
_currentAnimation++;
|
|
||||||
}
|
|
||||||
|
|
||||||
flareAnimation.updateAnimation(_animations[_currentAnimation]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _start() async {
|
|
||||||
flareAnimation = await FlareAnimation.load('assets/Bob_Minion.flr');
|
|
||||||
flareAnimation.updateAnimation('Stand');
|
|
||||||
|
|
||||||
flareAnimation.width = 306;
|
|
||||||
flareAnimation.height = 228;
|
|
||||||
|
|
||||||
final flareAnimation2 =
|
|
||||||
FlareComponent('assets/Bob_Minion.flr', 'Wave', 306, 228);
|
|
||||||
flareAnimation2.x = 50;
|
|
||||||
flareAnimation2.y = 240;
|
|
||||||
add(flareAnimation2);
|
|
||||||
|
|
||||||
final flareAnimation3 =
|
|
||||||
FlareComponent('assets/Bob_Minion.flr', 'Jump', 306, 228);
|
|
||||||
flareAnimation3.x = 50;
|
|
||||||
flareAnimation3.y = 400;
|
|
||||||
add(flareAnimation3);
|
|
||||||
|
|
||||||
final flareAnimation4 =
|
|
||||||
FlareComponent('assets/Bob_Minion.flr', 'Dance', 306, 228);
|
|
||||||
flareAnimation4.x = 50;
|
|
||||||
flareAnimation4.y = 550;
|
|
||||||
add(flareAnimation4);
|
|
||||||
|
|
||||||
loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void render(Canvas canvas) {
|
|
||||||
super.render(canvas);
|
|
||||||
|
|
||||||
if (loaded) {
|
|
||||||
canvas.drawRect(
|
|
||||||
Rect.fromLTWH(50, 50, flareAnimation.width, flareAnimation.height),
|
|
||||||
paint,
|
|
||||||
);
|
|
||||||
|
|
||||||
flareAnimation.render(canvas, x: 50, y: 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debugMode()) {
|
|
||||||
fpsTextConfig.render(canvas, fps(120).toString(), Position(0, 10));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void update(double dt) {
|
|
||||||
super.update(dt);
|
|
||||||
if (loaded) {
|
|
||||||
flareAnimation.update(dt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,73 +0,0 @@
|
|||||||
import 'dart:ui';
|
|
||||||
import 'package:flame/gestures.dart';
|
|
||||||
import 'package:flame/game.dart';
|
|
||||||
import 'package:flame/components/flare_component.dart';
|
|
||||||
import 'package:flame/text_config.dart';
|
|
||||||
import 'package:flame/position.dart';
|
|
||||||
import 'package:flame/palette.dart';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
|
||||||
|
|
||||||
final game = MyGame();
|
|
||||||
runApp(game.widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyGame extends BaseGame with TapDetector, DoubleTapDetector {
|
|
||||||
final TextConfig fpsTextConfig = TextConfig(color: BasicPalette.white.color);
|
|
||||||
|
|
||||||
final paint = Paint()..color = const Color(0xFFE5E5E5E5);
|
|
||||||
final List<String> _animations = ['Stand', 'Wave', 'Jump', 'Dance'];
|
|
||||||
int _currentAnimation = 0;
|
|
||||||
FlareComponent flareComponent;
|
|
||||||
|
|
||||||
bool loaded = false;
|
|
||||||
|
|
||||||
MyGame() {
|
|
||||||
_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool debugMode() => true;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onTap() {
|
|
||||||
cycleAnimation();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onDoubleTap() {
|
|
||||||
flareComponent.width += 10;
|
|
||||||
flareComponent.height += 10;
|
|
||||||
|
|
||||||
flareComponent.x -= 10;
|
|
||||||
flareComponent.y -= 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cycleAnimation() {
|
|
||||||
if (_currentAnimation == 3) {
|
|
||||||
_currentAnimation = 0;
|
|
||||||
} else {
|
|
||||||
_currentAnimation++;
|
|
||||||
}
|
|
||||||
flareComponent.updateAnimation(_animations[_currentAnimation]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _start() async {
|
|
||||||
flareComponent = FlareComponent('assets/Bob_Minion.flr', 'Stand', 306, 228);
|
|
||||||
flareComponent.x = 50;
|
|
||||||
flareComponent.y = 240;
|
|
||||||
add(flareComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void render(Canvas canvas) {
|
|
||||||
super.render(canvas);
|
|
||||||
|
|
||||||
if (debugMode()) {
|
|
||||||
fpsTextConfig.render(canvas, fps(120).toString(), Position(0, 10));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
name: flare
|
|
||||||
description: Flame sample for using Flare animations
|
|
||||||
|
|
||||||
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/Bob_Minion.flr
|
|
||||||
|
|
||||||
@ -1,799 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 24,
|
|
||||||
"artboards": [
|
|
||||||
{
|
|
||||||
"name": "Artboard",
|
|
||||||
"translation": [
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"width": 250,
|
|
||||||
"height": 250,
|
|
||||||
"origin": [
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"clipContents": true,
|
|
||||||
"color": [
|
|
||||||
0.364705890417099,
|
|
||||||
0.364705890417099,
|
|
||||||
0.364705890417099,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"nodes": [
|
|
||||||
{
|
|
||||||
"name": "Polygon",
|
|
||||||
"translation": [
|
|
||||||
125,
|
|
||||||
125
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"scale": [
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"opacity": 1,
|
|
||||||
"isCollapsed": false,
|
|
||||||
"clips": [],
|
|
||||||
"isVisible": true,
|
|
||||||
"blendMode": 3,
|
|
||||||
"drawOrder": 1,
|
|
||||||
"transformAffectsStroke": false,
|
|
||||||
"type": "shape"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Color",
|
|
||||||
"parent": 0,
|
|
||||||
"opacity": 1,
|
|
||||||
"color": [
|
|
||||||
0.4534761905670166,
|
|
||||||
0.8476190567016602,
|
|
||||||
0.7884976267814636,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"fillRule": 1,
|
|
||||||
"type": "colorFill"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Polygon Path",
|
|
||||||
"parent": 0,
|
|
||||||
"translation": [
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"scale": [
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"opacity": 1,
|
|
||||||
"isCollapsed": false,
|
|
||||||
"clips": [],
|
|
||||||
"width": 250,
|
|
||||||
"height": 250,
|
|
||||||
"sides": 4,
|
|
||||||
"type": "polygon"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "globe",
|
|
||||||
"translation": [
|
|
||||||
125,
|
|
||||||
125
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"scale": [
|
|
||||||
10,
|
|
||||||
10
|
|
||||||
],
|
|
||||||
"opacity": 1,
|
|
||||||
"isCollapsed": false,
|
|
||||||
"clips": [],
|
|
||||||
"type": "node"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Shape",
|
|
||||||
"parent": 3,
|
|
||||||
"translation": [
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"scale": [
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"opacity": 1,
|
|
||||||
"isCollapsed": false,
|
|
||||||
"clips": [],
|
|
||||||
"isVisible": true,
|
|
||||||
"blendMode": 3,
|
|
||||||
"drawOrder": 2,
|
|
||||||
"transformAffectsStroke": false,
|
|
||||||
"type": "shape"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Color",
|
|
||||||
"parent": 4,
|
|
||||||
"opacity": 1,
|
|
||||||
"color": [
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"width": 2,
|
|
||||||
"cap": 0,
|
|
||||||
"join": 0,
|
|
||||||
"trim": 0,
|
|
||||||
"type": "colorStroke"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ellipse",
|
|
||||||
"parent": 4,
|
|
||||||
"translation": [
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"scale": [
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"opacity": 1,
|
|
||||||
"isCollapsed": false,
|
|
||||||
"clips": [],
|
|
||||||
"width": 20,
|
|
||||||
"height": 20,
|
|
||||||
"type": "ellipse"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Shape",
|
|
||||||
"parent": 3,
|
|
||||||
"translation": [
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"scale": [
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"opacity": 1,
|
|
||||||
"isCollapsed": false,
|
|
||||||
"clips": [],
|
|
||||||
"isVisible": true,
|
|
||||||
"blendMode": 3,
|
|
||||||
"drawOrder": 3,
|
|
||||||
"transformAffectsStroke": false,
|
|
||||||
"type": "shape"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Color",
|
|
||||||
"parent": 7,
|
|
||||||
"opacity": 1,
|
|
||||||
"color": [
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"width": 2,
|
|
||||||
"cap": 0,
|
|
||||||
"join": 0,
|
|
||||||
"trim": 0,
|
|
||||||
"type": "colorStroke"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Path",
|
|
||||||
"parent": 7,
|
|
||||||
"translation": [
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"scale": [
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"opacity": 1,
|
|
||||||
"isCollapsed": false,
|
|
||||||
"clips": [],
|
|
||||||
"bones": [],
|
|
||||||
"isVisible": true,
|
|
||||||
"isClosed": true,
|
|
||||||
"points": [
|
|
||||||
{
|
|
||||||
"pointType": 2,
|
|
||||||
"translation": [
|
|
||||||
0,
|
|
||||||
-10
|
|
||||||
],
|
|
||||||
"in": [
|
|
||||||
0,
|
|
||||||
-10
|
|
||||||
],
|
|
||||||
"out": [
|
|
||||||
2.5012803077697754,
|
|
||||||
-7.2616472244262695
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pointType": 2,
|
|
||||||
"translation": [
|
|
||||||
4,
|
|
||||||
1.7763568394002505e-15
|
|
||||||
],
|
|
||||||
"in": [
|
|
||||||
3.922752857208252,
|
|
||||||
-3.7079660892486572
|
|
||||||
],
|
|
||||||
"out": [
|
|
||||||
3.922752857208252,
|
|
||||||
3.7079660892486572
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pointType": 2,
|
|
||||||
"translation": [
|
|
||||||
-2.6645352591003757e-14,
|
|
||||||
10
|
|
||||||
],
|
|
||||||
"in": [
|
|
||||||
2.5012803077697754,
|
|
||||||
7.2616472244262695
|
|
||||||
],
|
|
||||||
"out": [
|
|
||||||
-2.5012803077697754,
|
|
||||||
7.2616472244262695
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pointType": 2,
|
|
||||||
"translation": [
|
|
||||||
-4,
|
|
||||||
1.7763568394002505e-15
|
|
||||||
],
|
|
||||||
"in": [
|
|
||||||
-3.922752857208252,
|
|
||||||
3.7079660892486572
|
|
||||||
],
|
|
||||||
"out": [
|
|
||||||
-3.922752857208252,
|
|
||||||
-3.7079660892486572
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pointType": 2,
|
|
||||||
"translation": [
|
|
||||||
3.019806626980426e-14,
|
|
||||||
-10
|
|
||||||
],
|
|
||||||
"in": [
|
|
||||||
-2.5012803077697754,
|
|
||||||
-7.2616472244262695
|
|
||||||
],
|
|
||||||
"out": [
|
|
||||||
3.019806626980426e-14,
|
|
||||||
-10
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "path"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ellipse",
|
|
||||||
"translation": [
|
|
||||||
125,
|
|
||||||
125
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"scale": [
|
|
||||||
10,
|
|
||||||
10
|
|
||||||
],
|
|
||||||
"opacity": 1,
|
|
||||||
"isCollapsed": false,
|
|
||||||
"clips": [],
|
|
||||||
"isVisible": true,
|
|
||||||
"blendMode": 3,
|
|
||||||
"drawOrder": 4,
|
|
||||||
"transformAffectsStroke": false,
|
|
||||||
"type": "shape"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Color",
|
|
||||||
"parent": 10,
|
|
||||||
"opacity": 1,
|
|
||||||
"color": [
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"width": 10,
|
|
||||||
"cap": 1,
|
|
||||||
"join": 0,
|
|
||||||
"trim": 1,
|
|
||||||
"start": 0,
|
|
||||||
"end": 0,
|
|
||||||
"offset": 0,
|
|
||||||
"type": "colorStroke"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Ellipse Path",
|
|
||||||
"parent": 10,
|
|
||||||
"translation": [
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
],
|
|
||||||
"rotation": 0,
|
|
||||||
"scale": [
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
],
|
|
||||||
"opacity": 1,
|
|
||||||
"isCollapsed": false,
|
|
||||||
"clips": [],
|
|
||||||
"width": 14,
|
|
||||||
"height": 14,
|
|
||||||
"type": "ellipse"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"animations": [
|
|
||||||
{
|
|
||||||
"name": "Spin",
|
|
||||||
"fps": 60,
|
|
||||||
"duration": 10,
|
|
||||||
"isLooping": true,
|
|
||||||
"keyed": [
|
|
||||||
{
|
|
||||||
"component": 0,
|
|
||||||
"scaleY": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"time": 0,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 2.5,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 0.49699999999999966
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 5,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 7.766666666666667,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 0.49699999999999966
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 10,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"scaleX": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"time": 0,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 2.5,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 0.5049999999999999
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 5,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 7.766666666666667,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 0.5049999999999999
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 10,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"posX": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"time": 5,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 125
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"component": 1,
|
|
||||||
"fillColor": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"time": 0,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": [
|
|
||||||
0.4534761905670166,
|
|
||||||
0.6939033269882202,
|
|
||||||
0.8476190567016602,
|
|
||||||
1
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 5,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": [
|
|
||||||
0.4773571491241455,
|
|
||||||
0.776190459728241,
|
|
||||||
0.6058554649353027,
|
|
||||||
1
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 10,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": [
|
|
||||||
0.4534761905670166,
|
|
||||||
0.6939033269882202,
|
|
||||||
0.8476190567016602,
|
|
||||||
1
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"component": 3,
|
|
||||||
"rotation": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"time": 0,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 5,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 6.283185307179586
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 10,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"posX": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"time": 5,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 125
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"component": 9,
|
|
||||||
"pathVertices": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"time": 0,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": [
|
|
||||||
0,
|
|
||||||
-10,
|
|
||||||
0,
|
|
||||||
-10,
|
|
||||||
2.5012803077697754,
|
|
||||||
-7.2616472244262695,
|
|
||||||
4,
|
|
||||||
1.7763568394002505e-15,
|
|
||||||
3.922752857208252,
|
|
||||||
-3.7079660892486572,
|
|
||||||
3.922752857208252,
|
|
||||||
3.7079660892486572,
|
|
||||||
-2.6645352591003757e-14,
|
|
||||||
10,
|
|
||||||
2.5012803077697754,
|
|
||||||
7.2616472244262695,
|
|
||||||
-2.5012803077697754,
|
|
||||||
7.2616472244262695,
|
|
||||||
-4,
|
|
||||||
1.7763568394002505e-15,
|
|
||||||
-3.922752857208252,
|
|
||||||
3.7079660892486572,
|
|
||||||
-3.922752857208252,
|
|
||||||
-3.7079660892486572,
|
|
||||||
3.019806626980426e-14,
|
|
||||||
-10,
|
|
||||||
-2.5012803077697754,
|
|
||||||
-7.2616472244262695,
|
|
||||||
3.019806626980426e-14,
|
|
||||||
-10
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 5,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": [
|
|
||||||
0,
|
|
||||||
-10,
|
|
||||||
0,
|
|
||||||
-10,
|
|
||||||
-0.028131680563092232,
|
|
||||||
-0.08517590165138245,
|
|
||||||
9.294120788574219,
|
|
||||||
-0.05882320925593376,
|
|
||||||
9.216875076293945,
|
|
||||||
-3.766789197921753,
|
|
||||||
9.216875076293945,
|
|
||||||
3.6491427421569824,
|
|
||||||
-2.6645352591003757e-14,
|
|
||||||
10,
|
|
||||||
-0.02813015505671501,
|
|
||||||
-0.03246975317597389,
|
|
||||||
-0.03069210611283779,
|
|
||||||
-0.09129314869642258,
|
|
||||||
-8.999999046325684,
|
|
||||||
1.862645149230957e-7,
|
|
||||||
-8.92275333404541,
|
|
||||||
3.70796537399292,
|
|
||||||
-8.92275333404541,
|
|
||||||
-3.707965612411499,
|
|
||||||
3.019806626980426e-14,
|
|
||||||
-10,
|
|
||||||
-0.08951549977064133,
|
|
||||||
-0.14400005340576172,
|
|
||||||
3.019806626980426e-14,
|
|
||||||
-10
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 10,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": [
|
|
||||||
0,
|
|
||||||
-10,
|
|
||||||
0,
|
|
||||||
-10,
|
|
||||||
2.5012803077697754,
|
|
||||||
-7.2616472244262695,
|
|
||||||
4,
|
|
||||||
1.7763568394002505e-15,
|
|
||||||
3.922752857208252,
|
|
||||||
-3.7079660892486572,
|
|
||||||
3.922752857208252,
|
|
||||||
3.7079660892486572,
|
|
||||||
-2.6645352591003757e-14,
|
|
||||||
10,
|
|
||||||
2.5012803077697754,
|
|
||||||
7.2616472244262695,
|
|
||||||
-2.5012803077697754,
|
|
||||||
7.2616472244262695,
|
|
||||||
-4,
|
|
||||||
1.7763568394002505e-15,
|
|
||||||
-3.922752857208252,
|
|
||||||
3.7079660892486572,
|
|
||||||
-3.922752857208252,
|
|
||||||
-3.7079660892486572,
|
|
||||||
3.019806626980426e-14,
|
|
||||||
-10,
|
|
||||||
-2.5012803077697754,
|
|
||||||
-7.2616472244262695,
|
|
||||||
3.019806626980426e-14,
|
|
||||||
-10
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"component": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"component": 11,
|
|
||||||
"strokeStart": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"time": 0,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 2.5,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 0.25
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 5,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 0.5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 7.533333333333333,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 0.6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 10,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
],
|
|
||||||
"strokeEnd": [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"time": 0,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 2.5,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 0.5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 5,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 0.8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 7.533333333333333,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 0.8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"time": 10,
|
|
||||||
"interpolatorType": 2,
|
|
||||||
"cubicX1": 0.5913978494623656,
|
|
||||||
"cubicY1": 0.0766129032258065,
|
|
||||||
"cubicX2": 0.17204301075268819,
|
|
||||||
"cubicY2": 1.1048387096774193,
|
|
||||||
"value": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"animationStart": 0,
|
|
||||||
"animationEnd": 10,
|
|
||||||
"type": "animation"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "artboard"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -4,7 +4,6 @@ import 'dart:ui';
|
|||||||
|
|
||||||
import 'package:flame/sprite_animation.dart';
|
import 'package:flame/sprite_animation.dart';
|
||||||
import 'package:flame/components/component.dart';
|
import 'package:flame/components/component.dart';
|
||||||
import 'package:flame/flare_animation.dart';
|
|
||||||
import 'package:flame/particles/circle_particle.dart';
|
import 'package:flame/particles/circle_particle.dart';
|
||||||
import 'package:flame/particles/composed_particle.dart';
|
import 'package:flame/particles/composed_particle.dart';
|
||||||
import 'package:flame/particles/curved_particle.dart';
|
import 'package:flame/particles/curved_particle.dart';
|
||||||
@ -18,7 +17,6 @@ import 'package:flame/particles/accelerated_particle.dart';
|
|||||||
import 'package:flame/particles/paint_particle.dart';
|
import 'package:flame/particles/paint_particle.dart';
|
||||||
import 'package:flame/particles/animation_particle.dart';
|
import 'package:flame/particles/animation_particle.dart';
|
||||||
import 'package:flame/particles/component_particle.dart';
|
import 'package:flame/particles/component_particle.dart';
|
||||||
import 'package:flame/particles/flare_particle.dart';
|
|
||||||
import 'package:flame/flame.dart';
|
import 'package:flame/flame.dart';
|
||||||
import 'package:flame/game.dart';
|
import 'package:flame/game.dart';
|
||||||
import 'package:flame/time.dart' as flame_time;
|
import 'package:flame/time.dart' as flame_time;
|
||||||
@ -52,11 +50,9 @@ class MyGame extends BaseGame {
|
|||||||
|
|
||||||
Offset cellSize;
|
Offset cellSize;
|
||||||
Offset halfCellSize;
|
Offset halfCellSize;
|
||||||
FlareAnimation flareAnimation;
|
|
||||||
|
|
||||||
MyGame({
|
MyGame({
|
||||||
Size screenSize,
|
Size screenSize,
|
||||||
this.flareAnimation,
|
|
||||||
}) {
|
}) {
|
||||||
size = screenSize;
|
size = screenSize;
|
||||||
cellSize = Offset(size.width / gridSize, size.height / gridSize);
|
cellSize = Offset(size.width / gridSize, size.height / gridSize);
|
||||||
@ -92,7 +88,6 @@ class MyGame extends BaseGame {
|
|||||||
animationParticle(),
|
animationParticle(),
|
||||||
fireworkParticle(),
|
fireworkParticle(),
|
||||||
componentParticle(),
|
componentParticle(),
|
||||||
flareParticle(),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// Place all the [Particle] instances
|
// Place all the [Particle] instances
|
||||||
@ -461,36 +456,6 @@ class MyGame extends BaseGame {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [FlareParticle] renders fiven [FlareAnimation] inside
|
|
||||||
/// as you can see, animation could be reused across
|
|
||||||
/// different particles.
|
|
||||||
Particle flareParticle() {
|
|
||||||
final flare = ComposedParticle(children: <Particle>[
|
|
||||||
// Circle Particle for background
|
|
||||||
CircleParticle(
|
|
||||||
paint: Paint()..color = Colors.white12,
|
|
||||||
radius: flareAnimation.width / 2),
|
|
||||||
FlareParticle(flare: flareAnimation),
|
|
||||||
]);
|
|
||||||
|
|
||||||
final List<Offset> corners = [
|
|
||||||
-halfCellSize,
|
|
||||||
halfCellSize,
|
|
||||||
];
|
|
||||||
|
|
||||||
return RotatingParticle(
|
|
||||||
to: pi,
|
|
||||||
child: Particle.generate(
|
|
||||||
count: 2,
|
|
||||||
generator: (i) => MovingParticle(
|
|
||||||
to: corners[i] * .4,
|
|
||||||
curve: SineCurve(),
|
|
||||||
child: flare,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// [Particle] base class exposes a number
|
/// [Particle] base class exposes a number
|
||||||
/// of convenience wrappers to make positioning.
|
/// of convenience wrappers to make positioning.
|
||||||
///
|
///
|
||||||
@ -523,6 +488,7 @@ class MyGame extends BaseGame {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool debugMode() => true;
|
bool debugMode() => true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void render(Canvas canvas) {
|
void render(Canvas canvas) {
|
||||||
super.render(canvas);
|
super.render(canvas);
|
||||||
@ -587,13 +553,8 @@ Future<BaseGame> loadGame() async {
|
|||||||
'boom3.png',
|
'boom3.png',
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
const flareSize = 32.0;
|
|
||||||
final flareAnimation = await FlareAnimation.load('assets/diamond.flr');
|
|
||||||
flareAnimation.updateAnimation('Spin');
|
|
||||||
flareAnimation.width = flareSize;
|
|
||||||
flareAnimation.height = flareSize;
|
|
||||||
|
|
||||||
return MyGame(screenSize: gameSize, flareAnimation: flareAnimation);
|
return MyGame(screenSize: gameSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A curve which maps sinus output (-1..1,0..pi)
|
/// A curve which maps sinus output (-1..1,0..pi)
|
||||||
|
|||||||
@ -19,4 +19,3 @@ dev_dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
assets:
|
assets:
|
||||||
- assets/images/
|
- assets/images/
|
||||||
- assets/diamond.flr
|
|
||||||
|
|||||||
71
doc/examples/tiled/.gitignore
vendored
71
doc/examples/tiled/.gitignore
vendored
@ -1,71 +0,0 @@
|
|||||||
# Miscellaneous
|
|
||||||
*.class
|
|
||||||
*.lock
|
|
||||||
*.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
|
|
||||||
@ -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: 7a88fbc5fd987dce78e468ec45e9e841a49f422d
|
|
||||||
channel: dev
|
|
||||||
|
|
||||||
project_type: app
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
# tiled
|
|
||||||
|
|
||||||
An example usage of the Tiled API on Flame.
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.5 KiB |
File diff suppressed because one or more lines are too long
@ -1,45 +0,0 @@
|
|||||||
import 'package:flame/sprite_animation.dart';
|
|
||||||
import 'package:flame/components/sprite_animation_component.dart';
|
|
||||||
import 'package:flame/components/tiled_component.dart';
|
|
||||||
import 'package:flame/flame.dart';
|
|
||||||
import 'package:flame/game.dart';
|
|
||||||
import 'package:flutter/widgets.dart' hide Animation;
|
|
||||||
import 'package:tiled/tiled.dart' show ObjectGroup, TmxObject;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
|
||||||
Flame.images.load('coins.png');
|
|
||||||
final TiledGame game = TiledGame();
|
|
||||||
runApp(game.widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
class TiledGame extends BaseGame {
|
|
||||||
TiledGame() {
|
|
||||||
final TiledComponent tiledMap = TiledComponent('map.tmx', 16.0);
|
|
||||||
add(tiledMap);
|
|
||||||
_addCoinsInMap(tiledMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _addCoinsInMap(TiledComponent tiledMap) async {
|
|
||||||
final ObjectGroup objGroup =
|
|
||||||
await tiledMap.getObjectGroupFromLayer('AnimatedCoins');
|
|
||||||
if (objGroup == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
objGroup.tmxObjects.forEach((TmxObject obj) {
|
|
||||||
final comp = SpriteAnimationComponent(
|
|
||||||
20.0,
|
|
||||||
20.0,
|
|
||||||
SpriteAnimation.sequenced(
|
|
||||||
'coins.png',
|
|
||||||
8,
|
|
||||||
textureWidth: 20,
|
|
||||||
textureHeight: 20,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
comp.x = obj.x.toDouble();
|
|
||||||
comp.y = obj.y.toDouble();
|
|
||||||
add(comp);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
name: tiled_example
|
|
||||||
description: A simple tiled example
|
|
||||||
|
|
||||||
version: 1.0.0+1
|
|
||||||
|
|
||||||
environment:
|
|
||||||
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
|
||||||
|
|
||||||
dependencies:
|
|
||||||
flutter:
|
|
||||||
sdk: flutter
|
|
||||||
flame:
|
|
||||||
path: ../../../
|
|
||||||
tiled: 0.6.0
|
|
||||||
|
|
||||||
dev_dependencies:
|
|
||||||
flutter_test:
|
|
||||||
sdk: flutter
|
|
||||||
|
|
||||||
flutter:
|
|
||||||
assets:
|
|
||||||
- assets/tiles/map.tmx
|
|
||||||
- assets/images/map-level1.png
|
|
||||||
- assets/images/map-level2.png
|
|
||||||
- assets/images/coins.png
|
|
||||||
@ -305,14 +305,18 @@ class RectComponent extends Component {
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Flare Particle
|
## Flare Particle
|
||||||
A container for `FlareAnimation`, it propagates `update` and `render` hooks to its child.
|
|
||||||
|
To use Flare within Flame, use the [`flame_flare`](https://github.com/flame-engine/flame_flare) package.
|
||||||
|
|
||||||
|
It will provide a class `FlareParticle` that is a container for `FlareActorAnimation`, it propagates `update` and `render` hooks to its child.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
|
import 'package:flame_flare/flame_flare.dart';
|
||||||
|
|
||||||
// During game initialisation
|
// During game initialisation
|
||||||
const flareSize = 32.0;
|
const flareSize = 32.0;
|
||||||
final flareAnimation = await FlareAnimation.load('assets/sparkle.flr');
|
final flareAnimation = FlareActorAnimation('assets/sparkle.flr');
|
||||||
flareAnimation.updateAnimation('Shine');
|
flareAnimation.width = flareSize;
|
||||||
flareAnimation.width = flareSize;
|
|
||||||
flareAnimation.height = flareSize;
|
flareAnimation.height = flareSize;
|
||||||
|
|
||||||
// Somewhere in game
|
// Somewhere in game
|
||||||
|
|||||||
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
[Tiled](https://www.mapeditor.org/) is an awesome tool to design levels and maps.
|
[Tiled](https://www.mapeditor.org/) is an awesome tool to design levels and maps.
|
||||||
|
|
||||||
Flame bundles a [dart package](https://pub.dev/packages/tiled) that allows you to parse tmx (xml) files and access the tiles, objects and everything in there.
|
Flame provides a package ([flame_tiled](https://github.com/flame-engine/flame_tiled)) which bundles a [dart package](https://pub.dev/packages/tiled) that allows you to parse tmx (xml) files and access the tiles, objects and everything in there.
|
||||||
|
|
||||||
Flame also provides a simple TiledComponent for the map rendering, which renders the tiles on the screen and supports rotations and flips.
|
Flame also provides a simple Tiled class and its component wrapper TiledComponent, for the map rendering, which renders the tiles on the screen and supports rotations and flips.
|
||||||
|
|
||||||
Other advanced features are not yet supported but you can easily read the objects and other features of the tmx and add custom behaviour (eg regions for triggers and walking areas, custom animated objects).
|
Other advanced features are not yet supported but you can easily read the objects and other features of the tmx and add custom behaviour (eg regions for triggers and walking areas, custom animated objects).
|
||||||
|
|
||||||
You can check a working example [here](/doc/examples/tiled).
|
You can check a working example [here](https://github.com/flame-engine/flame_tiled/tree/master/example).
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'dart:ui';
|
|||||||
import '../flare_animation.dart';
|
import '../flare_animation.dart';
|
||||||
import 'position_component.dart';
|
import 'position_component.dart';
|
||||||
|
|
||||||
|
@Deprecated("Use flame_flare package instead")
|
||||||
class FlareComponent extends PositionComponent {
|
class FlareComponent extends PositionComponent {
|
||||||
FlareAnimation _flareAnimation;
|
FlareAnimation _flareAnimation;
|
||||||
|
|
||||||
|
|||||||
@ -1,176 +0,0 @@
|
|||||||
import 'dart:math' as math;
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:ui';
|
|
||||||
|
|
||||||
import 'package:flame/components/component.dart';
|
|
||||||
import 'package:flame/flame.dart';
|
|
||||||
import 'package:flutter/material.dart' show Colors;
|
|
||||||
import 'package:tiled/tiled.dart' hide Image;
|
|
||||||
|
|
||||||
/// Tiled represents all flips and rotation using three possible flips: horizontal, vertical and diagonal.
|
|
||||||
/// This class converts that representation to a simpler one, that uses one angle (with pi/2 steps) and two flips (H or V).
|
|
||||||
/// More reference: https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#tile-flipping
|
|
||||||
class _SimpleFlips {
|
|
||||||
/// The angle (in steps of pi/2 rads), clockwise, around the center of the tile.
|
|
||||||
final int angle;
|
|
||||||
|
|
||||||
/// Whether to flip across a central vertical axis (passing through the center).
|
|
||||||
final bool flipH;
|
|
||||||
|
|
||||||
/// Whether to flip across a central horizontal axis (passing through the center).
|
|
||||||
final bool flipV;
|
|
||||||
|
|
||||||
_SimpleFlips(this.angle, this.flipH, this.flipV);
|
|
||||||
|
|
||||||
/// This is the conversion from the truth table that I drew.
|
|
||||||
factory _SimpleFlips.fromFlips(Flips flips) {
|
|
||||||
int angle;
|
|
||||||
bool flipV, flipH;
|
|
||||||
|
|
||||||
if (!flips.diagonally && !flips.vertically && !flips.horizontally) {
|
|
||||||
angle = 0;
|
|
||||||
flipV = false;
|
|
||||||
flipH = false;
|
|
||||||
} else if (!flips.diagonally && !flips.vertically && flips.horizontally) {
|
|
||||||
angle = 0;
|
|
||||||
flipV = false;
|
|
||||||
flipH = true;
|
|
||||||
} else if (!flips.diagonally && flips.vertically && !flips.horizontally) {
|
|
||||||
angle = 0;
|
|
||||||
flipV = true;
|
|
||||||
flipH = false;
|
|
||||||
} else if (!flips.diagonally && flips.vertically && flips.horizontally) {
|
|
||||||
angle = 2;
|
|
||||||
flipV = false;
|
|
||||||
flipH = false;
|
|
||||||
} else if (flips.diagonally && !flips.vertically && !flips.horizontally) {
|
|
||||||
angle = 1;
|
|
||||||
flipV = false;
|
|
||||||
flipH = true;
|
|
||||||
} else if (flips.diagonally && !flips.vertically && flips.horizontally) {
|
|
||||||
angle = 1;
|
|
||||||
flipV = false;
|
|
||||||
flipH = false;
|
|
||||||
} else if (flips.diagonally && flips.vertically && !flips.horizontally) {
|
|
||||||
angle = 3;
|
|
||||||
flipV = false;
|
|
||||||
flipH = false;
|
|
||||||
} else if (flips.diagonally && flips.vertically && flips.horizontally) {
|
|
||||||
angle = 1;
|
|
||||||
flipV = true;
|
|
||||||
flipH = false;
|
|
||||||
} else {
|
|
||||||
// this should be exhaustive
|
|
||||||
throw 'Invalid combination of booleans: $flips';
|
|
||||||
}
|
|
||||||
|
|
||||||
return _SimpleFlips(angle, flipH, flipV);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This component renders a tile map based on a TMX file from Tiled.
|
|
||||||
class TiledComponent extends Component {
|
|
||||||
String filename;
|
|
||||||
TileMap map;
|
|
||||||
Image image;
|
|
||||||
Map<String, Image> images = <String, Image>{};
|
|
||||||
Future future;
|
|
||||||
bool _loaded = false;
|
|
||||||
double destTileSize;
|
|
||||||
|
|
||||||
static Paint paint = Paint()..color = Colors.white;
|
|
||||||
|
|
||||||
/// Creates this TiledComponent with the filename (for the tmx file resource)
|
|
||||||
/// and destTileSize is the tile size to be rendered (not the tile size in the texture, that one is configured inside Tiled).
|
|
||||||
TiledComponent(this.filename, this.destTileSize) {
|
|
||||||
future = _load();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future _load() async {
|
|
||||||
map = await _loadMap();
|
|
||||||
image = await Flame.images.load(map.tilesets[0].image.source);
|
|
||||||
images = await _loadImages(map);
|
|
||||||
_loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<TileMap> _loadMap() {
|
|
||||||
return Flame.bundle.loadString('assets/tiles/$filename').then((contents) {
|
|
||||||
final parser = TileMapParser();
|
|
||||||
return parser.parse(contents);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Map<String, Image>> _loadImages(TileMap map) async {
|
|
||||||
final Map<String, Image> result = {};
|
|
||||||
await Future.forEach(map.tilesets, (tileset) async {
|
|
||||||
await Future.forEach(tileset.images, (tmxImage) async {
|
|
||||||
result[tmxImage.source] = await Flame.images.load(tmxImage.source);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool loaded() => _loaded;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void render(Canvas c) {
|
|
||||||
if (!loaded()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
map.layers.forEach((layer) {
|
|
||||||
if (layer.visible) {
|
|
||||||
_renderLayer(c, layer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _renderLayer(Canvas c, Layer layer) {
|
|
||||||
layer.tiles.forEach((tileRow) {
|
|
||||||
tileRow.forEach((tile) {
|
|
||||||
if (tile.gid == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final image = images[tile.image.source];
|
|
||||||
|
|
||||||
final rect = tile.computeDrawRect();
|
|
||||||
final src = Rect.fromLTWH(
|
|
||||||
rect.left.toDouble(),
|
|
||||||
rect.top.toDouble(),
|
|
||||||
rect.width.toDouble(),
|
|
||||||
rect.height.toDouble(),
|
|
||||||
);
|
|
||||||
final dst = Rect.fromLTWH(
|
|
||||||
tile.x * destTileSize,
|
|
||||||
tile.y * destTileSize,
|
|
||||||
destTileSize,
|
|
||||||
destTileSize,
|
|
||||||
);
|
|
||||||
|
|
||||||
final flips = _SimpleFlips.fromFlips(tile.flips);
|
|
||||||
c.save();
|
|
||||||
c.translate(dst.center.dx, dst.center.dy);
|
|
||||||
c.rotate(flips.angle * math.pi / 2);
|
|
||||||
c.scale(flips.flipV ? -1.0 : 1.0, flips.flipH ? -1.0 : 1.0);
|
|
||||||
c.translate(-dst.center.dx, -dst.center.dy);
|
|
||||||
|
|
||||||
c.drawImageRect(image, src, dst, paint);
|
|
||||||
c.restore();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void update(double t) {}
|
|
||||||
|
|
||||||
/// This returns an object group fetch by name from a given layer.
|
|
||||||
/// Use this to add custom behaviour to special objects and groups.
|
|
||||||
Future<ObjectGroup> getObjectGroupFromLayer(String name) {
|
|
||||||
return future.then((onValue) {
|
|
||||||
return map.objectGroups
|
|
||||||
.firstWhere((objectGroup) => objectGroup.name == name);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,6 +5,7 @@ import "flame.dart";
|
|||||||
import "package:flare_flutter/flare.dart";
|
import "package:flare_flutter/flare.dart";
|
||||||
import "package:flare_flutter/flare_actor.dart";
|
import "package:flare_flutter/flare_actor.dart";
|
||||||
|
|
||||||
|
@Deprecated("Use flame_flare package instead")
|
||||||
class FlareAnimation {
|
class FlareAnimation {
|
||||||
final FlutterActorArtboard _artboard;
|
final FlutterActorArtboard _artboard;
|
||||||
|
|
||||||
|
|||||||
39
lib/fps_counter.dart
Normal file
39
lib/fps_counter.dart
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
import 'game/game.dart';
|
||||||
|
|
||||||
|
mixin FPSCounter on Game {
|
||||||
|
/// List of deltas used in debug mode to calculate FPS
|
||||||
|
final List<double> _dts = [];
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
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.
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,8 @@
|
|||||||
import 'dart:math' as math;
|
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flame/components/composed_component.dart';
|
||||||
|
import 'package:flame/fps_counter.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter/widgets.dart' hide WidgetBuilder;
|
import 'package:flutter/widgets.dart' hide WidgetBuilder;
|
||||||
import 'package:ordered_set/comparing.dart';
|
import 'package:ordered_set/comparing.dart';
|
||||||
@ -20,7 +21,7 @@ import 'game.dart';
|
|||||||
/// It still needs to be subclasses to add your game logic, but the [update], [render] and [resize] methods have default implementations.
|
/// It still needs to be subclasses to add your game logic, but the [update], [render] and [resize] methods have default implementations.
|
||||||
/// This is the recommended structure to use for most games.
|
/// This is the recommended structure to use for most games.
|
||||||
/// It is based on the Component system.
|
/// It is based on the Component system.
|
||||||
class BaseGame extends Game {
|
class BaseGame extends Game with FPSCounter {
|
||||||
/// The list of components to be updated and rendered by the base game.
|
/// The list of components to be updated and rendered by the base game.
|
||||||
OrderedSet<Component> components =
|
OrderedSet<Component> components =
|
||||||
OrderedSet(Comparing.on((c) => c.priority()));
|
OrderedSet(Comparing.on((c) => c.priority()));
|
||||||
@ -37,9 +38,6 @@ class BaseGame extends Game {
|
|||||||
/// Camera position; every non-HUD component is translated so that the camera position is the top-left corner of the screen.
|
/// Camera position; every non-HUD component is translated so that the camera position is the top-left corner of the screen.
|
||||||
Position camera = Position.empty();
|
Position camera = Position.empty();
|
||||||
|
|
||||||
/// List of deltas used in debug mode to calculate FPS
|
|
||||||
final List<double> _dts = [];
|
|
||||||
|
|
||||||
/// This method is called for every component added, both via [add] and [addLater] methods.
|
/// This method is called for every component added, both via [add] and [addLater] methods.
|
||||||
///
|
///
|
||||||
/// You can use this to setup your mixins, pre-calculate stuff on every component, or anything you desire.
|
/// You can use this to setup your mixins, pre-calculate stuff on every component, or anything you desire.
|
||||||
@ -100,6 +98,7 @@ class BaseGame extends Game {
|
|||||||
/// You can override it further to add more custom behaviour.
|
/// You can override it further to add more custom behaviour.
|
||||||
/// Beware of however you are rendering components if not using this; you must be careful to save and restore the canvas to avoid components messing up with each other.
|
/// Beware of however you are rendering components if not using this; you must be careful to save and restore the canvas to avoid components messing up with each other.
|
||||||
@override
|
@override
|
||||||
|
@mustCallSuper
|
||||||
void render(Canvas canvas) {
|
void render(Canvas canvas) {
|
||||||
canvas.save();
|
canvas.save();
|
||||||
components.forEach((comp) => renderComponent(canvas, comp));
|
components.forEach((comp) => renderComponent(canvas, comp));
|
||||||
@ -127,6 +126,7 @@ class BaseGame extends Game {
|
|||||||
/// It also actually adds the components that were added by the [addLater] method, and remove those that are marked for destruction via the [Component.destroy] method.
|
/// It also actually adds the components that were added by the [addLater] method, and remove those that are marked for destruction via the [Component.destroy] method.
|
||||||
/// You can override it further to add more custom behaviour.
|
/// You can override it further to add more custom behaviour.
|
||||||
@override
|
@override
|
||||||
|
@mustCallSuper
|
||||||
void update(double t) {
|
void update(double t) {
|
||||||
_removeLater.forEach((c) => components.remove(c));
|
_removeLater.forEach((c) => components.remove(c));
|
||||||
_removeLater.clear();
|
_removeLater.clear();
|
||||||
@ -155,36 +155,8 @@ class BaseGame extends Game {
|
|||||||
/// You can use this value to enable debug behaviors for your game, many components show extra information on screen when on debug mode
|
/// You can use this value to enable debug behaviors for your game, many components show extra information on screen when on debug mode
|
||||||
bool debugMode() => false;
|
bool debugMode() => false;
|
||||||
|
|
||||||
/// 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.
|
|
||||||
bool recordFps() => false;
|
|
||||||
|
|
||||||
/// This is a hook that comes from the RenderBox to allow recording of render times and statistics.
|
|
||||||
@override
|
@override
|
||||||
void recordDt(double dt) {
|
bool recordFps() => false;
|
||||||
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.
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the current time in seconds with microseconds precision.
|
/// Returns the current time in seconds with microseconds precision.
|
||||||
///
|
///
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
|
|||||||
import '../flare_animation.dart';
|
import '../flare_animation.dart';
|
||||||
import '../particle.dart';
|
import '../particle.dart';
|
||||||
|
|
||||||
|
@Deprecated("Use flame_flare package instead")
|
||||||
class FlareParticle extends Particle {
|
class FlareParticle extends Particle {
|
||||||
final FlareAnimation flare;
|
final FlareAnimation flare;
|
||||||
|
|
||||||
|
|||||||
@ -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.24.0
|
version: 0.25.0
|
||||||
homepage: https://github.com/flame-engine/flame
|
homepage: https://github.com/flame-engine/flame
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -11,7 +11,6 @@ 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.6.0
|
|
||||||
convert: ^2.0.1
|
convert: ^2.0.1
|
||||||
flare_flutter: ^2.0.1
|
flare_flutter: ^2.0.1
|
||||||
meta: ^1.1.8
|
meta: ^1.1.8
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 KiB |
File diff suppressed because one or more lines are too long
@ -1,28 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'dart:io';
|
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
import 'package:flame/components/tiled_component.dart';
|
|
||||||
import 'package:flame/flame.dart';
|
|
||||||
import 'package:flutter/services.dart' show CachingAssetBundle;
|
|
||||||
import 'package:test/test.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
test('my first widget test', () async {
|
|
||||||
await Flame.init(bundle: TestAssetBundle());
|
|
||||||
final tiled = TiledComponent('x', 16);
|
|
||||||
await tiled.future;
|
|
||||||
expect(1, equals(1));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class TestAssetBundle extends CachingAssetBundle {
|
|
||||||
@override
|
|
||||||
Future<ByteData> load(String key) async => File('assets/map-level1.png')
|
|
||||||
.readAsBytes()
|
|
||||||
.then((bytes) => ByteData.view(Uint8List.fromList(bytes).buffer));
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<String> loadString(String key, {bool cache = true}) =>
|
|
||||||
File('assets/map.tmx').readAsString();
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user