终于效果图:
1. 使用html 5 的canvas 技术和javascript实现弹球游戏
总体流程图:
1.1 html5 canvas技术的使用
首先在html页面中定义画布。
<canvas bgcolor = "#FFF" id="gamePane" width="1000" height="500" tabindex="0"> Sorry, your browser doesn‘t support the HTML5 game. </canvas>
定义完画布之后就能够在javascript代码中对画布进行操作。
canvas = document.getElementById(‘gamePane‘);
ctx = canvas.getContext("2d");在画布中构绘图形。
         ballImg = new Image();
         ballImg.src = "/site_media/images/kkball.ico";
         ctx.drawImage(ballImg, ballX- radius, ballY-radius, 2*radius, 2*radius);1.2 javascript弹球游戏实现
使用canvas技术我们实现了弹球游戏的GUI界面,接下来是游戏功能逻辑。
1.2.1首先明白游戏功能:
A. 游戏元素: 弹球,砖块。挡板,道具。
B. 游戏開始, 球从挡板出发。碰撞到砖块或者游戏边界时会反弹,碰撞到砖块时砖块消失,假设砖块隐藏了道具,道具显示并下落,碰到挡板时会发挥道具效果。弹球碰到挡板时也会反弹,可是假设碰到下边界则会损失游戏生命。
C. 当砖块全然消失时进入下一关,随着关卡数添加。板的长度会减小。球的速度回加快。
D. 道具: 1. 使弹球速度乘以1.3;2. 使弹球速度除以1.3;3. 使板的长度乘以2。4. 使板的长度除以2;
1.2.2 画布的刷新
画布的刷新使用html中的定时器实现。每0.003秒调用一次draw。更新画面。
interval = setInterval(draw, 3);
用户通过鼠标进行交互,游戏还未開始时, 球和板的x坐标都会随鼠标x坐标变化。这时点击鼠标左键,球和板的x坐标不再变化。这时能够设置球执行方向。方向为鼠标所在位置。
游戏開始后,板x坐标随鼠标x坐标变化。
为鼠标点击和移动设置响应函数。
canvas.addEventListener(‘mousedown‘,onMouseDown, false); canvas.addEventListener(‘mousemove‘, padMove, false); canvas.addEventListener(‘mouseup‘, start, false);
鼠标事件响应函数。
//鼠标落下点击事件
function onMouseDown(e){
        if(isStart==0){
           isPressed = 1;
 }
}
    //鼠标移动点击事件
function padMove(e){
var x;
x = e.layerX;
x = x<padWidth/2?padWidth/2:x;
x = x>(worldWidth-padWidth/2)?(worldWidth-padWidth/2):x;
padX = x;
 
if(isStart==0){ //假设游戏还未開始,则须要又一次绘制板。假设游戏開始了,板的绘制在draw中完毕。
           if(isPressed == 0){
                    ballX = padX;
                    ctx.clearRect(0, worldHeight-padHeight-2*radius, worldWidth, 2*radius); //clear the pad                 
                    drawBall();
                    drawPad();
           }
}
}
 
//鼠标抬起事件函数,设置弹球角度,设置定时器定时刷新页面。
function start(e){
if(isStart==0){
           ballAngle = Math.atan((worldHeight- e.layerY)/(e.layerX - ballX));
           if(ballAngle > 0){
                    ballAngle = - ballAngle;
           }
           else{
                    ballAngle = Math.PI - ballAngle;
           }
 
 
           isStart =1;
 
           isPressed = 0;
 
           interval = setInterval(draw, 3);
}
}
1.2.4 弹球运动与碰撞检測
弹球位置更新。
ballX = ballX + ballSpeed * Math.cos(ballAngle);
         ballY = ballY + ballSpeed * Math.sin(ballAngle);球游戏边界碰撞检測。
//球碰撞到左右两边边界
if(ballX < radius || ballX > worldWidth - radius){
           ballAngle = Math.PI - ballAngle;
}
//球碰到上边界
if(ballY < radius){
           ballAngle = Math.PI*2 - ballAngle;
}
//球碰到下边界
if(ballY > worldHeight-radius){
//假设球未碰到板上。则游戏停止,推断生命是否用完,用完游戏结束
           if(ballX< padX-padWidth/2 || ballX > padX + padWidth/2){
                    ctx.clearRect(0,0,worldWidth,worldHeight-padHeight);
                    self.clearInterval(interval);
                    if(life>0){
                             drawInfo(1);
                             life = life -1;
                             reset();
 
}
                    else if(life ==0){
                             drawInfo(2);
                             getData();
 
                    }
                    return;
           }
//球碰到板上
           else{
                    ballAngle = Math.PI*2 - ballAngle;
           }
}
//推断砖块是否打完,假设打完进入下一关
if(count>= col*row){
           ctx.clearRect(0,0,worldWidth,worldHeight-padHeight);
 
           self.clearInterval(interval);
           newLevel();
           return;
         }
         1.2.5 弹球与砖块碰撞检測。       
每次弹球到达可能有砖块的那一层的时候。推断弹球位置所在砖块是否还在。假设还在。则消去它。同一时候推断其是否有道具。假设有。则创建道具。
function testCollision(){
//球的位置不可能有砖块
if(ballY > brickHeight * row){
           return;
}
//循环推断弹球在那一层
for(var i = row;i>0;i--){
           if((ballY-radius)<=(brickHeight*i)){
                   
          
                    if((ballY-radius)>(brickHeight*(i-1))){
                             var x = Math.floor(ballX/brickWidth);
 
                             if(bricks[i-1][x].isdisplay==0){
                                       continue;
                             }
                             else{
                                       bricks[i-1][x].isdisplay=0;
                                       ballAngle= Math.PI*2-ballAngle;
                                       score= score+100;
                                       count = count +1;
                //推断是否有道具
                                       if(bricks[i-1][x].tool!=0){
                                                var brickX = bricks[i-1][x].col * brickWidth;
                                                var brickY = bricks[i-1][x].row * brickHeight;
                                                var temp = new tool(brickX, brickY, bricks[i-1][x].tool);
                                                toolArray.push(temp);                                            }
                                       return;
                             }
 
                    }
                    else{
                             continue;
                    }
 
           }
           else
                    break;
}
}
         初始化时创建一个存放道具的Array。
toolArray = new Array();
if(bricks[i-1][x].tool!=0){
           var brickX = bricks[i-1][x].col * brickWidth;
           var brickY = bricks[i-1][x].row * brickHeight;
           var temp = new tool(brickX, brickY, bricks[i-1][x].tool);
    toolArray.push(temp);                                           
}每次碰到砖块时,推断砖块是否有道具,假设有道具就创建道具。将其放入数组。
砖块是否有道具及道具类型由随机数产生。
每次刷新画面时调用testTool函数。推断道具是否落究竟部。
假设落到板上则发挥效果。
function testTool(){
//循环遍历整张道具数组
for(var i = 0;i<toolArray.length;i++){
           console.log("tesetool", toolArray[i].type);
           var temp = toolArray[i];
//道具还未落究竟部
           if(temp.y<worldHeight-padHeight){
                    continue;
           }
           else{
    //道具落到板上,推断道具类型。发挥效果。
                    if(temp.x>=padX-padWidth/2 && temp.x<=padX+padWidth/2){
                             switch(temp.type){
                                       case 1:{
                                                if(ballSpeed<2.6)
                                                         ballSpeed=ballSpeed*1.3;
                                                console.log("tool", temp.type);
                                                break;
                                       }
                                       case 2:{
                                                if(ballSpeed>1.5)
                                                ballSpeed=ballSpeed/1.3;
                                                console.log("tool", temp.type);
                                                break;
                                       }
                                       case 3:{
                                                if(padWidth<200){
                                                         padWidth = padWidth *2;
                                                }
                                                console.log("tool", temp.type);
                                                break;
                                       }
                                       case 4:{
                                                if(padWidth>50)
                                                         padWidth=padWidth /2;
                                                console.log("tool", temp.type);
                                                break;
                                       }
                             }
 
 
                    }
 
                    toolArray.splice(i, 1);
 
 
           }
}
}var canvas;
var ctx;
var ballX = 500;
var ballY = 470;
var ballAngle = -Math.PI/2;
var radius = 20;
var ballSpeed = 2;
var padX = 500;  //挡板位置
var padWidth = 100;
var padHeight = 10;
var worldWidth;
var worldHeight;
var interval;
var score = 0;
var brickWidth = 100;
var brickHeight = 25;
var bricks;
var color;
var col = 10;
var row = 5;
var isStart = 0;
var time = 0;
var life = 3;
var isPressed = 0;
var level = 1;
var count = 0;
var ballImg;
var brickImg;
var padImg;
var tool1Img;
var tool2Img;
var tool3Img;
var tool4Img;
var toolArray;
var toolLength = 30;
var toolHeight = 30;
var isLoad = [0,0,0,0,0,0,0];
var loadInterval;
function brick(){
	this.col = 0;
	this.row = 0;
	this.isdisplay = 1;  //是否显示
	this.tool = 0;  //道具类型,0 表示无道具。
	this.color = "#000000"
}
//tool: 
//type:
//1: make the ball speed x1.3
//2: make the ball speed /1.3
//3: make the pad length twice
//4: make the pad length 1/2
function tool(x , y ,type){
	this.x = x;
	this.y = y;
	this.type = type;
}
function loadImage(){
	tool1Img = new Image();
	tool1Img.src = "/site_media/images/tool1.png";1
	tool1Img.addEventListener(‘load‘, function(){isLoad[0]=1}, false);
	tool2Img = new Image();
	tool2Img.src = "/site_media/images/tool2.png";
	tool2Img.addEventListener(‘load‘, function(){isLoad[1]=1}, false);
	tool3Img = new Image();
	tool3Img.src = "/site_media/images/tool3.png";
	tool3Img.addEventListener(‘load‘, function(){isLoad[2]=1}, false);
	tool4Img = new Image();
	tool4Img.src = "/site_media/images/tool4.png";
	tool4Img.addEventListener(‘load‘, function(){isLoad[3]=1}, false);
	padImg = new Image();
	padImg.src = "/site_media/images/pad.png";
	padImg.addEventListener(‘load‘, function(){isLoad[4]=1}, false);
	ballImg = new Image();
	ballImg.src = "/site_media/images/kkball.ico";
	ballImg.addEventListener(‘load‘, function(){isLoad[5]=1}, false);
	brickImg = new Image();
	brickImg.src = "/site_media/images/brick.ico";
	brickImg.addEventListener(‘load‘, function(){isLoad[6]=1}, false);
	//brickImg.addEventListener(‘load‘, init, false);
	loadInterval = setInterval(loadTest, 3);
}
//to test if all of the image is loaded
function loadTest(){
	var i;
	for(i=0;i<isLoad.length;i++){
		if(isLoad[i]==0){
			break;
		}
	}
	if(i>=isLoad.length){
		self.clearInterval(loadInterval);
		init();
	}
}
function GetRandomNum(Min,Max)
{   
	var Rand = Math.random();   
	console.log("Rand", Rand);
	if(Rand>0 && Rand<0.6){
		return 0;
	}
	else if(Rand<=0.7){
		return 1;
	}
	else if(Rand<=0.8){
		return 2;
	}
	else if(Rand<=0.9){
		return 3;
	}
	else if(Rand <=1){
		return 4;
	}
}   
function init(){  //init the game pane
	padWidth = 100;
	ballSpeed = 2;
	count = 0;
	isStart = 0;
	ballX = 500;
	ballY = 470;
	padX = 500;
	canvas = document.getElementById(‘gamePane‘);
	worldWidth = canvas.width;
	worldHeight = canvas.height;
	ctx = canvas.getContext("2d");
	toolArray = new Array();
	//create the array of the bricks
	//canvas.addEventListener(‘keydown‘, onKeyDown, true);
	drawInfo(3);
	color = new Array("#FF0000", "#00FF00", "#0000FF", "#ff00ff")
	bricks = new Array();
	for(var i = 0; i< row; i++){
		bricks[i] = new Array();
		for(var j = 0;j<col;j++){
			var temp = new brick();
			temp.col = j;
			temp.row = i;
			temp.isdisplay=1;
			temp.tool = GetRandomNum(1, 4);
			console.log("temp.tool", temp.tool);
			temp.color = color[(i*col+j)%4];
			bricks[i][j]= temp;
			
		}
	}
	canvas.focus();
	drawBall();
	drawPad();
	drawText();
	drawBricks();
	canvas.addEventListener(‘mousedown‘,onMouseDown, false);
	canvas.addEventListener(‘mousemove‘, padMove, false);
	canvas.addEventListener(‘mouseup‘, start, false);
}
function reset(){
	padWidth = 100;
	ballSpeed =2;
	toolArray = new Array();
	isStart=0;
	ballX = 500;
	ballY = 470;
	padX = 500;
	drawBricks();
	drawBall();
	drawPad();
	drawText();
}
function newLevel(){
	padWidth = padWidth - 5;
	ballSpeed = ballSpeed + 0.1;
	if(padWidth<= 40){
		drawInfo(4);
		getData();
		return;
	}
	else{
		row = row +1;
		level =level + 1;
		init();
	}	
}
function onMouseDown(e){
	if(isStart==0){
		isPressed = 1;
	}
}
function padMove(e){
	var x;
	x = e.layerX; 
	x = x<padWidth/2?padWidth/2:x;
	x = x>(worldWidth-padWidth/2)?(worldWidth-padWidth/2):x;
	padX = x;
	if(isStart==0){
		if(isPressed == 0){
			ballX = padX;
			ctx.clearRect(0, worldHeight-padHeight-2*radius, worldWidth, 2*radius); //clear the pad		
			drawBall();
			drawPad();
		}
	}
}
function start(e){
	if(isStart==0){
		ballAngle = Math.atan((worldHeight- e.layerY)/(e.layerX - ballX));
		if(ballAngle > 0){
			ballAngle = - ballAngle;
		}
		else{
			ballAngle = Math.PI - ballAngle;
		}
		isStart =1;
		isPressed = 0;
		interval = setInterval(draw, 3);
	}
}
function testCollision(){
	if(ballY > brickHeight * row){
		return;
	}
	for(var i = row;i>0;i--){
		if((ballY-radius)<=(brickHeight*i)){
			
		
			if((ballY-radius)>(brickHeight*(i-1))){
				var x = Math.floor(ballX/brickWidth);
				if(bricks[i-1][x].isdisplay==0){
					continue;
				}
				else{
					bricks[i-1][x].isdisplay=0;
					ballAngle= Math.PI*2-ballAngle;
					score= score+100;
					count = count +1;
					if(bricks[i-1][x].tool!=0){
						var brickX = bricks[i-1][x].col * brickWidth;
						var brickY = bricks[i-1][x].row * brickHeight;
						var temp = new tool(brickX, brickY, bricks[i-1][x].tool);
						toolArray.push(temp);					}
					return;
				}
			}
			else{
				continue;
			}
		}
		else
			break;
	}
}
function testTool(){
	for(var i = 0;i<toolArray.length;i++){
		console.log("tesetool", toolArray[i].type);
		var temp = toolArray[i];
		if(temp.y<worldHeight-padHeight){
			continue;
		}
		else{
			if(temp.x>=padX-padWidth/2 && temp.x<=padX+padWidth/2){
				switch(temp.type){
					case 1:{
						if(ballSpeed<2.6)
							ballSpeed=ballSpeed*1.3;
						console.log("tool", temp.type);
						break;
					}
					case 2:{
						if(ballSpeed>1.5)
						ballSpeed=ballSpeed/1.3;
						console.log("tool", temp.type);
						break;
					}
					case 3:{
						if(padWidth<200){
							padWidth = padWidth *2;
						}
						console.log("tool", temp.type);
						break;
					}
					case 4:{
						if(padWidth>50)
							padWidth=padWidth /2;
						console.log("tool", temp.type);
						break;
					}
				}
			}
			toolArray.splice(i, 1);
		}
	}
}
function postData(){
	var xmlhttp = new XMLHttpRequest();
	xmlhttp.open("POST","../storeScore/",true);
	xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
	var text = "score="+score;
	xmlhttp.send(text)
}
function getData(){
	var url = "../storeScore/"+score+"/";
	window.location = url;
}
function drawInfo(num){
	ctx.font = ‘50pt Calibri‘;
	ctx.fillStyle = "#E67E22";
	var text="One life lost!"
	if (num ==2){
		text = "Game over!"
	}
	else if(num ==3){
		text = "Level "+ level;
	}
	else if(num ==4){
		text = "Congratulations!"
	}
	ctx.fillText(text, 350, 250);
}
function drawBall(){
	ctx.drawImage(ballImg, ballX- radius, ballY-radius, 2*radius, 2*radius);
}
function drawBricks(){
	for(var i =0;i<row;i++){
		for(var j=0;j<col;j++){
			if(bricks[i][j].isdisplay ==1){
				ctx.fillStyle = bricks[i][j].color;
				var x = bricks[i][j].col * brickWidth;
				var y = bricks[i][j].row * brickHeight;
				//ctx.fillRect(x, y, brickWidth, brickHeight);
				ctx.drawImage(brickImg, x, y, brickWidth, brickHeight);
			}
		}
	}
}
function drawPad(){
	//ctx.fillStyle = "#0000FF";
	ctx.clearRect(0, worldHeight-padHeight, worldWidth, padHeight); //clear the pad
	//ctx.fillRect(padX-padWidth/2, worldHeight-padHeight, padWidth, padHeight);
	ctx.drawImage(padImg, padX-padWidth/2, worldHeight-padHeight, padWidth, padHeight);
}
function drawText(){
	ctx.font = ‘15pt Calibri‘;
	ctx.fillStyle = "black";
	var text= "level:"+level;
	ctx.fillText(text, 900, 370)
	text = "life:   " + life;
	ctx.fillText(text, 900, 430);
	text = ‘point:‘+score; 
	ctx.fillText(text, 900, 390);
	var min;
	if(time > 60){
		min =Math.floor(time/60);
	}
	else{
		min =0;
	}
	var sec = Math.floor(time % 60);
	if(min <10){
		tMin = ‘0‘+ min;
	}
	else
		tMin = ‘‘+min;
	if(sec<10){
		tSec = ‘0‘+sec;
	}
	else
		tSec=‘‘+ sec;
	text = ‘time: ‘+ tMin +":"+tSec;
	ctx.fillText(text, 900, 410);
}
function drawTool(){
	for(var i =0;i<toolArray.length;i++){
		switch(toolArray[i].type){
			case 1:{
				ctx.drawImage(tool1Img, toolArray[i].x, toolArray[i].y, 30, 30);
				break;
			}
			case 2:{
				ctx.drawImage(tool2Img, toolArray[i].x, toolArray[i].y, 30, 30);
				break;
			}
			case 3:{
				ctx.drawImage(tool3Img, toolArray[i].x, toolArray[i].y, 30, 30);
				break;
			}
			case 4:{
				ctx.drawImage(tool4Img, toolArray[i].x, toolArray[i].y, 30, 30);
				break;
			}
		}
		toolArray[i].y = toolArray[i].y+1;
	
	}
}
function draw(){
	//first clear the canvas 
	ctx.clearRect(0,0,worldWidth,worldHeight-padHeight);
	//ball
	drawBall();
	drawPad();
	drawBricks();
	drawTool();
	drawText();
	//flush the position of the ball
	ballX = ballX + ballSpeed * Math.cos(ballAngle);
	ballY = ballY + ballSpeed * Math.sin(ballAngle);
	//test the collision of the brick and the ball
	testCollision();
	testTool();
	if(ballX < radius || ballX > worldWidth - radius){
		ballAngle = Math.PI - ballAngle;
	}
	if(ballY < radius){
		ballAngle = Math.PI*2 - ballAngle;
	}
	if(ballY > worldHeight-radius){
		if(ballX< padX-padWidth/2 || ballX > padX + padWidth/2){
			ctx.clearRect(0,0,worldWidth,worldHeight-padHeight);
			self.clearInterval(interval);
			if(life>0){
				drawInfo(1);
				life = life -1;
				reset();
			}
			else if(life ==0){
				drawInfo(2);
				getData();
			}
			return;
		}
		else{
			ballAngle = Math.PI*2 - ballAngle;
		}
	}
	if(count>= col*row){
		ctx.clearRect(0,0,worldWidth,worldHeight-padHeight);
		self.clearInterval(interval);
		newLevel();
		return;
	}
	time = time +0.003;
}
原文:http://www.cnblogs.com/lytwajue/p/6859642.html