电脑按方向键,手机在棋盘上滑动。操作方式不同,但小蛇真正需要收到的东西只有四个方向。

先把输入翻译成方向

页面负责读取按键、滑动和方向按钮,再把它们交给同一个转向入口。规则引擎不用知道玩家是在手机还是电脑上,也不用关心某个触点的坐标。

WASD 和方向键做映射;滑动则比较横向、纵向的位移,位移较大的轴决定转向。项目里把 18 个 CSS 像素作为一次滑动的识别门槛,用来减少手指轻微抖动带来的误转向。

为什么不能只保存最后一次按键?

假设蛇正在向右走,玩家很快按了“下、左”。如果只记最后一个“左”,它会被当成直接反向而忽略;如果立即改方向,又可能在同一步里反向撞到自己。我用了最多两项的输入队列,让连续两个合法转弯按步执行。

turn(direction) {
  if (!vectors[direction] || this.queue.length >= 2) return false;
  const last = this.queue.length
    ? this.queue[this.queue.length - 1]
    : this.direction;
  const a = vectors[last], b = vectors[direction];
  if (last === direction || (a[0] + b[0] === 0 && a[1] + b[1] === 0)) {
    return false;
  }
  this.queue.push(direction);
  return true;
}

相对于队列末尾,判断下一次转向

这里的小细节是 last:队列不为空时,新输入要和队列最后一个方向比较,而不是一直和当前方向比较。这才接得住“下、左”这样的连续操作。

队列也不宜太长。把好几秒前的输入一直留着,会让蛇看上去不听使唤。两项是这个小项目当前采用的长度,不是所有游戏都应该照搬的标准。

触屏,还要照顾手指离开棋盘的情况

按下时使用 Pointer Capture 跟踪同一个触点,抬起、取消或失去捕获时清理手势状态。识别出一次转向后,以当前触点作为新的起点,允许玩家不松手就继续滑出下一次转向。

棋盘设置 touch-action: none,避免操作时整页跟着滚;限制只放在棋盘上,正文部分依然可以正常上下浏览。手机下方也保留方向按钮,让不习惯滑动的人有另一个选择。