Guest User

Snake Game

a guest
May 5th, 2017
1,438
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.63 KB | None | 0 0
  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Simple Snake Game</title>
  6.  
  7. <!-- Basic styling, centering of the canvas. -->
  8. <style>
  9. canvas {
  10. display: block;
  11. position: absolute;
  12. border: 1px solid #000;
  13. margin: auto;
  14. top: 0;
  15. bottom: 0;
  16. right: 0;
  17. left: 0;
  18. }
  19. </style>
  20. </head>
  21. <body>
  22. <script>
  23. var
  24.  
  25. /**
  26. * Constante
  27. */
  28. COLS = 26,
  29. ROWS = 26,
  30.  
  31. EMPTY = 0,
  32. SNAKE = 1,
  33. FRUIT = 2,
  34.  
  35. LEFT = 0,
  36. UP = 1,
  37. RIGHT = 2,
  38. DOWN = 3,
  39.  
  40. KEY_LEFT = 37,
  41. KEY_UP = 38,
  42. KEY_RIGHT = 39,
  43. KEY_DOWN = 40,
  44.  
  45.  
  46. /**
  47. * Game objects
  48. */
  49. canvas, /* HTMLCanvas */
  50. ctx, /* CanvasRenderingContext2d */
  51. keystate, /* keyboard inputs */
  52. frames, /* used for animation */
  53. score; /* keep track of the player score */
  54.  
  55.  
  56. /**
  57. * Grid datastructor, usefull in games where the game world is
  58. * confined in absolute sized chunks of data or information.
  59. *
  60. * @type {Object}
  61. */
  62. grid = {
  63.  
  64. width: null, /* number, the number of columns */
  65. height: null, /* number, the number of rows */
  66. _grid: null, /* Array<any>, data representation */
  67.  
  68. /**
  69. * Initiate and fill a c x r grid with the value of d
  70. * @param {any} d default value to fill with
  71. * @param {number} c number of columns
  72. * @param {number} r number of rows
  73. */
  74. init: function(d, c, r) {
  75. this.width = c;
  76. this.height = r;
  77.  
  78. this._grid = [];
  79. for (var x=0; x < c; x++) {
  80. this._grid.push([]);
  81. for (var y=0; y < r; y++) {
  82. this._grid[x].push(d);
  83. }
  84. }
  85. },
  86.  
  87. /**
  88. * Set the value of the grid cell at (x, y)
  89. *
  90. * @param {any} val what to set
  91. * @param {number} x the x-coordinate
  92. * @param {number} y the y-coordinate
  93. */
  94. set: function(val, x, y) {
  95. this._grid[x][y] = val;
  96. },
  97.  
  98. /**
  99. * Get the value of the cell at (x, y)
  100. *
  101. * @param {number} x the x-coordinate
  102. * @param {number} y the y-coordinate
  103. * @return {any} the value at the cell
  104. */
  105. get: function(x, y) {
  106. return this._grid[x][y];
  107. }
  108. }
  109. /**
  110. * FUNCTION TO PAUSE THE Game
  111. *
  112. */
  113. function pauseGame() {
  114. game = clearTimeout(game);
  115. }
  116.  
  117. function keyDown(e) {
  118. if (e.keyCode == 80) pauseGame();
  119. }
  120.  
  121. function pauseGame() {
  122. if (!gamePaused) {
  123. game = clearTimeout(game);
  124. gamePaused = true;
  125. } else if (gamePaused) {
  126. game = setTimeout(loop, 1000 / 30);
  127. gamePaused = false;
  128. }
  129. }
  130.  
  131.  
  132.  
  133.  
  134. /****PAUSE GAME FUNCTIONS END*****/
  135. /**
  136. * The snake, works as a queue (FIFO, first in first out) of data
  137. * with all the current positions in the grid with the snake id
  138. *
  139. * @type {Object}
  140. */
  141. snake = {
  142.  
  143. direction: null, /* number, the direction */
  144. last: null, /* Object, pointer to the last element in
  145. the queue */
  146. _queue: null, /* Array<number>, data representation*/
  147.  
  148. /**
  149. * Clears the queue and sets the start position and direction
  150. *
  151. * @param {number} d start direction
  152. * @param {number} x start x-coordinate
  153. * @param {number} y start y-coordinate
  154. */
  155. init: function(d, x, y) {
  156. this.direction = d;
  157.  
  158. this._queue = [];
  159. this.insert(x, y);
  160. },
  161.  
  162. /**
  163. * Adds an element to the queue
  164. *
  165. * @param {number} x x-coordinate
  166. * @param {number} y y-coordinate
  167. */
  168. insert: function(x, y) {
  169. // unshift prepends an element to an array
  170. this._queue.unshift({x:x, y:y});
  171. this.last = this._queue[0];
  172. },
  173.  
  174. /**
  175. * Removes and returns the first element in the queue.
  176. *
  177. * @return {Object} the first element
  178. */
  179. remove: function() {
  180. // pop returns the last element of an array
  181. return this._queue.pop();
  182. }
  183. };
  184.  
  185. /**
  186. * Set a food id at a random free cell in the grid
  187. */
  188. function setFood() {
  189. var empty = [];
  190. // iterate through the grid and find all empty cells
  191. for (var x=0; x < grid.width; x++) {
  192. for (var y=0; y < grid.height; y++) {
  193. if (grid.get(x, y) === EMPTY) {
  194. empty.push({x:x, y:y});
  195. }
  196. }
  197. }
  198. // chooses a random cell
  199. var randpos = empty[Math.round(Math.random()*(empty.length - 1))];
  200. grid.set(FRUIT, randpos.x, randpos.y);
  201. }
  202.  
  203. /**
  204. * Starts the game
  205. */
  206. function main() {
  207. // create and initiate the canvas element
  208. canvas = document.createElement("canvas");
  209. canvas.width = COLS*20;
  210. canvas.height = ROWS*20;
  211. ctx = canvas.getContext("2d");
  212. // add the canvas element to the body of the document
  213. document.body.appendChild(canvas);
  214.  
  215. // sets an base font for bigger score display
  216. ctx.font = "15px Helvetica";
  217.  
  218. frames = 0;
  219. keystate = {};
  220. // keeps track of the keybourd input
  221. document.addEventListener("keydown", function(evt) {
  222. keystate[evt.keyCode] = true;
  223. });
  224. document.addEventListener("keyup", function(evt) {
  225. delete keystate[evt.keyCode];
  226. });
  227.  
  228. // intatiate game objects and starts the game loop
  229. init();
  230. loop();
  231. }
  232.  
  233. /**
  234. * Resets and inits game objects
  235. */
  236. function init() {
  237. score = 0;
  238.  
  239. grid.init(EMPTY, COLS, ROWS);
  240.  
  241. var sp = {x:Math.floor(COLS/2), y:ROWS-1};
  242. snake.init(UP, sp.x, sp.y);
  243. grid.set(SNAKE, sp.x, sp.y);
  244.  
  245. setFood();
  246. }
  247.  
  248. /**
  249. * The game loop function, used for game updates and rendering
  250. */
  251. function loop() {
  252. update();
  253. draw();
  254. // When ready to redraw the canvas call the loop function
  255. // first. Runs about 60 frames a second
  256. window.requestAnimationFrame(loop, canvas);
  257. }
  258.  
  259. /**
  260. * Updates the game logic
  261. */
  262. function update() {
  263. frames++;
  264.  
  265. // changing direction of the snake depending on which keys
  266. // that are pressed
  267. if (keystate[KEY_LEFT] && snake.direction !== RIGHT) {
  268. snake.direction = LEFT;
  269. }
  270. if (keystate[KEY_UP] && snake.direction !== DOWN) {
  271. snake.direction = UP;
  272. }
  273. if (keystate[KEY_RIGHT] && snake.direction !== LEFT) {
  274. snake.direction = RIGHT;
  275. }
  276. if (keystate[KEY_DOWN] && snake.direction !== UP) {
  277. snake.direction = DOWN;
  278. }
  279.  
  280. // each five frames update the game state.
  281. if (frames%5 === 0) {
  282. // pop the last element from the snake queue i.e. the
  283. // head
  284. var nx = snake.last.x;
  285. var ny = snake.last.y;
  286.  
  287. // updates the position depending on the snake direction
  288. switch (snake.direction) {
  289. case LEFT:
  290. nx--;
  291. break;
  292. case UP:
  293. ny--;
  294. break;
  295. case RIGHT:
  296. nx++;
  297. break;
  298. case DOWN:
  299. ny++;
  300. break;
  301. }
  302.  
  303. // checks all gameover conditions
  304. if (0 > nx || nx > grid.width-1 ||
  305. 0 > ny || ny > grid.height-1 ||
  306. grid.get(nx, ny) === SNAKE
  307. ) {
  308. return init();
  309. }
  310.  
  311. // check wheter the new position are on the fruit item
  312. if (grid.get(nx, ny) === FRUIT) {
  313. // increment the score and sets a new fruit position
  314. score++;
  315. setFood();
  316. } else {
  317. // take out the first item from the snake queue i.e
  318. // the tail and remove id from grid
  319. var tail = snake.remove();
  320. grid.set(EMPTY, tail.x, tail.y);
  321. }
  322.  
  323. // add a snake id at the new position and append it to
  324. // the snake queue
  325. grid.set(SNAKE, nx, ny);
  326. snake.insert(nx, ny);
  327. }
  328. }
  329.  
  330. /**
  331. * Render the grid to the canvas.
  332. */
  333. function draw() {
  334. // calculate tile-width and -height
  335. var tw = canvas.width/grid.width;
  336. var th = canvas.height/grid.height;
  337. // iterate through the grid and draw all cells
  338. for (var x=0; x < grid.width; x++) {
  339. for (var y=0; y < grid.height; y++) {
  340. // sets the fillstyle depending on the id of
  341. // each cell
  342. switch (grid.get(x, y)) {
  343. case EMPTY:
  344. ctx.fillStyle = "#fff";
  345. break;
  346. case SNAKE:
  347. ctx.fillStyle = "#038423";
  348. break;
  349. case FRUIT:
  350. ctx.fillStyle = "#f00";
  351. break;
  352. }
  353. ctx.fillRect(x*tw, y*th, tw, th);
  354. }
  355. }
  356. // changes the fillstyle once more and draws the score
  357. // message to the canvas
  358. ctx.fillStyle = "#000";
  359. ctx.fillText("SCORE: " + score, 10, canvas.height-10);
  360. }
  361.  
  362. // start and run the game
  363. main();
  364. </script>
  365. </body>
  366. </html>
Add Comment
Please, Sign In to add comment