将格子图案添加到动态绘制的 3 人棋盘中
Posted
技术标签:
【中文标题】将格子图案添加到动态绘制的 3 人棋盘中【英文标题】:Adding the checked pattern to a dynamically drawn 3 player chess board 【发布时间】:2014-04-17 13:39:02 【问题描述】:你好,你们这群出色的天才!
我似乎在这里达到了我的知识顶峰,希望有人能指出我正确的方向。
我正在尝试使用 javascript 和 html 5 画布动态绘制 3 人国际象棋/跳棋棋盘。
到目前为止,我想出了这个;
var canvas = document.getElementById('canvas')
var length = canvas.height / 2;
var center = canvas.width / 2;
var rotation = ToRadians(60);
var angle = ToRadians(30);
var height = length * Math.cos(angle);
var width = length * Math.sin(angle);
while (rotation < Math.PI * 2)
a = [center, length];
b = [a[0] - height * Math.sin(rotation), a[1] + height * Math.cos(rotation)];
c = [b[0] + width * Math.cos(rotation), b[1] + width * Math.sin(rotation)];
d = [c[0] + width * Math.sin(angle + rotation), c[1] - width * Math.cos(angle + rotation)];
//Drawing Main Frame and 6 segments
var c2 = canvas.getContext('2d');
c2.fillStyle = '#f00';
c2.strokeStyle = "#0f0";
c2.beginPath();
c2.moveTo(a[0], a[1]);
c2.lineTo(b[0], b[1]);
c2.lineTo(c[0], c[1]);
c2.lineTo(d[0], d[1]);
c2.closePath();
c2.stroke();
//Drawing first set of divides
ab1=[((a[0]+b[0])/2),((a[1]+b[1])/2)]
cd1=[((c[0]+d[0])/2),((c[1]+d[1])/2)]
ab2=[((a[0]+ab1[0])/2),((a[1]+ab1[1])/2)]
cd2=[((d[0]+cd1[0])/2),((d[1]+cd1[1])/2)]
ab3=[((b[0]+ab1[0])/2),((b[1]+ab1[1])/2)]
cd3=[((c[0]+cd1[0])/2),((c[1]+cd1[1])/2)]
c2.beginPath();
c2.moveTo(ab1[0], ab1[1]);
c2.lineTo(cd1[0], cd1[1]);
c2.moveTo(ab2[0], ab2[1]);
c2.lineTo(cd2[0], cd2[1]);
c2.moveTo(ab3[0], ab3[1]);
c2.lineTo(cd3[0], cd3[1]);
c2.stroke();
//Drawing second set of divides
bc1=[((c[0]+b[0])/2),((c[1]+b[1])/2)]
ad1=[((a[0]+d[0])/2),((a[1]+d[1])/2)]
bc2=[((c[0]+bc1[0])/2),((c[1]+bc1[1])/2)]
ad2=[((d[0]+ad1[0])/2),((d[1]+ad1[1])/2)]
bc3=[((b[0]+bc1[0])/2),((b[1]+bc1[1])/2)]
ad3=[((a[0]+ad1[0])/2),((a[1]+ad1[1])/2)]
c2.beginPath();
c2.moveTo(bc1[0], bc1[1]);
c2.lineTo(ad1[0], ad1[1]);
c2.moveTo(bc2[0], bc2[1]);
c2.lineTo(ad2[0], ad2[1]);
c2.moveTo(bc3[0], bc3[1]);
c2.lineTo(ad3[0], ad3[1]);
c2.stroke();
rotation += ToRadians(60);
function ToRadians(degrees)
return degrees / (180 / Math.PI);
小提琴:http://jsfiddle.net/yd7Wv/6529/
到目前为止,我对代码非常满意,但是当我需要添加检查模式时,我已经到了这一点,我完全被难住了。我真的不知道如何去做,所以想知道是否有人能指出我正确的方向。 我知道这里有一个普遍的共识,即人们应该尝试自己做,但我根本做不到! 任何指针将不胜感激。
干杯
【问题讨论】:
请在 jsfiddle 中重现此内容。 酷板概念,如果我不工作,我很想有一个破解:P 【参考方案1】:您正在查看的内容与四边形变换密切相关。
您可以将一个线段(“三角形”)视为只是透视变形的象限。
Fiddle demo
产生这个结果:
让我们从定义计算和循环所需的一些变量开始。
var w = canvas.width, // width
h = canvas.height, // height
cx = w * 0.5, // center of board
cy = h * 0.5,
r = cx * 0.9, // radius of board
pi2 = Math.PI * 2, // cache
segments = 6, // a hexagon based shape so 6
segment = pi2 / segments, // angle of each segment
hSegment = segment * 0.5, // half segment for center line
ul, ur, bl, br, // quad. corners
check = 0.25, // interpolation interval (one check)
yc = 0, xc = 0, // interpolation counters
toggle = false, // for color
x, y = 0, i = 0; // counters...
让我们通过定义其外边界的角来定义一个四边形:
第一个角将是棋盘的中心,因此很简单:
var ul =
x: cx,
y: cy
第二个角在右上角:
ur =
x: cx + r * Math.cos(hSegment) * 0.865,
y: cy + r * Math.sin(hSegment) * 0.865
;
右下第三:
br =
x: cx + r * Math.cos(segment),
y: cy + r * Math.sin(segment)
;
最后,左下角:
bl =
x: cx + r * Math.cos(hSegment + segment) * 0.865,
y: cy + r * Math.sin(hSegment + segment) * 0.865
;
如果我们画出这个形状,我们会得到这个:
现在我们有了角,我们只需按检查间隔 (0.25) 对“正方形”中的每一行进行插值,这将得到总共 5 行。我们将只计算 4,但我们还将使用 next 行与当前值。
为了插入两个点,我们使用一个简单的函数,它接受两个点和一个标准化值 [0.0, 1.0]:
function getInt(p1, p2, t)
return
x: p1.x + (p2.x - p1.x) * t,
y: p1.y + (p2.y - p1.y) * t,
我们创建了一个循环来遍历 y 和 x 点,以便我们可以系统地执行此操作:
for(y = 0, yc = 0; y < 4; y++)
for(x = 0, xc = 0; x < 4; x++)
// for upper lines (ul-ur), get first row:
var l1a = getInt(ul, bl, yc),
l1b = getInt(ur, br, yc),
l2a = getInt(ul, bl, yc + check),
l2b = getInt(ur, br, yc + check),
c1 = getInt(l1a, l1b, xc),
c2 = getInt(l1a, l1b, xc + check),
c3 = getInt(l2a, l2b, xc + check),
c4 = getInt(l2a, l2b, xc);
... draw shape ...
xc += check;
yc += check;
本节:
var l1a = getInt(ul, bl, yc), // current line [0, 3]
l1b = getInt(ur, br, yc),
l2a = getInt(ul, bl, yc + check), // next line [1, 4]
l2b = getInt(ur, br, yc + check),
计算外部垂直线上的插值点。这为我们提供了两个新点,然后我们使用它们来计算水平线上的一个点,并使我们能够计算每个角点以进行“检查”:
c1 = getInt(l1a, l1b, xc), // corner 1 UL
c2 = getInt(l1a, l1b, xc + check), // corner 2 UR (next line)
c3 = getInt(l2a, l2b, xc + check), // corner 3 BR (next line)
c4 = getInt(l2a, l2b, xc); // corner 4 BL
现在我们只需在这些角之间绘制一个多边形并进行填充:
ctx.beginPath();
ctx.moveTo(c1.x, c1.y);
ctx.lineTo(c2.x, c2.y);
ctx.lineTo(c3.x, c3.y);
ctx.lineTo(c4.x, c4.y);
ctx.fillStyle = toggle ? '#000' : '#fff';
我们使用拨动开关来改变颜色。
这个单一的片段看起来像这样:
下一步是绘制所有线段。我们重复使用上面的代码,每次只需将画布旋转一段并进行额外的切换。
当所有代码放在一起时,我们得到这个:
for(; i < segments; i++) // loop six segments
toggle = !toggle; // alter color each segment
// loop quadrilateral grid 4x4 cells (5x5 lines exclusive)
for(y = 0, yc = 0; y < 4; y++)
for(x = 0, xc = 0; x < 4; x++)
// for upper lines (ul-ur), get first row:
var l1a = getInt(ul, bl, yc),
l1b = getInt(ur, br, yc),
l2a = getInt(ul, bl, yc + check),
l2b = getInt(ur, br, yc + check),
c1 = getInt(l1a, l1b, xc),
c2 = getInt(l1a, l1b, xc + check),
c3 = getInt(l2a, l2b, xc + check),
c4 = getInt(l2a, l2b, xc);
ctx.beginPath();
ctx.moveTo(c1.x, c1.y);
ctx.lineTo(c2.x, c2.y);
ctx.lineTo(c3.x, c3.y);
ctx.lineTo(c4.x, c4.y);
ctx.fillStyle = toggle ? '#000' : '#fff';
ctx.fill();
toggle = !toggle;
xc += check;
yc += check; // next segment line
toggle = !toggle; // toggle per line as well
ctx.translate(cx, cy); // translate to center
ctx.rotate(segment); // rotate one segment
ctx.translate(-cx, -cy); // translate back
现在您可以根据需要简单地绘制轮廓等等。
【讨论】:
+1 干得好!您的解决方案具有创建 Spitfire2k6 可以用来放置他的棋子的多边形边界的额外好处。曾几何时,我真的很喜欢下棋。 @markE 好点。我忘记了,但是是的,将每个段作为一个多边形存储在一个数组中可以很容易地检查边界。我自己从来没有下过国际象棋,但我确实觉得生活本身就像一盘国际象棋:)以上是关于将格子图案添加到动态绘制的 3 人棋盘中的主要内容,如果未能解决你的问题,请参考以下文章