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; } }