Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1316)

Unified Diff: samples/openglui/src/blasteroids.dart

Issue 24698003: Removed the openglui sample app. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: samples/openglui/src/blasteroids.dart
diff --git a/samples/openglui/src/blasteroids.dart b/samples/openglui/src/blasteroids.dart
deleted file mode 100644
index 203a26fe499a5e6196d56cd9a7eb3e7446fa75ee..0000000000000000000000000000000000000000
--- a/samples/openglui/src/blasteroids.dart
+++ /dev/null
@@ -1,3334 +0,0 @@
-// A Dart port of Kevin Roast's Asteroids game.
-// http://www.kevs3d.co.uk/dev/asteroids
-// Used with permission, including the sound and bitmap assets.
-
-// This should really be multiple files but the embedder doesn't support
-// parts yet. I concatenated the parts in a somewhat random order.
-//
-// Note that Skia seems to have issues with the render compositing modes, so
-// explosions look a bit messy; they aren't transparent where they should be.
-//
-// Currently we use the accelerometer on the phone for direction and thrust.
-// This is hard to control and should probably be changed. The game is also a
-// bit janky on the phone.
-
-library asteroids;
-
-import 'dart:math' as Math;
-import 'gl.dart';
-
-const RAD = Math.PI / 180.0;
-const PI = Math.PI;
-const TWOPI = Math.PI * 2;
-const ONEOPI = 1.0 / Math.PI;
-const PIO2 = Math.PI / 2.0;
-const PIO4 = Math.PI / 4.0;
-const PIO8 = Math.PI / 8.0;
-const PIO16 = Math.PI / 16.0;
-const PIO32 = Math.PI / 32.0;
-
-var _rnd = new Math.Random();
-double random() => _rnd.nextDouble();
-int randomInt(int min, int max) => min + _rnd.nextInt(max - min + 1);
-
-class Key {
- static const SHIFT = 16;
- static const CTRL = 17;
- static const ESC = 27;
- static const RIGHT = 39;
- static const UP = 38;
- static const LEFT = 37;
- static const DOWN = 40;
- static const SPACE = 32;
- static const A = 65;
- static const E = 69;
- static const G = 71;
- static const L = 76;
- static const P = 80;
- static const R = 82;
- static const S = 83;
- static const Z = 90;
-}
-
-// Globals
-var Debug = {
- 'enabled': false,
- 'invincible': false,
- 'collisionRadius': false,
- 'fps': true
-};
-
-var glowEffectOn = true;
-const GLOWSHADOWBLUR = 8;
-const SCOREDBKEY = "asteroids-score-1.1";
-
-var _asteroidImgs = [];
-var _shieldImg = new ImageElement();
-var _backgroundImg = new ImageElement();
-var _playerImg = new ImageElement();
-var _enemyshipImg = new ImageElement();
-var soundManager;
-
-/** Asteroids color constants */
-class Colors {
- static const PARTICLE = "rgb(255,125,50)";
- static const ENEMY_SHIP = "rgb(200,200,250)";
- static const ENEMY_SHIP_DARK = "rgb(150,150,200)";
- static const GREEN_LASER = "rgb(120,255,120)";
- static const GREEN_LASER_DARK = "rgb(50,255,50)";
- static const GREEN_LASERX2 = "rgb(120,255,150)";
- static const GREEN_LASERX2_DARK = "rgb(50,255,75)";
- static const PLAYER_BOMB = "rgb(155,255,155)";
- static const PLAYER_THRUST = "rgb(25,125,255)";
- static const PLAYER_SHIELD = "rgb(100,100,255)";
-}
-
-/**
- * Actor base class.
- *
- * Game actors have a position in the game world and a current vector to
- * indicate direction and speed of travel per frame. They each support the
- * onUpdate() and onRender() event methods, finally an actor has an expired()
- * method which should return true when the actor object should be removed
- * from play.
- */
-class Actor {
- Vector position, velocity;
-
- Actor(this.position, this.velocity);
-
- /**
- * Actor game loop update event method. Called for each actor
- * at the start of each game loop cycle.
- */
- onUpdate(Scene scene) {}
-
- /**
- * Actor rendering event method. Called for each actor to
- * render for each frame.
- */
- void onRender(CanvasRenderingContext2D ctx) {}
-
- /**
- * Actor expiration test; return true if expired and to be removed
- * from the actor list, false if still in play.
- */
- bool expired() => false;
-
- get frameMultiplier => GameHandler.frameMultiplier;
- get frameStart => GameHandler.frameStart;
- get canvas_height => GameHandler.height;
- get canvas_width => GameHandler.width;
-}
-
-// Short-lived actors (like particles and munitions). These have a
-// start time and lifespan, and fade out after a period.
-
-class ShortLivedActor extends Actor {
- int lifespan;
- int start;
-
- ShortLivedActor(Vector position, Vector velocity,
- this.lifespan)
- : super(position, velocity),
- this.start = GameHandler.frameStart;
-
- bool expired() => (frameStart - start > lifespan);
-
- /**
- * Helper to return a value multiplied by the ratio of the remaining lifespan
- */
- double fadeValue(double val, int offset) {
- var rem = lifespan - (frameStart - start),
- result = val;
- if (rem < offset) {
- result = (val / offset) * rem;
- result = Math.max(0.0, Math.min(result, val));
- }
- return result;
- }
-}
-
-class AttractorScene extends Scene {
- AsteroidsMain game;
-
- AttractorScene(this.game)
- : super(false, null) {
- }
-
- bool start = false;
- bool imagesLoaded = false;
- double sine = 0.0;
- double mult = 0.0;
- double multIncrement = 0.0;
- List actors = null;
- const SCENE_LENGTH = 400;
- const SCENE_FADE = 75;
- List sceneRenderers = null;
- int currentSceneRenderer = 0;
- int currentSceneFrame = 0;
-
- bool isComplete() => start;
-
- void onInitScene() {
- start = false;
- mult = 512.0;
- multIncrement = 0.5;
- currentSceneRenderer = 0;
- currentSceneFrame = 0;
-
- // scene renderers
- // display welcome text, info text and high scores
- sceneRenderers = [
- sceneRendererWelcome,
- sceneRendererInfo,
- sceneRendererScores ];
-
- // randomly generate some background asteroids for attractor scene
- actors = [];
- for (var i = 0; i < 8; i++) {
- var pos = new Vector(random() * GameHandler.width.toDouble(),
- random() * GameHandler.height.toDouble());
- var vec = new Vector(((random() * 2.0) - 1.0), ((random() * 2.0) - 1.0));
- actors.add(new Asteroid(pos, vec, randomInt(3, 4)));
- }
-
- game.score = 0;
- game.lives = 3;
- }
-
- void onRenderScene(CanvasRenderingContext2D ctx) {
- if (imagesLoaded) {
- // Draw the background asteroids.
- for (var i = 0; i < actors.length; i++) {
- var actor = actors[i];
- actor.onUpdate(this);
- game.updateActorPosition(actor);
- actor.onRender(ctx);
- }
-
- // Handle cycling through scenes.
- if (++currentSceneFrame == SCENE_LENGTH) { // Move to next scene.
- if (++currentSceneRenderer == sceneRenderers.length) {
- currentSceneRenderer = 0; // Wrap to first scene.
- }
- currentSceneFrame = 0;
- }
-
- ctx.save();
-
- // fade in/out
- if (currentSceneFrame < SCENE_FADE) {
- // fading in
- ctx.globalAlpha = 1 - ((SCENE_FADE - currentSceneFrame) / SCENE_FADE);
- } else if (currentSceneFrame >= SCENE_LENGTH - SCENE_FADE) {
- // fading out
- ctx.globalAlpha = ((SCENE_LENGTH - currentSceneFrame) / SCENE_FADE);
- } else {
- ctx.globalAlpha = 1.0;
- }
-
- sceneRenderers[currentSceneRenderer](ctx);
-
- ctx.restore();
-
- sineText(ctx, "BLASTEROIDS",
- GameHandler.width ~/ 2 - 130, GameHandler.height ~/ 2 - 64);
- } else {
- centerFillText(ctx, "Loading...",
- "18pt Courier New", GameHandler.height ~/ 2, "white");
- }
- }
-
- void sceneRendererWelcome(CanvasRenderingContext2D ctx) {
- ctx.fillStyle = ctx.strokeStyle = "white";
- centerFillText(ctx, "Press SPACE or click to start", "18pt Courier New",
- GameHandler.height ~/ 2);
- fillText(ctx, "based on Javascript game by Kevin Roast",
- "10pt Courier New", 16, 624);
- }
-
- void sceneRendererInfo(CanvasRenderingContext2D ctx) {
- ctx.fillStyle = ctx.strokeStyle = "white";
- fillText(ctx, "How to play...", "14pt Courier New", 40, 320);
- fillText(ctx, "Arrow keys or tilt to rotate, thrust, shield. "
- "SPACE or touch to fire.",
- "14pt Courier New", 40, 350);
- fillText(ctx, "Pickup the glowing power-ups to enhance your ship.",
- "14pt Courier New", 40, 370);
- fillText(ctx, "Watch out for enemy saucers!", "14pt Courier New", 40, 390);
- }
-
- void sceneRendererScores(CanvasRenderingContext2D ctx) {
- ctx.fillStyle = ctx.strokeStyle = "white";
- centerFillText(ctx, "High Score", "18pt Courier New", 320);
- var sscore = this.game.highscore.toString();
- // pad with zeros
- for (var i=0, j=8-sscore.length; i<j; i++) {
- sscore = "0$sscore";
- }
- centerFillText(ctx, sscore, "18pt Courier New", 350);
- }
-
- /** Callback from image preloader when all images are ready */
- void ready() {
- imagesLoaded = true;
- }
-
- /**
- * Render the a text string in a pulsing x-sine y-cos wave pattern
- * The multiplier for the sinewave is modulated over time
- */
- void sineText(CanvasRenderingContext2D ctx, String txt, int xpos, int ypos) {
- mult += multIncrement;
- if (mult > 1024.0) {
- multIncrement = -multIncrement;
- } else if (this.mult < 128.0) {
- multIncrement = -multIncrement;
- }
- var offset = sine;
- for (var i = 0; i < txt.length; i++) {
- var y = ypos + ((Math.sin(offset) * RAD) * mult).toInt();
- var x = xpos + ((Math.cos(offset++) * RAD) * (mult * 0.5)).toInt();
- fillText(ctx, txt[i], "36pt Courier New", x + i * 30, y, "white");
- }
- sine += 0.075;
- }
-
- bool onKeyDownHandler(int keyCode) {
- log("In onKeyDownHandler, AttractorScene");
- switch (keyCode) {
- case Key.SPACE:
- if (imagesLoaded) {
- start = true;
- }
- return true;
- case Key.ESC:
- GameHandler.togglePause();
- return true;
- }
- return false;
- }
-
- bool onMouseDownHandler(e) {
- if (imagesLoaded) {
- start = true;
- }
- return true;
- }
-}
-
-/**
- * An actor representing a transient effect in the game world. An effect is
- * nothing more than a special graphic that does not play any direct part in
- * the game and does not interact with any other objects. It automatically
- * expires after a set lifespan, generally the rendering of the effect is
- * based on the remaining lifespan.
- */
-class EffectActor extends Actor {
- int lifespan; // in msec.
- int effectStart; // start time
-
- EffectActor(Vector position , Vector velocity, [this.lifespan = 0])
- : super(position, velocity) {
- effectStart = frameStart;
- }
-
- bool expired() => (frameStart - effectStart > lifespan);
-
- /**
- * Helper for an effect to return the value multiplied by the ratio of the
- * remaining lifespan of the effect.
- */
- double effectValue(double val) {
- var result = val - (val * (frameStart - effectStart)) / lifespan;
- return Math.max(0.0, Math.min(val, result));
- }
-}
-
-/** Text indicator effect actor class. */
-class TextIndicator extends EffectActor {
- int fadeLength;
- int textSize;
- String msg;
- String color;
-
- TextIndicator(Vector position, Vector velocity, this.msg,
- [this.textSize = 12, this.color = "white",
- int fl = 500]) :
- super(position, velocity, fl), fadeLength = fl;
-
- const DEFAULT_FADE_LENGTH = 500;
-
-
- void onRender(CanvasRenderingContext2D ctx) {
- // Fade out alpha.
- ctx.save();
- ctx.globalAlpha = effectValue(1.0);
- fillText(ctx, msg, "${textSize}pt Courier New",
- position.x, position.y, color);
- ctx.restore();
- }
-}
-
-/** Score indicator effect actor class. */
-class ScoreIndicator extends TextIndicator {
- ScoreIndicator(Vector position, Vector velocity, int score,
- [int textSize = 12, String prefix = '', String color = "white",
- int fadeLength = 500]) :
- super(position, velocity, '${prefix.length > 0 ? "$prefix " : ""}${score}',
- textSize, color, fadeLength);
-}
-
-/** Power up collectable. */
-class PowerUp extends EffectActor {
- PowerUp(Vector position, Vector velocity)
- : super(position, velocity);
-
- const RADIUS = 8;
- int pulse = 128;
- int pulseinc = 5;
-
- void onRender(CanvasRenderingContext2D ctx) {
- ctx.save();
- ctx.globalAlpha = 0.75;
- var col = "rgb(255,${pulse.toString()},0)";
- ctx.fillStyle = col;
- ctx.strokeStyle = "rgb(255,255,128)";
- ctx.beginPath();
- ctx.arc(position.x, position.y, RADIUS, 0, TWOPI, true);
- ctx.closePath();
- ctx.fill();
- ctx.stroke();
- ctx.restore();
- pulse += pulseinc;
- if (pulse > 255){
- pulse = 256 - pulseinc;
- pulseinc =- pulseinc;
- } else if (pulse < 0) {
- pulse = 0 - pulseinc;
- pulseinc =- pulseinc;
- }
- }
-
- get radius => RADIUS;
-
- void collected(AsteroidsMain game, Player player, GameScene scene) {
- // Randomly select a powerup to apply.
- var message = null;
- var n, m, enemy, pos;
- switch (randomInt(0, 9)) {
- case 0:
- case 1:
- message = "Energy Boost!";
- player.energy += player.ENERGY_INIT / 2;
- if (player.energy > player.ENERGY_INIT) {
- player.energy = player.ENERGY_INIT;
- }
- break;
-
- case 2:
- message = "Fire When Shielded!";
- player.fireWhenShield = true;
- break;
-
- case 3:
- message = "Extra Life!";
- game.lives++;
- break;
-
- case 4:
- message = "Slow Down Asteroids!";
- m = scene.enemies.length;
- for (n = 0; n < m; n++) {
- enemy = scene.enemies[n];
- if (enemy is Asteroid) {
- enemy.velocity.scale(0.66);
- }
- }
- break;
-
- case 5:
- message = "Smart Bomb!";
-
- var effectRad = 96;
-
- // Add a BIG explosion actor at the smart bomb weapon position
- // and vector.
- var boom = new Explosion(position.clone(),
- velocity.nscale(0.5), effectRad / 8);
- scene.effects.add(boom);
-
- // Test circle intersection with each enemy actor.
- // We check the enemy list length each iteration to catch baby asteroids
- // this is a fully fledged smart bomb after all!
- pos = position;
- for (n = 0; n < scene.enemies.length; n++) {
- enemy = scene.enemies[n];
-
- // Test the distance against the two radius combined.
- if (pos.distance(enemy.position) <= effectRad + enemy.radius) {
- // Intersection detected!
- enemy.hit(-1);
- scene.generatePowerUp(enemy);
- scene.destroyEnemy(enemy, velocity, true);
- }
- }
- break;
-
- case 6:
- message = "Twin Cannons!";
- player.primaryWeapons["main"] = new TwinCannonsWeapon(player);
- break;
-
- case 7:
- message = "Spray Cannons!";
- player.primaryWeapons["main"] = new VSprayCannonsWeapon(player);
- break;
-
- case 8:
- message = "Rear Gun!";
- player.primaryWeapons["rear"] = new RearGunWeapon(player);
- break;
-
- case 9:
- message = "Side Guns!";
- player.primaryWeapons["side"] = new SideGunWeapon(player);
- break;
- }
-
- if (message != null) {
- // Generate a effect indicator at the destroyed enemy position.
- var vec = new Vector(0.0, -1.5);
- var effect = new TextIndicator(
- new Vector(position.x, position.y - RADIUS), vec,
- message, null, null, 700);
- scene.effects.add(effect);
- }
- }
-}
-/**
- * This is the common base class of actors that can be hit and destroyed by
- * player bullets. It supports a hit() method which should return true when
- * the enemy object should be removed from play.
- */
-class EnemyActor extends SpriteActor {
- EnemyActor(Vector position, Vector velocity, this.size)
- : super(position, velocity);
-
- bool alive = true;
-
- /** Size - values from 1-4 are valid for asteroids, 0-1 for ships. */
- int size;
-
- bool expired() => !alive;
-
- bool hit(num force) {
- alive = false;
- return true;
- }
-}
-
-/**
- * Asteroid actor class.
- */
-class Asteroid extends EnemyActor {
- Asteroid(Vector position, Vector velocity, int size, [this.type])
- : super(position, velocity, size) {
- health = size;
-
- // Randomly select an asteroid image bitmap.
- if (type == null) {
- type = randomInt(1, 4);
- }
- animImage = _asteroidImgs[type-1];
-
- // Rrandomly setup animation speed and direction.
- animForward = (random() < 0.5);
- animSpeed = 0.3 + random() * 0.5;
- animLength = ANIMATION_LENGTH;
- rotation = randomInt(0, 180);
- rotationSpeed = (random() - 0.5) / 30;
- }
-
- const ANIMATION_LENGTH = 180;
-
- /** Asteroid graphic type i.e. which bitmap it is drawn from. */
- int type;
-
- /** Asteroid health before it's destroyed. */
- num health = 0;
-
- /** Retro graphics mode rotation orientation and speed. */
- int rotation = 0;
- double rotationSpeed = 0.0;
-
- /** Asteroid rendering method. */
- void onRender(CanvasRenderingContext2D ctx) {
- var rad = size * 8;
- ctx.save();
- // Render asteroid graphic bitmap. The bitmap is rendered slightly large
- // than the radius as the raytraced asteroid graphics do not quite touch
- // the edges of the 64x64 sprite - this improves perceived collision
- // detection.
- renderSprite(ctx, position.x - rad - 2, position.y - rad - 2, (rad * 2)+4);
- ctx.restore();
- }
-
- get radius => size * 8;
-
- bool hit(num force) {
- if (force != -1) {
- health -= force;
- } else {
- // instant kill
- health = 0;
- }
- return !(alive = (health > 0));
- }
-}
-
-/** Enemy Ship actor class. */
-class EnemyShip extends EnemyActor {
-
- get radius => _radius;
-
- EnemyShip(GameScene scene, int size)
- : super(null, null, size) {
- // Small ship, alter settings slightly.
- if (size == 1) {
- BULLET_RECHARGE_MS = 1300;
- _radius = 8;
- } else {
- _radius = 16;
- }
-
- // Randomly setup enemy initial position and vector
- // ensure the enemy starts in the opposite quadrant to the player.
- var p, v;
- if (scene.player.position.x < canvas_width / 2) {
- // Player on left of the screen.
- if (scene.player.position.y < canvas_height / 2) {
- // Player in top left of the screen.
- position = new Vector(canvas_width-48, canvas_height-48);
- } else {
- // Player in bottom left of the screen.
- position = new Vector(canvas_width-48, 48);
- }
- velocity = new Vector(-(random() + 0.25 + size * 0.75),
- random() + 0.25 + size * 0.75);
- } else {
- // Player on right of the screen.
- if (scene.player.position.y < canvas_height / 2) {
- // Player in top right of the screen.
- position = new Vector(0, canvas_height-48);
- } else {
- // Player in bottom right of the screen.
- position = new Vector(0, 48);
- }
- velocity = new Vector(random() + 0.25 + size * 0.75,
- random() + 0.25 + size * 0.75);
- }
-
- // Setup SpriteActor values.
- animImage = _enemyshipImg;
- animLength = SHIP_ANIM_LENGTH;
- }
-
- const SHIP_ANIM_LENGTH = 90;
- int _radius;
- int BULLET_RECHARGE_MS = 1800;
-
-
- /** True if ship alive, false if ready for expiration. */
- bool alive = true;
-
- /** Bullet fire recharging counter. */
- int bulletRecharge = 0;
-
- void onUpdate(GameScene scene) {
- // change enemy direction randomly
- if (size == 0) {
- if (random() < 0.01) {
- velocity.y = -(velocity.y + (0.25 - (random()/2)));
- }
- } else {
- if (random() < 0.02) {
- velocity.y = -(velocity.y + (0.5 - random()));
- }
- }
-
- // regular fire a bullet at the player
- if (frameStart - bulletRecharge >
- BULLET_RECHARGE_MS && scene.player.alive) {
- // ok, update last fired time and we can now generate a bullet
- bulletRecharge = frameStart;
-
- // generate a vector pointed at the player
- // by calculating a vector between the player and enemy positions
- var v = scene.player.position.clone().sub(position);
- // scale resulting vector down to bullet vector size
- var scale = (size == 0 ? 3.0 : 3.5) / v.length();
- v.x *= scale;
- v.y *= scale;
- // slightly randomize the direction (big ship is less accurate also)
- v.x += (size == 0 ? (random() * 2.0 - 1.0) : (random() - 0.5));
- v.y += (size == 0 ? (random() * 2.0 - 1.0) : (random() - 0.5));
- // - could add the enemy motion vector for correct momentum
- // - but this leads to slow bullets firing back from dir of travel
- // - so pretend that enemies are clever enough to account for this...
- //v.add(this.vector);
-
- var bullet = new EnemyBullet(position.clone(), v);
- scene.enemyBullets.add(bullet);
- //soundManager.play('enemy_bomb');
- }
- }
-
- /** Enemy rendering method. */
- void onRender(CanvasRenderingContext2D ctx) {
- // render enemy graphic bitmap
- var rad = radius + 2;
- renderSprite(ctx, position.x - rad, position.y - rad, rad * 2);
- }
-
- /** Enemy hit by a bullet; return true if destroyed, false otherwise. */
- bool hit(num force) {
- alive = false;
- return true;
- }
-
- bool expired() {
- return !alive;
- }
-}
-
-class GameCompleted extends Scene {
- AsteroidsMain game;
- var player;
-
- GameCompleted(this.game)
- : super(false) {
- interval = new Interval("CONGRATULATIONS!", intervalRenderer);
- player = game.player;
- }
-
- bool isComplete() => true;
-
- void intervalRenderer(Interval interval, CanvasRenderingContext2D ctx) {
- if (interval.framecounter++ == 0) {
- if (game.score == game.highscore) {
- // save new high score to HTML5 local storage
- if (window.localStorage) {
- window.localStorage[SCOREDBKEY] = game.score;
- }
- }
- }
- if (interval.framecounter < 1000) {
- fillText(ctx, interval.label, "18pt Courier New",
- GameHandler.width ~/ 2 - 96, GameHandler.height ~/ 2 - 32, "white");
- fillText(ctx, "Score: ${game.score}", "14pt Courier New",
- GameHandler.width ~/ 2 - 64, GameHandler.height ~/ 2, "white");
- if (game.score == game.highscore) {
- fillText(ctx, "New High Score!", "14pt Courier New",
- GameHandler.width ~/ 2 - 64,
- GameHandler.height ~/ 2 + 24, "white");
- }
- } else {
- interval.complete = true;
- }
- }
-}
-
-/**
- * Game Handler.
- *
- * Singleton instance responsible for managing the main game loop and
- * maintaining a few global references such as the canvas and frame counters.
- */
-class GameHandler {
- /**
- * The single Game.Main derived instance
- */
- static GameMain game = null;
-
- static bool paused = false;
- static CanvasElement canvas = null;
- static int width = 0;
- static int height = 0;
- static int frameCount = 0;
-
- /** Frame multiplier - i.e. against the ideal fps. */
- static double frameMultiplier = 1.0;
-
- /** Last frame start time in ms. */
- static int frameStart = 0;
-
- /** Debugging output. */
- static int maxfps = 0;
-
- /** Ideal FPS constant. */
- static const FPSMS = 1000 / 60;
-
- static Prerenderer bitmaps;
-
- /** Init function called once by your window.onload handler. */
- static void init(c) {
- canvas = c;
- width = canvas.width;
- height = canvas.height;
- log("Init GameMain($c,$width,$height)");
- }
-
- /**
- * Game start method - begins the main game loop.
- * Pass in the object that represent the game to execute.
- */
- static void start(GameMain g) {
- game = g;
- frameStart = new DateTime.now().millisecondsSinceEpoch;
- log("Doing first frame");
- game.frame();
- }
-
- /** Called each frame by the main game loop unless paused. */
- static void doFrame(_) {
- log("Doing next frame");
- game.frame();
- }
-
- static void togglePause() {
- if (paused) {
- paused = false;
- frameStart = new DateTime.now().millisecondsSinceEpoch;
- game.frame();
- } else {
- paused = true;
- }
- }
-
- static bool onAccelerometer(double x, double y, double z) {
- return game == null ? true : game.onAccelerometer(x, y, z);
- }
-}
-
-bool onAccelerometer(double x, double y, double z) {
- return GameHandler.onAccelerometer(x, y, z);
-}
-
-/** Game main loop class. */
-class GameMain {
-
- GameMain() {
- var me = this;
-
- document.onKeyDown.listen((KeyboardEvent event) {
- var keyCode = event.keyCode;
-
- log("In document.onKeyDown($keyCode)");
- if (me.sceneIndex != -1) {
- if (me.scenes[me.sceneIndex].onKeyDownHandler(keyCode) != null) {
- // if the key is handled, prevent any further events
- if (event != null) {
- event.preventDefault();
- event.stopPropagation();
- }
- }
- }
- });
-
- document.onKeyUp.listen((KeyboardEvent event) {
- var keyCode = event.keyCode;
- if (me.sceneIndex != -1) {
- if (me.scenes[me.sceneIndex].onKeyUpHandler(keyCode) != null) {
- // if the key is handled, prevent any further events
- if (event != null) {
- event.preventDefault();
- event.stopPropagation();
- }
- }
- }
- });
-
- document.onMouseDown.listen((MouseEvent event) {
- if (me.sceneIndex != -1) {
- if (me.scenes[me.sceneIndex].onMouseDownHandler(event) != null) {
- // if the event is handled, prevent any further events
- if (event != null) {
- event.preventDefault();
- event.stopPropagation();
- }
- }
- }
- });
-
- document.onMouseUp.listen((MouseEvent event) {
- if (me.sceneIndex != -1) {
- if (me.scenes[me.sceneIndex].onMouseUpHandler(event) != null) {
- // if the event is handled, prevent any further events
- if (event != null) {
- event.preventDefault();
- event.stopPropagation();
- }
- }
- }
- });
-
- }
-
- List scenes = [];
- Scene startScene = null;
- Scene endScene = null;
- Scene currentScene = null;
- int sceneIndex = -1;
- var interval = null;
- int totalFrames = 0;
-
- bool onAccelerometer(double x, double y, double z) {
- if (currentScene != null) {
- return currentScene.onAccelerometer(x, y, z);
- }
- return true;
- }
- /**
- * Game frame execute method - called by anim handler timeout
- */
- void frame() {
- var frameStart = new DateTime.now().millisecondsSinceEpoch;
-
- // Calculate scene transition and current scene.
- if (currentScene == null) {
- // Set to scene zero (game init).
- currentScene = scenes[sceneIndex = 0];
- currentScene.onInitScene();
- } else if (isGameOver()) {
- sceneIndex = -1;
- currentScene = endScene;
- currentScene.onInitScene();
- }
-
- if ((currentScene.interval == null ||
- currentScene.interval.complete) && currentScene.isComplete()) {
- if (++sceneIndex >= scenes.length){
- sceneIndex = 0;
- }
- currentScene = scenes[sceneIndex];
- currentScene.onInitScene();
- }
-
- var ctx = GameHandler.canvas.getContext('2d');
-
- // Rrender the game and current scene.
- ctx.save();
- if (currentScene.interval == null || currentScene.interval.complete) {
- currentScene.onBeforeRenderScene();
- onRenderGame(ctx);
- currentScene.onRenderScene(ctx);
- } else {
- onRenderGame(ctx);
- currentScene.interval.intervalRenderer(currentScene.interval, ctx);
- }
- ctx.restore();
-
- GameHandler.frameCount++;
-
- // Calculate frame total time interval and frame multiplier required
- // for smooth animation.
-
- // Time since last frame.
- var frameInterval = frameStart - GameHandler.frameStart;
- if (frameInterval == 0) frameInterval = 1;
- if (GameHandler.frameCount % 16 == 0) { // Update fps every 16 frames
- GameHandler.maxfps = (1000 / frameInterval).floor().toInt();
- }
- GameHandler.frameMultiplier = frameInterval.toDouble() / GameHandler.FPSMS;
-
- GameHandler.frameStart = frameStart;
-
- if (!GameHandler.paused) {
- window.requestAnimationFrame(GameHandler.doFrame);
- }
- if ((++totalFrames % 600) == 0) {
- log('${totalFrames} frames; multiplier ${GameHandler.frameMultiplier}');
- }
- }
-
- void onRenderGame(CanvasRenderingContext2D ctx) {}
-
- bool isGameOver() => false;
-}
-
-class AsteroidsMain extends GameMain {
-
- AsteroidsMain() : super() {
- var attractorScene = new AttractorScene(this);
-
- // get the images graphics loading
- var loader = new Preloader();
- loader.addImage(_playerImg, 'player.png');
- loader.addImage(_asteroidImgs[0], 'asteroid1.png');
- loader.addImage(_asteroidImgs[1], 'asteroid2.png');
- loader.addImage(_asteroidImgs[2], 'asteroid3.png');
- loader.addImage(_asteroidImgs[3], 'asteroid4.png');
- loader.addImage(_shieldImg, 'shield.png');
- loader.addImage(_enemyshipImg, 'enemyship1.png');
-
- // The attactor scene is displayed first and responsible for allowing the
- // player to start the game once all images have been loaded.
- loader.onLoadCallback(() {
- attractorScene.ready();
- });
-
- // Generate the single player actor - available across all scenes.
- player = new Player(
- new Vector(GameHandler.width / 2, GameHandler.height / 2),
- new Vector(0.0, 0.0),
- 0.0);
-
- scenes.add(attractorScene);
-
- for (var i = 0; i < 12; i++){
- var level = new GameScene(this, i+1);
- scenes.add(level);
- }
-
- scenes.add(new GameCompleted(this));
-
- // Set special end scene member value to a Game Over scene.
- endScene = new GameOverScene(this);
-
- if (window.localStorage.containsKey(SCOREDBKEY)) {
- highscore = int.parse(window.localStorage[SCOREDBKEY]);
- }
- // Perform prerender steps - create some bitmap graphics to use later.
- GameHandler.bitmaps = new Prerenderer();
- GameHandler.bitmaps.execute();
- }
-
- Player player = null;
- int lives = 0;
- int score = 0;
- int highscore = 0;
- /** Background scrolling bitmap x position */
- double backgroundX = 0.0;
- /** Background starfield star list */
- List starfield = [];
-
- void onRenderGame(CanvasRenderingContext2D ctx) {
- // Setup canvas for a render pass and apply background
- // draw a scrolling background image.
- var w = GameHandler.width;
- var h = GameHandler.height;
- //var sourceRect = new Rect(backgroundX, 0, w, h);
- //var destRect = new Rect(0, 0, w, h);
- //ctx.drawImageToRect(_backgroundImg, destRect,
- // sourceRect:sourceRect);
- ctx.drawImageScaledFromSource(_backgroundImg,
- backgroundX, 0, w, h, 0, 0, w, h);
-
- backgroundX += (GameHandler.frameMultiplier / 4.0);
- if (backgroundX >= _backgroundImg.width / 2) {
- backgroundX -= _backgroundImg.width / 2;
- }
- ctx.shadowBlur = 0;
- }
-
- bool isGameOver() {
- if (currentScene is GameScene) {
- var gs = currentScene as GameScene;
- return (lives == 0 && gs.effects != null && gs.effects.length == 0);
- }
- return false;
- }
-
- /**
- * Update an actor position using its current velocity vector.
- * Scale the vector by the frame multiplier - this is used to ensure
- * all actors move the same distance over time regardles of framerate.
- * Also handle traversing out of the coordinate space and back again.
- */
- void updateActorPosition(Actor actor) {
- actor.position.add(actor.velocity.nscale(GameHandler.frameMultiplier));
- actor.position.wrap(0, GameHandler.width - 1, 0, GameHandler.height - 1);
- }
-}
-
-class GameOverScene extends Scene {
- var game, player;
-
- GameOverScene(this.game) :
- super(false) {
- interval = new Interval("GAME OVER", intervalRenderer);
- player = game.player;
- }
-
- bool isComplete() => true;
-
- void intervalRenderer(Interval interval, CanvasRenderingContext2D ctx) {
- if (interval.framecounter++ == 0) {
- if (game.score == game.highscore) {
- window.localStorage[SCOREDBKEY] = game.score.toString();
- }
- }
- if (interval.framecounter < 300) {
- fillText(ctx, interval.label, "18pt Courier New",
- GameHandler.width * 0.5 - 64, GameHandler.height*0.5 - 32, "white");
- fillText(ctx, "Score: ${game.score}", "14pt Courier New",
- GameHandler.width * 0.5 - 64, GameHandler.height*0.5, "white");
- if (game.score == game.highscore) {
- fillText(ctx, "New High Score!", "14pt Courier New",
- GameHandler.width * 0.5 - 64, GameHandler.height*0.5 + 24, "white");
- }
- } else {
- interval.complete = true;
- }
- }
-}
-
-class GameScene extends Scene {
- AsteroidsMain game;
- int wave;
- var player;
- List actors = null;
- List playerBullets = null;
- List enemies = null;
- List enemyBullets = null;
- List effects = null;
- List collectables = null;
- int enemyShipCount = 0;
- int enemyShipAdded = 0;
- int scoredisplay = 0;
- bool skipLevel = false;
-
- Input input;
-
- GameScene(this.game, this.wave)
- : super(true) {
- interval = new Interval("Wave ${wave}", intervalRenderer);
- player = game.player;
- input = new Input();
- }
-
- void onInitScene() {
- // Generate the actors and add the actor sub-lists to the main actor list.
- actors = [];
- enemies = [];
- actors.add(enemies);
- actors.add(playerBullets = []);
- actors.add(enemyBullets = []);
- actors.add(effects = []);
- actors.add(collectables = []);
-
- // Reset player ready for game restart.
- resetPlayerActor(wave != 1);
-
- // Randomly generate some asteroids.
- var factor = 1.0 + ((wave - 1) * 0.075);
- for (var i=1, j=(4 + wave); i < j; i++) {
- enemies.add(generateAsteroid(factor));
- }
-
- // Reset enemy ship count and last enemy added time.
- enemyShipAdded = GameHandler.frameStart;
- enemyShipCount = 0;
-
- // Reset interval flag.
- interval.reset();
- skipLevel = false;
- }
-
- /** Restore the player to the game - reseting position etc. */
- void resetPlayerActor(bool persistPowerUps) {
- actors.add([player]);
-
- // Reset the player position.
- player.position.x = GameHandler.width / 2;
- player.position.y = GameHandler.height / 2;
- player.velocity.x = 0.0;
- player.velocity.y = 0.0;
- player.heading = 0.0;
- player.reset(persistPowerUps);
-
- // Reset keyboard input values.
- input.reset();
- }
-
- /** Scene before rendering event handler. */
- void onBeforeRenderScene() {
- // Handle key input.
- if (input.left) {
- // Rotate anti-clockwise.
- player.heading -= 4 * GameHandler.frameMultiplier;
- }
- if (input.right) {
- // Rotate clockwise.
- player.heading += 4 * GameHandler.frameMultiplier;
- }
- if (input.thrust) {
- player.thrust();
- }
- if (input.shield) {
- if (!player.expired()) {
- player.activateShield();
- }
- }
- if (input.fireA) {
- player.firePrimary(playerBullets);
- }
- if (input.fireB) {
- player.fireSecondary(playerBullets);
- }
-
- // Add an enemy every N frames (depending on wave factor).
- // Later waves can have 2 ships on screen - earlier waves have one.
- if (enemyShipCount <= (wave < 5 ? 0 : 1) &&
- GameHandler.frameStart - enemyShipAdded > (20000 - (wave * 1024))) {
- enemies.add(new EnemyShip(this, (wave < 3 ? 0 : randomInt(0, 1))));
- enemyShipCount++;
- enemyShipAdded = GameHandler.frameStart;
- }
-
- // Update all actors using their current vector.
- updateActors();
- }
-
- /** Scene rendering event handler */
- void onRenderScene(CanvasRenderingContext2D ctx) {
- renderActors(ctx);
-
- if (Debug['collisionRadius']) {
- renderCollisionRadius(ctx);
- }
-
- // Render info overlay graphics.
- renderOverlay(ctx);
-
- // Detect bullet collisions.
- collisionDetectBullets();
-
- // Detect player collision with asteroids etc.
- if (!player.expired()) {
- collisionDetectPlayer();
- } else {
- // If the player died, then respawn after a short delay and
- // ensure that they do not instantly collide with an enemy.
- if (GameHandler.frameStart - player.killedOn > 3000) {
- // Perform a test to check no ememy is close to the player.
- var tooClose = false;
- var playerPos =
- new Vector(GameHandler.width * 0.5, GameHandler.height * 0.5);
- for (var i=0, j=this.enemies.length; i<j; i++) {
- var enemy = this.enemies[i];
- if (playerPos.distance(enemy.position) < 80) {
- tooClose = true;
- break;
- }
- }
- if (tooClose == false) {
- resetPlayerActor(false);
- }
- }
- }
- }
-
- bool isComplete() =>
- (skipLevel || (enemies.length == 0 && effects.length == 0));
-
- void intervalRenderer(Interval interval, CanvasRenderingContext2D ctx) {
- if (interval.framecounter++ < 100) {
- fillText(ctx, interval.label, "18pt Courier New",
- GameHandler.width*0.5 - 48, GameHandler.height*0.5 - 8, "white");
- } else {
- interval.complete = true;
- }
- }
-
- bool onAccelerometer(double x, double y, double z) {
- if (input != null) {
- input.shield =(x > 2.0);
- input.thrust = (x < -1.0);
- input.left = (y < -1.5);
- input.right = (y > 1.5);
- }
- return true;
- }
-
- bool onMouseDownHandler(e) {
- input.fireA = input.fireB = false;
- if (e.clientX < GameHandler.width / 3) input.fireB = true;
- else if (e.clientX > 2 * GameHandler.width / 3) input.fireA = true;
- return true;
- }
-
- bool onMouseUpHandler(e) {
- input.fireA = input.fireB = false;
- return true;
- }
-
- bool onKeyDownHandler(int keyCode) {
- log("In onKeyDownHandler, GameScene");
- switch (keyCode) {
- // Note: GLUT doesn't send key up events,
- // so the emulator sends key events as down/up pairs,
- // which is not what we want. So we have some special
- // numeric key handlers here that are distinct for
- // up and down to support use with GLUT.
- case 52: // '4':
- case Key.LEFT:
- input.left = true;
- return true;
- case 54: // '6'
- case Key.RIGHT:
- input.right = true;
- return true;
- case 56: // '8'
- case Key.UP:
- input.thrust = true;
- return true;
- case 50: // '2'
- case Key.DOWN:
- case Key.SHIFT:
- input.shield = true;
- return true;
- case 48: // '0'
- case Key.SPACE:
- input.fireA = true;
- return true;
- case Key.Z:
- input.fireB = true;
- return true;
-
- case Key.A:
- if (Debug['enabled']) {
- // generate an asteroid
- enemies.add(generateAsteroid(1));
- return true;
- }
- break;
-
- case Key.G:
- if (Debug['enabled']) {
- glowEffectOn = !glowEffectOn;
- return true;
- }
- break;
-
- case Key.L:
- if (Debug['enabled']) {
- skipLevel = true;
- return true;
- }
- break;
-
- case Key.E:
- if (Debug['enabled']) {
- enemies.add(new EnemyShip(this, randomInt(0, 1)));
- return true;
- }
- break;
-
- case Key.ESC:
- GameHandler.togglePause();
- return true;
- }
- return false;
- }
-
- bool onKeyUpHandler(int keyCode) {
- switch (keyCode) {
- case 53: // '5'
- input.left = false;
- input.right = false;
- input.thrust = false;
- input.shield = false;
- input.fireA = false;
- input.fireB = false;
- return true;
-
- case Key.LEFT:
- input.left = false;
- return true;
- case Key.RIGHT:
- input.right = false;
- return true;
- case Key.UP:
- input.thrust = false;
- return true;
- case Key.DOWN:
- case Key.SHIFT:
- input.shield = false;
- return true;
- case Key.SPACE:
- input.fireA = false;
- return true;
- case Key.Z:
- input.fireB = false;
- return true;
- }
- return false;
- }
-
- /**
- * Randomly generate a new large asteroid. Ensures the asteroid is not
- * generated too close to the player position!
- */
- Asteroid generateAsteroid(num speedFactor) {
- while (true){
- // perform a test to check it is not too close to the player
- var apos = new Vector(random()*GameHandler.width,
- random()*GameHandler.height);
- if (player.position.distance(apos) > 125) {
- var vec = new Vector( ((random()*2)-1)*speedFactor,
- ((random()*2)-1)*speedFactor );
- return new Asteroid(apos, vec, 4);
- }
- }
- }
-
- /** Update the actors position based on current vectors and expiration. */
- void updateActors() {
- for (var i = 0, j = this.actors.length; i < j; i++) {
- var actorList = this.actors[i];
-
- for (var n = 0; n < actorList.length; n++) {
- var actor = actorList[n];
-
- // call onUpdate() event for each actor
- actor.onUpdate(this);
-
- // expiration test first
- if (actor.expired()) {
- actorList.removeAt(n);
- } else {
- game.updateActorPosition(actor);
- }
- }
- }
- }
-
- /**
- * Perform the operation needed to destory the player.
- * Mark as killed as reduce lives, explosion effect and play sound.
- */
- void destroyPlayer() {
- // Player destroyed by enemy bullet - remove from play.
- player.kill();
- game.lives--;
- var boom =
- new PlayerExplosion(player.position.clone(), player.velocity.clone());
- effects.add(boom);
- soundManager.play('big_boom');
- }
-
- /**
- * Detect player collisions with various actor classes
- * including Asteroids, Enemies, bullets and collectables
- */
- void collisionDetectPlayer() {
- var playerRadius = player.radius;
- var playerPos = player.position;
-
- // Test circle intersection with each asteroid/enemy ship.
- for (var n = 0, m = enemies.length; n < m; n++) {
- var enemy = enemies[n];
-
- // Calculate distance between the two circles.
- if (playerPos.distance(enemy.position) <= playerRadius + enemy.radius) {
- // Collision detected.
- if (player.isShieldActive()) {
- // Remove thrust from the player vector due to collision.
- player.velocity.scale(0.75);
-
- // Destroy the enemy - the player is invincible with shield up!
- enemy.hit(-1);
- destroyEnemy(enemy, player.velocity, true);
- } else if (!Debug['invincible']) {
- destroyPlayer();
- }
- }
- }
-
- // Test intersection with each enemy bullet.
- for (var i = 0; i < enemyBullets.length; i++) {
- var bullet = enemyBullets[i];
-
- // Calculate distance between the two circles.
- if (playerPos.distance(bullet.position) <= playerRadius + bullet.radius) {
- // Collision detected.
- if (player.isShieldActive()) {
- // Remove this bullet from the actor list as it has been destroyed.
- enemyBullets.removeAt(i);
- } else if (!Debug['invincible']) {
- destroyPlayer();
- }
- }
- }
-
- // Test intersection with each collectable.
- for (var i = 0; i < collectables.length; i++) {
- var item = collectables[i];
-
- // Calculate distance between the two circles.
- if (playerPos.distance(item.position) <= playerRadius + item.radius) {
- // Collision detected - remove item from play and activate it.
- collectables.removeAt(i);
- item.collected(game, player, this);
-
- soundManager.play('powerup');
- }
- }
- }
-
- /** Detect bullet collisions with asteroids and enemy actors. */
- void collisionDetectBullets() {
- var i;
- // Collision detect player bullets with asteroids and enemies.
- for (i = 0; i < playerBullets.length; i++) {
- var bullet = playerBullets[i];
- var bulletRadius = bullet.radius;
- var bulletPos = bullet.position;
-
- // Test circle intersection with each enemy actor.
- var n, m = enemies.length, z;
- for (n = 0; n < m; n++) {
- var enemy = enemies[n];
-
- // Test the distance against the two radius combined.
- if (bulletPos.distance(enemy.position) <= bulletRadius + enemy.radius){
- // intersection detected!
-
- // Test for area effect bomb weapon.
- var effectRad = bullet.effectRadius;
- if (effectRad == 0) {
- // Impact the enemy with the bullet.
- if (enemy.hit(bullet.power)) {
- // Destroy the enemy under the bullet.
- destroyEnemy(enemy, bullet.velocity, true);
- // Randomly release a power up.
- generatePowerUp(enemy);
- } else {
- // Add a bullet impact particle effect to show the hit.
- var effect =
- new PlayerBulletImpact(bullet.position, bullet.velocity);
- effects.add(effect);
- }
- } else {
- // Inform enemy it has been hit by a instant kill weapon.
- enemy.hit(-1);
- generatePowerUp(enemy);
-
- // Add a big explosion actor at the area weapon position and vector.
- var comboCount = 1;
- var boom = new Explosion(
- bullet.position.clone(),
- bullet.velocity.nscale(0.5), 5);
- effects.add(boom);
-
- // Destroy the enemy.
- destroyEnemy(enemy, bullet.velocity, true);
-
- // Wipe out nearby enemies under the weapon effect radius
- // take the length of the enemy actor list here - so we don't
- // kill off -all- baby asteroids - so some elements of the original
- // survive.
- for (var x = 0, z = this.enemies.length, e; x < z; x++) {
- e = enemies[x];
-
- // test the distance against the two radius combined
- if (bulletPos.distance(e.position) <= effectRad + e.radius) {
- e.hit(-1);
- generatePowerUp(e);
- destroyEnemy(e, bullet.velocity, true);
- comboCount++;
- }
- }
-
- // Special score and indicator for "combo" detonation.
- if (comboCount > 4) {
- // Score bonus based on combo size.
- var inc = comboCount * 1000 * wave;
- game.score += inc;
-
- // Generate a special effect indicator at the destroyed
- // enemy position.
- var vec = new Vector(0, -3.0);
- var effect = new ScoreIndicator(
- new Vector(enemy.position.x,
- enemy.position.y - (enemy.size * 8)),
- vec.add(enemy.velocity.nscale(0.5)),
- inc, 16, 'COMBO X ${comboCount}', 'rgb(255,255,55)', 1000);
- effects.add(effect);
-
- // Generate a powerup to reward the player for the combo.
- generatePowerUp(enemy, true);
- }
- }
-
- // Remove this bullet from the actor list as it has been destroyed.
- playerBullets.removeAt(i);
- break;
- }
- }
- }
-
- // collision detect enemy bullets with asteroids
- for (i = 0; i < enemyBullets.length; i++) {
- var bullet = enemyBullets[i];
- var bulletRadius = bullet.radius;
- var bulletPos = bullet.position;
-
- // test circle intersection with each enemy actor
- var n, m = enemies.length, z;
- for (n = 0; n < m; n++) {
- var enemy = enemies[n];
-
- if (enemy is Asteroid) {
- if (bulletPos.distance(enemy.position) <=
- bulletRadius + enemy.radius) {
- // Impact the enemy with the bullet.
- if (enemy.hit(1)) {
- // Destroy the enemy under the bullet.
- destroyEnemy(enemy, bullet.velocity, false);
- } else {
- // Add a bullet impact particle effect to show the hit.
- var effect = new EnemyBulletImpact(bullet.position,
- bullet.velocity);
- effects.add(effect);
- }
-
- // Remove this bullet from the actor list as it has been destroyed.
- enemyBullets.removeAt(i);
- break;
- }
- }
- }
- }
- }
-
- /** Randomly generate a power up to reward the player */
- void generatePowerUp(EnemyActor enemy, [bool force = false]) {
- if (collectables.length < 5 &&
- (force || randomInt(0, ((enemy is Asteroid) ? 25 : 1)) == 0)) {
- // Apply a small random vector in the direction of travel
- // rotate by slightly randomized enemy heading.
- var vec = enemy.velocity.clone();
- var t = new Vector(0.0, -(random() * 2));
- t.rotate(enemy.velocity.theta() * (random() * Math.PI));
- vec.add(t);
-
- // Add a power up to the collectables list.
- collectables.add(new PowerUp(
- new Vector(enemy.position.x, enemy.position.y - (enemy.size * 8)),
- vec));
- }
- }
-
- /**
- * Blow up an enemy.
- *
- * An asteroid may generate new baby asteroids and leave an explosion
- * in the wake.
- *
- * Also applies the score for the destroyed item.
- *
- * @param enemy {Game.EnemyActor} The enemy to destory and add score for
- * @param parentVector {Vector} The vector of the item that hit the enemy
- * @param player {boolean} If true, the player was the destroyer
- */
- void destroyEnemy(EnemyActor enemy, Vector parentVector, player) {
- if (enemy is Asteroid) {
- soundManager.play('asteroid_boom${randomInt(1,4)}');
-
- // generate baby asteroids
- generateBabyAsteroids(enemy, parentVector);
-
- // add an explosion at the asteriod position and vector
- var boom = new AsteroidExplosion(
- enemy.position.clone(), enemy.velocity.clone(), enemy);
- effects.add(boom);
-
- if (player!= null) {
- // increment score based on asteroid size
- var inc = ((5 - enemy.size) * 4) * 100 * wave;
- game.score += inc;
-
- // generate a score effect indicator at the destroyed enemy position
- var vec = new Vector(0, -1.5).add(enemy.velocity.nscale(0.5));
- var effect = new ScoreIndicator(
- new Vector(enemy.position.x, enemy.position.y -
- (enemy.size * 8)), vec, inc);
- effects.add(effect);
- }
- } else if (enemy is EnemyShip) {
- soundManager.play('asteroid_boom1');
-
- // add an explosion at the enemy ship position and vector
- var boom = new EnemyExplosion(enemy.position.clone(),
- enemy.velocity.clone(), enemy);
- effects.add(boom);
-
- if (player != null) {
- // increment score based on asteroid size
- var inc = 2000 * wave * (enemy.size + 1);
- game.score += inc;
-
- // generate a score effect indicator at the destroyed enemy position
- var vec = new Vector(0, -1.5).add(enemy.velocity.nscale(0.5));
- var effect = new ScoreIndicator(
- new Vector(enemy.position.x, enemy.position.y - 16),
- vec, inc);
- effects.add(effect);
- }
-
- // decrement scene ship count
- enemyShipCount--;
- }
- }
-
- /**
- * Generate a number of baby asteroids from a detonated parent asteroid.
- * The number and size of the generated asteroids are based on the parent
- * size. Some of the momentum of the parent vector (e.g. impacting bullet)
- * is applied to the new asteroids.
- */
- void generateBabyAsteroids(Asteroid asteroid, Vector parentVector) {
- // generate some baby asteroid(s) if bigger than the minimum size
- if (asteroid.size > 1) {
- var xc=randomInt(asteroid.size ~/ 2, asteroid.size - 1);
- for (var x=0; x < xc; x++) {
- var babySize = randomInt(1, asteroid.size - 1);
-
- var vec = asteroid.velocity.clone();
-
- // apply a small random vector in the direction of travel
- var t = new Vector(0.0, -random());
-
- // rotate vector by asteroid current heading - slightly randomized
- t.rotate(asteroid.velocity.theta() * (random() * Math.PI));
- vec.add(t);
-
- // add the scaled parent vector - to give some momentum from the impact
- vec.add(parentVector.nscale(0.2));
-
- // create the asteroid - slightly offset from the centre of the old one
- var baby = new Asteroid(
- new Vector(asteroid.position.x + (random()*5)-2.5,
- asteroid.position.y + (random()*5)-2.5),
- vec, babySize, asteroid.type);
- enemies.add(baby);
- }
- }
- }
-
- /** Render each actor to the canvas. */
- void renderActors(CanvasRenderingContext2D ctx){
- for (var i = 0, j = actors.length; i < j; i++) {
- // walk each sub-list and call render on each object
- var actorList = actors[i];
-
- for (var n = actorList.length - 1; n >= 0; n--) {
- actorList[n].onRender(ctx);
- }
- }
- }
-
- /**
- * DEBUG - Render the radius of the collision detection circle around
- * each actor.
- */
- void renderCollisionRadius(CanvasRenderingContext2D ctx) {
- ctx.save();
- ctx.strokeStyle = "rgb(255,0,0)";
- ctx.lineWidth = 0.5;
- ctx.shadowBlur = 0;
-
- for (var i = 0, j = actors.length; i < j; i++) {
- var actorList = actors[i];
-
- for (var n = actorList.length - 1, actor; n >= 0; n--) {
- actor = actorList[n];
- if (actor.radius) {
- ctx.beginPath();
- ctx.arc(actor.position.x, actor.position.y, actor.radius, 0,
- TWOPI, true);
- ctx.closePath();
- ctx.stroke();
- }
- }
- }
- ctx.restore();
- }
-
- /**
- * Render player information HUD overlay graphics.
- *
- * @param ctx {object} Canvas rendering context
- */
- void renderOverlay(CanvasRenderingContext2D ctx) {
- ctx.save();
- ctx.shadowBlur = 0;
-
- // energy bar (100 pixels across, scaled down from player energy max)
- ctx.strokeStyle = "rgb(50,50,255)";
- ctx.strokeRect(4, 4, 101, 6);
- ctx.fillStyle = "rgb(100,100,255)";
- var energy = player.energy;
- if (energy > player.ENERGY_INIT) {
- // the shield is on for "free" briefly when he player respawns
- energy = player.ENERGY_INIT;
- }
- ctx.fillRect(5, 5, (energy / (player.ENERGY_INIT / 100)), 5);
-
- // lives indicator graphics
- for (var i=0; i<game.lives; i++) {
- drawScaledImage(ctx, _playerImg, 0, 0, 64,
- 350+(i*20), 0, 16);
-
- // score display - update towards the score in increments to animate it
- var score = game.score;
- var inc = (score - scoredisplay) ~/ 10;
- scoredisplay += inc;
- if (scoredisplay > score) {
- scoredisplay = score;
- }
- var sscore = scoredisplay.ceil().toString();
- // pad with zeros
- for (var i=0, j=8-sscore.length; i<j; i++) {
- sscore = "0${sscore}";
- }
- fillText(ctx, sscore, "12pt Courier New", 120, 12, "white");
-
- // high score
- // TODO: add method for incrementing score so this is not done here
- if (score > game.highscore) {
- game.highscore = score;
- }
- sscore = game.highscore.toString();
- // pad with zeros
- for (var i=0, j=8-sscore.length; i<j; i++) {
- sscore = "0${sscore}";
- }
- fillText(ctx, "HI: ${sscore}", "12pt Courier New", 220, 12, "white");
-
- // debug output
- if (Debug['fps']) {
- fillText(ctx, "FPS: ${GameHandler.maxfps}", "12pt Courier New",
- 0, GameHandler.height - 2, "lightblue");
- }
- }
- ctx.restore();
- }
-}
-
-class Interval {
- String label;
- Function intervalRenderer;
- int framecounter = 0;
- bool complete = false;
-
- Interval([this.label = null, this.intervalRenderer = null]);
-
- void reset() {
- framecounter = 0;
- complete = false;
- }
-}
-
-class Bullet extends ShortLivedActor {
-
- Bullet(Vector position, Vector velocity,
- [this.heading = 0.0, int lifespan = 1300])
- : super(position, velocity, lifespan) {
- }
-
- const BULLET_WIDTH = 2;
- const BULLET_HEIGHT = 6;
- const FADE_LENGTH = 200;
-
- double heading;
- int _power = 1;
-
- void onRender(CanvasRenderingContext2D ctx) {
- // hack to stop draw under player graphic
- if (frameStart - start > 40) {
- ctx.save();
- ctx.globalCompositeOperation = "lighter";
- ctx.globalAlpha = fadeValue(1.0, FADE_LENGTH);
- // rotate the bullet bitmap into the correct heading
- ctx.translate(position.x, position.y);
- ctx.rotate(heading * RAD);
- // TODO(gram) - figure out how to get rid of the vector art so we don't
- // need the [0] below.
- ctx.drawImage(GameHandler.bitmaps.images["bullet"],
- -(BULLET_WIDTH + GLOWSHADOWBLUR*2)*0.5,
- -(BULLET_HEIGHT + GLOWSHADOWBLUR*2)*0.5);
- ctx.restore();
- }
- }
-
- /** Area effect weapon radius - zero for primary bullets. */
- get effectRadius => 0;
-
- // approximate based on average between width and height
- get radius => 4;
-
- get power => _power;
-}
-
-/**
- * Player BulletX2 actor class. Used by the TwinCannons primary weapon.
- */
-class BulletX2 extends Bullet {
-
- BulletX2(Vector position, Vector vector, double heading)
- : super(position, vector, heading, 1750) {
- _power = 2;
- }
-
- void onRender(CanvasRenderingContext2D ctx) {
- // hack to stop draw under player graphic
- if (frameStart - start > 40) {
- ctx.save();
- ctx.globalCompositeOperation = "lighter";
- ctx.globalAlpha = fadeValue(1.0, FADE_LENGTH);
- // rotate the bullet bitmap into the correct heading
- ctx.translate(position.x, position.y);
- ctx.rotate(heading * RAD);
- ctx.drawImage(GameHandler.bitmaps.images["bulletx2"],
- -(BULLET_WIDTH + GLOWSHADOWBLUR*4) / 2,
- -(BULLET_HEIGHT + GLOWSHADOWBLUR*2) / 2);
- ctx.restore();
- }
- }
-
- get radius => BULLET_HEIGHT;
-}
-
-class Bomb extends Bullet {
- Bomb(Vector position, Vector velocity)
- : super(position, velocity, 0.0, 3000);
-
- const BOMB_RADIUS = 4.0;
- const FADE_LENGTH = 200;
- const EFFECT_RADIUS = 45;
-
- void onRender(CanvasRenderingContext2D ctx) {
- ctx.save();
- ctx.globalCompositeOperation = "lighter";
- ctx.globalAlpha = fadeValue(1.0, FADE_LENGTH);
- ctx.translate(position.x, position.y);
- ctx.rotate((frameStart % (360*32)) / 32);
- var scale = fadeValue(1.0, FADE_LENGTH);
- if (scale <= 0) scale = 0.01;
- ctx.scale(scale, scale);
- ctx.drawImage(GameHandler.bitmaps.images["bomb"],
- -(BOMB_RADIUS + GLOWSHADOWBLUR),
- -(BOMB_RADIUS + GLOWSHADOWBLUR));
- ctx.restore();
- }
-
- get effectRadius => EFFECT_RADIUS;
- get radius => fadeValue(BOMB_RADIUS, FADE_LENGTH);
-}
-
-class EnemyBullet extends Bullet {
- EnemyBullet(Vector position, Vector velocity)
- : super(position, velocity, 0.0, 2800);
-
- const BULLET_RADIUS = 4.0;
- const FADE_LENGTH = 200;
-
- void onRender(CanvasRenderingContext2D ctx) {
- ctx.save();
- ctx.globalAlpha = fadeValue(1.0, FADE_LENGTH);
- ctx.globalCompositeOperation = "lighter";
- ctx.translate(position.x, position.y);
- ctx.rotate((frameStart % (360*64)) / 64);
- var scale = fadeValue(1.0, FADE_LENGTH);
- if (scale <= 0) scale = 0.01;
- ctx.scale(scale, scale);
- ctx.drawImage(GameHandler.bitmaps.images["enemybullet"],
- -(BULLET_RADIUS + GLOWSHADOWBLUR),
- -(BULLET_RADIUS + GLOWSHADOWBLUR));
- ctx.restore();
- }
-
- get radius => fadeValue(BULLET_RADIUS, FADE_LENGTH) + 1;
-}
-
-class Particle extends ShortLivedActor {
- int size;
- int type;
- int fadelength;
- String color;
- double rotate;
- double rotationv;
-
- Particle(Vector position, Vector velocity, this.size, this.type,
- int lifespan, this.fadelength,
- [this.color = Colors.PARTICLE])
- : super(position, velocity, lifespan) {
-
- // randomize rotation speed and angle for line particle
- if (type == 1) {
- rotate = random() * TWOPI;
- rotationv = (random() - 0.5) * 0.5;
- }
- }
-
- bool update() {
- position.add(velocity);
- return !expired();
- }
-
- void render(CanvasRenderingContext2D ctx) {
- ctx.globalAlpha = fadeValue(1.0, fadelength);
- switch (type) {
- case 0: // point (prerendered image)
- ctx.translate(position.x, position.y);
- ctx.drawImage(
- GameHandler.bitmaps.images["points_${color}"][size], 0, 0);
- break;
- // TODO: prerender a glowing line to use as the particle!
- case 1: // line
- ctx.translate(position.x, position.y);
- var s = size;
- ctx.rotate(rotate);
- this.rotate += rotationv;
- ctx.strokeStyle = color;
- ctx.lineWidth = 1.5;
- ctx.beginPath();
- ctx.moveTo(-s, -s);
- ctx.lineTo(s, s);
- ctx.closePath();
- ctx.stroke();
- break;
- case 2: // smudge (prerendered image)
- var offset = (size + 1) << 2;
- renderImage(ctx,
- GameHandler.bitmaps.images["smudges_${color}"][size],
- 0, 0, (size + 1) << 3,
- position.x - offset, position.y - offset, (size + 1) << 3);
- break;
- }
- }
-}
-
-/**
- * Particle emitter effect actor class.
- *
- * A simple particle emitter, that does not recycle particles, but sets itself
- * as expired() once all child particles have expired.
- *
- * Requires a function known as the emitter that is called per particle
- * generated.
- */
-class ParticleEmitter extends Actor {
-
- List<Particle> particles;
-
- ParticleEmitter(Vector position, Vector velocity)
- : super(position, velocity);
-
- Particle emitter() {}
-
- void init(count) {
- // generate particles based on the supplied emitter function
- particles = [];
- for (var i = 0; i < count; i++) {
- particles.add(emitter());
- }
- }
-
- void onRender(CanvasRenderingContext2D ctx) {
- ctx.save();
- ctx.shadowBlur = 0;
- ctx.globalCompositeOperation = "lighter";
- for (var i=0, particle; i < particles.length; i++) {
- particle = particles[i];
-
- // update particle and test for lifespan
- if (particle.update()) {
- ctx.save();
- particle.render(ctx);
- ctx.restore();
- } else {
- // particle no longer alive, remove from list
- particles.removeAt(i);
- }
- }
- ctx.restore();
- }
-
- bool expired() => (particles.length == 0);
-}
-
-class AsteroidExplosion extends ParticleEmitter {
- var asteroid;
-
- AsteroidExplosion(Vector position, Vector vector, this.asteroid)
- : super(position, vector) {
- init(asteroid.size*2);
- }
-
- Particle emitter() {
- // Randomise radial direction vector - speed and angle, then add parent
- // vector.
- var pos = position.clone();
- if (random() < 0.5) {
- var t = new Vector(0, randomInt(5, 10));
- t.rotate(random() * TWOPI).add(velocity);
- return new Particle(pos, t, (random() * 4).floor(), 0, 400, 300);
- } else {
- var t = new Vector(0, randomInt(1, 3));
- t.rotate(random() * TWOPI).add(velocity);
- return new Particle(pos, t,
- (random() * 4).floor() + asteroid.size, 2, 500, 250);
- }
- }
-}
-
-class PlayerExplosion extends ParticleEmitter {
- PlayerExplosion(Vector position, Vector vector)
- : super(position, vector) {
- init(12);
- }
-
- Particle emitter() {
- // Randomise radial direction vector - speed and angle, then add
- // parent vector.
- var pos = position.clone();
- if (random() < 0.5){
- var t = new Vector(0, randomInt(5, 10));
- t.rotate(random() * TWOPI).add(velocity);
- return new Particle(pos, t, (random() * 4).floor(), 0, 400, 300);
- } else {
- var t = new Vector(0, randomInt(1, 3));
- t.rotate(random() * TWOPI).add(velocity);
- return new Particle(pos, t, (random() * 4).floor() + 2, 2, 500, 250);
- }
- }
-}
-
-/** Enemy particle based explosion - Particle effect actor class. */
-class EnemyExplosion extends ParticleEmitter {
- var enemy;
- EnemyExplosion(Vector position, Vector vector, this.enemy)
- : super(position, vector) {
- init(8);
- }
-
- Particle emitter() {
- // randomise radial direction vector - speed and angle, then
- // add parent vector.
- var pos = position.clone();
- if (random() < 0.5) {
- var t = new Vector(0, randomInt(5, 10));
- t.rotate(random() * TWOPI).add(velocity);
- return new Particle(pos, t, (random() * 4).floor(), 0,
- 400, 300, Colors.ENEMY_SHIP);
- } else {
- var t = new Vector(0, randomInt(1, 3));
- t.rotate(random() * 2 * TWOPI).add(velocity);
- return new Particle(pos, t,
- (random() * 4).floor() + (enemy.size == 0 ? 2 : 0), 2,
- 500, 250, Colors.ENEMY_SHIP);
- }
- }
-}
-
-class Explosion extends EffectActor {
-/**
- * Basic explosion effect actor class.
- *
- * TODO: replace all instances of this with particle effects
- * - this is still usedby the smartbomb
- */
- Explosion(Vector position, Vector vector, this.size)
- : super(position, vector, FADE_LENGTH);
-
- static const FADE_LENGTH = 300;
-
- num size = 0;
-
- void onRender(CanvasRenderingContext2D ctx) {
- // fade out
- var brightness = (effectValue(255.0)).floor(),
- rad = effectValue(size * 8.0),
- rgb = brightness.toString();
- ctx.save();
- ctx.globalAlpha = 0.75;
- ctx.fillStyle = "rgb(${rgb},0,0)";
- ctx.beginPath();
- ctx.arc(position.x, position.y, rad, 0, TWOPI, true);
- ctx.closePath();
- ctx.fill();
- ctx.restore();
- }
-}
-
-/**
- * Player bullet impact effect - Particle effect actor class.
- * Used when an enemy is hit by player bullet but not destroyed.
- */
-class PlayerBulletImpact extends ParticleEmitter {
- PlayerBulletImpact(Vector position, Vector vector)
- : super(position, vector) {
- init(5);
- }
-
- Particle emitter() {
- // slightly randomise vector angle - then add parent vector
- var t = velocity.nscale(0.75 + random() * 0.5);
- t.rotate(random() * PIO4 - PIO8);
- return new Particle(position.clone(), t,
- (random() * 4).floor(), 0, 250, 150, Colors.GREEN_LASER);
- }
-}
-
-/**
- * Enemy bullet impact effect - Particle effect actor class.
- * Used when an enemy is hit by player bullet but not destroyed.
- */
-class EnemyBulletImpact extends ParticleEmitter {
- EnemyBulletImpact(Vector position , Vector vector)
- : super(position, vector) {
- init(5);
- }
-
- Particle emitter() {
- // slightly randomise vector angle - then add parent vector
- var t = velocity.nscale(0.75 + random() * 0.5);
- t.rotate(random() * PIO4 - PIO8);
- return new Particle(position.clone(), t,
- (random() * 4).floor(), 0, 250, 150, Colors.ENEMY_SHIP);
- }
-}
-
-class Player extends SpriteActor {
- Player(Vector position, Vector vector, this.heading)
- : super(position, vector) {
- energy = ENERGY_INIT;
-
- // setup SpriteActor values - used for shield sprite
- animImage = _shieldImg;
- animLength = SHIELD_ANIM_LENGTH;
-
- // setup weapons
- primaryWeapons = {};
- }
-
- const MAX_PLAYER_VELOCITY = 8.0;
- const PLAYER_RADIUS = 9;
- const SHIELD_RADIUS = 14;
- const SHIELD_ANIM_LENGTH = 100;
- const SHIELD_MIN_PULSE = 20;
- const ENERGY_INIT = 400;
- const THRUST_DELAY_MS = 100;
- const BOMB_RECHARGE_MS = 800;
- const BOMB_ENERGY = 80;
-
- double heading = 0.0;
-
- /** Player energy (shield and bombs). */
- num energy = 0;
-
- /** Player shield active counter. */
- num shieldCounter = 0;
-
- bool alive = true;
- Map primaryWeapons = null;
-
- /** Bomb fire recharging counter. */
- num bombRecharge = 0;
-
- /** Engine thrust recharge counter. */
- num thrustRecharge = 0;
-
- /** True if the engine thrust graphics should be rendered next frame. */
- bool engineThrust = false;
-
- /**
- * Time that the player was killed - to cause a delay before respawning
- * the player
- */
- num killedOn = 0;
-
- bool fireWhenShield = false;
-
- /** Player rendering method
- *
- * @param ctx {object} Canvas rendering context
- */
- void onRender(CanvasRenderingContext2D ctx) {
- var headingRad = heading * RAD;
-
- // render engine thrust?
- if (engineThrust) {
- ctx.save();
- ctx.translate(position.x, position.y);
- ctx.rotate(headingRad);
- ctx.globalAlpha = 0.5 + random() * 0.5;
- ctx.globalCompositeOperation = "lighter";
- ctx.fillStyle = Colors.PLAYER_THRUST;
- ctx.beginPath();
- ctx.moveTo(-5, 8);
- ctx.lineTo(5, 8);
- ctx.lineTo(0, 18 + random() * 6);
- ctx.closePath();
- ctx.fill();
- ctx.restore();
- engineThrust = false;
- }
-
- // render player graphic
- var size = (PLAYER_RADIUS * 2) + 6;
- // normalise the player heading to 0-359 degrees
- // then locate the correct frame in the sprite strip -
- // an image for each 4 degrees of rotation
- var normAngle = heading.floor() % 360;
- if (normAngle < 0) {
- normAngle = 360 + normAngle;
- }
- ctx.save();
- drawScaledImage(ctx, _playerImg,
- 0, (normAngle / 4).floor() * 64, 64,
- position.x - (size / 2), position.y - (size / 2), size);
- ctx.restore();
-
- // shield up? if so render a shield graphic around the ship
- if (shieldCounter > 0 && energy > 0) {
- // render shield graphic bitmap
- ctx.save();
- ctx.translate(position.x, position.y);
- ctx.rotate(headingRad);
- renderSprite(ctx, -SHIELD_RADIUS-1,
- -SHIELD_RADIUS-1, (SHIELD_RADIUS * 2) + 2);
- ctx.restore();
-
- shieldCounter--;
- energy -= 1.5;
- }
- }
-
- /** Execute player forward thrust request. */
- void thrust() {
- // now test we did not thrust too recently, based on time since last thrust
- // request - ensures same thrust at any framerate
- if (frameStart - thrustRecharge > THRUST_DELAY_MS) {
- // update last thrust time
- thrustRecharge = frameStart;
-
- // generate a small thrust vector
- var t = new Vector(0.0, -0.5);
-
- // rotate thrust vector by player current heading
- t.rotate(heading * RAD);
-
- // add player thrust vector to position
- velocity.add(t);
-
- // player can't exceed maximum velocity - scale vector down if
- // this occurs - do this rather than not adding the thrust at all
- // otherwise the player cannot turn and thrust at max velocity
- if (velocity.length() > MAX_PLAYER_VELOCITY) {
- velocity.scale(MAX_PLAYER_VELOCITY / velocity.length());
- }
- }
- // mark so that we know to render engine thrust graphics
- engineThrust = true;
- }
-
- /**
- * Execute player active shield request.
- * If energy remaining the shield will be briefly applied.
- */
- void activateShield() {
- // ensure shield stays up for a brief pulse between key presses!
- if (energy >= SHIELD_MIN_PULSE) {
- shieldCounter = SHIELD_MIN_PULSE;
- }
- }
-
- bool isShieldActive() => (shieldCounter > 0 && energy > 0);
-
- get radius => (isShieldActive() ? SHIELD_RADIUS : PLAYER_RADIUS);
-
- bool expired() => !(alive);
-
- void kill() {
- alive = false;
- killedOn = frameStart;
- }
-
- /** Fire primary weapon(s). */
-
- void firePrimary(List bulletList) {
- var playedSound = false;
- // attempt to fire the primary weapon(s)
- // first ensure player is alive and the shield is not up
- if (alive && (!isShieldActive() || fireWhenShield)) {
- for (var w in primaryWeapons.keys) {
- var b = primaryWeapons[w].fire();
- if (b != null) {
- for (var i=0; i<b.length; i++) {
- bulletList.add(b[i]);
- }
- if (!playedSound) {
- soundManager.play('laser');
- playedSound = true;
- }
- }
- }
- }
- }
-
- /**
- * Fire secondary weapon.
- * @param bulletList {Array} to add bullet to on success
- */
- void fireSecondary(List bulletList) {
- // Attempt to fire the secondary weapon and generate bomb object if
- // successful. First ensure player is alive and the shield is not up.
- if (alive && (!isShieldActive() || fireWhenShield) && energy > BOMB_ENERGY){
- // now test we did not fire too recently
- if (frameStart - bombRecharge > BOMB_RECHARGE_MS) {
- // ok, update last fired time and we can now generate a bomb
- bombRecharge = frameStart;
-
- // decrement energy supply
- energy -= BOMB_ENERGY;
-
- // generate a vector rotated to the player heading and then add the
- // current player vector to give the bomb the correct directional
- // momentum.
- var t = new Vector(0.0, -3.0);
- t.rotate(heading * RAD);
- t.add(velocity);
-
- bulletList.add(new Bomb(position.clone(), t));
- }
- }
- }
-
- void onUpdate(_) {
- // slowly recharge the shield - if not active
- if (!isShieldActive() && energy < ENERGY_INIT) {
- energy += 0.1;
- }
- }
-
- void reset(bool persistPowerUps) {
- // reset energy, alive status, weapons and power up flags
- alive = true;
- if (!persistPowerUps) {
- primaryWeapons = {};
- primaryWeapons["main"] = new PrimaryWeapon(this);
- fireWhenShield = false;
- }
- energy = ENERGY_INIT + SHIELD_MIN_PULSE; // for shield as below
-
- // active shield briefly
- activateShield();
- }
-}
-
-/**
- * Image Preloader class. Executes the supplied callback function once all
- * registered images are loaded by the browser.
- */
-class Preloader {
- Preloader() {
- images = new List();
- }
-
- /**
- * Image list
- *
- * @property images
- * @type Array
- */
- var images = [];
-
- /**
- * Callback function
- *
- * @property callback
- * @type Function
- */
- var callback = null;
-
- /**
- * Images loaded so far counter
- */
- var counter = 0;
-
- /**
- * Add an image to the list of images to wait for
- */
- void addImage(ImageElement img, String url) {
- var me = this;
- img.src = url;
- // attach closure to the image onload handler
- img.onLoad.listen((_) {
- me.counter++;
- if (me.counter == me.images.length) {
- // all images are loaded - execute callback function
- me.callback();
- }
- });
- images.add(img);
- }
-
- /**
- * Load the images and call the supplied function when ready
- */
- void onLoadCallback(Function fn) {
- counter = 0;
- callback = fn;
- // load the images
- //for (var i=0, j = images.length; i<j; i++) {
- // images[i].src = images[i].url;
- //}
- }
-}
-
-/**
- * Game prerenderer class.
- */
-class GamePrerenderer {
- GamePrerenderer();
-
- /**
- * Image list. Keyed by renderer ID - returning an array also. So to get
- * the first image output by prerenderer with id "default":
- * images["default"][0]
- */
- Map images = {};
- Map _renderers = {};
-
- /** Add a renderer function to the list of renderers to execute. */
- addRenderer(Function fn, String id) => _renderers[id] = fn;
-
-
- /** Execute all prerender functions. */
- void execute() {
- var buffer = new CanvasElement();
- for (var id in _renderers.keys) {
- images[id] = _renderers[id](buffer);
- }
- }
-}
-
-/**
- * Asteroids prerenderer class.
- *
- * Encapsulates the early rendering of various effects used in the game. Each
- * effect is rendered once to a hidden canvas object, the image data is
- * extracted and stored in an Image object - which can then be reused later.
- * This is much faster than rendering each effect again and again at runtime.
- *
- * The downside to this is that some constants are duplicated here and in the
- * original classes - so updates to the original classes such as the weapon
- * effects must be duplicated here.
- */
-class Prerenderer extends GamePrerenderer {
- Prerenderer() : super() {
-
- // function to generate a set of point particle images
- var fnPointRenderer = (CanvasElement buffer, String color) {
- var imgs = [];
- for (var size = 3; size <= 6; size++) {
- var width = size << 1;
- buffer.width = buffer.height = width;
- CanvasRenderingContext2D ctx = buffer.getContext('2d');
- var radgrad = ctx.createRadialGradient(size, size, size >> 1,
- size, size, size);
- radgrad.addColorStop(0, color);
- radgrad.addColorStop(1, "#000");
- ctx.fillStyle = radgrad;
- ctx.fillRect(0, 0, width, width);
- var img = new ImageElement();
- img.src = buffer.toDataUrl("image/png");
- imgs.add(img);
- }
- return imgs;
- };
-
- // add the various point particle image prerenderers based on above function
- // default explosion color
- addRenderer((CanvasElement buffer) {
- return fnPointRenderer(buffer, Colors.PARTICLE);
- }, "points_${Colors.PARTICLE}");
-
- // player bullet impact particles
- addRenderer((CanvasElement buffer) {
- return fnPointRenderer(buffer, Colors.GREEN_LASER);
- }, "points_${Colors.GREEN_LASER}");
-
- // enemy bullet impact particles
- addRenderer((CanvasElement buffer) {
- return fnPointRenderer(buffer, Colors.ENEMY_SHIP);
- }, "points_${Colors.ENEMY_SHIP}");
-
- // add the smudge explosion particle image prerenderer
- var fnSmudgeRenderer = (CanvasElement buffer, String color) {
- var imgs = [];
- for (var size = 4; size <= 32; size += 4) {
- var width = size << 1;
- buffer.width = buffer.height = width;
- CanvasRenderingContext2D ctx = buffer.getContext('2d');
- var radgrad = ctx.createRadialGradient(size, size, size >> 3,
- size, size, size);
- radgrad.addColorStop(0, color);
- radgrad.addColorStop(1, "#000");
- ctx.fillStyle = radgrad;
- ctx.fillRect(0, 0, width, width);
- var img = new ImageElement();
- img.src = buffer.toDataUrl("image/png");
- imgs.add(img);
- }
- return imgs;
- };
-
- addRenderer((CanvasElement buffer) {
- return fnSmudgeRenderer(buffer, Colors.PARTICLE);
- }, "smudges_${Colors.PARTICLE}");
-
- addRenderer((CanvasElement buffer) {
- return fnSmudgeRenderer(buffer, Colors.ENEMY_SHIP);
- }, "smudges_${Colors.ENEMY_SHIP}");
-
- // standard player bullet
- addRenderer((CanvasElement buffer) {
- // NOTE: keep in sync with Asteroids.Bullet
- var BULLET_WIDTH = 2, BULLET_HEIGHT = 6;
- var imgs = [];
- buffer.width = BULLET_WIDTH + GLOWSHADOWBLUR*2;
- buffer.height = BULLET_HEIGHT + GLOWSHADOWBLUR*2;
- CanvasRenderingContext2D ctx = buffer.getContext('2d');
-
- var rf = (width, height) {
- ctx.beginPath();
- ctx.moveTo(0, height);
- ctx.lineTo(width, 0);
- ctx.lineTo(0, -height);
- ctx.lineTo(-width, 0);
- ctx.closePath();
- };
-
- ctx.shadowBlur = GLOWSHADOWBLUR;
- ctx.translate(buffer.width * 0.5, buffer.height * 0.5);
- ctx.shadowColor = ctx.fillStyle = Colors.GREEN_LASER_DARK;
- rf(BULLET_WIDTH-1, BULLET_HEIGHT-1);
- ctx.fill();
- ctx.shadowColor = ctx.fillStyle = Colors.GREEN_LASER;
- rf(BULLET_WIDTH, BULLET_HEIGHT);
- ctx.fill();
- var img = new ImageElement();
- img.src = buffer.toDataUrl("image/png");
- return img;
- }, "bullet");
-
- // player bullet X2
- addRenderer((CanvasElement buffer) {
- // NOTE: keep in sync with Asteroids.BulletX2
- var BULLET_WIDTH = 2, BULLET_HEIGHT = 6;
- buffer.width = BULLET_WIDTH + GLOWSHADOWBLUR*4;
- buffer.height = BULLET_HEIGHT + GLOWSHADOWBLUR*2;
- CanvasRenderingContext2D ctx = buffer.getContext('2d');
-
- var rf = (width, height) {
- ctx.beginPath();
- ctx.moveTo(0, height);
- ctx.lineTo(width, 0);
- ctx.lineTo(0, -height);
- ctx.lineTo(-width, 0);
- ctx.closePath();
- };
-
- ctx.shadowBlur = GLOWSHADOWBLUR;
- ctx.translate(buffer.width * 0.5, buffer.height * 0.5);
- ctx.save();
- ctx.translate(-4, 0);
- ctx.shadowColor = ctx.fillStyle = Colors.GREEN_LASERX2_DARK;
- rf(BULLET_WIDTH-1, BULLET_HEIGHT-1);
- ctx.fill();
- ctx.shadowColor = ctx.fillStyle = Colors.GREEN_LASERX2;
- rf(BULLET_WIDTH, BULLET_HEIGHT);
- ctx.fill();
- ctx.translate(8, 0);
- ctx.shadowColor = ctx.fillStyle = Colors.GREEN_LASERX2_DARK;
- rf(BULLET_WIDTH-1, BULLET_HEIGHT-1);
- ctx.fill();
- ctx.shadowColor = ctx.fillStyle = Colors.GREEN_LASERX2;
- rf(BULLET_WIDTH, BULLET_HEIGHT);
- ctx.fill();
- ctx.restore();
- var img = new ImageElement();
- img.src = buffer.toDataUrl("image/png");
- return img;
- }, "bulletx2");
-
- // player bomb weapon
- addRenderer((CanvasElement buffer) {
- // NOTE: keep in sync with Asteroids.Bomb
- var BOMB_RADIUS = 4;
- buffer.width = buffer.height = BOMB_RADIUS*2 + GLOWSHADOWBLUR*2;
- CanvasRenderingContext2D ctx = buffer.getContext('2d');
-
- var rf = () {
- ctx.beginPath();
- ctx.moveTo(BOMB_RADIUS * 2, 0);
- for (var i = 0; i < 15; i++) {
- ctx.rotate(PIO8);
- if (i % 2 == 0) {
- ctx.lineTo((BOMB_RADIUS * 2 / 0.525731) * 0.200811, 0);
- } else {
- ctx.lineTo(BOMB_RADIUS * 2, 0);
- }
- }
- ctx.closePath();
- };
-
- ctx.shadowBlur = GLOWSHADOWBLUR;
- ctx.shadowColor = ctx.fillStyle = Colors.PLAYER_BOMB;
- ctx.translate(buffer.width * 0.5, buffer.height * 0.5);
- rf();
- ctx.fill();
-
- var img = new ImageElement();
- img.src = buffer.toDataUrl("image/png");
- return img;
- }, "bomb");
-
- //enemy weapon
- addRenderer((CanvasElement buffer) {
- // NOTE: keep in sync with Asteroids.EnemyBullet
- var BULLET_RADIUS = 4;
- var imgs = [];
- buffer.width = buffer.height = BULLET_RADIUS*2 + GLOWSHADOWBLUR*2;
- CanvasRenderingContext2D ctx = buffer.getContext('2d');
-
- var rf = () {
- ctx.beginPath();
- ctx.moveTo(BULLET_RADIUS * 2, 0);
- for (var i=0; i<7; i++) {
- ctx.rotate(PIO4);
- if (i % 2 == 0) {
- ctx.lineTo((BULLET_RADIUS * 2/0.525731) * 0.200811, 0);
- } else {
- ctx.lineTo(BULLET_RADIUS * 2, 0);
- }
- }
- ctx.closePath();
- };
-
- ctx.shadowBlur = GLOWSHADOWBLUR;
- ctx.shadowColor = ctx.fillStyle = Colors.ENEMY_SHIP;
- ctx.translate(buffer.width * 0.5, buffer.height * 0.5);
- ctx.beginPath();
- ctx.arc(0, 0, BULLET_RADIUS-1, 0, TWOPI, true);
- ctx.closePath();
- ctx.fill();
- rf();
- ctx.fill();
-
- var img = new ImageElement();
- img.src = buffer.toDataUrl("image/png");
- return img;
- }, "enemybullet");
- }
-}
-
-/**
- * Game scene base class.
- */
-class Scene {
- bool playable;
- Interval interval;
-
- Scene([this.playable = true, this.interval = null]);
-
- /** Return true if this scene should update the actor list. */
- bool isPlayable() => playable;
-
- void onInitScene() {
- if (interval != null) {
- // reset interval flag
- interval.reset();
- }
- }
-
- void onBeforeRenderScene() {}
- void onRenderScene(ctx) {}
- void onRenderInterval(ctx) {}
- void onMouseDownHandler(e) {}
- void onMouseUpHandler(e) {}
- void onKeyDownHandler(int keyCode) {}
- void onKeyUpHandler(int keyCode) {}
- bool isComplete() => false;
-
- bool onAccelerometer(double x, double y, double z) {
- return true;
- }
-}
-
-class SoundManager {
- bool _isDesktopEmulator;
- Map _sounds = {};
-
- SoundManager(this._isDesktopEmulator);
-
- void createSound(Map props) {
- if (!_isDesktopEmulator) {
- var a = new AudioElement();
- a.volume = props['volume'] / 100.0;;
- a.src = props['url'];
- _sounds[props['id']] = a;
- }
- }
-
- void play(String id) {
- if (!_isDesktopEmulator) {
- _sounds[id].play();
- }
- }
-}
-
-/**
- * An actor that can be rendered by a bitmap. The sprite handling code deals
- * with the increment of the current frame within the supplied bitmap sprite
- * strip image, based on animation direction, animation speed and the animation
- * length before looping. Call renderSprite() each frame.
- *
- * NOTE: by default sprites source images are 64px wide 64px by N frames high
- * and scaled to the appropriate final size. Any other size input source should
- * be set in the constructor.
- */
-class SpriteActor extends Actor {
- SpriteActor(Vector position, Vector vector, [this.frameSize = 64])
- : super(position, vector);
-
- /** Size in pixels of the width/height of an individual frame in the image. */
- int frameSize;
-
- /**
- * Animation image sprite reference.
- * Sprite image sources are all currently 64px wide 64px by N frames high.
- */
- ImageElement animImage = null;
-
- /** Length in frames of the sprite animation. */
- int animLength = 0;
-
- /** Animation direction, true for forward, false for reverse. */
- bool animForward = true;
-
- /** Animation frame inc/dec speed. */
- double animSpeed = 1.0;
-
- /** Current animation frame index. */
- int animFrame = 0;
-
- /**
- * Render sprite graphic based on current anim image, frame and anim direction
- * Automatically updates the current anim frame.
- */
- void renderSprite(CanvasRenderingContext2D ctx, num x, num y, num s) {
- renderImage(ctx, animImage, 0, animFrame << 6, frameSize, x, y, s);
-
- // update animation frame index
- if (animForward) {
- animFrame += (animSpeed * frameMultiplier).toInt();
- if (animFrame >= animLength) {
- animFrame = 0;
- }
- } else {
- animFrame -= (animSpeed * frameMultiplier).toInt();
- if (animFrame < 0) {
- animFrame = animLength - 1;
- }
- }
- }
-}
-
-class Star {
- Star();
-
- double MAXZ = 12.0;
- double VELOCITY = 0.85;
-
- num x = 0;
- num y = 0;
- num z = 0;
- num prevx = 0;
- num prevy = 0;
-
- void init() {
- // select a random point for the initial location
- prevx = prevy = 0;
- x = (random() * GameHandler.width - (GameHandler.width * 0.5)) * MAXZ;
- y = (random() * GameHandler.height - (GameHandler.height * 0.5)) * MAXZ;
- z = MAXZ;
- }
-
- void render(CanvasRenderingContext2D ctx) {
- var xx = x / z;
- var yy = y / z;
-
- if (prevx != 0) {
- ctx.lineWidth = 1.0 / z * 5 + 1;
- ctx.beginPath();
- ctx.moveTo(prevx + (GameHandler.width * 0.5),
- prevy + (GameHandler.height * 0.5));
- ctx.lineTo(xx + (GameHandler.width * 0.5),
- yy + (GameHandler.height * 0.5));
- ctx.stroke();
- }
-
- prevx = xx;
- prevy = yy;
- }
-}
-
-void drawText(CanvasRenderingContext2D g,
- String txt, String font, num x, num y,
- [String color]) {
- g.save();
- if (color != null) g.strokeStyle = color;
- g.font = font;
- g.strokeText(txt, x, y);
- g.restore();
-}
-
-void centerDrawText(CanvasRenderingContext2D g, String txt, String font, num y,
- [String color]) {
- g.save();
- if (color != null) g.strokeStyle = color;
- g.font = font;
- g.strokeText(txt, (GameHandler.width - g.measureText(txt).width) / 2, y);
- g.restore();
-}
-
-void fillText(CanvasRenderingContext2D g, String txt, String font, num x, num y,
- [String color]) {
- g.save();
- if (color != null) g.fillStyle = color;
- g.font = font;
- g.fillText(txt, x, y);
- g.restore();
-}
-
-void centerFillText(CanvasRenderingContext2D g, String txt, String font, num y,
- [String color]) {
- g.save();
- if (color != null) g.fillStyle = color;
- g.font = font;
- g.fillText(txt, (GameHandler.width - g.measureText(txt).width) / 2, y);
- g.restore();
-}
-
-void drawScaledImage(CanvasRenderingContext2D ctx, ImageElement image,
- num nx, num ny, num ns, num x, num y, num s) {
- ctx.drawImageToRect(image, new Rect(x, y, s, s),
- sourceRect: new Rect(nx, ny, ns, ns));
-}
-/**
- * This method will automatically correct for objects moving on/off
- * a cyclic canvas play area - if so it will render the appropriate stencil
- * sections of the sprite top/bottom/left/right as needed to complete the image.
- * Note that this feature can only be used if the sprite is absolutely
- * positioned and not translated/rotated into position by canvas operations.
- */
-void renderImage(CanvasRenderingContext2D ctx, ImageElement image,
- num nx, num ny, num ns, num x, num y, num s) {
- print("renderImage(_,$nx,$ny,$ns,$ns,$x,$y,$s,$s)");
- ctx.drawImageScaledFromSource(image, nx, ny, ns, ns, x, y, s, s);
-
- if (x < 0) {
- ctx.drawImageScaledFromSource(image, nx, ny, ns, ns,
- GameHandler.width + x, y, s, s);
- }
- if (y < 0) {
- ctx.drawImageScaledFromSource(image, nx, ny, ns, ns,
- x, GameHandler.height + y, s, s);
- }
- if (x < 0 && y < 0) {
- ctx.drawImageScaledFromSource(image, nx, ny, ns, ns,
- GameHandler.width + x, GameHandler.height + y, s, s);
- }
- if (x + s > GameHandler.width) {
- ctx.drawImageScaledFromSource(image, nx, ny, ns, ns,
- x - GameHandler.width, y, s, s);
- }
- if (y + s > GameHandler.height) {
- ctx.drawImageScaledFromSource(image, nx, ny, ns, ns,
- x, y - GameHandler.height, s, s);
- }
- if (x + s > GameHandler.width && y + s > GameHandler.height) {
- ctx.drawImageScaledFromSource(image, nx, ny, ns, ns,
- x - GameHandler.width, y - GameHandler.height, s, s);
- }
-}
-
-void renderImageRotated(CanvasRenderingContext2D ctx, ImageElement image,
- num x, num y, num w, num h, num r) {
- var w2 = w*0.5, h2 = h*0.5;
- var rf = (tx, ty) {
- ctx.save();
- ctx.translate(tx, ty);
- ctx.rotate(r);
- ctx.drawImage(image, -w2, -h2);
- ctx.restore();
- };
-
- rf(x, y);
-
- if (x - w2 < 0) {
- rf(GameHandler.width + x, y);
- }
- if (y - h2 < 0) {
- rf(x, GameHandler.height + y);
- }
- if (x - w2 < 0 && y - h2 < 0) {
- rf(GameHandler.width + x, GameHandler.height + y);
- }
- if (x - w2 + w > GameHandler.width) {
- rf(x - GameHandler.width, y);
- }
- if (y - h2 + h > GameHandler.height){
- rf(x, y - GameHandler.height);
- }
- if (x - w2 + w > GameHandler.width && y - h2 + h > GameHandler.height) {
- rf(x - GameHandler.width, y - GameHandler.height);
- }
-}
-
-void renderImageRotated2(CanvasRenderingContext2D ctx, ImageElement image,
- num x, num y, num w, num h, num r) {
- print("Rendering rotated sprite ${image.src} to dest $x,$y");
- var w2 = w*0.5, h2 = h*0.5;
- var rf = (tx, ty) {
- ctx.save();
- ctx.translate(tx, ty);
- ctx.rotate(r);
- ctx.drawImage(image, -w2, -h2);
- ctx.restore();
- };
-
- rf(x, y);
-
- if (x - w2 < 0) {
- rf(GameHandler.width + x, y);
- }
- if (y - h2 < 0) {
- rf(x, GameHandler.height + y);
- }
- if (x - w2 < 0 && y - h2 < 0) {
- rf(GameHandler.width + x, GameHandler.height + y);
- }
- if (x - w2 + w > GameHandler.width) {
- rf(x - GameHandler.width, y);
- }
- if (y - h2 + h > GameHandler.height){
- rf(x, y - GameHandler.height);
- }
- if (x - w2 + w > GameHandler.width && y - h2 + h > GameHandler.height) {
- rf(x - GameHandler.width, y - GameHandler.height);
- }
-}
-
-class Vector {
- num x, y;
-
- Vector(this.x, this.y);
-
- Vector clone() => new Vector(x, y);
-
- void set(Vector v) {
- x = v.x;
- y = v.y;
- }
-
- Vector add(Vector v) {
- x += v.x;
- y += v.y;
- return this;
- }
-
- Vector nadd(Vector v) => new Vector(x + v.x, y + v.y);
-
- Vector sub(Vector v) {
- x -= v.x;
- y -= v.y;
- return this;
- }
-
- Vector nsub(Vector v) => new Vector(x - v.x, y - v.y);
-
- double dot(Vector v) => x * v.x + y * v.y;
-
- double length() => Math.sqrt(x * x + y * y);
-
- double distance(Vector v) {
- var dx = x - v.x;
- var dy = y - v.y;
- return Math.sqrt(dx * dx + dy * dy);
- }
-
- double theta() => Math.atan2(y, x);
-
- double thetaTo(Vector vec) {
- // calc angle between the two vectors
- var v = clone().norm();
- var w = vec.clone().norm();
- return Math.sqrt(v.dot(w));
- }
-
- double thetaTo2(Vector vec) =>
- Math.atan2(vec.y, vec.x) - Math.atan2(y, x);
-
- Vector norm() {
- var len = length();
- x /= len;
- y /= len;
- return this;
- }
-
- Vector nnorm() {
- var len = length();
- return new Vector(x / len, y / len);
- }
-
- rotate(num a) {
- var ca = Math.cos(a);
- var sa = Math.sin(a);
- var newx = x*ca - y*sa;
- var newy = x*sa + y*ca;
- x = newx;
- y = newy;
- return this;
- }
-
- Vector nrotate(num a) {
- var ca = Math.cos(a);
- var sa = Math.sin(a);
- return new Vector(x * ca - y * sa, x * sa + y * ca);
- }
-
- Vector invert() {
- x = -x;
- y = -y;
- return this;
- }
-
- Vector ninvert() {
- return new Vector(-x, -y);
- }
-
- Vector scale(num s) {
- x *= s;
- y *= s;
- return this;
- }
-
- Vector nscale(num s) {
- return new Vector(x * s, y * s);
- }
-
- Vector scaleTo(num s) {
- var len = s / length();
- x *= len;
- y *= len;
- return this;
- }
-
- nscaleTo(num s) {
- var len = s / length();
- return new Vector(x * len, y * len);
- }
-
- trim(num minx, num maxx, num miny, num maxy) {
- if (x < minx) x = minx;
- else if (x > maxx) x = maxx;
- if (y < miny) y = miny;
- else if (y > maxy) y = maxy;
- }
-
- wrap(num minx, num maxx, num miny, num maxy) {
- if (x < minx) x = maxx;
- else if (x > maxx) x = minx;
- if (y < miny) y = maxy;
- else if (y > maxy) y = miny;
- }
-
- String toString() => "<$x, $y>";
-}
-
-class Weapon {
- Weapon(this.player, [this.rechargeTime = 125]);
-
- int rechargeTime;
- int lastFired = 0;
- Player player;
-
- bool canFire() =>
- (GameHandler.frameStart - lastFired) >= rechargeTime;
-
- List fire() {
- if (canFire()) {
- lastFired = GameHandler.frameStart;
- return doFire();
- }
- }
-
- Bullet makeBullet(double headingDelta, double vectorY,
- [int lifespan = 1300]) {
- var h = player.heading - headingDelta;
- var t = new Vector(0.0, vectorY).rotate(h * RAD).add(player.velocity);
- return new Bullet(player.position.clone(), t, h, lifespan);
- }
-
- List doFire() => [];
-}
-
-class PrimaryWeapon extends Weapon {
- PrimaryWeapon(Player player) : super(player);
-
- List doFire() => [ makeBullet(0.0, -4.5) ];
-}
-
-class TwinCannonsWeapon extends Weapon {
- TwinCannonsWeapon(Player player) : super(player, 150);
-
- List doFire() {
- var h = player.heading;
- var t = new Vector(0.0, -4.5).rotate(h * RAD).add(player.velocity);
- return [ new BulletX2(player.position.clone(), t, h) ];
- }
-}
-
-class VSprayCannonsWeapon extends Weapon {
- VSprayCannonsWeapon(Player player) : super(player, 250);
-
- List doFire() =>
- [ makeBullet(-15.0, -3.75),
- makeBullet(0.0, -3.75),
- makeBullet(15.0, -3.75) ];
-}
-
-class SideGunWeapon extends Weapon {
- SideGunWeapon(Player player) : super(player, 250);
-
- List doFire() =>
- [ makeBullet(-90.0, -4.5, 750),
- makeBullet(+90.0, -4.5, 750)];
-}
-
-class RearGunWeapon extends Weapon {
- RearGunWeapon(Player player) : super(player, 250);
-
- List doFire() => [makeBullet(180.0, -4.5, 750)];
-}
-
-class Input {
- bool left, right, thrust, shield, fireA, fireB;
-
- Input() { reset(); }
-
- void reset() {
- left = right = thrust = shield = fireA = fireB = false;
- }
-}
-
-void resize(int w, int h) {}
-
-
-void setup(canvasp, int w, int h, int f) {
- var canvas;
- if (canvasp == null) {
- log("Allocating canvas");
- canvas = new CanvasElement(width: w, height: h);
- document.body.nodes.add(canvas);
- } else {
- log("Using parent canvas");
- canvas = canvasp;
- }
-
- for (var i = 0; i < 4; i++) {
- _asteroidImgs.add(new ImageElement());
- }
- // attach to the image onload handler
- // once the background is loaded, we can boot up the game
- _backgroundImg.onLoad.listen((e) {
- // init our game with Game.Main derived instance
- log("Loaded background image ${_backgroundImg.src}");
- GameHandler.init(canvas);
- GameHandler.start(new AsteroidsMain());
- });
- _backgroundImg.src = 'bg3_1.png';
- loadSounds(f == 1);
-}
-
-void loadSounds(bool isDesktopEmulator) {
- soundManager = new SoundManager(isDesktopEmulator);
- // load game sounds
- soundManager.createSound({
- 'id': 'laser',
- 'url': 'laser.$sfx_extension',
- 'volume': 40,
- 'autoLoad': true,
- 'multiShot': true
- });
- soundManager.createSound({
- 'id': 'enemy_bomb',
- 'url': 'enemybomb.$sfx_extension',
- 'volume': 60,
- 'autoLoad': true,
- 'multiShot': true
- });
- soundManager.createSound({
- 'id': 'big_boom',
- 'url': 'bigboom.$sfx_extension',
- 'volume': 50,
- 'autoLoad': true,
- 'multiShot': true
- });
- soundManager.createSound({
- 'id': 'asteroid_boom1',
- 'url': 'explosion1.$sfx_extension',
- 'volume': 50,
- 'autoLoad': true,
- 'multiShot': true
- });
- soundManager.createSound({
- 'id': 'asteroid_boom2',
- 'url': 'explosion2.$sfx_extension',
- 'volume': 50,
- 'autoLoad': true,
- 'multiShot': true
- });
- soundManager.createSound({
- 'id': 'asteroid_boom3',
- 'url': 'explosion3.$sfx_extension',
- 'volume': 50,
- 'autoLoad': true,
- 'multiShot': true
- });
- soundManager.createSound({
- 'id': 'asteroid_boom4',
- 'url': 'explosion4.$sfx_extension',
- 'volume': 50,
- 'autoLoad': true,
- 'multiShot': true
- });
- soundManager.createSound({
- 'id': 'powerup',
- 'url': 'powerup.$sfx_extension',
- 'volume': 50,
- 'autoLoad': true,
- 'multiShot': true
- });
-}
-
« dart.gyp ('K') | « samples/openglui/pubspec.yaml ('k') | samples/openglui/src/chrome.hex » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698