天天看点

原生JS五子棋

用js实现一款五子棋小游戏,首先把五子棋所有的功能总结一下

原生JS五子棋

然后是html部分, 一个canvas标签.

<body style="background: rgb(248, 204, 179);">
	<canvas style="border:solid 2px red;margin: 50px;" id="can" height="600" width="600"></canvas>
	<div id="ts" style="font-size: 50px;display: none;"></div>
</body>
           

接下来就是JS里实现五子棋的功能了。首先把棋盘绘制出来

var qijuHeight = 15;//棋盘的横线个数
var qijuWidth = 15;//棋盘的竖线个数
var qiju = [];//定义一个储存棋子位置的变量 棋局
/** @type {HTMLCanvasElement} */
var can = document.getElementById("can");//获取canvas标签
var c = can.getContext("2d");//把他转换成2d画布
//棋谱  棋局 初始化
for(var y = 0;y < qijuHeight;y++){//绘制棋盘Y上的格子
	qiju.push([]);//在数组里面添加数组以充当Y轴
	for (var x = 0; x < qijuWidth; x++) {//绘制棋盘X上的格子
		qiju[y].push(0);//在二维数组里面添加棋子,0是空,1是黑棋,2是白棋
		if(y <14 && x < 14){//
			c.strokeStyle = "black";//设置格子的颜色
			//绘制每个格子的位置,因为画布比棋盘大40像素,我们要把棋盘居中就需要在XY上面加20像素-
			c.strokeRect(x * 40 + 20,y * 40 + 20,40,40);//绘制格子
		}
	}
}
           

棋盘就出来了

原生JS五子棋

并且生成了一个名字为qiju的数组,用来存放棋子用

原生JS五子棋

0代表空的格子,可以下棋(实际上棋子是下在点上的,而不是格子中心)

然后就是实现落子效果

var ssss = 0;//游戏结束的判定,1为已经结束
		var hb = 1;//当前是黑棋还是白棋
	    can.onclick = function(e){ //鼠标点击canvas的点击事件
	        if(ssss == 1){//判断游戏是否已经结束的东西
	            return;//结束的话就中止,防止赢了之后可以继续下棋
	        }
	        var Y = parseInt(e.layerY / 40);//鼠标在画布的位置除以40就能判断鼠标点击的格子
	        var X = parseInt(e.layerX / 40);//鼠标在画布的位置除以40就能判断鼠标点击的格子
	        if(qiju[Y][X] == 0){ //如果点击的地方是空的格子,那么就把棋子绘制
	            qiju[Y][X] = hb;//把鼠标点击的位置,把对应数组中位置的0用当前的棋子替代;
				//hb  是当前是黑棋还是白棋,1黑棋,2白棋
	            pd(Y,X,hb);//这个是调用判断方法,在下面,跟绘制棋子没关系
	            hb = hb == 1 ?2:1;//下完之后把黑棋变成白棋,白棋变成黑棋
	            if(ssss == 1){ //判断游戏是否已经结束的东西
	                return;
	            }
	            ht();//调用绘图功能
	        }
	    }
		//这样就可以在数组中放置棋子了,但是canvas还没有更新,所以我们要写一个绘图的方法ht()
		var color = ["green","black","white"];//颜色数组 1是黑棋,2是白棋
		function ht(){//绘图的方法
            c.clearRect(0, 0, can.width, can.height);//首先把canvas清除掉,重新绘制
            for(var y = 0;y < qijuHeight;y++){//然后是两层for循环重新绘制棋谱,Y轴
                for (var x = 0; x < qijuWidth; x++){//X轴
                    if(y < qijuHeight - 1 && x < qijuWidth - 1){//因为棋子是下在点上而不是格子中间,所以要少生成一个格子
                        c.strokeStyle = "black";//设置格子的颜色
                        //绘制每个格子的位置,因为画布比棋盘大40像素,我们要把棋盘居中就需要在XY上面加20像素-
                        c.strokeRect(x * 40 + 20,y * 40 + 20,40,40);//跟初始化一样
                    }
                    if(qiju[y][x] != 0){//判断棋局里面有下了棋子的地方
                        hz(x,y,15,color[qiju[y][x]])//把棋子绘制出来,数组里面是1就传黑色,是2就是白色
						//调用hz()方法 在下面	
                    }
                }
            }
        }
//这里是绘制棋子的方法
		function hz(x,y,r,co){//四个参数,xy棋子的位置,r棋子的半径,co棋子的颜色
            c.beginPath();//绘制起点
            c.arc((x * 40) + 20,(y * 40) + 20 ,r,0,2 * Math.PI);//绘制圆
            c.shadowBlur=10;//设置阴影
            c.shadowOffsetX=5; //设置阴影x长度
            c.shadowOffsetY=5; //设置阴影y长度
            c.shadowColor="#747371";//设置阴影颜色
            c.fillStyle = co;//设置颜色
            c.fill();//闭合起点
            c.shadowBlur=0;//初始化阴影,不然下次调用会叠加
            c.shadowOffsetX=0; //初始化阴影,
            c.shadowOffsetY=0; //初始化阴影,
            c.shadowColor="black";//初始化阴影,
        }
           

绘制棋子的方法就完成了

原生JS五子棋

现在就差最后一步,棋子的判定,判定棋子我是这样想的,一个棋子有八个方向,每次判断方向都是一个方向和一个相反的方向,所以我把它分为两部分,上下部分,然后就可以for循环,从左-右,左上-右下,上-下,右-上,左-下这样来,只需要循环四次。只要有5个棋子是在一个方向的,那么就获胜

原生JS五子棋
原生JS五子棋

每个棋子有八个方向需要判定,所以我分为上下两个部分

var fx = [[0,-1],[-1,-1],[-1,0],[-1,1]];//左 左上 上 右上  上半部分
var fx2 = [[0,1],[1,1],[1,0],[1,-1]];//左 左上 上 右上   下半部分 

var lsgs = 1;//连着的个数,因为要算上下的那颗棋子,所以默认为1
var cfhs = [];//存放获胜的数组  用来获胜的时候显示用

//三个参数,位置,当前下的棋子是黑还是白
		function pd(y,x,hb){//判断方法pd()
            for (var i = 0; i < 4; i++) {//循环方向数组
                pdfx(y,x,hb,i,1);//上半部分的判断, 1是上半部分,2是下半部分
                pdfx(y,x,hb,i,2);//下半部分的判定, 因为分为两部分,所以调用两次
                if(lsgs == 5){//如果连起来的个数是等于五的,那么就判定获胜
                    var msg = "";//定义获胜消息
                    msg = hb == 1? "黑棋" : "白棋";//绑定棋子对应的颜色
					  //把在html显示出获胜的信息
                    document.getElementById("ts").innerHTML = msg + "获胜!!!!!";
                    document.getElementById("ts").style.display = "block";
                    cfhs.push([y,x]);//还要把当前下的棋子的位置放进获胜数组里面
                    //获胜特效
                    for(var j = 0;j < cfhs.length;j++){//然后就是把获胜数组里面的棋子变大,观看效果好一点
                        hz(cfhs[j][1],cfhs[j][0],20,color[hb]);//绘制半径20的圆
                    }
                    //
                    ssss = 1;//游戏结束
                    return;
                }else{//连起来不是5颗棋子的
                    lsgs=1;//初始化连着的棋子
                    cfhs = [];//初始化连着棋子的数组
                }
            }
        }
		 //四个参数,xy方向,黑白棋子,哪个方向
		 function pdfx(y,x,hb,i,sx){//判断方向
		     var fxy;//当前的位置加上方向后的位置
		     var fxx ;//当前的位置加上方向后的位置
		     if(sx == 1){//上半部分
		         fxy = fx[i][0] + y;//加上方向后的位置
		         fxx = fx[i][1] + x;//加上方向后的位置
		         if(fxy < 0 || fxx < 0){//如果方向后的位置是棋谱外,直接放回连接的棋子个数
		             return lsgs;
		         }
		     }else{//下半部分
		         fxy = fx2[i][0] + y;//加上方向后的位置
		         fxx = fx2[i][1] + x;//加上方向后的位置
		         if(fxy > qijuHeight - 1 || fxx > qijuWidth - 1){//如果方向后的位置是棋谱外,直接放回连接的棋子个数
		             return lsgs;
		         }
		     }
		     if(qiju[fxy][fxx] == hb){//如果方向后的位置,还是跟下的棋子颜色一样,递归调用,延申方向
		         lsgs++;//连接个数加1
		         cfhs.push([fxy,fxx]);//存放连起来的数组;
		         pdfx(fxy,fxx,hb,i,sx)//递归
		     }
		 }
		//基本上就完成了,最后再加点鼠标移动的特效
		can.onmousemove = function(e){//鼠标移动事件
            if(ssss == 1){//是否结束
                return;
            }
            var Y = parseInt(e.layerY / 40);//位置
            var X = parseInt(e.layerX / 40);
            ht();//绘图
            if(qiju[Y][X] == 0){//
                hz(X,Y,20,color[hb])//绘制棋子
            }
        }
           

整个五子棋就完成了,最后最终代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JS五子棋</title>
    <style>
        
    </style>
</head>
 
<body style="background: rgb(248, 204, 179);">
    <canvas style="border:solid 2px red;margin: 50px;" id="can" height="600" width="600"></canvas>
    <div id="ts" style="font-size: 50px;display: none;"></div>
    <script>
        var qijuHeight = 15;//棋盘的横线个数
        var qijuWidth = 15;//棋盘的竖线个数
        var qiju = [];//定义一个储存棋子位置的变量 棋局
        /** @type {HTMLCanvasElement} */
        var can = document.getElementById("can");//获取canvas标签
        var c = can.getContext("2d");//把他转换成2d画布
        for(var y = 0;y < qijuHeight;y++){//绘制棋盘Y上的格子
            qiju.push([]);//在数组里面添加数组以充当Y轴
            for (var x = 0; x < qijuWidth; x++) {//绘制棋盘X上的格子
                qiju[y].push(0);//在二维数组里面添加棋子,0是空,1是黑棋,2是白棋
                if(y <14 && x < 14){//
                    c.strokeStyle = "black";//设置格子的颜色
                    //绘制每个格子的位置,因为画布比棋盘大40像素,我们要把棋盘居中就需要在XY上面加20像素-
                    c.strokeRect(x * 40 + 20,y * 40 + 20,40,40);
                }
            }
        }
        console.log(qiju);
        var ssss = 0;
        var hb = 1;//当前是黑棋还是白棋
        can.onclick = function(e){
            if(ssss == 1){
                return;
            }
            var Y = parseInt(e.layerY / 40);
            var X = parseInt(e.layerX / 40);
            if(qiju[Y][X] == 0){
                qiju[Y][X] = hb;
                pd(Y,X,hb);
                hb = hb == 1 ?2:1;
                if(ssss == 1){
                    return;
                }
                ht();
            }
        }
        var color = ["green","black","white"];//颜色数组
        function ht(){
            c.clearRect(0, 0, can.width, can.height);
            for(var y = 0;y < qijuHeight;y++){
                for (var x = 0; x < qijuWidth; x++){
                    if(y <14 && x < 14){//
                        c.strokeStyle = "black";//设置格子的颜色
                        //绘制每个格子的位置,因为画布比棋盘大40像素,我们要把棋盘居中就需要在XY上面加20像素-
                        c.strokeRect(x * 40 + 20,y * 40 + 20,40,40);
                    }
                    if(qiju[y][x] != 0){
                        hz(x,y,15,color[qiju[y][x]])
                    }
                }
            }
        }
        function hz(x,y,r,co){
            c.beginPath();
            c.arc((x * 40) + 20,(y * 40) + 20 ,r,0,2 * Math.PI);
            c.shadowBlur=10;
            c.shadowOffsetX=5;
            c.shadowOffsetY=5;
            c.shadowColor="#747371";
            c.fillStyle = co;
            c.fill();
            c.shadowBlur=0;
            c.shadowOffsetX=0;
            c.shadowOffsetY=0;
            c.shadowColor="black";
        }
        var fx = [[0,-1],[-1,-1],[-1,0],[-1,1]];//左 左上 上 右上
        var fx2 = [[0,1],[1,1],[1,0],[1,-1]];//左 左上 上 右上
        var lsgs = 1;//连着的个数,因为要算上下的那颗棋子,所以默认为1
        var cfhs = [];//存放获胜的数组
        function pd(y,x,hb){
            for (var i = 0; i < 4; i++) {
                pdfx(y,x,hb,i,1);
                pdfx(y,x,hb,i,2);
                if(lsgs == 5){
                    var msg = "";
                    msg = hb == 1? "黑棋" : "白棋";
                    document.getElementById("ts").innerHTML = msg + "获胜!!!!!";
                    document.getElementById("ts").style.display = "block";
                    cfhs.push([y,x]);
                    //获胜特效
                    for(var j = 0;j < cfhs.length;j++){
                        hz(cfhs[j][1],cfhs[j][0],20,color[hb]);
                    }
                    //
                    ssss = 1;
                    return;
                }else{
                    lsgs=1;
                    cfhs = [];
                }
            }
        }
        //四个参数,xy方向,黑白棋子,哪个方向,哪个部分
        function pdfx(y,x,hb,i,sx){//判断方向
            var fxy;//当前的位置加上方向后的位置
            var fxx ;//当前的位置加上方向后的位置
            if(sx == 1){//上半部分
                fxy = fx[i][0] + y;//加上方向后的位置
                fxx = fx[i][1] + x;//加上方向后的位置
                if(fxy < 0 || fxx < 0){//如果方向后的位置是棋谱外,直接放回连接的棋子个数
                    return lsgs;
                }
            }else{//下半部分
                fxy = fx2[i][0] + y;//加上方向后的位置
                fxx = fx2[i][1] + x;//加上方向后的位置
                if(fxy > qijuHeight - 1 || fxx > qijuWidth - 1){//如果方向后的位置是棋谱外,直接放回连接的棋子个数
                    return lsgs;
                }
            }
            if(qiju[fxy][fxx] == hb){//如果方向后的位置,还是跟下的棋子颜色一样,递归调用,延申方向
                lsgs++;//连接个数加1
                cfhs.push([fxy,fxx]);//存放连起来的数组;
                pdfx(fxy,fxx,hb,i,sx)//递归
            }
        }
        can.onmousemove = function(e){
            if(ssss == 1){
                return;
            }
            var Y = parseInt(e.layerY / 40);
            var X = parseInt(e.layerX / 40);
            ht();
            if(qiju[Y][X] == 0){
                hz(X,Y,20,color[hb])
            }
        }
    </script>
</body> 
</html>
           

这样一个150行代码的五子棋就完成了。

继续阅读