game_demo_node.dart 7.54 KB
Newer Older
1 2 3 4 5
part of game;

final double _gameSizeWidth = 320.0;
double _gameSizeHeight = 320.0;

6
final double _chunkSpacing = 640.0;
7
final int _chunksPerLevel = 9;
8

9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
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);

41
    // Add heads up display
42
    _playerState = new PlayerState(_spritesUI, _spritesGame);
43 44 45
    addChild(_playerState);

    _objectFactory = new GameObjectFactory(_spritesGame, _sounds, _level, _playerState);
46 47

    _level.ship = new Ship(_objectFactory);
48
    _level.ship.setupActions();
49 50 51 52 53 54
    _level.addChild(_level.ship);

    // Add the joystick
    _joystick = new VirtualJoystick();
    _gameScreen.addChild(_joystick);

55
    // Add initial game objects
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
    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;
80
  PlayerState _playerState;
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

  // 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
97 98
    _scroll = _level.scroll(_playerState.scrollSpeed);
    _starField.move(0.0, _playerState.scrollSpeed);
99

100 101
    _background.move(_playerState.scrollSpeed * 0.1);
    _nebula.move(_playerState.scrollSpeed);
102 103 104 105 106 107 108 109 110 111 112 113

    // Add objects
    addObjects();

    // Move the ship
    if (!_gameOver) {
      _level.ship.applyThrust(_joystick.value, _scroll);
    }

    // Add shots
    if (_framesToFire == 0 && _joystick.isDown && !_gameOver) {
      fire();
114
      _framesToFire = (_playerState.speedLaserActive) ? _framesBetweenShots ~/ 2 : _framesBetweenShots;
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
    }
    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
150
          damageable.addDamage(laser.impact);
151 152 153 154 155 156 157 158 159 160
          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)) {
161 162 163 164 165 166 167
          if (_playerState.shieldActive) {
            // Hit, but saved by the shield!
            node.destroy();
          } else {
            // The ship was hit :(
            killShip();
          }
168
        }
169 170 171
      } else if (node is GameObject && node.canBeCollected) {
        if (node.collidingWith(_level.ship)) {
          // The ship ran over something collectable
172
          node.collect();
173
        }
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
      }
    }
  }

  int _chunk = 0;

  void addObjects() {

    while (_scroll + _chunkSpacing >= _chunk * _chunkSpacing) {
      addLevelChunk(
        _chunk,
        -_chunk * _chunkSpacing - _chunkSpacing);

      _chunk += 1;
    }
  }

  void addLevelChunk(int chunk, double yPos) {
192 193 194 195
    int level = chunk ~/ _chunksPerLevel;
    int part = chunk % _chunksPerLevel;

    if (part == 0) {
196 197 198 199
      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) {
200
      _objectFactory.addAsteroids(10 + level * 2, yPos, 0.0 + (level * 0.2).clamp(0.0, 0.7));
201
    } else if (part == 2) {
202
      _objectFactory.addEnemyScoutSwarm(4 + level * 2, yPos);
203
    } else if (part == 3) {
204
      _objectFactory.addAsteroids(10 + level * 2, yPos, 0.0 + (level * 0.2).clamp(0.0, 0.7));
205
    } else if (part == 4) {
206 207
      _objectFactory.addEnemyDestroyerSwarm(2 + level, yPos);
    } else if (part == 5) {
208 209 210 211 212
      _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));
213 214
    } else if (part == 8) {
      _objectFactory.addBossFight(level, yPos);
215 216 217 218
    }
  }

  void fire() {
219 220 221
    int laserLevel = _objectFactory.playerState.laserLevel;

    Laser shot0 = new Laser(_objectFactory, laserLevel, -90.0);
222 223 224
    shot0.position = _level.ship.position + new Offset(17.0, -10.0);
    _level.addChild(shot0);

225
    Laser shot1 = new Laser(_objectFactory, laserLevel, -90.0);
226 227 228
    shot1.position = _level.ship.position + new Offset(-17.0, -10.0);
    _level.addChild(shot1);

229
    if (_playerState.sideLaserActive) {
230
      Laser shot2 = new Laser(_objectFactory, laserLevel, -45.0);
231 232 233
      shot2.position = _level.ship.position + new Offset(17.0, -10.0);
      _level.addChild(shot2);

234
      Laser shot3 = new Laser(_objectFactory, laserLevel, -135.0);
235 236 237 238
      shot3.position = _level.ship.position + new Offset(-17.0, -10.0);
      _level.addChild(shot3);
    }

239 240 241 242 243 244 245 246 247 248
    _effectPlayer.play(_sounds["laser"]);
  }

  void killShip() {
    // Hide ship
    _level.ship.visible = false;

    _effectPlayer.play(_sounds["explosion"]);

    // Add explosion
249
    ExplosionBig explo = new ExplosionBig(_spritesGame);
250 251 252 253 254 255 256 257 258 259 260 261
    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
262
    new Timer(new Duration(seconds: 2), () { _gameOverCallback(_playerState.score); });
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
  }
}

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