对于一些复杂或不规则的UI,我们可能无法通过组合其它组件的方式来实现,比如我们需要一个
- 正六边形
- 一个渐变的圆形进度条
- 一个棋盘等。
当然,有时候我们可以使用图片来实现,但在一些需要动态交互的场景静态图片也是实现不了的,比如要实现一个手写输入面板,这时,我们就需要来自己绘制UI外观
几乎所有的UI系统都会提供一个自绘UI的接口,这个接口通常会提供一块2D画布Canvas,Canvas内部封装了一些基本绘制的API,开发者可以通过Canvas绘制各种自定义图形。在Flutter中,提供了一个CustomPaint 组件,它可以结合画笔CustomPainter来实现自定义图形绘制。
CustomPaint
我们看看CustomPaint构造函数:
CustomPaint({
Key key,
this.painter,
this.foregroundPainter,
this.size = Size.zero,
this.isComplex = false,
this.willChange = false,
Widget child, //子节点,可以为空
})
- painter: 背景画笔,会显示在子节点后面;
- foregroundPainter: 前景画笔,会显示在子节点前面
- size:
- 当child为null时,代表默认绘制区域大小
- 如果有child则忽略此参数,画布尺寸则为child尺寸
- 如果有child但是想指定画布为特定大小,可以使用SizeBox包裹CustomPaint实现。
- isComplex:是否复杂的绘制,如果是,Flutter会应用一些缓存策略来减少重复渲染的开销。
- willChange:和isComplex配合使用,当启用缓存时,该属性代表在下一帧中绘制是否会改变。
可以看到,绘制时我们需要提供前景或背景画笔,两者也可以同时提供。我们的画笔需要继承CustomPainter类,我们在画笔类中实现真正的绘制逻辑
注意
如果CustomPaint有子节点,为了避免子节点不必要的重绘并提高性能,通常情况下都会将子节点包裹在RepaintBoundary组件中,这样会在绘制时就会创建一个新的绘制层(Layer),其子组件将在新的绘制层(Layer)上绘制,而父组件将在原来Layer上绘制,也就是说RepaintBoundary 子组件的绘制将独立于父组件的绘制,RepaintBoundary会隔离其子节点和CustomPaint本身的绘制边界。示例如下:
CustomPaint(
size: Size(300, 300), //指定画布大小
painter: MyPainter(),
child: RepaintBoundary(child:...)),
)
CustomPainter
CustomPainter中提定义了一个虚函数paint:
void paint(Canvas canvas, Size size);
paint有两个参数:
- Canvas:一个画布,包括各种绘制方法,我们列出一下常用的方法:
- drawLine 画线
- drawPoint 画点
- drawPath 画路径
- drawImage 画图像
- drawRect 画矩形
- drawCircle 画圆
- drawOval 画椭圆
- drawArc 画圆弧
- Size:当前绘制区域大小
画笔Paint
现在画布有了,我们最后还缺一个画笔,Flutter提供了Paint类来实现画笔。在Paint中,我们可以配置画笔的各种属性如粗细、颜色、样式等。如:
var paint = Paint() //创建一个画笔并配置其属性
..isAntiAlias = true //是否抗锯齿
..style = PaintingStyle.fill //画笔样式:填充
..color=Color(0x77cdb175);//画笔颜色
更多的配置属性读者可以参考Paint类定义。
示例:五子棋/盘
下面我们通过一个五子棋游戏中棋盘和棋子的绘制来演示自绘UI的过程,首先我们看一下我们的目标效果,如图所示:
代码:
import 'package:flutter/material.dart';
import 'dart:math';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: true,
title: 'CustomPaintRoute',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(title: Text("CustomPaintRoute")),
body: CustomPaintRoute(),
));
}
}
class CustomPaintRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: CustomPaint(
size: Size(300, 300), //指定画布大小
painter: MyPainter(),
),
);
}
}
class MyPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
double eWidth = size.width / 15;
double eHeight = size.height / 15;
//画棋盘背景
var paint = Paint()
..isAntiAlias = true
..style = PaintingStyle.fill //填充
..color = Color(0x77cdb175); //背景为纸黄色
canvas.drawRect(Offset.zero & size, paint);
//画棋盘网格
paint
..style = PaintingStyle.stroke //线
..color = Colors.black87
..strokeWidth = 1.0;
for (int i = 0; i <= 15; ++i) {
double dy = eHeight * i;
canvas.drawLine(Offset(0, dy), Offset(size.width, dy), paint);
}
for (int i = 0; i <= 15; ++i) {
double dx = eWidth * i;
canvas.drawLine(Offset(dx, 0), Offset(dx, size.height), paint);
}
//画一个黑子
paint
..style = PaintingStyle.fill
..color = Colors.black;
canvas.drawCircle(
Offset(size.width / 2 - eWidth / 2, size.height / 2 - eHeight / 2),
min(eWidth / 2, eHeight / 2) - 2,
paint,
);
//画一个白子
paint.color = Colors.white;
canvas.drawCircle(
Offset(size.width / 2 + eWidth / 2, size.height / 2 - eHeight / 2),
min(eWidth / 2, eHeight / 2) - 2,
paint,
);
}
//在实际场景中正确利用此回调可以避免重绘开销,本示例我们简单的返回true
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
性能
绘制是比较昂贵的操作,所以我们在实现自绘控件时应该考虑到性能开销,下面是两条关于性能优化的建议:
- 尽可能的利用好shouldRepaint返回值:在UI树重新build时,控件在绘制前都会先调用该方法以确定是否有必要重绘;
- 假如我们绘制的UI不依赖外部状态,那么就应该始终返回false,因为外部状态改变导致重新build时不会影响我们的UI外观;
- 如果绘制依赖外部状态,那么我们就应该在shouldRepaint中判断依赖的状态是否改变,如果已改变则应返回true来重绘,反之则应返回false不需要重绘。
绘制尽可能多的分层:在上面五子棋的示例中,我们将棋盘和棋子的绘制放在了一起,这样会有一个问题:由于棋盘始终是不变的,用户每次落子时变的只是棋子,但是如果按照上面的代码来实现,每次绘制棋子时都要重新绘制一次棋盘,这是没必要的。优化的方法就是将棋盘单独抽为一个组件,并设置其shouldRepaint回调值为false,然后将棋盘组件作为背景。然后将棋子的绘制放到另一个组件中,这样每次落子时只需要绘制棋子。
总结
自绘控件非常强大,理论上可以实现任何2D图形外观,实际上Flutter提供的所有组件最终都是通过调用Canvas绘制出来的,只不过绘制的逻辑被封装起来了,读者有兴趣可以查看具有外观样式的组件源码,找到其对应的RenderObject对象,
如Text对应的RenderParagraph对象最终会通过Canvas实现文本绘制逻辑
对比HTML+JS中的canvas
<style>
canvas { background:rgba(222, 222, 222, 0.3) }
div { background: gray;float: left;}
</style>
<div></div><canvas id="myCanvas" width="400px" height="400px"></canvas></div>
<div><canvas id="mycanvas2" width="600px" height="600px"></canvas></div>
<div><canvas id="mycanvas3" width="800px" height="500px" style="background: red;"></canvas></div>
<div> <canvas id="mycanvas4" width="500px" height="500px"></canvas></div>
<script>
var c = document.querySelector("#myCanvas");
var ctx = c.getContext("2d");
var cX = 200; //y轴坐标
var cY = 200; //x轴坐标
var r = 200; //半径
var deg = 0; //角度
var angle = deg * Math.PI / 180; //弧度
var start = Math.PI / 2;
var end = start + Math.PI;
var ang = Math.PI / 180; //弧度
function drawCirle(ctx, x, y, r, start, end, color = "#000", anti = false) {
ctx.beginPath();
ctx.fillStyle = color;
ctx.arc(x, y, r, start, end, anti);
ctx.fill();
}
setInterval(function () {
ctx.clearRect(0, 0, c.width, c.height);
drawCirle(ctx, cX, cY, r, start + deg * ang, end + deg * ang, "#000", false);
drawCirle(ctx, cX, cY, r, start + deg * ang, end + deg * ang, "#fff", true);
drawCirle(ctx, cX + (r / 2) * Math.sin(deg * ang), cY - (r / 2) * Math.cos(deg * ang), r / 2, 0, Math.PI * 2, "#000", true);
drawCirle(ctx, cX - (r / 2) * Math.sin(deg * ang), cY + (r / 2) * Math.cos(deg * ang), r / 2, 0, Math.PI * 2, "#fff", false);
drawCirle(ctx, cX + (r / 2) * Math.sin(deg * ang), cY - (r / 2) * Math.cos(deg * ang), 20, 0, Math.PI * 2, "#fff", true);
drawCirle(ctx, cX - (r / 2) * Math.sin(deg * ang), cY + (r / 2) * Math.cos(deg * ang), 20, 0, Math.PI * 2, "#000", true);
deg++;
c.style.transform = "rotate(" + deg + "deg)";
}, 100);
</script>
<script>
var mycanvas = document.querySelector("#mycanvas2");
var ctx2 = mycanvas.getContext("2d");
setInterval(function () {
ctx2.beginPath();
ctx2.strokeStyle = "rgb(" + rand(0, 255) + "," + rand(0, 255) + "," + rand(0, 255) + ")";
ctx2.lineWidth = 3;
ctx2.moveTo(rand(0, 500), rand(0, 500));
ctx2.lineTo(rand(0, 600), rand(0, 600));
ctx2.stroke();
}, 1000);
function rand(min, max) {
return Math.round(Math.random() * (max - min)) + min;
}
setInterval(function () {
ctx2.beginPath();
//填充坐标
ctx2.fillRect(rand(0, 300), rand(0, 300), rand(0, 300), rand(0, 300));
//边框颜色
ctx2.strokeStyle = "rgb(" + rand(0, 200) + "," + rand(0, 200) + "," + rand(0, 200) + ")";
ctx2.lineWidth = 2;
//边框坐标
ctx2.strokeRect(rand(1, 300), rand(1, 300), rand(1, 300), rand(1, 300));
//填充颜色
ctx2.fillStyle = "rgb(" + rand(0, 255) + "," + rand(0, 255) + "," + rand(0, 255) + ")";
}, 3000)
</script>
<script type="text/javascript">
var mycanvas=document.querySelector("#mycanvas3");
var cx=mycanvas.getContext("2d");
function drawstar(cxt,x,y,R,r,fillStyle,rot){
cxt.beginPath();
for (var i=0;i<5;i++) {
cxt.lineTo(Math.cos((18+72*i)/180*Math.PI+rot)*R+x,-Math.sin((18+72*i)/180*Math.PI+rot)*R+y);
cxt.lineTo(Math.cos((54+72*i)/180*Math.PI+rot)*r+x,-Math.sin((54+72*i)/180*Math.PI+rot)*r+y);
}
cxt.fillStyle=fillStyle;
cxt.closePath();
cxt.fill()
}
drawstar(cx,120,130,80,35,"yellow",0)
drawstar(cx,250,50,30,12,"yellow",12)
drawstar(cx,300,110,30,12,"yellow",-12)
drawstar(cx,290,200,30,12,"yellow",-12)
drawstar(cx,220,250,30,12,"yellow",12)
</script>
<script type="text/javascript">
var mycanvas = document.querySelector("#mycanvas4");
var cx = mycanvas.getContext("2d");
function drawCircle({fillStyle,x,y,r,start,end,color}) {
cx.beginPath();
cx.fillStyle = color||"#fff";
cx.arc(x||250, y||250, r||200, start||0, end||Math.PI*2)
cx.fill();
}
function drawLine({strokeColor,lineWidth,y,r,start,end,color,x1,y1,x2,y2}) {
cx.beginPath();
cx.strokeStyle=strokeColor||"red";
cx.lineWidth=lineWidth||"8"
cx.moveTo(x1||240,y1||140);
cx.lineTo(x2||160,y2||220);
cx.stroke();
}
drawCircle({color:'red',x:250,y:250,r:200})
drawCircle({color:'#fff',x:250,y:250,r:194})
drawCircle({color:'red',x:250,y:250,r:190})
drawCircle({color:'#fff',x:250,y:250,r:145})
drawCircle({color:'red',x:250,y:250,r:139})
drawCircle({color:'#fff',x:250,y:250,r:133})
drawLine({x1:240,y1:140,x2:160,y2:220})
drawLine({x1:160,y1:216,x2:228,y2:300})
drawLine({x1:228,y1:300,x2:280,y2:300})
</script>
JS画板绘图
<style type="text/css">
body{background-color:#8fbc8f;}
#bj{margin:0 400px;width:530px;height:700px;border-radius:20px;background-color:#000;}
canvas{margin:15px;border-radius:20px;background-color:#fff;}
#to{margin:0 100px;color:#FFF;}
input{margin:0 8px;}
</style>
<div id="bj">
<canvas id="mycanvas" width="500px" height="600px"></canvas>
<div id="to">
画笔颜色:<input id="color" type="color" /> 画笔大小:
<input type="number" id="number" min="1" max="20" value="1" />
</div>
</div>
<script>
var mycanvas = document.querySelector("#mycanvas");
var cxt = mycanvas.getContext("2d");
var color = "#000";
var lineWith = 2;
//接触鼠标时候,然后在移动鼠标时候
mycanvas.onmousedown = function (e) {
start_draw();
cxt.moveTo(e.clientX - mycanvas.offsetLeft, e.clientY - mycanvas.offsetTop);
mycanvas.addEventListener("mousemove", draw);
}
//松开鼠标
mycanvas.onmouseup = function () {
mycanvas.removeEventListener("mousemove", draw);
}
//选择画笔
document.querySelector("#color").oninput = function () {
color = this.value;
}
//选择画笔大小
document.querySelector("#number").oninput = function () {
lineWith = this.value;
}
//开始画
function start_draw() {
cxt.beginPath();
cxt.strokeStyle = color;
cxt.lineWidth = lineWith;
}
function draw(e) {
e.preventDefault();
cxt.lineTo(e.clientX - mycanvas.offsetLeft, e.clientY - mycanvas.offsetTop);
cxt.stroke();
}
</script>
JS canvas绘制象棋
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<!--<script src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script>-->
<!--<link rel="stylesheet" type="text/css" href="css/chess.css"/>-->
<script src="js/jquery.js" type="text/javascript" charset="utf-8"></script>
</head>
<style type="text/css">
* {
margin: 0;
padding: 0
}
#Wrap {
width: 700px;
height: 640px;
margin: 0 auto
}
#currActive {
font-size: 30px;
font-weight: 700;
margin-left: 260px;
margin: 8px 250px
}
#canvas {
float: left;
background: #EAC591;
display: block
}
#take_notes {
width: 80px;
height: 645px;
padding: 10px;
float: right;
overflow: hidden;
display: flex;
flex-direction: column-reverse;
}
#ul {
list-style: none;
margin: 0;
padding: 0
}
#ul li {
padding: 2px;
overflow: hidden
}
#shuying {
float: left
}
#shuying p {
margin: 10px;
font-size: 30px
}
#main {
width: 600px;
height: 150px;
-webkit-justify-content: space-around;
display: flex; //分横栏
justify-content: space-around
}
#main div {
width: 100px;
height: 50px;
line-height: 50px;
text-align: center;
margin-top: 10px;
border-radius: 20%;
font-weight: 700
}
#main div a {
text-decoration: none;
color: #000
}
#main div a:hover {
color: #00f
}
#main div ul {
list-style: none;
position: relative
}
#main div ul {
position: absolute
}
.daohang {
position: absolute;
display: none;
margin-left: 18px;
margin-top: -190px;
background: pink;
border-radius: 10%
}
.daohang a {
font: "微软雅黑";
font-size: 15px;
margin-top: -6px
}
#dianji:hover .daohang {
display: block
}
#red_zi {
color: red
}
</style>
<body>
<div id="Wrap">
<div id="currActive"></div>
<canvas id="canvas" width="600" height="660"></canvas>
<div id="take_notes">
<div id="shuying"></div>
<ul id="ul"></ul>
</div>
<div id="main">
<div style="background-color:coral;"><a href="canvas绘制象棋.html">重新开始</a></div>
<div style="background-color:lightblue;"><a href="#">提示</a></div>
<div style="background-color:khaki;"><a href="#">悔棋</a></div>
<div style="background-color:pink;" id="dianji">
<a href="#">设置</a>
<ul class="daohang">
<li class="daohang_1"><a href="#">棋盘大小</a></li>
<li class="daohang_2"><a href="#">棋子大小</a></li>
<li class="daohang_3"><a href="#">棋子颜色</a></li>
</ul>
</div>
</div>
</body>
<script>
var obj = {};
// 棋盘初始化
obj.init = function (lqfs) {
var canvas = document.querySelector("canvas");
this.ctx = canvas.getContext("2d");
// 棋盘初始化
obj.init_back = function () {
this.drawRowLine();
this.drawColLine();
this.ctx.clearRect(this.chunk + 1, this.chunk * 5 + 1, this.chunk * 8 - 2, this.chunk - 2);
this.drawsharpS();
this.drawX();
this.drawText();
}
// this.chunk =lqfs&&lqfs.chunk?lqfs.chunk:50;
// this.radius =lqfs&&lqfs.radius?lqfs.radius:23;
// this.CandidateCircleR =lqfs&&lqfs.ccr?lqfs.ccr:5;
/*---------------------------可以修改棋盘、棋子大小,颜色,谁先手 ------------------------------------------------------------*/
obj.chunk = 60; //棋盘线格大小
this.radius = this.chunk / 2 - 3; // 棋子半径
this.CandidateCircleR = this.chunk / 10; //候选棋子的半径大小
this.drawCandidateCircle_fillStyle = "#fff"; //候选的内圆颜色
this.drawCandidateCircle_strokeStyle = "red"; //候选的内圆边框原色
this.drawCandidateCircle_lineWidth = 2; //候选内圆的边框大小
this.init_back();
this.init_chess();
$(canvas).unbind();
this.addEvent();
this.Notations = []; // 记录步骤
this.currActive = "red"; // 先下
$("#currActive").text("红方先下").css({ "color": "red", })
/*---------------------------------------------------------------------------------------------------------------------------------*/
}
/*---------------------------------------------------------------------------------------------------------------------------------*/
// 棋子初始化
obj.init_chess = function () {
//上方(红)
var Car_b1 = { x: 1, y: 1, text: "車" }
var Horse_b1 = { x: 2, y: 1, text: "馬" }
var Elephant_b1 = { x: 3, y: 1, text: "象" }
var Scholar_b1 = { x: 4, y: 1, text: "士" }
var Boss_b = { x: 5, y: 1, text: "将" }
var Scholar_b2 = { x: 6, y: 1, text: "士" }
var Elephant_b2 = { x: 7, y: 1, text: "象" }
var Horse_b2 = { x: 8, y: 1, text: "馬" }
var Car_b2 = { x: 9, y: 1, text: "車" }
var Cannon_b1 = { x: 2, y: 3, text: "炮" }
var Cannon_b2 = { x: 8, y: 3, text: "炮" }
var Soldier_b1 = { x: 1, y: 4, text: "卒" }
var Soldier_b2 = { x: 3, y: 4, text: "卒" }
var Soldier_b3 = { x: 5, y: 4, text: "卒" }
var Soldier_b4 = { x: 7, y: 4, text: "卒" }
var Soldier_b5 = { x: 9, y: 4, text: "卒" }
//下方(黑)
var Car_r1 = { x: 1, y: 10, text: "車" }
var Horse_r1 = { x: 2, y: 10, text: "馬" }
var Elephant_r1 = { x: 3, y: 10, text: "相" }
var Scholar_r1 = { x: 4, y: 10, text: "仕" }
var Boss_r = { x: 5, y: 10, text: "帅" }
var Scholar_r2 = { x: 6, y: 10, text: "仕" }
var Elephant_r2 = { x: 7, y: 10, text: "相" }
var Horse_r2 = { x: 8, y: 10, text: "馬" }
var Car_r2 = { x: 9, y: 10, text: "車" }
var Cannon_r1 = { x: 2, y: 8, text: "炮" }
var Cannon_r2 = { x: 8, y: 8, text: "炮" }
var Soldier_r1 = { x: 1, y: 7, text: "兵" }
var Soldier_r2 = { x: 3, y: 7, text: "兵" }
var Soldier_r3 = { x: 5, y: 7, text: "兵" }
var Soldier_r4 = { x: 7, y: 7, text: "兵" }
var Soldier_r5 = { x: 9, y: 7, text: "兵" }
this.cheer_arr_B = [Car_b1, Horse_b1, Elephant_b1, Scholar_b1, Boss_b, Scholar_b2, Elephant_b2, Horse_b2, Car_b2,
Cannon_b1, Cannon_b2, Soldier_b1, Soldier_b2, Soldier_b3, Soldier_b4, Soldier_b5];
this.cheer_arr_R = [Car_r1, Horse_r1, Elephant_r1, Scholar_r1, Boss_r, Scholar_r2, Elephant_r2, Horse_r2, Car_r2,
Cannon_r1, Cannon_r2, Soldier_r1, Soldier_r2, Soldier_r3, Soldier_r4, Soldier_r5];
var that = this;
$.each(this.cheer_arr_B, function (i, e) {
e.color = "#000"; //圆的文字颜色
e.bgcolor = "#fff"; //圆的背景颜色
e.bgColor_b = "#000"; //外边的框颜色
e.type = "black";
that.drawPiece(e);
that.drawChessText(e);
});
$.each(this.cheer_arr_R, function (i, e) {
e.color = "#f00"; //圆的文字颜色
e.bgcolor = "#fff"; //圆的背景颜色
e.bgColor_b = "#f00"; //外边的框颜色
e.type = "red";
that.drawPiece(e);
that.drawChessText(e);
});
this.cheer_arr_ALL = this.cheer_arr_B.concat(this.cheer_arr_R);
}
/*--------------------------------------------------------------------------------------------------------------------------------------*/
// 画棋子形状
obj.drawPiece = function (e) {
this.ctx.beginPath();
this.ctx.fillStyle = e.bgcolor;
this.ctx.strokeStyle = e.bgColor_b;
this.ctx.lineWidth = 2;
this.ctx.arc(e.x * this.chunk, e.y * this.chunk, this.radius, 0, Math.PI * 2, true); //this.radius棋子大小
this.ctx.closePath();
this.ctx.fill();
this.ctx.stroke();
}
/*--------------------------------------------------------------------------------------------------------------------------------------*/
// 画棋子文字
obj.drawChessText = function (e) {
var font = "" + this.chunk / 1.5 + "px "
this.ctx.font = "bold " + font + " Courier New";
this.ctx.fillStyle = e.color;
var offset = this.ctx.measureText(e.text).width / 2;
this.ctx.fillText(e.text, e.x * this.chunk - offset, e.y * this.chunk + this.chunk / 4.5);
}
/*---------------------------------------------------------------------------------------------------------------------------------*/
// 画直线
obj.drawLine = function (x0, y0, x1, y1, lw) {
this.ctx.beginPath();
var x0 = x0 * this.chunk;
var y0 = y0 * this.chunk;
var x1 = x1 * this.chunk;
var y1 = y1 * this.chunk;
this.ctx.strokeStyle = "#000";
this.ctx.lineWidth = lw ? lw : 1;
this.ctx.moveTo(x0, y0);
this.ctx.lineTo(x1, y1);
this.ctx.closePath();
this.ctx.stroke();
}
/*---------------------------------------------------------------------------------------------------------------------------------*/
// 画横线
obj.drawRowLine = function () {
for (var i = 1; i <= 10; i++) {
this.drawLine(1, i, 9, i);
}
}
// 画竖线
obj.drawColLine = function () {
for (var i = 1; i <= 9; i++) {
this.drawLine(i, 1, i, 10);
}
}
// 画X
obj.drawX = function () {
this.drawLine(4, 1, 6, 3, 0.5);
this.drawLine(4, 3, 6, 1, 0.5);
this.drawLine(4, 8, 6, 10, 0.5);
this.drawLine(4, 10, 6, 8, 0.5);
}
/*---------------------------------------------------------------------------------------------------------------------------------*/
// 画单个#
obj.drawsharp = function (x, y) {
var x = x * this.chunk;
var y = y * this.chunk;
var range_y = this.chunk / 4.3; /*#的竖的距离*/
var range_x = this.chunk / 4.3; /*#的横的距离*/
var range_close = this.chunk / 12; /*间隔距离*/
/*var range_y=10;
var range_x=10;
var range_close=5; */
this.ctx.beginPath();
this.ctx.strokeStyle = "#000";
this.ctx.lineWidth = 1;
if (x != 1) {
// 左上
this.ctx.moveTo(x - range_close, y - range_y);
this.ctx.lineTo(x - range_close, y - range_close);
this.ctx.lineTo(x - range_x, y - range_close);
// 左下
this.ctx.moveTo(x - range_close, y + range_y);
this.ctx.lineTo(x - range_close, y + range_close);
this.ctx.lineTo(x - range_x, y + range_close);
}
if (x != 9) {
// 右上
this.ctx.moveTo(x + range_close, y - range_y);
this.ctx.lineTo(x + range_close, y - range_close);
this.ctx.lineTo(x + range_x, y - range_close);
// 右下
this.ctx.moveTo(x + range_close, y + range_y);
this.ctx.lineTo(x + range_close, y + range_close);
this.ctx.lineTo(x + range_x, y + range_close);
}
this.ctx.stroke();
this.ctx.closePath();
}
// 画#
/*obj.drawsharpS = function(){
this.drawsharp(2,3);
this.drawsharp(8,3);
this.drawsharp(1,4);
this.drawsharp(3,4);
this.drawsharp(5,4);
this.drawsharp(7,4);
this.drawsharp(9,4);
this.drawsharp(2,8);
this.drawsharp(8,8);
this.drawsharp(1,7);
this.drawsharp(3,7);
this.drawsharp(5,7);
this.drawsharp(7,7);
this.drawsharp(9,7);
}*/
//用循环函数的并和画#
obj.drawsharpS = function () {
this.drawsharp(2, 3);
this.drawsharp(8, 3);
for (var i = 1; i <= 5; i++) {
this.drawsharp(2 * i - 1, 4)
}
for (var i = 1; i <= 5; i++) {
this.drawsharp(2 * i - 1, 7)
}
this.drawsharp(2, 8);
this.drawsharp(8, 8);
}
/*--------------------------------------------------------------------------------------------------------------------------------------*/
// 画楚河/漢界
obj.drawText = function () {
var font = "" + this.chunk / 1.5 + "px ";
this.ctx.font = "bold " + font + " KaiTi_GB2312";
this.ctx.fillStyle = "#000";
this.ctx.fillText("楚 河", this.chunk * 2, this.chunk * 5 + this.chunk / 1.3);
this.ctx.fillText("漢 界", this.chunk * 6 + this.chunk / 3, this.chunk * 5 + this.chunk / 1.3);
var font1 = "" + this.chunk / 6 + "px"
this.ctx.font = "" + font1 + " Courier New";
this.text_arr = ["九", "八", "七", "六", "五", "四", "三", "二", "一"];
for (var i = 0; i < 9; i++) {
this.ctx.fillText((i + 1).toString(), this.chunk * (i + 1) - 5, 20);
this.ctx.fillText(this.text_arr[i], this.chunk * (i + 1) - 5, this.chunk * 11 - this.chunk / 6);
}
}
/*---------------------------------------------------------------------------------------------------------------------------------*/
// 画候选形状
obj.drawCandidateCircle = function (x, y) {
this.ctx.beginPath();
this.ctx.fillStyle = this.drawCandidateCircle_fillStyle; //候选内圆的颜色
this.ctx.strokeStyle = this.drawCandidateCircle_strokeStyle; //候选内圆的边框颜色
this.ctx.lineWidth = this.drawCandidateCircle_lineWidth; //候选内圆的边框大小
this.ctx.arc(x * this.chunk, y * this.chunk, this.CandidateCircleR, 0, Math.PI * 2, true);
this.ctx.closePath();
this.ctx.fill();
this.ctx.stroke();
}
// 画选中棋子状态
obj.drawChecked = function (p) {
//画候选的形状
var temp_x = p.x * this.chunk;
var temp_y = p.y * this.chunk;
this.ctx.beginPath();
this.ctx.strokeStyle = "#00f";
this.ctx.lineWidth = 1;
this.ctx.moveTo(temp_x - this.radius, temp_y - this.radius + 10); //this.radius棋子大小
this.ctx.lineTo(temp_x - this.radius, temp_y - this.radius);
this.ctx.lineTo(temp_x - this.radius + 10, temp_y - this.radius);
this.ctx.moveTo(temp_x - this.radius, temp_y + this.radius - 10);
this.ctx.lineTo(temp_x - this.radius, temp_y + this.radius);
this.ctx.lineTo(temp_x - this.radius + 10, temp_y + this.radius);
this.ctx.moveTo(temp_x + this.radius, temp_y - this.radius + 10);
this.ctx.lineTo(temp_x + this.radius, temp_y - this.radius);
this.ctx.lineTo(temp_x + this.radius - 10, temp_y - this.radius);
this.ctx.moveTo(temp_x + this.radius, temp_y + this.radius - 10);
this.ctx.lineTo(temp_x + this.radius, temp_y + this.radius);
this.ctx.lineTo(temp_x + this.radius - 10, temp_y + this.radius);
this.ctx.stroke();
this.ctx.closePath();
}
// 画候选位置
obj.drawCandidate = function () {
switch (this.action.text) {
case "車":
var temp_y = this.action.y;
while (!this.inArray(this.action.x, ++temp_y) && temp_y <= 10) {
this.drawCandidateCircle(this.action.x, temp_y);
}
var temp_y = this.action.y;
while (!this.inArray(this.action.x, --temp_y) && temp_y > 0) {
this.drawCandidateCircle(this.action.x, temp_y);
}
var temp_x = this.action.x;
while (!this.inArray(++temp_x, this.action.y) && temp_x < 10) {
this.drawCandidateCircle(temp_x, this.action.y);
}
var temp_x = this.action.x;
while (!this.inArray(--temp_x, this.action.y) && temp_x > 0) {
this.drawCandidateCircle(temp_x, this.action.y);
}
break;
case "馬":
if (!this.inArray(this.action.x - 2, this.action.y - 1)
&& this.action.x - 2 >= 1 && this.action.y - 1 >= 1
&& !this.inArray(this.action.x - 1, this.action.y)) {
this.drawCandidateCircle(this.action.x - 2, this.action.y - 1);
}
if (!this.inArray(this.action.x - 1, this.action.y - 2)
&& this.action.x - 1 >= 1 && this.action.y - 2 >= 1
&& !this.inArray(this.action.x, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x - 1, this.action.y - 2);
}
if (!this.inArray(this.action.x + 1, this.action.y - 2)
&& this.action.x + 1 <= 9 && this.action.y - 2 >= 1
&& !this.inArray(this.action.x, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x + 1, this.action.y - 2);
}
if (!this.inArray(this.action.x + 2, this.action.y - 1)
&& this.action.x + 2 <= 9 && this.action.y - 1 >= 1
&& !this.inArray(this.action.x + 1, this.action.y)) {
this.drawCandidateCircle(this.action.x + 2, this.action.y - 1);
}
if (!this.inArray(this.action.x + 2, this.action.y + 1)
&& this.action.x + 2 <= 9 && this.action.y + 1 <= 10
&& !this.inArray(this.action.x + 1, this.action.y)) {
this.drawCandidateCircle(this.action.x + 2, this.action.y + 1);
}
if (!this.inArray(this.action.x + 1, this.action.y + 2)
&& this.action.x + 1 <= 9 && this.action.y + 2 <= 10
&& !this.inArray(this.action.x, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x + 1, this.action.y + 2);
}
if (!this.inArray(this.action.x - 1, this.action.y + 2)
&& this.action.x - 1 >= 1 && this.action.y + 2 <= 10
&& !this.inArray(this.action.x, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x - 1, this.action.y + 2);
}
if (!this.inArray(this.action.x - 2, this.action.y + 1)
&& this.action.x - 2 >= 1 && this.action.y + 1 <= 10
&& !this.inArray(this.action.x - 1, this.action.y)) {
this.drawCandidateCircle(this.action.x - 2, this.action.y + 1);
}
break;
case "相":
if (this.action.y == 10) {
if (!this.inArray(this.action.x - 2, this.action.y - 2)
&& !this.inArray(this.action.x - 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x - 2, this.action.y - 2);
}
if (!this.inArray(this.action.x + 2, this.action.y - 2)
&& !this.inArray(this.action.x + 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x + 2, this.action.y - 2);
}
} else if (this.action.y == 6) {
if (!this.inArray(this.action.x - 2, this.action.y + 2)
&& !this.inArray(this.action.x - 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x - 2, this.action.y + 2);
}
if (!this.inArray(this.action.x + 2, this.action.y + 2)
&& !this.inArray(this.action.x + 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x + 2, this.action.y + 2);
}
} else if (this.action.x == 1) {
if (!this.inArray(this.action.x + 2, this.action.y - 2)
&& !this.inArray(this.action.x + 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x + 2, this.action.y - 2);
}
if (!this.inArray(this.action.x + 2, this.action.y + 2)
&& !this.inArray(this.action.x + 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x + 2, this.action.y + 2);
}
} else if (this.action.x == 9) {
if (!this.inArray(this.action.x - 2, this.action.y - 2)
&& !this.inArray(this.action.x - 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x - 2, this.action.y - 2);
}
if (!this.inArray(this.action.x - 2, this.action.y + 2)
&& !this.inArray(this.action.x - 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x - 2, this.action.y + 2);
}
} else {
if (!this.inArray(this.action.x + 2, this.action.y - 2)
&& !this.inArray(this.action.x + 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x + 2, this.action.y - 2);
}
if (!this.inArray(this.action.x + 2, this.action.y + 2)
&& !this.inArray(this.action.x + 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x + 2, this.action.y + 2);
}
if (!this.inArray(this.action.x - 2, this.action.y - 2)
&& !this.inArray(this.action.x - 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x - 2, this.action.y - 2);
}
if (!this.inArray(this.action.x - 2, this.action.y + 2)
&& !this.inArray(this.action.x - 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x - 2, this.action.y + 2);
}
}
break;
case "象":
if (this.action.y == 1) {
if (!this.inArray(this.action.x - 2, this.action.y + 2)
&& !this.inArray(this.action.x - 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x - 2, this.action.y + 2);
}
if (!this.inArray(this.action.x + 2, this.action.y + 2)
&& !this.inArray(this.action.x + 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x + 2, this.action.y + 2);
}
} else if (this.action.y == 5) {
if (!this.inArray(this.action.x - 2, this.action.y - 2)
&& !this.inArray(this.action.x - 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x - 2, this.action.y - 2);
}
if (!this.inArray(this.action.x + 2, this.action.y - 2)
&& !this.inArray(this.action.x + 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x + 2, this.action.y - 2);
}
} else if (this.action.x == 1) {
if (!this.inArray(this.action.x + 2, this.action.y - 2)
&& !this.inArray(this.action.x + 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x + 2, this.action.y - 2);
}
if (!this.inArray(this.action.x + 2, this.action.y + 2)
&& !this.inArray(this.action.x + 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x + 2, this.action.y + 2);
}
} else if (this.action.x == 9) {
if (!this.inArray(this.action.x - 2, this.action.y - 2)
&& !this.inArray(this.action.x - 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x - 2, this.action.y - 2);
}
if (!this.inArray(this.action.x - 2, this.action.y + 2)
&& !this.inArray(this.action.x - 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x - 2, this.action.y + 2);
}
} else {
if (!this.inArray(this.action.x + 2, this.action.y - 2)
&& !this.inArray(this.action.x + 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x + 2, this.action.y - 2);
}
if (!this.inArray(this.action.x + 2, this.action.y + 2)
&& !this.inArray(this.action.x + 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x + 2, this.action.y + 2);
}
if (!this.inArray(this.action.x - 2, this.action.y - 2)
&& !this.inArray(this.action.x - 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x - 2, this.action.y - 2);
}
if (!this.inArray(this.action.x - 2, this.action.y + 2)
&& !this.inArray(this.action.x - 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x - 2, this.action.y + 2);
}
}
break;
case "仕":
if (this.action.x == 5 && this.action.y == 9) {
if (!this.inArray(this.action.x - 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x - 1, this.action.y - 1);
}
if (!this.inArray(this.action.x - 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x - 1, this.action.y + 1);
}
if (!this.inArray(this.action.x + 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x + 1, this.action.y - 1);
}
if (!this.inArray(this.action.x + 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x + 1, this.action.y + 1);
}
} else {
this.drawCandidateCircle(5, 9);
}
break;
case "士":
if (this.action.x == 5 && this.action.y == 2) {
if (!this.inArray(this.action.x - 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x - 1, this.action.y - 1);
}
if (!this.inArray(this.action.x - 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x - 1, this.action.y + 1);
}
if (!this.inArray(this.action.x + 1, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x + 1, this.action.y - 1);
}
if (!this.inArray(this.action.x + 1, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x + 1, this.action.y + 1);
}
} else {
this.drawCandidateCircle(5, 2);
}
break;
case "帅":
if (!this.inArray(this.action.x, this.action.y - 1) && this.action.y > 8) {
this.drawCandidateCircle(this.action.x, this.action.y - 1);
}
if (!this.inArray(this.action.x, this.action.y + 1) && this.action.y < 10) {
this.drawCandidateCircle(this.action.x, this.action.y + 1);
}
if (!this.inArray(this.action.x - 1, this.action.y) && this.action.x > 4) {
this.drawCandidateCircle(this.action.x - 1, this.action.y);
}
if (!this.inArray(this.action.x + 1, this.action.y) && this.action.x < 6) {
this.drawCandidateCircle(this.action.x + 1, this.action.y);
}
break;
case "将":
if (!this.inArray(this.action.x, this.action.y - 1) && this.action.y > 1) {
this.drawCandidateCircle(this.action.x, this.action.y - 1);
}
if (!this.inArray(this.action.x, this.action.y + 1) && this.action.y < 3) {
this.drawCandidateCircle(this.action.x, this.action.y + 1);
}
if (!this.inArray(this.action.x - 1, this.action.y) && this.action.x > 4) {
this.drawCandidateCircle(this.action.x - 1, this.action.y);
}
if (!this.inArray(this.action.x + 1, this.action.y) && this.action.x < 6) {
this.drawCandidateCircle(this.action.x + 1, this.action.y);
}
break;
case "兵":
if (this.action.y > 5 && !this.inArray(this.action.x, this.action.y - 1)) {
this.drawCandidateCircle(this.action.x, this.action.y - 1);
} else if (this.action.y <= 5) {
if (!this.inArray(this.action.x, this.action.y - 1) && this.action.y > 1) {
this.drawCandidateCircle(this.action.x, this.action.y - 1);
}
if (!this.inArray(this.action.x - 1, this.action.y) && this.action.x > 1) {
this.drawCandidateCircle(this.action.x - 1, this.action.y);
}
if (!this.inArray(this.action.x + 1, this.action.y) && this.action.x < 9) {
this.drawCandidateCircle(this.action.x + 1, this.action.y);
}
}
break;
case "卒":
if (this.action.y <= 5 && !this.inArray(this.action.x, this.action.y + 1)) {
this.drawCandidateCircle(this.action.x, this.action.y + 1);
} else if (this.action.y > 5) {
if (!this.inArray(this.action.x, this.action.y + 1) && this.action.y < 10) {
this.drawCandidateCircle(this.action.x, this.action.y + 1);
}
if (!this.inArray(this.action.x - 1, this.action.y) && this.action.x > 1) {
this.drawCandidateCircle(this.action.x - 1, this.action.y);
}
if (!this.inArray(this.action.x + 1, this.action.y) && this.action.x < 9) {
this.drawCandidateCircle(this.action.x + 1, this.action.y);
}
}
break;
case "炮":
var temp_y = this.action.y;
while (!this.inArray(this.action.x, ++temp_y) && temp_y <= 10) {
this.drawCandidateCircle(this.action.x, temp_y);
}
var temp_y = this.action.y;
while (!this.inArray(this.action.x, --temp_y) && temp_y > 0) {
this.drawCandidateCircle(this.action.x, temp_y);
}
var temp_x = this.action.x;
while (!this.inArray(++temp_x, this.action.y) && temp_x < 10) {
this.drawCandidateCircle(temp_x, this.action.y);
}
var temp_x = this.action.x;
while (!this.inArray(--temp_x, this.action.y) && temp_x > 0) {
this.drawCandidateCircle(temp_x, this.action.y);
}
break;
}
}
/*---------------------------------------------------------------------------------------------------------------------------------*/
// 更新棋局
obj.updateChess = function (e) {
var lqf =
this.ctx.clearRect(0, 0, canvas.width, canvas.height);
this.init_back();
var that = this;
$.each(this.cheer_arr_ALL, function (i, e) {
that.drawPiece(e);
that.drawChessText(e);
});
$("#ul").empty(); //清空
$.each(this.Notations, function (iii, lqfs) {
var cars = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25"]
for (var i = 1; i < 2; i++) {
var html_2 = '<li data-id="' + cars[i] + '" class="lqf' + i * 6 + '" style="color: red" >' + lqfs + '</li>';
var html_1 = '<li data-id="' + cars[3] + '" class="lqf' + i * 7 + '" style="color: black">' + lqfs + '</li>';
var tas = true;
if (tas) { $("#ul").append(html_1); tas = false; }
else { $("#ul").append(html_2); tas = true; }
}
});
}
/*---------------------------------------------------------------------------------------------------------------------------------*/
// 增加点击事件
obj.addEvent = function () {
var that = this;//保存当前对象
this.checked = false;//保存选中当前棋子的索引
$(canvas).on("mousedown", function (ev) { //鼠标按下
for (var j = 1; j <= 10; j++) {
for (var i = 1; i <= 9; i++) {
//计算当前棋子的位置坐标
var temp_i = i * obj.chunk;
var temp_j = j * obj.chunk;
//计算当前位置和鼠标位置之间的距离
var distanct = Math.sqrt(Math.pow(temp_i - ev.offsetX, 2) + Math.pow(temp_j - ev.offsetY, 2));
if (distanct <= that.radius) {
var overChess = false;
$.each(that.cheer_arr_ALL, function (ii, ee) {
if (ee.x == i && ee.y == j) {
overChess = true;
var p = { x: ee.x, y: ee.y };
// console.log(that.checked);
if (that.currActive != ee.type && !that.checked) {
return false;
}
if (!that.checked) {
console.log("选中一个棋子");
that.drawChecked(p);
that.action = ee;
that.drawCandidate();
that.checked = true;
} else if (that.action.x == ee.x && that.action.y == ee.y) {
console.log("点在原棋子上");
that.updateChess();
that.checked = false;
} else if (that.action.type == ee.type) {
console.log("切换棋子");
that.updateChess();
that.drawChecked(p);
that.action = ee;
that.drawCandidate();
} else {
// 是否能吃子
if (that.Eating_ruless(i, j)) {
that.eat(ii, ee, i, j);
} else if (that.action.text == "帅") { // 对将
if (that.action.x == i) {
var canEat = true;
$.each(that.cheer_arr_ALL, function (iii, lqfs) {
if (lqfs.x == that.action.x && lqfs.y == j) {
if (lqfs.text == "将") {
for (var t = that.action.y - 1; t > j; t--) {
if (that.inArray(that.action.x, t)) {
canEat = false;
break;
}
}
} else {
canEat = false;
}
return false;
}
});
if (canEat) {
that.eat(ii, ee, i, j);
}
}
} else if (that.action.text == "将") {
if (that.action.x == i) {
var canEat = true;
$.each(that.cheer_arr_ALL, function (iii, lqfs) {
if (lqfs.x == that.action.x && lqfs.y == j) {
if (lqfs.text == "帅") {
for (var t = that.action.y + 1; t < j; t++) {
if (that.inArray(that.action.x, t)) {
canEat = false;
break;
}
}
} else {
canEat = false;
}
return false;
}
});
if (canEat) {
that.eat(ii, ee, i, j);
}
}
}
}
return false;
}
});
if (overChess) {
console.log("点在棋子上");
} else {
// 是否能移动
if (that.checked && that.Move_rules(i, j)) {
console.log("移动棋子");
that.move(i, j);
}
}
}
}
}
});
}
// 记谱
obj.book = function (ee, i, j) {
var distance = Math.abs(ee.y - j);
var Notation;
if (ee.type == "red") {
$("#currActive").text("轮到黑方").css({ "color": "black", })
var oldP = this.text_arr[ee.x - 1];
var newP = this.text_arr[i - 1];
var num = this.text_arr[9 - distance];
if (j < ee.y) {
if (ee.x == i) {
var tag_1 = '<span style="color: red">进<span>';
var tag_2 = '<span style="color: red">' + ee.text + '<span>';
console.log(ee.text + oldP + "进" + num);
Notation = tag_2 + oldP + tag_1 + num;
} else {
var tag_1 = '<span style="color: red">进<span>';
var tag_2 = '<span style="color: red">' + ee.text + '<span>';
console.log(ee.text + oldP + "进" + newP);
Notation = tag_2 + oldP + tag_1 + newP;
}
} else if (j > ee.y) {
if (ee.x == i) {
var tag_1 = '<span style="color: red">退<span>';
var tag_2 = '<span style="color: red">' + ee.text + '<span>';
console.log(ee.text + oldP + "退" + num);
Notation = tag_2 + oldP + tag_1 + num;
} else {
var tag_1 = '<span style="color: red">退<span>';
var tag_2 = '<span style="color: red">' + ee.text + '<span>';
console.log(ee.text + oldP + "退" + newP);
Notation = tag_2 + oldP + tag_1 + newP;
}
} else {
var tag_1 = '<span style="color: red">平<span>';
var tag_2 = '<span style="color: red">' + ee.text + '<span>';
console.log(ee.text + oldP + "平" + newP);
Notation = tag_2 + oldP + tag_1 + newP;
}
} else {
$("#currActive").text("轮到红方").css({ "color": "red", })
if (j > ee.y) {
if (ee.x == i) {
console.log(ee.text + ee.x + "进" + distance);
Notation = ee.text + ee.x + "进" + distance
} else {
console.log(ee.text + ee.x + "进" + i);
Notation = ee.text + ee.x + "进" + i;
}
} else if (j < ee.y) {
if (ee.x == i) {
console.log(ee.text + ee.x + "退" + distance);
Notation = ee.text + ee.x + "退" + distance;
} else {
console.log(ee.text + ee.x + "退" + i);
Notation = ee.text + ee.x + "退" + i;
}
} else {
console.log(ee.text + ee.x + "平" + i);
Notation = ee.text + ee.x + "平" + i;
}
}
this.Notations.push(Notation);
}
// 是否结束
obj.isOver = function (ee) {
if (ee.text == "将") {
$("#shuying").html('<p>' + "结束红方赢" + '</p>').css({ "background": "yellow", "color": "red" });
$("#ul").empty();
return true;
} else if (ee.text == "帅") {
$("#shuying").html('<p>' + "结束黑方赢" + '</p>').css({ "background": "yellow", "color": "black" });
$("#ul").empty();
return true;
} else {
return false;
}
}
/*--------------------------------------------------------------------------------------------------------------------------------------*/
// 移动
obj.move = function (i, j) {
var that = this;
$.each(that.cheer_arr_ALL, function (iii, lqfs) {
if (lqfs.x == that.action.x && lqfs.y == that.action.y) {
that.book(lqfs, i, j);
lqfs.x = i;
lqfs.y = j;
that.currActive = lqfs.type == "red" ? "black" : "red";
return false;
}
});
that.updateChess();
that.checked = false;
}
// 吃子
obj.eat = function (ii, ee, i, j) {
this.cheer_arr_ALL.splice(ii, 1);
this.move(i, j);
if (this.isOver(ee)) {
this.ctx.clearRect(0, 0, canvas.width, canvas.height);
this.init();
return false;
};
}
/*---------------------------------------------------------------------------------------------------------------------------------*/
// 棋子移动规则
obj.Move_rules = function (i, j) {
switch (this.action.text) {
case "車":
return this.rules_Car(i, j);
case "馬":
return this.rules_Horse(i, j);
case "相":
return this.rules_Elephant_r(i, j);
case "象":
return this.rules_Elephant_b(i, j);
case "仕":
return this.rules_Scholar_r(i, j);
case "士":
return this.rules_Scholar_b(i, j);
case "帅":
return this.rules_Boss_r(i, j);
case "将":
return this.rules_Boss_b(i, j);
case "兵":
return this.rules_Soldier_r(i, j);
case "卒":
return this.rules_Soldier_b(i, j);
case "炮":
if (this.rules_Cannon(i, j) == 0) {
return true;
}
return false;
}
}
/*---------------------------------------------------------------------------------------------------------------------------------*/
// 棋子吃子规则
obj.Eating_ruless = function (i, j) {
switch (this.action.text) {
case "車":
return this.rules_Car(i, j);
case "馬":
return this.rules_Horse(i, j);
case "相":
return this.rules_Elephant_r(i, j);
case "象":
return this.rules_Elephant_b(i, j);
case "仕":
return this.rules_Scholar_r(i, j);
case "士":
return this.rules_Scholar_b(i, j);
case "帅":
return this.rules_Boss_r(i, j);
case "将":
return this.rules_Boss_b(i, j);
case "兵":
return this.rules_Soldier_r(i, j);
case "卒":
return this.rules_Soldier_b(i, j);
case "炮":
if (this.rules_Cannon(i, j) == 1) {
return true;
}
return false;
}
}
/*---------------------------------------------------------------------------------------------------------------------------------*/
//各个棋子的规则
// 車的规则
obj.rules_Car = function (i, j) {
if (this.action.x == i || this.action.y == j) {
if (this.action.x == i) {
if (this.action.y < j) {
console.log("车下");
var hasObstacle = false;
for (var p = this.action.y + 1; p < j; p++) {
if (this.inArray(i, p)) {
hasObstacle = true;
break;
}
}
if (hasObstacle) {
return false;
}
}
if (this.action.y > j) {
console.log("车上");
var hasObstacle = false;
for (var p = this.action.y - 1; p > j; p--) {
if (this.inArray(i, p)) {
hasObstacle = true;
break;
}
}
if (hasObstacle) {
return false;
}
}
}
if (this.action.y == j) {
if (this.action.x < i) {
console.log("车右");
var hasObstacle = false;
for (var p = this.action.x + 1; p < i; p++) {
if (this.inArray(p, j)) {
hasObstacle = true;
break;
}
}
if (hasObstacle) {
return false;
}
}
if (this.action.x > i) {
console.log("车左");
var hasObstacle = false;
for (var p = this.action.x - 1; p > i; p--) {
if (this.inArray(p, j)) {
hasObstacle = true;
break;
}
}
if (hasObstacle) {
return false;
}
}
}
return true;
}
return false;
}
// 馬的规则
obj.rules_Horse = function (i, j) {
var hasObstacle = false;
var that = this;
if ((Math.abs(this.action.x - i) == 1 && Math.abs(this.action.y - j) == 2)
|| (Math.abs(this.action.x - i) == 2 && Math.abs(this.action.y - j) == 1)) {
if (this.action.x - i == 2) { // 左
$.each(that.cheer_arr_ALL, function (ii, ee) {
if (ee.x == that.action.x - 1 && ee.y == that.action.y) {
hasObstacle = true;
return false;
}
});
if (hasObstacle) {
return false;
}
} else if (i - that.action.x == 2) { // 右
$.each(that.cheer_arr_ALL, function (ii, ee) {
if (ee.x == that.action.x + 1 && ee.y == that.action.y) {
hasObstacle = true;
return false;
}
});
if (hasObstacle) {
return false;
}
} else if (that.action.y - j == 2) { // 上
$.each(that.cheer_arr_ALL, function (ii, ee) {
if (ee.x == that.action.x && ee.y == that.action.y - 1) {
hasObstacle = true;
return false;
}
});
if (hasObstacle) {
return false;
}
} else if (j - that.action.y == 2) { // 下
$.each(that.cheer_arr_ALL, function (ii, ee) {
if (ee.x == that.action.x && ee.y == that.action.y + 1) {
hasObstacle = true;
return false;
}
});
if (hasObstacle) {
return false;
}
}
return true;
}
return false;
}
// 红相的规则
obj.rules_Elephant_r = function (i, j) {
var hasObstacle = false;
var that = this;
if ((Math.abs(that.action.x - i) == 2 && Math.abs(that.action.y - j) == 2) && j >= 6) {
var vgaX = (that.action.x + i) / 2;
var vgaY = (that.action.y + j) / 2;
console.log(vgaX);
$.each(that.cheer_arr_ALL, function (ii, ee) {
if (ee.x == vgaX && ee.y == vgaY) {
hasObstacle = true;
return false;
}
});
if (hasObstacle) {
return false;
}
return true;
}
return false;
}
// 黑象的规则
obj.rules_Elephant_b = function (i, j) {
var hasObstacle = false;
var that = this;
if ((Math.abs(that.action.x - i) == 2 && Math.abs(that.action.y - j) == 2) && j < 6) {
var vgaX = (that.action.x + i) / 2;
var vgaY = (that.action.y + j) / 2;
// console.log(vgaX);
$.each(that.cheer_arr_ALL, function (ii, ee) {
if (ee.x == vgaX && ee.y == vgaY) {
hasObstacle = true;
return false;
}
});
if (hasObstacle) {
return false;
}
return true;
}
return false;
}
// 红仕的规则
obj.rules_Scholar_r = function (i, j) {
if (this.action.x == 5 && this.action.y == 9) {
if (Math.abs(this.action.x - i) == 1 && Math.abs(this.action.y - j) == 1) {
return true;
}
}
else if (i == 5 && j == 9) {
return true;
}
return false;
}
// 黑仕的规则
obj.rules_Scholar_b = function (i, j) {
if (this.action.x == 5 && this.action.y == 2) {
if (Math.abs(this.action.x - i) == 1 && Math.abs(this.action.y - j) == 1) {
return true;
}
} else if (i == 5 && j == 2) {
return true;
}
return false;
}
// 帅的规则
obj.rules_Boss_r = function (i, j) {
if ((Math.abs(this.action.x - i) == 1 && this.action.y == j)
|| (this.action.x == i && Math.abs(this.action.y - j) == 1)) {
if (i >= 4 && i <= 6 && j >= 8 && j <= 10) {
return true;
} else {
return false;
}
}
return false;
}
// 将的规则
obj.rules_Boss_b = function (i, j) {
if ((Math.abs(this.action.x - i) == 1 && this.action.y == j)
|| (this.action.x == i && Math.abs(this.action.y - j) == 1)) {
if (i >= 4 && i <= 6 && j >= 1 && j <= 3) {
return true;
} else {
return false;
}
}
return false;
}
// 兵的规则
obj.rules_Soldier_r = function (i, j) {
if (this.action.y <= 5) {
if ((this.action.x == i && this.action.y - 1 == j) || (this.action.x - 1 == i && this.action.y == j) || (this.action.x + 1 == i && this.action.y == j)) {
return true;
}
} else {
if (this.action.x == i && this.action.y - 1 == j) {
return true;
}
}
return false;
}
// 卒的规则
obj.rules_Soldier_b = function (i, j) {
if (this.action.y > 5) {
if ((this.action.x == i && this.action.y + 1 == j) || (this.action.x - 1 == i && this.action.y == j) || (this.action.x + 1 == i && this.action.y == j)) {
return true;
}
} else {
if (this.action.x == i && this.action.y + 1 == j) {
return true;
}
}
return false;
}
// 炮的规则
obj.rules_Cannon = function (i, j) {
var that = this;
if (this.action.x == i || this.action.y == j) {
var t = 0;
if (this.action.x == i) {
var temp = this.action.y;
if (temp < j) {
while (++temp != j) {
$.each(this.cheer_arr_ALL, function (ii, ee) {
if (ee.x == that.action.x && ee.y == temp) {
t++;
return false;
}
});
}
return t;
} else {
while (--temp != j) {
$.each(this.cheer_arr_ALL, function (ii, ee) {
if (ee.x == that.action.x && ee.y == temp) {
t++;
return false;
}
});
}
return t;
}
} else {
var temp = this.action.x;
if (temp < i) {
while (++temp != i) {
$.each(this.cheer_arr_ALL, function (ii, ee) {
if (ee.x == temp && ee.y == that.action.y) {
t++;
return false;
}
});
}
return t;
} else {
while (--temp != i) {
$.each(this.cheer_arr_ALL, function (ii, ee) {
if (ee.x == temp && ee.y == that.action.y) {
t++;
return false;
}
});
}
return t;
}
}
}
return 2;
}
obj.inArray = function (x, y) {
var hasObstacle = false;
$.each(this.cheer_arr_ALL, function (ii, ee) {
if (ee.x == x && ee.y == y) {
hasObstacle = true;
return false;
}
});
return hasObstacle;
}
obj.init();
</script>
</html>