Commit 639e47bd authored by Viktor Lidholt's avatar Viktor Lidholt

Adds API documentation, improves the API names, and cleans up code.

R=ianh@google.com

Review URL: https://codereview.chromium.org/1201983004.
parent 5b594b7c
...@@ -42,7 +42,7 @@ class GameDemoWorld extends NodeWithSize { ...@@ -42,7 +42,7 @@ class GameDemoWorld extends NodeWithSize {
StarField _starField; StarField _starField;
Nebula _nebula; Nebula _nebula;
GameDemoWorld(ImageMap images) : super.withSize(new Size(_gameSizeWidth, _gameSizeHeight)) { GameDemoWorld(ImageMap images) : super(new Size(_gameSizeWidth, _gameSizeHeight)) {
// Fetch images // Fetch images
_imgBg = images["https://raw.githubusercontent.com/slembcke/GalacticGuardian.spritebuilder/GDC/Packages/SpriteBuilder%20Resources.sbpack/resources-auto/BurnTexture.png"]; _imgBg = images["https://raw.githubusercontent.com/slembcke/GalacticGuardian.spritebuilder/GDC/Packages/SpriteBuilder%20Resources.sbpack/resources-auto/BurnTexture.png"];
...@@ -81,7 +81,7 @@ class GameDemoWorld extends NodeWithSize { ...@@ -81,7 +81,7 @@ class GameDemoWorld extends NodeWithSize {
// Methods for adding game objects // Methods for adding game objects
void addBackground() { void addBackground() {
Sprite sprtBg = new Sprite.withImage(_imgBg); Sprite sprtBg = new Sprite(_imgBg);
sprtBg.size = new Size(_gameSizeWidth, _gameSizeHeight); sprtBg.size = new Size(_gameSizeWidth, _gameSizeHeight);
sprtBg.pivot = Point.origin; sprtBg.pivot = Point.origin;
_gameLayer.addChild(sprtBg); _gameLayer.addChild(sprtBg);
...@@ -296,7 +296,7 @@ class Asteroid extends Sprite { ...@@ -296,7 +296,7 @@ class Asteroid extends Sprite {
return _radius; return _radius;
} }
Asteroid.withImage(Image img, AsteroidSize this._asteroidSize) : super.withImage(img) { Asteroid.withImage(Image img, AsteroidSize this._asteroidSize) : super(img) {
size = new Size(radius * 2.0, radius * 2.0); size = new Size(radius * 2.0, radius * 2.0);
position = new Point(_gameSizeWidth * _rand.nextDouble(), _gameSizeHeight * _rand.nextDouble()); position = new Point(_gameSizeWidth * _rand.nextDouble(), _gameSizeHeight * _rand.nextDouble());
rotation = 360.0 * _rand.nextDouble(); rotation = 360.0 * _rand.nextDouble();
...@@ -322,7 +322,7 @@ class Ship extends Sprite { ...@@ -322,7 +322,7 @@ class Ship extends Sprite {
Vector2 _movementVector; Vector2 _movementVector;
double _rotationTarget; double _rotationTarget;
Ship.withImage(Image img) : super.withImage(img) { Ship.withImage(Image img) : super(img) {
_movementVector = new Vector2.zero(); _movementVector = new Vector2.zero();
rotation = _rotationTarget = 270.0; rotation = _rotationTarget = 270.0;
...@@ -350,7 +350,7 @@ class Laser extends Sprite { ...@@ -350,7 +350,7 @@ class Laser extends Sprite {
Point _movementVector; Point _movementVector;
double radius = 10.0; double radius = 10.0;
Laser.withImage(Image img, Ship ship) : super.withImage(img) { Laser.withImage(Image img, Ship ship) : super(img) {
size = new Size(20.0, 20.0); size = new Size(20.0, 20.0);
position = ship.position; position = ship.position;
rotation = ship.rotation + 90.0; rotation = ship.rotation + 90.0;
...@@ -436,7 +436,7 @@ class Nebula extends Node { ...@@ -436,7 +436,7 @@ class Nebula extends Node {
Nebula.withImage(Image img) { Nebula.withImage(Image img) {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
Sprite sprt = new Sprite.withImage(img); Sprite sprt = new Sprite(img);
sprt.pivot = Point.origin; sprt.pivot = Point.origin;
sprt.position = new Point(i * _gameSizeWidth - _gameSizeWidth, j * _gameSizeHeight - _gameSizeHeight); sprt.position = new Point(i * _gameSizeWidth - _gameSizeWidth, j * _gameSizeHeight - _gameSizeHeight);
addChild(sprt); addChild(sprt);
......
This diff is collapsed.
part of sprites; part of sprites;
/// The super class of any [Node] that has a size.
///
/// NodeWithSize adds the ability for a node to have a size and a pivot point.
abstract class NodeWithSize extends Node { abstract class NodeWithSize extends Node {
/// Changing the size will affect the size of the rendering of the node.
///
/// myNode.size = new Size(1024.0, 1024.0);
Size size; Size size;
Point pivot;
NodeWithSize() { /// The normalized point which the node is transformed around.
size = Size.zero; ///
pivot = Point.origin; /// // Position myNode from is middle top
} /// myNode.pivot = new Point(0.5, 0.0);
Point pivot;
NodeWithSize.withSize(Size this.size, [Point this.pivot]) { /// Creates a new NodeWithSize.
///
/// The default [size] is zero and the default [pivot] point is the origin. Subclasses may change the default values.
///
/// var myNodeWithSize = new NodeWithSize(new Size(1024.0, 1024.0));
NodeWithSize([Size this.size, Point this.pivot]) {
if (size == null) size = Size.zero;
if (pivot == null) pivot = Point.origin; if (pivot == null) pivot = Point.origin;
} }
/// Call this method in your [paint] method if you want the origin of your drawing to be the top left corner of the
/// node's bounding box.
///
/// If you use this method you will need to save and restore your canvas at the beginning and
/// end of your [paint] method.
///
/// void paint(PictureRecorder canvas) {
/// canvas.save();
/// applyTransformForPivot(canvas);
///
/// // Do painting here
///
/// canvas.restore();
/// }
void applyTransformForPivot(PictureRecorder canvas) { void applyTransformForPivot(PictureRecorder canvas) {
if (pivot.x != 0 || pivot.y != 0) { if (pivot.x != 0 || pivot.y != 0) {
double pivotInPointsX = size.width * pivot.x; double pivotInPointsX = size.width * pivot.x;
......
part of sprites; part of sprites;
// TODO: Actually draw images /// A Sprite is a [Node] that renders a bitmap image to the screen.
class Sprite extends NodeWithSize { class Sprite extends NodeWithSize {
Image _image; /// The image that the sprite will render to screen.
///
/// If the image is null, the sprite will be rendered as a red square
/// marking the bounds of the sprite.
///
/// mySprite.image = myImage;
Image image;
/// If true, constrains the proportions of the image by scaling it down, if its proportions doesn't match the [size].
///
/// mySprite.constrainProportions = true;
bool constrainProportions = false; bool constrainProportions = false;
double _opacity = 1.0; double _opacity = 1.0;
/// The color to draw on top of the sprite, null if no color overlay is used.
///
/// // Color the sprite red
/// mySprite.colorOverlay = new Color(0x77ff0000);
Color colorOverlay; Color colorOverlay;
TransferMode transferMode;
Sprite() { /// The transfer mode used when drawing the sprite to screen.
} ///
/// // Add the colors of the sprite with the colors of the background
/// mySprite.transferMode = TransferMode.plusMode;
TransferMode transferMode;
Sprite.withImage(Image image) { /// Creates a new sprite from the provided [image].
///
/// var mySprite = new Sprite(myImage);
Sprite([Image this.image]) {
pivot = new Point(0.5, 0.5); pivot = new Point(0.5, 0.5);
if (image != null) {
size = new Size(image.width.toDouble(), image.height.toDouble()); size = new Size(image.width.toDouble(), image.height.toDouble());
_image = image; }
} }
/// The opacity of the sprite in the range 0.0 to 1.0.
///
/// mySprite.opacity = 0.5;
double get opacity => _opacity; double get opacity => _opacity;
void set opacity(double opacity) { void set opacity(double opacity) {
...@@ -33,19 +56,19 @@ class Sprite extends NodeWithSize { ...@@ -33,19 +56,19 @@ class Sprite extends NodeWithSize {
// Account for pivot point // Account for pivot point
applyTransformForPivot(canvas); applyTransformForPivot(canvas);
if (_image != null && _image.width > 0 && _image.height > 0) { if (image != null && image.width > 0 && image.height > 0) {
double scaleX = size.width/_image.width; double scaleX = size.width/image.width;
double scaleY = size.height/_image.height; double scaleY = size.height/image.height;
if (constrainProportions) { if (constrainProportions) {
// Constrain proportions, using the smallest scale and by centering the image // Constrain proportions, using the smallest scale and by centering the image
if (scaleX < scaleY) { if (scaleX < scaleY) {
canvas.translate(0.0, (size.height - scaleX * _image.height)/2.0); canvas.translate(0.0, (size.height - scaleX * image.height)/2.0);
scaleY = scaleX; scaleY = scaleX;
} }
else { else {
canvas.translate((size.width - scaleY * _image.width)/2.0, 0.0); canvas.translate((size.width - scaleY * image.width)/2.0, 0.0);
scaleX = scaleY; scaleX = scaleY;
} }
} }
...@@ -62,7 +85,7 @@ class Sprite extends NodeWithSize { ...@@ -62,7 +85,7 @@ class Sprite extends NodeWithSize {
paint.setTransferMode(transferMode); paint.setTransferMode(transferMode);
} }
canvas.drawImage(_image, 0.0, 0.0, paint); canvas.drawImage(image, 0.0, 0.0, paint);
} }
else { else {
// Paint a red square for missing texture // Paint a red square for missing texture
......
part of sprites; part of 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, 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, 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], uses the width of the root node to set the size of the coordinate system, this option will change
/// the height of the root node to fit the box.
/// * [fixedHeight], uses the height of the root node to set the size of the coordinate system, this option will change
/// the width of the root node to fit the box.
enum SpriteBoxTransformMode { enum SpriteBoxTransformMode {
nativePoints, nativePoints,
letterbox, letterbox,
...@@ -22,9 +34,10 @@ class SpriteBox extends RenderBox { ...@@ -22,9 +34,10 @@ class SpriteBox extends RenderBox {
double _frameRate = 0.0; double _frameRate = 0.0;
// Transformation mode // Transformation mode
SpriteBoxTransformMode transformMode; SpriteBoxTransformMode _transformMode;
// double _systemWidth;
// double _systemHeight; /// The transform mode used by the [SpriteBox].
SpriteBoxTransformMode get transformMode => _transformMode;
// Cached transformation matrix // Cached transformation matrix
Matrix4 _transformMatrix; Matrix4 _transformMatrix;
...@@ -33,7 +46,14 @@ class SpriteBox extends RenderBox { ...@@ -33,7 +46,14 @@ class SpriteBox extends RenderBox {
// Setup // Setup
SpriteBox(NodeWithSize rootNode, [SpriteBoxTransformMode mode = SpriteBoxTransformMode.nativePoints]) { /// Creates a new SpriteBox with a node as its content, by default uses letterboxing.
///
/// The [rootNode] provides the content of the node tree, typically it's a custom subclass of [NodeWithSize]. The
/// [mode] provides different ways to scale the content to best fit it to the screen. In most cases it's preferred to
/// use a [SpriteWidget] that automatically wraps the SpriteBox.
///
/// var spriteBox = new SpriteBox(myNode, SpriteBoxTransformMode.fixedHeight);
SpriteBox(NodeWithSize rootNode, [SpriteBoxTransformMode mode = SpriteBoxTransformMode.letterbox]) {
assert(rootNode != null); assert(rootNode != null);
assert(rootNode._spriteBox == null); assert(rootNode._spriteBox == null);
...@@ -44,9 +64,7 @@ class SpriteBox extends RenderBox { ...@@ -44,9 +64,7 @@ class SpriteBox extends RenderBox {
_addSpriteBoxReference(_rootNode); _addSpriteBoxReference(_rootNode);
// Setup transform mode // Setup transform mode
transformMode = mode; _transformMode = mode;
// _systemWidth = rootNode.size.width;
// _systemHeight = rootNode.size.height;
_scheduleTick(); _scheduleTick();
} }
...@@ -60,9 +78,9 @@ class SpriteBox extends RenderBox { ...@@ -60,9 +78,9 @@ class SpriteBox extends RenderBox {
// Properties // Properties
double get systemWidth => rootNode.size.width; /// The root node of the node tree that is rendered by this box.
double get systemHeight => rootNode.size.height; ///
/// var rootNode = mySpriteBox.rootNode;
NodeWithSize get rootNode => _rootNode; NodeWithSize get rootNode => _rootNode;
void performLayout() { void performLayout() {
...@@ -98,7 +116,7 @@ class SpriteBox extends RenderBox { ...@@ -98,7 +116,7 @@ class SpriteBox extends RenderBox {
} }
} }
void handleEvent(Event event, SpriteBoxHitTestEntry entry) { void handleEvent(Event event, _SpriteBoxHitTestEntry entry) {
if (event is PointerEvent) { if (event is PointerEvent) {
if (event.type == 'pointerdown') { if (event.type == 'pointerdown') {
...@@ -148,12 +166,17 @@ class SpriteBox extends RenderBox { ...@@ -148,12 +166,17 @@ class SpriteBox extends RenderBox {
} }
bool hitTest(HitTestResult result, { Point position }) { bool hitTest(HitTestResult result, { Point position }) {
result.add(new SpriteBoxHitTestEntry(this, position)); result.add(new _SpriteBoxHitTestEntry(this, position));
return true; return true;
} }
// Rendering // Rendering
/// The transformation matrix used to transform the root node to the space of the box.
///
/// It's uncommon to need access to this property.
///
/// var matrix = mySpriteBox.transformMatrix;
Matrix4 get transformMatrix { Matrix4 get transformMatrix {
// Get cached matrix if available // Get cached matrix if available
if (_transformMatrix != null) { if (_transformMatrix != null) {
...@@ -171,7 +194,7 @@ class SpriteBox extends RenderBox { ...@@ -171,7 +194,7 @@ class SpriteBox extends RenderBox {
double systemWidth = rootNode.size.width; double systemWidth = rootNode.size.width;
double systemHeight = rootNode.size.height; double systemHeight = rootNode.size.height;
switch(transformMode) { switch(_transformMode) {
case SpriteBoxTransformMode.stretch: case SpriteBoxTransformMode.stretch:
scaleX = size.width/systemWidth; scaleX = size.width/systemWidth;
scaleY = size.height/systemHeight; scaleY = size.height/systemHeight;
...@@ -287,6 +310,12 @@ class SpriteBox extends RenderBox { ...@@ -287,6 +310,12 @@ class SpriteBox extends RenderBox {
// Hit tests // Hit tests
/// Finds all nodes at a position defined in the box's coordinates.
///
/// Use this method with caution. It searches the complete node tree to locate the nodes, which can be slow if the
/// node tree is large.
///
/// List nodes = mySpriteBox.findNodesAtPosition(new Point(50.0, 50.0));
List<Node> findNodesAtPosition(Point position) { List<Node> findNodesAtPosition(Point position) {
assert(position != null); assert(position != null);
...@@ -311,15 +340,44 @@ class SpriteBox extends RenderBox { ...@@ -311,15 +340,44 @@ class SpriteBox extends RenderBox {
} }
} }
class SpriteBoxHitTestEntry extends BoxHitTestEntry { class _SpriteBoxHitTestEntry extends BoxHitTestEntry {
List<Node> nodeTargets; List<Node> nodeTargets;
SpriteBoxHitTestEntry(RenderBox target, Point localPosition) : super(target, localPosition); _SpriteBoxHitTestEntry(RenderBox target, Point localPosition) : super(target, localPosition);
} }
/// An event that is passed down the node tree when pointer events occur. The SpriteBoxEvent is typically handled in
/// the handleEvent method of [Node].
class SpriteBoxEvent { class SpriteBoxEvent {
Point boxPosition;
String type;
int pointer;
/// The position of the event in box coordinates.
///
/// You can use the convertPointToNodeSpace of [Node] to convert the position to local coordinates.
///
/// bool handleEvent(SpriteBoxEvent event) {
/// Point localPosition = convertPointToNodeSpace(event.boxPosition);
/// if (event.type == 'pointerdown') {
/// // Do something!
/// }
/// }
final Point boxPosition;
/// The type of event, there are currently four valid types, 'pointerdown', 'pointermoved', 'pointerup', and
/// 'pointercancel'.
///
/// if (event.type == 'pointerdown') {
/// // Do something!
/// }
final String type;
/// The id of the pointer. Each pointer on the screen will have a unique pointer id.
///
/// if (event.pointer == firstPointerId) {
/// // Do something
/// }
final int pointer;
/// Creates a new SpriteBoxEvent, typically this is done internally inside the SpriteBox.
///
/// var event = new SpriteBoxEvent(new Point(50.0, 50.0), 'pointerdown', 0);
SpriteBoxEvent(this.boxPosition, this.type, this.pointer); SpriteBoxEvent(this.boxPosition, this.type, this.pointer);
} }
\ No newline at end of file
part of sprites; part of sprites;
/// A widget that uses a [SpriteBox] to render a sprite node tree to the screen.
class SpriteWidget extends OneChildRenderObjectWrapper { class SpriteWidget extends OneChildRenderObjectWrapper {
/// The rootNode of the sprite node tree.
///
/// var node = mySpriteWidget.rootNode;
final NodeWithSize rootNode; final NodeWithSize rootNode;
/// The transform mode used to fit the sprite node tree to the size of the widget.
final SpriteBoxTransformMode transformMode; final SpriteBoxTransformMode transformMode;
/// Creates a new sprite widget with [rootNode] as its content.
///
/// The widget will setup the coordinate space for the sprite node tree using the size of the [rootNode] in
/// combination with the supplied [transformMode]. By default the letterbox transform mode is used. See
/// [SpriteBoxTransformMode] for more details on the different modes.
///
/// The most common way to setup the sprite node graph is to subclass [NodeWithSize] and pass it to the sprite widget.
/// In the custom subclass it's possible to build the node graph, do animations and handle user events.
///
/// var mySpriteTree = new MyCustomNodeWithSize();
/// var mySpriteWidget = new SpriteWidget(mySpriteTree, SpriteBoxTransformMode.fixedHeight);
SpriteWidget(this.rootNode, [this.transformMode = SpriteBoxTransformMode.letterbox]); SpriteWidget(this.rootNode, [this.transformMode = SpriteBoxTransformMode.letterbox]);
SpriteBox get root => super.root; SpriteBox get root => super.root;
...@@ -16,6 +33,6 @@ class SpriteWidget extends OneChildRenderObjectWrapper { ...@@ -16,6 +33,6 @@ class SpriteWidget extends OneChildRenderObjectWrapper {
// SpriteBox doesn't allow mutation of these properties // SpriteBox doesn't allow mutation of these properties
assert(rootNode == root.rootNode); assert(rootNode == root.rootNode);
assert(transformMode == root.transformMode); assert(transformMode == root._transformMode);
} }
} }
\ No newline at end of file
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