JS開發打氣球游戲


JS開發打氣球游戲

觀視頻《月薪4萬的程序員有多強?半小時原生JS開發打氣球游戲,征服現場數萬人!》

清晨,日常打開B站,被首頁此視頻的標題所吸引,雖一看就是標題黨,但還是沒能抑制住好奇心。
視頻共計60*3分鍾,學習到了很多東西。其中后半部分有許多正三觀的見解也非常認同。
視頻地址:https://www.bilibili.com/video/av15152538/
在線試玩:http://sandbox.runjs.cn/show/luderhbq
參考視頻寫的demo:https://coding.net/u/yimocoding/p/WeDemo/git/tree/氣球大戰

看了視頻,自己來實現試試

花了半天的時間,人生中的第二個游戲終於完成了,想起第一次做拼圖游戲也已經是3年前了~
來吧,試玩一下,看能消滅多少個氣球【笑哭】:http://sandbox.runjs.cn/show/luderhbq
然后,一起來一步步構建自己的【氣球大戰】(文中代碼為核心代碼,后續有優化,故非完整代碼),可以在runjs中去查看

1.用css3畫一個氣球

看視頻的時候覺得自己這個會那個也會,寫代碼的時候才發現沒有智能提示啥都不會,打錯單詞的次數不是一次兩次~

氣球效果預覽

css代碼

//html→→_→→<div class="balloon"></div>

body{margin:0;padding:0} .balloon{width:150px;height:150px;position:absolute;left:0;top:0;background-color:pink;border-radius:50% 50% 10% 50%;transform:rotate(45deg);box-shadow:1px 1px 20px 20px red inset} .balloon:after{width:20px;height:20px;content:"";display:block;background:0 0;position:absolute;right:-15px;bottom:-15px;border-left:5px solid red;border-top:5px solid red} .balloon:before{width:2px;height:50px;content:"";display:block;background:pink;position:absolute;right:-10px;top:100%;margin-top:-16px;transform:rotate(-45deg)}

2.隨機創建氣球

首先定義了一些變量

    var bnElements=[];//存放所有氣球 var random=Math.random;//隨機函數 var wW=window.innerWidth;//窗口寬度 var wH=window.innerHeight;//窗口高度 var ballW=160;//氣球的寬度 var ballH=300;//氣球的寬度 var minSpeed=3;//最小速度,每次向上移動至少3px var speedNum=8;//速度的定量 var defBnNumber=10;//初始化氣球

首先編寫並調用初始化方法生成氣球

生成氣球代碼

    init(defBnNumber); //初始化氣球 function init(num){ //創建一個虛擬文檔節點 var docFragment=document.createDocumentFragment(); for(var i=0;i<num;i++){ var bnElement=document.createElement('div'); bnElement.className='balloon'; //速度隨機,限定最小值 var speed=Math.max(minSpeed,~~(random()*speedNum)); bnElement.setAttribute('speed',speed);//~~取整 移動速度 bnElement.setAttribute('id','ball-'+(bnElements.length+i+1)); //分散排列 var x=(~~(random()*wW))-ballW; x=Math.max(0,x); bnElement.style.left=x+'px'; bnElement.style.top=wH+'px';//露一點出來 //1.先將創建的氣球放入創建的虛擬文檔節點 docFragment.appendChild(bnElement); bnElements.push(bnElement); } //2.將虛擬文檔節點添加到body中 document.body.appendChild(docFragment); }

效果預覽

3.氣球向上移動

創建一個move方法並在初始化后調用

氣球移動代碼

    move();//移動氣球 只需要調用一次即可 function move(){ var bl=bnElements.length for(var i=0;i<bl;i++){ var currentElement=bnElements[i] if(currentElement==null){ continue; } var offsetTop=currentElement.offsetTop; if(offsetTop>-ballH){//窗口中 var speed=currentElement.getAttribute('speed'); currentElement.style.top=offsetTop-speed+'px' } else{ //移除dom節點 document.body.removeChild(currentElement); //移除數組中 bnElements.splice(i,1); init(1); } } setTimeout(move,1000/30); }

效果預覽

4.點擊氣球,氣球消失

發現顏色有點丑~~遂改。

氣球消失代碼

bindClick(); //綁定點擊氣球事件 function bindClick(){ document.body.addEventListener('click',function(e){ if(e.target.className=='balloon'){ boom.call(e.target,function(){ e.target.parentNode.removeChild(e.target); bnElements.splice(bnElements.lastIndexOf(e.target),1); init(1); }); } }); } function boom(callback){ //var that=this; //替換了上下文,但是沒有使用this的意義. var speed=this.getAttribute('speed'); this.timer=setInterval(function(){ this.style.opacity=0.1*(speed--) console.log(this.offsetWidth); if(speed<1){ callback&&callback(); clearInterval(this.timer); } }.bind(this),1000/30); }

效果預覽


核心代碼終於寫完,在我的純靜態工具站點生成二維碼掃一掃,在我的小米手機上玩了玩,ok正常,然后再新入手的ipad中試了試。。。擦。坑爹呢,點了咋沒反應啊。
好吧,為了ipad能玩,強忍着淚水(餓的)解決了iOS的safari兼容問題~

5.解決遇到的safari瀏覽器兼容問題

  • 問題一:Safari中單擊事件不能綁定到document.body上~~,因為無效~
    解決方法:給元素加了個父級~,若click事件有問題則還需要將click換成touchend~

  • 問題二:transform變換z-index層級渲染異常
    解決方法:未變換的元素上添加樣式:transform: translateZ(120px);
    參考文章:http://www.zhangxinxu.com/wordpress/2016/08/safari-3d-transform-z-index/

總結

get了幾個以前不知道沒用過的新技能

  • 文檔片段
    當需要將一堆節點添加到dom中可以使用document.createDocumentFragment();創建虛擬文檔節點,讓后將節點先添加到此虛擬節點中,再將此節點追加到指定元素,能夠降低dom渲染次數
  • 使用位運算符取整
    取0-9的隨機數 ~~(Math.random()*10) //Math.random()大於等於 0.0 且小於 1.0
  • Math.max() Math.min() 可以用來限定邊界值
  • setInterval問題:
    • 可能會丟幀(瀏覽器的刷新頻率為60FPS,一秒最大可以重繪60次),故理論上setinterval()間隔時間大於1000/60就不會參數丟幀的情況
    • 時間線偏移(甚至重疊沒執行完就執行下一次任務了),若需要每次都執行完才執行下次任務則使用setTimeout+遞歸
    • this的傳遞(可以使用bind()去綁定this,不能使用call,會提示沒有權限)
      傳遞this到setInterval中:setInterval(function(){}.bind(this),1000/30)
  • 值的相等判斷使用===會比==性能好一點,大部分情況應當使用===
  • 判斷回調函數並執行回調函數
    以前我是這樣寫的:if(typeof(callback)==='function')callback();
    視頻中有用短路運算符實現即:callback&&callback()

  • 踩了踩safari的坑
  • 最可怕的事情,不是別人比你強,而是比你強的人比你還努力!!!

作者:易墨 
個人小站:http://www.yimo.link 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM