mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
278 lines
7.5 KiB
Dart
278 lines
7.5 KiB
Dart
part of game;
|
|
|
|
final double _gameSizeWidth = 320.0;
|
|
double _gameSizeHeight = 320.0;
|
|
|
|
final double _chunkSpacing = 640.0;
|
|
final int _chunksPerLevel = 9;
|
|
|
|
final bool _drawDebug = false;
|
|
|
|
class GameDemoNode extends NodeWithSize {
|
|
|
|
GameDemoNode(
|
|
this._images,
|
|
this._spritesGame,
|
|
this._spritesUI,
|
|
this._sounds,
|
|
this._gameOverCallback
|
|
): super(new Size(320.0, 320.0)) {
|
|
// Add background
|
|
_background = new RepeatedImage(_images["assets/starfield.png"]);
|
|
addChild(_background);
|
|
|
|
// Create starfield
|
|
_starField = new StarField(_spritesGame, 200);
|
|
addChild(_starField);
|
|
|
|
// Add nebula
|
|
_nebula = new RepeatedImage(_images["assets/nebula.png"], ui.TransferMode.plus);
|
|
addChild(_nebula);
|
|
|
|
// Setup game screen, it will always be anchored to the bottom of the screen
|
|
_gameScreen = new Node();
|
|
addChild(_gameScreen);
|
|
|
|
// Setup the level and add it to the screen, the level is the node where
|
|
// all our game objects live. It is moved to scroll the game
|
|
_level = new Level();
|
|
_gameScreen.addChild(_level);
|
|
|
|
// Add heads up display
|
|
_playerState = new PlayerState(_spritesUI, _spritesGame);
|
|
addChild(_playerState);
|
|
|
|
_objectFactory = new GameObjectFactory(_spritesGame, _sounds, _level, _playerState);
|
|
|
|
_level.ship = new Ship(_objectFactory);
|
|
_level.ship.setupActions();
|
|
_level.addChild(_level.ship);
|
|
|
|
// Add the joystick
|
|
_joystick = new VirtualJoystick();
|
|
_gameScreen.addChild(_joystick);
|
|
|
|
// Add initial game objects
|
|
addObjects();
|
|
}
|
|
|
|
// Resources
|
|
ImageMap _images;
|
|
Map<String, SoundEffect> _sounds;
|
|
SpriteSheet _spritesGame;
|
|
SpriteSheet _spritesUI;
|
|
|
|
// Sounds
|
|
SoundEffectPlayer _effectPlayer = SoundEffectPlayer.sharedInstance();
|
|
|
|
// Callback
|
|
Function _gameOverCallback;
|
|
|
|
// Game screen nodes
|
|
Node _gameScreen;
|
|
VirtualJoystick _joystick;
|
|
|
|
GameObjectFactory _objectFactory;
|
|
Level _level;
|
|
StarField _starField;
|
|
RepeatedImage _background;
|
|
RepeatedImage _nebula;
|
|
PlayerState _playerState;
|
|
|
|
// Game properties
|
|
double _scroll = 0.0;
|
|
|
|
int _framesToFire = 0;
|
|
int _framesBetweenShots = 20;
|
|
|
|
bool _gameOver = false;
|
|
|
|
void spriteBoxPerformedLayout() {
|
|
_gameSizeHeight = spriteBox.visibleArea.height;
|
|
_gameScreen.position = new Point(0.0, _gameSizeHeight);
|
|
}
|
|
|
|
void update(double dt) {
|
|
// Scroll the level
|
|
_scroll = _level.scroll(_playerState.scrollSpeed);
|
|
_starField.move(0.0, _playerState.scrollSpeed);
|
|
|
|
_background.move(_playerState.scrollSpeed * 0.1);
|
|
_nebula.move(_playerState.scrollSpeed);
|
|
|
|
// Add objects
|
|
addObjects();
|
|
|
|
// Move the ship
|
|
if (!_gameOver) {
|
|
_level.ship.applyThrust(_joystick.value, _scroll);
|
|
}
|
|
|
|
// Add shots
|
|
if (_framesToFire == 0 && _joystick.isDown && !_gameOver) {
|
|
fire();
|
|
_framesToFire = (_playerState.speedLaserActive) ? _framesBetweenShots ~/ 2 : _framesBetweenShots;
|
|
}
|
|
if (_framesToFire > 0) _framesToFire--;
|
|
|
|
// Move game objects
|
|
for (Node node in _level.children) {
|
|
if (node is GameObject) {
|
|
node.move();
|
|
}
|
|
}
|
|
|
|
// Remove offscreen game objects
|
|
for (int i = _level.children.length - 1; i >= 0; i--) {
|
|
Node node = _level.children[i];
|
|
if (node is GameObject) {
|
|
node.removeIfOffscreen(_scroll);
|
|
}
|
|
}
|
|
|
|
if (_gameOver) return;
|
|
|
|
// Check for collisions between lasers and objects that can take damage
|
|
List<Laser> lasers = [];
|
|
for (Node node in _level.children) {
|
|
if (node is Laser) lasers.add(node);
|
|
}
|
|
|
|
List<GameObject> damageables = [];
|
|
for (Node node in _level.children) {
|
|
if (node is GameObject && node.canBeDamaged) damageables.add(node);
|
|
}
|
|
|
|
for (Laser laser in lasers) {
|
|
for (GameObject damageable in damageables) {
|
|
if (laser.collidingWith(damageable)) {
|
|
// Hit something that can take damage
|
|
damageable.addDamage(laser.impact);
|
|
laser.destroy();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check for collsions between ship and objects that can damage the ship
|
|
List<Node> nodes = new List.from(_level.children);
|
|
for (Node node in nodes) {
|
|
if (node is GameObject && node.canDamageShip) {
|
|
if (node.collidingWith(_level.ship)) {
|
|
if (_playerState.shieldActive) {
|
|
// Hit, but saved by the shield!
|
|
node.destroy();
|
|
} else {
|
|
// The ship was hit :(
|
|
killShip();
|
|
}
|
|
}
|
|
} else if (node is GameObject && node.canBeCollected) {
|
|
if (node.collidingWith(_level.ship)) {
|
|
// The ship ran over something collectable
|
|
node.collect();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int _chunk = 0;
|
|
|
|
void addObjects() {
|
|
|
|
while (_scroll + _chunkSpacing >= _chunk * _chunkSpacing) {
|
|
addLevelChunk(
|
|
_chunk,
|
|
-_chunk * _chunkSpacing - _chunkSpacing);
|
|
|
|
_chunk += 1;
|
|
}
|
|
}
|
|
|
|
void addLevelChunk(int chunk, double yPos) {
|
|
int level = chunk ~/ _chunksPerLevel;
|
|
int part = chunk % _chunksPerLevel;
|
|
|
|
if (part == 0) {
|
|
LevelLabel lbl = new LevelLabel(_objectFactory, level + 1);
|
|
lbl.position = new Point(0.0, yPos + _chunkSpacing / 2.0 - 150.0);
|
|
_level.addChild(lbl);
|
|
} else if (part == 1) {
|
|
_objectFactory.addAsteroids(10 + level * 2, yPos, 0.0 + (level * 0.2).clamp(0.0, 0.7));
|
|
} else if (part == 2) {
|
|
_objectFactory.addEnemyScoutSwarm(4 + level * 2, yPos);
|
|
} else if (part == 3) {
|
|
_objectFactory.addAsteroids(10 + level * 2, yPos, 0.0 + (level * 0.2).clamp(0.0, 0.7));
|
|
} else if (part == 4) {
|
|
_objectFactory.addEnemyDestroyerSwarm(2 + level, yPos);
|
|
} else if (part == 5) {
|
|
_objectFactory.addAsteroids(10 + level * 2, yPos, 0.0 + (level * 0.2).clamp(0.0, 0.7));
|
|
} else if (part == 6) {
|
|
_objectFactory.addEnemyScoutSwarm(4 + level * 2, yPos);
|
|
} else if (part == 7) {
|
|
_objectFactory.addAsteroids(10 + level * 2, yPos, 0.0 + (level * 0.2).clamp(0.0, 0.7));
|
|
} else if (part == 8) {
|
|
_objectFactory.addBossFight(level, yPos);
|
|
}
|
|
}
|
|
|
|
void fire() {
|
|
int laserLevel = _objectFactory.playerState.laserLevel;
|
|
|
|
Laser shot0 = new Laser(_objectFactory, laserLevel, -90.0);
|
|
shot0.position = _level.ship.position + new Offset(17.0, -10.0);
|
|
_level.addChild(shot0);
|
|
|
|
Laser shot1 = new Laser(_objectFactory, laserLevel, -90.0);
|
|
shot1.position = _level.ship.position + new Offset(-17.0, -10.0);
|
|
_level.addChild(shot1);
|
|
|
|
if (_playerState.sideLaserActive) {
|
|
Laser shot2 = new Laser(_objectFactory, laserLevel, -45.0);
|
|
shot2.position = _level.ship.position + new Offset(17.0, -10.0);
|
|
_level.addChild(shot2);
|
|
|
|
Laser shot3 = new Laser(_objectFactory, laserLevel, -135.0);
|
|
shot3.position = _level.ship.position + new Offset(-17.0, -10.0);
|
|
_level.addChild(shot3);
|
|
}
|
|
|
|
_effectPlayer.play(_sounds["laser"]);
|
|
}
|
|
|
|
void killShip() {
|
|
// Hide ship
|
|
_level.ship.visible = false;
|
|
|
|
_effectPlayer.play(_sounds["explosion"]);
|
|
|
|
// Add explosion
|
|
ExplosionBig explo = new ExplosionBig(_spritesGame);
|
|
explo.scale = 1.5;
|
|
explo.position = _level.ship.position;
|
|
_level.addChild(explo);
|
|
|
|
// Add flash
|
|
Flash flash = new Flash(size, 1.0);
|
|
addChild(flash);
|
|
|
|
// Set the state to game over
|
|
_gameOver = true;
|
|
|
|
// Return to main scene and report the score back in 2 seconds
|
|
new Timer(new Duration(seconds: 2), () { _gameOverCallback(_playerState.score); });
|
|
}
|
|
}
|
|
|
|
class Level extends Node {
|
|
Level() {
|
|
position = new Point(160.0, 0.0);
|
|
}
|
|
|
|
Ship ship;
|
|
|
|
double scroll(double scrollSpeed) {
|
|
position += new Offset(0.0, scrollSpeed);
|
|
return position.y;
|
|
}
|
|
}
|