//V1.0 : 实现棋子的布局,画布及游戏场景的初始化
//V2.0 : 实现棋子的颜色改变
//V3.0 :实现所有象棋的走棋规则
//V4.0 : 实现所有棋子的吃子功能
完整的项目源码已经开源:https://github.com/xiugangzhang/ChineseChess
项目在线预览地址:
目前就实现了上面的几个功能,最近也么时间再弄了,需要的朋友可以自己下载下来继续开发哈!
主要特点:
1.无任何插件和第三方库,纯原生js实现
2.没使用任何素材,棋盘和棋子都是由canvas画布绘制
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="600px" height="660px">
</canvas>
<script>
//V1.0 : 实现棋子的布局,画布及游戏场景的初始化
//V2.0 : 实现棋子的颜色改变
//V3.0 :实现所有象棋的走棋规则
//V4.0 : 实现所有棋子的吃子功能
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
/**
* 棋子对象
* @param x
* @param y
* @param color
* @constructor
*/
function Chess(x, y, color, type) {
this.x = x;
this.y = y;
this.color = color;
this.type = type;
// 记录颜色
this.chessColor = color;
// 是否死掉
this.isDead = false;
}
// 成员函数
Chess.prototype = {
_getChessText: function () {
switch (this.type) {
case "CHE":
return "车";
case "MA":
return "马";
case "PAO":
return "炮";
case "BING":
return "兵";
case "JIANG":
return "将";
case "SHI":
return "士";
case "XIANG":
return "相";
}
return "错误";
}
}
/**
* 游戏场景
* @constructor
*/
function Game() {
// 存放当前棋盘上所有的棋子
this._chesses = [];
//初始位置
this._initX = 60;
this._initY = 60;
// 判断鼠标是否点击有棋子
this._selectedChess = null;
this._initCount = 0;
}
Game.prototype = {
// 场景的初始化
execute: function () {
this._initChesses();
this._start();
},
_initChesses: function () {
// 绘制棋子(初始位置)
// 总共需要绘制32颗棋子
// 红色棋子
var redChess;
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 9; j++) {
if ((i == 0 && j == 0) || (j == 8 && i == 0)) {
// 把棋子的颜色传进去
redChess = new Chess(j, i, "red", "CHE");
this._chesses.push(redChess);
} else if ((j == 1 && i == 0) || (j == 7 && i == 0 )) {
redChess = new Chess(j, i, "red", "MA");
this._chesses.push(redChess);
} else if ((j == 2 && i == 0) || (j == 6 && i == 0)) {
redChess = new Chess(j, i, "red", "XIANG");
this._chesses.push(redChess);
} else if ((j == 3 && i == 0) || (j == 5 && i == 0)) {
redChess = new Chess(j, i, "red", "SHI");
this._chesses.push(redChess);
} else if ((j == 4 && i == 0)) {
redChess = new Chess(j, i, "red", "JIANG");
this._chesses.push(redChess);
} else if ((j == 1 && i == 2) || (j == 7 && i == 2)) {
redChess = new Chess(j, i, "red", "PAO");
this._chesses.push(redChess);
} else if ((j == 0 && i == 3) || (j == 2 && i == 3) || (j == 4 && i == 3) || (j == 6 && i == 3) || (j == 8 && i == 3)) {
redChess = new Chess(j, i, "red", "BING");
this._chesses.push(redChess);
}
}
}
// 绘制黑色棋子
var blackChess;
for (var i = 6; i < 10; i++) {
for (var j = 0; j < 10; j++) {
if ((j == 0 && i == 9) || (j == 8 && i == 9)) {
blackChess = new Chess(j, i, "black", "CHE");
this._chesses.push(blackChess);
} else if ((j == 1 && i == 9) || (j == 7 && i == 9)) {
blackChess = new Chess(j, i, "black", "MA");
this._chesses.push(blackChess);
} else if ((j == 2 && i == 9) || (j == 6 && i == 9)) {
blackChess = new Chess(j, i, "black", "XIANG");
this._chesses.push(blackChess);
} else if ((j == 3 && i == 9) || (j == 5 && i == 9)) {
blackChess = new Chess(j, i, "black", "SHI");
this._chesses.push(blackChess);
} else if (j == 4 && i == 9) {
blackChess = new Chess(j, i, "black", "JIANG");
this._chesses.push(blackChess);
} else if ((j == 1 && i == 7) || (j == 7 && i == 7)) {
blackChess = new Chess(j, i, "black", "PAO");
this._chesses.push(blackChess);
} else if ((j == 0 && i == 6) || (j == 2 && i == 6) || (j == 4 && i == 6) || (j == 6 && i == 6) || (j == 8 && (i == 6))) {
blackChess = new Chess(j, i, "black", "BING");
this._chesses.push(blackChess);
}
}
}
//console.log(redChess);
//console.log(blackChess);
console.log(this._chesses);
},
/**
* 绘制棋子 车马相士将
* @private
*/
_drawChesses: function () {
var isDeadChess = null;
// 根据游戏中棋子的数目来绘制棋子
// 游戏中的棋子始终是32颗, 因此只能根据棋子是否存活来决定是否绘制这个棋子(原来的位置还是有棋子, 这是让他隐藏起来)
for (var i = 0; i < this._chesses.length; i++) {
var chess = this._chesses[i];
// 原来的位置还是有棋子, 这是让他隐藏起来
if (!chess.isDead) {
// 只有当这个棋子的属性isDead = false; 才绘制这个棋子
// 根据棋子的属性来绘制
context.fillStyle = "#C78843";
context.beginPath();
// 绘制棋子(注意要把棋子的初始位置复位)
context.arc(chess.x * 60 + this._initX, chess.y * 60 + this._initY, 25, 0, Math.PI * 2, true);
context.closePath();
context.fill();
// 绘制文本
if (chess.color == "red") {
context.fillStyle = 'red';
}
if (chess.color == "black") {
context.fillStyle = 'black';
}
if (chess.color == "blue") {
context.fillStyle = 'blue';
}
context.font = '43px 华文新魏';
context.fillText(chess._getChessText(), chess.x * 60 + this._initX - 22, chess.y * 60 + this._initY + 10);
}
else {
isDeadChess = chess;
}
}
// 有棋子被吃了,就重新开始
//this._selectedChess = null;
if (this._initCount == 0) {
//console.log(chess.x+","+chess.y+","+chess.type+"已经隐藏");
}
},
_drawChessboard: function () {
context.strokeStyle = "black";
// 绘制棋盘外边界
context.lineWidth = 3;
context.beginPath();
context.moveTo(0, 0);
context.lineTo(600, 0);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(0, 0);
context.lineTo(0, 660);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(600, 0);
context.lineTo(600, 660);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(0, 660);
context.lineTo(660, 660);
context.closePath();
context.stroke();
// 内部的外边界
context.beginPath();
context.moveTo(40, 40);
context.lineTo(40, 620);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(40, 40);
context.lineTo(560, 40);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(560, 40);
context.lineTo(560, 620);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(560, 620);
context.lineTo(40, 620);
context.closePath();
context.stroke();
//棋盘横线
context.lineWidth = 1;
for (var i = 1; i < 11; i++) {
context.beginPath();
context.moveTo(60, 60 * i);
context.lineTo(540, 60 * i);
context.closePath();
context.stroke();
}
// 棋盘纵线
for (var i = 1; i < 10; i++) {
context.beginPath();
context.moveTo(i * 60, 60);
context.lineTo(i * 60, 300);
context.closePath();
context.stroke();
}
for (var i = 1; i < 10; i++) {
context.beginPath();
context.moveTo(i * 60, 360);
context.lineTo(i * 60, 600);
context.closePath();
context.stroke();
}
context.beginPath();
context.moveTo(60, 300);
context.lineTo(60, 360);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(540, 300);
context.lineTo(540, 360);
context.closePath();
context.stroke();
// 棋盘斜线
context.beginPath();
context.moveTo(240, 60);
context.lineTo(360, 180);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(360, 60);
context.lineTo(240, 180);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(240, 480);
context.lineTo(360, 600);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(360, 480);
context.lineTo(240, 600);
context.closePath();
context.stroke();
// 绘制炮的位置(左上)
context.beginPath();
context.moveTo(115, 160);
context.lineTo(115, 175);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(115, 175);
context.lineTo(100, 175);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(125, 160);
context.lineTo(125, 175);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(125, 175);
context.lineTo(140, 175);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(115, 185);
context.lineTo(115, 200);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(115, 185);
context.lineTo(100, 185);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(125, 185);
context.lineTo(125, 200);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(125, 185);
context.lineTo(140, 185);
context.closePath();
context.stroke();
// 右上
context.beginPath();
context.moveTo(475, 175);
context.lineTo(460, 175);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(475, 175);
context.lineTo(475, 160);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(485, 160);
context.lineTo(485, 175);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(485, 175);
context.lineTo(500, 175);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(485, 185);
context.lineTo(485, 200);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(485, 185);
context.lineTo(500, 185);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(475, 185);
context.lineTo(475, 200);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(475, 185);
context.lineTo(460, 185);
context.closePath();
context.stroke();
// 左下
context.beginPath();
context.moveTo(115, 485);
context.lineTo(115, 500);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(115, 485);
context.lineTo(100, 485);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(115, 475);
context.lineTo(100, 475);
context.closePath();
context.stroke();
context.beginPath();
context.moveTo(115, 475);
context.lineTo(115, 460);
context.closePath();