写在前面
之前没有写过canvas游戏,所以是以网上的成品为参考,自己边研究以后边独立写出来的,中间的一些bug也是独立思考解决的。
代码的整体风格并不是自己的风格,但是,为了学会,就先写着学着吧。
canvas的代码生成
var myGameArea={
canvas:document.createElement("canvas"),
start:function(){
this.canvas.width=900;
this.canvas.height=500;
document.body.insertBefore(this.canvas,document.body.childNodes[0]);
this.context=this.canvas.getContext("2d");
},
clear:function(){
this.context.fillStyle="black";
this.context.fillRect(0,0,this.canvas.width,this.canvas.height);
}
}
myGameArea是游戏区域,是一个对象。start()是它的初始化函数,并设置了canvas是高度和宽度,并且要注意将document生成 (create)的canvas加入到页面中,用到了insertBefore(arg1,arg2),arg1为要插入的对象,arg2为被插入的对象。
要在 canvas里作画,需要作画工具,通过canvas.getContext(“2d”)生成。它可以直接通过fillStyle来设置画面的填充颜色,和fillRect来做一个填充矩形。
游戏角色的声明
var bricks=[];
var player;
var paddle;
var brick_width=60;
var brick_height=40;
bricks[]为砖块;player为运动的球;paddle为玩家控制的挡球板;而brick_width为砖块的宽度,brick_height 为砖块的高度。
对象生成函数(类似于Java里的类(class))
function box(x,y,width,height,color,speed){
this.width=width;
this.height=height;
this.x=x;
this.y=y;
this.speed=speed;
theta=Math.PI/2+Math.random()*Math.PI;
this.speedX=this.speed*Math.sin(theta);
this.speedY=this.speed*Math.cos(theta);
this.show=function(){
ctx=myGameArea.context;
ctx.fillStyle=color;
myGameArea.context.fillRect(this.x,this.y,this.width,this.height);
}
this.update=function(){
this.x+=this.speedX;
this.y+=this.speedY;
if(this.x>(myGameArea.canvas.width-this.width)||this.x<0){
this.speedX*=-1;
}
if(this.y+this.height>myGameArea.canvas.height||this.y<0){
this.speedY*=-1;
}
if(this.y+this.height>paddle.y&&this.x+this.width>paddle.x&&this.x<paddle.x+paddle.width){
this.speedY*=-1;
}
if(this.y+this.height>myGameArea.canvas.height){
clearInterval(myGameArea.interval);
}
}
this.collision=function(obj){
if(this.y<(obj.y+obj.height)&&this.y>obj.y&&this.x>obj.x&&this.x<(obj.x+obj.width)){
this.speedY*=-1;
return true;
}
return false;
}
}
几个形参的解释:x和y分别为对象在canvas里的位置,width和height为其宽度和高度,而color为其颜色,speed为其运动速度(对于要求静止的物体,可以设speed为0,或者省略改参数)。
而this关键字将参数依附到对象上。show()函数为在canvas里显示,update()函数为更新位置,几个if用于判断对象的碰撞并反弹,其反弹原理为在发生竖直碰撞时,速度的水平分量取反,在发送水平碰撞时,速度的竖直分量取反。
游戏更新
function updateGame(){
myGameArea.clear();
for (var i = bricks.length - 1; i >= 0; i--) {
bricks[i].show();
if(player.collision(bricks[i])){
bricks.splice(i,1);
};
};
player.update();
player.show();
paddle.move();
paddle.show();
}
每一帧要清屏;反弹球去和每个砖块检测是否发送碰撞,如果发生了碰撞,该砖块就被从bricks[]中删掉,在下一帧中就看不到了;反弹球player进行更新(update)和显示(show)。
游戏开始
function startGame(){
// player=new box(myGameArea.canvas.width/2,myGameArea.canvas.height-50,30,30,"green",1);
player=new box(450,400,30,30,"green",4);
paddle=new box(300,470,300,20,"yellow",0);
myGameArea.start();
this.arrange=function(){
var xoff=0;
var yoff=0;
for(yoff=0;yoff<myGameArea.canvas.height/3;yoff+=(brick_height+10)){
xoff=0;
for(xoff=0;xoff<myGameArea.canvas.width;xoff+=brick_width+10){
var new_box=new box(xoff,yoff,brick_width,brick_height,"red");
bricks.push(new_box);
}
}
}
this.arrange();
}
player和paddle要在myGameArea.start()之前要进行实例化,因为start()里引用了它们的函数,否则会报错。arrange()则是为了用两层for循环的嵌套来排列砖块。
遗留问题
event的用法还是很蛋疼。