第一次写掘金帖子,没啥经验,也是写来玩玩的
闲来没事,写了个五子棋玩玩,基于canvas写的,大概长这样:↓↓↓↓
首先是css的代码
*{
padding: 0;
margin: 0;
}
body,html{
width: 100%;
height: 100%;
position: relative;
background-color: #eee;
}
.wrap{
width: 700px;
height: 700px;
position: absolute;
top: calc(50% - 40px);
left: 50%;
transform: translate(-50%, -50%);
}
.control_wrap{
width: 100%;
position: absolute;
bottom: 10%;
left: 50%;
transform: translateX(-50%);
text-align: center;
font-size: 16px;
color: #333;
}
.control_wrap span{
margin-right: 4px;
}
.control_wrap input{
border: none;
padding: 10px;
font-size: 16px;
border-radius: 6px;
}
.control_wrap button{
width: 90px;
height: 30px;
margin-left: 10px;
cursor: pointer;
}
然后是简单的html布局
这部分主要就是一个canvas,然后加了个控制栏,控制栏里面联上了js里的几个数据
<div class="wrap">
<canvas id="canvas" width="800" height="800"></canvas>
</div>
<div class="control_wrap">
<span>棋盘大小:</span>
<input type="text" class="stage_big" value="700">
<span>连子获胜:</span>
<input type="text" class="win_num" value="5">
<button class="start_btn">开始游戏</button>
</div>
最后是js的部分了,这部分代码我写得比较多,没有优化过的,主要懒的
首先是基础数据,简单地写了点注释
let arr = []; //数据矩阵
let stageLeng = 25; //数组长度
let stageWidth = 700; //初始化棋盘大小
let _w = stageWidth/stageLeng | 0; //棋盘线条间隔
let gameState = 'finish'; //游戏状态 start finish 两个状态
let linNumber = 5; //胜利需要连几颗棋子
let black = document.createElement('img'); //棋子图片
let white = document.createElement('img'); //白色棋子图片
black.src = './black.png';
white.src = './white.png';
let c_width = _w * 0.8 | 0; //棋子的宽高
c_width = c_width % 2 ? c_width + 1 : c_width;
let canvas = document.querySelector('#canvas');
canvas.width = stageWidth; //画布的宽度
canvas.height = stageWidth; //画布的高度
let ctx = canvas.getContext('2d');
let isBlack = true; //是否轮到黑棋,每轮变换
然后开始游戏按钮,拿到控制的数据,或者默认数据
document.querySelector('.start_btn').onclick = function (){
// if(gameState == 'start') return false;
let stageBig = document.querySelector('.stage_big').value || 700;
let winNum = document.querySelector('.win_num').value || 5;
if(stageBig != stageWidth){
document.querySelector('.wrap').style.width = stageBig + 'px';
document.querySelector('.wrap').style.height = stageBig + 'px';
stageWidth = stageBig | 0;
_w = stageWidth/stageLeng | 0;
c_width = _w * 0.8 | 0;
c_width = c_width % 2 ? c_width + 1 : c_width;
canvas.width = stageWidth; //画布的宽度
canvas.height = stageWidth; //画布的高度
}
linNumber = winNum != linNumber ? winNum | 0 : linNumber;
initList();
drawCheckerboard();
gameState = 'start';
};
初始化棋盘
function initList (){
arr = [];
for(let i = 0; i < stageLeng; i++){
let aaa = []
for(let b = 0; b < stageLeng; b++){
aaa.push(0)
}
arr.push(aaa)
}
}
在canvas上画棋盘的线
function drawCheckerboard(){ //绘画棋盘的线条
ctx.fillStyle="#caa281";
ctx.fillRect(0,0,stageWidth,stageWidth);
let _p = new Array(stageLeng).fill([0, 0]);
for(let i = 0; i < stageLeng; i++){
ctx.lineWidth="1";
ctx.strokeStyle = '#000'
ctx.beginPath();
ctx.moveTo(0, i*_w);
ctx.lineTo(stageWidth, i*_w);
ctx.stroke();
_p[i][1] = i * _w;
}
for(let i = 0; i < stageLeng; i++){
ctx.lineWidth="1";
ctx.strokeStyle = '#000'
ctx.beginPath();
ctx.moveTo(i*_w, 0);
ctx.lineTo(i*_w, stageWidth);
ctx.stroke();
_p[i][0] = i * _w;
}
}
在棋盘上增加点击事件这里用的是canvas代理
canvas.onclick = function(e){ //给棋盘增加点击事件
if(gameState == 'finish') return false;
let x = e.clientX - this.getBoundingClientRect().left | 0;
let y = e.clientY - this.getBoundingClientRect().top | 0;
drawChess(x, y)
}
跟点击事件配合的就是在棋盘上绘制棋子
function drawChess(x, y){ //在棋盘上绘制棋子
let _x = x % _w;
let _y = y % _w;
_x > (_w / 2 | 0) ? x += parseInt(_w - _x) : x -= _x;
_y > (_w / 2 | 0) ? y += parseInt(_w - _y) : y -= _y;
let l = x / _w | 0, j = y / _w | 0;
if(arr[j][l] || l == 0 || j == 0 || l == arr.length || j == arr.length) return false;
arr[j][l] = isBlack ? 1 : 2;
ctx.drawImage(isBlack ? black : white, x - (c_width / 2), y - (c_width / 2), c_width, c_width);
checkWin(isBlack ? 1 : 2);
isBlack = !isBlack;
}
最后就是判断输赢,说实话,这个我看别人的写的好简单,然后我用了个最慢的方法,就是去盘一个米字,看看当前有没有连着N个棋子,是否达到了胜负条件
function checkWin(target){
let end = getCondition(target);
//横的 + 竖的
for(let i = 0; i < arr.length; i++){
let linkString = "";
for(let j = 0; j < arr.length; j++){
linkString+=arr[j][i];
if(arr[i].join("").includes(end) || linkString.includes(end)){
alert('游戏结束'+(target == 1 ? ',黑棋' : ',白棋')+'获胜');
console.info('结束',target == 1 ? '黑棋' : '白棋', '赢了');
gameState = 'finish'
return false;
}
}
}
checkSlashWin(target, end);
reverseSlashWin(target, end);
};
function getCondition(t){
let e = ''
for(let i = 0; i< linNumber; i++){
e += t;
}
return parseInt(e)
};
function checkSlashWin(target, end){
let _idx = arr.length - 1;
let flag = true
while(_idx > linNumber - 1){
let linkString = "";
let i = arr.length - 1, j = _idx;
while(j > 0){
if(flag) {linkString += arr[i][j];}
else {linkString += arr[j][i];}
i--;
j--;
}
_idx--;
if(_idx == linNumber - 1 && flag){
flag = false;
_idx = arr.length - 1;
}
if(linkString.includes(end)){
alert('游戏结束'+(target == 1 ? ',黑棋' : ',白棋')+'获胜');
console.info('结束',target == 1 ? '黑棋' : '白棋', '赢了');
gameState = 'finish'
return false;
}
}
}
function reverseSlashWin(target, end){
let idx = arr.length -1;
let flag = true;
while(idx > 0){
let linkString = "";
let i = arr.length - 1, j = idx;
if(flag){
i = 0;
while(j > 0){
linkString += arr[i][j];
i++;
j--;
}
}else {
while(j < arr.length){
linkString += arr[i][j];
i--;
j++;
}
}
idx--;
if(idx == 0 && flag){
flag = false;
idx = arr.length -1
}
if(linkString.includes(end)){
alert('游戏结束'+(target == 1 ? ',黑棋' : ',白棋')+'获胜');
console.info('结束',target == 1 ? '黑棋' : '白棋', '赢了');
gameState = 'finish'
return false;
}
}
}