您的位置:首页 > Web前端 > HTML5

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

2015-03-31 11:17 711 查看
      接着上一篇讲,在上一篇中呢,我已经使用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);
}
}

游戏截图:



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


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐