ホームページ >ウェブフロントエンド >H5 チュートリアル >遊びながら学ぶHTML5(7) ~アニメーションのはじまり~空飛ぶエルフ~

遊びながら学ぶHTML5(7) ~アニメーションのはじまり~空飛ぶエルフ~

黄舟
黄舟オリジナル
2017-03-29 15:10:141198ブラウズ

1. HTML5 を選んだ理由

HTML5 遊びながら学ぶ この記事を始める前に、なぜ遊びながら学ぶ HTML5 なのかを説明したいと思います。なぜなら、HTML5 は新しいものだからです。私が注目を集めるために HTML5 を使用したことは認めます。「遊びながら学ぶ」シリーズのすべての記事を読むと、最初の 6 つの記事の内容は実際には HTML5 の学習であることがわかります。 2Dグラフィックスと画像プログラミングのメモ。

2D プログラミングを学びたい場合、実際には無数のプログラミング環境から選択できます。MFC と Delphi にはすべてグラフィックスおよび画像処理機能 (つまり GDI)、Java、.Net があり、オープン ソースをサポートしている場合は言うまでもなく、 GTK、QT、wxPython も良い選択です。Flash はさらに優れています。また、いくつかの人気のある携帯電話プラットフォームにも 2D モジュールが必要です。

2D プログラミングを学ぶために上記のプログラミング環境のいずれかを選択すると、その内容は基本的に同じであることがわかります: 線種、塗りつぶし、色、グラデーション、画像、組み合わせ、トリミング領域、変換など、多くのものも関数名はまったく同じです。結局のところ、それらの理論的根拠はグラフィックスです。

私たちが本当に学びたいことを見つけた後、プログラミング環境は実際には個人的な好みに基づいて最も使いやすいものを選択する単なるツールです。実際、私は Python プログラミング環境を好みますが、Python を使用すると、私と通信する人はあまり多くないと思いますし、マシンに Python ランタイムをインストールする人も多くないでしょう。

では、なぜ他のものではなく HTML5 を選ぶのでしょうか?まず第一に、JavaScript 構文は簡潔かつ柔軟であり、対応する関数ライブラリは小さいながらも十分であり、HTML5 Canvas タグの 2D パフォーマンス機能も要件を満たしており、Chrome ブラウザの実行速度も満足のいくものです。さらに、面倒な統合開発環境やランタイムをインストールする必要はありません。アイデアを実装し、その効果をネットワーク上に直接表示するために必要なのは、強化されたメモ帳とブラウザだけです。私たちは、自分の考えを他の人たちと共有するために記事を公開しているだけです。もちろん、プラットフォーム、フレームワーク、言語機能については、これらの関連性のないものが少ないほど良いのです。これが、私が HTML5 を選択した理由です。

それでは、タイトルの意味を誤解しないでください。このシリーズは HTML5 の学習ノートではなく、HTML5 を使用して知識コンテンツを示しているだけです。より注目すべきは知識とコンテンツそのものです。他のプログラミング環境で再現します。

2. 予備アニメーション

アニメーションは、単に順番に提示される連続した絵です。しかし、映画やテレビでは、これらの絵はあらかじめ用意されていますが、コンピュータープログラムでは、すべての瞬間の絵が実際に描かれます。一般的なプロセスは次のように説明できます:

a. グラフィックスのデータを少し変更します (座標、形状、色など)

b. グラフィックスを描画します

d.戻る ステップ a に進みます

もちろん、ここでは最も単純なプロセス フレームワークにすぎませんが、複雑なアニメーションを実装するには、ローカル クリアや衝突検出など、さらに多くの問題を考慮する必要がある場合があります。

さらに、描画プロセス中に制御する必要がある速度が 2 つあります:

1 つ目は描画速度、つまり 1 秒間に何回 (フレーム) 描画されるか、言い換えれば、どのくらいの時間で描画されるかです。フレームごとに一時停止されます。アニメーションがフレームごとに同じに見えるが、位置が異なる場合、この速度はほとんど影響しません。

2 番目のシェイプが移動する速度。

したがって、これら 2 つの速度を混同しないでください。描画が速いということは、アニメーションがよりスムーズであることを意味するだけで、画像の動きが速くなることを意味するわけではありません。

HTML5 を使用してアニメーションを描画する手順は基本的に上記のプロセスですが、次の 2 つの点に注意する必要があります:

1. グラフィックの描画を容易にするために、コンテキスト

状態 を変更することがよくあります。オブジェクトなので、Before/Afterグラフィックスを描画するときは、状態を保存して復元することを忘れないでください。状態がわからない場合は、以前の記事「遊びながら学ぶHTML5 (6): Autobots、Transformation」を参照してください。 ..." 2. 描画アクション全体を

タイマー

に入れる必要があります。そうしないと、ブラウザ全体が応答を失います。 Javascript には、次の 2 つのタイマー メソッドがあります。

setInterval(code,millisec) 和 setTimeout(code,millisec)
これら 2 つのメソッドを紹介しました。関連情報については、Google にアクセスしてください。


以下に、ブロックが上下に移動すると方向が変わる小さなアニメーションを示します。コードは次のとおりです。

基本动画



Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><canvas id="canvas1" width="250" height="300" style="background-color:black">

    你的浏览器不支持 Canvas 标签,请使用 Chrome 浏览器 或者 FireFox 浏览器

</canvas><br/>

帧数:<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(&#39;txt1&#39;).value);

        //每秒绘制多少次

        var fps=parseInt(document.getElementById(&#39;txt2&#39;).value);



        //画布对象

        var canvas=document.getElementById("canvas1")

        //获取上下文对象

        var ctx = canvas.getContext("2d");

        //设置颜色

        ctx.fillStyle="red";

        

        //方块的初始位置

        var x=100;var y=50;

        //方块的长度和宽度

        var w=30;var h=30;

        

        //开始动画

        interval = setInterval(function(){

            //改变 y 坐标

            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"));

            //保存状态

            ctx.save();

            //移动坐标

            ctx.translate(x,y);

            //重新绘制

            ctx.fillRect(0,0,w,h);

            //恢复状态

            ctx.restore();

        },1000/fps);

    }    

</script>

3. コードを再構成します

上記のコードは正常に動作しますが、主に次の点で多くの問題があります。

1. の位置を計算するコード。ブロックとそのブロックを描画するコードが混在、つまりロジックと

ビュー

が混在しており、基本的には展開できません

2、代码没办法复用,比如我们需要绘制多个不同的方块对象:起始位置、大小、颜色、速度各不相同,每一种情况都需要重写一遍。

下面我们重新组织一下代码,把方块的共同属性抽象出来,组成一个 Box 类,由这个 Box 类负责计算每一帧方块的位置,这样就可以解决上面两个问题了。代码如下:

重新组织代码



Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><canvas id="canvas2" width="250" height="300" style="background-color:black">

    你的浏览器不支持 Canvas 标签,请使用 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);

    }



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

    //重新组织代码

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

    //方块的构造函数

    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){

        //获取当前时间

        var now=(new Date()).getTime();

        //如果达到了延迟时间,则更新数据

        if((now-this.last_update)>this.delay){

        

            //改变 y 坐标

            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"));

        

        //创建多个方块对象

        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);

                //更新数据

                box.update(canvas);

                //保存状态

                ctx.save();

                //设置颜色

                ctx.fillStyle=box.color;

                //移动坐标

                ctx.translate(box.x,box.y);

                //重新绘制

                ctx.fillRect(0,0,box.w,box.h);

                //恢复状态

                ctx.restore();

            }

        },1);//尽可能快的循环

    }    

</script>

 

四、精灵登场

据说在很久远的年代,有多远我也不知道,可能是任天堂红白机是哪个年代吧,由于游戏机处理器的计算速度有限,所以专门设置了一个硬件用来处理角色图像的相关数据,这些数据可能包括:

1、计算当前的角色应该绘制哪一帧。上面我们的方块虽然在移动,但是始终都是一个样子;可是在游戏中,一个跑动的精灵,跑动动作是由很多幅连续的图像组成,我们需要知道现在应该绘制其中的哪一幅图像;

2、表现精灵动作的很多幅连续的图像通常是集中放置在一个大图中,我们需要计算当前绘制的那一幅,在大图中处于什么位置,并把它截取出来

上面说到这个硬件,曾经被叫做 Sprite 精灵。现如今,我们的处理器已经十分强大,不再需要 Sprite 这样的辅助硬件,但是这样的功能仍然需要,只不过用软件来实现罢了,所以,我们依然用 Sprite 来称呼游戏中的一个角色。

这里有一幅图像,他描绘了一个小精灵的飞行动作

 

下面我们将实现一个 Sprite 类,让他在浏览器里面飞起来。

精灵登场



Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--><canvas id="canvas3" width="250" height="300" style="background-color:black">

    你的浏览器不支持 &lt;canvas&gt;标签,请使用 Chrome 浏览器 或者 FireFox 浏览器

</canvas><br/>

帧数:<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){

        //获取当前时间

        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;

            }

            //取出当前帧的坐标

            this.frame=frames[this.index];

            

            //当前帧在大图中的位置

            this.sx=this.frame[0];

            this.sy=this.frame[1];

            this.sw=this.frame[2];

            this.sh=this.frame[3];

            

            //当前帧大小

            this.dw=this.frame[2];

            this.dh=this.frame[3];

            

            //改变 x 坐标

            this.dx=this.dx+this.delta;

            //左边缘检测

            if(this.dx<0){

                this.dx=0;

                //转向

                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;

                //转向

                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(&#39;txt4&#39;).value);

        //每秒绘制多少次

        var fps=parseInt(document.getElementById(&#39;txt5&#39;).value);

        //比例

        var scale=parseInt(document.getElementById(&#39;txt6&#39;).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"));

            //更新数据

            sprite.update(canvas);

            //保存状态

            ctx.save();

            //移动坐标

            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);

            //恢复状态

            ctx.restore();

        },1);

        

    }

    

</script>


以上が遊びながら学ぶHTML5(7) ~アニメーションのはじまり~空飛ぶエルフ~の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。