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的)
文章
10.49W+人气
19粉丝
1关注
©Copyrights 2016-2022 杭州易知微科技有限公司 浙ICP备2021017017号-3 浙公网安备33011002011932号
互联网信息服务业务 合字B2-20220090