Adds hit tests and transformations between coordinate systems in sprites Sprite nodes use Point instead of Vector2 Updates sprite test app Refactors accounting for pivot points in sprites Adds abstract NodeWithSize class in Sprites. Refactors SpriteNode to Sprite Refactors TransformNode to Node (may need to find another name as it conflicts with Sky's Node). Sprite system now uses and caches transformation matrices. R=abarth@chromium.org Review URL: https://codereview.chromium.org/1180703002.
diff --git a/sky/examples/game/lib/game.dart b/sky/examples/game/lib/game.dart index 8e0aa03..37122f4 100644 --- a/sky/examples/game/lib/game.dart +++ b/sky/examples/game/lib/game.dart
@@ -5,6 +5,7 @@ import 'package:vector_math/vector_math_64.dart'; import 'sprites.dart'; import 'package:box2d/box2d.dart'; +import 'package:sky/framework/rendering/box.dart'; part 'game_world.dart'; part 'game_box.dart';
diff --git a/sky/examples/game/lib/game_tests.dart b/sky/examples/game/lib/game_tests.dart index c9800df..b74910e 100644 --- a/sky/examples/game/lib/game_tests.dart +++ b/sky/examples/game/lib/game_tests.dart
@@ -2,7 +2,59 @@ Math.Random _rand; -class GameTests extends TransformNode{ +class GameTestsBox extends SpriteBox { + GameTestsBox(Node tests, SpriteBoxTransformMode mode) : super(tests, mode); + + void handleEvent(Event event, BoxHitTestEntry entry) { + + if (event is PointerEvent) { + Point pointerPos = new Point(event.x, event.y); + int pointer = event.pointer; + + switch (event.type) { + case 'pointerdown': + List sprites = findNodesAtPosition(pointerPos); + for (Node node in sprites) { + if (node is Sprite) { + Sprite sprt = node; + sprt.colorOverlay = new Color(0x66ff0000); + } + } + break; + } + } + } +} + +class GameTestsSimple extends Node { + Image _imgAsteroid; + Image _imgBg; + Image _imgShip; + + GameTestsSimple(ImageMap images) { + // Setup random number generator + _rand = new Math.Random(); + + // Fetch images + _imgBg = images["https://raw.githubusercontent.com/slembcke/GalacticGuardian.spritebuilder/GDC/Packages/SpriteBuilder%20Resources.sbpack/resources-auto/BurnTexture.png"]; + _imgAsteroid = images["https://raw.githubusercontent.com/slembcke/GalacticGuardian.spritebuilder/GDC/Packages/SpriteBuilder%20Resources.sbpack/Sprites/resources-auto/asteroid_big_002.png"]; + _imgShip = images["https://raw.githubusercontent.com/slembcke/GalacticGuardian.spritebuilder/GDC/Packages/SpriteBuilder%20Resources.sbpack/Sprites/resources-auto/GG_blueship_Lv3.png"]; + + Sprite sprt0 = new Sprite.withImage(_imgBg); + sprt0.size = new Size(100.0, 100.0); + sprt0.pivot = new Point(0.0, 0.0); + sprt0.position = new Point(100.0, 100.0); + this.addChild(sprt0); + + Sprite sprt1 = new Sprite.withImage(_imgBg); + sprt1.size = new Size(100.0, 100.0); + sprt1.pivot = new Point(0.0, 0.0); + sprt1.position = new Point(100.0, 100.0); + sprt0.addChild(sprt1); + } +} + +class GameTests extends Node{ Image _imgAsteroid; Image _imgBg; @@ -24,8 +76,7 @@ void addSprite([double scale = null]) { TestAsteroidSprite sprt = new TestAsteroidSprite.withImage(_imgAsteroid); - sprt.width = 64.0; - sprt.height = 64.0; + sprt.size = new Size(64.0, 64.0); if (scale == null) { scale = _rand.nextDouble(); @@ -33,19 +84,29 @@ sprt.zPosition = scale; sprt.scale = scale; - sprt.position = new Vector2(_rand.nextDouble()*1024.0, _rand.nextDouble()*1024.0); + sprt.position = new Point(_rand.nextDouble()*1024.0, _rand.nextDouble()*1024.0); this.addChild(sprt); + + Sprite sprtMoon0 = new Sprite.withImage(_imgAsteroid); + sprtMoon0.size = new Size(32.0, 32.0); + sprtMoon0.position = new Point(32.0, 0.0); + sprt.addChild(sprtMoon0); + + Sprite sprtMoon1 = new Sprite.withImage(_imgAsteroid); + sprtMoon1.size = new Size(32.0, 32.0); + sprtMoon1.position = new Point(-32.0, 0.0); + sprt.addChild(sprtMoon1); } void update(double dt) { - for (TransformNode child in children) { + for (Node child in children) { child.update(dt); } } } -class TestAsteroidSprite extends SpriteNode { +class TestAsteroidSprite extends Sprite { Vector2 _movementVector; double _rotationalSpeed; @@ -56,11 +117,14 @@ } void update(double dt) { - position = position + _movementVector * scale; + Vector2 vPos = new Vector2(position.x, position.y); + Vector2 vNewPos = vPos + _movementVector * scale; + + position = new Point(vNewPos[0], vNewPos[1]); // Bounce at edges - if (position[0] < 0 || position[0] > 1024.0) _movementVector[0] = -_movementVector[0]; - if (position[1] < 0 || position[1] > 1024.0) _movementVector[1] = -_movementVector[1]; + if (position.x < 0 || position.x > 1024.0) _movementVector[0] = -_movementVector[0]; + if (position.y < 0 || position.y > 1024.0) _movementVector[1] = -_movementVector[1]; rotation += _rotationalSpeed; }
diff --git a/sky/examples/game/lib/game_world.dart b/sky/examples/game/lib/game_world.dart index ba4d12c..6be46e2 100644 --- a/sky/examples/game/lib/game_world.dart +++ b/sky/examples/game/lib/game_world.dart
@@ -1,6 +1,6 @@ part of game; -class GameWorld extends TransformNode { +class GameWorld extends Node { World world; List<Body> bodies = []; @@ -42,7 +42,7 @@ } void addBackground() { - SpriteNode sprtBg = new SpriteNode.withImage(_imgBg); + Sprite sprtBg = new Sprite.withImage(_imgBg); sprtBg.width = width; sprtBg.height = height; sprtBg.pivot = new Vector2(0.0, 0.0); @@ -81,7 +81,7 @@ bodies.add(body); // Create sprite - SpriteNode sprt = new SpriteNode.withImage(_imgAsteroid); + Sprite sprt = new Sprite.withImage(_imgAsteroid); sprt.width = radius*2; sprt.height = radius*2; // sprt.colorOverlay = new Color(0x33ff0000); @@ -122,7 +122,7 @@ _bodyShip = body; // Create sprite - SpriteNode sprt = new SpriteNode.withImage(_imgShip); + Sprite sprt = new Sprite.withImage(_imgShip); sprt.width = radius*2; sprt.height = radius*2; sprt.position = new Vector2(width/2.0, height/2.0); @@ -155,7 +155,7 @@ } void updateBody(Body body) { - SpriteNode sprt = body.userData; + Sprite sprt = body.userData; double rot = 0.0; //body.getRotation(); // Check bounds and warp objects
diff --git a/sky/examples/game/lib/node.dart b/sky/examples/game/lib/node.dart new file mode 100644 index 0000000..d8cfc28 --- /dev/null +++ b/sky/examples/game/lib/node.dart
@@ -0,0 +1,268 @@ +part of sprites; + +double degrees2radians(double degrees) => degrees * Math.PI/180.8; + +double radians2degrees(double radians) => radians * 180.0/Math.PI; + +class Node { + + // Member variables + + SpriteBox _spriteBox; + Node _parent; + + Point _position; + double _rotation; + + bool _isMatrixDirty; + Matrix4 _transformMatrix; + Matrix4 _transformMatrixFromWorld; + + double _scaleX; + double _scaleY; + + bool visible; + + double _zPosition; + int _addedOrder; + int _childrenLastAddedOrder; + bool _childrenNeedSorting; + + List<Node>_children; + + // Constructors + + Node() { + _rotation = 0.0; + _position = new Point(0.0, 0.0); + _scaleX = _scaleY = 1.0; + _isMatrixDirty = false; + _transformMatrix = new Matrix4.identity(); + _children = []; + _childrenNeedSorting = false; + _childrenLastAddedOrder = 0; + visible = true; + } + + // Property setters and getters + + SpriteBox get spriteBox => _spriteBox; + + Node get parent => _parent; + + double get rotation => _rotation; + + void set rotation(double rotation) { + _rotation = rotation; + _isMatrixDirty = true; + } + + Point get position => _position; + + void set position(Point position) { + _position = position; + _isMatrixDirty = true; + } + + double get zPosition => _zPosition; + + void set zPosition(double zPosition) { + _zPosition = zPosition; + if (_parent != null) { + _parent._childrenNeedSorting = true; + } + } + + double get scale { + assert(_scaleX == _scaleY); + return _scaleX; + } + + void set scale(double scale) { + _scaleX = _scaleY = scale; + _isMatrixDirty = true; + } + + List<Node> get children => _children; + + // Adding and removing children + + void addChild(Node child) { + assert(child._parent == null); + + _childrenNeedSorting = true; + _children.add(child); + child._parent = this; + child._spriteBox = this._spriteBox; + _childrenLastAddedOrder += 1; + child._addedOrder = _childrenLastAddedOrder; + } + + void removeChild(Node child) { + if (_children.remove(child)) { + child._parent = null; + child._spriteBox = null; + } + } + + void removeFromParent() { + assert(_parent != null); + _parent.removeFromParent(); + } + + void removeAllChildren() { + for (Node child in _children) { + child._parent = null; + child._spriteBox = null; + } + _children = []; + _childrenNeedSorting = false; + } + + // Calculating the transformation matrix + + Matrix4 get transformMatrix { + if (!_isMatrixDirty) { + return _transformMatrix; + } + + double cx, sx, cy, sy; + + if (_rotation == 0.0) { + cx = 1.0; + sx = 0.0; + cy = 1.0; + sy = 0.0; + } + else { + double radiansX = degrees2radians(_rotation); + double radiansY = degrees2radians(_rotation); + + cx = Math.cos(radiansX); + sx = Math.sin(radiansX); + cy = Math.cos(radiansY); + sy = Math.sin(radiansY); + } + + // Create transformation matrix for scale, position and rotation + _transformMatrix.setValues(cy * _scaleX, sy * _scaleX, 0.0, 0.0, + -sx * _scaleY, cx * _scaleY, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + _position.x, _position.y, 0.0, 1.0 + ); + + return _transformMatrix; + } + + // Transforms to other nodes + + Matrix4 _nodeToBoxMatrix() { + Matrix4 t = transformMatrix; + + Node p = this.parent; + while (p != null) { + t = new Matrix4.copy(p.transformMatrix).multiply(t); + p = p.parent; + } + return t; + } + + Matrix4 _boxToNodeMatrix() { + Matrix4 t = _nodeToBoxMatrix(); + t.invert(); + return t; + } + + Point convertPointToNodeSpace(Point boxPoint) { + assert(boxPoint != null); + assert(_spriteBox != null); + + Vector4 v =_boxToNodeMatrix().transform(new Vector4(boxPoint.x, boxPoint.y, 0.0, 1.0)); + return new Point(v[0], v[1]); + } + + Point convertPointToBoxSpace(Point nodePoint) { + assert(nodePoint != null); + assert(_spriteBox != null); + + Vector4 v =_nodeToBoxMatrix().transform(new Vector4(nodePoint.x, nodePoint.y, 0.0, 1.0)); + return new Point(v[0], v[1]); + } + + Point convertPointFromNode(Point point, Node node) { + assert(node != null); + assert(point != null); + assert(_spriteBox != null); + assert(_spriteBox == node._spriteBox); + + Point boxPoint = node.convertPointToBoxSpace(point); + Point localPoint = convertPointToNodeSpace(boxPoint); + + return localPoint; + } + + // Hit test + + bool hitTest(Point nodePoint) { + assert(nodePoint != null); + + return false; + } + + // Rendering + + void visit(PictureRecorder canvas) { + if (!visible) return; + + prePaint(canvas); + paint(canvas); + visitChildren(canvas); + postPaint(canvas); + } + + void prePaint(PictureRecorder canvas) { + canvas.save(); + + // TODO: Can this be done more efficiently? + // Get the transformation matrix and apply transform + List<double> matrix = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]; + this.transformMatrix.copyIntoArray(matrix); + Float32List list32 = new Float32List.fromList(matrix); + canvas.concat(list32); + } + + void paint(PictureRecorder canvas) { + + } + + void visitChildren(PictureRecorder canvas) { + // Sort children primarily by zPosition, secondarily by added order + if (_childrenNeedSorting) { + _children.sort((Node a, Node b) { + if (a._zPosition == b._zPosition) { + return b._addedOrder - a._addedOrder; + } + else if (a._zPosition > b._zPosition) { + return 1; + } + else { + return -1; + } + }); + _childrenNeedSorting = false; + } + + // Visit each child + _children.forEach((child) => child.visit(canvas)); + } + + void postPaint(PictureRecorder canvas) { + canvas.restore(); + } + + // Receiving update calls + + void update(double dt) { + + } +} \ No newline at end of file
diff --git a/sky/examples/game/lib/node_with_size.dart b/sky/examples/game/lib/node_with_size.dart new file mode 100644 index 0000000..1e7c657 --- /dev/null +++ b/sky/examples/game/lib/node_with_size.dart
@@ -0,0 +1,31 @@ +part of sprites; + +abstract class NodeWithSize extends Node { + Size size; + Point pivot; + + NodeWithSize() { + size = new Size(0.0, 0.0); + pivot = new Point(0.0, 0.0); + } + + NodeWithSize.withSize(Size size, [Point pivot]); + + void applyTransformForPivot(PictureRecorder canvas) { + if (pivot.x != 0 || pivot.y != 0) { + double pivotInPointsX = size.width * pivot.x; + double pivotInPointsY = size.height * pivot.y; + canvas.translate(-pivotInPointsX, -pivotInPointsY); + } + } + + bool hitTest (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); + } +}
diff --git a/sky/examples/game/lib/sprite_node.dart b/sky/examples/game/lib/sprite.dart similarity index 67% rename from sky/examples/game/lib/sprite_node.dart rename to sky/examples/game/lib/sprite.dart index 327f5e0..d62bb14 100644 --- a/sky/examples/game/lib/sprite_node.dart +++ b/sky/examples/game/lib/sprite.dart
@@ -2,7 +2,7 @@ // TODO: Actually draw images -class SpriteNode extends TransformNode { +class Sprite extends NodeWithSize { Image _image; bool constrainProportions = false; @@ -10,12 +10,12 @@ Color colorOverlay; TransferMode transferMode; - SpriteNode() { - this.pivot = new Vector2(0.5, 0.5); + Sprite() { } - SpriteNode.withImage(Image image) : super() { - this.pivot = new Vector2(0.5, 0.5); + Sprite.withImage(Image image) { + this.pivot = new Point(0.5, 0.5); + this.size = new Size(image.width.toDouble(), image.height.toDouble()); _image = image; } @@ -27,21 +27,24 @@ } void paint(PictureRecorder canvas) { + canvas.save(); + + // Account for pivot point + applyTransformForPivot(canvas); if (_image != null && _image.width > 0 && _image.height > 0) { - canvas.save(); - double scaleX = _width/_image.width; - double scaleY = _height/_image.height; + double scaleX = size.width/_image.width; + double scaleY = size.height/_image.height; if (constrainProportions) { // Constrain proportions, using the smallest scale and by centering the image if (scaleX < scaleY) { - canvas.translate(0.0, (_height - scaleX * _image.height)/2.0); + canvas.translate(0.0, (size.height - scaleX * _image.height)/2.0); scaleY = scaleX; } else { - canvas.translate((_width - scaleY * _image.width)/2.0, 0.0); + canvas.translate((size.width - scaleY * _image.width)/2.0, 0.0); scaleX = scaleY; } } @@ -59,13 +62,12 @@ } canvas.drawImage(_image, 0.0, 0.0, paint); - canvas.restore(); } else { // Paint a red square for missing texture - canvas.drawRect(new Rect.fromLTRB(0.0, 0.0, this.width, this.height), + canvas.drawRect(new Rect.fromLTRB(0.0, 0.0, size.width, size.height), new Paint()..setARGB(255, 255, 0, 0)); } + canvas.restore(); } - }
diff --git a/sky/examples/game/lib/sprite_box.dart b/sky/examples/game/lib/sprite_box.dart index 6e7b686..7c95ee7 100644 --- a/sky/examples/game/lib/sprite_box.dart +++ b/sky/examples/game/lib/sprite_box.dart
@@ -11,8 +11,10 @@ class SpriteBox extends RenderBox { + // Member variables + // Root node for drawing - TransformNode _rootNode; + Node _rootNode; // Tracking of frame rate and updates double _lastTimeStamp; @@ -22,7 +24,9 @@ double _systemWidth; double _systemHeight; - SpriteBox(TransformNode rootNode, [SpriteBoxTransformMode mode = SpriteBoxTransformMode.nativePoints, double width=1024.0, double height=1024.0]) { + // Setup + + SpriteBox(Node rootNode, [SpriteBoxTransformMode mode = SpriteBoxTransformMode.nativePoints, double width=1024.0, double height=1024.0]) { assert(rootNode != null); assert(rootNode._spriteBox == null); @@ -40,30 +44,31 @@ _scheduleTick(); } - void _addSpriteBoxReference(TransformNode node) { + void _addSpriteBoxReference(Node node) { node._spriteBox = this; - for (TransformNode child in node._children) { + for (Node child in node._children) { _addSpriteBoxReference(child); } } + // Properties + double get systemWidth => _systemWidth; double get systemHeight => _systemHeight; - TransformNode get rootNode => _rootNode; + Node get rootNode => _rootNode; void performLayout() { size = constraints.constrain(Size.infinite); } + // Event handling + void handleEvent(Event event, BoxHitTestEntry entry) { - switch (event.type) { - case 'pointerdown': - print("pointerdown"); - break; - } } + // Rendering + void paint(RenderObjectDisplayList canvas) { // Move to correct coordinate space before drawing double scaleX = 1.0; @@ -104,7 +109,6 @@ scaleX = size.width/_systemWidth; scaleY = scaleX; _systemHeight = size.height/scaleX; - print("systemHeight: $_systemHeight"); break; case SpriteBoxTransformMode.fixedHeight: scaleY = size.height/_systemHeight; @@ -129,6 +133,8 @@ canvas.restore(); } + // Updates + int _animationId = 0; void _scheduleTick() { @@ -151,4 +157,29 @@ _rootNode.update(delta); _scheduleTick(); } + + // Hit tests + + List<Node> findNodesAtPosition(Point position) { + assert(position != null); + + List<Node> nodes = []; + + // Traverse the render tree and find objects at the position + _addNodesAtPosition(_rootNode, position, nodes); + + return nodes; + } + + _addNodesAtPosition(Node node, Point position, List<Node> list) { + // Visit children first + for (Node child in node.children) { + _addNodesAtPosition(child, position, list); + } + // Do the hit test + Point posInNodeSpace = node.convertPointToNodeSpace(position); + if (node.hitTest(posInNodeSpace)) { + list.add(node); + } + } }
diff --git a/sky/examples/game/lib/sprites.dart b/sky/examples/game/lib/sprites.dart index 74bba15..79a6fd3 100644 --- a/sky/examples/game/lib/sprites.dart +++ b/sky/examples/game/lib/sprites.dart
@@ -3,14 +3,14 @@ import 'dart:sky'; import 'dart:math' as Math; import 'package:vector_math/vector_math_64.dart'; -import 'package:sky/framework/app.dart'; +import 'dart:typed_data'; import 'package:sky/framework/rendering/box.dart'; -//import 'package:sky/framework/rendering/node.dart'; import 'package:sky/framework/rendering/object.dart'; import 'package:sky/framework/scheduler.dart' as scheduler; import 'package:sky/framework/net/image_cache.dart' as image_cache; part 'sprite_box.dart'; -part 'transform_node.dart'; -part 'sprite_node.dart'; +part 'node.dart'; +part 'node_with_size.dart'; +part 'sprite.dart'; part 'image_map.dart'; \ No newline at end of file
diff --git a/sky/examples/game/lib/transform_node.dart b/sky/examples/game/lib/transform_node.dart deleted file mode 100644 index 07c08b6..0000000 --- a/sky/examples/game/lib/transform_node.dart +++ /dev/null
@@ -1,255 +0,0 @@ -part of sprites; - -double degrees2radians(double degrees) => degrees * Math.PI/180.8; - -double radians2degrees(double radians) => radians * 180.0/Math.PI; - -class TransformNode { - - // Member variables - - SpriteBox _spriteBox; - TransformNode _parent; - - Vector2 _position; - double _rotation; - - bool _isMatrixDirty; - Matrix3 _transform; - Matrix3 _pivotTransform; - - double _width; - double _height; - - double _scaleX; - double _scaleY; - - Vector2 _pivot; - - bool visible; - - double _zPosition; - int _addedOrder; - int _childrenLastAddedOrder; - bool _childrenNeedSorting; - - List<TransformNode>_children; - - // Constructors - - TransformNode() { - _width = 0.0; - _height = 0.0; - _rotation = 0.0; - _pivot = new Vector2(0.0, 0.0); - _position = new Vector2(0.0, 0.0); - _scaleX = _scaleY = 1.0; - _isMatrixDirty = false; - _transform = new Matrix3.identity(); - _pivotTransform = new Matrix3.identity(); - _children = []; - _childrenNeedSorting = false; - _childrenLastAddedOrder = 0; - visible = true; - } - - // Property setters and getters - - SpriteBox get spriteBox => _spriteBox; - - TransformNode get parent => _parent; - - double get rotation => _rotation; - - void set rotation(double rotation) { - _rotation = rotation; - _isMatrixDirty = true; - } - - Vector2 get position => _position; - - void set position(Vector2 position) { - _position = position; - _isMatrixDirty = true; - } - - double get width => _width; - - void set width(double width) { - _width = width; - _isMatrixDirty = true; - } - - double get height => _height; - - void set height(double height) { - _height = height; - _isMatrixDirty = true; - } - - Vector2 get pivot => _pivot; - - void set pivot(Vector2 pivot) { - _pivot = pivot; - _isMatrixDirty = true; - } - - double get zPosition => _zPosition; - - void set zPosition(double zPosition) { - _zPosition = zPosition; - if (_parent != null) { - _parent._childrenNeedSorting = true; - } - } - - double get scale { - assert(_scaleX == _scaleY); - return _scaleX; - } - - void set scale(double scale) { - _scaleX = _scaleY = scale; - _isMatrixDirty = true; - } - - List<TransformNode> get children => _children; - - // Adding and removing children - - void addChild(TransformNode child) { - assert(child._parent == null); - - _childrenNeedSorting = true; - _children.add(child); - child._parent = this; - child._spriteBox = this._spriteBox; - _childrenLastAddedOrder += 1; - child._addedOrder = _childrenLastAddedOrder; - } - - void removeChild(TransformNode child) { - if (_children.remove(child)) { - child._parent = null; - child._spriteBox = null; - } - } - - void removeFromParent() { - assert(_parent != null); - _parent.removeFromParent(); - } - - void removeAllChildren() { - for (TransformNode child in _children) { - child._parent = null; - child._spriteBox = null; - } - _children = []; - _childrenNeedSorting = false; - } - - // Calculating the transformation matrix - - Matrix3 get transformMatrix { - if (!_isMatrixDirty) { - return _transform; - } - - Vector2 pivotInPoints = new Vector2(_width * _pivot[0], _height * _pivot[1]); - - double cx, sx, cy, sy; - - if (_rotation == 0) { - cx = 1.0; - sx = 0.0; - cy = 1.0; - sy = 0.0; - } - else { - double radiansX = degrees2radians(_rotation); - double radiansY = degrees2radians(_rotation); - - cx = Math.cos(radiansX); - sx = Math.sin(radiansX); - cy = Math.cos(radiansY); - sy = Math.sin(radiansY); - } - - // TODO: Add support for scale - double scaleX = 1.0; - double scaleY = 1.0; - - // Create transformation matrix for scale, position and rotation - _transform.setValues(cy * scaleX, sy * scaleX, 0.0, - -sx * scaleY, cx * scaleY, 0.0, - _position[0], _position[1], 1.0); - - if (_pivot.x != 0 || _pivot.y != 0) { - _pivotTransform.setValues(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, pivotInPoints[0], pivotInPoints[1], 1.0); - _transform.multiply(_pivotTransform); - } - - return _transform; - } - - // Rendering - - void visit(PictureRecorder canvas) { - if (!visible) return; - - prePaint(canvas); - paint(canvas); - visitChildren(canvas); - postPaint(canvas); - } - - void prePaint(PictureRecorder canvas) { - canvas.save(); - - canvas.translate(_position[0], _position[1]); - canvas.rotate(degrees2radians(_rotation)); - canvas.scale(_scaleX, _scaleY); - canvas.translate(-_width*_pivot[0], -_height*_pivot[1]); - - // TODO: Use transformation matrix instead of individual calls -// List<double> matrix = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]; -// this.transformMatrix.copyIntoArray(matrix); -// canvas.concat(matrix); - } - - void paint(PictureRecorder canvas) { - - } - - void visitChildren(PictureRecorder canvas) { - // Sort children primarily by zPosition, secondarily by added order - if (_childrenNeedSorting) { - _children.sort((TransformNode a, TransformNode b) { - if (a._zPosition == b._zPosition) { - return b._addedOrder - a._addedOrder; - } - else if (a._zPosition > b._zPosition) { - return 1; - } - else { - return -1; - } - }); - _childrenNeedSorting = false; - } - - // Visit each child - _children.forEach((child) => child.visit(canvas)); - } - - void postPaint(PictureRecorder canvas) { - canvas.restore(); - } - - // Receiving update calls - - void update(double dt) { - - } -} \ No newline at end of file
diff --git a/sky/examples/game/main.dart b/sky/examples/game/main.dart index 35cb8bd..273204c 100644 --- a/sky/examples/game/main.dart +++ b/sky/examples/game/main.dart
@@ -19,5 +19,5 @@ // Create a new app with the sprite box that contains our game world //app = new AppView(new GameBox(new GameWorld(loader))); //print("hello"); - app = new AppView((new SpriteBox(new GameTests(loader), SpriteBoxTransformMode.letterbox))); + app = new AppView((new GameTestsBox(new GameTests(loader), SpriteBoxTransformMode.nativePoints))); }