HTML5吃豆豆游戏开发实战(二)主角移动和动画循环设置

      接着上一篇讲,在上一篇中呢,我已经使用Canvas绘制出了我们游戏的主角,姑且叫它“小嘴”吧,因为只有嘴巴,嘿嘿,我还添了眼睛。

      在这一篇中呢,就实现物体的移动和动画播放(一直张开嘴吧关闭嘴巴的动画,很饥渴的样子)。

      1. 要做玩家和游戏的交互,当然要考虑--如何设置按键响应这个问题

      那么如何设置呢?

      我们可以通过在body标签里面添加事件来响应用户的操作:

      技术分享

        由于我们要用W,A,S,D来控制物体的上下移动,这是按键响应,于是我们选择用onkeydown事件。

        onkeydown 事件:事件会在用户按下键盘按键时触发。

         技术分享

          (上面的图片解释来自:http://www.w3school.com.cn/jsref/event_onkeydown.asp)

         请注意:浏览器差异,IE使用event.KeyCode取回被按下的字符(ASCII),而火狐和欧朋使用event.Which.

        2.动画:计时器和游戏循环

           动画实际上就是绘制物体、擦掉,再重绘。

           我们使用setInterval(functionName,timeInerval)告诉浏览器,每隔一个固定的时间间隔就调用一次给定的函数,直到函数clearInterval( )被调用.如果我们要停止动画播放(比如游戏暂停或者结束),那就调用clearInterval( )函数。

      下面是源代码:(可直接复制运行)

      

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>物体移动简单演示</title>
</head>
<!--注意在body这里添加按键响应事件,引号内为函数名-->
<body onkeydown="test()">
<h1>小球上下移动</h1>
<canvas id="test" width="1200px" height="600px" style="background-color: white"></canvas>
<script type="text/javascript">
    //得到画布
    var can = document.getElementById("test");
    var cxt = can.getContext("2d");
    //游戏世界原点坐标
    var Ox = 162;
    var Oy = 0;
    //窗口宽高
    var WinWidth = 900;
    var WinHeight = 500;
    //四周边界值
    var WinMaxX = Ox + WinWidth;
    var WinMinX = Ox;
    var WinMaxY = Oy + WinHeight;
    var WinMinY = Oy;
    //小球圆心坐标x,y
    var x = 30 + Ox;
    var y = 30;
    //小球半径
    var radius = 20;
    var dir = 0;
    var ball = new Ball(x,y,dir,radius,3);//实例化小球对象
    var state = 0;//全局变量,控制张嘴闭嘴动画切换
    //墙壁数组,大小为3
    //注意js里面定义数组并且初始化的方法!
    //walls按x从小到大排序
    var walls = [new Wall(262,200,100,30),new Wall(662,60,30,400),new Wall(762,300,200,30)];

    //动画循环
    setInterval("drawBall(ball)",100);
    //setInterval( function(){drawBall(ball),1000});
    //小球类
    //注意js里面类的定义方法,直接类加函数参数的形式,就相当于定义了,然后里面直接this.xx=xx_,很高效
    //参数:x,y坐标,球的方向,球的半径,运动速度
    function Ball(x_,y_,dir_,r_,sp_)
    {

        this.x = x_;
        this.y = y_;
        this.dir = dir_;
        this.r = r_;    //灰色表示还没用
        this.sp = sp_;
        //定义上下左右:0,1,2,3
        this.moveUp = function()
        {
            this.y -= this.sp;
            this.dir = 0;
        }
        this.moveDown = function()
        {
            this.y += this.sp;
            this.dir = 1;
        }
        this.moveLeft = function()
        {
            this.x -= this.sp;
            this.dir = 2;
        }
        this.moveRight = function()
        {
            this.x += this.sp;
            this.dir = 3;
        }
        //获得小球的坐标
        this.getX = function()
        {
            return this.x;
        }
        this.getY = function()
        {
            return this.y;
        }
        //获得球的各个方向的边界值
        this.getMaxX = function()
        {
            return this.x + this.r;
        }
        this.getMaxY = function()
        {
            return this.y + this.r;
        }
        /**
         * @return {number}
         */
        this.getMinX = function()
        {
           return this.x - this.r;
        }
        /**
         * @return {number}
         */
        this.getMinY = function()
        {
            return this.y - this.r;
        }


    }
    function Wall(x_,y_,width_,height_)
    {
        this.x = x_;
        this.y = y_;
        this.width = width_;
        this.height = height_;
        this.getX = function()
        {
            return this.x;
        }
        this.getY = function()
        {
            return this.y;
        }
        this.getWidth = function()
        {
            return this.width;
        }
        this.getHeight = function()
        {
            return this.height;
        }
    }
    function drawBall(ball_)
    {
        FreshWindow(Ox,Oy,WinWidth,WinHeight);
        switch (ball_.dir)
        {
            case 0:
                drawBall_UpOrDown(ball_,true);
                break;
            case 1:
                drawBall_UpOrDown(ball_,false);
                break;
            case 2:
                drawBall_RightOrLeft(ball_,false);
                break;
            case  3:
                drawBall_RightOrLeft(ball_,true);
                break;
            default :
                break;
        }
    }
    function drawWall(walls_)
    {
       // cxt.fillStyle="#000000";
      //  document.write(walls_[1].x);
        for(var i=0;i<walls_.length;i++)
        {
            cxt.strokeRect(walls_[i].x,walls_[i].y,walls_[i].width,walls_[i].height);
        }
    }
    function FreshWindow(x,y,width,height)
    {
        //清理画布
        cxt.clearRect(x,y,width,height);
        cxt.strokeRect(x,y,width,height);
        drawWall(walls);
    }

    //往右/左的样子
    function drawBall_RightOrLeft(ball,isRight)
    {

        //document.write(state);
        //画眼睛,眼睛是公共的
        //画眼睛-外圈
        var eyeX;
        if(isRight == true)     //右
            eyeX = ball.x - 5;
        else eyeX = ball.x + 5;//左
        var eyeY = ball.y-8;
        var eyeR = 6;//目前限定死这个
        cxt.beginPath();
        cxt.fillStyle="#000000";
        cxt.arc(eyeX,eyeY,eyeR,0,Math.PI * 2,false);
        cxt.fill();
        cxt.closePath();
        //画眼睛-眼球
        var qiuR = eyeR / 2;
        cxt.beginPath();
        cxt.fillStyle="#FF0000";
        cxt.arc(eyeX,eyeY,qiuR,0,Math.PI * 2,false);
        cxt.fill();
        cxt.closePath();
        switch(state)
        {
            //张嘴
            case 1:
                //画红球
                cxt.beginPath();
                cxt.fillStyle="#FF0000";
                //嘴巴大小为90°
                //画圆弧--脸
                if(isRight)
                cxt.arc(ball.x,ball.y,radius,1/4 * Math.PI,3/2 * Math.PI + 1/4 * Math.PI,false);
                    else
                    cxt.arc(ball.x,ball.y,radius,3/4 * Math.PI, Math.PI + 1/4 * Math.PI,true);
                cxt.stroke();
                cxt.closePath();
                cxt.beginPath();
                //画嘴巴
                var ax = 0,ay = 0;
                var bx = 0,by = 0;
                var temp = radius * Math.sqrt(2)/2;
                if(isRight)
                ax = ball.x + temp;
                    else
                        ax = ball.x - temp;
                ay = ball.y - temp;
                bx = ax;
                by = ball.y + temp;
                cxt.moveTo(ball.x,ball.y);
                cxt.lineTo(ax,ay);
                cxt.moveTo(ball.x,ball.y);
                cxt.lineTo(bx,by);
                cxt.closePath();
                cxt.stroke();
                state = 0;
                break;
            //闭嘴
            case 0:
                //画圆弧--脸
                cxt.beginPath();
                cxt.arc(ball.x,ball.y,radius,0,Math.PI * 2,false);
                cxt.stroke();
                cxt.closePath();
                //从圆心到嘴巴末点的连线
                cxt.beginPath();
                cxt.moveTo(ball.x,ball.y);
                if(isRight)
                cxt.lineTo(ball.x + radius,ball.y);
                    else
                    cxt.lineTo(ball.x - radius,ball.y);
                cxt.stroke();
                cxt.closePath();
                state = 1;
                break;
            default :
                break;
        }
    }

    //往上/下的样子
    function drawBall_UpOrDown(ball,isUp)
    {

            //document.write(state);
            //画眼睛,眼睛是公共的
            //画眼睛-外圈
            var eyeX = ball.x - 5;
            var eyeY = ball.y + 8;
            if(!isUp)
            {
                eyeX = ball.x + 5;
                eyeY = ball.y - 8;
            }
            var eyeR = 6;//目前限定死这个
            cxt.beginPath();
            cxt.fillStyle="#000000";
            cxt.arc(eyeX,eyeY,eyeR,0,Math.PI * 2,false);
            cxt.fill();
            cxt.closePath();
            //画眼睛-眼球
            var qiuR = eyeR / 2;
            cxt.beginPath();
            cxt.fillStyle="#FF0000";
            cxt.arc(eyeX,eyeY,qiuR,0,Math.PI * 2,false);
            cxt.fill();
            cxt.closePath();
            switch(state)
            {
                //张嘴
                case 1:
                    //画红球
                    cxt.beginPath();
                    cxt.fillStyle="#FF0000";
                    //嘴巴大小为90°
                    //画圆弧--脸
                    if(!isUp)
                        cxt.arc(ball.x,ball.y,radius,1/4 * Math.PI ,3/4 * Math.PI,true);
                        else
                            cxt.arc(ball.x,ball.y,radius,Math.PI +  1/4 * Math.PI,3/2 * Math.PI+  1/4 * Math.PI,true);
                    cxt.stroke();
                    cxt.closePath();
                    cxt.beginPath();
                    //画嘴巴
                    var ax = 0,ay = 0;
                    var bx = 0,by = 0;
                    var temp = radius * Math.sqrt(2)/2;
                    ax = ball.x - temp;
                    ay = ball.y - temp;
                    by = ay;
                    bx = ball.x + temp;
                        if(!isUp)
                        {
                            ax = ball.x + temp;
                            ay = ball.y + temp;
                            by = ay;
                            bx = ball.x - temp;
                        }
                    cxt.moveTo(ball.x,ball.y);
                    cxt.lineTo(ax,ay);
                    cxt.moveTo(ball.x,ball.y);
                    cxt.lineTo(bx,by);
                    cxt.closePath();
                    cxt.stroke();
                    state = 0;
                    break;
                //闭嘴
                case 0:
                    //画圆弧--脸
                    cxt.beginPath();
                    cxt.arc(ball.x,ball.y,radius,0,Math.PI * 2,false);
                    cxt.stroke();
                    cxt.closePath();
                    //从圆心到嘴巴末点的连线
                    cxt.beginPath();
                    cxt.moveTo(ball.x,ball.y);
                    if(!isUp)
                        cxt.lineTo(ball.x ,ball.y + radius);
                        else
                            cxt.lineTo(ball.x ,ball.y- radius);
                    cxt.stroke();
                    cxt.closePath();
                    state = 1;
                    break;
                default :
                    break;
            }


    }
    function test()
    {
        //清理画布
        //cxt.clearRect(0,0,400,300);
        var code = event.keyCode;//对应字母的ascii
        //alert(code);
        switch(code)
        {
            //数字是ASCII码,记不住的话可以对照ASCII码表
            //上

            case 87:
                    if(ball.getMinY() >= WinMinY)
                    ball.moveUp();
               break;
            //下
            case 83:
                    if(ball.getMaxY() <= WinMaxY)
                    ball.moveDown();
                break;
            //左
            case 65:
                    if(ball.getMinX() >= WinMinX)
                    ball.moveLeft();
                break;
            //右
            case 68:
                    if(ball.getMaxX() <= WinMaxX )
                    ball.moveRight();
                break;

            default :break;
        }

    }
</script>
</body>
</html>

注意,给像和我一样的新手一个免费提示,这样写,代码越来越多,越来越乱,整个结构会越来越不清晰,于是,我把JS分割出来,这很有必要。

方法:新建xxx.js,将要移植的代码贴入,然后使用

<script type="text/javascript" src="Ball.js"></script>

将脚本引入即可。

修改过后的工程如下:

1.物体移动demo.html

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>物体移动简单演示</title>
</head>
<!--注意在body这里添加按键响应事件,引号内为函数名-->
<body onkeydown="test()">
<h1>小球上下移动</h1>
<canvas id="test" width="1200px" height="600px" style="background-color: white"></canvas>
<!--把Ball.js和Wall.js引入本页面-->
<script type="text/javascript" src="Ball.js"></script>
<script type="text/javascript" src="Wall.js"></script>
<script type="text/javascript">
    //得到画布
    var can = document.getElementById("test");
    var cxt = can.getContext("2d");
    //游戏世界原点坐标
    var Ox = 162;
    var Oy = 0;dddddd
    //窗口宽高
    var WinWidth = 900;
    var WinHeight = 500;
    //四周边界值
    var WinMaxX = Ox + WinWidth;
    var WinMinX = Ox;
    var WinMaxY = Oy + WinHeight;
    var WinMinY = Oy;
    //小球圆心坐标x,y
    var x = 30 + Ox;
    var y = 30;
    //小球半径
    var radius = 20;
    var dir = 0;
    var ball = new Ball(x,y,dir,radius,3);//实例化小球对象
    var state = 0;//全局变量,控制张嘴闭嘴动画切换
    //墙壁数组,大小为3
    //注意js里面定义数组并且初始化的方法!
    //walls按x从小到大排序
    var walls = [new Wall(262,200,100,30),new Wall(662,60,30,400),new Wall(762,300,200,30)];

    //动画循环
    setInterval("drawBall(ball)",100);
    //setInterval( function(){drawBall(ball),1000});
    function FreshWindow(x,y,width,height)
    {
        //清理画布
        cxt.clearRect(x,y,width,height);
        cxt.strokeRect(x,y,width,height);
        drawWall(walls);
    }
    function test()
    {
        //清理画布
        //cxt.clearRect(0,0,400,300);
        var code = event.keyCode;//对应字母的ascii
        //alert(code);
        switch(code)
        {
            //数字是ASCII码,记不住的话可以对照ASCII码表
            //上

            case 87:
                    if(ball.getMinY() >= WinMinY)
                    ball.moveUp();
               break;
            //下
            case 83:
                    if(ball.getMaxY() <= WinMaxY)
                    ball.moveDown();
                break;
            //左
            case 65:
                    if(ball.getMinX() >= WinMinX)
                    ball.moveLeft();
                break;
            //右
            case 68:
                    if(ball.getMaxX() <= WinMaxX )
                    ball.moveRight();
                break;

            default :break;
        }

    }
</script>
</body>
</html>

2.Ball.js

//小球类
//注意js里面类的定义方法,直接类加函数参数的形式,就相当于定义了,然后里面直接this.xx=xx_,很高效
//参数:x,y坐标,球的方向,球的半径,运动速度
function Ball(x_,y_,dir_,r_,sp_)
{

    this.x = x_;
    this.y = y_;
    this.dir = dir_;
    this.r = r_;    //灰色表示还没用
    this.sp = sp_;
    //定义上下左右:0,1,2,3
    this.moveUp = function()
    {
        this.y -= this.sp;
        this.dir = 0;
    }
    this.moveDown = function()
    {
        this.y += this.sp;
        this.dir = 1;
    }
    this.moveLeft = function()
    {
        this.x -= this.sp;
        this.dir = 2;
    }
    this.moveRight = function()
    {
        this.x += this.sp;
        this.dir = 3;
    }
    //获得小球的坐标
    this.getX = function()
    {
        return this.x;
    }
    this.getY = function()
    {
        return this.y;
    }
    //获得球的各个方向的边界值
    this.getMaxX = function()
    {
        return this.x + this.r;
    }
    this.getMaxY = function()
    {
        return this.y + this.r;
    }
    /**
     * @return {number}
     */
    this.getMinX = function()
    {
        return this.x - this.r;
    }
    /**
     * @return {number}
     */
    this.getMinY = function()
    {
        return this.y - this.r;
    }


}
function drawBall(ball_)
{
    FreshWindow(Ox,Oy,WinWidth,WinHeight);
    switch (ball_.dir)
    {
        case 0:
            drawBall_UpOrDown(ball_,true);
            break;
        case 1:
            drawBall_UpOrDown(ball_,false);
            break;
        case 2:
            drawBall_RightOrLeft(ball_,false);
            break;
        case  3:
            drawBall_RightOrLeft(ball_,true);
            break;
        default :
            break;
    }
}
//往右/左的样子
function drawBall_RightOrLeft(ball,isRight)
{

    //document.write(state);
    //画眼睛,眼睛是公共的
    //画眼睛-外圈
    var eyeX;
    if(isRight == true)     //右
        eyeX = ball.x - 5;
    else eyeX = ball.x + 5;//左
    var eyeY = ball.y-8;
    var eyeR = 6;//目前限定死这个
    cxt.beginPath();
    cxt.fillStyle="#000000";
    cxt.arc(eyeX,eyeY,eyeR,0,Math.PI * 2,false);
    cxt.fill();
    cxt.closePath();
    //画眼睛-眼球
    var qiuR = eyeR / 2;
    cxt.beginPath();
    cxt.fillStyle="#FF0000";
    cxt.arc(eyeX,eyeY,qiuR,0,Math.PI * 2,false);
    cxt.fill();
    cxt.closePath();
    switch(state)
    {
        //张嘴
        case 1:
            //画红球
            cxt.beginPath();
            cxt.fillStyle="#FF0000";
            //嘴巴大小为90°
            //画圆弧--脸
            if(isRight)
                cxt.arc(ball.x,ball.y,radius,1/4 * Math.PI,3/2 * Math.PI + 1/4 * Math.PI,false);
            else
                cxt.arc(ball.x,ball.y,radius,3/4 * Math.PI, Math.PI + 1/4 * Math.PI,true);
            cxt.stroke();
            cxt.closePath();
            cxt.beginPath();
            //画嘴巴
            var ax = 0,ay = 0;
            var bx = 0,by = 0;
            var temp = radius * Math.sqrt(2)/2;
            if(isRight)
                ax = ball.x + temp;
            else
                ax = ball.x - temp;
            ay = ball.y - temp;
            bx = ax;
            by = ball.y + temp;
            cxt.moveTo(ball.x,ball.y);
            cxt.lineTo(ax,ay);
            cxt.moveTo(ball.x,ball.y);
            cxt.lineTo(bx,by);
            cxt.closePath();
            cxt.stroke();
            state = 0;
            break;
        //闭嘴
        case 0:
            //画圆弧--脸
            cxt.beginPath();
            cxt.arc(ball.x,ball.y,radius,0,Math.PI * 2,false);
            cxt.stroke();
            cxt.closePath();
            //从圆心到嘴巴末点的连线
            cxt.beginPath();
            cxt.moveTo(ball.x,ball.y);
            if(isRight)
                cxt.lineTo(ball.x + radius,ball.y);
            else
                cxt.lineTo(ball.x - radius,ball.y);
            cxt.stroke();
            cxt.closePath();
            state = 1;
            break;
        default :
            break;
    }
}

//往上/下的样子
function drawBall_UpOrDown(ball,isUp)
{

    //document.write(state);
    //画眼睛,眼睛是公共的
    //画眼睛-外圈
    var eyeX = ball.x - 5;
    var eyeY = ball.y + 8;
    if(!isUp)
    {
        eyeX = ball.x + 5;
        eyeY = ball.y - 8;
    }
    var eyeR = 6;//目前限定死这个
    cxt.beginPath();
    cxt.fillStyle="#000000";
    cxt.arc(eyeX,eyeY,eyeR,0,Math.PI * 2,false);
    cxt.fill();
    cxt.closePath();
    //画眼睛-眼球
    var qiuR = eyeR / 2;
    cxt.beginPath();
    cxt.fillStyle="#FF0000";
    cxt.arc(eyeX,eyeY,qiuR,0,Math.PI * 2,false);
    cxt.fill();
    cxt.closePath();
    switch(state)
    {
        //张嘴
        case 1:
            //画红球
            cxt.beginPath();
            cxt.fillStyle="#FF0000";
            //嘴巴大小为90°
            //画圆弧--脸
            if(!isUp)
                cxt.arc(ball.x,ball.y,radius,1/4 * Math.PI ,3/4 * Math.PI,true);
            else
                cxt.arc(ball.x,ball.y,radius,Math.PI +  1/4 * Math.PI,3/2 * Math.PI+  1/4 * Math.PI,true);
            cxt.stroke();
            cxt.closePath();
            cxt.beginPath();
            //画嘴巴
            var ax = 0,ay = 0;
            var bx = 0,by = 0;
            var temp = radius * Math.sqrt(2)/2;
            ax = ball.x - temp;
            ay = ball.y - temp;
            by = ay;
            bx = ball.x + temp;
            if(!isUp)
            {
                ax = ball.x + temp;
                ay = ball.y + temp;
                by = ay;
                bx = ball.x - temp;
            }
            cxt.moveTo(ball.x,ball.y);
            cxt.lineTo(ax,ay);
            cxt.moveTo(ball.x,ball.y);
            cxt.lineTo(bx,by);
            cxt.closePath();
            cxt.stroke();
            state = 0;
            break;
        //闭嘴
        case 0:
            //画圆弧--脸
            cxt.beginPath();
            cxt.arc(ball.x,ball.y,radius,0,Math.PI * 2,false);
            cxt.stroke();
            cxt.closePath();
            //从圆心到嘴巴末点的连线
            cxt.beginPath();
            cxt.moveTo(ball.x,ball.y);
            if(!isUp)
                cxt.lineTo(ball.x ,ball.y + radius);
            else
                cxt.lineTo(ball.x ,ball.y- radius);
            cxt.stroke();
            cxt.closePath();
            state = 1;
            break;
        default :
            break;
    }


}


3.Wall.js

function Wall(x_,y_,width_,height_)
{
    this.x = x_;
    this.y = y_;
    this.width = width_;
    this.height = height_;
    this.getX = function()
    {
        return this.x;
    }
    this.getY = function()
    {
        return this.y;
    }
    this.getWidth = function()
    {
        return this.width;
    }
    this.getHeight = function()
    {
        return this.height;
    }
}
function drawWall(walls_)
{
    // cxt.fillStyle="#000000";
    //  document.write(walls_[1].x);
    for(var i=0;i<walls_.length;i++)
    {
        cxt.strokeRect(walls_[i].x,walls_[i].y,walls_[i].width,walls_[i].height);
    }
}

游戏截图:


技术分享



下一篇,做游戏主角和墙壁的碰撞检测,欢迎交流,谢谢.代码粗糙,希望各位朋友指导小弟,谢谢。




郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。