也试着写游戏:四路顶
进入游戏
我学会的第一种棋,不是中国象棋也不是五子棋,而是家乡代代相传的土棋。它叫四路顶,听说在山东叫走四棋儿。
4×4 的棋盘,双方各执四子摆满相对的边;双方轮流走棋,每步一格。若一方通过走棋,摆成纵横相邻两个子,且一颗对方的子与这两个子相邻、这三个子的两端位置没有别的子,就把对方的那颗棋子吃掉了。
下面展示了空心子被吃的例子,方向键表示上次的移动。
1 2 3 4 |
┌─┬─↓─┐ ┌─↓─┬─┐ ├─●─●─○ ├─●─●─○ ├─┼─┼─┤ ├─●─┼─┤ └─┴─┴─┘ └─○─┴─┘ |
而下列情况均不构成吃棋:
1 2 3 4 |
┌─┬─↓─┐ ┌─↓─┬─┐ ┌─┬─↓─┐ ●─●─●─○ ●─●─○─○ ●─●─○─┤ ├─┼─┼─┤ ├─┼─┼─┤ ├─┼─┼─┤ └─┴─┴─┘ └─┴─┴─┘ └─┴─┴─┘ |
我开发了一个在线对战的版本,支持创建私人房间。服务端用 Node.js 和 socket.io,容器化后托管在 DaoCloud.io 上;客户端是用 canvas 绘制的。
在这个项目里,客户端只负责处理通信和绘图,逻辑处理均在服务端。尽管这个游戏谈不上复杂,但每次开发都会总结出些许经验:
- socket.io 的数据传递方式是 JSON,而
undefined
和数组中的空位置都会在序列化过程中被转换为null
; - 游戏大体开发完成时,我告知了一些友人,结果不幸被他们找到了注入点。谨记:客户端传来的所有数据都是不可信的。有个经典的例子:
- 适当把方法分离得细小,以便于子类的修改。我在高中时发明了一个变种,用六边形的棋盘,可以让三个人玩。这个类继承下来,只改了三个必改的方法:
1234567891011121314151617181920212223242526272829class LiuLuDing extends SiLuDing {constructor(room, emitter) {super(room, emitter);}initGrid() {// 设置棋盘this.grid = [[0, 0, 0, 0],[null, null, null, null, null],[null, null, null, null, null, null],[1, null, null, null, null, null, 2],[null, 1, null, null, null, null, 2],[null, null, 1, null, null, null, 2],[null, null, null, 1, null, null, 2],];}check(i, j) {// 当玩家落子时,告诉程序要检查哪些方向this.checkByDirection(i, j, 'horizonal');this.checkByDirection(i, j, 'slash');this.checkByDirection(i, j, 'backslash');}getLineOfSeven(i, j, direction) {// 对于每个方向,拿出附近的七个位置的信息用来判断是否吃子}} - 对于这种在线多人应用,不能忽略内存回收的问题。JavaScript 的内存回收机制是这样的:在运行时,检测每个对象的被引用数,若这个数为 0,则表明这个对象已无法访问,垃圾回收器就会将其回收。所以当一个对象的生命周期结束后,记得手动清除对其所有的引用。
游戏源码放在了 Github 上,感兴趣的同学可移步。之后还会加入一些特性,比如成就等等。说不定将来某天会登陆 steam 呢
愛している
哇哇你真好看
这个游戏我给 82 分,剩下 18 分以 666 的形式发出