├── CNAME
├── README.md
├── pacman
├── data
│ └── map.png
├── images
│ ├── 32_dot.png
│ ├── 32_player_close.png
│ ├── 32_player_open.png
│ ├── bg_center.png
│ ├── bg_down.png
│ ├── bg_left.png
│ ├── bg_right.png
│ ├── bg_up.png
│ └── enemy_red.png
├── index.html
└── js
│ ├── ai.js
│ ├── assets.js
│ ├── collision.js
│ ├── controls.js
│ ├── draw.js
│ ├── game.js
│ ├── objects.js
│ ├── objectsLoad.js
│ ├── update.js
│ └── utils.js
├── snake
├── data
│ └── map.png
├── index.html
└── js
│ ├── controls.js
│ ├── draw.js
│ ├── framework.js
│ ├── logic.js
│ └── utils.js
└── space-invaders
├── enemies.json
├── images
├── 32_enemy.png
├── 32_laser_blue.png
├── 32_laser_red.png
├── 32_player.png
├── 64_1.png
├── 64_2.png
├── 64_laser_blue.png
├── 64_laser_red.png
└── background.png
├── index.html
└── js
├── ai.js
├── assets.js
├── controls.js
├── draw.js
├── game.js
├── objects.js
├── update.js
└── utils.js
/CNAME:
--------------------------------------------------------------------------------
1 | 404.coconauts.net
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | A collection of simple 404-themed games made with
2 | [canvas](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial).
3 | Ideal to embed in your 404 page!
4 | As seen on [coconauts.net](http://coconauts.net/404).
5 |
6 | ## How to embed them in a page
7 |
8 | Copy the folder for your desired game, and then use an `iframe`
9 | pointing to the relative path of that folder.
10 |
11 |
13 |
14 | ## I can't decide, can't I have a random one every time?
15 |
16 | Then you'll need a little js snippet:
17 |
18 | ```
19 | var randomBetween = function(f, to){
20 | return Math.floor(Math.random() * to) + f;
21 | }
22 | var randomGame = function(){
23 | var games = ["pacman", "space-invaders", "snake"];
24 | var randomGame = randomBetween(0,games.length);
25 | return games[randomGame];
26 | }
27 | var src = "path/to/games/folder/" + randomGame();
28 | document.getElementById('404-game').src = src;
29 | ```
30 |
31 | Have fun!
32 |
--------------------------------------------------------------------------------
/pacman/data/map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coconauts/404-games/c8096c8ab65e66312bc64496deaae90de82037df/pacman/data/map.png
--------------------------------------------------------------------------------
/pacman/images/32_dot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coconauts/404-games/c8096c8ab65e66312bc64496deaae90de82037df/pacman/images/32_dot.png
--------------------------------------------------------------------------------
/pacman/images/32_player_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coconauts/404-games/c8096c8ab65e66312bc64496deaae90de82037df/pacman/images/32_player_close.png
--------------------------------------------------------------------------------
/pacman/images/32_player_open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coconauts/404-games/c8096c8ab65e66312bc64496deaae90de82037df/pacman/images/32_player_open.png
--------------------------------------------------------------------------------
/pacman/images/bg_center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coconauts/404-games/c8096c8ab65e66312bc64496deaae90de82037df/pacman/images/bg_center.png
--------------------------------------------------------------------------------
/pacman/images/bg_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coconauts/404-games/c8096c8ab65e66312bc64496deaae90de82037df/pacman/images/bg_down.png
--------------------------------------------------------------------------------
/pacman/images/bg_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coconauts/404-games/c8096c8ab65e66312bc64496deaae90de82037df/pacman/images/bg_left.png
--------------------------------------------------------------------------------
/pacman/images/bg_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coconauts/404-games/c8096c8ab65e66312bc64496deaae90de82037df/pacman/images/bg_right.png
--------------------------------------------------------------------------------
/pacman/images/bg_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coconauts/404-games/c8096c8ab65e66312bc64496deaae90de82037df/pacman/images/bg_up.png
--------------------------------------------------------------------------------
/pacman/images/enemy_red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coconauts/404-games/c8096c8ab65e66312bc64496deaae90de82037df/pacman/images/enemy_red.png
--------------------------------------------------------------------------------
/pacman/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 404 Pacman
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/pacman/js/ai.js:
--------------------------------------------------------------------------------
1 | var updateEnemies = function(modifier){
2 |
3 | for (var i= 0; i < enemies.length; i++){
4 | var enemy = enemies[i];
5 | if (isCollidingBlocks(enemy,enemy.direction)){
6 | changeDirection(enemy);
7 |
8 | } else {
9 | move(enemy, modifier);
10 | }
11 | }
12 | }
13 |
14 | var changeDirection = function(enemy){
15 | var tol = p(-5,0);
16 | var randomDirection = randomBetween(0, 3);
17 | switch(randomDirection){
18 | case 0: if (!isCollidingBlocks(enemy, LEFT, tol)) enemy.direction = LEFT;break;
19 | case 1: if (!isCollidingBlocks(enemy, RIGHT, tol)) enemy.direction = RIGHT;break;
20 | case 2: if (!isCollidingBlocks(enemy, UP, tol)) enemy.direction = UP;break;
21 | default: if (!isCollidingBlocks(enemy, DOWN, tol)) enemy.direction = DOWN;break;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/pacman/js/assets.js:
--------------------------------------------------------------------------------
1 | var setImage = function(img){
2 | var i = new Image();
3 | i.src = img;
4 | return i;
5 | };
6 |
7 | // Hero image
8 | var playerImageClose = setImage("images/32_player_close.png");
9 | var playerImageOpen = setImage("images/32_player_open.png");
10 |
11 | var monsterImage = setImage("images/enemy_red.png");
12 |
13 | var dotImage = setImage("images/32_dot.png");
14 |
15 | var backgroundImage = {};
16 | backgroundImage.center = setImage("images/bg_center.png");
17 | backgroundImage.left = setImage("images/bg_left.png");
18 | backgroundImage.right = setImage("images/bg_right.png");
19 | backgroundImage.down = setImage("images/bg_down.png");
20 | backgroundImage.up = setImage("images/bg_up.png");
21 |
--------------------------------------------------------------------------------
/pacman/js/collision.js:
--------------------------------------------------------------------------------
1 | //http://gamedev.stackexchange.com/questions/13774/how-do-i-detect-the-direction-of-2d-rectangular-object-collisions
2 | var collision = new Collision();
3 |
4 | var RIGHT = { x: 1, y: 0};
5 | var LEFT = { x: -1, y: 0};
6 | var UP = { x: 0, y: -1};
7 | var DOWN = { x: 0, y: 1};
8 |
9 | function Collision(){
10 |
11 | this.onCollisionChange = function(ojb1, obj2, size, callback) {
12 | var isColliding = false;
13 | setInterval(
14 | function(){
15 | var beforeStatus = isColliding;
16 | isColliding = collision(obj1, obj2, size);
17 | if (beforeStatus != isColliding) callback();
18 | }, 100);
19 | }
20 |
21 | this.isCollidingDirection = function(obj1, obj2, direction, offset){
22 | switch(direction){
23 | case LEFT: return collision.containsLeft(obj1, obj2, SIZE, offset); break;
24 | case RIGHT: return collision.containsRight(obj1, obj2, SIZE, offset); break;
25 | case UP: return collision.containsUp(obj1, obj2, SIZE, offset); break;
26 | case DOWN: return collision.containsDown(obj1, obj2, SIZE, offset); break;
27 | default: console.log("Undefined direction");
28 | }
29 | }
30 |
31 | this.contains = function(obj, p, size){
32 | var contains = p.x > obj.x && p.x < (obj.x + size) &&
33 | p.y > obj.y && p.y < (obj.y + size);
34 | return contains;
35 | }
36 |
37 | this.collision = function(obj1, obj2, size){
38 | return obj1.x <= (obj2.x + size)
39 | && obj2.x <= (obj1.x + size)
40 | && obj1.y <= (obj2.y + size)
41 | && obj2.y <= (obj1.y + size)
42 | }
43 |
44 | this.containsLeft = function(obj1, obj2, size, offset){
45 | return this.contains(obj1, addCoords(middlePoints(obj2, size).left, offset) , size);
46 | }
47 | this.containsRight = function(obj1, obj2, size, offset){
48 | return this.contains(obj1, addCoords(middlePoints(obj2, size).right, offset), size);
49 | }
50 | this.containsUp = function(obj1, obj2, size, offset){
51 | return this.contains(obj1, addCoords(middlePoints(obj2, size).top, offset), size);
52 | }
53 | this.containsDown = function(obj1, obj2, size, offset){
54 | return this.contains(obj1, addCoords( middlePoints(obj2, size).bottom, offset), size);
55 | }
56 |
57 | var addCoords = function(point, offset) {
58 | return p(point.x + offset.x, point.y + offset.y);
59 | }
60 |
61 | var middlePoints = function(obj, size){
62 | var middleX = (obj.x + obj.x + size) / 2; //(obj.x *2 + size) / 2; ?
63 | var middleY = (obj.y + obj.y + size) / 2;
64 | return {
65 | left: p(obj.x, middleY),
66 | right: p(obj.x + size , middleY),
67 | top: p(middleX, obj.y),
68 | bottom: p(middleX, obj.y + size),
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/pacman/js/controls.js:
--------------------------------------------------------------------------------
1 | // Handle keyboard controls
2 | var keysDown = {};
3 |
4 | var KEY_UP =38, KEY_DOWN =40, KEY_LEFT =37, KEY_RIGHT =39;
5 |
6 | addEventListener("keydown", function (e) {
7 | keysDown[e.keyCode] = true;
8 | }, false);
9 |
10 | addEventListener("keyup", function (e) {
11 | delete keysDown[e.keyCode];
12 | }, false);
13 |
14 |
15 | //Called from update.js
16 | var controls = function(modifier){
17 | if (KEY_LEFT in keysDown && !isCollidingBlocks(player, LEFT, p(-5,0))) player.direction = LEFT;
18 | if (KEY_RIGHT in keysDown && !isCollidingBlocks(player,RIGHT, p(5,0))) player.direction = RIGHT;
19 | if (KEY_UP in keysDown && !isCollidingBlocks(player,UP, p(0,-5))) player.direction = UP;
20 | if (KEY_DOWN in keysDown && !isCollidingBlocks(player,DOWN, p(0,5))) player.direction = DOWN;
21 | }
22 |
--------------------------------------------------------------------------------
/pacman/js/draw.js:
--------------------------------------------------------------------------------
1 | // Create the canvas
2 | var canvas = document.getElementById("canvas");
3 | var ctx = canvas.getContext("2d");
4 |
5 | var SIZE = 32;
6 |
7 | var directionToRotation = function(direction){
8 | switch(direction){
9 | case RIGHT : return 0;
10 | case LEFT: return 180;
11 | case DOWN: return 90;
12 | case UP: return 270;
13 |
14 | }
15 | }
16 | // Draw everything
17 | var render = function () {
18 | // ctx.clearRect(0,0,canvas.width,canvas.height);
19 | /*
20 | if (bgReady) {
21 | ctx.drawImage(bgImage,0 , 0);
22 | }*/
23 | ctx.fillStyle="black";
24 | ctx.fillRect(0,0,canvas.width,canvas.height);
25 |
26 | drawBackground();
27 |
28 | if (!player.dead) {
29 | var image;
30 | if(player.sprite == 0) image = playerImageClose;
31 | else image = playerImageOpen;
32 | //TODO rotate with direction
33 | // ctx.drawImage(image, player.x, player.y, SIZE, SIZE);
34 | var rotation = directionToRotation(player.direction);
35 | drawRotated(image, player.x, player.y, rotation);
36 | }
37 |
38 | for (var i=0; i < dots.length; i++){
39 | var dot = dots[i];
40 | ctx.drawImage(dotImage, dot.x, dot.y ,SIZE, SIZE);
41 | }
42 |
43 | for (var i=0; i < enemies.length; i++){
44 | var enemy = enemies[i];
45 | ctx.drawImage(monsterImage, enemy.x, enemy.y,SIZE, SIZE);
46 |
47 | }
48 | if (false) //DEBUG
49 | for (var i=0; i < blocks.length; i++){
50 | var block = blocks[i];
51 | ctx.drawImage(monsterImage, block.x, block.y ,SIZE, SIZE);
52 | }
53 |
54 |
55 |
56 | if (player.dead){
57 | ctx.fillStyle = "red";
58 | ctx.font = "48px Helvetica";
59 | ctx.textAlign = "center";
60 | ctx.textBaseline = "top";
61 | ctx.fillText("Game Over", canvas.width / 2, canvas.height/ 2);
62 | }
63 | };
64 |
65 | function drawBackground(){
66 | for (var i= 0; i < background.length; i++){
67 | var b = background[i];
68 |
69 | //ctx.drawImage(backgroundImage.center, b.x, b.y ,SIZE, SIZE);
70 | for (var j= 0; j < b.directions.length; j++){
71 | var d = b.directions[j];
72 | ctx.drawImage(backgroundImage[d], b.x, b.y ,SIZE, SIZE);
73 | }
74 | }
75 | }
76 | var TO_RADIANS = Math.PI/180;
77 |
78 | //http://creativejs.com/2012/01/day-10-drawing-rotated-images-into-canvas/
79 | function drawRotated(image, x, y, angle) {
80 | var halfWidth = image.width/2;
81 | var halfHeight = image.height/2;
82 | ctx.save();
83 | ctx.translate(x +halfWidth, y + halfHeight);
84 | ctx.rotate(angle * TO_RADIANS);
85 | ctx.drawImage(image, -halfWidth, -halfHeight);
86 | ctx.restore();
87 | }
88 |
--------------------------------------------------------------------------------
/pacman/js/game.js:
--------------------------------------------------------------------------------
1 | // The main game loop
2 | var main = function () {
3 | var now = Date.now();
4 | var delta = now - then;
5 |
6 | update(delta / 1000);
7 | render();
8 |
9 | then = now;
10 |
11 | // Request to do this again ASAP
12 | requestAnimationFrame(main);
13 | };
14 |
15 | // Cross-browser support for requestAnimationFrame
16 | var w = window;
17 | requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;
18 |
19 | // Let's play this game!
20 | var then = Date.now();
21 | main();
22 |
--------------------------------------------------------------------------------
/pacman/js/objects.js:
--------------------------------------------------------------------------------
1 | // Game objects
2 | var player = {
3 | direction: LEFT,
4 | speed: 100,
5 | sprite: 0
6 | }
7 |
8 | var enemies = [];
9 | var dots = [];
10 | var blocks = [];
11 |
12 | var background = [];
13 |
--------------------------------------------------------------------------------
/pacman/js/objectsLoad.js:
--------------------------------------------------------------------------------
1 | var BLACK = {r: 0, g: 0, b: 0};
2 | var WHITE = {r: 255, g: 255, b: 255};
3 | var YELLOW = {r: 255, g: 255, b: 0};
4 | var GREEN = {r: 0, g: 255, b: 0};
5 | var ORANGE = {r: 255, g: 127, b: 0};
6 | var CYAN = {r: 0, g: 255, b: 255};
7 | var RED = {r: 255, g: 0, b: 0};
8 | var PINK = {r: 255, g: 0, b: 255};
9 |
10 | var addEnemy = function(x, y){
11 | var enemy = {
12 | direction: DOWN,
13 | speed: 100,
14 | x: x,
15 | y: y
16 | };
17 | enemies.push(enemy);
18 | }
19 |
20 | var bg = function(x, y , dirs) {
21 | return {
22 | x: x * SIZE,
23 | y: y * SIZE,
24 | directions: dirs
25 | }
26 | }
27 |
28 | loadImagePixels("data/map.png", function(pixels){
29 |
30 | pixelBackground(pixels);
31 |
32 | for(i=0;i canvas.height ) obj.y = 0 ;
39 | }
40 |
41 | var isCollidingBlocks = function(obj, direction, offset){
42 | if (!offset) offset = p(0,0);
43 | for (var i=0; i < blocks.length; i++){
44 | var block = blocks[i];
45 |
46 | var isColliding = collision.isCollidingDirection(block, obj, direction, offset);
47 | if (isColliding) return true;
48 | }
49 | return false;
50 | }
51 |
--------------------------------------------------------------------------------
/pacman/js/utils.js:
--------------------------------------------------------------------------------
1 | var loadJSON = function (path, success, error)
2 | {
3 | var oReq = new XMLHttpRequest();
4 | oReq.onload = function reqListener () {
5 | jsonData = JSON.parse(this.responseText);
6 | //console.log("Loading JSON data", jsonData);
7 | success(jsonData);
8 | };;
9 | oReq.open("get", path, true);
10 | oReq.send();
11 | }
12 |
13 | var p = function(x,y){ return {x: x, y: y}; }
14 |
15 | var loadImagePixels = function(image, callback){
16 |
17 | var img = new Image();
18 | img.src = image;
19 | img.onload = function() {
20 | console.log("Image " + image + " loaded " + img.width + "x" +img.height);
21 | var canvas = document.createElement('canvas');
22 | document.body.appendChild(canvas);
23 |
24 | var ctx = canvas.getContext('2d');
25 | canvas.width = img.width;
26 | canvas.height = img.height;
27 | ctx.drawImage(img, 0, 0);
28 | img.style.display = 'none';
29 | var imgData = ctx.getImageData(0,0,canvas.width, canvas.height);
30 |
31 | var pixels = [];
32 | for(i=0;i
2 |
3 |
4 |
5 | 404 snake
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/snake/js/controls.js:
--------------------------------------------------------------------------------
1 | // Handle keyboard controls
2 | var keysDown = {};
3 |
4 | var KEY_UP =38, KEY_DOWN =40, KEY_LEFT =37, KEY_RIGHT =39;
5 |
6 | addEventListener("keydown", function (e) {
7 | keysDown[e.keyCode] = true;
8 | }, false);
9 |
10 | addEventListener("keyup", function (e) {
11 | delete keysDown[e.keyCode];
12 | }, false);
13 |
14 | //Called from update.js
15 | var controls = function(){
16 | if (KEY_LEFT in keysDown) GAME_STATE.snake.move('l');
17 | if (KEY_RIGHT in keysDown) GAME_STATE.snake.move('r');
18 | if (KEY_UP in keysDown) GAME_STATE.snake.move('u');
19 | if (KEY_DOWN in keysDown) GAME_STATE.snake.move('d');
20 | }
21 |
--------------------------------------------------------------------------------
/snake/js/draw.js:
--------------------------------------------------------------------------------
1 | // Create the canvas
2 | var canvas = document.getElementById("canvas");
3 | var ctx = canvas.getContext("2d");
4 |
5 | var SIZE = 32;
6 |
7 | Cell.prototype.draw = function(){
8 | switch(this.content){
9 | case 'SNAKE':
10 | ctx.fillStyle="gray";
11 | break;
12 | case 'BLOCK':
13 | ctx.fillStyle="black";
14 | break;
15 | case 'FOOD':
16 | ctx.fillStyle="silver";
17 | break;
18 | }
19 | if (this.content && this.content != 'INVALID'){
20 | ctx.fillRect(this.x*BLOCK_SIZE, this.y*BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)
21 | }
22 | }
23 |
24 | // Draw everything
25 | var render = function () {
26 | if (GAME_STATE.game_over) {
27 | ctx.fillStyle = "rgb(250, 0, 0)";
28 | ctx.font = "48px Helvetica";
29 | ctx.textAlign = "center";
30 | ctx.textBaseline = "top";
31 | ctx.fillText("Game Over", canvas.width / 2, canvas.height * 2 / 3);
32 | }
33 | else {
34 | // draw the background
35 | ctx.fillStyle="white";
36 | ctx.fillRect(0,0,canvas.width,canvas.height);
37 |
38 | // draw game state
39 | Object.keys(GAME_STATE.grid).forEach(function(key){
40 | GAME_STATE.grid[key].draw();
41 | });
42 | }
43 | };
44 |
--------------------------------------------------------------------------------
/snake/js/framework.js:
--------------------------------------------------------------------------------
1 | // The main game loop
2 | var main = function () {
3 | var now = Date.now();
4 | var delta = now - then;
5 |
6 | controls();
7 | render();
8 |
9 | then = now;
10 |
11 | // Request to do this again ASAP
12 | requestAnimationFrame(main);
13 | };
14 |
15 | //var canvas = document.createElement('canvas');
16 | //document.body.appendChild(canvas);
17 |
18 |
19 |
20 | setInterval(function(){update()}, 300);
21 |
22 | // Cross-browser support for requestAnimationFrame
23 | var w = window;
24 | requestAnimationFrame =
25 | (
26 | w.requestAnimationFrame ||
27 | w.webkitRequestAnimationFrame ||
28 | w.msRequestAnimationFrame ||
29 | w.mozRequestAnimationFrame
30 | );
31 |
32 | // Let's play this game!
33 | var then = Date.now();
34 | initGameState(main);
35 |
--------------------------------------------------------------------------------
/snake/js/logic.js:
--------------------------------------------------------------------------------
1 | var BLOCK_SIZE = 16;
2 |
3 | function update(){
4 | if (GAME_STATE.complete) GAME_STATE.snake.update();
5 | }
6 |
7 | function initGameState(callback){
8 | GAME_STATE.grid = {};
9 | loadImagePixels("data/map.png", function(rows){
10 | rows.forEach(function(row, i){
11 | row.forEach(function(pixel, j){
12 | var cell = new Cell(i,j);
13 | if (isColor(pixel, BLACK))
14 | cell.content = 'BLOCK';
15 | else if (isColor(pixel, GREEN))
16 | cell.content = 'INVALID';
17 | else if (isColor(pixel, RED)){
18 | cell.content = 'SNAKE';
19 | GAME_STATE.snake = new Snake(cell);
20 | }
21 | GAME_STATE.grid[[i,j]] = cell;
22 | GAME_STATE.gameHeight = i;
23 | GAME_STATE.gameWidth = j;
24 | });
25 | });
26 | Grid.newFood();
27 | GAME_STATE.complete = true;
28 | callback();
29 | });
30 | }
31 |
32 | var GAME_STATE = {
33 | snake: null,
34 | grid: null,
35 | gameOver: false,
36 | gameHeight: 0,
37 | gameWidth: 0,
38 | }
39 |
40 | function Grid(){}
41 |
42 | Grid.get = function(x,y){
43 | return GAME_STATE.grid[[x,y]];
44 | }
45 |
46 | Grid.set = function(x, y, content){
47 | var cell = GAME_STATE.grid[[x,y]];
48 | cell.content = content;
49 | return cell;
50 | }
51 |
52 | Grid.unset = function(x, y){
53 | var cell = GAME_STATE.grid[[x,y]];
54 | cell.content = null;
55 | return cell;
56 | }
57 |
58 | Grid.randomFree = function(){
59 | do{
60 | var row = Math.floor(Math.random() * GAME_STATE.gameHeight);
61 | var col = Math.floor(Math.random() * GAME_STATE.gameWidth);
62 | var cell = this.get(row,col);
63 | } while (cell.content);
64 | return cell;
65 | }
66 |
67 | Grid.newFood = function (){
68 | var freeCell = this.randomFree();
69 | freeCell.content = 'FOOD';
70 | }
71 |
72 | function Cell(x,y){
73 | this.x = x;
74 | this.y = y;
75 | this.content = null;
76 | }
77 |
78 |
79 | function Snake(initCell){
80 | this.body = [initCell];
81 | this.dir = {x: -1, y: 0}; // start moving to the left
82 | }
83 |
84 | Snake.prototype.head = function(){
85 | return this.body[0];
86 | }
87 |
88 | Snake.prototype.tail = function(){
89 | return this.body[-1];
90 | }
91 |
92 | Snake.prototype.move = function(dir){
93 | switch(dir){
94 | case 'l':
95 | this.dir = {x: -1, y: 0};
96 | break;
97 | case 'r':
98 | this.dir = {x: 1, y: 0};
99 | break;
100 | case 'u':
101 | this.dir = {x: 0, y: -1};
102 | break;
103 | case 'd':
104 | this.dir = {x: 0, y: 1};
105 | break;
106 | }
107 | }
108 |
109 | Snake.prototype.update = function(dir){
110 | // compute new position of the head
111 | var head = this.head();
112 | var dir = this.dir;
113 | var newX = head.x + dir.x;
114 | var newY = head.y + dir.y;
115 | var newHead = Grid.get(newX, newY);
116 |
117 | // check collisions
118 |
119 | // if food, grow (on the head)
120 | if (newHead.content == 'FOOD') {
121 | newHead.content = 'SNAKE';
122 | this.body.unshift(newHead);
123 | Grid.newFood();
124 | }
125 |
126 | // if block, die
127 | else if (newHead.content != null){
128 | GAME_STATE.game_over = true;
129 | }
130 |
131 | // else, move
132 | else {
133 | oldTail = this.body.pop();
134 | oldTail.content = null;
135 |
136 | newHead.content = 'SNAKE';
137 | this.body.unshift(newHead);
138 | }
139 |
140 | }
141 |
--------------------------------------------------------------------------------
/snake/js/utils.js:
--------------------------------------------------------------------------------
1 | var loadImagePixels = function(image, callback){
2 |
3 | var img = new Image();
4 | img.src = image;
5 | img.onload = function() {
6 | console.log("Image " + image + " loaded " + img.width + "x" +img.height);
7 | var canvas = document.createElement('canvas');
8 | document.body.appendChild(canvas);
9 |
10 | var ctx = canvas.getContext('2d');
11 | canvas.width = img.width;
12 | canvas.height = img.height;
13 | ctx.drawImage(img, 0, 0);
14 | img.style.display = 'none';
15 | var imgData = ctx.getImageData(0,0,canvas.width, canvas.height);
16 |
17 | var pixels = [];
18 | for(i=0;i
2 |
3 |
4 |
5 | 404 Space Invaders
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/space-invaders/js/ai.js:
--------------------------------------------------------------------------------
1 | var updateEnemies = function(){
2 |
3 | if (hasReachedEnd()) {
4 | changeEnemyDirection();
5 | return;
6 | }
7 | var enemyMovement;
8 | if (enemyDirection == LEFT) enemyMovement = -10;
9 | else enemyMovement = 10;
10 |
11 | for (var i = 0 ; i < enemies.length; i++){
12 | var enemy = enemies[i];
13 | enemy.x = enemy.x + enemyMovement ;
14 | }
15 | }
16 |
17 | var hasReachedEnd = function(){
18 | var threshold = 32;
19 |
20 | for (var i = 0 ; i < enemies.length; i++){
21 | var enemy = enemies[i];
22 | if (enemyDirection == RIGHT && enemy.x > canvas.width - threshold - 32) return true;
23 | else if (enemyDirection == LEFT && enemy.x < threshold) return true;
24 | }
25 | return false;
26 | }
27 |
28 | var changeEnemyDirection = function(){
29 | if (enemyDirection == LEFT) enemyDirection = RIGHT;
30 | else enemyDirection = LEFT;
31 |
32 | for (var i = 0 ; i < enemies.length; i++){
33 | var enemy = enemies[i];
34 | enemy.y = enemy.y + 30 ;
35 | }
36 | }
37 |
38 | var enemyShot = function(){
39 | var enemy = enemies[Math.floor(Math.random()*enemies.length)];
40 | enemyShots.push({x:enemy.x, y: enemy.y});
41 | }
42 |
--------------------------------------------------------------------------------
/space-invaders/js/assets.js:
--------------------------------------------------------------------------------
1 | /**
2 | Ship and laser assets by Cpt_Flash
3 | Available at: http://opengameart.org/content/space-ships-2-units
4 | License: GPL 3.0
5 | **/
6 |
7 | // Background image
8 | var bgReady = false;
9 | var bgImage = new Image();
10 |
11 | bgImage.onload = function () {
12 | bgReady = true;
13 | };
14 | bgImage.src = "images/background.png";
15 |
16 | // Hero image
17 | var heroReady = false;
18 | var heroImage = new Image();
19 | heroImage.onload = function () {
20 | heroReady = true;
21 | };
22 | heroImage.src = "images/32_player.png";
23 |
24 | // Monster image
25 | var monsterReady = false;
26 | var monsterImage = new Image();
27 | monsterImage.onload = function () {
28 | monsterReady = true;
29 | };
30 | monsterImage.src = "images/32_enemy.png";
31 |
32 | // Hero image
33 | var shotReady = false;
34 | var shotImage = new Image();
35 | shotImage.onload = function () {
36 | shotReady = true;
37 | };
38 | shotImage.src = "images/32_laser_blue.png";
39 |
40 | var shotRedReady = false;
41 | var shotRedImage = new Image();
42 | shotRedImage.onload = function () {
43 | shotRedReady = true;
44 | };
45 | shotRedImage.src = "images/32_laser_red.png";
46 |
--------------------------------------------------------------------------------
/space-invaders/js/controls.js:
--------------------------------------------------------------------------------
1 | // Handle keyboard controls
2 | var keysDown = {};
3 |
4 | var KEY_UP =38, KEY_DOWN =40, KEY_LEFT =37, KEY_RIGHT =39;
5 |
6 | addEventListener("keydown", function (e) {
7 | keysDown[e.keyCode] = true;
8 | }, false);
9 |
10 | addEventListener("keyup", function (e) {
11 | delete keysDown[e.keyCode];
12 | }, false);
13 |
14 | addEventListener("mousemove", function(evt) {
15 | hero.x = evt.pageX - 24 ;
16 | }, false);
17 |
18 | var lastShot = 0;
19 | var SHOT_DELAY = 1000;
20 |
21 | addEventListener("click", function(evt) {
22 | if (!hero.dead) {
23 | var now = new Date().getTime();
24 | if (lastShot +SHOT_DELAY < now ) {
25 | lastShot = now;
26 | playerShots.push({x:evt.pageX, y: hero.y});
27 | }
28 | }
29 | }, false);
30 |
31 |
32 | //Called from update.js
33 | var controls = function(modifier){
34 | if (KEY_LEFT in keysDown) { // Player holding left
35 | hero.x -= hero.speed * modifier;
36 | }
37 | if (KEY_RIGHT in keysDown) { // Player holding right
38 | hero.x += hero.speed * modifier;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/space-invaders/js/draw.js:
--------------------------------------------------------------------------------
1 | // Create the canvas
2 | var canvas = document.getElementById("canvas");
3 | var ctx = canvas.getContext("2d");
4 |
5 | var SIZE = 32;
6 |
7 | var vy = 0;
8 | // Draw everything
9 | var render = function () {
10 | if (bgReady) {
11 |
12 | ctx.drawImage(bgImage, 0, vy);
13 | ctx.drawImage(bgImage, 0, bgImage.height-Math.abs(vy));
14 |
15 | if (Math.abs(vy) > bgImage.height) vy = 0;
16 | vy -= 2;
17 | }
18 |
19 | if (heroReady && !hero.dead) {
20 | ctx.drawImage(heroImage, hero.x, hero.y,SIZE, SIZE);
21 | }
22 |
23 | for (var i=0; i < enemies.length; i++){
24 | var enemy = enemies[i];
25 | ctx.drawImage(monsterImage, enemy.x, enemy.y,SIZE, SIZE);
26 |
27 | }
28 | for (var i=0; i < enemyShots.length; i++){
29 | var shot = enemyShots[i];
30 | ctx.drawImage(shotRedImage, shot.x, shot.y ,SIZE, SIZE);
31 | }
32 |
33 | for (var i=0; i < playerShots.length; i++){
34 | var shot = playerShots[i];
35 | ctx.drawImage(shotImage, shot.x, shot.y ,SIZE, SIZE);
36 | }
37 |
38 | if (hero.dead){
39 | ctx.fillStyle = "rgb(250, 0, 0)";
40 | ctx.font = "48px Helvetica";
41 | ctx.textAlign = "center";
42 | ctx.textBaseline = "top";
43 | ctx.fillText("Game Over", canvas.width / 2, canvas.height/ 2);
44 | }
45 | };
46 |
--------------------------------------------------------------------------------
/space-invaders/js/game.js:
--------------------------------------------------------------------------------
1 | // Reset the game when the player catches a monster
2 | var reset = function () {
3 | hero.x = canvas.width / 2;
4 | hero.y = canvas.height - 64;
5 | };
6 |
7 | // The main game loop
8 | var main = function () {
9 | var now = Date.now();
10 | var delta = now - then;
11 |
12 | update(delta / 1000);
13 | render();
14 |
15 | then = now;
16 |
17 | // Request to do this again ASAP
18 | requestAnimationFrame(main);
19 | };
20 |
21 | // Cross-browser support for requestAnimationFrame
22 | var w = window;
23 | requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;
24 |
25 | // Let's play this game!
26 | var then = Date.now();
27 | reset();
28 | main();
29 |
--------------------------------------------------------------------------------
/space-invaders/js/objects.js:
--------------------------------------------------------------------------------
1 | // Game objects
2 | var hero = {};
3 | var playerShots = [];
4 | var enemyShots = [];
5 |
6 | var shotSpeed = 200;
7 |
8 | var RIGHT = 1, LEFT = 0;
9 | var enemies = [];
10 | var enemyDirection = RIGHT;
11 | var loadEnemy = function(offset, json){
12 | var size = 32;
13 |
14 | for (var i = 0; i< json.length; i++){
15 | var pos = json[i];
16 | var enemy = {x: offset.x + pos.x * size, y: offset.y + pos.y * size} ;
17 | enemies.push(enemy);
18 | }
19 | }
20 |
21 | loadJSON('enemies.json',
22 | function(data) {
23 |
24 | loadEnemy({ x: 50, y: 50 }, data.four);
25 | loadEnemy({ x: 180, y: 50 }, data.zero);
26 | loadEnemy({ x: 300, y: 50 }, data.four);
27 | },
28 | function(xhr) { console.error(xhr); }
29 | );
30 |
--------------------------------------------------------------------------------
/space-invaders/js/update.js:
--------------------------------------------------------------------------------
1 |
2 | // Update game objects
3 | var update = function (modifier) {
4 | controls(modifier);
5 |
6 | for (var i = 0; i< playerShots.length; i++){
7 | var shot = playerShots[i];
8 | shot.y = shot.y - modifier * shotSpeed;
9 |
10 | for (var e= 0; e < enemies.length; e++){
11 | var enemy = enemies[e];
12 | if (collision(shot, enemy)) {
13 | console.log("Collision with enemy ", shot, enemy);
14 | playerShots.splice(i, 1);
15 | enemies.splice(e, 1);
16 | break;
17 | }
18 | }
19 | }
20 |
21 | for (var i = 0; i< enemyShots.length; i++){
22 | var shot = enemyShots[i];
23 | shot.y = shot.y + modifier * shotSpeed;
24 |
25 | if (collision(shot, hero)) {
26 | console.log("Collision with hero ", shot, hero);
27 | enemyShots.splice(i, 1);
28 | hero.dead = true;
29 | }
30 | }
31 | //updateEnemies();
32 | // Are they touching?
33 | };
34 |
35 | var collision = function(shot, enemy){
36 | return shot.x <= (enemy.x + 32)
37 | && enemy.x <= (shot.x + 32)
38 | && shot.y <= (enemy.y + 32)
39 | && enemy.y <= (shot.y + 32)
40 | }
41 |
42 | //AI METHODS
43 | setInterval(function(){updateEnemies()}, 500);
44 |
45 | setInterval(function(){enemyShot()}, 1000);
46 |
--------------------------------------------------------------------------------
/space-invaders/js/utils.js:
--------------------------------------------------------------------------------
1 | var loadJSON = function (path, success, error)
2 | {
3 | var oReq = new XMLHttpRequest();
4 | oReq.onload = function reqListener () {
5 | jsonData = JSON.parse(this.responseText);
6 | console.log("Loading JSON data", jsonData);
7 | success(jsonData);
8 | };;
9 | oReq.open("get", path, true);
10 | oReq.send();
11 | }
12 |
--------------------------------------------------------------------------------