<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 48,comments - 156,trackbacks - 0

    一、為什么選擇 HTML5

    HTML5 邊玩邊學(xué)算上這篇已經(jīng)是第七篇了,在這篇開始之前,我想先說明一下為什么叫“HTML5” 邊玩邊學(xué),因為有人對 HTML5 提出質(zhì)疑,畢竟他是一個新生事物。我承認(rèn)我用 HTML5 來吸引眼球了,如果看過邊玩邊學(xué)系列的每一篇,你會發(fā)現(xiàn)前六篇文章內(nèi)容的和 HTML5 關(guān)系不是太大,真正的內(nèi)容其實是 2D 圖形圖像編程的學(xué)習(xí)筆記。

    如果我們想學(xué)習(xí) 2D 編程,其實可供選擇的編程環(huán)境數(shù)不勝數(shù):MFC、Delphi都有圖形圖像處理功能(即GDI),Java、.Net 更不用說了,如果你支持開源,GTK、QT、wxPython 也是不錯的選擇,F(xiàn)lash 更是拿手好戲,甚至幾個流行的只能手機平臺應(yīng)該也有 2D 模塊。

    如果你選擇了上面任何一款編程環(huán)境學(xué)習(xí) 2D 編程,你會發(fā)現(xiàn)他們的內(nèi)容基本上是一樣的:線型、填充、顏色、漸變、圖像、組合、裁剪區(qū)、變形等等,甚至連函數(shù)名很多都是一摸一樣,畢竟他們的理論基礎(chǔ)都是圖形學(xué)。

     搞清楚我們真正想學(xué)習(xí)什么以后,其實編程環(huán)境只是個工具而已,我們根據(jù)個人喜好,選擇最方便的一款來使用。其實我更青睞 Python 編程環(huán)境,只是如果我用了Python,估計跟我交流的人就不會太多了,大家機器里安裝 Python 運行時的估計不會太多。

    那么為什么選擇 HTML5 而不是其他呢?首先,Javascript 語法簡潔靈活,相應(yīng)的函數(shù)庫小巧但是夠用, HTML5 Canvas 標(biāo)簽的 2D 表現(xiàn)能力也達(dá)到了要求,Chrome 瀏覽器的運行速度讓人滿意。除此之外,我們不用安裝笨重的集成開發(fā)環(huán)境,不需要安裝運行時,我們只需要一個加強功能的記事本、一個瀏覽器就可以去實踐我們的想法,并且直接將效果呈現(xiàn)在網(wǎng)絡(luò)上。我們只是發(fā)表文章同其他人分享自己的想法而已,至于平臺、框架、語言特性,這些無關(guān)的東西當(dāng)然牽扯的越少越好,這就是我選擇 HTML5 的原因。

    所以,請大家不要誤解了標(biāo)題的含義:這個系列并不是 HTML5 的學(xué)習(xí)筆記,而只是用 HTML5 來展現(xiàn)一些知識內(nèi)容而已,你更多關(guān)注的應(yīng)該是知識和內(nèi)容本身,你可以在任何其他一款編程環(huán)境下再現(xiàn)他們。

     

    二、動畫初步

    動畫就是一系列連續(xù)的畫面按順序呈現(xiàn)出來而已,只是,在電影電視中,這些畫面實現(xiàn)已經(jīng)被準(zhǔn)備好了,而在電腦程序中,我們見到每一瞬間的畫面都是即時繪制的,大體流程可以表述如下:

    a、輕微改變圖形的數(shù)據(jù)(坐標(biāo)、形狀、顏色等等)

    b、清空畫布

    c、繪制圖形

    d、回到步驟 a

    當(dāng)然,這里只是給出了一個最簡單的流程框架,要實現(xiàn)復(fù)雜的動畫可能還要考慮更多的問題,比如局部清除、碰撞檢測之類的。

     

    另外,繪制過程中有兩個速度需要控制:

    第一個是繪制速度,即每秒鐘繪制多少次(幀),或者也可以這樣說,每一幀暫停多少時間。如果你的動畫每一幀都是一個樣子,只是位置不同,這個速度影響不大。

    第二個圖形移動的速度。

    所以,千萬不要把這兩個速度搞混了,繪制的越快,只能代表動畫更流暢,但并不代表你的圖像移動的更快。

     

    使用 HTML5 繪制動畫基本上就是上面這個流程,只是你還需要注意兩點:

    1、為了方便繪制的圖形,我們經(jīng)常會改變上下文對象的的狀態(tài),所以在繪制圖形前后,千萬別忘了保存和恢復(fù)狀態(tài),如果你不太了解狀態(tài)是什么,請看前面的一篇文章《HTML5邊玩邊學(xué)(6):汽車人,變形......》

    2、我們需要將整個繪制動作放到定時器里面,否則整個瀏覽器將失去響應(yīng)。Javascript 有兩個定時器方法,分別是:

    setInterval(code,millisec) 和 setTimeout(code,millisec)

    這兩個方法我就介紹了,可以去 Google 相關(guān)的資料。

    下面我們給出一個上下移動方塊的小動畫,當(dāng)遇到頂部或者底部時,會改變方向。代碼如下:

    基本動畫
    <canvas id="canvas1" width="250" height="300" style="background-color:black">
        你的瀏覽器不支持 Canvas 標(biāo)簽,請使用 Chrome 瀏覽器 或者 FireFox 瀏覽器
    </canvas><br/>
    幀數(shù):
    <input  id="txt1" type="text" value="25"/><br/>
    每次移動距離:
    <input type="text" id="txt2" value="10"/><br/>
    <input type="button" value="開始" onclick="move_box()"/>
    <input type="button" value="暫停" onclick="stop()"/>


    <script type="text/javascript">
        
    //定時器
        var interval=null;
        
        
    //停止動畫
        function stop(){
            clearInterval(interval);
        }

        
    //===================================================================
        
    //基本動畫
        
    //====================================================================
        function move_box(){
            
    //停止動畫
            stop();
            
    //移動速度
            var delta=parseInt(document.getElementById('txt1').value);
            
    //每秒繪制多少次
            var fps=parseInt(document.getElementById('txt2').value);

            
    //畫布對象
            var canvas=document.getElementById("canvas1")
            
    //獲取上下文對象
            var ctx = canvas.getContext("2d");
            
    //設(shè)置顏色
            ctx.fillStyle="red";
            
            
    //方塊的初始位置
            var x=100;var y=50;
            
    //方塊的長度和寬度
            var w=30;var h=30;
            
            
    //開始動畫
            interval = setInterval(function(){
                
    //改變 y 坐標(biāo)
                y=y+delta;
                
    //上邊緣檢測
                if(y<0){
                    y
    =0;
                    delta
    =-delta;
                }
                
    //下邊緣檢測
                if((y+h)>canvas.getAttribute("height")){
                    y
    =canvas.getAttribute("height")-h;
                    delta
    =-delta;
                } 
                
    //清空畫布
                ctx.clearRect(0,0,canvas.getAttribute("width"),canvas.getAttribute("height"));
                
    //保存狀態(tài)
                ctx.save();
                
    //移動坐標(biāo)
                ctx.translate(x,y);
                
    //重新繪制
                ctx.fillRect(0,0,w,h);
                
    //恢復(fù)狀態(tài)
                ctx.restore();
            },
    1000/fps);
        }    
    </script>

     

     

    {{{{ 你的瀏覽器不支持 Canvas 標(biāo)簽,請使用 Chrome 瀏覽器 或者 FireFox 瀏覽器
    幀數(shù):
    每次移動距離:
    }}}}

     

    三、重新組織代碼

    上面的代碼能正常工作了,但是存在很多問題,主要有以下幾點:

    1、計算方塊位置的代碼和繪制方塊的代碼混雜一起,即邏輯和視圖混雜,基本上不能擴展了

    2、代碼沒辦法復(fù)用,比如我們需要繪制多個不同的方塊對象:起始位置、大小、顏色、速度各不相同,每一種情況都需要重寫一遍。

    下面我們重新組織一下代碼,把方塊的共同屬性抽象出來,組成一個 Box 類,由這個 Box 類負(fù)責(zé)計算每一幀方塊的位置,這樣就可以解決上面兩個問題了。代碼如下:

    重新組織代碼
    <canvas id="canvas2" width="250" height="300" style="background-color:black">
        你的瀏覽器不支持 Canvas 標(biāo)簽,請使用 Chrome 瀏覽器 或者 FireFox 瀏覽器
    </canvas><br/>
    <input type="button" value="開始" onclick="move_box2()"/>
    <input type="button" value="暫停" onclick="stop()"/>

    <script type="text/javascript">
        
    //定時器
        var interval=null;
        
        
    //停止動畫
        function stop(){
            clearInterval(interval);
        }

        
    //===================================================================
        
    //重新組織代碼
        
    //====================================================================
        
    //方塊的構(gòu)造函數(shù)
        function Box(color,x,y,w,h,delta){
            
    this.color=color;
            
    this.x=x;
            
    this.y=y;
            
    this.w=w;
            
    this.h=h;
            
    this.delta=delta;
            
    //三十幀
            this.fps=30;
            
    //每一幀的延遲時間
            this.delay=1000/this.fps;
            
    //上一次重繪的時間
            this.last_update=0;
        }
        
        
    //方塊更新
        Box.prototype.update=function(canvas){
            
    //獲取當(dāng)前時間
            var now=(new Date()).getTime();
            
    //如果達(dá)到了延遲時間,則更新數(shù)據(jù)
            if((now-this.last_update)>this.delay){
            
                
    //改變 y 坐標(biāo)
                this.y=this.y+this.delta;
                
    //上邊緣檢測
                if(this.y<0){
                    
    this.y=0;
                    
    this.delta=-this.delta;
                }
                
    //下邊緣檢測
                if((this.y+this.h)>canvas.getAttribute("height")){
                    
    this.y=canvas.getAttribute("height")-this.h;
                    
    this.delta=-this.delta;
                } 
                
    //記下最新一次繪制時間
                this.last_update=now;
            }
            
        }
        
        
        function move_box2(){
            
    //停止動畫
            stop();
            
    //畫布對象
            var canvas=document.getElementById("canvas2")
            
    //獲取上下文對象
            var ctx = canvas.getContext("2d");
            
    //清空畫布
            ctx.clearRect(0,0,canvas.getAttribute("width"),canvas.getAttribute("height"));
            
            
    //創(chuàng)建多個方塊對象
            var boxes=[];
            boxes[
    0]= new Box("red",3,2,10,35,2,10);//速度10
            boxes[1]= new Box("blue",60,28,44,15,5);//速度20
            boxes[2]= new Box("green",130,200,23,18,10);//速度30
            boxes[3]= new Box("pink",200,150,35,10,20);//速度40
            
            
    //開始動畫繪制
            interval = setInterval(function(){
                
    for(var i=0;i<boxes.length;i++){
                    
    //取出一個方塊
                    var box=boxes[i];
                    
    //清空這個方塊
                    ctx.clearRect(box.x,box.y,box.w,box.h);
                    
    //更新數(shù)據(jù)
                    box.update(canvas);
                    
    //保存狀態(tài)
                    ctx.save();
                    
    //設(shè)置顏色
                    ctx.fillStyle=box.color;
                    
    //移動坐標(biāo)
                    ctx.translate(box.x,box.y);
                    
    //重新繪制
                    ctx.fillRect(0,0,box.w,box.h);
                    
    //恢復(fù)狀態(tài)
                    ctx.restore();
                }
            },
    1);//盡可能快的循環(huán)
        }    
    </script>

     

    {{{{ 你的瀏覽器不支持 Canvas 標(biāo)簽,請使用 Chrome 瀏覽器 或者 FireFox 瀏覽器
    }}}}

     

    四、精靈登場

    據(jù)說在很久遠(yuǎn)的年代,有多遠(yuǎn)我也不知道,可能是任天堂紅白機是哪個年代吧,由于游戲機處理器的計算速度有限,所以專門設(shè)置了一個硬件用來處理角色圖像的相關(guān)數(shù)據(jù),這些數(shù)據(jù)可能包括:

    1、計算當(dāng)前的角色應(yīng)該繪制哪一幀。上面我們的方塊雖然在移動,但是始終都是一個樣子;可是在游戲中,一個跑動的精靈,跑動動作是由很多幅連續(xù)的圖像組成,我們需要知道現(xiàn)在應(yīng)該繪制其中的哪一幅圖像;

    2、表現(xiàn)精靈動作的很多幅連續(xù)的圖像通常是集中放置在一個大圖中,我們需要計算當(dāng)前繪制的那一幅,在大圖中處于什么位置,并把它截取出來

    上面說到這個硬件,曾經(jīng)被叫做 Sprite 精靈。現(xiàn)如今,我們的處理器已經(jīng)十分強大,不再需要 Sprite 這樣的輔助硬件,但是這樣的功能仍然需要,只不過用軟件來實現(xiàn)罷了,所以,我們依然用 Sprite 來稱呼游戲中的一個角色。

    這里有一幅圖像,他描繪了一個小精靈的飛行動作

     

    下面我們將實現(xiàn)一個 Sprite 類,讓他在瀏覽器里面飛起來。

    精靈登場
    <canvas id="canvas3" width="250" height="300" style="background-color:black">
        你的瀏覽器不支持 
    &lt;canvas&gt;標(biāo)簽,請使用 Chrome 瀏覽器 或者 FireFox 瀏覽器
    </canvas><br/>
    幀數(shù):
    <input  id="txt4" type="text" value="10"/><br/>
    速度:
    <input type="text" id="txt5" value="5"/><br/>
    比例:
    <input type="text" id="txt6" value="2"/><br/>
    <input type="button" value="開始" onclick="animate()"/>
    <input type="button" value="暫停" onclick="stop()"/>

    <script type="text/javascript">
        
    //定時器
        var interval=null;
        
        
    //停止動畫
        function stop(){
            clearInterval(interval);
        }
        
        
    //===================================================================
        
    //精靈登場
        
    //====================================================================
        
    //每一幀在大圖中的位置
        var frames=[];
        frames[
    0]=[0,4,19,19];
        frames[
    1]=[22,1,24,19];
        frames[
    2]=[49,0,18,17];
        frames[
    3]=[1,32,18,17];
        frames[
    4]=[22,33,24,19];
        frames[
    5]=[49,36,19,19];
        
        
    //精靈類
        function Sprite(dx,dy,delta,fps){
            
    this.dx=dx;
            
    this.dy=dy;
            
    this.fps=fps;
            
    this.delay=1000/fps;
            
    this.last_update=0;
            
    //移動速度
            this.delta=-delta;
            
    //幀編號
            this.index=0;
            
    //方向
            this.dir_left=true;
        }
        
        Sprite.prototype.update
    =function(canvas){
            
    //獲取當(dāng)前時間
            var now=(new Date()).getTime();
            
    if((now-this.last_update)>this.delay){
                
    if(this.dir_left){
                    
    //方向朝左,只繪制0 1 2幀
                    if(this.index>2)
                        
    this.index=0;
                }
                
    else{
                    
    //方向朝右,只繪制 3 4 5 幀
                    if(this.index>5)
                        
    this.index=3;
                }
                
    //取出當(dāng)前幀的坐標(biāo)
                this.frame=frames[this.index];
                
                
    //當(dāng)前幀在大圖中的位置
                this.sx=this.frame[0];
                
    this.sy=this.frame[1];
                
    this.sw=this.frame[2];
                
    this.sh=this.frame[3];
                
                
    //當(dāng)前幀大小
                this.dw=this.frame[2];
                
    this.dh=this.frame[3];
                
                
    //改變 x 坐標(biāo)
                this.dx=this.dx+this.delta;
                
    //左邊緣檢測
                if(this.dx<0){
                    
    this.dx=0;
                    
    //轉(zhuǎn)向
                    this.delta=-this.delta;
                    
    this.dir_left=false;
                    
    this.index=3;
                }
                
    //右邊緣檢測
                if((this.dx+this.dw)>canvas.getAttribute("width")){
                    
    this.dx=canvas.getAttribute("width")-this.dw;
                    
    //轉(zhuǎn)向
                    this.delta=-this.delta;
                    
    this.dir_left=true;
                    
    this.index=0;
                }         
                
    this.dy=this.dy;//y 不移動
                

                
    this.index++;
                
    this.last_update=now;
            }
        }
        
        function animate(){
            
    //停止動畫
            stop();
            
    //移動速度
            var delta=parseInt(document.getElementById('txt4').value);
            
    //每秒繪制多少次
            var fps=parseInt(document.getElementById('txt5').value);
            
    //比例
            var scale=parseInt(document.getElementById('txt6').value);
            
            
    //畫布對象
            var canvas=document.getElementById("canvas3")
            
    //獲取上下文對象
            var ctx = canvas.getContext("2d");
            
    //清空畫布
            ctx.clearRect(0,0,canvas.getAttribute("width"),canvas.getAttribute("height"));
            
            var img
    =new Image();
            img.src
    ="http://images.cnblogs.com/cnblogs_com/myqiao/html5/sprite.gif";

            var sprite
    =new Sprite(120,150,delta,fps);
            interval 
    = setInterval(function(){
                
    //清空畫布
                ctx.clearRect(0,0,canvas.getAttribute("width"),canvas.getAttribute("height"));
                
    //更新數(shù)據(jù)
                sprite.update(canvas);
                
    //保存狀態(tài)
                ctx.save();
                
    //移動坐標(biāo)
                ctx.translate(sprite.dx,sprite.dy);
                ctx.scale(scale,scale);
                ctx.drawImage(img,sprite.sx,sprite.sy,sprite.sw,sprite.sh,
    0,0,sprite.dw,sprite.dh);
                
    //恢復(fù)狀態(tài)
                ctx.restore();
            },
    1);
            
        }
        
    </script>

    {{{ 你的瀏覽器不支持 <canvas>標(biāo)簽,請使用 Chrome 瀏覽器 或者 FireFox 瀏覽器
    幀數(shù):
    速度:
    比例:
    }}}

     

     

     

     


    //==========================================

    posted on 2010-10-08 00:14 左洸 閱讀(2519) 評論(1)  編輯  收藏 所屬分類: HTML5

    FeedBack:
    # re: HTML5邊玩邊學(xué)(7):動畫初步 之 飛舞的精靈
    2010-10-08 00:23 | 別玩HTML5了,閑的蛋疼
    呵呵,沒仔細(xì)看樓主的文章內(nèi)容,看了標(biāo)題HTML5就煩了,如果樓主改個標(biāo)題似乎更好,一個2d編程應(yīng)用系列之類的。我最近也在弄qt,可以仔細(xì)的看看樓主的文章,看看能否舉一反三,呵呵  回復(fù)  更多評論
      
    主站蜘蛛池模板: 亚洲伦理一二三四| 亚洲精品无码AV中文字幕电影网站| 99久久人妻精品免费一区| 国内精品久久久久影院免费| 国产99久久久久久免费看| 在线播放国产不卡免费视频| 一本久久免费视频| 日本高清免费中文在线看| 日韩毛片一区视频免费| 中文字幕在线成人免费看| 三级网站在线免费观看| 久久国产乱子免费精品| 99久久免费观看| 日本亚洲免费无线码| 日韩高清在线高清免费| 免费欧洲美女牲交视频| 亚洲天堂免费在线视频| 亚洲精品无码AV人在线播放| 久久久综合亚洲色一区二区三区| 亚洲一区二区影院| ASS亚洲熟妇毛茸茸PICS| 亚洲女女女同性video| 特级做a爰片毛片免费看| 久久久免费观成人影院| 99久热只有精品视频免费看| 亚洲欧洲免费无码| 国产乱子伦精品免费女| 亚洲熟妇中文字幕五十中出| 亚洲人成电影福利在线播放| 亚洲一级毛片在线播放| 羞羞网站免费观看| 国产午夜无码精品免费看动漫| 在线观看永久免费| 日韩视频免费一区二区三区| 久久久久久久亚洲精品| 亚洲一级二级三级不卡| 亚洲综合久久精品无码色欲 | 亚洲国产中文v高清在线观看| 亚洲乱色熟女一区二区三区丝袜| 中文字幕亚洲色图| 亚洲精华国产精华精华液好用|