背景

兄弟们,之前我开发了支持联机对战的五子棋、斗地主、UNO。在大家的呼吁之下,我准备开发「象棋」啦!

😄 不出意外,国庆假期,联机象棋就能跟大家见面了!

给大家同步下进展:今天,我绘制了象棋的棋盘,是用SVG绘制的。

象棋棋盘什么样子

[教你做小游戏] 用SVG画一个象棋棋盘_掘金·日新计划

图片来自维基百科「象棋」。

象棋是9*10的棋盘,虽然中间有一条「楚河汉界」,但是可以忽略不计。你就把象棋当作9*10的棋盘,共计90个位置就可以了。而且那条「楚河汉界」的宽度刚好是一个格子的宽度。

此外,在将帅的九宫格位置,分别有斜线,组成叉叉形状。

此外,在5个兵卒、2个炮的位置,分别有标记点,也需要画出来。

定义好SVG骨架

<svg id="svg" viewBox="-6,-6,92,102" xmlns="http://www.w3.org/2000/svg">
...
</svg>

我们不妨设每个格子宽度为10,那么整个棋盘大小应该是80*90(注意:棋子可以放在角落,虽然能放置9*10=90个棋子,但是其实格线组成的正方形是8*9个)。但是考虑到边线上的棋子,SVG骨架宽度应该超过80*90。我们设棋子半径为4.5,那么SVG骨架尺寸应该超过89*99。这里我们为了美观,再留白一些,设置尺寸为92*102,上下左右都比80*90多余6,是足够完全展示边角的棋子的。

此外,为了计算方便,我们设置坐标时,都要用棋子的中心点来设置,而且需要是10的整数倍。所以SVG视野范围就从(-6, -6)开始了,这样可以保证左上角的棋子坐标是(0, 0)。

绘制边框

通过path绘制。

<path stroke="brown" stroke-width="0.5" fill="none" d="M0,0h80v90h-80z"

我们这就绘制了一个矩形,尺寸是80*90。

绘制格线

我们继续完善上述的path,在d后面补充就可以了。需要补充8条横线、7+7条竖线(注意竖线不要超过楚河汉界)。

<path stroke="brown" stroke-width="0.5" fill="none" d="M0,0h80v90h-80zM0,10h80M0,20h80M0,30h80M0,40h80M0,50h80M0,60h80M0,70h80M0,80h80M10,0v40M20,0v40M30,0v40M40,0v40M50,0v40M60,0v40M70,0v40M10,50v40M20,50v40M30,50v40M40,50v40M50,50v40M60,50v40M70,50v40M30,0l20,20M50,0l-20,20"

绘制斜线

最后在path的d里补充​​M30,70l20,20M50,70l-20,20​​,画2个叉叉:

<path stroke="brown" stroke-width="0.5" fill="none" d="M0,0h80v90h-80zM0,10h80M0,20h80M0,30h80M0,40h80M0,50h80M0,60h80M0,70h80M0,80h80M10,0v40M20,0v40M30,0v40M40,0v40M50,0v40M60,0v40M70,0v40M10,50v40M20,50v40M30,50v40M40,50v40M50,50v40M60,50v40M70,50v40M30,0l20,20M50,0l-20,20M30,70l20,20M50,70l-20,20"

绘制标记点

这里可以复用,我们利用svg的​​<defs>​​定义组件:

<defs>
<path id="mark-right" stroke="brown" stroke-width="0.4" fill="none" d="M1,-2.8v1.8h1.8M1,2.8v-1.8h1.8"
<path id="mark-left" stroke="brown" stroke-width="0.4" fill="none" d="M-1,-2.8v1.8h-1.8M-1,2.8v-1.8h-1.8"
<path id="mark" stroke="brown" stroke-width="0.4" fill="none" d="M1,-2.8v1.8h1.8M1,2.8v-1.8h1.8M-1,-2.8v1.8h-1.8M-1,2.8v-1.8h-1.8"
</defs>

我们定义了3个组件,分别表示「只有右侧的标记点」、「只有左侧的标记点」、「完整的标记点」,也是通过path实现的。

每个标记点的四分之一都是一个小折线,我设置了小折线的宽度、长度均为1.8,并且和标记点中心的水平、垂直距离均是1.2。这是我根据网上的棋盘截图,抓像素计算的大概比例。看起来确实很舒服。

然后通过​​use​​引用组件即可:

<use xlink:href="#mark" x="10" y="20"
<use xlink:href="#mark" x="70" y="20"
<use xlink:href="#mark-right" x="0" y="30"
<use xlink:href="#mark" x="20" y="30"
<use xlink:href="#mark" x="40" y="30"
<use xlink:href="#mark" x="60" y="30"
<use xlink:href="#mark-left" x="80" y="30"
<use xlink:href="#mark-right" x="0" y="60"
<use xlink:href="#mark" x="20" y="60"
<use xlink:href="#mark" x="40" y="60"
<use xlink:href="#mark" x="60" y="60"
<use xlink:href="#mark-left" x="80" y="60"
<use xlink:href="#mark" x="10" y="70"
<use xlink:href="#mark" x="70" y="70"

写下楚河汉界

用​​text​​​写楚河汉界,为了让他们垂直水平居中,我使用了文本的​​text-anchor=middle​​​和​​alignment-baseline=central​​属性,这时候只要设置x和y为整个棋盘的中心点就可以了。为了让「楚河汉界」四个字中间有固定距离,我使用了全角空格。

<text x="40" y="45" text-anchor="middle" alignment-baseline="central" fill="brown" font-size="6">楚河   漢界</text>

预览效果

写在最后

我是HullQin,独立开发了《联机桌游合集》​,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费无广告。还独立开发了《合成大西瓜重制版》​。还开发了《Dice Crush》​参加Game Jam 2022。喜欢可以关注我噢~我有空了会分享做游戏的相关技术,会在这2个专栏里分享:《教你做小游戏》、《极致用户体验》。