fighting_room.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. const qcloud = require('../../vendor/wafer2-client-sdk/index')
  2. const config = require('../../config')
  3. const util = require('../../utils/util.js')
  4. const app = getApp()
  5. const option = {
  6. CHOICE_DELAY_SHOW: 1500,//选项延时1.5S显示
  7. }
  8. Page({
  9. data: {
  10. roomName: '',//对战房间号
  11. userInfo_me: '', //本人用户信息
  12. userInfo_others: '',//对手用户信息
  13. countdown: 10,//倒计时
  14. question: '',//websocket服务器传过来的问题及答案
  15. hasClick: false,//判断是否已选答案,不能重新选择
  16. localClick: false,//是否本地单击的答案
  17. tunnelIdReplacing: 0,//tunnelIdReplacing存在2种转态:0表示不存在信道替换,1表示信道正在替换中:禁止发送数据
  18. clickIndex: '',//判断用户选择了哪个答案
  19. answerColor: '',//根据选择正确与否给选项添加背景颜色
  20. scoreMyself: 0,//自己的总分
  21. status_users_others: {
  22. openId: '', //对手的openid
  23. userChoose: '',//对手选择了第几项
  24. answerColor: '',//对手是否选择正确
  25. },//对手的答题状态
  26. score_others: 0,//对手的总分
  27. game_over: false, //判断此次PK是否结束
  28. win: 2, //0:表示输,1:表示赢,2:表示平手
  29. sendNumber: 0,//每一轮的答题次数不能超过1次
  30. },
  31. onLoad(options) {
  32. app.appData.fromClickId = options.currentClickId
  33. app.upDateUser_networkFromClickId = require('../../utils/upDateUser_networkFromClickId.js').upDateUser_networkFromClickId
  34. wx.showShareMenu({
  35. withShareTicket: true
  36. })
  37. this.setData({
  38. roomName: options.roomName,
  39. userInfo_me: wx.getStorageSync('user_me'),
  40. userInfo_others: wx.getStorageSync('user_others'),
  41. })
  42. wx.removeStorageSync('user_me')//清理缓存
  43. wx.removeStorageSync('user_others')//清理缓存
  44. this.startAnimate()//定义开始动画
  45. this.fightingReady(options.roomName) //通知服务器我已准备好了
  46. this.exceptionalListener() //监听异常情况,如断线重新连接
  47. },
  48. onShareAppMessage(res) {
  49. const that = this;
  50. return {
  51. title: '谁才是头脑王者?比比看吧!',
  52. path: `/pages/entry/entry?currentClickId=${app.appData.currentClickId}`,
  53. success(res) {
  54. //转发时向用户关系表中更新一条转发记录(个人为person,群为GId)。
  55. require('../../utils/upDateShareInfoToUser_network.js').upDateShareInfoToUser_network(app, that, res)
  56. wx.redirectTo({
  57. url: '../entry/entry'
  58. })
  59. }
  60. }
  61. },
  62. fightingReady(roomName) { //通知服务器我已准备好了
  63. const that = this
  64. const tunnel = this.tunnel = app.tunnel
  65. //tunnel.emit('has_ready', { roomName })//通知服务器,已经准备好可以答题了
  66. //监听后台是否收到前端发送的选项
  67. tunnel.on('getAnswer', (res) => {
  68. that.setData({//答题后将hasClick设置为true,防止重新选择答案
  69. hasClick: true
  70. })
  71. })
  72. //监听是否在重连,若是,则禁止发送数据到后台
  73. app.tunnelReconnectingCallback = () => {
  74. that.setData({
  75. tunnelIdReplacing: 1,//tunnelIdReplacing存在2种转态:0表示不存在信道替换,1表示信道正在替换中
  76. })
  77. }
  78. //监听逃跑者的信息
  79. tunnel.on('runawayNotice', (res) => {
  80. console.log('对手已逃跑')
  81. util.showSuccess(res.message)
  82. that.setData({
  83. game_over: true,
  84. win: 1,
  85. })
  86. app.tunnel.close()
  87. })
  88. //监听服务器端发送过来的问题
  89. let getNextQuestions, timerCountdown, timerReset //定义倒计时定时器,定义重置定时器(注意:只有将timer_countdown定义在最外边才能清除掉上一个定时器)
  90. tunnel.on('sendQuestion', (res) => {
  91. console.log('收到题目', res)
  92. let question = res.question
  93. if (Object.getOwnPropertyNames(question).length) {
  94. question.answer = JSON.parse(question.answer)//将答案转换为js对象
  95. }
  96. //显示对手的答题状态
  97. if (res.choicePlayer1[0] !== that.data.userInfo_me.openId) {
  98. that.setData({
  99. status_users_others: {
  100. openId: res.choicePlayer1[0],
  101. userChoose: res.choicePlayer1[1],
  102. answerColor: res.choicePlayer1[2],
  103. },
  104. score_others: res.choicePlayer1[3],//对手总分单独拎出来,不更新
  105. animate_rightAnswer: 'right',//显示正确答案
  106. })
  107. } else {
  108. that.setData({
  109. status_users_others: {
  110. openId: res.choicePlayer2[0],
  111. userChoose: res.choicePlayer2[1],
  112. answerColor: res.choicePlayer2[2],
  113. },
  114. score_others: res.choicePlayer2[3],//对手总分单独拎出来,不更新
  115. animate_rightAnswer: 'right',//显示正确答案
  116. })
  117. }
  118. clearTimeout(getNextQuestions)
  119. if (Object.getOwnPropertyNames(question).length) {
  120. getNextQuestions = setTimeout(function () { //先等待2s查看对方的选择状态,再开始下一题
  121. reset(that)//运行重置函数
  122. }, 2000)
  123. } else { //当question中无问题时,即回答完所有问题
  124. getNextQuestions = setTimeout(function () { //答完题显示战果
  125. if (that.data.scoreMyself > that.data.score_others) {
  126. that.setData({
  127. game_over: true,
  128. win: 1,
  129. })
  130. } else if (that.data.scoreMyself < that.data.score_others) {
  131. that.setData({
  132. game_over: true,
  133. win: 0,
  134. })
  135. }
  136. else {
  137. that.setData({
  138. game_over: true
  139. })
  140. }
  141. //将当前用户的比赛结果发送给服务器
  142. tunnel.emit('fightingResult', {
  143. openId: that.data.userInfo_me.openId,
  144. fightingResult: that.data.win
  145. })
  146. }, 2000)
  147. }
  148. function reset(that) {//定义重置函数
  149. //获取新题目后,倒计时归为10,将clickIndex清空,hasClick改为未选择.
  150. that.setData({
  151. question,//更新题目
  152. animate_showChoice: '',
  153. countdown: 10,
  154. localClick: false,
  155. hasClick: false,
  156. clickIndex: '',
  157. answerColor: '',
  158. //scoreMyself: 0,
  159. status_users_others: {
  160. openId: '',
  161. userChoose: '',
  162. answerColor: '',
  163. //scoreMyself: 0,
  164. },
  165. sendNumber: 0,
  166. animate_rightAnswer: '',
  167. })
  168. //(重新)开始倒计时
  169. clearInterval(timerCountdown)//获取新题目后,倒计时定时器清空(注意:只有将timer_countdown定义在最外边才能清除掉上一个定时器)
  170. let countdown = that.data.countdown;
  171. setTimeout(() => {//2S后显示选项和开始倒计时
  172. that.setData({ animate_showChoice: 'fadeIn' })
  173. timerCountdown = setInterval(function () {
  174. countdown--
  175. that.setData({
  176. countdown
  177. })
  178. if (countdown == 0) {
  179. clearInterval(timerCountdown)
  180. }
  181. }, 1000)
  182. }, option.CHOICE_DELAY_SHOW)
  183. //(重新)设置定时器,若用户未选择答案,10s后也将用户结果发给服务器
  184. clearTimeout(timerReset);
  185. timerReset = setTimeout(() => {
  186. if (!that.data.localClick && !that.data.hasClick) {
  187. that.sendAnswer(that)
  188. }
  189. }, 11000)
  190. }
  191. })
  192. },
  193. answer(e) {//开始答题
  194. const that = this
  195. if (!that.data.localClick) { //防止重新选择答案
  196. if (e.currentTarget.dataset.right) {//判断答案是否正确
  197. that.setData({
  198. clickIndex: e.currentTarget.dataset.index,
  199. answerColor: 'right'
  200. })
  201. //答对了则加分,时间越少加分越多,总分累加
  202. that.setData({
  203. scoreMyself: that.data.scoreMyself + that.data.countdown * 10
  204. })
  205. } else {
  206. that.setData({
  207. clickIndex: e.currentTarget.dataset.index,
  208. answerColor: 'error'
  209. })
  210. }
  211. that.setData({
  212. localClick: true//本地已经点击,若hasClick仍未false,则说明没有发送数据出去
  213. })
  214. that.sendAnswer(that)
  215. }
  216. },
  217. //ping-pong机制,监听前端是否与服务端保持长连接,防止答题期间的卡死问题
  218. sendAnswer(that) {//若存在信道替换,且信道替换还未完成,则不发送数据到后台,但是本地还是算点击一次,
  219. if (that.data.sendNumber > 0) {
  220. return
  221. }
  222. if (that.data.tunnelIdReplacing == 1 || !(app.appData.tunnelStatus == 'connect' || app.appData.tunnelStatus == 'reconnect')) {//当信道正在替换中时,禁止发送数据
  223. return
  224. }
  225. that.tunnel.emit('answer', { //将选项、是否正确、总分3项发送给服务器,若双方都已发送,服务器直接返回下一题
  226. roomName: that.data.roomName,
  227. choice: {
  228. openId: that.data.userInfo_me.openId,
  229. userChoose: that.data.clickIndex,
  230. answerColor: that.data.answerColor,
  231. scoreMyself: that.data.scoreMyself,
  232. }
  233. })
  234. let sendNumber = that.data.sendNumber + 1//BUG:保证每一轮发送次数不能大于1,至于为什么会大于1,暂时不清楚原因
  235. that.setData({
  236. sendNumber,
  237. })
  238. },
  239. //异常处理:重新连接、网络错误
  240. exceptionalListener() {
  241. const that = this
  242. const tunnel = this.tunnel = app.tunnel
  243. //重新连接后,信道id会改变,通知服务器信道id已改变,待接收到服务器端信道ID已替换的通知后再将选项发送给服务器
  244. app.tunnelReconnectCallback = () => {
  245. //信道id完成替换后,将本地的userInfo_me中的tunnel_id进行更新
  246. tunnel.on('tunnelIdReplaced', (res) => {//监听信道替换成功
  247. let userInfo_me = that.data.userInfo_me
  248. userInfo_me.tunnel_id = res.newTunnelId
  249. that.setData({//更新当前用户的信道idh和信道替换状态
  250. userInfo_me,
  251. tunnelIdReplacing: 0
  252. })
  253. if (that.data.localClick && !that.data.hasClick) {//如果本地已点击过,并且还没发送成功,则向服务器再次发送数据
  254. that.sendAnswer(that)
  255. }
  256. })
  257. }
  258. },
  259. continue_fighting() {
  260. wx.reLaunch({
  261. url: '../entry/entry',
  262. })
  263. },
  264. startAnimate() {
  265. const that = this
  266. that.setData({
  267. zoomIn: 'zoomIn'
  268. })
  269. setTimeout(function () {
  270. that.setData({
  271. zoomOut: 'zoomOut'
  272. })
  273. }, 1500)
  274. }
  275. })