【斗兽棋】-单机游戏-微信小程序项目开发入门

还记得小时候玩过的斗兽棋游戏不,90后的经典怀旧游戏哦,笔者TA远方在读小学的时候,曾玩过的游戏名单就有它,也许有人忘记了,现在才想起,理清一下斗兽棋游戏的规则:

👉 游戏的基本规则

  • 吃小:象 > 狮 > 虎 > 豹>狼 > 狗 > 猫 > 鼠
  • 吃大:只有鼠 能吃 象
  • 同棋:互吃
  • 潜水:只有鼠 能游在河里,河边的不能吃河里的,同样,河里的不能吃河边的
  • 走法:只能往前后左右方向走一格,狮和虎可横向跳过小河
  • 陷阱:对方的棋落入我方陷阱,我方的任意棋都可吃陷阱里的
  • 嬴法:我方的棋走入对方的兽穴就算赢
  1. 首先,打开微信小程序开发工具,新建一个小程序项目后,打开游戏页面的布局文件/pages/index.index.wxml,添加代码如下所示,
<view class="page">
		<view class="canvas-box">
			<canvas class="canvas" canvas-id="canvA" id="canvA" type="2d"></canvas>
			<canvas class="canvas" canvas-id="canvB" id="canvB" type="2d"></canvas>
			<canvas class="canvas" canvas-id="canvC" id="canvC" type="2d" bindtouchstart="onTouch"></canvas>
		</view>
		<!-- ... -->
</view>
  1. 接下来,在样式文件/pages/index/index.wxss中,写好布局样式,使得布局显示效果图如下,图中的绿色区域是用组件canvas多层显示的效果
    在这里插入图片描述
  2. 接着,开始实现游戏的逻辑,打开主要文件/pages/index/index.js,添加的代码如下,当页面加载时,最后走得是自动重置游戏逻辑
import CanvasContext from '../../utils/canvas_context';

Page({
	data: {
		//定义所有画布组件
		canvas: {},
	},
	onLoad(){
		//...获取页面布局的canvas组件信息,包括size大小,node节点
	  wx.createSelectorQuery().select('#canvA').fields({ size: true, node: true },res=>{
	      this.data.canvas.width = res.width;
	      this.data.canvas.height = res.height;
	      //处在底层的画布
	      this.data.canvas.canvA = new CanvasContext(res);
	
	      wx.createSelectorQuery().select('#canvB').fields({ size: true, node: true },res=>{
	      	//处在中间层的画布
	        this.data.canvas.canvB = new CanvasContext(res);
	  
	        wx.createSelectorQuery().select('#canvC').fields({ size: true, node: true },res=>{
	        	//处在顶层的画布
	          this.data.canvas.canvC = new CanvasContext(res);
	          this.reset()
	        }).exec()
	      }).exec()
	    }).exec()
	},
	//处理用户触摸点击的
	onTouch(e){
		//...具体后面有讲
	},
	//重置按钮点击
	onReset(){
	    wx.showModal({
	      title:'系统提示',
	      content:'确定要重置游戏吗?',
	      success: res => {
	        if (!res.confirm) return;
	        this.reset();
	        wx.showToast({
	          title:'已重置',
	          icon:'none'
	        })
	      }
	    })
	  },
	//重置游戏逻辑
	reset(){
		//...下面接着讲
	}
})

💡小提示

  1. 重置游戏逻辑,先处理初始化,再处理画出来,实现代码如下
//游戏中大部分颜色信息都在这里定义
const Colors = {
	//...
};
//游戏的所有棋子名字都在这里定义
const beastNames = {
	//...象>狮>虎>豹>狼>狗>猫>鼠
};

Page({
	data: {
		//定义所有画布
		canvas: {}stateMsg: '初始化...',//游戏状态消息
		isMyFlag: true,//当前是否是我方先手
		trapCoordinate: [],//陷阱坐标
	    denCoordinate: [],//兽穴坐标
	    rillCoordinate: [],//小河坐标
	    beastCoordinates: [],//所有兽布局坐标
	    gameEnd: false,//游戏是否结束
	},
	//初始化游戏数据
	init(){
		//棋盘中就像地图,存在的一切物体都可化作数据, 只用坐标表示数据就可以了

		//...陷阱坐标数据
		this.data.trapCoordinate = [
	      //...
	    ];
	    //两个兽穴坐标数据,其中[3,0]是坐标数组,如一个兽穴在地图的坐标点(3,0)处
	    this.data.denCoordinate = [ [3,0],[3,8] ];
	    //小河坐标数据
	    this.data.rillCoordinate = [
	      //...
	    ];
	    //所有的棋子数据
	    this.data.beastCoordinates = [
	      { name: beastNames.rat, rank: 0, myFlag: false, coordinate: [0,2] },
	      //...
	    ];
	},
	//重置游戏逻辑
	reset(){
		const { canvA, canvB, canvC, width, height } = this.data.canvas;
	    this.init();
	    //...设置画布的相关参数	    
	    canvA.setFillStyle(Colors.backColor);
	    canvA.setStrokeStyle(Colors.borderColor);
	    canvA.fillRect(0,0,width,height);//画背景色
	    canvA.beginPath();
	    const cols = 7;//棋盘的横向格子数
	    const rows = cols+2;//棋盘的纵向格子数
	    const gw = Math.trunc(width/cols);//格子宽度
	    const gh = Math.trunc(height/rows);//格子高度
	    //遍历处理
	    for(let i=1; i<rows; i++){
	      //...把棋盘的所有格子都画出来
	    }
	    //此处省略...设置画布的相关参数
	    
	    //格子一半的宽度和高度,由于是手机竖屏显示,宽高比有不同
	    const gwR = gw/2;
	    const ghR = gh/2;
	    //把所有的陷阱画出来
	    this.data.trapCoordinate.forEach(e => {
	      //...
	      canvA.fillText("陷阱", x, y);
	    });
	   
	    //把两个兽穴画出来
	    this.data.denCoordinate.forEach(e => {
		  //...
	      canvA.fillText("兽穴",x,y);
	    });
	    
	    //把两条小河画出来
	    this.data.rillCoordinate.forEach(e => {
	      //...
	      canvA.fillRect(x+1,y+1,waW,waH);
	    });
	    
	    canvA.draw();
	    //将格子的宽高信息设置到canvas画布中,后面有用
	    Object.assign(this.data.canvas, {
	      gw,
	      gh,
	      gwR,
	      ghR
	    });
	    
		//把所有的兽棋画出来
	    this.data.beastCoordinates.forEach(e => {
	      this.drawChess(e,canvB);
	    });
	    canvB.draw();
	    //...初始化数据
	    this.data.isMyFlag = true;
	    this.data.gameEnd = false;
	    this.setData({
	      stateMsg: '👉我方先手'
	    })
	},
	//画兽棋的方法
	drawChess(e,canv, isMax){
	    const { gw, gh, gwR, ghR } = this.data.canvas;
	    this.drawChessTo({
	      x: e.coordinate[0] * gw + gwR,//计算出x坐标
	      y: e.coordinate[1] * gh + ghR,//计算出y坐标
	      name: e.name,//兽棋的名称
	      myFlag: e.myFlag,//是否是我方的
	      canv,//画布
	      isMax,//是否画到最大,当拾起棋子时就画到最大
	      gwR,//格子宽度一半
	    });
  },
  //具体的画棋方法,根据坐标定位来画
  drawChessTo(e){
  	//...此处省略
  }
}
  1. 以上就是初始化游戏的处理过程,接下来,讲一下处理用户触摸点击的逻辑,这里的逻辑就复杂了一些,需要细分成三个逻辑来处理,分别是识棋,吃棋,走棋,实现代码如下
Page({
	data: {
		//定义所有画布
		canvas: {}stateMsg: '初始化...',//游戏状态消息
		isMyFlag: true,//当前是否是我方先手
		trapCoordinate: [],//陷阱
	    denCoordinate: [],//兽穴
	    rillCoordinate: [],//小河
	    beastCoordinates: [],//所有兽
	    gameEnd: false,//游戏是否结束
	},
	//处理用户触摸点击的
	onTouch(e){
		if (this.data.gameEnd || this.data.isLoadAnimation) return;
	    const { canvC, gwR } = this.data.canvas;
	    const touch = e.touches[0];//第一个触摸点
	    let chess = this.findChess(touch);
	    //触摸位置处是棋子
	    if (chess!=null) {
	      //如果当前有拾起的棋子
	      if (this.data.selectChess!=null){
	      	//触摸的棋子不是我方的
	        if (chess.myFlag!=this.data.selectChess.myFlag){
	          this.eatChess(chess);
	          return;
	        }
	        //若是我方的,当前还不是我方先手,不能选择我方的棋子
	        else if(this.data.isMyFlag!=this.data.selectChess.myFlag){
	          return;
	        }
	      }
	      //拾起棋子前,判断是我方先手,只能选择我方的棋子
	      else if (chess.myFlag!=this.data.isMyFlag){
	        return;
	      }
	    } else {
	      this.moveChess(touch);
	      return;
	    }
	    //选择棋子后,画出来
	    this.data.selectChess = chess;
	    this.drawChess(chess,canvC,true);
	    canvC.draw();
	},
	//识别棋盘中棋子
	findChess(touch){
		//...
	},
	//处理吃棋的方法
	eatChess(e){
		//...
	},
	//移动棋子的方法
	moveChess(t){
		//...
	},
	//画棋子的方法
	drawChess(e,canv, isMax){
		//...上面有讲过了
	}
})
  1. 不够详细吧,那写具体一点,识棋,吃棋,走棋的实现方法大致思路如下
Page({
	data: {
		//定义所有画布
		canvas: {}stateMsg: '初始化...',//游戏状态消息
		isMyFlag: true,//当前是否是我方先手
		trapCoordinate: [],//陷阱
	    denCoordinate: [],//兽穴
	    rillCoordinate: [],//小河
	    beastCoordinates: [],//所有兽
	    gameEnd: false,//游戏是否结束
	},
	//处理吃棋的方法
	eatChess(e){
		if (e==null || this.data.selectChess==null) return;
	    let x = e.coordinate[0];//x坐标
	    let y = e.coordinate[1];//y坐标
	    let c = this.getMoveCoordainte(x, y);
	    if (c==null) return;//不可移动该位置
	    let s = this.data.selectChess;//拾起的棋子所在的位置
	    
	    let isEat = false;
	    //先判断该位置是否有陷阱
	    let trap = this.data.trapCoordinate.find(m => m[0]==x && m[1]==y);
	    let rill = null;
	    //如果没有陷阱,判断是否有小河
	    if (trap==null) rill = this.data.rillCoordinate.find(m => m[0]==x && m[1]==y);
	    //拾起的棋子(鼠),是否在小河中
	    let rill2 = this.data.rillCoordinate.find(m => m[0]==s.coordinate[0] && m[1]==s.coordinate[1]);
	    if (rill) {
	      isEat = rill!=null && rill2!=null;//在小河中是否互吃
	    } else if (rill2==null) {
	      //在陷阱中,任意吃
	      if (trap) isEat = (y>4 && this.data.isMyFlag) || (y<4 && this.data.isMyFlag==false);
	      //还是不能吃的话,最后用大吃小的规则判断,还有鼠 能吃 象
	      if (!isEat) isEat = (s.rank==0 && e.rank==7) || (!(s.rank==7 && e.rank==0) && s.rank>=e.rank);
	    }
	    if (isEat) {
	    	//能吃,查找棋子的索引
	      let index = this.data.beastCoordinates.findIndex(m => m.name==e.name && m.myFlag==e.myFlag);
	      //如果存在,就吃棋
	      if (index>=0){
	        //...处理细节省略
	        this.startAnimaFromCanvC({
	          chess: s,
	          start: { x: c2[0], y: c2[1] },
	          end: { x, y },
	          complete:()=>{
	          	//...省略处理细节
	          	//移除被吃掉的棋子
	          	this.data.beastCoordinates.splice(index,1);
	            //如果进入对方的兽穴,就判定游戏结束
	            if(c.endGame) this.data.gameEnd = true;
	            this.data.selectChess = null;
	            this.updateGameState();
	          }
	        });
	      }
	    }
	},
	//移动(走)棋子的方法
	moveChess(t){
		if (t==null || this.data.selectChess==null) return;
	    const { canvB, canvC, gw, gh } = this.data.canvas;
	    
	    let x = Math.trunc(t.x / gw);
	    let y = Math.trunc(t.y / gh);
	    let c = this.getMoveCoordainte(x,y);
	    //不可移动该位置
	    if (c==null) return;
		//...此处省略细节
		this.startAnimaFromCanvC({
	      chess: this.data.selectChess,
	      start: { x: c2[0], y: c2[1] },
	      end: { x, y },
	      complete:()=>{
	        //...此处省略细节
	        //如果进入对方的兽穴,就判定游戏结束
	        if(c.endGame) this.data.gameEnd = true;
	        this.data.selectChess = null;
	        this.updateGameState();
	      }
	    });
	},
	//识别棋盘中棋子
	findChess(touch){
		const { gw, gh } = this.data.canvas;
		//...知道了触摸点在棋盘中的位置,就可以从所有兽棋数据中查找并返回
	    return this.data.beastCoordinates.find(m => {
	    	//...
	    });
	},
	//获取可移动的坐标
	getMoveCoordainte(x,y){
		//...
	},
	//走棋,吃棋动作处理成动画
	startAnimaFromCanvC(e){
		//...
		e.complete();//执行动画结束时调用
	},
	//更新游戏状态
	updateGameState(){
		//...
	}
})
  1. 一不小心就写到这么多,就到此结束吧,剩下的方法都有列出来的,一个都不能少,只是部分实现细节都用省略号代替,能耐心看到这里,讲得还算可以吧,实现过程是不难,就代码写得比较多,不知读者能否看懂,对此文章讲得实现思路有清晰了没有呢🙂

💡小提示
如果想要看更详细的,有相关的项目源码,请点此前往查看
资源一栏下,里面有斗兽棋项目源码,选择下载即可,然后用微信开发工具打开,直接编译运行就能看到效果

  1. 最后项目完工,游戏编译正常,运行效果如下图所示,是个动图哦,如觉得有帮助,麻烦请点个👍,或,鼓励一下,在此谢过~

在这里插入图片描述

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我可以为您提供一些五子游戏的代码实现,您可以采用微信小程序游戏的方式进行开发。以下是一些五子的代码示例: 1. 连续五个子代表胜利 ```javascript // 检查当前位置的左右、上下和斜线上是否有5个相同的子 function checkWin(x, y, chessBoard, N, color) { let count = 0; // 检查左右 for (let i = x; i >= 0; i--) { if (chessBoard[i][y] === color) { count++; } else { break; } } for (let i = x + 1; i < N; i++) { if (chessBoard[i][y] === color) { count++; } else { break; } } if (count >= 5) { return true; } count = 0; // 检查上下 for (let j = y; j >= 0; j--) { if (chessBoard[x][j] === color) { count++; } else { break; } } for (let j = y + 1; j < N; j++) { if (chessBoard[x][j] === color) { count++; } else { break; } } if (count >= 5) { return true; } count = 0; // 检查左上右下斜线 for (let i = x, j = y; i >= 0 && j >= 0; i--, j--) { if (chessBoard[i][j] === color) { count++; } else { break; } } for (let i = x + 1, j = y + 1; i < N && j < N; i++, j++) { if (chessBoard[i][j] === color) { count++; } else { break; } } if (count >= 5) { return true; } count = 0; // 检查右上左下斜线 for (let i = x, j = y; i >= 0 && j < N; i--, j++) { if (chessBoard[i][j] === color) { count++; } else { break; } } for (let i = x + 1, j = y - 1; i < N && j >= 0; i++, j--) { if (chessBoard[i][j] === color) { count++; } else { break; } } if (count >= 5) { return true; } return false; } ``` 2. 初始化盘 ```javascript function initChessBoard(N) { const chessBoard = new Array(N); for (let i = 0; i < N; i++) { chessBoard[i] = new Array(N); for (let j = 0; j < N; j++) { chessBoard[i][j] = 0; } } return chessBoard; } ``` 3. 下操作 ```javascript function makeMove(x, y, player, chessBoard) { chessBoard[x][y] = player; } ``` 以上是部分五子游戏的代码示例,您可以根据自己的需求进行修改和完善。希望能对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TA远方

谢谢!收到你的爱╮(╯▽╰)╭

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值