手记

在线网页游戏框架(1)——走井游戏

走井是个古老的亲子游戏,在电子游戏,电脑,手机没有普及时间相信很多孩子都跟大人玩过这个游戏,沙地上找4个石子画个框就能走起。不过为了让电子时代的小鲜肉们也能知道后面在说什么,下面我们介绍一下走井游戏

走井规则

走井的有两名玩家,每个玩家有两粒棋子,两名玩家交替走子,当一名玩家移动完自己的子之后,对方无子可动即获得胜利。


well.png

翻译成计算机语言

按照上图0,1,2,3,4这5个位置,列出每个位置的可移动状态,如下表

位置\可移动位置01234十进制十六进制
0NA1111310x1F
11NA10050x5
211NA10110xB
3101NA1210x15
41001NA90x9

该表格查看方式类似于公交梯型票价图,如按行查看,位置1可以的移动的目标位置为 0,2,按位组合后为000101即十进制数字5,十六进制为0x5。其它的位置如查表即可得到。

将棋盘上唯的空位按照其所处的位置表示成一个5bit的数字,1的位置(可移动的目标位置或者说是空着的位置)在5bit中来回移动。如开局时空为位于0,该值为00001--(hex)-->0x1

SVG

一种矢量图元描述格式,常用于作图形软件的数据交换。具体参见教程(内网)
svg导学(互联网)
一个基本的svg结构如下所示:

<html><body><h1>My first SVG</h1><svg width="100%" height="100%">
    <!---->
    <path d="M32 32 l128 0 l0 128 l-128 0 l128,-128" fill="none" stroke="black"></path>
    <line x1="32" y1="32" x2="160" y2="160" stroke="black" />

    <circle cx="96" cy="96" r="20" class="invisible" id='p0' />

    <circle cx="32" cy="32" r="20" class="gray" id='p1' />
    <circle cx="160" cy="32" r="20" class="black" id='p2' />

    <circle cx="160" cy="160" r="20" class="black" id='p3' />
    <circle cx="32" cy="160" r="20" class="gray" id='p4' />

    <rect id="turnSide" x="200" y="16" width="64" height="32" class="black"></rect> 
  </svg></body></html>

CSS 样式

我们可以通过css模式直接控制svg元素的显示属性。

    .black {      fill: black
    }    .gray {      fill: gray
    }    .invisible {      display: none
    }

我们定义黑色(black)、灰色(gray)、和不可见(invisible)三个显示。

DOM事件

由于svg节点也是DOM节点,DOM事件也是可用的,我们通过向节点增加click事件,来处理按键点击。

function init() {
      
      elements = document.querySelectorAll('circle');      for (var ele of elements) {        console.log(ele);
        ele.addEventListener('click', pawnclick);
      }

    }

通过选择器,选择所有的circle标签,为它们增加点击事件。

将逻辑连接起来

有了每个位置的可移动位置及当前棋盘上的空位,我们可以通过位运算得出点中子是否可移动,以及其移动的去向。如果子可动则把目标位置置为当前点击位置的颜色(css class),点击位置置为空(.invisible),并进入下一手next()。下面是pawnclick()的实现。

    function pawnclick() {      if (this.className.baseVal != current_player[round % 2]) {        console.log('not your turn');        return;
      }      console.log(`click me ${this.id}`);      //获取可移动位置
      var moveDest = moveCandiate[this.id] & blankPos;      if (moveDest != 0) {        console.log(`move dest ${moveDest} boardPost ${mask2pos[moveDest]}`);

        blankPos = pos2mask[this.id];//将空位置为当前子的位置

        //如果可以移动,则移动该子,并取消事件监听,进入下一轮

        //获取目标位置
        var destPos = document.getElementById(mask2pos[moveDest]);
        destPos.className.baseVal = this.className.baseVal;        this.className.baseVal = "invisible";

        nextTurn();//换手
      }      else//没有气不可移动
      {        console.log(`${this.id} 不可动`);
      }
    }

为了方便快速查找 翻译成计算机语言中的表格,我们定义了 moveCandiate,mask2pos,pos2mask三个查找表。

var moveCandiate = {      'p0': 0x1F,      'p1': 0x5,      'p2': 0xB,      'p3': 0x15,      'p4': 0x9
    };    // 移动目标位转棋盘位置
    var mask2pos = {      1: 'p0',      2: 'p1',      4: 'p2',      8: 'p3',      16: 'p4'
    }    var pos2mask = {      'p0': 1,      'p1': 2,      'p2': 4,      'p3': 8,      'p4': 16
    }

胜负判定

换手后++round,我们需要判断当前方是否还有子可动,如果无子可动则游戏结束。

function nextTurn()    {
      ++round;      var class_selector = current_player[round % 2];//根据手数确定是哪边
      document.getElementById('turnSide').className.baseVal = class_selector;      var pawns = document.getElementsByClassName(class_selector);      var hasMove = 0;      for( var pawn of pawns)
      {
        hasMove |= (moveCandiate[pawn.id] & blankPos);
      }      if(!hasMove)
      {        console.log(`${class_selector} loose!`);
      }      console.log(pawns);
    }

nextTurn()中还增加表示当前移动方的指示方格document.getElementById('turnSide').className.baseVal = class_selector,对应svg部分的<rect id="turnSide" x="200" y="16" width="64" height="32" class="black"></rect>



作者:清洼
链接:https://www.jianshu.com/p/3fd4352c0cbd


0人推荐
随时随地看视频
慕课网APP