柿霖不是林 发表于 2017-3-3 16:51:57

微信小程序学习用demo:五子棋,基于canvas


预览图片:



var Stone = require('Stone');
var judger = require('FiveStoneJudger');

/**
* 五子棋的主控制类
*/
export default class FiveStone {

    /**
   * 初始化棋盘
   * @param   page                  当前页面页面
   * @param   chessBoardSize          当前棋盘每行和列最多能下多少个子子
   * @param   chessboardSizePercent   棋盘的宽度相当于屏幕宽度的百分比(0<x<1)
   */
    constructor(chessBoardSize, chessboardSizePercent) {
      var self = this;
      var chessBoard = [];
      //占位
      var chessBoardCell = [];
      this.chessBoardSize = chessBoardSize;
      for (var r = 0; r < chessBoardSize; r++) {
            var row = [];
            var cellRow = [];
            for (var c = 0; c < chessBoardSize; c++) {
                row.push({
                  stoneType:Stone.none,
                  //位置使用到的时候才计算
                  pos:null
                });
                if (c < chessBoardSize - 1) {
                  cellRow.push(0);
                }
            }
            chessBoard.push(row);
            if (r < chessBoardSize - 1) {
                chessBoardCell.push(cellRow);
            }
      }
      this.chessBoard = chessBoard;
      this.chessBoardCell = chessBoardCell;
      //获取系统信息
      wx.getSystemInfo({
            success: function(res) {
                self.chessboardSizePX = res.windowWidth * chessboardSizePercent;
                console.log('%c棋盘大小:%c' +
               self.chessboardSizePX +
                  '%cpx',
                  'color:red;',
                  'color:blue;',
                  'color:black;'
                  );
                self.cellSizePX = self.chessboardSizePX / (chessBoardSize - 1);
                console.log('%c单元格大小:%c' +
               self.cellSizePX +
                  '%cpx',
                  'color:red;',
                  'color:blue;',
                  'color:black;'
                  );
                  self.halfCellSizePX = self.cellSizePX * 0.5;
            }
      });
      //当前下子的类型
      this.stone = Stone.black;
      //下子监听的回调集合
      this.onStepStoneCallbacks = [];
      //是否能够下子的开关
      this._canStep = true;
      //历史
      this.history = [];
      //设置裁判
      this.setJudger(judger);
    }

    /**
   * 通过事件获取下子在棋盘的位置
   */
    getStepLocation(e) {
      var curTarget = e.currentTarget;
      var offset = {
            x: curTarget.offsetLeft,
            y: curTarget.offsetTop
      };
      var touch = e.touches;
      //相对棋盘的位置
      var clientPos = {
            x:touch.pageX - offset.x,
            y:touch.pageY - offset.y
      };
      var stepPos = {
            x: Math.ceil((clientPos.x - this.halfCellSizePX) / this.cellSizePX),
            y: Math.ceil((clientPos.y - this.halfCellSizePX) / this.cellSizePX)
      };
      if (stepPos.x < 0 || stepPos.x >= this.chessBoardSize ||
            stepPos.y < 0 || stepPos.y >= this.chessBoardSize) {
                return null;
            }
      return stepPos;
    }

    /**
   * 通过事件获取下子在棋盘的绝对位置
   */
    getStepPosition(e) {
      var curTarget = e.currentTarget;
      var stepPos = this.getStepLocation(e);
      if (stepPos == null) {
            return null;
      }
      var absPos = stepPos.clone();
      //后面的那个1像素怎么出来的我也不知道,反正减了之后位置看起来正很多
      absPos.x = absPos.x * this.cellSizePX + curTarget.offsetLeft - this.halfCellSizePX - 1;
      absPos.y = absPos.y * this.cellSizePX + curTarget.offsetTop - this.halfCellSizePX - 1;
      this.chessBoard.pos = absPos.clone();
      return absPos;
    }

    /**
   * 下棋,设置的是基于棋盘的坐标
   * @return返回true就是下子成功,否则为失败
   */
    step(x, y) {
      if (this.canStepAt(x, y)) {
            this.chessBoard.stoneType = this.nowStone();
            const nowStone = this.nowStone();
            this.stone = nowStone == Stone.black ? Stone.white:Stone.black;
            this.onStepStone(nowStone, x, y);

            if (!(this.history instanceof Array)) {
                this.history = [];
            }
            //插入到历史
            this.history.push({
                'x':x,
                'y':y,
                'stoneType':nowStone
            });
            this.judge(nowStone, x, y);
            return true;
      }
      return false;
    }

    /**
   * 悔棋
   */
    undo() {
      if (!(this.history instanceof Array) || this.history.length <= 0) {
            return;
      }
      const lastStoneIndex = this.history.length - 1;
      const lastStone = this.history;
      this.stone = lastStone.stoneType;
      this.history.splice(lastStoneIndex, 1);
      this.chessBoard.stoneType = Stone.none;
      this.allowStep();
    }

    /**
   * 判断该棋子是否能够下
   */
    canStepAt(x, y) {
      if (x < 0 || x >= this.chessBoardSize ||
            y < 0 || y >= this.chessBoardSize ||
            this.chessBoard.stoneType != Stone.none) {
                return false;
      }
      return this._canStep;
    }

    /**
   * 当触发了下子的事件的时候
   */
    onStepStone(nowStone, x, y) {
      if (this.onStepStoneCallbacks instanceof Array) {
            for (var i in this.onStepStoneCallbacks) {
                const cb = this.onStepStoneCallbacks;
                if (typeof(cb) === 'function') {
                  cb.call(this, nowStone, x, y);
                }
            }
      }
    }

    /**
   * 添加下子的监听器
   * @return 如果返回0则代表插入失败,成功返回索引
   */
    addOnStepStoneCallback(func) {
      if (!(this.onStepStoneCallbacks instanceof Array)) {
            this.onStepStoneCallbacks = [];
      }
      if (typeof(func) == 'function') {
            //push以后会返回数组的长度,所以减一之后就会是对应的索引
            return this.onStepStoneCallbacks.push(func) - 1;
      }
      return 0;
    }

    /**
   * 通过索引删除下子的监听器
   */
    removeOnStepStoneCallback(index) {
      if (this.onStepStoneCallbacks instanceof Array) {
            if (this.onStepStoneCallbacks.length > index) {
                this.onStepStoneCallbacks.splice(index, 1);
            }
      }
    }

    /**
   * 重新开局
   */
    restart() {
      this.stone = Stone.black;
      for (var r in this.chessBoard) {
            for (var c in this.chessBoard) {
                this.chessBoard.stoneType = Stone.none;
            }
      }
      //清空历史
      this.history = [];
      this.allowStep();
    }

    /**
   * 阻止下子
   */
    preventStep() {
      this._canStep = false;
    }

    /**
   * 允许下子
   */
    allowStep() {
      this._canStep = true;
    }

    /**
   * 获取当前是下的黑子还是白子
   */
    nowStone() {
      return this.stone;
    }

    /**
   * 返回当前是否允许下子
   */
    canStep() {
      return this._canStep;
    }

    /**
   * 进行裁判(下子成功之后触发)
   * @param stepStone 当前下子的类型
   * @param x         下子基于棋盘的x坐标
   * @param y         下子基于棋盘的y坐标
   */
    judge(stepStone, x, y) {
      if (typeof(this._judger) == 'function') {
            this._judger.call(this, stepStone, x, y, this._winCallback);
      }
    }

    /**
   * 设置裁判回调
   */
    setJudger(func) {
      if (typeof(func) == 'function') {
            this._judger = func;
      }
    }

    /**
   * 设置胜利之后的回调
   */
    setWinCallback(func) {
      if (typeof(func) == 'function') {
            this._winCallback = func;
      }
    }
}

**** Hidden Message *****

sharly_xie 发表于 2017-7-3 11:23:18

:o来学习

巫山帅才少儿棋苑 发表于 2017-9-21 23:37:44

下车费vgbhnjmk

地破哲 发表于 2018-7-23 17:25:03

学习学习

看看看 发表于 2018-7-23 17:30:29

so niceeeeeeeeeeeeeeeeeeeeeeeeeee

李赫海 发表于 2018-8-1 16:14:39

666666666666666666666666666666

Asr.Q 发表于 2019-5-7 14:16:35

过来找找答案

ygj1 发表于 2019-5-7 23:11:26

ffffffffffffffffffffff

tt2271267273 发表于 2019-6-23 11:47:57

真厉害

18301569033 发表于 2019-7-13 11:18:33

学习一下
页: [1] 2 3
查看完整版本: 微信小程序学习用demo:五子棋,基于canvas