PageRenderTime 60ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/js/script.js

https://github.com/mathphreak/Zrczr
JavaScript | 342 lines | 293 code | 16 blank | 33 comment | 41 complexity | cbaaec002de9764856979e4ded90f7ed MD5 | raw file
  1. var Coordinate = goog.math.Coordinate;
  2. var Vector = goog.math.Vec2;
  3. var cos = Math.cos;
  4. var sin = Math.sin;
  5. var Zrczr = {};
  6. Zrczr.App = {};
  7. Zrczr.App.Backgrounds = {};
  8. Zrczr.Models = {};
  9. var conv = function(corv) {
  10. // corv is a Coordinate or a Vector.
  11. if (corv.constructor === Coordinate) {
  12. // we want a Vector
  13. return new Vector(corv.x, corv.y);
  14. } else if (corv.constructor === Vector) {
  15. // we want a Coordinate
  16. return new Coordinate(corv.x, corv.y);
  17. }
  18. }
  19. Zrczr.App.Server = {
  20. setup: function() {
  21. return {
  22. locX: 0,
  23. locY: 0
  24. }
  25. }
  26. };
  27. Zrczr.Models.Background = Backbone.Model.extend({
  28. draw: function(context) {
  29. this.get("draw").call(this, context);
  30. },
  31. move: function(context) {}
  32. });
  33. Zrczr.Models.World = Backbone.Model.extend({
  34. initialize: function() {
  35. if (!this.get("walls")) { // assume that everything else is missing, too
  36. function makeCollection(model) {
  37. var a = Backbone.Collection.extend({
  38. model: model
  39. });
  40. return new a();
  41. }
  42. this.set({
  43. walls: makeCollection(Zrczr.Models.Wall),
  44. bullets: makeCollection(Zrczr.Models.Bullet)
  45. });
  46. }
  47. this.iterator = function(functor) {
  48. var funcargs = _.toArray(arguments).slice(1);
  49. return function(i) {
  50. i[functor].apply(i, funcargs);
  51. };
  52. }
  53. },
  54. draw: function(context) {
  55. var drawIt = this.iterator('draw', context);
  56. var me = this.get("me");
  57. context.save();
  58. context.translate(context.canvas.width / 2, context.canvas.height / 2);
  59. // context.rotate(-me.get("rotation"));
  60. context.translate(-me.get("location").x, -me.get("location").y);
  61. Zrczr.App.Background.draw(context);
  62. this.get("walls").each(drawIt);
  63. this.get("bullets").each(drawIt);
  64. me.draw(context);
  65. context.restore();
  66. },
  67. move: function() {
  68. var moveIt = this.iterator('move');
  69. this.get("walls").each(moveIt);
  70. this.get("bullets").each(moveIt);
  71. if (!!this.get("me")) this.get("me").move();
  72. },
  73. die: function() {
  74. $("#canvas").explode();
  75. },
  76. checkWalls: function() {
  77. var me = this.get("me");
  78. return _.any(this.get("walls").map(function(w) {
  79. return collisionDetection(me, w);
  80. }));
  81. },
  82. checkBullets: function() {
  83. var me = this.get("me");
  84. return _.any(this.get("bullets").map(function(w) {
  85. return collisionDetection(me, w);
  86. }));
  87. }
  88. });
  89. Zrczr.Models.Person = Backbone.Model.extend({
  90. initialize: function() {
  91. var srv = Zrczr.App.Server.setup();
  92. var loc = new Coordinate(srv.locX, srv.locY);
  93. var rot = amplify.store("rotation");
  94. if (!rot) {
  95. rot = (Math.random() * 2 * Math.PI);
  96. }
  97. var siz = amplify.store("size");
  98. if (!siz) {
  99. siz = 5;
  100. amplify.store("size", siz);
  101. }
  102. this.set({
  103. location: loc,
  104. rotation: rot,
  105. size: siz
  106. });
  107. },
  108. draw: function(context) {
  109. context.save();
  110. var loc = this.get("location");
  111. context.translate(loc.x, loc.y);
  112. context.rotate(this.get("rotation"));
  113. context.fillStyle = "black";
  114. var size = this.get("size");
  115. context.beginPath();
  116. context.moveTo(-size, size);
  117. context.lineTo(size, size);
  118. context.lineTo(size, -size);
  119. context.lineTo(-size, -size);
  120. context.closePath();
  121. context.fill();
  122. context.fillStyle = "white";
  123. context.beginPath();
  124. context.moveTo(size - 1, 0);
  125. context.lineTo(size - 1, -size + 1);
  126. context.lineTo(0, -size + 1);
  127. context.closePath();
  128. context.fill();
  129. context.beginPath();
  130. context.moveTo(-size + 1, 0);
  131. context.lineTo(-size + 1, -size + 1);
  132. context.lineTo(0, -size + 1);
  133. context.closePath();
  134. context.fill();
  135. context.restore();
  136. },
  137. move: function() {
  138. var k = Backbone.Keyboard.status;
  139. var loc = this.get("location");
  140. var rotation = this.get("rotation");
  141. hitWall = Zrczr.App.World.checkWalls();
  142. if (k.up && !hitWall) {
  143. var vec = new Vector(sin(rotation), -cos(rotation));
  144. loc = Coordinate.sum(loc, vec);
  145. }
  146. if (k.left) {
  147. rotation -= Math.PI / 20;
  148. } else if (k.right) {
  149. rotation += Math.PI / 20;
  150. } else if (k.down) {
  151. rotation += Math.PI;
  152. k.down = false;
  153. }
  154. this.set({
  155. location: loc,
  156. rotation: rotation
  157. });
  158. if (k.drop && !this.justDropped) {
  159. Zrczr.App.World.get("walls").add({
  160. parent: this
  161. });
  162. this.justDropped = true;
  163. } else if (!k.drop) {
  164. this.justDropped = false;
  165. }
  166. amplify.store("rotation", rotation);
  167. }
  168. });
  169. Zrczr.Models.Wall = Backbone.Model.extend({
  170. initialize: function() {
  171. var parent = this.get("parent");
  172. var loc = parent.get("location");
  173. var rotation = parent.get("rotation");
  174. var parentMovement = new Vector(sin(rotation), -cos(rotation));
  175. var size = parent.get("size");
  176. this.set({
  177. location: Coordinate.difference(loc, parentMovement.scale(size*2 + 2)),
  178. rotation: rotation,
  179. size: size
  180. });
  181. },
  182. draw: function(context) {
  183. var loc = this.get("location");
  184. var rot = this.get("rotation");
  185. var size = this.get("size");
  186. var size2 = 2*size;
  187. context.save();
  188. context.translate(loc.x, loc.y);
  189. context.rotate(rot);
  190. context.fillStyle = "black";
  191. context.beginPath();
  192. context.moveTo(-size, -size);
  193. context.lineTo(-size, size);
  194. context.lineTo(size, size);
  195. context.lineTo(size, -size);
  196. context.closePath();
  197. context.fill();
  198. context.restore();
  199. },
  200. move: function() {}
  201. });
  202. Zrczr.App.Backgrounds.Empty = new Zrczr.Models.Background({
  203. draw: function() {}
  204. });
  205. Zrczr.App.Backgrounds.Axes = new Zrczr.Models.Background({
  206. draw: function(context) {
  207. context.strokeStyle = "red"; // x
  208. context.beginPath();
  209. context.moveTo(-context.canvas.width, 0);
  210. context.lineTo(context.canvas.width, 0);
  211. context.stroke();
  212. context.strokeStyle = "green"; // y
  213. context.beginPath();
  214. context.moveTo(0, -context.canvas.height);
  215. context.lineTo(0, context.canvas.height);
  216. context.stroke();
  217. }
  218. });
  219. Zrczr.App.Backgrounds.Grid = new Zrczr.Models.Background({
  220. draw: function(context) {
  221. var limit = 20;
  222. // draw axes
  223. Zrczr.App.Backgrounds.Axes.draw(context);
  224. context.strokeStyle = "silver";
  225. var width = context.canvas.width;
  226. var height = context.canvas.height;
  227. for (var i = -limit; i < limit; i++) {
  228. // draw horizontal axis
  229. context.beginPath();
  230. context.moveTo(-width, i*(height/limit));
  231. context.lineTo(width, i*(height/limit));
  232. context.stroke();
  233. // draw vertical axis
  234. context.beginPath();
  235. context.moveTo(i*(width/limit), -height);
  236. context.lineTo(i*(width/limit), height);
  237. context.stroke();
  238. }
  239. }
  240. });
  241. function collisionDetection(objA, objB) {
  242. var aLoc = (_.isFunction(objA.get) && objA.get("location") !== undefined) ? objA.get("location") : objA.location;
  243. var bLoc = (_.isFunction(objB.get) && objB.get("location") !== undefined) ? objB.get("location") : objB.location;
  244. var aRot = (_.isFunction(objA.get) && objA.get("rotation") !== undefined) ? objA.get("rotation") : objA.rotation;
  245. var bRot = (_.isFunction(objB.get) && objB.get("rotation") !== undefined) ? objB.get("rotation") : objB.rotation;
  246. var aSize = (_.isFunction(objA.get) && objA.get("size") !== undefined) ? objA.get("size") : objA.size;
  247. var bSize = (_.isFunction(objB.get) && objB.get("size") !== undefined) ? objB.get("size") : objB.size;
  248. var difference = Coordinate.difference(aLoc, bLoc);
  249. var distSquared = Coordinate.squaredDistance(aLoc, bLoc);
  250. var distX = Math.abs(difference.x);
  251. var distY = Math.abs(difference.y);
  252. var totalSize = aSize + bSize;
  253. if (distX < totalSize && distY < totalSize) {
  254. // we're awfully close...but we don't know for sure yet.
  255. var aVec = new Vector(sin(aRot), -cos(aRot));
  256. var nextALoc = Coordinate.sum(aLoc, aVec);
  257. return Coordinate.squaredDistance(nextALoc, bLoc) < distSquared;
  258. } else if (distX == distY == totalSize) {
  259. // we have the non-collision:
  260. /* +---+
  261. * | A |
  262. * +---+
  263. * +---+
  264. * | B |
  265. * +---+
  266. */
  267. return false;
  268. } else if (distX == totalSize || distY == totalSize) {
  269. // we have the not-quite-collision:
  270. /* +---+
  271. * | A | ->
  272. * +---+
  273. * +---+
  274. * | B |
  275. * +---+
  276. */
  277. // or we could have the just-barely-collision:
  278. /* +---++---+
  279. * ->| A || B |
  280. * +---++---+
  281. */
  282. // either way, we can just wait for the next step and see if there's a collision then.
  283. // but actually, this doesn't work, so we have to do things the hard way.
  284. var aVec = new Vector(sin(aRot), -cos(aRot));
  285. var nextALoc = Coordinate.sum(aLoc, aVec);
  286. return Coordinate.squaredDistance(nextALoc, bLoc) < distSquared;
  287. } else if (distX > totalSize || distY > totalSize) {
  288. // we've got plenty of space between A and B...
  289. return false;
  290. } else {
  291. // there's no way in heck this is possible...
  292. throw new Error("Logical contradiction in collisionDetection()");
  293. }
  294. }
  295. function canvasWorks(canvas) {
  296. var context = canvas.getContext("2d");
  297. function update() {
  298. Zrczr.App.World.move();
  299. context.clearRect(0, 0, context.canvas.width, context.canvas.height);
  300. Zrczr.App.World.draw(context);
  301. Zrczr.App.FPSStats.update();
  302. Zrczr.App.MSStats.update();
  303. requestAnimFrame(update, $("#canvas")[0]);
  304. }
  305. update();
  306. }
  307. $(function(){
  308. Backbone.Keyboard.bindArrowWASD();
  309. Backbone.Keyboard.keyMeans(' '.charCodeAt(0), 'drop');
  310. Zrczr.App.Background = Zrczr.App.Backgrounds.Grid;
  311. Zrczr.App.World = new Zrczr.Models.World();
  312. Zrczr.App.World.set({
  313. me: new Zrczr.Models.Person()
  314. });
  315. Zrczr.App.FPSStats = new Stats();
  316. Zrczr.App.FPSStats.domElement.style.position = 'relative';
  317. Zrczr.App.MSStats = new Stats();
  318. Zrczr.App.MSStats.domElement.style.position = 'relative';
  319. Zrczr.App.MSStats.show('ms');
  320. $("header").append(Zrczr.App.FPSStats.domElement);
  321. $("header").append(Zrczr.App.MSStats.domElement);
  322. var canvas = document.getElementById("canvas");
  323. if (canvas.getContext) {
  324. canvasWorks(canvas);
  325. }
  326. });