[Checkers] Checkers Game-Multiplayer Game-WeChat Mini Program Development Process Detailed Explanation

I saw the game of checkers, a game that can be played by 2 to 6 people, so I thought of the pinball game I played with my classmates when I was in elementary school. Is it very similar to the game of checkers? After reading the game of checkers, I am interested Just research, here is the game of checkers, if you want to know how to draw a map, students who are interested in this can do research, let the family and children participate in the game interaction, and cherish the happy time of companionship.

Open the WeChat development tool, select the applet, create a project,

For example, the project name is miniprogram_chinese_draughts, then select the following, and then confirm the creation

  • AppID uses its own test number
  • Does not use cloud services
  • JavaScript - Basic Templates

start page

After creating a new Mini Program project, the development tool will automatically generate some basic template files,

In the position /pages/index/indexhere, index.wxmlchange it to the start page, add a form for selecting the number of people, and a button, as shown below
insert image description here

In the game of checkers, there cannot be 5 people participating, because the fifth player has no opponent, it is not fair,

Modify index.jshere, add a method enterGame(e), click to start the game will be called, the code is as follows,

enterGame(e){
    
    
    const {
    
     count } = e.detail.value;
    wx.navigateTo({
    
    
      url: '/pages/game/game?args='+count,
    })
}

Jump to the game page, and at the same time pass a parameter countindicating the number of participants

game page

Add a game page, the file location is pages/game/game, game.wxmladd the layout in the page, the content is as follows

<view class="page">
    <canvas class="canvas" id="canv" type="2d" bindtouchstart="onTouchStart"></canvas>
    <scroll-view class="scroll-view" scroll-y="true">
        <view class="game-info">
        <!-- 这里显示游戏状态信息的布局 --->
        </view>
    </scroll-view>
</view>

Among them canvas, the canvas is the most important component, which can be used to draw the screen,
and another component is used to display the game status of each participating player (player).

initialization

The start page has the parameter count passed in, and onLoad(options)it is obtained from the game page loading method. The code is as follows

/**
 * 页面的初始数据
 */
data: {
    
    
    players:[],//参与的玩家列表
    currentPlayer:0,//指定哪个玩家下棋
},
onLoad(options) {
    
    
    let index = 0;//默认的选择
    //如果从上一页有传来参数,这里改变默认的选择
    if(options?.args) index = ['2','3','4','6'].indexOf(options.args);
    //按照选择人数分配玩家
    let players = [[0,5],[1,2,5],[1,2,3,4],[0,1,2,3,4,5]][index].map(id=>{
    
    
        return {
    
    
            id: parseInt(id),//玩家的id
            color: ChessColors[id],//对应的颜色
            step: 0,//开始步数
            rank: 0,//用于记录的排名
        }
    });
    //更新玩家列表显示
    this.setData({
    
    
        players
    })
},

Next, from the preparation complete event onReady()method of the game page,

Get it in the page layout canvas, and then bind the touch start event, the code is as follows

onReady() {
    
    
  wx.createSelectorQuery().select('#canv').fields({
    
    
        size:true,
        node:true
    },res=>{
    
    
        //...
        //获取画布数据
        this.canvasData = {
    
    
            canvas:res.node,//画布canvas元素的节点
            ctx:res.node.getContext('2d'),//画布canvas的绘制工具
        };
        //实例化地图对象
		const map = new Map(this.canvasData,this.data.players.map(p=>p.id));
		//绘制地图的异步方法
		map.drawMap(()=>{
    
    
			//绘制完成了,这里绘制所有参与玩家的棋子
		    map.drawChesses();
		});
		this.map = map;
        //...
    }).exec()
},
onTouchStart(e) {
    
    
	//...这里是canvas画布触摸开始的处理方法
}

From the above, where Maprefers to the map module,

Before using the module, you need to write a line of code to import the module in the header of the code file, that is, a reference, the code is as follows

import {
    
     Map, ChessColors } from '../../utils/map.js';

In addition ChessColors , it is the set of chess piece colors assigned to players by default. If you want to customize it, you can modify it here. The
module file code has a total of 240 lines (including blank lines), which is not much to look at. It implements map data and map drawing methods

game background

In the above initialization logic, the game background has been drawn,

The drawing method of the map is drawMap(callback)that the parameter callbackis the incoming callback method, which will be called after the drawing is completed.

Here is a brief description of its implementation process, the code is as follows

drawMap(callback){
    
    
   const {
    
     canvas, ctx } = this.canvasData;
   //定义它们分别是网格,所有棋子,格子大小,格子半径,圆半径
   const {
    
     grids, chesses, gSize, gR, gRp } = this;
	//初始化值
   const angle = Math.PI*2;
   //修改设置
   ctx.strokeStyle=BorderColor;
   grids.forEach((g,i)=>{
    
    
   		//这个方法是扫描一个格子位置中相邻的一些格子(圆)
       let gs = this.scanGrids(g);
       if (gs.length<=0)  return;
       //在这里画上一些格子之间的连接线
       gs.forEach(g1=>{
    
    
           ctx.beginPath();
           ctx.moveTo(g.x,g.y);
           ctx.lineTo(g1.x,g1.y);
           ctx.stroke();
       });
   });
   ctx.fillStyle=BorderColor;
   //接下来,画出所有的格子(圆),就是覆盖着画
   grids.forEach((g,i)=>{
    
    
       //...
       ctx.beginPath();
       ctx.arc(g.x,g.y,gRp,0,angle);
       ctx.fill();
       ctx.stroke();
   });
	//这里就算画好了,导出图像
   let img = canvas.createImage();
   img.onload = () => callback(img);
   img.src = canvas.toDataURL();
   //网格地图,需要设置到bgImg缓存起来(背景图),将来有用
   this.bgImg = img;
}

Since it is set in bgImgthe cache here, it needs to be redrawn every time it is updated, and
the drawn image can also be set to the background image. It is not necessary to redraw the map every time it is updated, and it is directly displayed on the bottom layer, and
then draw other things, such as drawing Chess pieces after changing position

players and pieces

Draw the chess pieces in different players' camps, which can also be regarded as beads. The chess pieces and grids represented by different players have different colors.

If the position of the chess piece changes, you need to call the method of the map drawChesses(selectIndex)to redraw,

Display the latest layout of all chess pieces, the code is as follows

drawChesses(selectIndex){
    
    
	const {
    
     canvas, ctx } = this.canvasData;
    const {
    
     grids, chesses, gSize, gR, gRp } = this;
    const angle = Math.PI*2;
    //每次绘制前,都要清空画布
    ctx.clearRect(0,0,canvas.width,canvas.height);
    //将缓存的背景图重新绘制出来
    ctx.drawImage(this.bgImg, 0, 0);
    //然后,再去绘制所有的棋子
    let isSelect=false;
    chesses.forEach(chess=>{
    
    
    	//判断是否有选择,记录一下
        if(chess.index==selectIndex) isSelect=true;
    	//如果有选择棋子,就在棋子周围画一个圆(代表选择)
        this.drawChesse(chess,selectIndex);
    });
    //这里还要判断,如果没有棋子被选择过,那剩下可能是选择了没有棋子占用的格子
    if(!isSelect) {
    
    
        this.drawChesse(undefined,selectIndex);
    }
}

It can be seen from the above that the parameter passed in selectIndexrefers to the grid index selected by the player,
and it is also passed to the method drawChesse(chess,selectIndex). The other parameter chessrefers to the chess piece selected, and it is passed if there is no selection undefined. This method realizes how to draw the chess pieces in the grid

Speaking of this, even if the game page is drawn, compile and run to see the effect.

It is displayed as shown in the picture below, a checkers game involving a total of 6 players
insert image description here

game logic

To process from the touch start event of the canvas is the method mentioned above onTouchStart(e).

game rules

Let’s think about the game logic here again. When the user clicks on the chess piece and selects his own chess piece, how should it be realized next?

Learn the following rules of the game here,

According to the rules of the game, clarify the implementation ideas:

  • Judging the number of steps of each player, if the player does not walk out of his camp within 30 steps, he will be out of the game and cannot continue;
  • There are two ways to move chess: the first is to take only one step; the second is to jump to the other side of the chess piece in the direction of the next chess piece, and you can jump continuously;
  • For the number of steps, one step counts as one step, one jump counts as one step, and one step counts as continuous jumps, which can be modified;
  • If all the chess pieces of the opponent's camp are occupied, the winner will be judged. If there are more than three players, the winner will be calculated according to the ranking, and the rest will be judged out of the game;

How to implement the game logic? Implementing the game logic is the most complicated part. In other words, as long as you understand its implementation process, you can basically try it yourself.

choose pieces

The first step is to select a chess piece, and then move the chess piece, just handle it in its touch event, the code is as follows

onTouchStart(e) {
    
    
	//...
   const touch = e.touches[0];//第一个触摸点(位置)
   const {
    
     grids, gRp, chesses } = this.map;
   //所有玩家,指向当前下棋的玩家
   const {
    
     players, currentPlayer } = this.data;
	//通过触摸点位置判断,从网格中找出选择的棋子
   let chess;
   let grid = grids.find(grid=>{
    
    
   		//先从网格位置判断...如果是在这个格子里,再判断是否有棋子在这个格子上...
   });
   //没有点到格子的画,就返回不处理了
   if (grid==undefined) return;
   //给出当前在下棋的玩家
   const player = players[currentPlayer];
   let {
    
     selectGridData } = this;
   //判断之前是否选择过网格(棋子)了,还有就是选择的棋子是当前在下棋的玩家的,如果条件满足了,反之就是不满足
   if (!(selectGridData?.chess?.id==player.id)) {
    
    
   		//不满足以上条件,就重新设置选择数据
       this.selectGridData = {
    
     grid, chess, moveCount:0 };
       //重新绘制所有棋子
       this.map.drawChesses(grid.i);
       //不再继续处理
       return;
   }
	//如果选择到棋子
   if (chess) {
    
    
   		//不是自己的,提示一下
       if (chess.id!=player.id) {
    
    
           this.showToast(`${
      
      player.id+1}号玩家操作`);
           return;
       }
       //如果是相邻跳过的,又选择下一个棋子,就不是连续跳了
       if (selectGridData.moveCount>1) {
    
    
       		//换下一个玩家
           this.setNextPlayer();
           return;
       }
       //剩下的,只有选择棋子了吧,直接给它更新显示
       Object.assign(this.selectGridData, {
    
     chess, grid });
       this.map.drawChesses(grid.i);
       return;
   }
	//获得移动到下一个位置的距离,相对格子的,一个格子算一个单位距离
   let count = this.map.gotoGrid(selectGridData.grid,grid);
   if (count>0) {
    
    
   		//判断是否只移动1个(走),然后就是上次移动的是否大于1个(跳),满足条件
       if (!(count==1 && selectGridData.moveCount>count)) {
    
    
       		//反之不满足,这里更新选择的棋子位置
           chess = selectGridData.chess;
           chess.index =  grid.i;
           //记录移动距离
           selectGridData.moveCount = count;
           //棋子步数加1
           player.step++;
           //获取玩家在自己阵营内的所有棋子
           let chesses2 = this.map.getPlayerChessesAtGrids(player.id);
           //判断这个玩家是否在游戏,还有步数
           if (player.rank==0 && player.step==MinStep) {
    
    
           		//步数大于MinStep限制,还未走出自己阵营,就得通知这个玩家出局了...
           }
           //更新显示玩家的状态
           this.setData({
    
    
               players
           });
       }
   }
   //若只移动1个(走),就更新绘制棋子,换下一个玩家
   if (count==1){
    
    
       this.map.drawChesses(grid.i);
       this.setNextPlayer();
       return;
   }
	//剩下的,就是其它操作了,直接更新显示即可
   Object.assign(this.selectGridData, {
    
     chess, grid });
   this.map.drawChesses(grid.i);
},

Looking at the above, you will notice that there are some details in the method of the map module,

There is another important method above setNextPlayer(), which is to deal with the replacement of the player. Before switching the player, a judgment must be added.

It is to judge whether the player wins or loses. In the end, if the remaining player has not won, then the game is over. The code is as follows

setNextPlayer(){
    
    
   const {
    
     players, currentPlayer } = this.data;
	//定义当前参与的玩家
   const player = players[currentPlayer];
   //找出当前玩家的所有棋子
   let chesses2 = this.map.getPlayerChessesAtGrids(player.id);
   //计算当前玩家是否全部占领对方的阵营
   let isWin = chesses2.reduce((current,next,index)=>{
    
    
   		//棋子flag属性判断即可...
   });
   if (isWin) {
    
    
       let rank=0;
       //全部占领了,更新排名,不再参与...
       player.rank = rank+1;
       //可通过排名和参与人数判断是否到最后了
       if (player.rank+1 >= players.length) {
    
    
           //这里是最后的了,直接弹出游戏结束...
           this.showGameOver(`${
      
      player.id+1}号玩家赢了,成功占领对方的阵营`);
           return;
       }else{
    
    
       		//提示一下,然后继续
           this.showModal(`${
      
      player.id+1}号玩家赢了,成功占领对方的阵营`);
       }
   }
	//换下一个玩家
   let current = (currentPlayer+1)%players.length;
   //此处省略了...
   this.setData({
    
    
       currentPlayer: current,
       players
   });
   this.showToast(`${
      
      players[current].id+1}号玩家操作`);
},

game testing

That’s it, the realization idea of ​​the checkers game is probably clear, right?

The other method of calling is wrong, although I didn’t mention it, but I know its meaning after seeing its name, I believe that I can realize it,

Let’s take a look. The effect of the game running is as follows. This is two people participating. After the test, I feel that there is no problem.
Please add a picture description

If you want to see the source code of the project, please click here to view it , and find the resource category column ( if you can’t find it on your mobile phone, you can use a computer browser to access it ),

In the resource list, find the source code of the checkers game project, please rest assured to download, thank you for your support.

Game Inspiration: What inspiration do you have for this?

  • Choose the target and occupy it as soon as possible, similar to the mutual generation and mutual restraint in the five elements fighting method,
  • In this game rule, move as fast as possible, and you will be beaten if you fall behind

Guess you like

Origin blog.csdn.net/zs1028/article/details/130119079