今天我們來讓我們的遊戲畫面可以接上遊戲伺服器吧!
我們大概就是把cst、cmd這兩個指令的代號搬過來,讓我們跟伺服器可以共用相同代號。
我們還新增了$io.ts這一用來管我們的socketio。
└─src
│ App.ts
│ cmd.ts
│ cst.ts
│ Game.ts
├─components
│ ├─elements
│ │ Animation.ts
│ │ Sprite.ts
│ │ Texture.ts
│ │ Wrapper.ts
│ │ WrapperContainer.ts
│ │ WrapperContainerCenter.ts
│ │ WrapperType.ts
│ ├─groups
│ │ Body.ts
│ │ Casino.ts
│ │ ChipBox.ts
│ │ Loading.ts
│ │ Navbottom.ts
│ │ Navtop.ts
│ │ Pokers.ts
│ │ Table.ts
│ └─objects
│ AreaBetNumber.ts
│ Bg.ts
│ Chip.ts
│ Countdown.ts
│ CountdownNumber.ts
│ Dealer.ts
│ Desk.ts
│ DeskHover.ts
│ Info.ts
│ InfoMoneyNumber.ts
│ Poker.ts
│ PokerPoint.ts
│ PokerResult.ts
│ PokerWin.ts
│ TotalBetNumber.ts
│ WaitNextBetNotify.ts
├─config
│ chipType.ts
│ imagePath.ts
│ loadingPath.ts
│ pokerPoint.ts
│ pokerType.ts
├─loaders
│ Loader.ts
├─services
│ $io.ts
├─store
│ actions.ts
│ index.ts
│ reducer.ts
│ redux.ts
│ store.ts
└─utils
tools.ts
首先大致說明一下我們的$io.ts架構,因為是模擬http的req、res,所以必須要有timeout防止指令超時,另外直接把一些請求方法封裝在這,比較好可以直接使用,不然組件內會一堆emit、on,而目前token暫時直接使用id,之後正式版本會採用jwt的token,就會很安全了!
$io.ts
import io from 'socket.io-client'
import cmd from '@/cmd'
let $io = function () {
let $io: any
let token: string
let timeout: number = 5000
return {
initalSocket: function (url: any) {
token = localStorage.getItem('user') || '1'
$io = io(url, {
query: {
token: token
}
})
},
on: function (cmd: string, listener: Function) {
$io.on(cmd, listener)
},
emit: function (cmd: string) {
let args = [].slice.call(arguments, 1)
$io.emit(cmd, ...args)
},
REQ_USER_INFO: function (data?: any) {
return new Promise((resolve, reject) => {
let _timeout = setTimeout(reject, timeout);
$io.emit(cmd.REQ_USER_INFO, data)
$io.on(cmd.RES_USER_INFO, (data: any) => {
resolve(data.result)
clearTimeout(_timeout)
})
})
},
REQ_USER_LOGIN: function (data?: any) {
return new Promise((resolve, reject) => {
let _timeout = setTimeout(reject, timeout);
$io.emit(cmd.REQ_USER_LOGIN, data)
$io.on(cmd.RES_USER_LOGIN, (data: any) => {
resolve(data.result)
clearTimeout(_timeout)
})
})
},
REQ_USER_TB_SITDOWN: function (data?: any) {
return new Promise((resolve, reject) => {
let _timeout = setTimeout(reject, timeout);
$io.emit(cmd.REQ_USER_TB_SITDOWN, { tbid: '1' })
$io.on(cmd.RES_USER_TB_SITDOWN, (data: any) => {
resolve(data.result)
clearTimeout(_timeout)
})
})
}
}
}()
export default $io
這是Game.ts,一開始進入的地方,也是有loading頁面的地方,在這邊我們會先做基本的請求資料還有與伺服器說我們登入了,另外還有坐下這功能,代表我們不只登入了,還選了一張桌子坐下了!不過都是桌號1,因為我們目前只有一桌,但預留可以多開多桌的功能。
Game.ts
import Loader from '@/loaders/Loader'
import imagePath from '@/config/imagePath'
import Wrapper from '@/components/elements/Wrapper'
import WrapperContainer from '@/components/elements/WrapperContainer'
import loadingPath from '@/config/loadingPath'
import Casino from '@/components/groups/Casino'
import Loading from '@/components/groups/Loading'
import $io from '@/services/$io'
import { store, actions } from '@/store/index'
export default class Game {
private _app: PIXI.Application
private _game: Wrapper
private _loading: Wrapper
constructor() {
this._app = new PIXI.Application({ width: 1625, height: 900 })
this._game = new WrapperContainer()
this._loading = new WrapperContainer()
this._game.addChild(this._loading)
this._app.stage.addChild(this._game.getContainer())
document.body.appendChild(this._app.view)
$io.initalSocket('http://localhost:3000')
$io.on('connect', () => {
console.log('connect')
})
// 先load載入頁面
this.loadimage(loadingPath)
.then(() => {
// 再load所有圖片
return this.loadimage(imagePath, 0)
})
.then(() => {
return this.loadInfo()
}).then(() => {
return this.initalInfo()
}).then(() => {
this.setup()
})
}
private setup(): void {
let casino = new Casino()
this._game.addContainer(casino.getContainer())
}
private loadimage(imagePath: any, delay?: number): Promise<any> {
return new Promise((resolve, reject) => {
try {
let loading = new Loading()
this._loading.addChild(loading)
Loader.load(imagePath)
.on((e: number) => {
loading.update(e * 100)
})
.then(() => {
return loading.done(delay)
})
.then(() => {
this._loading.removeChildren()
resolve()
})
} catch (err) {
reject(err)
}
})
}
private initalInfo() {
return new Promise((resolve, reject) => {
Promise.all([$io.REQ_USER_LOGIN(), $io.REQ_USER_TB_SITDOWN(), $io.REQ_USER_INFO()]).then((res: any) => {
console.log(res[0])
console.log(res[1])
console.log(res[2])
store.dispatch(actions.updateBalance({ balance: res[2].balance }))
resolve()
})
})
}
private loadInfo() {
return new Promise((resolve, reject) => {
let user = localStorage.getItem('user')
resolve()
})
}
}
這只是Table的一部分,我們收到TB就是Table的通知的時候,會找到對應的代號,並且更新要更新的值,像現在有的功能是更新桌的倒數計時。
還有如果超過三局沒有下注,是會被踢出的,因為遊戲如果沒有人在玩的時候(坐下),就會休息,那超過三局是防止有人掛機,害伺服器一直發牌。
Table.ts
constructor() {
super()
// ...以上省略
$io.on(cmd.MSG_TB_NTF, (reason: any, data: any) => {
switch (reason) {
case cst.TB_NTF_COUNTDOWN_START:
console.log('cst.TB_NTF_COUNTDOWN_START')
break
case cst.TB_NTF_COUNTDOWN_STOP:
console.log('cst.TB_NTF_COUNTDOWN_STOP')
break
case cst.TB_NTF_COUNTDOWN_TIME:
this._countdown.updateCountdown(data.countdown)
break
case cst.TB_NTF_FANPI:
console.log('cst.TB_NTF_FANPI')
break
case cst.TB_NTF_PI_RESULT:
console.log('cst.TB_NTF_PI_RESULT')
break
case cst.TB_NTF_STR_JOIN:
console.log('cst.TB_NTF_STR_JOIN')
break
case cst.TB_NTF_STR_BETOUT:
console.log('cst.TB_NTF_STR_BETOUT')
break
case cst.TB_NTF_STR_QUIT:
console.log('cst.TB_NTF_STR_QUIT')
break
case cst.TB_NTF_KICKOUT:
alert('被遊戲踢出!')
console.log('cst.TB_NTF_KICKOUT')
break
}
})
// ...以下省略
}
今天大概就是這樣,沒想到串一下也花了我好多時間,因為伺服器出了點問題,但大致上串一串應該是OK,過兩天應該可以直接部屬在Heroku上給大家玩了!