游戏试玩git
前言github
这个小游戏主要思路是canvas与数组的映射,每个小网格对应二维数组的一个元素,利用数组来存储网格的信息,如 某网格是否有雷,周围九宫格雷的个数,是否已经被打开canvas
这里定义了三个数组数组
let gridStatus_arr = []; //存储格子身份状态,状态1为雷
let mineNum_arr = []; //存储格子周围八个格子雷的数量
let click_arr = []; //存储格子点击状态,点击过的为1
复制代码
先添加三个难度的按钮dom
<button class="type" data-row="9" data-col="9" data-mine="10">简单</button>
<button class="type" data-row="14" data-col="14" data-mine="36">中级</button>
<button class="type" data-row="14" data-col="22" data-mine="56">高级</button>
复制代码
点击相应按钮经过 js 获取对应的 data 属性, 而后动态的生成相应的方格, 而后动态计算包裹全部小方格的宽度和高度布局
而后建立一个canvas元素this
<canvas id="canvas"></canvas>
复制代码
canvas画布的大小属性width和height先不设置,后面经过js动态设置spa
点击难度按钮,动态初始化画布code
//获取canvas元素
context = $("#canvas")[0].getContext("2d");
$(".type").click(function(){
row = $(this).data('row');
col = $(this).data('col');
mine = $(this).data('mine');
init(mine);
})
//初始化
function init(mine){
createGrid(); //建立网格
createMine(mine); //随机生成雷
countArountMine(); //计算每一个格子周围八个格子雷的数量
createClickEvent(); //添加点击事件
}
复制代码
3.canvas建立网格对象
利用canvas画网格,先画一个相应大小的矩形,而后在矩形内画线造成网格
function createGrid(){
//计算画布宽高
let width = GAID_WIDTH*col;
let height = GAID_HEIGHT*row;
//设置画布宽高
canvas.setAttribute("width",width)
canvas.setAttribute("height",height)
//描绘边框
context.beginPath();
context.linewidth = 1;
context.rect(0,0,width,height);
context.stroke();
context.fillStyle = '#909090';
context.fill();
//准备画横线
for(let row_i = 1; row_i<row; row_i++){
var y = row_i*GAID_HEIGHT;
context.strokeStyle = 'white';
context.moveTo(0,y);
context.lineTo(width,y);
}
//准备画竖线
for(let col_i = 1; col_i<col; col_i++){
var x = col_i*GAID_WIDTH;
context.strokeStyle = 'white';
context.moveTo(x,0);
context.lineTo(x,height);
}
//完成描绘
context.stroke();
}
复制代码
添加雷,改变格子身份状态 ,1表明雷区
这里是利用二维数组和网格的映射来实现的
function createMine(mine){
$('#mine').text(mine);
//将数组变为二维
for(let i=0; i<row; i++){
gridStatus_arr[i] = [];
mineNum_arr[i] = [];
click_arr[i] = [];
}
//初始化二维数组
for(let i=0; i<row; i++){
for(let j=0; j<col; j++){
gridStatus_arr[i][j] = 0;
mineNum_arr[i][j] = 0;
click_arr[i][j] = 0;
}
}
//添加雷,改变格子身份状态
while(mine!=0){
let mine_row = Math.floor(Math.random() * row);
let mine_col = Math.floor(Math.random() * col);
mine--;
//预防生成位置相同
if(gridStatus_arr[mine_row][mine_col] == 1){
mine++;
continue;
}
gridStatus_arr[mine_row][mine_col] = 1;
}
}
复制代码
5.计算每一个格子周围八个格子雷的数量
利用对象来取当前格子周围九宫格的范围,遍历查看对应数组的身份状态
function countArountMine(){
for(let i=0; i<row; i++){
for(let j=0; j<col; j++){
let around = aroundGrid(i,j);
let nx = around.nx,
sx = around.sx,
wy = around.wy,
ey = around.ey;
let mineNum = 0;
for(let x=nx; x<=sx; x++){
for(let y=wy; y<ey; y++){
if(gridStatus_arr[x][y]==1){
mineNum++;
}
}
}
mineNum_arr[i][j] = mineNum;
}
}
}
复制代码
要先去掉默认的contextmenu事件,不然会和默认右键事件同时出现。
document.oncontextmenu = function (e) {
e.preventDefault();
};
复制代码
再添加鼠标点击事件,e.which = 1为鼠标左键 ,e.which = 3为鼠标右键
function createClickEvent(){
$("#canvas").off();
$("#canvas").mousedown(function(e){
//由于canvas的X,Y坐标和数组的行列相反,这里直接转换了一下
let x = Math.floor(e.offsetY / GAID_HEIGHT);
let y = Math.floor(e.offsetX / GAID_WIDTH);
if(e.which == 1){
judgeGridStatus(x,y);
}else if(e.which == 3){
signMine(x,y);
}
})
}
复制代码
对比身份状态是否为1 来判断是否点击到雷。
经过 已打开的格子个数 和 row*col - mine 对比判断是否扫雷成功
这里就不贴代码了,详细可参考个人GitHub仓库
最后
在canvas的用法上可能有一些不规范,由于花的时间比较短, 可能里面还存在一些问题,还请大佬们多多包涵,也欢迎大佬们来指正。本小白感激涕零。