Commit 0bbb25b2 authored by Viktor Lidholt's avatar Viktor Lidholt

Adds missing Flutter Sprites API docs and improved README (#4022)

parent 880f2f78
# Flutter Sprites
Flutter Sprites is a toolkit for building complex, high performance animations and 2D games with Flutter. Your sprite render tree lives inside a SpriteWidget that mixes seamlessly with other Flutter and Material widgets. You can use Flutter Sprites to create anything from an animated icon to a full fledged game.
A sprite toolkit built on top of Flutter.
This guide assumes a basic knowledge of Flutter and Dart. You can find an example of Flutter Sprites in the Flutter Gallery in the Weather demo, or in the flutter/game repository on Github.
## Getting Started
## Setting up a SpriteWidget
The first thing you need to do to use Flutter Sprites is to setup a SpriteWidget with a root node that is used to draw it's contents. Any sprite nodes that you add to the root node will be rendered by the SpriteWidget. Typically, your root node is part of your app's state. This is an example of how you can setup a custom stateful widget with Flutter Sprites:
For help getting started with Flutter, view our online
[documentation](http://flutter.io).
import 'package:flutter/material.dart';
import 'package:flutter_sprites/flutter_sprites.dart';
class MyWidget extends StatefulWidget {
@override
MyWidgetState createState() => new MyWidgetState();
}
class MyWidgetState extends State<MyWidget> {
NodeWithSize rootNode;
@override
void initState() {
super.initState();
rootNode = new NodeWithSize(const Size(1024.0, 1024.0));
}
@override
Widget build(BuildContext context) {
return new SpriteWidget(rootNode);
}
}
The root node that you provide the SpriteWidget is a NodeWithSize, the size of the root node defines the coordinate system used by the SpriteWidget. By default the SpriteWidget uses letterboxing to display its contents. This means that the size that you give the root node will determine how the SpriteWidget's contents will be scaled to fit. If it doesn't fit perfectly in the area of the widget, either its top and bottom or the left and right side will be trimmed. You can optionally pass in a parameter to the SpriteWidget for other scaling options depending on your needs.
When you have added the SpriteWidget to your app's build method it will automatically start running animations and handling user input. There is no need for any other extra setup.
## Adding objects to your node graph
Your SpriteWidget manages a node graph, the root node is the NodeWithSize that is passed in to the SpriteWidget when it's created. To render sprites, particles systems, or any other objects simply add them to the node graph.
Each node in the node graph has a transform. The transform is inherited by its children, this makes it possible to build more complex structures by grouping objects together as children to a node and then manipulating the parent node. For example the following code creates a car sprite with two wheels attached to it. The car is added to the root node.
Sprite car = new Sprite.fromImage(carImage);
Sprite frontWheel = new Sprite.fromImage(wheelImage);
Sprite rearWheel = new Sprite.fromImage(wheelImage);
frontWheel.position = const Point(100, 50);
rearWheel.position = const Point(-100, 50);
car.addChild(frontWheel);
car.addChild(rearWheel);
rootNode.addChild(car);
You can manipulate the transform by setting the position, rotation, scale, and skew properties.
## Sprites, textures, and sprite sheets
The most common node type is the Sprite node. A sprite simply draws an image to the screen. Sprites can be drawn from Image objects or Texture objects. A texture is a part of an Image. Using a SpriteSheet you can pack several texture elements within a single image. This saves space in the device's gpu memory and also make drawing faster. Currently Flutter Sprites supports sprite sheets in json format and produced with a tool such as TexturePacker. It's uncommon to manually edit the sprite sheet files. You can create a SpriteSheet with a definition in json and an image:
SpriteSheet sprites = new SpriteSheet(myImage, jsonCode);
Texture texture = sprites['texture.png'];
## The frame cycle
Each time a new frame is rendered to screen Flutter Sprites will perform a number of actions. Sometimes when creating more advanced interactive animations or games, the order in which these actions are performed may matter.
This is the order things will happen:
1. Handle input events
2. Run animation actions
3. Call update functions on nodes
4. Apply constraints
5. Render the frame to screen
Read more about each of the different phases below.
## Handling user input
You can subclass any node type to handle touches. To receive touches, you need to set the userInteractionEnabled property to true and override the handleEvent method. If the node you are subclassing doesn't have a size, you will also need to override the isPointInside method.
class EventHandlingNode extends NodeWithSize {
EventHandlingNode(Size size) : super(size) {
userInteractionEnabled = true;
}
@override handleEvent(SpriteBoxEvent event) {
if (event.type == PointerDownEvent)
...
else if (event.type == PointerMoveEvent)
...
return true;
}
}
If you want your node to receive multiple touches, set the handleMultiplePointers property to true. Each touch down or dragged touch will generate a separate call to the handleEvent method, you can distinguish each touch by its pointer property.
## Animating using actions
Flutter Sprites provides easy to use functions for animating nodes through actions. You can combine simple action blocks to create more complex animations.
To execute an action animation you first build the action itself, then pass it to the run method of a nodes action manager (see the Tweens section below for an example).
### Tweens
Tweens are the simplest building block for creating an animation. It will interpolate a value or property over a specified time period. You provide the ActionTween class with a setter function, its start and end value, and the duration for the tween.
After creating a tween, execute it by running it through a node's action manager.
Node myNode = new Node();
ActionTween myTween = new ActionTween(
(Point a) => myNode.position = a,
Point.origin,
const Point(100.0, 0.0),
1.0
);
myNode.actions.run(myTween);
You can animate values of different types, such as floats, points, rectangles, and even colors. You can also optionally provide the ActionTween class with an easing function.
### Sequences
When you need to play two or more actions in a sequence, use the ActionSequence class:
ActionSequence sequence = new ActionSequence([
firstAction,
middleAction,
lastAction
]);
### Groups
Use ActionGroup to play actions in parallel:
ActionGroup group = new ActionGroup([
action0,
action1
]);
### Repeat
You can loop any action, either a fixed number of times, or until the end of times:
ActionRepeat repeat = new ActionRepeat(loopedAction, 5);
ActionRepeatForever longLoop = new ActionRepeatForever(loopedAction);
### Composition
It's possible to create more complex actions by composing them in any way:
ActionSequence complexAction = new ActionSequence([
new ActionRepeat(myLoop, 2),
new ActionGroup([
action0,
action1
])
]);
## Handle update events
Each frame, update events are sent to each node in the current node tree. Override the update method to manually do animations or to perform game logic.
MyNode extends Node {
@override
update(double dt) {
// Move the node at a constant speed
position += new Offset(dt * 1.0, 0.0);
}
}
## Defining constraints
Constraints are used to constrain properties of nodes. They can be used to position nodes relative other nodes, or adjust the rotation or scale. You can apply more than one constraint to a single node.
For example, you can use a constraint to make a node follow another node at a specific distance with a specified dampening. The dampening will smoothen out the following node's movement.
followingNode.constraints = [
new ConstraintPositionToNode(
targetNode,
offset: const Offset(0.0, 100.0),
dampening: 0.5
)
];
Constraints are applied at the end of the frame cycle. If you need them to be applied at any other time, you can directly call the applyConstraints method of a Node object.
## Perform custom drawing
Flutter Sprites provides a default set of drawing primitives, but there are cases where you may want to perform custom drawing. To do this you will need to subclass either the Node or NodeWithSize class and override the paint method:
class RedCircle extends Node {
RedCircle(this.radius);
double radius;
@override
void paint(Canvas canvas) {
canvas.drawCircle(
Point.origin,
radius,
new Paint()..color = const Color(0xffff0000)
);
}
}
If you are overriding a NodeWithSize you may want to call applyTransformForPivot before starting drawing to account for the node's pivot point. After the call the coordinate system is setup so you can perform drawing starting at origo to the size of the node.
@override
void paint(Canvas canvas) {
applyTransformForPivot(canvas);
canvas.drawRect(
new Rect.fromLTWH(0.0, 0.0, size.width, size.height),
myPaint
);
}
## Add effects using particle systems
Particle systems are great for creating effects such as rain, smoke, or fire. It's easy to setup a particle system, but there are very many properties that can be tweaked. The best way of to get a feel for how they work is to simply play around with the them.
This is an example of how a particle system can be created, configured, and added to the scene:
ParticleSystem particles = new ParticleSystem(
particleTexture,
posVar: const Point(100, 100.0),
startSize: 1.0,
startSizeVar: 0.5,
endSize: 2.0,
endSizeVar: 1.0,
life: 1.5 * distance,
lifeVar: 1.0 * distance
);
rootNode.addChild(particles);
\ No newline at end of file
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// Signature for callbacks used by the [ActionCallFunction].
typedef void ActionCallback();
/// Actions are used to animate properties of nodes or any other type of
......@@ -34,19 +39,21 @@ abstract class Action {
_finished = false;
}
/// The total time it will take to complete the action, in seconds.
double get duration => 0.0;
}
/// Signature for callbacks for setting properties, used by [ActionTween].
typedef void SetterCallback(dynamic value);
/// The abstract class for an action that changes properties over a time
/// interval, optionally using an easing curve.
abstract class ActionInterval extends Action {
/// Creates a new ActionInterval, typically you will want to pass in a
/// [duration] to specify how long time the action will take to complete.
ActionInterval([this._duration = 0.0, this.curve]);
/// The duration, in seconds, of the action.
///
/// double myTime = myAction.duration;
@override
double get duration => _duration;
double _duration;
......@@ -84,9 +91,13 @@ abstract class ActionInterval extends Action {
}
}
/// An action that repeats an action a fixed number of times.
/// An action that repeats another action a fixed number of times.
class ActionRepeat extends ActionInterval {
/// The number of times the [action] is repeated.
final int numRepeats;
/// The action that is repeated.
final ActionInterval action;
int _lastFinishedRepeat = -1;
......@@ -119,6 +130,8 @@ class ActionRepeat extends ActionInterval {
/// An action that repeats an action an indefinite number of times.
class ActionRepeatForever extends Action {
/// The action that is repeated indefinitely.
final ActionInterval action;
double _elapsedInAction = 0.0;
......@@ -325,6 +338,8 @@ abstract class ActionInstant extends Action {
_finished = true;
}
/// Called when the action is executed. If you are implementing your own
/// ActionInstant, override this method.
void fire();
}
......@@ -546,6 +561,8 @@ class ActionController {
}
}
/// Steps the action forward by the specified time, typically there is no need
/// to directly call this method.
void step(double dt) {
for (int i = _actions.length - 1; i >= 0; i--) {
Action action = _actions[i];
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
Point _cardinalSplineAt(Point p0, Point p1, Point p2, Point p3, double tension, double t) {
......@@ -17,6 +21,7 @@ Point _cardinalSplineAt(Point p0, Point p1, Point p2, Point p3, double tension,
return new Point(x, y);
}
/// Signature for callbacks used by the [ActionSpline] to set a [Point] value.
typedef void PointSetterCallback(Point value);
/// The spline action is used to animate a point along a spline definied by
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// A sequence of colors representing a gradient or a color transition over
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// A constraint limits or otherwise controls a [Node]'s properties, such as
......@@ -139,8 +143,13 @@ class ConstraintPositionToNode extends Constraint {
/// same parent, but they need to be added to the same [SpriteBox].
ConstraintPositionToNode(this.targetNode, {this.dampening, this.offset: Offset.zero});
/// Target node to follow.
final Node targetNode;
/// Offset to the target node.
final Offset offset;
/// Dampening used when following the [targetNode], value between 0.0 and 1.0.
final double dampening;
@override
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// Used by [EffectLine] to determine how the width of the line is calculated.
enum EffectLineWidthMode {
/// Linear interpolation between minWidth at the start and maxWidth at the
/// end of the line.
linear,
/// Creates a barrel shaped line, with minWidth at the end points of the line
/// and maxWidth at the middle.
barrel,
}
/// Used by [EffectLine] to determine how the texture of the line is animated.
enum EffectLineAnimationMode {
/// The texture of the line isn't animated.
none,
/// The texture of the line is scrolling.
scroll,
/// The texture of the line is set to a random position at every frame. This
/// mode is useful for creating flashing or electricity styled effects.
random,
}
/// The EffectLine class is using the [TexturedLine] class to draw animated
/// lines. These can be used to draw things such as smoke trails, electricity
/// effects, or other animated types of lines.
class EffectLine extends Node {
/// Creates a new EffectLine with the specified parameters. Only the
/// [texture] parameter is required, all other parameters are optional.
EffectLine({
this.texture: null,
this.transferMode: TransferMode.dstOver,
......@@ -49,22 +73,41 @@ class EffectLine extends Node {
_painter.textureLoopLength = textureLoopLength;
}
/// The texture used to draw the line.
final Texture texture;
/// The transfer mode used to draw the line, default is
/// [TransferMode.dstOver].
final TransferMode transferMode;
/// Mode used to calculate the width of the line.
final EffectLineWidthMode widthMode;
/// The width of the line at its thinnest point.
final double minWidth;
/// The width of the line at its thickest point.
final double maxWidth;
/// The speed at which the line is growing, defined in points per second.
final double widthGrowthSpeed;
/// The mode used to animate the texture of the line.
final EffectLineAnimationMode animationMode;
/// The speed of which the texture of the line is scrolling. This property
/// is only used if the [animationMode] is set to
/// [EffectLineAnimationMode.scroll].
final double scrollSpeed;
ColorSequence _colorSequence;
/// Color gradient used to draw the line, from start to finish.
ColorSequence get colorSequence => _colorSequence;
List<Point> _points;
ColorSequence _colorSequence;
/// List of points that make up the line. Typically, you will only want to
/// set this at the beginning. Then use [addPoint] to add additional points
/// to the line.
List<Point> get points => _points;
set points(List<Point> points) {
......@@ -75,15 +118,26 @@ class EffectLine extends Node {
}
}
List<Point> _points;
List<double> _pointAges;
List<Color> _colors;
List<double> _widths;
/// The time it takes for an added point to fade out. It's total life time is
/// [fadeDuration] + [fadeAfterDelay].
final double fadeDuration;
/// The time it takes until an added point starts to fade out.
final double fadeAfterDelay;
/// The length, in points, that the texture is stretched to. If the
/// textureLoopLength is shorter than the line, the texture will be looped.
final double textureLoopLength;
/// True if the line should be simplified by removing points that are close
/// to other points. This makes drawing faster, but can result in a slight
/// jittering effect when points are added.
final bool simplify;
TexturedLinePainter _painter;
......@@ -168,6 +222,7 @@ class EffectLine extends Node {
_painter.paint(canvas);
}
/// Adds a new point to the end of the line.
void addPoint(Point point) {
// Skip duplicate points
if (points.length > 0 && point.x == points[points.length - 1].x && point.y == points[points.length - 1].y)
......
......@@ -4,12 +4,18 @@
part of flutter_sprites;
/// The ImageMap is a helper class for loading and keeping references to
/// multiple images.
class ImageMap {
/// Creates a new ImageMap where images will be loaded from the specified
/// [bundle].
ImageMap(AssetBundle bundle) : _bundle = bundle;
final AssetBundle _bundle;
final Map<String, ui.Image> _images = new Map<String, ui.Image>();
/// Loads a list of images given their urls.
Future<List<ui.Image>> load(List<String> urls) {
return Future.wait(urls.map(_loadImage));
}
......@@ -20,6 +26,9 @@ class ImageMap {
return image;
}
/// Returns a preloaded image, given its [url].
ui.Image getImage(String url) => _images[url];
/// Returns a preloaded image, given its [url].
ui.Image operator [](String url) => _images[url];
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// Labels are used to display a string of text in a the node tree. To align
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// A [Node] that provides an intermediate rendering surface in the sprite
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// A NineSliceSprite is similar to a [Sprite], but it it can strech its
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// Converts degrees to radians.
double convertDegrees2Radians(double degrees) => degrees * math.PI/180.8;
/// Converts radians to degrees.
double convertRadians2Degrees(double radians) => radians * 180.0/math.PI;
/// A base class for all objects that can be added to the sprite node tree and rendered to screen using [SpriteBox] and
......@@ -428,7 +434,8 @@ class Node {
return _transformMatrixBoxToNode;
}
Matrix4 inverseTransformMatrix() {
/// The inverse transform matrix used by this node.
Matrix4 get inverseTransformMatrix {
if (_transformMatrixInverse == null) {
_transformMatrixInverse = new Matrix4.copy(transformMatrix);
_transformMatrixInverse.invert();
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// An node that transforms its children using a 3D perspective projection. This
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// The super class of any [Node] that has a size.
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
class _Particle {
......@@ -41,6 +45,8 @@ class _ParticleAccelerations {
/// number of particles can never exceed the [maxParticles] limit.
class ParticleSystem extends Node {
/// Creates a new particle system with the given properties. The only
/// required parameter is the texture, all other parameters are optional.
ParticleSystem(this.texture,
{this.life: 1.5,
this.lifeVar: 1.0,
......@@ -208,6 +214,8 @@ class ParticleSystem extends Node {
double _emitCounter;
int _numEmittedParticles = 0;
/// The over all opacity of the particle system. This value is multiplied by
/// the opacity of the individual particles.
double opacity = 1.0;
static Paint _paint = new Paint()
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// An audio asset loaded by the SoundEffectPlayer.
class SoundEffect {
/// Creates a new sound effect with the given sound id. Normally,
/// SoundEffect objects are created through the [SoundEffectPlayer].
SoundEffect(this._soundId);
int _soundId;
......@@ -9,6 +16,9 @@ class SoundEffect {
/// A sound being played by the SoundEffectPlayer.
class SoundEffectStream {
/// Creates a new SoundEffectStream. Typically SoundEffectStream objects are
/// created by the SoundEffectPlayer.
SoundEffectStream(SoundEffectPlayer player, int streamId, {
double leftVolume,
double rightVolume,
......@@ -27,10 +37,12 @@ class SoundEffectStream {
SoundPoolProxy get _soundPool => _player._soundPool;
/// Stop the sound effect.
void stop() {
_soundPool.ptr.stop(_streamId);
}
/// True if the sound effect is paused.
bool get paused => _paused;
bool _paused;
set paused(bool value) {
......@@ -42,6 +54,7 @@ class SoundEffectStream {
}
}
/// Left volume of the sound effect, valid values are 0.0 to 1.0.
double get leftVolume => _leftVolume;
double _leftVolume;
set leftVolume(double value) {
......@@ -49,6 +62,7 @@ class SoundEffectStream {
_soundPool.ptr.setVolume(_streamId, <double>[_leftVolume, _rightVolume]);
}
/// Right volume of the sound effect, valid values are 0.0 to 1.0.
double get rightVolume => _rightVolume;
double _rightVolume;
set rightVolume(double value) {
......@@ -56,6 +70,8 @@ class SoundEffectStream {
_soundPool.ptr.setVolume(_streamId, <double>[_leftVolume, _rightVolume]);
}
/// The pitch of the sound effect, a value of 1.0 plays back the sound effect
/// at normal speed. Cannot be negative.
double get pitch => _pitch;
double _pitch;
set pitch(double value) {
......@@ -64,7 +80,11 @@ class SoundEffectStream {
}
}
/// The SoundEffectPlayer loads and plays sound effects.
class SoundEffectPlayer {
/// Creates a new SoundEffectPlayer with a max number of simultaneous
/// streams specified.
SoundEffectPlayer(int maxStreams) {
MediaServiceProxy mediaService = new MediaServiceProxy.unbound();
shell.connectToService("mojo:media_service", mediaService);
......@@ -76,6 +96,7 @@ class SoundEffectPlayer {
bool _paused;
int _nextStreamId = 0;
/// Loads a sound effect.
Future<SoundEffect> load(MojoDataPipeConsumer data) async {
SoundPoolLoadResponseParams result = await _soundPool.ptr.load(data);
if (result.success)
......@@ -84,6 +105,7 @@ class SoundEffectPlayer {
throw new Exception('Unable to load sound');
}
/// Plays a sound effect.
Future<SoundEffectStream> play(SoundEffect sound, {
double leftVolume: 1.0,
double rightVolume: 1.0,
......@@ -106,6 +128,7 @@ class SoundEffectPlayer {
throw new Exception('Unable to play sound');
}
/// Set to true to pause a sound effect.
bool get paused => _paused;
set paused(bool value) {
......@@ -118,23 +141,44 @@ class SoundEffectPlayer {
}
}
/// Signature for callbacks used by [SoundTrack].
typedef void SoundTrackCallback(SoundTrack soundTrack);
/// Signature for callbacks used by [SoundTrack].
typedef void SoundTrackBufferingCallback(SoundTrack soundTrack, int index);
/// A sound track is typically longer than a [SoundEffect]. Use sound tracks to
/// play back music or ambient sounds.
class SoundTrack {
MediaPlayerProxy _player;
/// Called when the sound has finished playing.
SoundTrackCallback onSoundComplete;
/// Called when a seek operation has finished.
SoundTrackCallback onSeekComplete;
/// Called when buffering is being performed.
SoundTrackBufferingCallback onBufferingUpdate;
/// If true, the sound track will automatically loop.
bool loop;
/// The current playback time in seconds.
double time;
/// The volume the sound track is currently played at, valid range is 0.0 to
/// 1.0.
double volume;
}
SoundTrackPlayer _sharedSoundTrackPlayer;
/// Loads and plays [SoundTrack]s.
class SoundTrackPlayer {
/// Creates a new [SoundTrackPlayer], typically you will want to use the
/// [sharedInstance] method to receive the player.
SoundTrackPlayer() {
_mediaService = new MediaServiceProxy.unbound();
shell.connectToService("mojo:media_service", _mediaService);
......@@ -144,10 +188,13 @@ class SoundTrackPlayer {
Set<SoundTrack> _soundTracks = new HashSet<SoundTrack>();
/// Retrives a singleton object of the SoundTrackPlayer, use this method
/// in favor for the constructor.
static SoundTrackPlayer sharedInstance() {
return _sharedSoundTrackPlayer ??= new SoundTrackPlayer();
}
/// Loads a [SoundTrack].
Future<SoundTrack> load(Future<MojoDataPipeConsumer> pipe) async {
// Create media player
SoundTrack soundTrack = new SoundTrack();
......@@ -158,11 +205,13 @@ class SoundTrackPlayer {
return soundTrack;
}
/// Unloads a [SoundTrack] from memory.
void unload(SoundTrack soundTrack) {
stop(soundTrack);
_soundTracks.remove(soundTrack);
}
/// Plays a [SoundTrack].
void play(SoundTrack soundTrack, {
bool loop: false,
double volume: 1.0,
......@@ -175,15 +224,19 @@ class SoundTrackPlayer {
_soundTracks.add(soundTrack);
}
/// Stops a [SoundTrack]. You may also want to call the [unload] method to
/// remove if from memory if you are not planning to play it again.
void stop(SoundTrack track) {
track._player.ptr.pause();
}
/// Pauses all [SoundTrack]s that are currently playing.
void pauseAll() {
for (SoundTrack soundTrack in _soundTracks)
soundTrack._player.ptr.pause();
}
/// Resumes all [SoundTrack]s that have been loaded by this player.
void resumeAll() {
for (SoundTrack soundTrack in _soundTracks)
soundTrack._player.ptr.start();
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// A Sprite is a [Node] that renders a bitmap image to the screen.
......@@ -84,6 +88,8 @@ class Sprite extends NodeWithSize with SpritePaint {
}
}
/// Defines properties, such as [opacity] and [transferMode] that are shared
/// between [Node]s that render textures to screen.
abstract class SpritePaint {
double _opacity = 1.0;
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// Options for setting up a [SpriteBox].
///
/// * [nativePoints]: use the same points as the parent [Widget].
/// * [letterbox]: use the size of the root node for the coordinate system, and constrain the aspect ratio and trim off
/// areas that end up outside the screen.
/// * [stretch]: use the size of the root node for the coordinate system, and scale it to fit the size of the box.
/// * [scaleToFit]: similar to the letterbox option, but instead of trimming areas the sprite system will be scaled
/// down to fit the box.
/// * [fixedWidth]: use the width of the root node to set the size of the coordinate system, and change
/// the height of the root node to fit the box.
/// * [fixedHeight]: use the height of the root node to set the size of the coordinate system, and change
/// the width of the root node to fit the box.
/// Options for setting up a [SpriteBox]'s coordinate system.
enum SpriteBoxTransformMode {
/// Use the same points as the parent [Widget].
nativePoints,
/// Use the size of the root node for the coordinate system, and constrain the
/// aspect ratio and trim off areas that end up outside the screen.
letterbox,
/// Use the size of the root node for the coordinate system, and scale it to
/// fit the size of the box.
stretch,
/// Similar to the letterbox option, but instead of trimming areas the sprite
/// system will be scaled down to fit the box.
scaleToFit,
/// Use the width of the root node to set the size of the coordinate system,
/// and change the height of the root node to fit the box.
fixedWidth,
/// Use the height of the root node to set the size of the coordinate system,
/// and change the width of the root node to fit the box.
fixedHeight,
}
/// A [RenderBox] that draws a sprite world represented by a [Node] tree.
class SpriteBox extends RenderBox {
// Setup
......@@ -71,31 +81,6 @@ class SpriteBox extends RenderBox {
// Member variables
// Root node for drawing
NodeWithSize _rootNode;
set rootNode (NodeWithSize value) {
if (value == _rootNode) return;
// Ensure that the root node has a size
assert(_transformMode == SpriteBoxTransformMode.nativePoints
|| value.size.width > 0);
assert(_transformMode == SpriteBoxTransformMode.nativePoints
|| value.size.height > 0);
// Remove sprite box references
if (_rootNode != null)
_removeSpriteBoxReference(_rootNode);
// Update the value
_rootNode = value;
_actionControllers = null;
// Add new references
_addSpriteBoxReference(_rootNode);
markNeedsLayout();
}
// Tracking of frame rate and updates
Duration _lastTimeStamp;
double _frameRate = 0.0;
......@@ -126,14 +111,16 @@ class SpriteBox extends RenderBox {
List<Node> _constrainedNodes;
Rect _visibleArea;
/// A rectangle that represents the visible area of the sprite world's
/// coordinate system.
Rect get visibleArea {
if (_visibleArea == null)
_calcTransformMatrix();
return _visibleArea;
}
Rect _visibleArea;
bool _initialized = false;
// Properties
......@@ -143,6 +130,30 @@ class SpriteBox extends RenderBox {
/// var rootNode = mySpriteBox.rootNode;
NodeWithSize get rootNode => _rootNode;
NodeWithSize _rootNode;
set rootNode (NodeWithSize value) {
if (value == _rootNode) return;
// Ensure that the root node has a size
assert(_transformMode == SpriteBoxTransformMode.nativePoints
|| value.size.width > 0);
assert(_transformMode == SpriteBoxTransformMode.nativePoints
|| value.size.height > 0);
// Remove sprite box references
if (_rootNode != null)
_removeSpriteBoxReference(_rootNode);
// Update the value
_rootNode = value;
_actionControllers = null;
// Add new references
_addSpriteBoxReference(_rootNode);
markNeedsLayout();
}
@override
void performLayout() {
size = constraints.biggest;
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// A widget that uses a [SpriteBox] to render a sprite node tree to the screen.
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// A sprite sheet packs a number of smaller images into a single large image.
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// A texture represents a rectangular area of an image and is typically used to draw a sprite to the screen.
......@@ -65,6 +69,7 @@ class Texture {
/// myTexture.pivot = new Point(0.5, 0.5);
Point pivot;
/// Creates a new Texture from a part of the current texture.
Texture textureFromRect(Rect rect, [String name = null]) {
assert(rect != null);
assert(!rotated);
......@@ -73,6 +78,8 @@ class Texture {
return new Texture._fromSpriteFrame(image, name, rect.size, false, false, srcFrame, dstFrame, new Point(0.5, 0.5));
}
/// Draws the texture to a [Canvas] at a specified [position] and with the
/// specified [paint].
void drawTexture(Canvas canvas, Point position, Paint paint) {
// Get drawing position
double x = position.x;
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// A [Node] that draws a polyline from a list of points using the provided
/// [Texture]. The textured line draws static lines. If you want to create an
/// animated line, consider using the [EffectLine] instead.
class TexturedLine extends Node {
/// Creates a new TexturedLine.
TexturedLine(List<Point> points, List<Color> colors, List<double> widths, [Texture texture, List<double> textureStops]) {
painter = new TexturedLinePainter(points, colors, widths, texture, textureStops);
}
/// The painter used to draw the line.
TexturedLinePainter painter;
@override
......@@ -13,26 +23,34 @@ class TexturedLine extends Node {
}
}
/// Draws a polyline to a [Canvas] from a list of points using the provided [Texture].
class TexturedLinePainter {
TexturedLinePainter(this._points, this.colors, this.widths, [Texture texture, this.textureStops]) {
this.texture = texture;
}
List<Point> _points;
/// The points that makes up the polyline.
List<Point> get points => _points;
List<Point> _points;
set points(List<Point> points) {
_points = points;
_calculatedTextureStops = null;
}
/// The color of each point on the polyline. The color of the line will be
/// interpolated between the points.
List<Color> colors;
/// The width of the line at each point on the polyline.
List<double> widths;
Texture _texture;
/// The texture this line will be drawn using.
Texture get texture => _texture;
Texture _texture;
set texture(Texture texture) {
_texture = texture;
if (texture == null) {
......@@ -47,41 +65,51 @@ class TexturedLinePainter {
}
}
/// Defines the position in the texture for each point on the polyline.
List<double> textureStops;
List<double> _calculatedTextureStops;
/// The [textureStops] used if no explicit texture stops has been provided.
List<double> get calculatedTextureStops {
if (_calculatedTextureStops == null)
_calculateTextureStops();
return _calculatedTextureStops;
}
List<double> _calculatedTextureStops;
double _length;
/// The length of the line.
double get length {
if (_calculatedTextureStops == null)
_calculateTextureStops();
return _length;
}
/// The offset of the texture on the line.
double textureStopOffset = 0.0;
double _textureLoopLength;
/// The length, in points, that the texture is stretched to. If the
/// textureLoopLength is shorter than the line, the texture will be looped.
double get textureLoopLength => textureLoopLength;
double _textureLoopLength;
set textureLoopLength(double textureLoopLength) {
_textureLoopLength = textureLoopLength;
_calculatedTextureStops = null;
}
/// If true, the textured line attempts to remove artifacts at sharp corners
/// on the polyline.
bool removeArtifacts = true;
/// The [TransferMode] used to draw the line to the [Canvas].
TransferMode transferMode = TransferMode.srcOver;
Paint _cachedPaint = new Paint();
/// Paints the line to the [canvas].
void paint(Canvas canvas) {
// Check input values
assert(_points != null);
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
part of flutter_sprites;
/// Provides a virtual joystick that can easily be added to your sprite scene.
class VirtualJoystick extends NodeWithSize {
/// Creates a new virtual joystick.
VirtualJoystick() : super(new Size(160.0, 160.0)) {
userInteractionEnabled = true;
handleMultiplePointers = false;
......@@ -17,11 +24,15 @@ class VirtualJoystick extends NodeWithSize {
..style = PaintingStyle.stroke;
}
Point _value = Point.origin;
/// Reads the current value of the joystick. A point with from (-1.0, -1.0)
/// to (1.0, 1.0). If the joystick isn't moved it will return (0.0, 0.0).
Point get value => _value;
Point _value = Point.origin;
bool _isDown = false;
/// True if the user is currently touching the joystick.
bool get isDown => _isDown;
bool _isDown = false;
Point _pointerDownAt;
Point _center;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment