| 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"], sky.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; |
| } |
| } |