mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
745 lines
21 KiB
Dart
745 lines
21 KiB
Dart
part of game;
|
|
|
|
const double _steeringThreshold = 0.0;
|
|
const double _steeringMax = 150.0;
|
|
|
|
// 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;
|
|
|
|
const int _numStarsInStarField = 150;
|
|
|
|
const int _numFramesShieldActive = 60 * 5;
|
|
const int _numFramesShieldFlickers = 60;
|
|
|
|
class GameDemoWorld extends NodeWithSize {
|
|
// Images
|
|
sky.Image _imgNebula;
|
|
|
|
SpriteSheet _spriteSheet;
|
|
SpriteSheet _spriteSheetUI;
|
|
Navigator _navigator;
|
|
|
|
// Inputs
|
|
double _joystickX = 0.0;
|
|
double _joystickY = 0.0;
|
|
|
|
Node _gameLayer;
|
|
|
|
Ship _ship;
|
|
Sprite _shield;
|
|
List<Asteroid> _asteroids = [];
|
|
List<Laser> _lasers = [];
|
|
StarField _starField;
|
|
Nebula _nebula;
|
|
|
|
// Game state
|
|
int _numFrames = 0;
|
|
bool _isGameOver = false;
|
|
int _gameOverFrame;
|
|
int _currentLevel = 0;
|
|
|
|
// Heads up display
|
|
Hud _hud;
|
|
|
|
Function _gameOverCallback;
|
|
|
|
GameDemoWorld(App app, this._navigator, ImageMap images, this._spriteSheet, this._spriteSheetUI, this._gameOverCallback) : super(new Size(_gameSizeWidth, _gameSizeHeight)) {
|
|
// Fetch images
|
|
_imgNebula = images["assets/nebula.png"];
|
|
|
|
_gameLayer = new Node();
|
|
this.addChild(_gameLayer);
|
|
// Add ship
|
|
addShip();
|
|
|
|
// Add background
|
|
Sprite sprtBackground = new Sprite.fromImage(images["assets/starfield.png"]);
|
|
sprtBackground.position = new Point(512.0, 512.0);
|
|
sprtBackground.zPosition = -3.0;
|
|
addChild(sprtBackground);
|
|
|
|
// Add starfield
|
|
_starField = new StarField(_spriteSheet, _numStarsInStarField);
|
|
_starField.zPosition = -2.0;
|
|
addChild(_starField);
|
|
|
|
// Add nebula
|
|
addNebula();
|
|
|
|
userInteractionEnabled = true;
|
|
handleMultiplePointers = true;
|
|
|
|
_hud = new Hud(_spriteSheetUI);
|
|
_hud.zPosition = 1000.0;
|
|
addChild(_hud);
|
|
|
|
// Setup level
|
|
setupLevel(0);
|
|
}
|
|
|
|
void setupLevel(int level) {
|
|
int numLargeAsteroids = 5 + level * 2;
|
|
int numMediumAsteroids = 5 + level * 2;
|
|
|
|
// Add some asteroids to the game world
|
|
for (int i = 0; i < numLargeAsteroids; i++) {
|
|
addAsteroid(AsteroidSize.large);
|
|
}
|
|
for (int i = 0; i < numMediumAsteroids; i++) {
|
|
addAsteroid(AsteroidSize.medium);
|
|
}
|
|
|
|
_numFrames = 0;
|
|
_shield.visible = true;
|
|
}
|
|
|
|
// Methods for adding game objects
|
|
|
|
void addAsteroid(AsteroidSize size, [Point pos]) {
|
|
Asteroid asteroid = new Asteroid(_spriteSheet, size);
|
|
asteroid.zPosition = 1.0;
|
|
if (pos != null) asteroid.position = pos;
|
|
_gameLayer.addChild(asteroid);
|
|
_asteroids.add(asteroid);
|
|
|
|
// Animate asteroid into the scene
|
|
Action action = new ActionTween((a) => asteroid.scale = a, 0.0, 1.0, 1.0, bounceOut);
|
|
_gameLayer.actions.run(action);
|
|
}
|
|
|
|
void addShip() {
|
|
Ship ship = new Ship(_spriteSheet["ship.png"]);
|
|
ship.zPosition = 10.0;
|
|
_gameLayer.addChild(ship);
|
|
_ship = ship;
|
|
|
|
_shield = new Sprite(_spriteSheet["shield.png"]);
|
|
_shield.zPosition = 11.0;
|
|
_shield.scale = 0.5;
|
|
_shield.transferMode = sky.TransferMode.plus;
|
|
_gameLayer.addChild(_shield);
|
|
|
|
Action rotate = new ActionRepeatForever(new ActionTween((a) => _shield.rotation = a, 0.0, 360.0, 1.0));
|
|
actions.run(rotate);
|
|
}
|
|
|
|
void addLaser() {
|
|
Laser laser = new Laser(_spriteSheet["laser.png"], _ship);
|
|
laser.zPosition = 8.0;
|
|
laser.constrainProportions = true;
|
|
_lasers.add(laser);
|
|
_gameLayer.addChild(laser);
|
|
}
|
|
|
|
void addNebula() {
|
|
_nebula = new Nebula.withImage(_imgNebula);
|
|
_gameLayer.addChild(_nebula);
|
|
}
|
|
|
|
void addExplosion(AsteroidSize asteroidSize, Point position) {
|
|
Node explosionNode = new Node();
|
|
|
|
// Add particles
|
|
ParticleSystem particlesDebris = new ParticleSystem(
|
|
_spriteSheet["explosion_particle.png"],
|
|
rotateToMovement: true,
|
|
startRotation:90.0,
|
|
startRotationVar: 0.0,
|
|
endRotation: 90.0,
|
|
startSize: 0.3,
|
|
startSizeVar: 0.1,
|
|
endSize: 0.3,
|
|
endSizeVar: 0.1,
|
|
numParticlesToEmit: 25,
|
|
emissionRate:1000.0,
|
|
greenVar: 127,
|
|
redVar: 127
|
|
);
|
|
particlesDebris.zPosition = 1010.0;
|
|
explosionNode.addChild(particlesDebris);
|
|
|
|
ParticleSystem particlesFire = new ParticleSystem(
|
|
_spriteSheet["fire_particle.png"],
|
|
colorSequence: new ColorSequence([new Color(0xffffff33), new Color(0xffff3333), new Color(0x00ff3333)], [0.0, 0.5, 1.0]),
|
|
numParticlesToEmit: 25,
|
|
emissionRate: 1000.0,
|
|
startSize: 0.5,
|
|
startSizeVar: 0.1,
|
|
endSize: 0.5,
|
|
endSizeVar: 0.1,
|
|
posVar: new Point(10.0, 10.0),
|
|
speed: 10.0,
|
|
speedVar: 5.0
|
|
);
|
|
particlesFire.zPosition = 1011.0;
|
|
explosionNode.addChild(particlesFire);
|
|
|
|
|
|
// Add ring
|
|
Sprite sprtRing = new Sprite(_spriteSheet["explosion_ring.png"]);
|
|
sprtRing.transferMode = sky.TransferMode.plus;
|
|
explosionNode.addChild(sprtRing);
|
|
|
|
Action scale = new ActionTween( (a) => sprtRing.scale = a, 0.2, 1.0, 1.5);
|
|
Action scaleAndRemove = new ActionSequence([scale, new ActionRemoveNode(sprtRing)]);
|
|
Action fade = new ActionTween( (a) => sprtRing.opacity = a, 1.0, 0.0, 1.5);
|
|
actions.run(scaleAndRemove);
|
|
actions.run(fade);
|
|
|
|
// Add streaks
|
|
for (int i = 0; i < 5; i++) {
|
|
Sprite sprtFlare = new Sprite(_spriteSheet["explosion_flare.png"]);
|
|
sprtFlare.pivot = new Point(0.3, 1.0);
|
|
sprtFlare.scaleX = 0.3;
|
|
sprtFlare.transferMode = sky.TransferMode.plus;
|
|
sprtFlare.rotation = _rand.nextDouble() * 360.0;
|
|
explosionNode.addChild(sprtFlare);
|
|
|
|
double multiplier = _rand.nextDouble() * 0.3 + 1.0;
|
|
|
|
Action scale = new ActionTween( (a) => sprtFlare.scaleY = a, 0.3 * multiplier, 0.8, 1.5 * multiplier);
|
|
Action scaleAndRemove = new ActionSequence([scale, new ActionRemoveNode(sprtFlare)]);
|
|
Action fadeIn = new ActionTween( (a) => sprtFlare.opacity = a, 0.0, 1.0, 0.5 * multiplier);
|
|
Action fadeOut = new ActionTween( (a) => sprtFlare.opacity = a, 1.0, 0.0, 1.0 * multiplier);
|
|
Action fadeInOut = new ActionSequence([fadeIn, fadeOut]);
|
|
actions.run(scaleAndRemove);
|
|
actions.run(fadeInOut);
|
|
}
|
|
|
|
explosionNode.position = position;
|
|
explosionNode.zPosition = 1010.0;
|
|
|
|
if (asteroidSize == AsteroidSize.large) {
|
|
explosionNode.scale = 1.5;
|
|
}
|
|
|
|
_gameLayer.addChild(explosionNode);
|
|
}
|
|
|
|
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();
|
|
_shield.position = _ship.position;
|
|
|
|
// 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 and explosions
|
|
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);
|
|
}
|
|
|
|
addExplosion(asteroid._asteroidSize, asteroid.position);
|
|
|
|
// Remove asteroid
|
|
asteroid.removeFromParent();
|
|
_asteroids.removeAt(j);
|
|
|
|
// Scoring
|
|
if (asteroid._asteroidSize == AsteroidSize.large)
|
|
addScore(100);
|
|
else if (asteroid._asteroidSize == AsteroidSize.medium)
|
|
addScore(50);
|
|
else
|
|
addScore(10);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check collisions between asteroids and ship
|
|
if (_numFrames > _numFramesShieldActive) {
|
|
// Shield is no longer active
|
|
|
|
for (int i = _asteroids.length - 1; i >= 0; i--) {
|
|
// Iterate over all the asteroids
|
|
Asteroid asteroid = _asteroids[i];
|
|
|
|
if (pointQuickDist(asteroid.position, _ship.position) < asteroid.radius + _ship.radius) {
|
|
killShip();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Move objects to center camera and warp objects around the edges
|
|
centerCamera();
|
|
warpObjects();
|
|
|
|
// Check for level up
|
|
if (_asteroids.length == 0) {
|
|
_currentLevel++;
|
|
setupLevel(_currentLevel);
|
|
}
|
|
|
|
// Update shield
|
|
if (_numFrames > _numFramesShieldActive) _shield.visible = false;
|
|
else if (_numFrames > _numFramesShieldActive - _numFramesShieldFlickers) _shield.visible = !_shield.visible;
|
|
|
|
// Check for exit back to main screen
|
|
if (_isGameOver && _numFrames - _gameOverFrame == 60) {
|
|
_navigator.pop();
|
|
}
|
|
|
|
_numFrames++;
|
|
}
|
|
|
|
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 _gameLayer.children) {
|
|
child.position = pointAdd(child.position, delta);
|
|
}
|
|
|
|
// Update starfield
|
|
_starField.move(delta.x, delta.y);
|
|
}
|
|
|
|
void warpObjects() {
|
|
for (Node child in _gameLayer.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));
|
|
}
|
|
}
|
|
|
|
void killShip() {
|
|
if (_isGameOver) return;
|
|
|
|
// Set game over
|
|
_isGameOver = true;
|
|
_gameOverFrame = _numFrames;
|
|
_gameOverCallback(_hud.score);
|
|
|
|
// Remove the ship
|
|
_ship.visible = false;
|
|
|
|
// Add an explosion
|
|
addExplosion(AsteroidSize.large, _ship.position);
|
|
}
|
|
|
|
// Handling controls
|
|
|
|
void controlSteering(double x, double y) {
|
|
// Reset controls if it's game over
|
|
if (_isGameOver) {
|
|
x = y = 0.0;
|
|
}
|
|
|
|
_joystickX = x;
|
|
_joystickY = y;
|
|
}
|
|
|
|
void controlFire() {
|
|
// Don't shoot if it's game over
|
|
if (_isGameOver) return;
|
|
|
|
addLaser();
|
|
}
|
|
|
|
// Handle pointer events
|
|
|
|
int _firstPointer = -1;
|
|
int _secondPointer = -1;
|
|
Point _firstPointerDownPos;
|
|
|
|
bool handleEvent(SpriteBoxEvent event) {
|
|
|
|
Point pointerPos = convertPointToNodeSpace(event.boxPosition);
|
|
int pointer = event.pointer;
|
|
|
|
switch (event.type) {
|
|
case 'pointerdown':
|
|
if (_firstPointer == -1) {
|
|
// Assign the first pointer
|
|
_firstPointer = pointer;
|
|
_firstPointerDownPos = pointerPos;
|
|
}
|
|
else if (_secondPointer == -1) {
|
|
// Assign second pointer
|
|
_secondPointer = pointer;
|
|
controlFire();
|
|
}
|
|
else {
|
|
// There is a pointer used for steering, let's fire instead
|
|
controlFire();
|
|
}
|
|
break;
|
|
case 'pointermove':
|
|
if (pointer == _firstPointer) {
|
|
// Handle turning control
|
|
double joystickX = 0.0;
|
|
double deltaX = pointerPos.x - _firstPointerDownPos.x;
|
|
if (deltaX > _steeringThreshold || deltaX < -_steeringThreshold) {
|
|
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;
|
|
}
|
|
|
|
controlSteering(joystickX, joystickY);
|
|
}
|
|
break;
|
|
case 'pointerup':
|
|
case 'pointercancel':
|
|
if (pointer == _firstPointer) {
|
|
// Un-assign the first pointer
|
|
_firstPointer = -1;
|
|
_firstPointerDownPos = null;
|
|
controlSteering(0.0, 0.0);
|
|
}
|
|
else if (pointer == _secondPointer) {
|
|
_secondPointer = -1;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Scoring and HUD
|
|
void addScore(int score) {
|
|
_hud.score += score;
|
|
}
|
|
}
|
|
|
|
// 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(SpriteSheet spriteSheet, AsteroidSize this._asteroidSize) {
|
|
size = new Size(radius * 2.0, radius * 2.0);
|
|
position = new Point(_gameSizeWidth * _rand.nextDouble(), _gameSizeHeight * _rand.nextDouble());
|
|
rotation = 360.0 * _rand.nextDouble();
|
|
|
|
if (_asteroidSize == AsteroidSize.small) {
|
|
texture = spriteSheet["asteroid_small_${_rand.nextInt(2)}.png"];
|
|
} else {
|
|
texture = spriteSheet["asteroid_big_${_rand.nextInt(2)}.png"];
|
|
}
|
|
|
|
_movementVector = new Point(_rand.nextDouble() * _maxAsteroidSpeed * 2 - _maxAsteroidSpeed,
|
|
_rand.nextDouble() * _maxAsteroidSpeed * 2 - _maxAsteroidSpeed);
|
|
|
|
userInteractionEnabled = true;
|
|
|
|
// Rotate forever
|
|
double direction = (_rand.nextBool()) ? 360.0 : -360.0;
|
|
ActionTween rot = new ActionTween( (a) => rotation = a, 0.0, direction, 2.0 * _rand.nextDouble() + 2.0);
|
|
ActionRepeatForever repeat = new ActionRepeatForever(rot);
|
|
actions.run(repeat);
|
|
}
|
|
|
|
bool handleEvent(SpriteBoxEvent event) {
|
|
if (event.type == "pointerdown") {
|
|
actions.stopWithTag("fade");
|
|
colorOverlay = new Color(0x99ffffff);
|
|
}
|
|
else if (event.type == "pointerup") {
|
|
// Fade out the color overlay
|
|
Action fadeOut = new ActionTween((a) => this.colorOverlay = a, new Color(0x99ffffff), new Color(0x00ffffff), 1.0);
|
|
Action fadeOutAndRemove = new ActionSequence([fadeOut, new ActionCallFunction(() => this.colorOverlay = null)]);
|
|
actions.run(fadeOutAndRemove, "fade");
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
class Ship extends Sprite {
|
|
Vector2 _movementVector;
|
|
double _rotationTarget;
|
|
double radius = _shipRadius;
|
|
|
|
Ship(Texture img) : super(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 = 20.0;
|
|
|
|
Laser(Texture img, Ship ship) : super(img) {
|
|
size = new Size(30.0, 30.0);
|
|
position = ship.position;
|
|
rotation = ship.rotation + 90.0;
|
|
transferMode = sky.TransferMode.plus;
|
|
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]);
|
|
}
|
|
|
|
void move() {
|
|
position = pointAdd(position, _movementVector);
|
|
_frameCount++;
|
|
}
|
|
}
|
|
|
|
// Background starfield
|
|
|
|
class StarField extends NodeWithSize {
|
|
sky.Image _image;
|
|
int _numStars;
|
|
bool _autoScroll;
|
|
List<Point> _starPositions;
|
|
List<double> _starScales;
|
|
List<Rect> _rects;
|
|
List<Color> _colors;
|
|
Paint _paint = new Paint()
|
|
..setFilterQuality(sky.FilterQuality.low)
|
|
..isAntiAlias = false
|
|
..setTransferMode(sky.TransferMode.plus);
|
|
|
|
StarField(SpriteSheet spriteSheet, this._numStars, [this._autoScroll = false]) : super(new Size(1024.0, 1024.0)) {
|
|
_starPositions = [];
|
|
_starScales = [];
|
|
_colors = [];
|
|
_rects = [];
|
|
|
|
for (int i = 0; i < _numStars; i++) {
|
|
_starPositions.add(new Point(_rand.nextDouble() * _gameSizeWidth, _rand.nextDouble() * _gameSizeHeight));
|
|
_starScales.add(_rand.nextDouble());
|
|
_colors.add(new Color.fromARGB((255.0 * (_rand.nextDouble() * 0.5 + 0.5)).toInt(), 255, 255, 255));
|
|
_rects.add(spriteSheet["star_${_rand.nextInt(2)}.png"].frame);
|
|
}
|
|
|
|
_image = spriteSheet.image;
|
|
}
|
|
|
|
void paint(PaintingCanvas canvas) {
|
|
// Create a transform for each star
|
|
List<sky.RSTransform> transforms = [];
|
|
for (int i = 0; i < _numStars; i++) {
|
|
sky.RSTransform transform = new sky.RSTransform(_starScales[i], 0.0, _starPositions[i].x, _starPositions[i].y);
|
|
transforms.add(transform);
|
|
}
|
|
|
|
// Draw the stars
|
|
canvas.drawAtlas(_image, transforms, _rects, _colors, sky.TransferMode.modulate, null, _paint);
|
|
}
|
|
|
|
void move(double dx, double dy) {
|
|
for (int i = 0; i < _numStars; i++) {
|
|
double xPos = _starPositions[i].x;
|
|
double yPos = _starPositions[i].y;
|
|
double scale = _starScales[i];
|
|
|
|
xPos += dx * scale;
|
|
yPos += dy * scale;
|
|
|
|
if (xPos >= _gameSizeWidth) xPos -= _gameSizeWidth;
|
|
if (xPos < 0) xPos += _gameSizeWidth;
|
|
if (yPos >= _gameSizeHeight) yPos -= _gameSizeHeight;
|
|
if (yPos < 0) yPos += _gameSizeHeight;
|
|
|
|
_starPositions[i] = new Point(xPos, yPos);
|
|
}
|
|
}
|
|
|
|
void update(double dt) {
|
|
if (_autoScroll) {
|
|
move(dt * 100.0, 0.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
class Hud extends NodeWithSize {
|
|
SpriteSheet spriteSheetUI;
|
|
Sprite sprtBgScore;
|
|
Sprite sprtBgShield;
|
|
bool _dirtyScore = true;
|
|
|
|
int _score = 0;
|
|
|
|
int get score => _score;
|
|
|
|
set score(int score) {
|
|
_score = score;
|
|
_dirtyScore = true;
|
|
}
|
|
|
|
Hud(this.spriteSheetUI) : super(Size.zero) {
|
|
pivot = Point.origin;
|
|
|
|
sprtBgScore = new Sprite(spriteSheetUI["scoreboard.png"]);
|
|
sprtBgScore.pivot = new Point(1.0, 0.0);
|
|
sprtBgScore.scale = 0.6;
|
|
addChild(sprtBgScore);
|
|
|
|
sprtBgShield = new Sprite(spriteSheetUI["bar_shield.png"]);
|
|
sprtBgShield.pivot = Point.origin;
|
|
sprtBgShield.scale = 0.6;
|
|
// TODO: Add shield
|
|
//addChild(sprtBgShield);
|
|
}
|
|
|
|
void spriteBoxPerformedLayout() {
|
|
// Set the size and position of HUD display
|
|
position = spriteBox.visibleArea.topLeft;
|
|
size = spriteBox.visibleArea.size;
|
|
|
|
// Position hud objects
|
|
sprtBgShield.position = new Point(20.0, 20.0);
|
|
sprtBgScore.position = new Point(size.width - 20.0, 20.0);
|
|
}
|
|
|
|
void update(double dt) {
|
|
// Update score
|
|
if (_dirtyScore) {
|
|
|
|
sprtBgScore.removeAllChildren();
|
|
|
|
String scoreStr = _score.toString();
|
|
double xPos = -50.0;
|
|
for (int i = scoreStr.length - 1; i >= 0; i--) {
|
|
String numStr = scoreStr.substring(i, i + 1);
|
|
Sprite numSprt = new Sprite(spriteSheetUI["number_$numStr.png"]);
|
|
numSprt.position = new Point(xPos, 49.0);
|
|
sprtBgScore.addChild(numSprt);
|
|
xPos -= 37.0;
|
|
}
|
|
_dirtyScore = false;
|
|
}
|
|
// Update power bar
|
|
}
|
|
}
|
|
|
|
class Nebula extends Node {
|
|
|
|
Nebula.withImage(sky.Image img) {
|
|
for (int i = 0; i < 2; i++) {
|
|
for (int j = 0; j < 2; j++) {
|
|
Sprite sprt = new Sprite.fromImage(img);
|
|
sprt.transferMode = sky.TransferMode.plus;
|
|
sprt.pivot = Point.origin;
|
|
sprt.position = new Point(i * _gameSizeWidth - _gameSizeWidth, j * _gameSizeHeight - _gameSizeHeight);
|
|
addChild(sprt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|