iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 24
1
Modern Web

關於你關於我關於phaser系列 第 24

Day 24 連線五子棋 ~ 關於實作

今天來實作我如何將 server 與 client 結合,可以連線對弈並且判斷輸贏(良好的 UX/UI 與流程並沒有做)

首先先架起 server 並讓 client 可以連到且 server 也監聽得到
server 先 npm install socket.io express -S
client 引入 socket 的 CDN:

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>

並在 server 開一個 port 讓 client 去聽
而 server 在有使用者連上時 console 一個訊息代表有人連上並且 server 也有監聽到

//server index.js
var app = require('express')()
var http = require('http').Server(app)
var io = require('socket.io')(http)


http.listen(3000, function() {
  console.log('listen on port : 3000')
})

io.on('connection',function(socket)){
    console.log('user connetion')
}

// client main.js
function create(){
    socket = io('http://localhost:3000/');
}

再來就要將一些原本寫在 client 的東西放在 server , client 負責的東西很簡單,就是送出點了那個點,再來就是將接收到 server 的訊息渲染到畫面

我們這邊分幾個步驟:

  1. 判斷有兩個使用者
  2. 可以輪流下棋且下棋對方看得到
  3. 可以判斷勝利

先判斷兩個使用者,我用一個 playId 去裝 client 連進來的 id,並判斷有兩個人就開始遊戲;而開始方式就是讓第一個使用者有下棋的權力

所以我們透過 socket.id 去判斷使用者,用 socket.broadcast.to(playId[player]).emit 去對某個 client 發出可以下棋的訊息,所以 client 接到就會有滑鼠監聽事件,就可以下棋

// server index.js
var playId
io.on('connection', function(socket) {
    playId.push(socket.id)
    if (playId.length === 2) {
        checkerboard = createCheckerboard()
        socket.broadcast.to(playId[player]).emit('changeYou', true);
      }
}

//client main.js
function create(){
    socket.on('changeYou', yourRound => {
    if (yourRound) {
      self.input.on('pointerdown', putChess)
    }
}

而下棋就是將要下的位置傳給 server ,判斷可以下就回傳給所有的 client ,而這邊 server判端兩件事情,回傳回來的 client 與允許可以下棋的 client 是否一樣,再來是棋盤的位置是否是空的,都成立就會回傳給 client 下棋,並且改變狀態換人下棋

ps:這邊記得將在 client 建立的棋盤放在 server

//client main.js
function putChess(pointer) {
  //送訊息給scoket
  let i = Math.floor(pointer.y / 30)
  let j = Math.floor(pointer.x / 30)
  socket.emit('putChess', i, j)
}
//server index.js
io.on('connection', function(socket) {
    //...
    socket.on('putChess', (i, j) => {
        if (playId[player] === socket.id) {
          if (checkerboard[i][j] === 0) {
              io.emit('drawChess', i, j)
              checkerboard[i][j] = chess
              player = player === 0 ? 1 : 0
              chess = chess === 'o' ? 'x' : 'o'
              socket.broadcast.to(playId[player]).emit('changeYou', true);
            }
        }
    })
})
//client main.js
function create(){
    socket.on('drawChess', function(i, j) {
        updateCheckerboard(i, j)
    })
}

最後將原先寫在 client 的勝利判斷放在 server ,如果沒有人獲勝才轉換下棋的人,不然就回傳一個停止渲染並誰勝利的訊息給 client

//server index.js
io.on('connection', function(socket) {
    //...
    socket.on('putChess', (i, j) => {
        if (playId[player] === socket.id) {
          if (checkerboard[i][j] === 0) {
            console.log(socket.id, i, j)
            io.emit('drawChess', i, j)
            checkerboard[i][j] = chess
            if (isWin(i, j)) {
              io.emit('winner', chess)
              console.log(chess + " is winner")
              player = 0
              chess = 'o'
            } else {
              player = player === 0 ? 1 : 0
              chess = chess === 'o' ? 'x' : 'o'
              socket.broadcast.to(playId[player]).emit('changeYou', true);
            }
          }
        }
      })
})

function isWin(i, j) {
  return horizontalWin(i, j) || straightWin(i, j) || rightOblique(i, j) || leftOblique(i, j)
}

// 從 client 搬來的判斷式...
// client main.js
function create(){
    //..
    socket.on('winner', function(player) {
    if (player === 'o') {
      gameStatusText.setText("黑子獲勝")
      console.log('黑子獲勝')
    }
    if (player === 'x') {
      gameStatusText.setText("白子獲勝")
      console.log('白子獲勝')
    }
    self.scene.pause(); 
    }
}

如果到這邊都沒問題,就可以自己開 server 並開兩個視窗自己下棋了,並且一個視窗可以看到另一個視窗下的位置,且 server 也可以看到 client 傳來的訊息

如果有什麼問題可以去我的 github,或是留言討論的,而明天則會說一下我在實作過程中遇到的問題與我本來希望優化的地方(後來當然沒做啦)


上一篇
Day 23 連線五子棋 ~ 關於 server
下一篇
Day 25 連線五子棋 ~ 關於遇到的問題與可以優化的地方
系列文
關於你關於我關於phaser30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言