Commit 3260d998 authored by Viktor Lidholt's avatar Viktor Lidholt

Adds support for zOrder and references to parent nodes in sprites, also start of new test app.

R=eseidel@chromium.org

Review URL: https://codereview.chromium.org/1177563004.
parent 0e5bb2d2
...@@ -7,4 +7,5 @@ import 'sprites.dart'; ...@@ -7,4 +7,5 @@ import 'sprites.dart';
import 'package:box2d/box2d.dart'; import 'package:box2d/box2d.dart';
part 'game_world.dart'; part 'game_world.dart';
part 'game_box.dart'; part 'game_box.dart';
\ No newline at end of file part 'game_tests.dart';
part of game;
Math.Random _rand;
class GameTests extends TransformNode{
Image _imgAsteroid;
Image _imgBg;
Image _imgShip;
GameTests(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"];
for (int i = 0; i < 100; i++) {
addSprite(i/100.0);
}
}
void addSprite([double scale = null]) {
TestAsteroidSprite sprt = new TestAsteroidSprite.withImage(_imgAsteroid);
sprt.width = 64.0;
sprt.height = 64.0;
if (scale == null) {
scale = _rand.nextDouble();
}
sprt.zPosition = scale;
sprt.scale = scale;
sprt.position = new Vector2(_rand.nextDouble()*1024.0, _rand.nextDouble()*1024.0);
this.addChild(sprt);
}
void update(double dt) {
for (TransformNode child in children) {
child.update(dt);
}
}
}
class TestAsteroidSprite extends SpriteNode {
Vector2 _movementVector;
double _rotationalSpeed;
TestAsteroidSprite.withImage(Image img) : super.withImage(img) {
_movementVector = new Vector2(_rand.nextDouble() * 4.0 - 2.0, _rand.nextDouble() * 4.0 - 2.0);
_rotationalSpeed = _rand.nextDouble() * 2.0 - 1.0;
}
void update(double dt) {
position = position + _movementVector * scale;
// 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];
rotation += _rotationalSpeed;
}
}
...@@ -30,10 +30,10 @@ class GameWorld extends TransformNode { ...@@ -30,10 +30,10 @@ class GameWorld extends TransformNode {
addBackground(); addBackground();
// Add some asteroids to the game world // Add some asteroids to the game world
for (int i = 0; i < 5; i++) { for (int i = 0; i < 50; i++) {
addAsteroid(10.0); addAsteroid(10.0);
} }
for (int i = 0; i < 5; i++) { for (int i = 0; i < 50; i++) {
addAsteroid(20.0); addAsteroid(20.0);
} }
...@@ -46,7 +46,7 @@ class GameWorld extends TransformNode { ...@@ -46,7 +46,7 @@ class GameWorld extends TransformNode {
sprtBg.width = width; sprtBg.width = width;
sprtBg.height = height; sprtBg.height = height;
sprtBg.pivot = new Vector2(0.0, 0.0); sprtBg.pivot = new Vector2(0.0, 0.0);
this.children.add(sprtBg); this.addChild(sprtBg);
} }
void addAsteroid([double radius=20.0]) { void addAsteroid([double radius=20.0]) {
...@@ -87,7 +87,7 @@ class GameWorld extends TransformNode { ...@@ -87,7 +87,7 @@ class GameWorld extends TransformNode {
// sprt.colorOverlay = new Color(0x33ff0000); // sprt.colorOverlay = new Color(0x33ff0000);
// sprt.transferMode = TransferMode.plusMode; // sprt.transferMode = TransferMode.plusMode;
body.userData = sprt; body.userData = sprt;
this.children.add(sprt); this.addChild(sprt);
} }
void addShip() { void addShip() {
...@@ -127,7 +127,7 @@ class GameWorld extends TransformNode { ...@@ -127,7 +127,7 @@ class GameWorld extends TransformNode {
sprt.height = radius*2; sprt.height = radius*2;
sprt.position = new Vector2(width/2.0, height/2.0); sprt.position = new Vector2(width/2.0, height/2.0);
body.userData = sprt; body.userData = sprt;
this.children.add(sprt); this.addChild(sprt);
} }
void update(double dt) { void update(double dt) {
......
...@@ -23,9 +23,15 @@ class SpriteBox extends RenderBox { ...@@ -23,9 +23,15 @@ class SpriteBox extends RenderBox {
double _systemHeight; double _systemHeight;
SpriteBox(TransformNode rootNode, [SpriteBoxTransformMode mode = SpriteBoxTransformMode.nativePoints, double width=1024.0, double height=1024.0]) { SpriteBox(TransformNode rootNode, [SpriteBoxTransformMode mode = SpriteBoxTransformMode.nativePoints, double width=1024.0, double height=1024.0]) {
assert(rootNode != null);
assert(rootNode._spriteBox == null);
// Setup root node // Setup root node
_rootNode = rootNode; _rootNode = rootNode;
// Assign SpriteBox reference to all the nodes
_addSpriteBoxReference(_rootNode);
// Setup transform mode // Setup transform mode
transformMode = mode; transformMode = mode;
_systemWidth = width; _systemWidth = width;
...@@ -34,6 +40,13 @@ class SpriteBox extends RenderBox { ...@@ -34,6 +40,13 @@ class SpriteBox extends RenderBox {
_scheduleTick(); _scheduleTick();
} }
void _addSpriteBoxReference(TransformNode node) {
node._spriteBox = this;
for (TransformNode child in node._children) {
_addSpriteBoxReference(child);
}
}
double get systemWidth => _systemWidth; double get systemWidth => _systemWidth;
double get systemHeight => _systemHeight; double get systemHeight => _systemHeight;
......
...@@ -5,6 +5,12 @@ double degrees2radians(double degrees) => degrees * Math.PI/180.8; ...@@ -5,6 +5,12 @@ double degrees2radians(double degrees) => degrees * Math.PI/180.8;
double radians2degrees(double radians) => radians * 180.0/Math.PI; double radians2degrees(double radians) => radians * 180.0/Math.PI;
class TransformNode { class TransformNode {
// Member variables
SpriteBox _spriteBox;
TransformNode _parent;
Vector2 _position; Vector2 _position;
double _rotation; double _rotation;
...@@ -14,11 +20,22 @@ class TransformNode { ...@@ -14,11 +20,22 @@ class TransformNode {
double _width; double _width;
double _height; double _height;
double _scaleX;
double _scaleY;
Vector2 _pivot; Vector2 _pivot;
List<TransformNode>children; bool visible;
double _zPosition;
int _addedOrder;
int _childrenLastAddedOrder;
bool _childrenNeedSorting;
List<TransformNode>_children;
// Constructors
TransformNode() { TransformNode() {
_width = 0.0; _width = 0.0;
...@@ -26,11 +43,21 @@ class TransformNode { ...@@ -26,11 +43,21 @@ class TransformNode {
_rotation = 0.0; _rotation = 0.0;
_pivot = new Vector2(0.0, 0.0); _pivot = new Vector2(0.0, 0.0);
_position = new Vector2(0.0, 0.0); _position = new Vector2(0.0, 0.0);
_scaleX = _scaleY = 1.0;
_isMatrixDirty = false; _isMatrixDirty = false;
_transform = new Matrix3.identity(); _transform = new Matrix3.identity();
_pivotTransform = new Matrix3.identity(); _pivotTransform = new Matrix3.identity();
children = []; _children = [];
_childrenNeedSorting = false;
_childrenLastAddedOrder = 0;
visible = true;
} }
// Property setters and getters
SpriteBox get spriteBox => _spriteBox;
TransformNode get parent => _parent;
double get rotation => _rotation; double get rotation => _rotation;
...@@ -38,8 +65,7 @@ class TransformNode { ...@@ -38,8 +65,7 @@ class TransformNode {
_rotation = rotation; _rotation = rotation;
_isMatrixDirty = true; _isMatrixDirty = true;
} }
Vector2 get position => _position; Vector2 get position => _position;
void set position(Vector2 position) { void set position(Vector2 position) {
...@@ -54,7 +80,6 @@ class TransformNode { ...@@ -54,7 +80,6 @@ class TransformNode {
_isMatrixDirty = true; _isMatrixDirty = true;
} }
double get height => _height; double get height => _height;
void set height(double height) { void set height(double height) {
...@@ -68,7 +93,63 @@ class TransformNode { ...@@ -68,7 +93,63 @@ class TransformNode {
_pivot = pivot; _pivot = pivot;
_isMatrixDirty = true; _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 { Matrix3 get transformMatrix {
if (!_isMatrixDirty) { if (!_isMatrixDirty) {
...@@ -111,8 +192,12 @@ class TransformNode { ...@@ -111,8 +192,12 @@ class TransformNode {
return _transform; return _transform;
} }
// Rendering
void visit(PictureRecorder canvas) { void visit(PictureRecorder canvas) {
if (!visible) return;
prePaint(canvas); prePaint(canvas);
paint(canvas); paint(canvas);
visitChildren(canvas); visitChildren(canvas);
...@@ -124,6 +209,7 @@ class TransformNode { ...@@ -124,6 +209,7 @@ class TransformNode {
canvas.translate(_position[0], _position[1]); canvas.translate(_position[0], _position[1]);
canvas.rotate(degrees2radians(_rotation)); canvas.rotate(degrees2radians(_rotation));
canvas.scale(_scaleX, _scaleY);
canvas.translate(-_width*_pivot[0], -_height*_pivot[1]); canvas.translate(-_width*_pivot[0], -_height*_pivot[1]);
// TODO: Use transformation matrix instead of individual calls // TODO: Use transformation matrix instead of individual calls
...@@ -137,14 +223,33 @@ class TransformNode { ...@@ -137,14 +223,33 @@ class TransformNode {
} }
void visitChildren(PictureRecorder canvas) { void visitChildren(PictureRecorder canvas) {
children.forEach((child) => child.visit(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) { void postPaint(PictureRecorder canvas) {
canvas.restore(); canvas.restore();
} }
// Receiving update calls
void update(double dt) { void update(double dt) {
} }
} }
\ No newline at end of file
...@@ -17,5 +17,7 @@ void main() { ...@@ -17,5 +17,7 @@ void main() {
void allLoaded(ImageMap loader) { void allLoaded(ImageMap loader) {
// Create a new app with the sprite box that contains our game world // Create a new app with the sprite box that contains our game world
app = new AppView(new GameBox(new GameWorld(loader))); //app = new AppView(new GameBox(new GameWorld(loader)));
//print("hello");
app = new AppView((new SpriteBox(new GameTests(loader), SpriteBoxTransformMode.letterbox)));
} }
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