game.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. var fontDeferred = Q.defer();
  2. WebFontConfig = {
  3. google: { families: [ 'Quicksand::latin' ] },
  4. active: function() {
  5. fontDeferred.resolve();
  6. }
  7. };
  8. (function() {
  9. var wf = document.createElement('script');
  10. wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
  11. '://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
  12. wf.type = 'text/javascript';
  13. wf.async = 'true';
  14. var s = document.getElementsByTagName('script')[0];
  15. s.parentNode.insertBefore(wf, s);
  16. })();
  17. var soundDeferred = Q.defer();
  18. soundManager.setup({
  19. url: 'swf/',
  20. flashVersion: 9,
  21. onready: function() {
  22. soundDeferred.resolve(this);
  23. }
  24. });
  25. var Game = {
  26. canvas: document.getElementById('game'),
  27. context: document.getElementById('game').getContext('2d'),
  28. keysDown: {},
  29. start: function() {
  30. addEventListener('keydown', function(e) {
  31. Game.keysDown[e.keyCode] = true;
  32. }, false);
  33. addEventListener('keyup', function(e) {
  34. delete Game.keysDown[e.keyCode];
  35. }, false);
  36. var fontPromise = fontDeferred.promise.timeout(5000);
  37. var soundPromise = soundDeferred.promise.then(function() {
  38. return [
  39. createSound('confirm', 'sound/confirm.mp3'),
  40. createSound('back', 'sound/back.mp3'),
  41. createSound('pause', 'sound/pause.mp3'),
  42. createSound('cursor', 'sound/cursor.mp3')
  43. ]
  44. });
  45. Game.sceneManager.push(SplashScreen);
  46. Q.allResolved([fontPromise, soundPromise]).done(function() {
  47. Game.sceneManager.pop();
  48. Game.sceneManager.push(MainMenu);
  49. });
  50. Ticker.start();
  51. Ticker.addListener(function(dt) {
  52. Game.sceneManager.update(dt);
  53. Game.sceneManager.draw();
  54. });
  55. },
  56. pause: function() {
  57. Game.sceneManager.push(PauseScreen, 0);
  58. },
  59. sceneManager: {
  60. sceneStack: [],
  61. currentScene: null,
  62. promise: Q(),
  63. update: function(delta) {
  64. if(this.currentScene) this.currentScene._update(delta);
  65. },
  66. draw: function() {
  67. if(this.currentScene) this.currentScene._draw();
  68. this.drawFade();
  69. },
  70. push: function(scene, outDuration, inDuration) {
  71. outDuration = (outDuration == undefined) ? 0.5 : outDuration;
  72. inDuration = (inDuration == undefined) ? outDuration : inDuration;
  73. var self = this;
  74. var promise = this.promise;
  75. if(this.currentScene) {
  76. console.log('hi');
  77. this.currentScene.pause();
  78. promise = this.fadeOut(outDuration);
  79. }
  80. promise.then(function() {
  81. self.sceneStack.push(scene);
  82. if(!scene.hasTicker) scene._init();
  83. scene.load();
  84. self.currentScene = scene;
  85. return self.fadeIn(inDuration);
  86. });
  87. },
  88. pop: function(count, outDuration, inDuration) {
  89. outDuration = (outDuration == undefined) ? 0.5 : outDuration;
  90. inDuration = (inDuration == undefined) ? outDuration : inDuration;
  91. count = count || 1;
  92. var scenes = [];
  93. for(var i = 0; i < count; ++i) {
  94. scenes.push(this.sceneStack.pop());
  95. }
  96. var promise = scenes.reduce(function(acc, scene) {
  97. return Q.when(acc, scene.unload());
  98. }, Q());
  99. var self = this;
  100. Q.all([this.fadeOut(outDuration), promise]).then(function() {
  101. if(self.sceneStack.length > 0) {
  102. self.currentScene = self.sceneStack[self.sceneStack.length-1];
  103. self.currentScene.resume();
  104. self.fadeIn(inDuration);
  105. }
  106. else {
  107. self.currentScene = null;
  108. }
  109. });
  110. },
  111. fadeIn: function(duration) {
  112. var self = this
  113. this.promise = this.promise.then(function() {
  114. self.tween = tweenFrom(1).to(0, duration).animate();
  115. return self.tween.promise;
  116. });
  117. return this.promise;
  118. },
  119. fadeOut: function(duration) {
  120. var self = this;
  121. this.promise = this.promise.then(function() {
  122. self.tween = tweenFrom(0).to(1, duration).animate();
  123. return self.tween.promise;
  124. });
  125. return this.promise;
  126. },
  127. drawFade: function() {
  128. if(this.tween && this.promise.isPending()) {
  129. Game.context.globalAlpha = this.tween.value;
  130. Game.context.fillStyle = 'black';
  131. Game.context.fillRect(0, 0, Game.canvas.width, Game.canvas.height);
  132. Game.context.globalAlpha = 1;
  133. }
  134. }
  135. }
  136. };
  137. function Scene() {}
  138. Scene.prototype._init = function() {
  139. makeObservable(this);
  140. };
  141. Scene.prototype._update = function(dt) {
  142. this.notify(dt);
  143. this.update(dt);
  144. };
  145. Scene.prototype._draw = function() {
  146. this.draw();
  147. };
  148. Scene.prototype.tween = function(from) {
  149. var tween = new DeferredTween(from);
  150. tween.ticker = this.ticker;
  151. return tween;
  152. };
  153. Scene.prototype.update = function() {};
  154. Scene.prototype.draw = function() {};
  155. Scene.prototype.load = function() {};
  156. Scene.prototype.unload = function() {};
  157. Scene.prototype.resume = function() {};
  158. Scene.prototype.pause = function() {};
  159. var SplashScreen = new Scene();
  160. (function() {
  161. var ctx = Game.context;
  162. var x = Game.canvas.width / 2;
  163. var y = Game.canvas.height / 2;
  164. var position = {x: x, y: y};
  165. var RADIUS = 8;
  166. var RIPPLE_SIZE = 10;
  167. var RIPPLE_SPEED = 10;
  168. var rippleCounter = 0;
  169. SplashScreen.color = function(p) {
  170. return color(255, 255, 255, p);
  171. };
  172. SplashScreen.update = function(dt) {
  173. rippleCounter += RIPPLE_SPEED * dt;
  174. if(rippleCounter > RIPPLE_SIZE) {
  175. rippleCounter = 0;
  176. }
  177. };
  178. SplashScreen.draw = function() {
  179. ctx.fillStyle = 'black';
  180. ctx.fillRect(0, 0, Game.canvas.width, Game.canvas.height);
  181. ctx.fillStyle = 'white';
  182. drawCircle(position, RADIUS, 3, this.color(1));
  183. drawCircle(position, 2, 3, this.color(1));
  184. // ripples
  185. var p = lerp(1, 0, ease(rippleCounter/RIPPLE_SIZE));
  186. drawCircle(position, RADIUS+7+rippleCounter, 1, this.color(p));
  187. drawCircle(position, RADIUS+4+rippleCounter, 1, this.color(p*0.8));
  188. drawCircle(position, RADIUS+1+rippleCounter, 1, this.color(p*0.5));
  189. };
  190. })();
  191. var MainMenu = new Scene();
  192. (function() {
  193. var ctx = Game.context;
  194. var canvasW = Game.canvas.width;
  195. var canvasH = Game.canvas.height;
  196. var selected = 0;
  197. var alternate = false;
  198. var notYetDone = {
  199. name: '???',
  200. alt: '???',
  201. start: function() {}
  202. };
  203. var games = [
  204. {
  205. name: 'sound safari',
  206. alt: 'sound catcher',
  207. start: function() {
  208. var beats = [
  209. {url: 'sound/b1.mp3', duration: 4000},
  210. {url: 'sound/b2.mp3', duration: 4000},
  211. {url: 'sound/b3.mp3', duration: 4000},
  212. {url: 'sound/b4.mp3', duration: 4000},
  213. {url: 'sound/b5.mp3', duration: 4000}
  214. ];
  215. Game.sceneManager.push(new SoundSafari(beats));
  216. }
  217. },
  218. notYetDone,
  219. notYetDone,
  220. notYetDone,
  221. notYetDone,
  222. notYetDone,
  223. notYetDone
  224. ];
  225. function onKeyUp(e) {
  226. switch(e.keyCode) {
  227. case 66:
  228. alternate = !alternate;
  229. document.title = alternate ? 'SoundVoyager' : 'audventure';
  230. break;
  231. case 38:
  232. e.preventDefault();
  233. soundManager.play('cursor');
  234. selected = (selected + games.length -1) % games.length;
  235. break;
  236. case 40:
  237. e.preventDefault();
  238. soundManager.play('cursor');
  239. selected = (selected + 1) % games.length;
  240. break;
  241. case 32:
  242. e.preventDefault();
  243. case 13:
  244. soundManager.play('confirm');
  245. games[selected].start();
  246. }
  247. }
  248. MainMenu.update = function() {};
  249. MainMenu.draw = function() {
  250. ctx.fillStyle = 'black';
  251. ctx.fillRect(0, 0, canvasW, canvasH);
  252. ctx.fillStyle = 'white';
  253. ctx.textAlign = 'center';
  254. var canvasWM = canvasW/2;
  255. var canvasHM = canvasH/2;
  256. ctx.font = font(48);
  257. ctx.fillText(alternate ? 'SoundVoyager' : 'audventure', canvasWM, canvasHM - 50);
  258. ctx.font = font(16);
  259. games.forEach(function(game, index) {
  260. var y = canvasHM + 10 + index * 25;
  261. var name = alternate ? game.alt : game.name;
  262. ctx.fillText(name, canvasWM, y);
  263. if(index == selected) {
  264. var offset = ctx.measureText(name).width / 2 + 10;
  265. drawTriangle(canvasWM - offset, y - 5, 10, 7);
  266. drawTriangle(canvasWM + offset, y - 5, 10, -7);
  267. }
  268. });
  269. };
  270. MainMenu.load = MainMenu.resume = function() {
  271. addEventListener('keydown', onKeyUp);
  272. };
  273. MainMenu.unload = MainMenu.pause = function() {
  274. removeEventListener('keydown', onKeyUp);
  275. };
  276. })();
  277. var PauseScreen = new Scene();
  278. (function() {
  279. var onKeyUp = function(e) {
  280. switch(e.charCode) {
  281. case 81:
  282. case 113:
  283. case 27:
  284. Game.sceneManager.pop(2);
  285. soundManager.play('back');
  286. break;
  287. case 80:
  288. case 112:
  289. case 32:
  290. Game.sceneManager.pop(1, 0);
  291. soundManager.play('back');
  292. }
  293. };
  294. PauseScreen.load = PauseScreen.resume = function() {
  295. addEventListener('keypress', onKeyUp);
  296. };
  297. PauseScreen.unload = PauseScreen.pause = function() {
  298. removeEventListener('keypress', onKeyUp);
  299. };
  300. PauseScreen.update = function() {};
  301. PauseScreen.draw = function() {
  302. Game.context.fillStyle = 'black';
  303. Game.context.fillRect(0, 0, Game.canvas.width, Game.canvas.height);
  304. Game.context.fillStyle = 'white';
  305. Game.context.textAlign = 'center';
  306. Game.context.fillText('Paused', Game.canvas.width/2, Game.canvas.height/2 - 30);
  307. Game.context.fillText('P to unpause', Game.canvas.width/2, Game.canvas.height/2);
  308. Game.context.fillText('Q to quit', Game.canvas.width/2, Game.canvas.height/2 + 20);
  309. Game.context.textAlign = 'left';
  310. };
  311. })();
  312. Game.start();