<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] 開始毫無頭緒,找了幾個專門做游戲的框架,layabox 裝了打開報錯、cocos studio 感覺太復雜,phaser感覺引用資源好復雜。 最后我感覺我這個小游戲沒啥精靈動畫,應該普通h5+js能實現。就拿了目前最熟悉可以雙向綁定的vue來弄。 開發的時候感覺沒效率,不知道游戲場景里放什么,后來干脆用墨刀設計了一個[原型](https://modao.cc/app/kyykUyNnY6dZUCWvfUAykOIfwhpkR2y)。 # UI設計 主要設計了歡迎頁、游戲頁、結束頁 三個場景。 ![歡迎頁](https://box.kancloud.cn/9528337c572e8347c09ad455c6d2d639_773x753.png) ![游戲頁](https://box.kancloud.cn/45c4884e747f274fd4f76c944d67e092_1123x806.png) ![結束頁](https://box.kancloud.cn/1e8ad30804f22b3badbc897c7c183b0e_738x819.png) # Vue的使用 ## Vue 的生命周期 ![生命周期](https://box.kancloud.cn/c7bfd289342941961506e8a3063bf621_1200x3039.png) jquery 以前有個ready 事件(所有元素加載完)。vue上是什么一直沒搞懂。 后來經過我的研究,是*mounted*。 還有加載前的事件 *beforeCreate*。 ## Vue的路由研究 開始想場景相當于spa應用的單頁面。但是一看到那個vue-router 安裝要npm 就煩。感覺別人的實現也就div的顯隱。 后來想html5 不是有個 history api。用于監聽url變化的。 經過實驗,history api 監聽地址改變,動態將當前頁設為錨點對應的方法是可以的。 ~~~ beforeCreate:function(){ var isHistoryApi = !!(window.history && history.pushState); if(!isHistoryApi){ alert('該瀏覽器不支持History,請換一個現代化瀏覽器'); } }, mounted :function(){ const that = this; window.onpopstate = function(event){ // console.log(location); // console.log(event); var next_page = location.hash.substr(1); that.page = next_page; that.message = next_page; } try { if ("WebSocket" in window) { ws = new WebSocket("ws://"+that.host); } else if ("MozWebSocket" in window) { ws = new MozWebSocket("ws://"+that.host); } SocketCreated = true; isUserloggedout = false; ws.onopen = that.wsopen; ws.onmessage = that.wsmsg; ws.onclose = that.wsclose; ws.onerror = that.wserror; if(this.page == 'welcome'){ } } catch (ex) { console.log(ex); alert('該瀏覽器不支持Websocket,請換一個現代化瀏覽器'); return; } } ~~~ 試圖里直接v-if `<section v-if="page == 'gaming'" id="gaming">` 開始用的template 標簽,結果vue 里自定義標簽會報warning。后來就改成section了。 ## Vue的websocket使用 websocket 我用過,問題它怎么于vue 結合起來。后來找了一圈vue 好像有套件。可是安裝又比較麻煩。我就想想辦法把。 最終研究出來的方式是,定義一個ws變量,mounted 時候鏈接一下。 var ws; ~~~ mounted :function(){ const that = this; window.onpopstate = function(event){ // console.log(location); // console.log(event); var next_page = location.hash.substr(1); that.page = next_page; that.message = next_page; } try { if ("WebSocket" in window) { ws = new WebSocket("ws://"+that.host); } else if ("MozWebSocket" in window) { ws = new MozWebSocket("ws://"+that.host); } SocketCreated = true; isUserloggedout = false; ws.onopen = that.wsopen; ws.onmessage = that.wsmsg; ws.onclose = that.wsclose; ws.onerror = that.wserror; if(this.page == 'welcome'){ } } catch (ex) { console.log(ex); alert('該瀏覽器不支持Websocket,請換一個現代化瀏覽器'); return; } } ~~~ 然后這些ws用的方法通通以ws開頭,比如wsopen。 # 整體前端架構 ~~~ wslogin:function(name){ this.wssend({op:'reg_user', nickname:name}); }, wsbegin:function(room_id, uid){ this.wssend({ op:"begin", room_id: room_id, uid:uid }); }, wsopen: function(){ if(this.page == 'gaming' && this.name != ''){ this.wslogin(this.name); } }, wssend: function(msg){ if(ws){ if(typeof msg !== 'string'){ msg = JSON.stringify(msg); } ws.send(msg); }else{ this.wserror(); } }, wsmsg : function(event){ try { console.log(event); var obj = JSON.parse(event.data); console.log(obj); if(obj.code == 0){ alert(obj.msg); } console.log(obj.msg); console.log(obj.data); switch(obj.msg){ case 'after_reg_user': this.uid = obj.data.uid; this.fd = obj.data.fd; localStorage.setItem('uid', this.uid); localStorage.setItem('nickname', obj.data.nickname); if(!this.room_id){ if(localStorage.getItem('room_id') == undefined){ this.wssend({ op: 'create_room', name: 'room'+ new Date().getTime() + Math.random(), hours: 1, uid: this.uid, number: 2 }); }else{ this.room_id = localStorage.getItem('room_id'); } } if(this.fd && this.uid && this.room_id && this.get_new('compete_uid')){ this.start(); } break; case 'after_create_room': this.room_id = obj.data.room_id; localStorage.setItem('room_id', this.room_id); if(!this.get_new('compete_uid') && this.uid && this.room_id){ this.wsbegin(this.room_id, this.uid); } break; case 'after_begin': this.compete_uid = obj.data.compete_uid; localStorage.setItem('compete_uid', this.compete_uid); this.user.name = obj.data.user_name; this.compete_user.name = obj.data.compete_name; this.start(); break; case 'room_user_list': if(this.room_id == obj.data.room_id){ for (var i = 0; i < obj.data.list.length; i++) { var user = obj.data.list[i]; if(user.uid == this.uid){ this.user.stars = user.stars; } if(user.uid == this.compete_uid){ this.compete_user.stars = user.stars; } obj.data.list[i]; } this.count_down_cards = obj.data.count_down_cards; } break; case 'after_enter_room': for (var i = 0; i < obj.data.list.length; i++) { var user = obj.data.list[i]; if(user.uid == this.uid){ this.user.stars = user.stars; } if(user.uid == this.compete_uid){ this.compete_user.stars = user.stars; } obj.data.list[i]; } this.user.name = obj.data.user_name; this.user.石頭 = obj.data.石頭; this.user.剪刀 = obj.data.剪刀; this.user.布 = obj.data.布; this.compete_user.name = obj.data.compete_name; this.count_down_cards = obj.data.count_down_cards; break; case 'after_do_guess': this.user.石頭 = obj.data.left_cards.石頭; this.user.剪刀 = obj.data.left_cards.剪刀; this.user.布 = obj.data.left_cards.布; switch(obj.data.compete_type){ case '石頭': this.compete_type = 'shitou'; break; case '剪刀': this.compete_type = 'jiandao'; this.user.剪刀 = obj.data.left_cards.剪刀; break; case '布': this.compete_type = 'bu'; this.user.布 = obj.data.left_cards.布; break; } // this.result = obj.data.result; var that = this; setTimeout(function(){ var dialog = new Dialog({ onRemove:function(){ that.result = ''; that.compete_type = 'back'; that.user.checked = ''; } }).alert('U ' +obj.data.result, { type:'remind', }) }, 200) break; case 'win':case 'draw':case'lose': this.end_status = obj.msg; this.room_id = 0; this.compete_uid = 0; this.egg_name = obj.data.egg_name; localStorage.removeItem('room_id'); localStorage.removeItem('compete_uid'); location.href = '#end'; break; case 'notify': this.notify = obj.data.info; break; default: ; } } catch (error) { console.log(error); alert('錯誤的服務器消息'); } finally { } }, wsclose: function(){ this.fd = 0; ws.close(); }, wserror: function(){ alert('網絡鏈接失敗'); if(this.page == 'gaming' || this.page == 'end'){ location.href = '/#welcome'; location.reload(true); } } ~~~ wsmsg處里消息。 wssend來發送消息。 定義了發消息的格式 json,帶op,和后端對應,然后wsmsg里,所有消息對應的響應方法都有`after_ `前綴。 然后根據這些事件的響應,更新ui 比如卡牌倒計時、每個人的星星等。 # 初始化數據 ~~~ data: { notify: '歡迎進入比賽', page: 'welcome', end_status: 'Win', egg_name: '', host: '127.0.0.1:9502', uid: 0, fd: 0, room_id: 0, compete_uid: 0, guess_type: '', compete_type: 'back', user: { name: '', stars: 3, checked: '', '石頭': 4, '剪刀': 4, '布': 4, }, compete_user: { name: '', stars:3, }, count_down_cards: {'石頭':8,'剪刀':8,'布':8}, }, ~~~ 一些預設配置,一些動態比如用戶和對手信息,最新消息等。 # 緩存 在做的過程中,發現用戶有刷新當前頁面的習慣。所以只要之前的游戲沒結束,就要回到刷新前的狀態。后來就用localStorage,來持久化信息。當然也加了一些消息用于主動獲取信息,如enter_room。 # 刷新后保持狀態和最新數據 一開始,卡牌倒計時是每次出過牌后才返回來。但是如果恢復場景,就不知道,所以加了個enter_room消息。 # UI 變為場景 開始我打算樣式一個個手寫。后來發現墨刀的預覽效果上,都是html+css實現的。 ![](https://box.kancloud.cn/608ec2f53f76eac9be5c2e4fac8e00f7_1592x455.png) 于是就復制,去掉無用id class屬性。把所有定位調整相對定位。然后通過調整top、left的方式總算把靜態部分實現了。 暫時不做自適應所有屏幕尺寸把。 # 當前剩余卡牌為0 的出牌無效 當時出牌沒判斷自己剩余的該卡牌是否還有剩余數量。 然后after_do_guess里加了*left_cards* ~~~ $left_cards = [ '石頭' => RoomUserCards::left_card('石頭', $data['room_id'], $data['uid']), '剪刀' => RoomUserCards::left_card('剪刀', $data['room_id'], $data['uid']), '布' => RoomUserCards::left_card('布', $data['room_id'], $data['uid']) ]; $this->success('after_do_guess', ['result' => $result,'compete_type'=>$compaire_card['type'], 'left_cards'=>$left_cards]); ~~~ 這樣每次出牌后我都更新user對象里的各種牌型的剩余數量。發現瀏覽器里中文js對象索引頁支持。 然后對應視圖里做判斷: ~~~ <div class="widget image_view user_card" id="user_shitou" v-bind:class="{checked :user.checked == '石頭', disabled: user.石頭 == 0}" @click="choose('石頭')"></div> <div class="widget image_view user_card" id="user_jiandao" v-bind:class="{checked :user.checked == '剪刀', disabled: user.剪刀 == 0}" @click="choose('剪刀')"></div> <div class="widget image_view user_card" id="user_bu" v-bind:class="{checked :user.checked == '布', disabled: user.布 == 0}" @click="choose('布')"></div> ~~~ # 一次判定后的處理 每次出牌后有結果后,就會將checked 重置。不讓其高亮選擇狀態。 開始界面想搞一個自動進入游戲,如果緩存的參數都在的情況下。 后來發現用vue的 watch 就可以了。 ~~~ watch: { page: function (val) { if(val == 'gaming'){ if(this.uid && this.compete_uid){ this.wssend({ op: 'enter_room', room_id: this.room_id, uid: this.uid, compete_uid: this.compete_uid, }); } }else if(val == 'welcome'){ this.start(); } }, }, ~~~ 當頁面發生切換時。 # 其他方法 start、get_new、choose、 again。 start 就是點擊開始按鈕,會做很多判斷。 get_new 就是老是被問是不是老婆知道。 choose 就是do_guess。 again 結束當前房間再來一次。 具體看完整源碼即可。 # 視圖 ~~~ <div id="app"> <section v-if="page == 'welcome'" id="welcome"> <div id="title"> 賭一把 <br> </div> <div class="widget button hcenter vmiddle clickable animated flash" id="start_btn" @click="start()"> <div class="button-wrapper"> <span class="text">開始</span> </div> </div> <div class="widget text_view hleft vtop" id="desc"> <div class="text" style="padding: 10px;"><p>游戲規則:初始進入創建角色后,再創建房間,每人初始3顆星,進行猜拳游戲,手中四組“石頭、剪刀、布”。雙方互相決定出什么牌后,翻面判定本次出牌勝負。每次出牌有 win 、lose、draw。三個結果。出過的牌作廢。win獲得對方的一顆星,平局不消耗星。輸了減少一顆星給對方。有人輸光3顆星或者牌走完,游戲結束。</p> </div> </div> <div class="widget label hcenter vmiddle" id="footer"><p>本游戲由jaylabs實驗室老楊提供</p></div> </section> <section v-if="page == 'gaming'" id="gaming"> <div class="widget rounded_rect hcenter vmiddle" id="notify"><p v-show="notify !=''">&nbsp;通知:{{notify}}</p></div> <div class="widget rounded_rect hleft vmiddle name" id="user_info_name" style="padding: 0px;"><p>{{user.name}}</p></div> <div class="widget rounded_rect hleft vmiddle name" id="compete_info_name" style="padding: 0px;"><p>{{compete_user.name}}</p></div> <div class="count_wraper"> <div class="widget image_view countdown" id="countdown_shitou"></div> <div class="widget image_view countdown" id="countdown_jiandao"></div> <div class="widget image_view countdown" id="countdown_bu"></div> </div> <div class="star_wraper"> <img src="static/img/star.png" v-for="n in user.stars"> </div> <div class="star_wraper" id="compete_stars"> <img src="static/img/star.png" v-for="n in compete_user.stars"> </div> <div class="countdown_num" id="countdown_num_shitou">{{count_down_cards.石頭}}</div> <div class="countdown_num" id="countdown_num_jiandao">{{count_down_cards.剪刀}}</div> <div class="countdown_num" id="countdown_num_bu">{{count_down_cards.布}}</div> <div class="widget image_view" v-bind:class="[compete_type]" id="compete_type"></div> <div class="widget image_view user_card" id="user_shitou" v-bind:class="{checked :user.checked == '石頭', disabled: user.石頭 == 0}" @click="choose('石頭')"></div> <div class="widget image_view user_card" id="user_jiandao" v-bind:class="{checked :user.checked == '剪刀', disabled: user.剪刀 == 0}" @click="choose('剪刀')"></div> <div class="widget image_view user_card" id="user_bu" v-bind:class="{checked :user.checked == '布', disabled: user.布 == 0}" @click="choose('布')"></div> </section> <section v-if="page == 'end'" id="end"> <div class="widget rounded_rect hcenter vmiddle" id="result"> <div class="text" style="padding: 0px;"> <p><font color="#ce1919">U {{end_status}}</font></p> <p class="egg_text" v-show="egg_name">我找到了我的妞,{{egg_name}}!</p> </div> </div> <div class="widget button hcenter vmiddle animated fadeOut" id="again_btn"> <div class="button-wrapper"><span class="text" @click="again()">再來一把</span></div> </div> </section> </div> ~~~ 整個視圖也就3個section。id分別為welcome、gaming、end。 ## v-for n in 顯示星星的時候,想用v-for 但是一般都是定義一個數組,我只想循環1-3 這種,終于被我在手冊里找到了。 ~~~ <div class="star_wraper" id="compete_stars"> <img src="static/img/star.png" v-for="n in compete_user.stars"> </div> ~~~ ## 結束頁的背景 因為背景圖是一個窄圖,放在中間很不好看,干脆搞了和圖片主色相近的背景色。 ![](https://box.kancloud.cn/8a914636c84f5932cfdc681495ad7738_925x781.png) ## 提高效率 因為這個都是相對定位,所以場景里的元素的定位相比原型里1440 的小了一些,每個都得調一下。后來嘗試了chrome的workspace 方法 。直接瀏覽器里改,也沒用什么live reload方案。 ### 彈窗 用了 Lulu UI的dialog。找了半天才找到回調在onClose里。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看