接着上一篇讲,在上一篇中呢,我已经使用Canvas绘制出了我们游戏的主角,姑且叫它“小嘴”吧,因为只有嘴巴,嘿嘿,我还添了眼睛。
在这一篇中呢,就实现物体的移动和动画播放(一直张开嘴吧关闭嘴巴的动画,很饥渴的样子)。
如何设置按键响应这个问题。
那么如何设置呢?
我们可以通过在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 οnkeydοwn="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 οnkeydοwn="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);
}
}
游戏截图:
下一篇,做游戏主角和墙壁的碰撞检测,欢迎交流,谢谢.代码粗糙,希望各位朋友指导小弟,谢谢。