Browse Source

game start,dismiss,ready,blind

master
tangmingyou 4 years ago
parent
commit
930f72d64a
  1. 4
      config/dev.js
  2. 1207
      src/api/proto.js
  3. 12
      src/api/websocket.js
  4. 11
      src/api/wsapi.js
  5. 2
      src/components/card.jsx
  6. 15
      src/components/style/title.scss
  7. 13
      src/components/title.jsx
  8. 4
      src/pages/lobby/lobby.jsx
  9. 107
      src/pages/table/table.jsx
  10. 23
      src/pages/table/table.scss
  11. 16
      src/store/user.js

4
config/dev.js

@ -10,8 +10,8 @@ module.exports = {
h5: { h5: {
devServer: { devServer: {
//host: '0.0.0.0', //host: '0.0.0.0',
//host: '192.168.110.53', host: '192.168.110.53',
host: '192.168.3.102', //host: '192.168.3.102',
port: 10086, port: 10086,
// 设置代理来解决 H5 请求的跨域问题 // 设置代理来解决 H5 请求的跨域问题
proxy: { proxy: {

1207
src/api/proto.js

File diff suppressed because it is too large Load Diff

12
src/api/websocket.js

@ -1,7 +1,10 @@
import store from '@/store/index'
import proto from '@/api/proto'; import proto from '@/api/proto';
import { fetchOpMap } from '@/api/api' import { fetchOpMap } from '@/api/api'
import { getStorage } from '@/utils/storage'; import { getStorage, removeStorage } from '@/utils/storage';
import { showToast } from '@/utils/application'; import { showToast } from '@/utils/application';
import { setUserInfo } from '@/store/user'
const { api } = proto const { api } = proto
@ -26,7 +29,6 @@ const websocket = {
this.opPathMap = opPathMap || {}; this.opPathMap = opPathMap || {};
this.nameOpMap = nameOpMap || {}; this.nameOpMap = nameOpMap || {};
// window.proto = proto; // window.proto = proto;
// websocket test
const ws = new WebSocket("ws://localhost:9999/api/conn/ws") const ws = new WebSocket("ws://localhost:9999/api/conn/ws")
this.conn = ws this.conn = ws
@ -39,6 +41,11 @@ const websocket = {
// const reqBuffer = api.ReqIdentity.encode(req).finish() // const reqBuffer = api.ReqIdentity.encode(req).finish()
this.send(req, res => { this.send(req, res => {
this.status = 2; this.status = 2;
// const dispatch = useDispatch();
// window.res = res;
// console.log(store, setUserInfo(res))
store.dispatch(setUserInfo(res.toJSON()));
console.log('identity success:', res) console.log('identity success:', res)
// 依次发送等待连接的消息队列 // 依次发送等待连接的消息队列
@ -49,6 +56,7 @@ const websocket = {
} }
} }
}, err => { }, err => {
removeStorage('_t')
showToast({title: err}) showToast({title: err})
console.error('连接认证失败:', err) console.error('连接认证失败:', err)
}) })

11
src/api/wsapi.js

@ -11,3 +11,14 @@ export const reqGameFullStatus = () => sendPromise(api.ReqGameFullStatus.create(
export const reqJoinTable = tableNo => sendPromise(api.ReqJoinTable.create({tableNo})); export const reqJoinTable = tableNo => sendPromise(api.ReqJoinTable.create({tableNo}));
export const reqKickOutTable = playerId => sendPromise(api.ReqKickOutTable.create({playerId})); export const reqKickOutTable = playerId => sendPromise(api.ReqKickOutTable.create({playerId}));
export const reqLeaveTable = () => sendPromise(api.ReqLeaveTable.create());
// 准备
export const reqReadyStart = () => sendPromise(api.ReqReadyStart.create());
// 取消准备
export const reqCancelReady = () => sendPromise(api.ReqCancelReady.create());
// 解散
export const reqDismissGameTable = () => sendPromise(api.ReqDismissGameTable.create());
// 开始牌局
export const reqGameStart = () => sendPromise(api.ReqGameStart.create());

2
src/components/card.jsx

@ -40,7 +40,7 @@ function Card(props) {
left: Taro.pxTransform(w / 8), left: Taro.pxTransform(w / 8),
}}> }}>
<Text style={{ <Text style={{
color: suit % 2 === 0?'#FF4A0E':'#000', fontSize: Taro.pxTransform(w / 3) color: suit==='D' || suit==='H'?'#FF4A0E':'#000', fontSize: Taro.pxTransform(w / 3)
}}>{dots[dot || 0]}</Text> }}>{dots[dot || 0]}</Text>
</View> </View>
<View className="suit-wrap"> <View className="suit-wrap">

15
src/components/style/title.scss

@ -30,16 +30,23 @@
color: #ffffff; color: #ffffff;
} }
.title-avatar-wrap {
width: 48px;
height: 48px;
display: flex;
flex-direction: row;
}
.avatar { .avatar {
width: 41px; width: 41px;
height: 41px; height: 41px;
// width: 32px;
// height: 32px;
border-radius: 50%; border-radius: 50%;
margin-top: 2px; margin-top: 2px;
} }
.username {
.blank { font-size: 12px;
width: 48px; font-weight: normal;
height: 48px;
} }
} }
} }

13
src/components/title.jsx

@ -7,7 +7,7 @@ import './style/title.scss'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
function Title(props) { function Title(props) {
const {username, nickname, avatar} = useSelector(state => state.user); const {username, nickname, avatar, defaultAvatar} = useSelector(state => state.user);
const { leftSolt, leftIcon, onLeftClick, rightSolt } = props; const { leftSolt, leftIcon, onLeftClick, rightSolt } = props;
return ( return (
<View> <View>
@ -15,8 +15,15 @@ function Title(props) {
{/* <View className='topHeight'></View> */} {/* <View className='topHeight'></View> */}
<View className='page-title'> <View className='page-title'>
{leftSolt || <Image className="icon" src={leftIcon || left} onClick={onLeftClick || navigateBack} />} {leftSolt || <Image className="icon" src={leftIcon || left} onClick={onLeftClick || navigateBack} />}
<View className={props.colorStyle ? "title" : "title1"}><Text>{props.title}</Text></View> <View className={props.colorStyle ? "title" : "title1"}>
{rightSolt || <View className='blank'><Image className='avatar' src={avatar} /></View>} <View><Text className="username">{username}</Text></View>
<View><Text>{props.title}</Text></View>
</View>
{
rightSolt || <View className='title-avatar-wrap'>
<Image className='avatar' src={avatar || defaultAvatar} />
</View>
}
</View> </View>
</View> </View>
{props.topNull ? '' : <View className='hidden'></View>} {props.topNull ? '' : <View className='hidden'></View>}

4
src/pages/lobby/lobby.jsx

@ -33,9 +33,9 @@ class Lobby extends Component {
} }
componentDidMount() { componentDidMount() {
setTimeout(() => { // setTimeout(() => {
this.handleReqLobbyView(); this.handleReqLobbyView();
}, 1500) // }, 1500)
// fetchLobbyView() // fetchLobbyView()
// .then(res => { // .then(res => {
// console.log('lobby', res) // console.log('lobby', res)

107
src/pages/table/table.jsx

@ -3,7 +3,11 @@ import { View, Text, Image, Input, Button } from '@tarojs/components'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import cnames from 'classnames' import cnames from 'classnames'
import { reqGameFullStatus, reqKickOutTable } from '@/api/wsapi' import {
reqGameFullStatus, reqKickOutTable, reqLeaveTable,
reqReadyStart, reqDismissGameTable, reqGameStart,
reqCancelReady
} from '@/api/wsapi'
import { addMsgListen, removeMsgListener } from '@/api/websocket' import { addMsgListen, removeMsgListener } from '@/api/websocket'
import { ifEmpty } from '@/utils/validator' import { ifEmpty } from '@/utils/validator'
@ -20,10 +24,11 @@ import Taro from '@tarojs/taro'
import { showToast, redirectTo } from '@/utils/application' import { showToast, redirectTo } from '@/utils/application'
import { isIn } from '@/utils/collect' import { isIn } from '@/utils/collect'
function PlayerStatus() { function PlayerStatus(props) {
const { text, color } = props;
return ( return (
<View> <View className="p-status">
<Text>Ready</Text> <Text>{text}</Text>
</View> </View>
) )
} }
@ -62,20 +67,24 @@ class Table extends Component {
componentWillUnmount() { componentWillUnmount() {
// //
removeMsgListener('api.ResGameFullStatus') removeMsgListener('api.ResGameFullStatus');
removeMsgListener('api.ResKickOutTable') removeMsgListener('api.ResKickOutTable');
} }
componentDidMount() { componentDidMount() {
// setTimeout(() => { // setTimeout(() => {
// //
addMsgListen('api.ResGameFullStatus', res => this.handleResGameFullStatus(res)); addMsgListen('api.ResGameFullStatus', this.handleResGameFullStatus); //
//
addMsgListen('api.ResKickOutTable', res => { addMsgListen('api.ResKickOutTable', res => {
console.log('listener level table', res); showToast({title: '您被请出牌桌'});
redirectTo({url: '/pages/lobby/lobby', complete() { setTimeout(() => redirectTo({url: '/pages/lobby/lobby'}), 800);
showToast({title: '您被请出牌桌'})
}});
}); });
//
addMsgListen('api.ResDismissGameTable', res => {
showToast({title: '牌桌已解散'});
setTimeout(() => redirectTo({url: '/pages/lobby/lobby'}), 800);
})
// //
reqGameFullStatus() reqGameFullStatus()
@ -92,7 +101,6 @@ class Table extends Component {
} }
handleResGameFullStatus = res => { handleResGameFullStatus = res => {
console.log('res game...++', this, res)
this.setState({ this.setState({
playerId: res.playerId, playerId: res.playerId,
inGame: !!res.inGame, inGame: !!res.inGame,
@ -126,11 +134,65 @@ class Table extends Component {
showToast({title: err}) showToast({title: err})
}) })
} }
});
}
// 退
handleLeaveTable() {
Taro.showModal({
title: '提示',
content: "是否离开牌桌?",
success: res => {
if (!res.confirm) {
return;
}
reqLeaveTable()
.then(_ => {
redirectTo({url: '/pages/lobby/lobby'})
})
.catch(err => showToast({title: err}))
}
})
}
//
handleReadyStart(playerStatus) {
(playerStatus === 1 ? reqReadyStart() : reqCancelReady())
.then(res => {
console.log('ready res:', res);
})
.catch(err => showToast({title: err}));
}
//
handleResDismissGameTable() {
Taro.showModal({
title: '提示',
content: "是否解散牌桌?",
success: res => {
if (!res.confirm) {
return;
}
reqDismissGameTable()
.then(_ => {
redirectTo({url: '/pages/lobby/lobby'})
})
.catch(err => showToast({title: err}));
}
}) })
} }
//
handleGameStart() {
reqGameStart()
.then(res => {
console.log('game start...', res)
})
.catch(err => showToast({title: err}));
}
render() { render() {
const { username, nickname, avatar } = this.props.user; // useSelector(state => state.user); const { username, nickname, avatar, defaultAvatar } = this.props.user; // useSelector(state => state.user);
// const players = [1, 2, 3, 4, 5, 6]; // const players = [1, 2, 3, 4, 5, 6];
const players = this.state.players.map((player, index) => ({player, index})); const players = this.state.players.map((player, index) => ({player, index}));
const {playerId, tableNo, stage, chip, roundTimes} = this.state; const {playerId, tableNo, stage, chip, roundTimes} = this.state;
@ -160,13 +222,10 @@ class Table extends Component {
row.map(({index, player}, j) => ( row.map(({index, player}, j) => (
<View key={j} className="player-wrap" onClick={(p => {console.log(p)}).bind(this, player)}> <View key={j} className="player-wrap" onClick={(p => {console.log(p)}).bind(this, player)}>
{ {
j % 2 === 0 && player.status === 2 && <View className="p-status-ready"><Text>Ready!</Text></View>
<View className={cnames('player-state-wrap', {'state-left': j % 2 === 0})}>
<PlayerStatus action={1} />
</View>
} }
<View className="player-bar"> <View className="player-bar">
<View className={cnames("player-no", { "player-no-running": player.index === 0 })}><Text>#{index}</Text></View> <View className={cnames("player-no", { "player-no-running": player.status > 1})}><Text>#{index}</Text></View>
{ {
stage === 1 && selfPlayer.master && player.id stage === 1 && selfPlayer.master && player.id
? <View className="kickout" onClick={this.handleKickoutPlayer.bind(this, player)}><Image className="kickout-icon" src={closeIcon} /></View> ? <View className="kickout" onClick={this.handleKickoutPlayer.bind(this, player)}><Image className="kickout-icon" src={closeIcon} /></View>
@ -233,14 +292,14 @@ class Table extends Component {
<View className="hand-five"> <View className="hand-five">
{ {
existsCard(selfPlayer.handCard[0]) && [1, 2, 3, 4, 5].map((_, i) => ( existsCard(selfPlayer.handCard[0]) && [1, 2, 3, 4, 5].map((_, i) => (
<View key={i} className="hand-five-item"><Card w={28} h={36} dot={12} suit={2} /></View> <View key={i} className="hand-five-item"><Card w={28} h={36} dot={12} suit={'H'} /></View>
)) ))
} }
</View> </View>
<View className='u-opt' style={{ display: 'flex' }}> <View className='u-opt' style={{ display: 'flex' }}>
<View> <View>
<View className="s-info-wrap"> <View className="s-info-wrap">
<View className="s-avatar"><Image className="s-avatar-img" src={selfPlayer.avatar || avatar} /></View> <View className="s-avatar"><Image className="s-avatar-img" src={selfPlayer.avatar || avatar || defaultAvatar} /></View>
<View className="s-username"><Text>{selfPlayer.username}</Text></View> <View className="s-username"><Text>{selfPlayer.username}</Text></View>
</View> </View>
<View className="s-wallet-wrap"> <View className="s-wallet-wrap">
@ -261,13 +320,13 @@ class Table extends Component {
stage === 1 ? ( stage === 1 ? (
// : , // : ,
selfPlayer.master ? <View className="ctl-opt-wrap"> selfPlayer.master ? <View className="ctl-opt-wrap">
<View className="ctl-opt"><Button className={cnames("ctl-opt-btn-4", {'ctl-opt-btn-disable': selfPlayer.status === 2})}>关闭牌桌</Button></View> <View className="ctl-opt"><Button onClick={this.handleResDismissGameTable.bind(this)} className={cnames("ctl-opt-btn-4", {'ctl-opt-btn-disable': selfPlayer.status === 2})}>关闭牌桌</Button></View>
<View className="ctl-opt"><Button className={cnames("ctl-opt-btn-6", {'ctl-opt-btn-disable': selfPlayer.status === 2})}>开始游戏</Button></View> <View className="ctl-opt"><Button onClick={this.handleGameStart.bind(this)} className={cnames("ctl-opt-btn-6", {'ctl-opt-btn-disable': selfPlayer.status === 2})}>开始游戏</Button></View>
</View> </View>
// 退, // 退,
: <View className="ctl-opt-wrap"> : <View className="ctl-opt-wrap">
<View className="ctl-opt"><Button style={{display: selfPlayer.status === 2 ? 'none' : 'block'}} className={cnames("ctl-opt-btn-4", {'ctl-opt-btn-disable': selfPlayer.status === 2})}>退出</Button></View> <View className="ctl-opt"><Button onClick={this.handleLeaveTable.bind(this)} style={{display: selfPlayer.status === 2 ? 'none' : 'block'}} className={cnames("ctl-opt-btn-4", {'ctl-opt-btn-disable': selfPlayer.status === 2})}>退出</Button></View>
<View className="ctl-opt"><Button className={cnames("ctl-opt-btn-5", {'ctl-opt-btn-5-ready': selfPlayer.status === 2})}>{selfPlayer.status === 2 ? '已准备' : '准备'}</Button></View> <View className="ctl-opt"><Button onClick={this.handleReadyStart.bind(this, selfPlayer.status)} className={cnames("ctl-opt-btn-5", {'ctl-opt-btn-5-ready': selfPlayer.status === 2})}>{selfPlayer.status === 2 ? '已准备' : '准备'}</Button></View>
</View> </View>
) )
: <View className="ctl-opt-wrap"> : <View className="ctl-opt-wrap">

23
src/pages/table/table.scss

@ -14,25 +14,14 @@
display: flex; display: flex;
} }
.player-state-wrap { .p-status-ready {
height: 53px;
width: 39px;
// background-color: #F1D09F;
position: absolute; position: absolute;
left: -40px; top: -25px;
top: 10px; left: 30px;
display: flex; color: #EE914E;
flex-direction: column; font-weight: bold;
justify-content: center; font-size: 12px;
align-items: center;
}
.state-left {
position: absolute;
left: 157px;
top: 10px;
} }
.player-no { .player-no {
position: absolute; position: absolute;
top: -25px; top: -25px;

16
src/store/user.js

@ -3,13 +3,19 @@ import { createSlice } from '@reduxjs/toolkit';
const userSlice = createSlice({ const userSlice = createSlice({
name: 'user', name: 'user',
initialState: { initialState: {
username: 'Prometheus', id: 0,
nickname: 'PrometheusNick', username: 'Prom',
avatar: 'https://img0.baidu.com/it/u=2477829979,2171947490&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500', nickname: 'PromNick',
avatar: '',
defaultAvatar: 'https://img0.baidu.com/it/u=2477829979,2171947490&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
}, },
reducers: { reducers: {
setUserInfo(state, action) { setUserInfo: (state, {payload}) => {
return {...state, ...action.payload} console.log('setUserInfo', state, payload)
state.id = payload.id;
state.username = payload.username;
state.avatar = payload.avatar;
// return {...state, ...action.payload}
} }
} }
}) })

Loading…
Cancel
Save