從頭開始構建web前端應用——字符炸彈小遊戲(一)

  我有個哥們,綽號小白,作黑盒測試。這系列隨筆是教他入門web前端時寫的,也送給剛打算轉行作前端的那些人,歡迎大神幫忙指正。javascript

  廢話很少說,進入正題。css

  新建txt文件,改後綴名爲「.html」。右擊,用記事本打開(固然也能夠用一些牛哄哄的IDE打開)。敲入如下字符:html

<html>
    <head>
    </head>
    <body>
    </body>
</html>

  這就是最簡單的網頁結構。前端

 

  如今在<head>標籤和<body>標籤中添加一些字符,使之變成以下樣子:java

<html>
    <head>
        this is a simple html
    </head>
    <body>
        Hello,world!
    </body>
</html>       

  保存一下,而後用瀏覽器打開此文件,ok,最簡單的網頁製做完畢。web

  你也能夠把「Hello,world!」替換成中文字符,好比「現代瀏覽器很強大」。  canvas

    保存,再次用瀏覽器打開,也許你會看到一堆亂碼,不要緊,指定一下頁面的顯示字符集。通常是「UTF-8」或者「GBK 」。數組

    在<head></head>標籤中加入如下字符:
      <meta charset="UTF-8" />
瀏覽器

    保存,再次用瀏覽器打開。ok。dom

  

  如今往<body>標籤裏面添加一個<canvas>標籤,以下面這樣

 <body>
    <canvas style="border:1px;">
    </canvas>
 </body>

  其中,style屬性指明瞭canvas標籤的邊框樣式。保存,再次用瀏覽器打開。ok。你能夠看到一個框框。這塊區域就是剛纔添加的canvas區域。以後的繪圖就是在這裏進行。

  爲了方便後續的修改調試,建議如今把這份代碼整理成下面這樣:

<html>
    <head>
        <meta charset="UTF-8" />
        <style type="text/css">
            .showBoxStyle {
                border: 1px solid #000;
            }
        </style>
    </head>
    <body>
        <canvas id="showBox" class="showBoxStyle">
            
        </canvas>
        </body>
</html>

  對,就是爲canvas標籤添加id和class屬性,而後在head標籤裏面指明style標籤寫樣式。

  

  而後,就開始正式寫js代碼做交互了。 

  javascript簡稱js,通常在HTML文檔的最後添加<script>標籤進行編輯。不妨先在<body>標籤結束以後寫一段js試試:

<html>
<head>
    <meta charset="UTF-8" />
    <style type="text/css">
        .showBoxStyle {
            border: 1px solid #000;
        }
    </style>
</head>
<body>
<canvas id="showBox" class="showBoxStyle">

</canvas>
</body>
<script type="text/javascript">

    var showBox = document.getElementById("showBox"); /*經過id屬性獲取界面對象canvas*/
    var context = showBox.getContext('2d');           /*設置canvas的繪製屬性*/

    context.clearRect(0,0,300,150);
    context.fillStyle = "#000000";
    context.fillRect(0, 0,300,150);

</script>
</html>

 

  保存,在瀏覽器裏打開,ok,如今繪製了一個全屏的黑色矩形,下面開始修改<script>標籤裏面的內容,首先將canvas繪圖區拉大,加長:

 var showBox = document.getElementById("showBox");
    var context = showBox.getContext('2d');

    showBox.setAttribute("width", "600px");
    showBox.setAttribute("height", "400px");

 

  而後,咱們須要一個產生隨機字符的函數,能夠先把字符集存在一個數組或字符串中,而後產生必定範圍的隨機數,這個隨機數表明隨機字符在字符串裏的位置。按照這個隨機數去取對應的字符。這裏我只列出26個小寫字母。

var samllchars = "abcdefghijklmnopqrstuvwxyz";

/*
 * 產生隨機整數
 */
function ranInt(num){
  return Math.floor(Math.random()*num);
}
            
/*
 * 產生隨機字符
 */
function ranChars() {
   var _num = ranInt(samllchars.length); 

  return samllchars[_num];
}

  

  接下來,須要一個顯示在界面上的字符對象,這個對象應該保存有字符信息,字符的位置等。

/*
 * 字符對象私有屬性
 */
function CharObj(){
  var _self = this;
  _self.chars = null;
   _self.top = 0;
   _self.left = 0;
   _self.v = 0;
}
            
/*
 * 字符對象初始化方法
 */
CharObj.prototype.init = function(){
   var _self = this;
   _self.chars = ranChars();
   _self.top = 0;
   _self.left = ranInt(500);
   _self.v = ranInt(10)+5;
             
}
            
/*
 * 字符對象移動方法
 */
CharObj.prototype.move = function(){
   var _self = this;
   _self.top += _self.v;
}
            
/*
 * 字符對象顯示方法
 */
CharObj.prototype.draw = function(){   var _self = this; context.font = 'bold 30px 幼圓'; context.fillStyle = "#F00"; context.fillText(_self.chars, _self.left, _self.top); }

  js是一種弱類型語言,稍微解釋下這段代碼。首先寫一個函數CharObj()做爲類對象的構造器(相似於C++等強類型語言的構造函數),而後在這個構造器裏面寫一些屬性(相似於強類型語言裏的私有屬性)。

  把this指針保存在_self變量裏面是我在工做中養成的習慣,由於團隊的代碼規範要求這樣。

  再而後在CharObj的原型上掛載一些方法,也能夠像上面的屬性同樣寫在構造器函數裏。這樣作的好處是能夠避免在屢次生成同一類型實例的時候都生成新的函數。

  

  如今,須要的是一個字符對象隊列,每次生成新字符的時候把字符插入這個隊列,在字符被正確輸入或移出屏幕時刪除。每隔一段時間就遍歷這個隊列,依次調用每一個字符的draw方法,繪製這些字符在畫布上,固然,在每次遍歷以前,須要先清空畫布,不然,繪製的圖像會有重疊,看不出動畫效果。

//字符隊列
var showCharObjs = [];

/*
 * 產生隨機字符並插入字符隊列
 */
function proNewCharObj(){
  var _charObj = new CharObj();   _charObj.init(); showCharObjs.push(_charObj); } /* * 移動並顯示字符隊列 */ function moveAndDrawCharObj(){   context.clearRect(0,0,600,400);   context.fillStyle = "#000000";   context.fillRect(0, 0,600,400);   var deleList = [];   for(var i=0;i<showCharObjs.length;i++){     showCharObjs[i].move(); if(showCharObjs[i].top >= 400 ){   deleList.push(showCharObjs[i].chars); } showCharObjs[i].draw(); } if(deleList){
    for(i=0;i<deleList.length;i++){   deleCharObj(deleList[i]); } }
}

/* * 刪除字符隊列的字符 */ function deleCharObj(cobj){   var arr = [];
  for(var i=0;i<showCharObjs.length;i++){     if(showCharObjs[i].chars != cobj ){
      arr.push(showCharObjs[i]);
    }

  } showCharObjs
= arr;
}

  的確,把字符移出隊列的方法確實有點ugly,但我確實沒有想到更好的方法,還望各位看官不吝賜教。

  

  接下來,就是對鍵盤事件進行響應了。

  當用戶對着網頁按下一個鍵的時候,能夠獲得這個鍵的鍵碼,而後比照鍵碼,將對應的字符移出隊列。

function getc(ewhich){
  var c = ewhich;
  if(c>=65&&c<=90){
      c = samllchars[c-65];
  }
  return c; } document.onkeydown = function(e){   var c = getc(e.which);   deleCharObj(c); }

 

  最後,還須要兩個計時器,一個不停地向字符隊列裏面插入隊列,一個不停地刷新畫布顯示:

 setInterval(proNewCharObj, 1000);
    setInterval(moveAndDrawCharObj, 100);

 

ok,到這裏基本的任務就完成了。接下來,須要作一些顯示上的優化。

1.修改顯示的字母顏色

2.添加一些新字符,好比「0-9」個數字

3.添加計分統計部分。

  修改:

1.修改字符對象函數,增長顏色屬性和繪製方法:

       /*
             * 字符對象私有屬性
             */
            function CharObj(){
                var _self = this;
                _self.chars = null;
                _self.top = 0;
                _self.left = 0;
                _self.v = 0;
                _self.color = null;
            }
            
            /*
             * 字符對象初始化方法
             */
            CharObj.prototype.init = function(){
                var _self = this;
                _self.chars = ranChars();
                _self.top = 0;
                _self.left = ranInt(500);
                _self.v = ranInt(10)+5;
                var r = ranInt(100)+140;
                var g = ranInt(100)+100;
                var b = ranInt(100)+50;
                _self.color = "rgb("+r+","+g+","+b+")";
            }
            
            /*
             * 字符對象移動方法
             */
            CharObj.prototype.move = function(){
                var _self = this;
                _self.top += _self.v;
            }
            
            /*
             * 字符對象顯示方法
             */
            CharObj.prototype.draw = function(){
                var _self = this;
                context.font = 'bold 30px 幼圓'; 
                context.fillStyle = _self.color;
                context.fillText(_self.chars, _self.left, _self.top); 
            }

  這裏考慮到背景顏色是黑色的,字符顏色不宜太暗,因此rgb的值能夠設置的高一點。

 

2.修改隨機字符串和生成隨機字符的函數

var samllchars = "abcdefghijklmnopqrstuvwxyz";
var nums = "0123456789";

var allchars = samllchars + nums;

            /*
             * 產生隨機整數
             */
            function ranInt(num){
                return Math.floor(Math.random()*num);
            }
            
            /*
             * 產生隨機字符
             */
            function ranChars() {
                var _num = ranInt(allchars.length);
                return allchars[_num];
            }    

 

3.添加頁面標籤,標識得失:

<body>
        <div>
            <a>
                points:&nbsp;<span id="points">0</span> 
            </a>
        </div>
        <canvas id="showBox" class="showBox">
            
        </canvas>
        <a>
                miss:&nbsp;<span id="miss">0</span> 
        </a>
</body>

而後修改按鍵監聽部分完成得分功能:

document.onkeydown = function(e){
                var c = getc(e.which);
                countPoint(c);
            }

function getc(ewhich){
                var c = ewhich;
                if(c>=48&&c<=57){
                    c = nums[c-48];
                }
                else if(c>=65&&c<=90){
                    c = samllchars[c-65];
                }
                return c;
            }
            
            function countPoint(c){
                pointFlag = false;
                deleCharObj(c);
                if(pointFlag){
                    points++;
                    pointSpan.innerHTML = points;
                }
                
            }

再修改字符超出界面時移出隊列做爲失分的計分

       /*
             * 移動並顯示字符隊列
             */
            function moveAndDrawCharObj(){
                context.clearRect(0,0,600,400);
                context.fillStyle = "#000000";
                context.fillRect(0, 0,600,400);
                var deleList = []; 
                for(var i=0;i<showCharObjs.length;i++){
                    showCharObjs[i].move();
                    if(showCharObjs[i].top >= 400 ){
                        deleList.push(showCharObjs[i].chars);
                    }
                    showCharObjs[i].draw();
                }
                if(deleList){
                    for(i=0;i<deleList.length;i++){
                        deleCharObj(deleList[i]);
                        misspoints++;
                    }
                    missSpan.innerHTML = misspoints;
                }    
            }

最後修改移出隊列的函數,以達到計分的目的(主要是修改標識符,得分和失分時都要將字符移出字符隊列)

/*
             * 刪除字符隊列的字符
             */
            function deleCharObj(cobj){
                var arr = [];
                for(var i=0;i<showCharObjs.length;i++){
                    if(showCharObjs[i].chars != cobj ){
                        arr.push(showCharObjs[i]);
                    }
                    else{
                        pointFlag = true;
                    }
                }
                showCharObjs = arr;
            }

 

 

最後,完整的代碼以下所示。

<html>
    <head>
        <style type="text/css">
            .showBox {
                border: 1px solid #000;
            }
        </style>
    </head>
    <body>
        <div>
            <a>
                points:&nbsp;<span id="points">0</span> 
            </a>
        </div>
        <canvas id="showBox" class="showBox">
        </canvas>
        <br />
        <a>
                miss:&nbsp;<span id="miss">0</span> 
        </a>

        <script type="text/javascript">
            var samllchars = "abcdefghijklmnopqrstuvwxyz";
            var nums = "0123456789";

            var allchars = samllchars + nums;

            var showBox = document.getElementById("showBox");
            var context = showBox.getContext('2d'); 
            
            /*
             * 產生隨機整數
             */
            function ranInt(num){
                return Math.floor(Math.random()*num);
            }
            
            /*
             * 產生隨機字符
             */
            function ranChars() {
                var _num = ranInt(allchars.length);
                return allchars[_num];
            }
            
            /*
             * 初始化畫布
             */
            function initCanvas(){
                showBox.setAttribute("width","600px");
                showBox.setAttribute("height","400px");
            }
            
            initCanvas();

            //得分的界面顯示區域
            var pointSpan = document.getElementById("points");
            //失分的界面顯示區域
            var missSpan = document.getElementById("miss");
            //字符隊列
            var showCharObjs = [];
            //得分
            var points = 0;
            //得分標記
            var pointFlag = false;
            var misspoints = 0;
            
            /*
             * 字符對象私有屬性
             */
            function CharObj(){
                var _self = this;
                _self.chars = null;
                _self.top = 0;
                _self.left = 0;
                _self.v = 0;
                _self.color = null;
            }
            
            /*
             * 字符對象初始化方法
             */
            CharObj.prototype.init = function(){
                var _self = this;
                _self.chars = ranChars();
                _self.top = 0;
                _self.left = ranInt(500);
                _self.v = ranInt(10)+5;
                var r = ranInt(100)+140;
                var g = ranInt(100)+100;
                var b = ranInt(100)+50;
                _self.color = "rgb("+r+","+g+","+b+")";
            }
            
            /*
             * 字符對象移動方法
             */
            CharObj.prototype.move = function(){
                var _self = this;
                _self.top += _self.v;
            }
            
            /*
             * 字符對象顯示方法
             */
            CharObj.prototype.draw = function(){
                var _self = this;
                context.font = 'bold 30px 幼圓'; 
                context.fillStyle = _self.color;
                context.fillText(_self.chars, _self.left, _self.top); 
            }
            
            /*
             * 產生隨機字符並插入字符隊列
             */
            function proNewCharObj(){
                var _charObj = new CharObj();
                _charObj.init();
                showCharObjs.push(_charObj);
            }
            
            /*
             * 移動並顯示字符隊列
             */
            function moveAndDrawCharObj(){
                context.clearRect(0,0,600,400);
                context.fillStyle = "#000000";
                context.fillRect(0, 0,600,400);
                var deleList = []; 
                for(var i=0;i<showCharObjs.length;i++){
                    showCharObjs[i].move();
                    if(showCharObjs[i].top >= 400 ){
                        deleList.push(showCharObjs[i].chars);
                    }
                    showCharObjs[i].draw();
                }
                if(deleList){
                    for(i=0;i<deleList.length;i++){
                        deleCharObj(deleList[i]);
                        misspoints++;
                    }
                    missSpan.innerHTML = misspoints;
                }    
            }
            
            /*
             * 刪除字符隊列的字符
             */
            function deleCharObj(cobj){
                var arr = [];
                for(var i=0;i<showCharObjs.length;i++){
                    if(showCharObjs[i].chars != cobj ){
                        arr.push(showCharObjs[i]);
                    }
                    else{
                        pointFlag = true;
                    }
                }
                showCharObjs = arr;
            }
            
            function getc(ewhich){
                var c = ewhich;
                if(c>=48&&c<=57){
                    c = nums[c-48];
                }
                else if(c>=65&&c<=90){
                    c = samllchars[c-65];
                }
                return c;
            }
            
            function countPoint(c){
                pointFlag = false;
                deleCharObj(c);
                if(pointFlag){
                    points++;
                    pointSpan.innerHTML = points;
                }
                
            }
            
            setInterval(proNewCharObj,1000);
            setInterval(moveAndDrawCharObj,100);
            document.onkeydown = function(e){
                var c = getc(e.which);
                countPoint(c);
            }
        </script>
    </body>
</html>

 

如今,面臨的問題是:

1.代碼過長,須要拆分以方便後續維護

2.字符下落速度和字符產生時間間隔能夠作成配置項,並在界面上添加遊戲難度選擇功能,經過不一樣的選擇,決定這些參數。

3.當字符隊列爲空時,字符隊列的length不可取,程序運行可能還會出現bug。

 

這些都會後續解決。

 

我以爲對於初學者,能看到這裏的人,我以爲須要掌握:

1.基本的網頁DOM結構和語義化的DOM標籤

2.知道怎麼設置CSS樣式。不須要知道CSS2全部的屬性值,但對樣式表有一點點初步的瞭解

3.知道怎麼用js去操做DOM,以及js的函數調用方式和構造器調用方式

4.知道怎麼用js去響應事件,對事件驅動模型有初步的認識。

5.對HTML5的<canvas>標籤有最直接的接觸。

這些是web前端中最基礎也是最簡單的部分。

相關文章
相關標籤/搜索