欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

VUE+Canvas實現(xiàn)簡單五子棋游戲的全過程

 更新時間:2021年05月10日 15:19:01   作者:登樓痕  
這篇文章主要給大家介紹了關于VUE+Canvas實現(xiàn)簡單五子棋游戲的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

在布局上,五子棋相比那些目標是隨機運動的游戲,實現(xiàn)起來相對簡單許多,思路也很清晰,總共分為:

(1)畫棋盤;

(2)監(jiān)聽點擊事件畫黑白棋子;

(3)每次落子之后判斷是否有5子相連,有則贏。

最復雜的恐怕就是如何判斷五子棋贏了,那么就先從簡單的開始,畫個棋盤吧~

1、畫棋盤

棋盤很簡單,我們畫個15*15的棋盤,橫線豎線相交錯:

drawCheckerboard() {
      // 畫棋盤
      let _this = this;
      _this.ctx.beginPath();
      _this.ctx.fillStyle = "#fff";
      _this.ctx.rect(0, 0, 450, 450);
      _this.ctx.fill();
      for (var i = 0; i < 15; i++) {
        _this.ctx.beginPath();
        _this.ctx.strokeStyle = "#D6D1D1";
        _this.ctx.moveTo(15 + i * 30, 15); //垂直方向畫15根線,相距30px;
        _this.ctx.lineTo(15 + i * 30, 435);
        _this.ctx.stroke();
        _this.ctx.moveTo(15, 15 + i * 30); //水平方向畫15根線,相距30px;
        _this.ctx.lineTo(435, 15 + i * 30);
        _this.ctx.stroke();
 
        _this.resultArr.push(new Array(15).fill(0));
      }
}

先用一個450 * 450 的正方形打底,四周留15寬度的空白,然后畫上間隔為30的線。在for循環(huán)里,我們還初始化了一個15 * 15的二維數(shù)組,并全部填上0,沒錯,就是記錄落子的。

2、監(jiān)聽點擊事件畫黑白棋子

好了,我們在獲取dom的時候順便監(jiān)聽一下click事件,來畫棋子:

let container = document.getElementById("gobang");

container.addEventListener("click", _this.handleClick);

handleClick(event) {
      let x = event.offsetX - 70;
      let y = event.offsetY - 70;
      if (x < 15 || x > 435 || y < 15 || y > 435) {
        // 點出界的
        return;
      }
      this.drawChess(x, y);
      if(this.winGame){
        this.drawResult();
        return;
      }
      this.whiteTurn = !this.whiteTurn;
      this.drawText();
}

畫棋子的代碼:

drawChess(x, y) {
      let _this = this;
      let xLine = Math.round((x - 15) / 30); // 豎線第x條
      let yLine = Math.round((y - 15) / 30); // 橫線第y條
      if(_this.resultArr[xLine][yLine] !== 0){
        return;
      }
      let grd = _this.ctx.createRadialGradient(
        xLine * 30 + 15,
        yLine * 30 + 15,
        4,
        xLine * 30 + 15,
        yLine * 30 + 15,
        10
      );
      grd.addColorStop(0, _this.whiteTurn ? "#fff" : "#4c4c4c");
      grd.addColorStop(1, _this.whiteTurn ? "#dadada" : "#000");
      _this.ctx.beginPath();
      _this.ctx.fillStyle = grd;
      _this.ctx.arc(
        xLine * 30 + 15,
        yLine * 30 + 15,
        10,
        0,
        2 * Math.PI,
        false
      );
      _this.ctx.fill();
      _this.ctx.closePath();
 
      _this.setResultArr(xLine, yLine);
      _this.checkResult(xLine, yLine);
}

很容易可以計算出點擊坐標最近的那個棋盤交叉點,當然,如果那里已經(jīng)落了子,就得return。然后在交點處畫上白子或者黑子,這里用漸變填充使棋子看起來更像那么回事。接著,在對應的二維數(shù)組里記錄一下棋子狀況:

setResultArr(m, n) {
      let _this = this;
      _this.resultArr[m][n] = _this.whiteTurn ? 1 : 2; // 白棋為1;黑棋為2
 
}

3、檢查五子棋輸贏結(jié)果

輸贏結(jié)果怎么判斷?肉眼看去,無非就是以當前落子為0,0原點建立坐標系,然后判斷0°,180°,45°和135°四條線上是否有連續(xù)5子。相比于直接遍歷計數(shù),更好的方法就是取出四條線上的數(shù)據(jù),然后判斷是否有相連的5個1或者2字符。

假設我們落子的數(shù)組坐標是[m, n]。

(1)橫線的結(jié)果數(shù)組字符串:this.resultArr[m].join('');

(2)豎線的結(jié)果數(shù)組字符串:

for(let i = 0; i<15; i++){
        lineHorizontal.push(_this.resultArr[i][n]);

}

(3)135°(左上到右下):j從0-15,分別取this.resultArr[m - j][n -j]結(jié)果unshift進臨時數(shù)組頭部,取this.resultArr[m + j][n + j]放到臨時數(shù)組尾部,行成結(jié)果;

(4)45°(左下到右上):j從0-15,分別取this.resultArr[m + j][n -j]結(jié)果unshift進臨時數(shù)組頭部,取this.resultArr[m - j][n + j]放到臨時數(shù)組尾部,行成結(jié)果;

當然這里面都是要判斷一下數(shù)組越界。

得到結(jié)果字符串后,我們判斷是否有“22222”或者“11111”這樣的字符串存在,有則說明勝利。

checkResult(m ,n){ // 判斷是否有5子相連
      let _this = this;
      let checkStr = _this.whiteTurn ? CheckStrWhite : CheckStrBlack;
      // 取出[m,n]橫豎斜四條線的一維數(shù)組
      let lineVertical = _this.resultArr[m].join('');
      if(lineVertical.indexOf(checkStr) > -1){
        _this.winGame = true;
        return;
      }
      let lineHorizontal = [];
      for(let i = 0; i<15; i++){
        lineHorizontal.push(_this.resultArr[i][n]);
      }
      lineHorizontal = lineHorizontal.join('');
      if(lineHorizontal.indexOf(checkStr) > -1){
        _this.winGame = true;
        return;
      }
      let line135 = [];
      for(let j = 0; j < 15; j++){
        if(m - j >= 0 && n - j >= 0){ // 左上角
          line135.unshift(_this.resultArr[m - j][n -j]);
        }
        if(j > 0 && m + j < 15 && n + j < 15){ // 右下角
          line135.push(_this.resultArr[m + j][n + j]);
        }
      }
      line135 = line135.join('');
      if(line135.indexOf(checkStr) > -1){
        _this.winGame = true;
        return;
      }
      let line45 = [];
      for(let j = 0; j < 15; j++){
        if(m + j < 15 && n - j >= 0){ // 右上角
          line45.unshift(_this.resultArr[m + j][n -j]);
        }
        if(j > 0 && m - j >=0 && n + j < 15){ // 左下角
          line45.push(_this.resultArr[m - j][n + j]);
        }
      }
      line45 = line45.join('');
      if(line45.indexOf(checkStr) > -1){
        _this.winGame = true;
        return;
      }
}

最后勝出,我們顯示一下是哪方獲勝。

至此,一個簡單的黑白棋游戲就做好了~~~~~

老規(guī)矩,源碼貼上:

<template>
  <div class="gobang">
    <canvas id="gobang" width="800" height="600"></canvas>
  </div>
</template>
 
<script>
const CheckStrWhite = "11111";
const CheckStrBlack = "22222";
export default {
  name: "Gobang",
  data() {
    return {
      ctx: null,
      winGame: false,
      whiteTurn: false, // 白棋輪;true-黑棋輪
      resultArr: [] // 記錄棋子位置的數(shù)組
    };
  },
  mounted() {
    let _this = this;
    let container = document.getElementById("gobang");
 
    container.addEventListener("click", _this.handleClick);
 
    _this.ctx = container.getContext("2d");
    _this.ctx.translate(70,70);
    _this.drawCheckerboard();
  },
  computed:{
    chessText(){
      return this.whiteTurn ? '白棋' : '黑棋';
    }
  },
  methods: {
    drawCheckerboard() {
      // 畫棋盤
      let _this = this;
      _this.ctx.beginPath();
      _this.ctx.fillStyle = "#fff";
      _this.ctx.rect(0, 0, 450, 450);
      _this.ctx.fill();
      for (var i = 0; i < 15; i++) {
        _this.ctx.beginPath();
        _this.ctx.strokeStyle = "#D6D1D1";
        _this.ctx.moveTo(15 + i * 30, 15); //垂直方向畫15根線,相距30px;
        _this.ctx.lineTo(15 + i * 30, 435);
        _this.ctx.stroke();
        _this.ctx.moveTo(15, 15 + i * 30); //水平方向畫15根線,相距30px;棋盤為14*14;
        _this.ctx.lineTo(435, 15 + i * 30);
        _this.ctx.stroke();
 
        _this.resultArr.push(new Array(15).fill(0));
      }
      _this.drawText();
    },
    drawChess(x, y) {
      let _this = this;
      let xLine = Math.round((x - 15) / 30); // 豎線第x條
      let yLine = Math.round((y - 15) / 30); // 橫線第y條
      if(_this.resultArr[xLine][yLine] !== 0){
        return;
      }
      let grd = _this.ctx.createRadialGradient(
        xLine * 30 + 15,
        yLine * 30 + 15,
        4,
        xLine * 30 + 15,
        yLine * 30 + 15,
        10
      );
      grd.addColorStop(0, _this.whiteTurn ? "#fff" : "#4c4c4c");
      grd.addColorStop(1, _this.whiteTurn ? "#dadada" : "#000");
      _this.ctx.beginPath();
      _this.ctx.fillStyle = grd;
      _this.ctx.arc(
        xLine * 30 + 15,
        yLine * 30 + 15,
        10,
        0,
        2 * Math.PI,
        false
      );
      _this.ctx.fill();
      _this.ctx.closePath();
 
      _this.setResultArr(xLine, yLine);
      _this.checkResult(xLine, yLine);
    },
    setResultArr(m, n) {
      let _this = this;
      _this.resultArr[m][n] = _this.whiteTurn ? 1 : 2; // 白棋為1;黑棋為2
 
    },
    
    checkResult(m ,n){ // 判斷是否有5子相連
      let _this = this;
      let checkStr = _this.whiteTurn ? CheckStrWhite : CheckStrBlack;
      // 取出[m,n]橫豎斜四條線的一維數(shù)組
      let lineVertical = _this.resultArr[m].join('');
      if(lineVertical.indexOf(checkStr) > -1){
        _this.winGame = true;
        return;
      }
      let lineHorizontal = [];
      for(let i = 0; i<15; i++){
        lineHorizontal.push(_this.resultArr[i][n]);
      }
      lineHorizontal = lineHorizontal.join('');
      if(lineHorizontal.indexOf(checkStr) > -1){
        _this.winGame = true;
        return;
      }
      let line135 = [];
      for(let j = 0; j < 15; j++){
        if(m - j >= 0 && n - j >= 0){ // 左上角
          line135.unshift(_this.resultArr[m - j][n -j]);
        }
        if(j > 0 && m + j < 15 && n + j < 15){ // 右下角
          line135.push(_this.resultArr[m + j][n + j]);
        }
      }
      line135 = line135.join('');
      if(line135.indexOf(checkStr) > -1){
        _this.winGame = true;
        return;
      }
      let line45 = [];
      for(let j = 0; j < 15; j++){
        if(m + j < 15 && n - j >= 0){ // 右上角
          line45.unshift(_this.resultArr[m + j][n -j]);
        }
        if(j > 0 && m - j >=0 && n + j < 15){ // 左下角
          line45.push(_this.resultArr[m - j][n + j]);
        }
      }
      line45 = line45.join('');
      if(line45.indexOf(checkStr) > -1){
        _this.winGame = true;
        return;
      }
    },
    drawText(){
      let _this = this;
      _this.ctx.clearRect(435 + 60, 0, 100, 70);
      _this.ctx.fillStyle = "#fff";
      _this.ctx.font="20px Arial";
      _this.ctx.fillText('本輪:' + _this.chessText, 435 + 70,  35);
    },
    drawResult(){
      let _this = this;
      _this.ctx.fillStyle = "#ff2424";
      _this.ctx.font="20px Arial";
      _this.ctx.fillText(_this.chessText+'勝!', 435 + 70,  70);
    },
    handleClick(event) {
      let x = event.offsetX - 70;
      let y = event.offsetY - 70;
      if (x < 15 || x > 435 || y < 15 || y > 435) {
        // 點出界的
        return;
      }
      this.drawChess(x, y);
      if(this.winGame){
        this.drawResult();
        return;
      }
      this.whiteTurn = !this.whiteTurn;
      this.drawText();
    }
  }
};
</script>
 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.gobang {
  #gobang {
    background: #2a4546;
  }
}
</style>

總結(jié)

到此這篇關于VUE+Canvas實現(xiàn)簡單五子棋游戲的文章就介紹到這了,更多相關VUE+Canvas五子棋游戲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Vue路由跳轉(zhuǎn)方式區(qū)別匯總(push,replace,go)

    Vue路由跳轉(zhuǎn)方式區(qū)別匯總(push,replace,go)

    vue項目中點擊router-link標簽鏈接都屬于聲明式導航。vue項目中編程式導航有this.$router.push(),this.$router.replace(),this.$router.go()???????。這篇文章主要介紹了Vue路由跳轉(zhuǎn)方式區(qū)別匯總(push,replace,go)
    2022-12-12
  • vue2.0實現(xiàn)選項卡導航效果

    vue2.0實現(xiàn)選項卡導航效果

    這篇文章主要為大家詳細介紹了vue2.0實現(xiàn)選項卡導航效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • vue實現(xiàn)在進行增刪改操作后刷新頁面

    vue實現(xiàn)在進行增刪改操作后刷新頁面

    這篇文章主要介紹了vue實現(xiàn)在進行增刪改操作后刷新頁面,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • vue antd Form表單的使用及說明

    vue antd Form表單的使用及說明

    這篇文章主要介紹了vue antd Form表單的使用及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • vue+el-upload實現(xiàn)多文件動態(tài)上傳

    vue+el-upload實現(xiàn)多文件動態(tài)上傳

    這篇文章主要為大家詳細介紹了vue+el-upload實現(xiàn)多文件動態(tài)上傳,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Vue前端后端的交互方式?axios

    Vue前端后端的交互方式?axios

    這篇文章主要介紹了Vue前端后端的交互方式?axios,axios?為第三方數(shù)據(jù)請求庫,下文具體的內(nèi)容介紹需要的小伙伴可以參考一下,希望對你的學習有所幫助
    2022-04-04
  • vue3?中v-model語法糖示例詳解

    vue3?中v-model語法糖示例詳解

    vue3中的v-model相當于vue2中的v-model和v-bind.sync 修飾符組合在一起的產(chǎn)物(擇優(yōu)整合)v-bind.sync 在 vue3 中被移除了可以在組件標簽上使用多個 v-model 綁定屬性,使用參數(shù)區(qū)分,這篇文章主要介紹了vue3?中v-model語法糖,需要的朋友可以參考下
    2024-06-06
  • 一文弄懂Vite 配置文件

    一文弄懂Vite 配置文件

    Vite?構(gòu)建環(huán)境分為開發(fā)環(huán)境和生產(chǎn)環(huán)境,不同環(huán)境會有不同的構(gòu)建策略,本文就來介紹下Vite 配置文件,具有一定的參考價值,感興趣的可以了解一下
    2024-08-08
  • element table列表根據(jù)數(shù)據(jù)設置背景色

    element table列表根據(jù)數(shù)據(jù)設置背景色

    在使用elementui中的el-table時,需要將表的背景色和字體顏色設置為新顏色,本文就來介紹一下element table列表根據(jù)數(shù)據(jù)設置背景色,感興趣的可以了解一下
    2023-08-08
  • vue添加axios,并且指定baseurl的方法

    vue添加axios,并且指定baseurl的方法

    今天小編就為大家分享一篇vue添加axios,并且指定baseurl的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09

最新評論