commit d7a2b327f2cfebc3a500198062a2d1d8993d68b2 Author: zapashcanon Date: Thu Mar 21 17:44:19 2019 +0100 first commit diff --git a/bomberman.conf b/bomberman.conf new file mode 100644 index 0000000..0edd3f8 --- /dev/null +++ b/bomberman.conf @@ -0,0 +1,38 @@ +Define short_name bomberman +Define server_name ${short_name}.zapashcanon.fr +Define admin_mail leo@ndrs.fr +Define cert_name ${server_name} +Define cert_dir /etc/letsencrypt/live +Define log_dir /var/log/apache2 +Define log_file ${log_dir}/${short_name} +Define error_log_file ${log_file}.error.log +Define access_log_file ${log_file}.access.log +Define doc_root /var/www/${server_name}/src + + + + RewriteEngine on + RewriteCond %{SERVER_NAME} =${server_name} + RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent] + + + + + + + ServerName ${server_name} + ServerAdmin ${admin_mail} + + DocumentRoot ${doc_root} + + ErrorLog ${error_log_file} + CustomLog ${access_log_file} combined + + Protocols h2 http/1.1 + + SSLCertificateFile ${cert_dir}/${cert_name}/fullchain.pem + SSLCertificateKeyFile ${cert_dir}/${cert_name}/privkey.pem + Include /etc/letsencrypt/options-ssl-apache.conf + + + diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 0000000..df31ce2 --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +set -eu + +( cd "$(dirname "$0")/../" + + domain=bomberman.zapashcanon.fr + + sudo cp ./*.conf /etc/apache2/sites-available/ + dst=/var/www/${domain}/ + sudo mkdir -p $dst + sudo cp -r src/ $dst + + sudo service apache2 restart + echo "Installed !" +) diff --git a/src/audio/intro-screen.mp3 b/src/audio/intro-screen.mp3 new file mode 100644 index 0000000..142a818 Binary files /dev/null and b/src/audio/intro-screen.mp3 differ diff --git a/src/audio/intro-screen.ogg b/src/audio/intro-screen.ogg new file mode 100644 index 0000000..3c732ae Binary files /dev/null and b/src/audio/intro-screen.ogg differ diff --git a/src/css/style.css b/src/css/style.css new file mode 100644 index 0000000..cd2e0d7 --- /dev/null +++ b/src/css/style.css @@ -0,0 +1,17 @@ +#canvas { + position: relative; + width: 1000px; + height: 600px; + border: 2px solid black; + z-index:1; +} + +.object { + position: absolute; + z-index:2; + background-color: black; +} + +/*#audioplayer { + display: none; +}*/ diff --git a/src/img/betty_bottom.png b/src/img/betty_bottom.png new file mode 100644 index 0000000..1432783 Binary files /dev/null and b/src/img/betty_bottom.png differ diff --git a/src/img/betty_dead.png b/src/img/betty_dead.png new file mode 100644 index 0000000..5ba5305 Binary files /dev/null and b/src/img/betty_dead.png differ diff --git a/src/img/betty_left.png b/src/img/betty_left.png new file mode 100644 index 0000000..fd45006 Binary files /dev/null and b/src/img/betty_left.png differ diff --git a/src/img/betty_right.png b/src/img/betty_right.png new file mode 100644 index 0000000..c42572e Binary files /dev/null and b/src/img/betty_right.png differ diff --git a/src/img/betty_roasted.png b/src/img/betty_roasted.png new file mode 100644 index 0000000..305f462 Binary files /dev/null and b/src/img/betty_roasted.png differ diff --git a/src/img/betty_top.png b/src/img/betty_top.png new file mode 100644 index 0000000..614c515 Binary files /dev/null and b/src/img/betty_top.png differ diff --git a/src/img/bettytwo_bottom.png b/src/img/bettytwo_bottom.png new file mode 100644 index 0000000..c2ce8ac Binary files /dev/null and b/src/img/bettytwo_bottom.png differ diff --git a/src/img/bettytwo_dead.png b/src/img/bettytwo_dead.png new file mode 100644 index 0000000..077229f Binary files /dev/null and b/src/img/bettytwo_dead.png differ diff --git a/src/img/bettytwo_left.png b/src/img/bettytwo_left.png new file mode 100644 index 0000000..63300cf Binary files /dev/null and b/src/img/bettytwo_left.png differ diff --git a/src/img/bettytwo_right.png b/src/img/bettytwo_right.png new file mode 100644 index 0000000..ebf71dc Binary files /dev/null and b/src/img/bettytwo_right.png differ diff --git a/src/img/bettytwo_roasted.png b/src/img/bettytwo_roasted.png new file mode 100644 index 0000000..2b1b021 Binary files /dev/null and b/src/img/bettytwo_roasted.png differ diff --git a/src/img/bettytwo_top.png b/src/img/bettytwo_top.png new file mode 100644 index 0000000..9abba8e Binary files /dev/null and b/src/img/bettytwo_top.png differ diff --git a/src/img/bomb_0.png b/src/img/bomb_0.png new file mode 100644 index 0000000..1460065 Binary files /dev/null and b/src/img/bomb_0.png differ diff --git a/src/img/bomb_1.png b/src/img/bomb_1.png new file mode 100644 index 0000000..97de121 Binary files /dev/null and b/src/img/bomb_1.png differ diff --git a/src/img/bomb_2.png b/src/img/bomb_2.png new file mode 100644 index 0000000..f1319e9 Binary files /dev/null and b/src/img/bomb_2.png differ diff --git a/src/img/bomb_3.png b/src/img/bomb_3.png new file mode 100644 index 0000000..97de121 Binary files /dev/null and b/src/img/bomb_3.png differ diff --git a/src/img/bomb_4.png b/src/img/bomb_4.png new file mode 100644 index 0000000..5e9d5bd Binary files /dev/null and b/src/img/bomb_4.png differ diff --git a/src/img/bomberman_bottom.png b/src/img/bomberman_bottom.png new file mode 100644 index 0000000..b0db846 Binary files /dev/null and b/src/img/bomberman_bottom.png differ diff --git a/src/img/bomberman_dead.png b/src/img/bomberman_dead.png new file mode 100644 index 0000000..d347ea8 Binary files /dev/null and b/src/img/bomberman_dead.png differ diff --git a/src/img/bomberman_left.png b/src/img/bomberman_left.png new file mode 100644 index 0000000..d774f78 Binary files /dev/null and b/src/img/bomberman_left.png differ diff --git a/src/img/bomberman_right.png b/src/img/bomberman_right.png new file mode 100644 index 0000000..329a880 Binary files /dev/null and b/src/img/bomberman_right.png differ diff --git a/src/img/bomberman_roasted.png b/src/img/bomberman_roasted.png new file mode 100644 index 0000000..31a4515 Binary files /dev/null and b/src/img/bomberman_roasted.png differ diff --git a/src/img/bomberman_top.png b/src/img/bomberman_top.png new file mode 100644 index 0000000..234c271 Binary files /dev/null and b/src/img/bomberman_top.png differ diff --git a/src/img/george_bottom.png b/src/img/george_bottom.png new file mode 100644 index 0000000..78a2430 Binary files /dev/null and b/src/img/george_bottom.png differ diff --git a/src/img/george_dead.png b/src/img/george_dead.png new file mode 100644 index 0000000..6b493ea Binary files /dev/null and b/src/img/george_dead.png differ diff --git a/src/img/george_left.png b/src/img/george_left.png new file mode 100644 index 0000000..6e054c0 Binary files /dev/null and b/src/img/george_left.png differ diff --git a/src/img/george_right.png b/src/img/george_right.png new file mode 100644 index 0000000..3ee47df Binary files /dev/null and b/src/img/george_right.png differ diff --git a/src/img/george_roasted.png b/src/img/george_roasted.png new file mode 100644 index 0000000..fa67a16 Binary files /dev/null and b/src/img/george_roasted.png differ diff --git a/src/img/george_top.png b/src/img/george_top.png new file mode 100644 index 0000000..964b97e Binary files /dev/null and b/src/img/george_top.png differ diff --git a/src/img/tile_grass.png b/src/img/tile_grass.png new file mode 100644 index 0000000..736cb8e Binary files /dev/null and b/src/img/tile_grass.png differ diff --git a/src/img/tile_wall.png b/src/img/tile_wall.png new file mode 100644 index 0000000..d2ea6c1 Binary files /dev/null and b/src/img/tile_wall.png differ diff --git a/src/img/tile_wood.png b/src/img/tile_wood.png new file mode 100644 index 0000000..32c82ec Binary files /dev/null and b/src/img/tile_wood.png differ diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..1cb1744 --- /dev/null +++ b/src/index.html @@ -0,0 +1,54 @@ + + + + + + Bomberman + + + + + + +
+
+

Bomberman

+
+
+
+ +
+
+
+ +
+
+ +
+
+
+

Commands

+

Player 1: e and d
+ Player 2: o and l

+
+ + + +
+ + + + + + + + + +
+ + + diff --git a/src/js/bomb.js b/src/js/bomb.js new file mode 100644 index 0000000..a0583d4 --- /dev/null +++ b/src/js/bomb.js @@ -0,0 +1,25 @@ +// @flow + +"use strict"; + +import * as point from "./point.js"; + +export class Bomb extends point.Point { + constructor (p) { + super(p.x, p.y); + this.created = Date.now(); + this.power = 2; // TODO: how much ? + }; + age () { + return Math.floor ((Date.now() - this.created) / 1000); + }; + is_alive () { + return this.age() < 4; // TODO: how long ? + }; + get_pos () { + return new point.Point(this.x, this.y); + }; + has_pos (p) { + return this.x == p.x && this.y == p.y; + } +} diff --git a/src/js/main.js b/src/js/main.js new file mode 100644 index 0000000..c4ddbc8 --- /dev/null +++ b/src/js/main.js @@ -0,0 +1,80 @@ +// @flow + +"use strict"; + +import * as renderer from "./renderer.js"; +import * as mover from "./mover.js"; +import * as state from "./state.js"; + +const get_json_callback = function(file_name, callback) { + let req = new XMLHttpRequest(); + req.open('GET', "json/" + file_name); + req.responseType = 'json'; + req.send(); + req.onload = function() { + callback(req.response); + } +} + +const mv_step = 0.25; + +window.addEventListener("load", get_json_callback("lvl_01.json", function (map) { + + const s = new state.State(map); + + const up = function(p) { + s.move_p(0, -mv_step); + }; + + const down = function(p) { + s.move_p(0, mv_step); + }; + + const left = function(p) { + s.move_p(-mv_step, 0); + }; + + const right = function(p) { + s.move_p(mv_step, 0); + } + + const keyboard = function(e /*:: : KeyboardEvent */) { + // TODO: forçage de meme, parser directement le .html avec les indications de touche + switch (e.key) { + case "z": + up(s); + break; + case "s": + down(s); + break; + case "q": + left(s); + break; + case "d": + right(s); + break; + case "b": + s.add_bomb(); + } + }; + + document.addEventListener("keydown", keyboard); + + // TODO: better FPS count + //let previous = Date.now(); + let interval; + interval = setInterval(function () { + try { + //const delta = (Date.now() - previous) / 1000; + //previous = Date.now(); + //console.log(1 / delta); + renderer.draw_state(s); + s.rm_bombs(); + } catch (e) { + clearInterval(interval); + throw(e); + } + + }, 1000 / 60); + +})); diff --git a/src/js/mover.js b/src/js/mover.js new file mode 100644 index 0000000..8f41fb7 --- /dev/null +++ b/src/js/mover.js @@ -0,0 +1,29 @@ +// @flow + +"use strict"; + +import * as point from "./point.js"; + +const dec_x = -0.1; // TODO +const dec_y = +0.2; // TODO + +export class Mover extends point.Point { + /*:: x: number */ + /*:: y: number */ + constructor (x /*: number */, y /*: number */) { + super(x, y); + this.alive = true; + } + kill () { + this.alive = false; + } + copy () { + let c = new Mover(this.x, this.y); + c.alive = this.alive; + return c; + } + move (p) { + this.x += p.x; + this.y += p.y; + } +} diff --git a/src/js/point.js b/src/js/point.js new file mode 100644 index 0000000..75ebab4 --- /dev/null +++ b/src/js/point.js @@ -0,0 +1,28 @@ +// @flow + +"use strict"; + +export class Point { + /*:: x: number */ + /*:: y: number */ + constructor (x /*: number */, y /*: number */) { + this.x = x; + this.y = y; + }; + add (p) { + return new Point(this.x + p.x, this.y + p.y); + }; + round () { + return new Point(Math.round(this.x), Math.round(this.y)); + }; + eq (p) { + return this.x == p.x && this.y == p.y; + }; +} + +const left = new Point(-1, 0); +const right = new Point(1, 0); +const bottom = new Point(0, 1); +const top = new Point(0, -1); + +export {left, right, bottom, top}; diff --git a/src/js/renderer.js b/src/js/renderer.js new file mode 100644 index 0000000..afd1133 --- /dev/null +++ b/src/js/renderer.js @@ -0,0 +1,74 @@ +// @flow + +"use strict"; + +import * as state from "./state.js"; + +const assert_valid = function (el, t) { + if (!(el && el instanceof t)) { + throw "invalid object"; + } +} + +const canvas = document.getElementById("canvas"); +assert_valid(canvas, HTMLCanvasElement); + +const width = canvas.width; +const height = canvas.height; + +const context = canvas.getContext("2d"); +assert_valid(context, CanvasRenderingContext2D); + +const tile_grass = document.getElementById("tile_grass"); +const tile_wall = document.getElementById("tile_wall"); +const tile_wood = document.getElementById("tile_wood"); +const betty_bottom = document.getElementById("betty_bottom"); +const bomb_0 = document.getElementById("bomb_0"); +const bomb_1 = document.getElementById("bomb_1"); +const bomb_2 = document.getElementById("bomb_2"); +const bomb_3 = document.getElementById("bomb_3"); +const bomb_4 = document.getElementById("bomb_4"); + +const img_of_block = function(b) { + switch (b) { + case state.block.Grass: + return tile_grass; + case state.block.Wood: + return tile_wood; + case state.block.Wall: + return tile_wall; + default: + console.log("Missing block img"); + } +} + +const draw_state = function (s) { + const step_x = width / s.width; + const step_y = height / s.height; + context.clearRect(0, 0, width, height); + for (let i = 0; i < s.width; i++) { + for (let j = 0; j < s.height; j++) { + context.drawImage(img_of_block(s.grid[i][j]), i * step_x, j * step_y, step_x, step_y); + } + } + // TODO: draw bombs U { p } starting with the one on the top so they don't overlap weirdly + s.bombs.forEach(function (b) { + let img = bomb_0; + let a = b.age(); + if (a >= 4) { + img = bomb_4; + } else if (a == 3) { + img = bomb_3; + } else if (a == 2) { + img = bomb_2; + } else if (a == 1) { + img = bomb_1; + } + context.drawImage(img, b.x * step_x, b.y * step_y, step_x, step_y); + } + ); + context.drawImage(betty_bottom, s.p.x * step_x, s.p.y * step_y, step_x, step_y); + context.fill(); +} + +export { draw_state }; diff --git a/src/js/state.js b/src/js/state.js new file mode 100644 index 0000000..4737891 --- /dev/null +++ b/src/js/state.js @@ -0,0 +1,110 @@ +// @flow + +"use strict"; + +import * as mover from "./mover.js"; +import * as bomb from "./bomb.js"; +import * as point from "./point.js"; + +const block = { + Empty : 1, + Grass : 2, + Wood : 3, + Wall: 4 +} + +export class State { + constructor (map) { + this.width = map.width; + this.height = map.height; + this.grid = map.grid; + this.p = new mover.Mover(map.p.x, map.p.y); + this.bombs = []; + }; + get_block(p) { + return this.grid[p.x][p.y]; + }; + set_block(p, v) { + this.grid[p.x][p.y] = v; + } + is_block_empty(p) { + const b = this.get_block(p); + return b == block.Empty || b == block.Grass; + }; + is_block_in_grid(p) { + return p.x >= 0 && p.y >= 0 && p.x < this.width && p.y < this.height; + }; + move_p(x, y) { + if (this.p.alive) { + // we move a copy + let p2 = this.p.copy(); + p2.move(new point.Point(x, y)); + let p_round = p2.round(); + // if it's valid, we use the copy + if (this.is_block_in_grid(p_round)) { + if (this.is_block_empty(p_round)) { + this.p = p2; + } + } + } + }; + block_has_bomb(p) { + let res = false; + this.bombs.forEach(function (b) { + if (b.has_pos(p)) { + res = false; // TODO: escape the foreach + } + }); + + return res; + } + add_bomb() { + if (this.p.alive) { + const p_round = this.p.round(); + if (!this.block_has_bomb(p_round)) { + this.bombs.push(new bomb.Bomb(p_round)); + } + } + }; + explode_block(b_pos) { + if (this.is_block_in_grid(b_pos)) { + let b = this.get_block(b_pos); + if (b == block.Wood) { + this.set_block(b_pos, block.Grass); + } else if (b_pos.eq(this.p)) { // TODO ugly and unclear + this.p.alive = false; + } + + // TODO: explode others bombs + } + }; + explode_dir(p, dir, power) { + if (power > 0) { + this.explode_block(p); // TODO: if something is destroyed or if there's an unbreakable block, return false + this.explode_dir(p.add(dir), dir, power - 1); // TODO: if the previous function returned false, we don't make this call + } + }; + explode_bomb(p, power) { + this.explode_block(p); + this.explode_dir(p, point.left, power); + this.explode_dir(p, point.right, power); + this.explode_dir(p, point.top, power); + this.explode_dir(p, point.bottom, power); + }; + rm_bombs() { + let bombs2 = []; + const s = this; + this.bombs.forEach(function (b) { + if (b) { + if (b.is_alive()) { + bombs2.push(b); + } else { + s.explode_bomb(b.get_pos(), b.power); + } + } + }); + this.bombs = bombs2; + }; +} + +export { block } diff --git a/src/json/lvl_01.json b/src/json/lvl_01.json new file mode 100644 index 0000000..9e4b338 --- /dev/null +++ b/src/json/lvl_01.json @@ -0,0 +1,30 @@ +{ "width": 20, + "height": 20, + "grid": [ + [2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3], + [2,4,2,2,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4], + [2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3], + [2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4], + [2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3], + [2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4], + [2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3], + [2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4], + [2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3], + [2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4], + [2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3], + [2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4], + [2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3], + [2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4], + [2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3], + [2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4], + [2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3], + [2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4], + [2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3], + [2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4,2,4] + ], + "p": { + "x": 3, + "y": 2 + } + +}