view source

JavaScript

document.title = 'ボンバーマン';

var style = document.createElement('style');
style.innerText = 'html,body{overflow:hidden;cursor:crosshair;}';
document.getElementsByTagName('head').item(0).appendChild(style);

var canvas = document.createElement('canvas');
var w = document.body.clientWidth;
var h = document.body.clientHeight;
var min = Math.min(w,h);
canvas.setAttribute('width',w);
canvas.setAttribute('height',h);
let demo = document.getElementById('demo');
demo.appendChild(canvas);

var ctx = canvas.getContext('2d');
var cx = w/2;
var cy = h/2;
var t = 0;
var rAry = [];
var grayLine;
var mapAry = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,0,1,0,1,0,1,0,1,0,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,0,1,0,1,0,1,0,1,0,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,0,1,0,1,0,1,0,1,0,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,0,1,0,1,0,1,0,1,0,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,0,1,0,1,0,1,0,1,0,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,0,1,0,1,0,1,0,1,0,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
];

mapAry[1][2]  = 2;

var len = mapAry.length;
console.log(len);

var crossAry = [
[0,0],
[-1,0],
[1,0],
[0,-1],
[0,1],
];

var max = mapAry.length;
var iw = Math.floor(min/max);
var ih = Math.floor(min/max);
var mg = Math.floor((w - mapAry.length*iw) /2);
var blockCount = 0;

//https://taira-komori.jpn.org/arms01.html
var se = new Audio('bomb.mp3');
se.volume = 0.2;

//http://blog.pipoya.net/blog-entry-405.html

var imgs = {};
imgFiles = [
  'bomb.png',
  'bomb-block.png',
  'bomb-fire.png',
];
imgFiles.forEach(function(v){
  var img = new Image();
  img.src = v;
  imgs[v] = img;
});

var img = new Image();
img.src = 'bomb.png';
var face = new Image();
face.src = 'homomi.png';
var bombs = [];
var fires = [];


function setBlocks() {
  var i = 0;
  var j = 0;
  mapAry.forEach(function(line){
    i=0;
    //console.log(line);
    line.forEach(function(v){
      if(v===0 && Math.random()*9>7){
        mapAry[j][i]  = 2;
      }
      i++;
    });
    j++;
  });
}

function draw() {
  ctx.clearRect(0, 0, w, h);
  ctx.strokeStyle = 'none';
  ctx.lineWidth = 0;
  ctx.fillStyle = '#000000';
  ctx.fillRect(0, 0, w, h);
  ctx.lineWidth = 1;
  var r = 0;
  rAry = [];
  var i = 0;
  var j = 0;
  blockCount = 0;
  mapAry.forEach(function(line){
    i=0;
    //console.log(line);
    line.forEach(function(v){
      if(v===1){
        ctx.fillStyle = '#7C787C';
        ctx.fillRect(mg+i*iw, j*ih, iw, ih);
        ctx.fillStyle = '#3A3A3F';
        ctx.fillRect(mg+i*iw, j*ih+ih*9/10, iw, ih/10);
        ctx.fillStyle = '#3A3A3F';
        ctx.fillRect(mg+i*iw+iw*39/40, j*ih, iw/40, ih);
        ctx.fillStyle = '#BEBCBE';
        ctx.fillRect(mg+i*iw, j*ih, iw/40, ih);
      } else if(v===0 || v === 2){
        if((i+j)%2===0){
          ctx.fillStyle = '#63AA51';
        } else {
          ctx.fillStyle = '#7EC160';
        }
        ctx.fillStyle = '#3F720F';
        ctx.fillRect(mg+i*iw, j*ih, iw, ih);
      }
      if(v===2){
        blockCount++;
        ctx.drawImage(imgs['bomb-block.png'], 0,0,104,86, mg+i*iw, j*ih, iw, ih);
      }
      i++;
    });
    j++;
  });
  if(blockCount<5 && Math.random()* 99 > 80){
    let ii = Math.floor(Math.random()*len);
    let jj = Math.floor(Math.random()*len);
    if(mapAry[ii][jj] === 0){
      //mapAry[ii][jj] = 2;
    }
  }

  bombs.forEach(function(bomb){
    bomb.draw();
  });
  //ctx.drawImage(imgs['bomb-fire.png'], 104*2-2*104,84*2-0*84,104,84, 0, 0, iw, ih);

  bombs.forEach(function(bomb, i, ar){
    if(bomb.o().isDead){
      delete ar[i];
    }
  });

  bombs  = bombs.filter(v => v);


  fires.forEach(function(fire){
    fire.draw();
  });

  fires.forEach(function(fire, i, ar){
    if(fire.o().isDead){
      delete ar[i];
    }
  });
  fires  = fires.filter(v => v);
}

draw();

function setBomb(x,y) {
  //console.log(x);
  //ctx.putImageData(grayLine,0,0); 
  var ii=0;

  ctx.strokeStyle = '#ff0000';
  ctx.lineWidth = 4;
  var ex = -iw;
  var ey = -ih;
  var i = 0;
  var j = 0;
  var isSet = false;
  for(j=0;j<mapAry.length;j++){
    if(y > j*ih && y < j*ih+ih){
      ey = j*ih+ih/2;
      break;
    }
  }
  for(i=0;i<mapAry.length;i++){
    if(x > mg+i*iw && x < mg+i*iw+iw){
      ex = mg+i*iw+iw/2;
      break;
    }
  }
  //console.log([i,j,mapAry[i][j]]);
  if(mapAry[j][i] === 0){//ji逆
    isSet=true;
  }

  if(isSet){
    ctx.beginPath();
    //ctx.fillStyle = '#000000';
    //ctx.arc(ex, ey, iw/3, 0, Math.PI * 2, true);
    ctx.fill();
    //ctx.drawImage(img, 32,0,32,32, ex-iw/2, ey-ih/2, iw, ih);
    bombs.push(new Bomb({i:i,j:j,x:ex-iw/2,y:ey-ih/2}));
  }
}


//********************************************
var Bomb = function(_o){
  var that = this;

  var t = 0;
  var x = _o.x;
  var y = _o.y;
  var i = _o.i;
  var j = _o.j;
  var isDead = false;

  that.o = function(){
    return {
      x:x,
      y:y,
      isDead:isDead,
    }
  }

  that.draw = function(){
    t++;
    sy = 0;
    sx = (t % 3)*32;
    if(t===30){
      isDead = true;
    }
    if(t===27){
      se.currentTime = 0;
      se.play();
    }
    if(t>27){
      //ctx.drawImage(imgs['bomb-fire.png'], 0,0,520,424, x-iw*2, y-iw*2, iw*5, ih*5);
    } else if(t>29){
      //ctx.drawImage(imgs['bomb-fire.png'], 520,0,520,424, x-iw*2, y-iw*2, iw*5, ih*5);
    }
    if(t===24 && blockCount>0){
      setFire({i:i,j:j,x:x,y:y});
    }
    if(t>25){
      sy = 5*32;
      sx = (t - 25)*32 +32*3;
    } else if(t>21){
      sx = (t-21)*32;
      sy = 1*32;
    }
    ctx.drawImage(img, sx,sy,32,32, x, y, iw, ih);
    if(t<24){
      //ctx.drawImage(face, x+4, y+4, iw-8, ih-8);
    }
  }
  return that;
}


var setFire = function(_o){
  var x = _o.x;
  var y = _o.y;
  var i = _o.i;
  var j = _o.j;

  crossAry.forEach(function(d){

    for(k=1;k<4;k++){
      let dx = d[0]*k;
      let dy = d[1]*k;
      let ii = i+d[0]*k;
      let jj = j+d[1]*k;
      let isSet=false;
      let isEnd=false;
      if(ii>0 && jj > 0 && ii< len && jj< len){
        if(mapAry[jj][ii] === 2){//ji逆
          mapAry[jj][ii] = 0;
        }
        if(mapAry[jj][ii] === 0){
          isSet=true;
        }
      }
      if(isSet){
        let fire = new Fire({i:ii,j:jj,x:x+iw*dx,y:y+ih*dy,pos:d,isEnd:isEnd});
        fires.push(fire);
      } else {
        break;
      }
      if(d[0] === 0 && d[1] === 0){
        break;
      }
    }
  });
}


//********************************************
var Fire = function(_o){
  var that = this;

  var t = 0;
  var x = _o.x;
  var y = _o.y;
  var i = _o.i;
  var j = _o.j;
  var pos = _o.pos || [0,0];
  var isEnd = _o.isEnd;
  var isDead = false;
  //console.log({x:x,y:y});

  that.o = function(){
    return {
      x:x,
      y:y,
      isDead:isDead,
    }
  }
  that.draw = function(){
    t++;
    sx = 104*2-pos[0]*104;
    sy = 84*2-pos[1]*84;
    if(isEnd){
      sx+= pos[0]*104;
      sy+= pos[1]*84;
    }
    if(t<4){
      ctx.drawImage(imgs['bomb-fire.png'], sx,sy,104,84, x, y, iw, ih);
    } else {
      ctx.drawImage(imgs['bomb-fire.png'], sx+104*5,sy,104,84, x, y, iw, ih);
    }
    //ctx.fillStyle = '#aa0000';
    //ctx.fillRect(x, y, iw/2, ih/2);
    if(t===5){
      isDead = true;
    }
  }
  return that;
}

setBlocks();
setInterval(function(){
  draw();
},199);






document.oncontextmenu = function () {return false;}
function resize() {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  console.table({w:canvas.width, h:canvas.height});
  w = document.body.clientWidth;
  h = document.body.clientHeight;
  cx = w/2;
  cy = h/2;
  iw = min/max;
  ih = min/max;
}

window.onresize = resize;
window.addEventListener('click', function(ev) {
  setBomb(ev.clientX,ev.clientY);
  console.log(mapAry);
  //resize();
  //document.body.requestFullscreen();
  //draw();
}, false );

window.addEventListener('dblclick', function(ev) {
  //draw();
  setBlocks();
}, false );

document.addEventListener('fullscreenchange',function(e){
  resize();
});

CSS

HTML

ページのソースを表示 : Ctrl+U , DevTools : F12

view-source:https://hi0a.com/demo/-js/js-canvas-grid-bomberman/

ABOUT

hi0a.com 「ひまアプリ」は無料で遊べるミニゲームや便利ツールを公開しています。

プログラミング言語の動作デモやWEBデザイン、ソースコード、フロントエンド等の開発者のための技術を公開しています。

必要な機能の関数をコピペ利用したり勉強に活用できます。

プログラムの動作サンプル結果は画面上部に出力表示されています。

環境:最新のブラウザ GoogleChrome / Windows / Android / iPhone 等の端末で動作確認しています。

画像素材や音素材は半分自作でフリー素材配布サイトも利用しています。LINK参照。

動く便利なものが好きなだけで技術自体に興味はないのでコードは汚いです。

途中放置や実験状態、仕様変更、API廃止等で動かないページもあります。