>웹 프론트엔드 >H5 튜토리얼 >HTML5로 놀면서 배우기(7) - 애니메이션의 시작: 날아다니는 엘프

HTML5로 놀면서 배우기(7) - 애니메이션의 시작: 날아다니는 엘프

黄舟
黄舟원래의
2017-03-29 15:10:141196검색

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. 캔버스 지우기

c. 그래픽 그리기

d. a단계로 돌아갑니다

물론 이것은 가장 간단한 과정입니다. Framework. 복잡한 애니메이션을 구현하려면 로컬 지우기, 충돌 감지 등과 같은 더 많은 문제를 고려해야 할 수도 있습니다.

또한 그리는 과정에서 제어해야 하는 속도는 두 가지가 있습니다.

첫 번째는 그리기 속도, 즉 초당 몇 번(프레임)이 그려지는지, 또는 매번 프레임이 일시 중지되는 시간이라고 말할 수도 있습니다. 애니메이션이 프레임마다 동일하게 보이지만 위치가 다른 경우 이 속도는 거의 영향을 미치지 않습니다.

두 번째 도형이 움직이는 속도입니다.

따라서 이 두 속도를 혼동하지 마세요. 빠르게 그릴수록 애니메이션이 더 부드러워진다는 의미일 뿐 이미지가 더 빠르게 움직이는 것은 아닙니다.

HTML5를 사용하여 애니메이션을 그리는 것은 기본적으로 위와 같은 과정이지만, 두 가지 사항에 주의해야 합니다.

1. , 우리는 종종 객체의 상태를 변경하므로 그래픽을 그리기 전후에 상태를 저장하고 복원하는 것을 잊지 마세요. 상태는 이전 글 "HTML5를 하면서 배우기(6):오토봇, 변신...》

2. 그리기 동작 전체를 타이머에 넣어야 하는데, 그렇지 않으면 전체 브라우저가 응답하지 않게 됩니다. Javascript에는

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

라는 두 가지 타이머 메소드가 있습니다. 이 두 메소드를 소개했습니다. 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.