提问 发文

震惊!可视化工具居然能用来做游戏!

微微菌

| 2024-02-06 17:17 278 0 0

4.当格子发出的回调被数据容器接收后,数据容器的过滤器需要根据对应的 index、hoverIndex、leaveIndex来修改window.ticData。三个回调的修改规则分别如下:

a.leaveIndex,表示鼠标移出了该下标的格子,如果该格子的数据为1(1表示之前鼠标在该格子上悬停了),则修改为0。

b.hoverIndex,表示鼠标移入了该下标的格子,如果该格子的数据为0(0表示该格子未被选中,也没有被悬停),则修改为1。

c.index,表示鼠标点击了该下标的格子,这里是落子的核心逻辑,我们在修改该格子的数据前,需要先判断该格子是否为空或空_悬停,因为已经落子的格子是不允许再落子的。如果格子未落子,则再检查一遍window.ticData,获取当前已落子的格子数量,若数量为偶数,则表示该次落子为玩家“圈”,因为“圈”先手,所以他落子时棋盘上的棋子数量必定是偶数;否则,就表示该次落子为玩家“叉”。检查完毕后,根据结果修改window.ticData下标为index的值,然后return window.ticData即可。

代码如下:

const { index, hoverIndex:hover, leaveIndex:leave } = callbackArgs;
if(!window.ticData){
  window.ticData = [
    0,0,0,
    0,0,0,
    0,0,0
  ];
}
try{
  //判断棋子是否已失焦点
  if(window.ticData[leave]==1){
    window.ticData[leave] = 0;
  }
  //判断棋子是否鼠标悬停
  if(window.ticData[hover]==0){
    window.ticData[hover] = 1;
  }
  //判断棋子是否可以落子
  if(index!=undefined && (window.ticData[index]==0 || window.ticData[index]==1)){
    const flag = window.ticData.filter(d=>d!=0 && d!=1).length%2==0?2:3;
    window.ticData[index] = flag;
  }
}catch(e){
}
return window.ticData;

5.数据容器在处理完毕棋盘数据后,还需要将处理完毕的数据发送给每个格子才行,所以我们给数据容器添加一个回调 dataMap。

6.给每个格子组件添加相同的数据过滤器,用于接收 dataMap,并根据其存储的值来返回对应的数据,改变自身的状态。

const values = [
  "空",
  "空_悬停",
  "圈",
  "叉"
  ];
const { dataMap } = callbackArgs;
const { index } = data[0];
try{
  return [{
    value:values[dataMap[index]],
    index
  }];
}catch(e){}
return data;

7.到此为止,我们其实已经完成了整个游戏的交互逻辑,现在只剩下最后一步了,那就是游戏结束的判断。由于数据容器承担了棋盘数据管理的功能,所以,在每次数据容器数据变化后,进行游戏结束的判断是最合理的,因此,我们还需要给数据容器添加两个自定义事件,并使用自定义条件来判断游戏是获胜还是平局。

//游戏获胜的算法
//什么?你居然问我这个算法啥意思?不好意思,我也不知道,但是chatgpt一定知道,因为我是问它的。
function gameover(arr){
  const rows = [0,0,0], cols = [0,0,0], digs = [0,0];
  for(let i=0;i<9;i++){
    const d = arr[i];
    const row = i<3?0 : i<6?1 : 2;
    const col = i%3;
    if(d==2){
      rows[row]++;
      cols[col]++;
      if(row==col) digs[0]++;
      if(row+col==2) digs[1]++;
      const over = rows[row]==3 || cols[col]==3 || row==col && digs[0]==3 || row+col==2 && digs[1]==3;
      if(over)return true;
    }else if(d==3){
      rows[row]--;
      cols[col]--;
      if(row==col) digs[0]--;
      if(row+col==2) digs[1]--;
      const over = rows[row]==-3 || cols[col]==-3 || row==col && digs[0]==-3 || row+col==2 && digs[1]==-3;
      if(over)return true;
    }
  }
  return false
}
return gameover(data);

//游戏平局的算法,平局的规则其实很简单,就是在没有人获胜的条件下,棋盘上没有任何格子可以落子了
//所以,在获胜算法的基础上,多加个判断即可。
return !gameover(data) && data.findIndex(d=>d==0 || d==1)==-1

8.到这里其实整个游戏已经做完了,不过最后我们还可以做一点优化,那就是告诉玩家到底是谁获胜了。这很简单,给状态背景添加一个数据过滤器,稍微改动一下获胜算法,我们就能直到是谁获胜了,然后返回对应的状态值即可。

const { dataMap=[] } = callbackArgs;
//判断游戏结束
function gameover(arr){
  const rows = [0,0,0], cols = [0,0,0], digs = [0,0];
  for(let i=0;i<9;i++){
    const d = arr[i];
    const row = i<3?0 : i<6?1 : 2;
    const col = i%3;
    if(d==2){
      rows[row]++;
      cols[col]++;
      if(row==col) digs[0]++;
      if(row+col==2) digs[1]++;
      const over = rows[row]==3 || cols[col]==3 || row==col && digs[0]==3 || row+col==2 && digs[1]==3;
      if(over)return "圈";
    }else if(d==3){
      rows[row]--;
      cols[col]--;
      if(row==col) digs[0]--;
      if(row+col==2) digs[1]--;
      const over = rows[row]==-3 || cols[col]==-3 || row==col && digs[0]==-3 || row+col==2 && digs[1]==-3;
      if(over)return "叉";
    }
  }
  return "空"
}
return [{
  value:gameover(dataMap)
}]

最后

其实实现这个游戏并不难,用到的组件也很简单,重要的是理清楚其中的逻辑关系(最难的胜负判断算法可以选择问AI),学会用window变量存储数据,利用好数据容器和状态背景组件的回调,我们还能实现更多类似的游戏,比如五子棋。

当然,以上实现思路其实还是比较繁琐的,比如你要为9个状态背景组件依次添加下标index,数据过滤器和三种回调,如果用这种方法来实现五子棋,那么效率将非常低下。好在我们平台有组件容器的功能,可以通过数据来生成所有的格子组件,这将使五子棋的开发效率提高225倍!(因为五子棋的棋盘是15*15的)

demo大屏

📎井字棋_2334663.zip

📎五子棋-美化版_2426557.zip

收藏 0
分享
分享方式
微信

评论

游客

全部 0条评论

轻松设计高效搭建,减少3倍设计改稿与开发运维工作量

开始免费试用 预约演示

扫一扫关注公众号 扫一扫联系客服

©Copyrights 2016-2022 杭州易知微科技有限公司 浙ICP备2021017017号-3 浙公网安备33011002011932号

互联网信息服务业务 合字B2-20220090

400-8505-905 复制
免费试用
微信社区
易知微-数据可视化
微信扫一扫入群