Chromium Code Reviews| Index: sky/examples/game/lib/node.dart |
| diff --git a/sky/examples/game/lib/node.dart b/sky/examples/game/lib/node.dart |
| index 5ab4dec1cd3cc211a50b58d8d7a338abe62d1707..ef6162be53d843681e4ed848523c412fbfe793fd 100644 |
| --- a/sky/examples/game/lib/node.dart |
| +++ b/sky/examples/game/lib/node.dart |
| @@ -4,6 +4,15 @@ double convertDegrees2Radians(double degrees) => degrees * Math.PI/180.8; |
| 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 |
| +/// [SpriteWidget]. |
| +/// |
| +/// The [Node] class itself doesn't render any content, but provides the basic functions of any type of node, such as |
| +/// handling transformations and user input. To render the node tree, a root node must be added to a [SpriteBox] or a |
| +/// [SpriteWidget]. Commonly used sub-classes of [Node] are [Sprite], [NodeWithSize], and many more upcoming subclasses. |
| +/// |
| +/// Nodes form a hierarchical tree. Each node can have a number of children, and the transformation (positioning, |
| +/// rotation, and scaling) of a node also affects its children. |
| class Node { |
| // Member variables |
| @@ -11,51 +20,72 @@ class Node { |
| SpriteBox _spriteBox; |
| Node _parent; |
| - Point _position; |
| - double _rotation; |
| + Point _position = Point.origin; |
| + double _rotation = 0.0; |
| - Matrix4 _transformMatrix; |
| + Matrix4 _transformMatrix = new Matrix4.identity(); |
| Matrix4 _transformMatrixNodeToBox; |
| Matrix4 _transformMatrixBoxToNode; |
| - double _scaleX; |
| - double _scaleY; |
| + double _scaleX = 1.0; |
| + double _scaleY = 1.0; |
| - bool visible; |
| + /// The visibility of this node and its children. |
| + bool visible = true; |
| - double _zPosition; |
| + double _zPosition = 0.0; |
| int _addedOrder; |
| - int _childrenLastAddedOrder; |
| - bool _childrenNeedSorting; |
| - |
| + int _childrenLastAddedOrder = 0; |
| + bool _childrenNeedSorting = false; |
| + |
| + /// Decides if the node and its children is currently paused. |
| + /// |
| + /// A paused node will not receive any input events, update calls, or run any animations. |
| + /// |
| + /// myNodeTree.paused = true; |
| bool paused = false; |
| bool _userInteractionEnabled = false; |
| + |
| + /// If set to true the node will receive multiple pointers, otherwise it will only receive events the first pointer. |
| + /// |
| + /// This property is only meaningful if [userInteractionEnabled] is set to true. Default value is false. |
| + /// |
| + /// class MyCustomNode extends Node { |
| + /// handleMultiplePointers = true; |
| + /// } |
| bool handleMultiplePointers = false; |
| int _handlingPointer; |
| - List<Node>_children; |
| + List<Node>_children = []; |
| // Constructors |
| - |
| + |
| + /// Creates a new [Node] without any transformation. |
| + /// |
| + /// var myNode = new Node(); |
| Node() { |
| - _rotation = 0.0; |
| - _position = Point.origin; |
| - _scaleX = _scaleY = 1.0; |
| - _transformMatrix = new Matrix4.identity(); |
| - _children = []; |
| - _childrenNeedSorting = false; |
| - _childrenLastAddedOrder = 0; |
| - _zPosition = 0.0; |
| - visible = true; |
| } |
| // Property setters and getters |
| + /// The [SpriteBox] this node is added to, or null if it's not currently added to a [SpriteBox]. |
| + /// |
| + /// For most applications it's not necessary to access the [SpriteBox] directly. |
| + /// |
| + /// // Get the transformMode of the sprite box |
| + /// var transformMode = myNode.spriteBox.transformMode; |
| SpriteBox get spriteBox => _spriteBox; |
| + /// The parent of this node, or null if it doesn't have a parent. |
| + /// |
| + /// // Hide the parent |
| + /// myNode.parent.visible = false; |
| Node get parent => _parent; |
| - |
| + |
| + /// The rotation of this node in degrees. |
| + /// |
| + /// myNode.rotation = 45.0; |
| double get rotation => _rotation; |
| void set rotation(double rotation) { |
| @@ -64,6 +94,9 @@ class Node { |
| _invalidateTransformMatrix(); |
| } |
| + /// The position of this node relative to its parent. |
| + /// |
| + /// myNode.position = new Point(42.0, 42.0); |
| Point get position => _position; |
| void set position(Point position) { |
| @@ -72,6 +105,14 @@ class Node { |
| _invalidateTransformMatrix(); |
| } |
| + /// The draw order of this node compared to its parent and its siblings. |
| + /// |
| + /// By default nodes are drawn in the order that they have been added to a parent. To override this behavior the |
| + /// [zPosition] property can be used. A higher value of this property will force the node to be drawn in front of |
| + /// siblings that have a lower value. If a negative value is used the node will be drawn behind its parent. |
| + /// |
| + /// nodeInFront.zPosition = 1.0; |
| + /// nodeBehind.zPosition = -1.0; |
| double get zPosition => _zPosition; |
| void set zPosition(double zPosition) { |
| @@ -82,6 +123,11 @@ class Node { |
| } |
| } |
| + /// The scale of this node relative its parent. |
| + /// |
| + /// The [scale] property is only valid if [scaleX] and [scaleY] are equal values. |
| + /// |
| + /// myNode.scale = 5.0; |
| double get scale { |
| assert(_scaleX == _scaleY); |
| return _scaleX; |
| @@ -93,6 +139,9 @@ class Node { |
| _invalidateTransformMatrix(); |
| } |
| + /// The horizontal scale of this node relative its parent. |
| + /// |
| + /// myNode.scaleX = 5.0; |
| double get scaleX => _scaleX; |
| void set scaleX(double scaleX) { |
| @@ -101,6 +150,9 @@ class Node { |
| _invalidateTransformMatrix(); |
| } |
| + /// The vertical scale of this node relative its parent. |
| + /// |
| + /// myNode.scaleY = 5.0; |
| double get scaleY => _scaleY; |
| void set scaleY(double scaleY) { |
| @@ -109,6 +161,14 @@ class Node { |
| _invalidateTransformMatrix(); |
| } |
| + /// A list of the children of this node. |
| + /// |
| + /// This list should only be modified by using the [addChild] and [removeChild] methods. |
| + /// |
| + /// // Iterate over a nodes children |
| + /// for (Node child in myNode.children) { |
| + /// // Do something with the child |
| + /// } |
| List<Node> get children { |
| _sortChildren(); |
| return _children; |
| @@ -116,6 +176,11 @@ class Node { |
| // Adding and removing children |
| + /// Adds a child to this node. |
| + /// |
| + /// The same node cannot be added to multiple nodes. |
| + /// |
| + /// addChild(new Sprite(myImage)); |
| void addChild(Node child) { |
| assert(child != null); |
| assert(child._parent == null); |
| @@ -129,6 +194,9 @@ class Node { |
| if (_spriteBox != null) _spriteBox._eventTargets = null; |
| } |
| + /// Removes a child from this node. |
| + /// |
| + /// removeChild(myChildNode); |
| void removeChild(Node child) { |
| assert(child != null); |
| if (_children.remove(child)) { |
| @@ -138,11 +206,17 @@ class Node { |
| } |
| } |
| + /// Removes this node from its parent node. |
| + /// |
| + /// removeFromParent(); |
| void removeFromParent() { |
| assert(_parent != null); |
| _parent.removeChild(this); |
| } |
| + /// Removes all children of this node. |
| + /// |
| + /// removeAllChildren(); |
| void removeAllChildren() { |
| for (Node child in _children) { |
| child._parent = null; |
| @@ -172,7 +246,12 @@ class Node { |
| } |
| // Calculating the transformation matrix |
| - |
| + |
| + /// The transformMatrix describes the transformation from the node's parent. |
| + /// |
| + /// You cannot set the transformMatrix directly, instead use the position, rotation and scale properties. |
| + /// |
| + /// Matrix4 matrix = myNode.transformMatrix; |
| Matrix4 get transformMatrix { |
| if (_transformMatrix != null) { |
| return _transformMatrix; |
| @@ -251,6 +330,12 @@ class Node { |
| return _transformMatrixBoxToNode; |
| } |
| + /// Converts a point from the coordinate system of the [SpriteBox] to the local coordinate system of the node. |
| + /// |
| + /// This method is particularly useful when handling pointer events and need the pointers position in a local |
| + /// coordinate space. |
| + /// |
| + /// Point localPoint = myNode.convertPointToNodeSpace(pointInBoxCoordinates); |
| Point convertPointToNodeSpace(Point boxPoint) { |
| assert(boxPoint != null); |
| assert(_spriteBox != null); |
| @@ -259,6 +344,9 @@ class Node { |
| return new Point(v[0], v[1]); |
| } |
| + /// Converts a point from the local coordinate system of the node to the coordinate system of the [SpriteBox]. |
| + /// |
| + /// Point pointInBoxCoordinates = myNode.convertPointToBoxSpace(localPoint); |
| Point convertPointToBoxSpace(Point nodePoint) { |
| assert(nodePoint != null); |
| assert(_spriteBox != null); |
| @@ -267,6 +355,9 @@ class Node { |
| return new Point(v[0], v[1]); |
| } |
| + /// Converts a [point] from another [node]s coordinate system into the local coordinate system of this node. |
| + /// |
| + /// Point pointInNodeASpace = nodeA.convertPointFromNode(pointInNodeBSpace, nodeB); |
| Point convertPointFromNode(Point point, Node node) { |
| assert(node != null); |
| assert(point != null); |
| @@ -281,8 +372,23 @@ class Node { |
| // Hit test |
| - bool isPointInside(Point nodePoint) { |
| - assert(nodePoint != null); |
| + /// Returns true if the [point] is inside the node, the [point] is in the local coordinate system of the node. |
| + /// |
| + /// myNode.isPointInside(localPoint); |
| + /// |
| + /// [NodeWithSize] provides a basic bounding box check for this method, if you require a more detailed check this |
| + /// method can be overridden. |
| + /// |
| + /// bool isPointInside (Point nodePoint) { |
| + /// double minX = -size.width * pivot.x; |
| + /// double minY = -size.height * pivot.y; |
| + /// double maxX = minX + size.width; |
| + /// double maxY = minY + size.height; |
| + /// return (nodePoint.x >= minX && nodePoint.x < maxX && |
| + /// nodePoint.y >= minY && nodePoint.y < maxY); |
| + /// } |
| + bool isPointInside(Point point) { |
| + assert(point != null); |
| return false; |
| } |
| @@ -304,7 +410,23 @@ class Node { |
| // Get the transformation matrix and apply transform |
| canvas.concat(transformMatrix.storage); |
| } |
| - |
| + |
| + /// Paints this node to the canvas. |
| + /// |
| + /// Subclasses, such as [Sprite], override this method to do the actual painting of the node. To do custom |
| + /// drawing override this method and make calls to the [canvas] object. All drawing is done in the node's local |
| + /// coordinate system, relative to the node's position. If you want to make the drawing relative to the node's |
| + /// bounding box's origin, override [NodeWithSize] and call the applyTransformForPivot method before making calls for |
| + /// drawing. |
| + /// |
| + /// void paint(PictureRecorder canvas) { |
| + /// canvas.save(); |
| + /// applyTransformForPivot(canvas); |
|
Hixie
2015/06/22 17:08:42
note that save/transform/restore is expensive (exp
|
| + /// |
| + /// // Do painting here |
| + /// |
| + /// canvas.restore(); |
| + /// } |
| void paint(PictureRecorder canvas) { |
| } |
| @@ -339,14 +461,35 @@ class Node { |
| // Receiving update calls |
| + /// Called before a frame is drawn. |
| + /// |
| + /// Override this method to do any updates to the node or node tree before it's drawn to screen. |
| + /// |
| + /// // Make the node rotate at a fixed speed |
| + /// void update(double dt) { |
| + /// rotation = rotation * 10.0 * dt; |
| + /// } |
| void update(double dt) { |
| } |
| + /// Called whenever the [SpriteBox] is modified or resized, or if the device is rotated. |
| + /// |
| + /// Override this method to do any updates that may be necessary to correctly display the node or node tree with the |
| + /// new layout of the [SpriteBox]. |
| + /// |
| + /// void spriteBoxPerformedLayout() { |
| + /// // Move some stuff around here |
| + /// } |
| void spriteBoxPerformedLayout() { |
| } |
| // Handling user interaction |
| + /// The node will receive user interactions, such as pointer (touch or mouse) events. |
| + /// |
| + /// class MyCustomNode extends NodeWithSize { |
| + /// userInteractionEnabled = true; |
| + /// } |
| bool get userInteractionEnabled => _userInteractionEnabled; |
| void set userInteractionEnabled(bool userInteractionEnabled) { |
| @@ -354,6 +497,33 @@ class Node { |
| if (_spriteBox != null) _spriteBox._eventTargets = null; |
| } |
| + /// Handles an event, such as a pointer (touch or mouse) event. |
| + /// |
| + /// Override this method to handle events. The node will only receive events if the [userInteractionEnabled] property |
| + /// is set to true and the [isPointInside] method returns true for the position of the pointer down event (default |
| + /// behavior provided by [NodeWithSize]). Unless [handleMultiplePointers] is set to true, the node will only receive |
| + /// events for the first pointer that is down. |
| + /// |
| + /// Return true if the node has consumed the event, if an event is consumed it will not be passed on to nodes behind |
| + /// the current node. |
| + /// |
| + /// // MyTouchySprite gets transparent when we touch it |
| + /// class MyTouchySprite extends Sprite { |
| + /// |
| + /// MyTouchySprite(Image img) : super (img) { |
| + /// userInteractionEnabled = true; |
| + /// } |
| + /// |
| + /// bool handleEvent(SpriteBoxEvent event) { |
| + /// if (event.type == 'pointerdown) { |
| + /// opacity = 0.5; |
| + /// } |
| + /// else if (event.type == 'pointerup') { |
| + /// opacity = 1.0; |
| + /// } |
| + /// return true; |
| + /// } |
| + /// } |
| bool handleEvent(SpriteBoxEvent event) { |
| return false; |
| } |