提交 5dc39bac 编写于 作者: V Viktor Lidholt

Updates game for new AppView API

Deletes old test game

Demo game is now playable

Updates demo game with steering and changes in sprites

Fixes smaller bugs in sprites

Refactor class names in game demo

Strips Box2D from game

Fixes ordering in game node

Adds frameRate property to SpriteBox and improves update methods.

Fixes node to box transformations for hit tests

Fixes minor code issues

R=abarth@chromium.org

Review URL: https://codereview.chromium.org/1179333002.
上级 5e5b220f
......@@ -7,6 +7,5 @@ import 'sprites.dart';
import 'package:box2d/box2d.dart';
import 'package:sky/rendering/box.dart';
part 'game_world.dart';
part 'game_box.dart';
part 'game_tests.dart';
part 'game_demo_world.dart';
part 'game_demo_box.dart';
part of game;
const double _steeringThreshold = 20.0;
const double _steeringMax = 50.0;
const double _steeringThreshold = 0.0;
const double _steeringMax = 150.0;
class GameBox extends SpriteBox {
class GameDemoBox extends SpriteBox {
GameBox(GameWorld game) : super(game, SpriteBoxTransformMode.letterbox);
GameDemoBox(GameDemoWorld game) : super(game, SpriteBoxTransformMode.letterbox);
GameWorld get _gameWorld => this.rootNode;
GameDemoWorld get _gameWorld => this.rootNode;
// Handle pointers
int _firstPointer = -1;
int _secondPointer = -1;
Vector2 _firstPointerDownPos;
Point _firstPointerDownPos;
void handleEvent(Event event, BoxHitTestEntry entry) {
if (event is PointerEvent) {
Vector2 pointerPos = new Vector2(event.x, event.y);
Point pointerPos = new Point(event.x, event.y);
int pointer = event.pointer;
switch (event.type) {
......@@ -29,7 +29,7 @@ class GameBox extends SpriteBox {
else if (_secondPointer == -1) {
// Assign second pointer
_secondPointer = pointer;
_gameWorld.controlThrust(1.0);
_gameWorld.controlFire();
}
else {
// There is a pointer used for steering, let's fire instead
......@@ -39,14 +39,23 @@ class GameBox extends SpriteBox {
case 'pointermove':
if (pointer == _firstPointer) {
// Handle turning control
double deltaX = pointerPos[0] - _firstPointerDownPos[0];
double joystickX = 0.0;
double deltaX = pointerPos.x - _firstPointerDownPos.x;
if (deltaX > _steeringThreshold || deltaX < -_steeringThreshold) {
double turnForce = (deltaX - _steeringThreshold)/(_steeringMax - _steeringThreshold);
if (turnForce > 1.0) turnForce = 1.0;
if (turnForce < -1.0) turnForce = -1.0;
_gameWorld.controlSteering(turnForce);
print("steering: $turnForce");
joystickX = (deltaX - _steeringThreshold)/(_steeringMax - _steeringThreshold);
if (joystickX > 1.0) joystickX = 1.0;
if (joystickX < -1.0) joystickX = -1.0;
}
double joystickY = 0.0;
double deltaY = pointerPos.y - _firstPointerDownPos.y;
if (deltaY > _steeringThreshold || deltaY < -_steeringThreshold) {
joystickY = (deltaY - _steeringThreshold)/(_steeringMax - _steeringThreshold);
if (joystickY > 1.0) joystickY = 1.0;
if (joystickY < -1.0) joystickY = -1.0;
}
_gameWorld.controlSteering(joystickX, joystickY);
}
break;
case 'pointerup':
......@@ -55,11 +64,11 @@ class GameBox extends SpriteBox {
// Un-assign the first pointer
_firstPointer = -1;
_firstPointerDownPos = null;
_gameWorld.controlSteering(null);
_gameWorld.controlSteering(0.0, 0.0);
}
else if (pointer == _secondPointer) {
_secondPointer = -1;
_gameWorld.controlThrust(null);
_gameWorld.controlFire();
}
break;
default:
......
part of game;
// Random generator
Math.Random _rand = new Math.Random();
const double _gameSizeWidth = 1024.0;
const double _gameSizeHeight = 1024.0;
const double _shipRadius = 30.0;
const double _lrgAsteroidRadius = 40.0;
const double _medAsteroidRadius = 20.0;
const double _smlAsteroidRadius = 10.0;
const double _maxAsteroidSpeed = 1.0;
const int _lifeTimeLaser = 50;
class GameDemoWorld extends NodeWithSize {
// Images
Image _imgBg;
Image _imgAsteroid;
Image _imgShip;
Image _imgLaser;
// Inputs
double _joystickX = 0.0;
double _joystickY = 0.0;
bool _fire;
Ship _ship;
List<Asteroid> _asteroids = [];
List<Laser> _lasers = [];
GameDemoWorld(ImageMap images) : super.withSize(new Size(_gameSizeWidth, _gameSizeHeight)) {
// 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"];
_imgLaser = images["https://raw.githubusercontent.com/slembcke/GalacticGuardian.spritebuilder/GDC/Packages/SpriteBuilder%20Resources.sbpack/Sprites/resources-auto/laserBlue.png"];
// Add some asteroids to the game world
for (int i = 0; i < 5; i++) {
addAsteroid(AsteroidSize.large);
}
for (int i = 0; i < 5; i++) {
addAsteroid(AsteroidSize.medium);
}
// Add ship
addShip();
}
// Methods for adding game objects
void addBackground() {
Sprite sprtBg = new Sprite.withImage(_imgBg);
sprtBg.size = new Size(_gameSizeWidth, _gameSizeHeight);
sprtBg.pivot = Point.origin;
this.addChild(sprtBg);
}
void addAsteroid(AsteroidSize size, [Point pos]) {
Asteroid asteroid = new Asteroid.withImage(_imgAsteroid, size);
asteroid.zPosition = 1.0;
if (pos != null) asteroid.position = pos;
this.addChild(asteroid);
_asteroids.add(asteroid);
}
void addShip() {
Ship ship = new Ship.withImage(_imgShip);
ship.zPosition = 10.0;
this.addChild(ship);
_ship = ship;
}
void addLaser() {
Laser laser = new Laser.withImage(_imgLaser, _ship);
laser.zPosition = 8.0;
_lasers.add(laser);
this.addChild(laser);
}
void update(double dt) {
// Move asteroids
for (Asteroid asteroid in _asteroids) {
asteroid.position = pointAdd(asteroid.position, asteroid._movementVector);
}
// Move lasers and remove expired lasers
for (int i = _lasers.length - 1; i >= 0; i--) {
Laser laser = _lasers[i];
laser.move();
if (laser._frameCount > _lifeTimeLaser) {
laser.removeFromParent();
_lasers.removeAt(i);
}
}
// Apply thrust to ship
if (_joystickX != 0.0 || _joystickY != 0.0) {
_ship.thrust(_joystickX, _joystickY);
}
// Move ship
_ship.move();
// Check collisions between asteroids and lasers
for (int i = _lasers.length -1; i >= 0; i--) {
// Iterate over all the lasers
Laser laser = _lasers[i];
for (int j = _asteroids.length - 1; j >= 0; j--) {
// Iterate over all the asteroids
Asteroid asteroid = _asteroids[j];
// Check for collision
if (pointQuickDist(laser.position, asteroid.position) < laser.radius + asteroid.radius) {
// Remove laser
laser.removeFromParent();
_lasers.removeAt(i);
// Add asteroids
if (asteroid._asteroidSize == AsteroidSize.large) {
for (int a = 0; a < 3; a++) addAsteroid(AsteroidSize.medium, asteroid.position);
}
else if (asteroid._asteroidSize == AsteroidSize.medium) {
for (int a = 0; a < 5; a++) addAsteroid(AsteroidSize.small, asteroid.position);
}
// Remove asteroid
asteroid.removeFromParent();
_asteroids.removeAt(j);
break;
}
}
}
// Move objects to center camera and warp objects around the edges
centerCamera();
warpObjects();
}
void centerCamera() {
const cameraDampening = 0.1;
Point delta = new Point(_gameSizeWidth/2 - _ship.position.x, _gameSizeHeight/2 - _ship.position.y);
delta = pointMult(delta, cameraDampening);
for (Node child in children) {
child.position = pointAdd(child.position, delta);
}
}
void warpObjects() {
for (Node child in children) {
if (child.position.x < 0) child.position = pointAdd(child.position, new Point(_gameSizeWidth, 0.0));
if (child.position.x >= _gameSizeWidth) child.position = pointAdd(child.position, new Point(-_gameSizeWidth, 0.0));
if (child.position.y < 0) child.position = pointAdd(child.position, new Point(0.0, _gameSizeHeight));
if (child.position.y >= _gameSizeHeight) child.position = pointAdd(child.position, new Point(0.0, -_gameSizeHeight));
}
}
// Handling controls
void controlSteering(double x, double y) {
_joystickX = x;
_joystickY = y;
}
void controlFire() {
addLaser();
}
}
// Game objects
enum AsteroidSize {
small,
medium,
large,
}
class Asteroid extends Sprite {
Point _movementVector;
AsteroidSize _asteroidSize;
double _radius;
double get radius {
if (_radius != null) return _radius;
if (_asteroidSize == AsteroidSize.small) _radius = _smlAsteroidRadius;
else if (_asteroidSize == AsteroidSize.medium) _radius = _medAsteroidRadius;
else if (_asteroidSize == AsteroidSize.large) _radius = _lrgAsteroidRadius;
return _radius;
}
Asteroid.withImage(Image img, AsteroidSize this._asteroidSize) : super.withImage(img) {
size = new Size(radius * 2.0, radius * 2.0);
position = new Point(_gameSizeWidth * _rand.nextDouble(), _gameSizeHeight * _rand.nextDouble());
rotation = 360.0 * _rand.nextDouble();
_movementVector = new Point(_rand.nextDouble() * _maxAsteroidSpeed * 2 - _maxAsteroidSpeed,
_rand.nextDouble() * _maxAsteroidSpeed * 2 - _maxAsteroidSpeed);
}
}
class Ship extends Sprite {
Vector2 _movementVector;
double _rotationTarget;
Ship.withImage(Image img) : super.withImage(img) {
_movementVector = new Vector2.zero();
rotation = _rotationTarget = 270.0;
// Create sprite
size = new Size(_shipRadius * 2.0, _shipRadius * 2.0);
position = new Point(_gameSizeWidth/2.0, _gameSizeHeight/2.0);
}
void thrust(double x, double y) {
_rotationTarget = convertRadians2Degrees(Math.atan2(y, x));
Vector2 directionVector = new Vector2(x, y).normalize();
_movementVector.addScaled(directionVector, 1.0);
}
void move() {
position = new Point(position.x + _movementVector[0], position.y + _movementVector[1]);
_movementVector.scale(0.9);
rotation = dampenRotation(rotation, _rotationTarget, 0.1);
}
}
class Laser extends Sprite {
int _frameCount = 0;
Point _movementVector;
double radius = 10.0;
Laser.withImage(Image img, Ship ship) : super.withImage(img) {
size = new Size(20.0, 20.0);
position = ship.position;
rotation = ship.rotation + 90.0;
transferMode = TransferMode.plusMode;
double rotRadians = convertDegrees2Radians(rotation);
_movementVector = pointMult(new Point(Math.sin(rotRadians), -Math.cos(rotRadians)), 10.0);
_movementVector = new Point(_movementVector.x + ship._movementVector[0], _movementVector.y + ship._movementVector[1]);
}
bool move() {
position = pointAdd(position, _movementVector);
_frameCount++;
}
}
// Convenience methods
Point pointAdd(Point a, Point b) {
return new Point(a.x+ b.x, a.y + b.y);
}
Point pointMult(Point a, double multiplier) {
return new Point(a.x * multiplier, a.y * multiplier);
}
double dampenRotation(double src, double dst, double dampening) {
double delta = dst - src;
while (delta > 180.0) delta -= 360;
while (delta < -180) delta += 360;
delta *= dampening;
return src + delta;
}
double pointQuickDist(Point a, Point b) {
double dx = a.x - b.x;
double dy = a.y - b.y;
if (dx < 0.0) dx = -dx;
if (dy < 0.0) dy = -dy;
if (dx > dy) {
return dx + dy/2.0;
}
else {
return dy + dx/2.0;
}
}
\ No newline at end of file
part of game;
Math.Random _rand;
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;
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.size = new Size(64.0, 64.0);
if (scale == null) {
scale = _rand.nextDouble();
}
sprt.zPosition = scale;
sprt.scale = scale;
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 (Node child in children) {
child.update(dt);
}
}
}
class TestAsteroidSprite extends Sprite {
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) {
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.x < 0 || position.x > 1024.0) _movementVector[0] = -_movementVector[0];
if (position.y < 0 || position.y > 1024.0) _movementVector[1] = -_movementVector[1];
rotation += _rotationalSpeed;
}
}
part of game;
class GameWorld extends Node {
World world;
List<Body> bodies = [];
Body _bodyShip;
Image _imgBg;
Image _imgAsteroid;
Image _imgShip;
double _steeringInput;
double _thrustInput;
double _lastSteeringSpeed = 0.0;
GameWorld(ImageMap images) {
this.width = 1024.0;
this.height = 1024.0;
// 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"];
// Create the physics world
world = new World.withGravity(new Vector2(0.0, 0.0));
// Add a background
addBackground();
// Add some asteroids to the game world
for (int i = 0; i < 50; i++) {
addAsteroid(10.0);
}
for (int i = 0; i < 50; i++) {
addAsteroid(20.0);
}
// Add ship
addShip();
}
void addBackground() {
Sprite sprtBg = new Sprite.withImage(_imgBg);
sprtBg.width = width;
sprtBg.height = height;
sprtBg.pivot = new Vector2(0.0, 0.0);
this.addChild(sprtBg);
}
void addAsteroid([double radius=20.0]) {
// Create shape
final CircleShape shape = new CircleShape();
shape.radius = radius;
// Define fixture (links body and shape)
final FixtureDef activeFixtureDef = new FixtureDef();
activeFixtureDef.restitution = 1.0;
activeFixtureDef.density = 0.05;
activeFixtureDef.shape = shape;
// Define body
final BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DYNAMIC;
bodyDef.position = new Vector2(0.0, 30.0);
bodyDef.linearDamping = 0.0;
bodyDef.angularDamping = 0.0;
// Create body and fixture from definitions
final Body body = world.createBody(bodyDef);
body.createFixtureFromFixtureDef(activeFixtureDef);
// Set position of object
Math.Random rand = new Math.Random();
body.setTransform(new Vector2(rand.nextDouble() * this.width, rand.nextDouble() * this.height), 0.0);
body.applyLinearImpulse(new Vector2(rand.nextDouble()*10000.0-5000.0, rand.nextDouble()*10000.0-5000.0), new Vector2(0.0, 0.0), true);
// Add to list
bodies.add(body);
// Create sprite
Sprite sprt = new Sprite.withImage(_imgAsteroid);
sprt.width = radius*2;
sprt.height = radius*2;
// sprt.colorOverlay = new Color(0x33ff0000);
// sprt.transferMode = TransferMode.plusMode;
body.userData = sprt;
this.addChild(sprt);
}
void addShip() {
double radius = 30.0;
// Create shape
final CircleShape shape = new CircleShape();
shape.radius = radius;
// Define fixture (links body and shape)
final FixtureDef activeFixtureDef = new FixtureDef();
activeFixtureDef.restitution = 1.0;
activeFixtureDef.density = 0.05;
activeFixtureDef.shape = shape;
// Define body
final BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DYNAMIC;
bodyDef.position = new Vector2(0.0, 30.0);
bodyDef.linearDamping = 0.0;
bodyDef.angularDamping = 0.95;
// Create body and fixture from definitions
final Body body = world.createBody(bodyDef);
body.createFixtureFromFixtureDef(activeFixtureDef);
// Center on screen
body.setTransform(new Vector2(width/2.0, height/2.0), 90.0);
// Add to list
bodies.add(body);
_bodyShip = body;
// Create sprite
Sprite sprt = new Sprite.withImage(_imgShip);
sprt.width = radius*2;
sprt.height = radius*2;
sprt.position = new Vector2(width/2.0, height/2.0);
body.userData = sprt;
this.addChild(sprt);
}
void update(double dt) {
// Apply thrust
if (_thrustInput != null) {
double force = _thrustInput*10000.0;
double rad = degrees2radians(_bodyShip.getAngle());
_bodyShip.applyLinearImpulse(new Vector2(Math.cos(rad)*force, Math.sin(rad)*force), new Vector2(0.0, 0.0), true);
}
// Simulate world
world.stepDt(1.0/60.0, 10, 10); // Pass in dt
// Apply stearing
if (_steeringInput != null) {
_lastSteeringSpeed = _steeringInput * 4.0;
}
else {
_lastSteeringSpeed *= 0.75;
}
_bodyShip.setTransform(_bodyShip.position, _bodyShip.getAngle() + _lastSteeringSpeed);
// Update all sprites
bodies.forEach(updateBody);
}
void updateBody(Body body) {
Sprite sprt = body.userData;
double rot = 0.0; //body.getRotation();
// Check bounds and warp objects
if (body.position[0] < -sprt.width/2) {
body.setTransform(new Vector2(body.position[0] + this.width + sprt.width, body.position[1]), rot);
}
if (body.position[0] > this.width + sprt.width/2) {
body.setTransform(new Vector2(body.position[0] - (this.width + sprt.width), body.position[1]), rot);
}
if (body.position[1] < -sprt.height/2) {
body.setTransform(new Vector2(body.position[0], body.position[1] + this.height + sprt.height), rot);
}
if (body.position[1] > this.height + sprt.height/2) {
body.setTransform(new Vector2(body.position[0], body.position[1] - (this.height + sprt.height)), rot);
}
// Update sprite
sprt.position = body.position;
sprt.rotation = body.getAngle();
}
void controlSteering(double input) {
_steeringInput = input;
}
void controlThrust(double input) {
_thrustInput = input;
}
void controlFire() {
}
}
part of sprites;
double degrees2radians(double degrees) => degrees * Math.PI/180.8;
double convertDegrees2Radians(double degrees) => degrees * Math.PI/180.8;
double radians2degrees(double radians) => radians * 180.0/Math.PI;
double convertRadians2Degrees(double radians) => radians * 180.0/Math.PI;
class Node {
......@@ -28,19 +28,22 @@ class Node {
int _childrenLastAddedOrder;
bool _childrenNeedSorting;
bool paused = false;
List<Node>_children;
// Constructors
Node() {
_rotation = 0.0;
_position = new Point(0.0, 0.0);
_position = Point.origin;
_scaleX = _scaleY = 1.0;
_isMatrixDirty = false;
_transformMatrix = new Matrix4.identity();
_children = [];
_childrenNeedSorting = false;
_childrenLastAddedOrder = 0;
_zPosition = 0.0;
visible = true;
}
......@@ -107,7 +110,7 @@ class Node {
void removeFromParent() {
assert(_parent != null);
_parent.removeFromParent();
_parent.removeChild(this);
}
void removeAllChildren() {
......@@ -135,8 +138,8 @@ class Node {
sy = 0.0;
}
else {
double radiansX = degrees2radians(_rotation);
double radiansY = degrees2radians(_rotation);
double radiansX = convertDegrees2Radians(_rotation);
double radiansY = convertDegrees2Radians(_rotation);
cx = Math.cos(radiansX);
sx = Math.sin(radiansX);
......@@ -157,19 +160,29 @@ class Node {
// Transforms to other nodes
Matrix4 _nodeToBoxMatrix() {
assert(_spriteBox != null);
Matrix4 t = transformMatrix;
// Apply transforms from parents
Node p = this.parent;
while (p != null) {
t = new Matrix4.copy(p.transformMatrix).multiply(t);
p = p.parent;
}
// Apply transform from sprite box
t = new Matrix4.copy(_spriteBox.transformMatrix).multiply(t);
return t;
}
Matrix4 _boxToNodeMatrix() {
assert(_spriteBox != null);
Matrix4 t = _nodeToBoxMatrix();
t.invert();
return t;
}
......@@ -223,12 +236,8 @@ class Node {
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);
canvas.concat(transformMatrix.storage);
}
void paint(PictureRecorder canvas) {
......@@ -240,7 +249,7 @@ class Node {
if (_childrenNeedSorting) {
_children.sort((Node a, Node b) {
if (a._zPosition == b._zPosition) {
return b._addedOrder - a._addedOrder;
return a._addedOrder - b._addedOrder;
}
else if (a._zPosition > b._zPosition) {
return 1;
......@@ -263,6 +272,8 @@ class Node {
// Receiving update calls
void update(double dt) {
}
void spriteBoxPerformedLayout() {
}
}
\ No newline at end of file
......@@ -5,11 +5,11 @@ abstract class NodeWithSize extends Node {
Point pivot;
NodeWithSize() {
size = new Size(0.0, 0.0);
pivot = new Point(0.0, 0.0);
size = Size.zero;
pivot = Point.origin;
}
NodeWithSize.withSize(Size size, [Point pivot]);
NodeWithSize.withSize(Size this.size, [Point this.pivot]);
void applyTransformForPivot(PictureRecorder canvas) {
if (pivot.x != 0 || pivot.y != 0) {
......
......@@ -14,8 +14,8 @@ class Sprite extends NodeWithSize {
}
Sprite.withImage(Image image) {
this.pivot = new Point(0.5, 0.5);
this.size = new Size(image.width.toDouble(), image.height.toDouble());
pivot = new Point(0.5, 0.5);
size = new Size(image.width.toDouble(), image.height.toDouble());
_image = image;
}
......
......@@ -19,11 +19,17 @@ class SpriteBox extends RenderBox {
// Tracking of frame rate and updates
double _lastTimeStamp;
int _numFrames = 0;
double _frameRate = 0.0;
// Transformation mode
SpriteBoxTransformMode transformMode;
double _systemWidth;
double _systemHeight;
// Cached transformation matrix
Matrix4 _transformMatrix;
bool _transformMatrixIsDirty;
// Setup
SpriteBox(Node rootNode, [SpriteBoxTransformMode mode = SpriteBoxTransformMode.nativePoints, double width=1024.0, double height=1024.0]) {
......@@ -41,6 +47,8 @@ class SpriteBox extends RenderBox {
_systemWidth = width;
_systemHeight = height;
_transformMatrixIsDirty = true;
_scheduleTick();
}
......@@ -60,6 +68,8 @@ class SpriteBox extends RenderBox {
void performLayout() {
size = constraints.constrain(Size.infinite);
_transformMatrixIsDirty = true;
_callSpriteBoxPerformedLayout(_rootNode);
}
// Event handling
......@@ -69,8 +79,15 @@ class SpriteBox extends RenderBox {
// Rendering
void paint(RenderObjectDisplayList canvas) {
// Move to correct coordinate space before drawing
Matrix4 get transformMatrix {
// Get cached matrix if available
if (!_transformMatrixIsDirty && _transformMatrix != null) {
return _transformMatrix;
}
_transformMatrix = new Matrix4.identity();
// Calculate matrix
double scaleX = 1.0;
double scaleY = 1.0;
double offsetX = 0.0;
......@@ -122,10 +139,17 @@ class SpriteBox extends RenderBox {
break;
}
_transformMatrix.translate(offsetX, offsetY);
_transformMatrix.scale(scaleX, scaleY);
return _transformMatrix;
}
void paint(RenderObjectDisplayList canvas) {
canvas.save();
canvas.translate(offsetX, offsetY);
canvas.scale(scaleX, scaleY);
// Move to correct coordinate space before drawing
canvas.concat(transformMatrix.storage);
// Draw the sprite tree
_rootNode.visit(canvas);
......@@ -151,13 +175,31 @@ class SpriteBox extends RenderBox {
// Count the number of frames we've been running
_numFrames += 1;
_frameRate = 1.0/delta;
// Print frame rate
if (_numFrames % 60 == 0) print("delta: ${delta} fps: ${1.0/delta}");
if (_numFrames % 60 == 0) print("delta: $delta fps: $_frameRate");
_rootNode.update(delta);
_callUpdate(_rootNode, delta);
_scheduleTick();
}
void _callUpdate(Node node, double dt) {
node.update(dt);
for (Node child in node.children) {
if (!child.paused) {
_callUpdate(child, dt);
}
}
}
void _callSpriteBoxPerformedLayout(Node node) {
node.spriteBoxPerformedLayout();
for (Node child in node.children) {
_callSpriteBoxPerformedLayout(child);
}
}
// Hit tests
List<Node> findNodesAtPosition(Point position) {
......
......@@ -2,7 +2,7 @@ library sprites;
import 'dart:sky';
import 'dart:math' as Math;
import 'package:vector_math/vector_math_64.dart';
import 'package:vector_math/vector_math.dart';
import 'dart:typed_data';
import 'package:sky/rendering/box.dart';
import 'package:sky/rendering/object.dart';
......
import 'dart:sky';
import 'lib/game.dart';
import 'lib/game_demo.dart';
import 'lib/sprites.dart';
import 'package:sky/app/view.dart';
......@@ -11,13 +11,11 @@ void main() {
"https://raw.githubusercontent.com/slembcke/GalacticGuardian.spritebuilder/GDC/Packages/SpriteBuilder%20Resources.sbpack/resources-auto/BurnTexture.png",
"https://raw.githubusercontent.com/slembcke/GalacticGuardian.spritebuilder/GDC/Packages/SpriteBuilder%20Resources.sbpack/Sprites/resources-auto/asteroid_big_002.png",
"https://raw.githubusercontent.com/slembcke/GalacticGuardian.spritebuilder/GDC/Packages/SpriteBuilder%20Resources.sbpack/Sprites/resources-auto/GG_blueship_Lv3.png",
"https://raw.githubusercontent.com/slembcke/GalacticGuardian.spritebuilder/GDC/Packages/SpriteBuilder%20Resources.sbpack/Sprites/resources-auto/laserBlue.png",
],
allLoaded);
}
void allLoaded(ImageMap loader) {
// 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(root: (new GameTestsBox(new GameTests(loader), SpriteBoxTransformMode.nativePoints)));
app = new AppView(root: (new GameDemoBox(new GameDemoWorld(loader))));
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册