game.js 8.6 KB

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