简单的画布打方块小游戏~

wocacaca
wocacaca 发布于 2015-12-19 00:10:03 浏览:1510 类型:原创 - 随笔 分类:HTML/CSS - 我的游戏 二维码: 作者原创 版权保护
终于抽空又写了一个游戏,这次是用画布,一个很简单的小游戏 预览地址  戳这里试玩  用谷歌浏览器哈~
  其实多多少少会有bug 我会在接下来抽空慢慢完善它,这里我简单的说一下原理
  
  这个游戏实际上就是画布在极短的时间内不停的对所有元素进行绘制,就像动画片一样。当然如果有更好的方法欢迎告诉我~
  
html:
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>canvas test</title>
	<style type="text/css">
		*{
			margin:0;
			padding:0;
		}
	</style>
</head>
<body>
	<div class="main">
		<canvas id="canvas"></canvas>
	</div>
	<script type="text/javascript" src="js/stick.js"></script>
	<script type="text/javascript" src="js/ball.js"></script>
	<script type="text/javascript" src="js/sqr.js"></script>
	<script type="text/javascript" src="js/main.js"></script>

</body>
</html>

以上是html代码,就只有一个canvas元素 作为舞台来进行游戏,可以看到引入了四个js文件 分别是 stick.js,ball.js, sqr.js ,main.js接下来我一一介绍每个js的功能
首先是sqr.js:
var sqr = function(){   // do draw 
	this.init()
}

sqr.prototype.level =  [[[1],[1],[1],[0],[1]],
				[[1],[1],[1],[1],[1]],
				[[1],[1],[1],[1],[1]],
				[[1],[1],[1],[1],[1]],
				[[1],[1],[1],[1],[1]],
				[[1],[1],[1],[1],[1]]];

sqr.prototype.chooseCol =  [[[1],[4],[5],[9],[4]],
					[[5],[1],[3],[6],[0]],
					[[7],[6],[2],[7],[2]],
					[[6],[9],[4],[6],[3]],
					[[2],[7],[0],[5],[4]],
					[[0],[5],[7],[4],[1]]];

sqr.prototype.col = function(){  // color lib
	var color = ["#02c1f1","#9f5bca","#5bcaa7","#5bca6d","#9fca5b","#c9ca5b","#ca855b","#ca5bbe","#ca5b66","#b4ca5b"]
	return color
}

sqr.prototype.init = function(){  // draw sqr
	this.x = this.level[0].length;
	this.y = this.level.length;
	this.w = (c_width / this.x);
	this.h = 18;
	cxt.save();
	cxt.strokeStyle = "#f0f0f0"; // border-color
	cxt.lineWidth = 1;
	for(var i=0;i<this.y;i++){
		for(var j=0;j<this.x;j++){
			var n = this.chooseCol[i][j];
			var m = this.level[i][j]
			var col = this.col()[n]; 
			cxt.beginPath()
			cxt.fillStyle = col;
			if(m != 0){
				cxt.fillRect(this.w*j,this.h*i,this.w,this.h)
				cxt.strokeRect(this.w*j,this.h*i,this.w,this.h)
			}
			cxt.closePath()
		}
	}
	cxt.restore();
}


其实 sqr.js 就是画方块的
sqr.prototype.level =  [[[1],[1],[1],[1],[1]],
					 [[1],[1],[1],[1],[1]],
					 [[1],[1],[1],[1],[1]],
					 [[1],[1],[1],[1],[1]],
					 [[1],[1],[1],[1],[1]],
					 [[1],[1],[1],[1],[1]]];

这个数组就是方块的初始化状态,是一个5*6的矩形,当然我可以通过将数组内的值置0来完成我想要的各种形状, sqr.prototype.chooseCol 也是一个数组,这个数组和后来的sqr.prototype.col是用来定义方块的颜色的。接下来就是绘制过程了
cxt.fillRect(this.w*j,this.h*i,this.w,this.h)
				cxt.strokeRect(this.w*j,this.h*i,this.w,this.h)

熟悉canvas API的人应该知道,cxt是canvas.getContext('2d')的简写,然后strokeRcet和fillRect传入的参数都是 (x,y,w,h),(x,y)是绘制矩形的起始坐标,w和h是矩形的宽和高,这里通过对level内部布局的三维数组循环来布局,其实这里可以将level改写成这样
sqr.prototype.level =  [[1,1,1,1,1],
					 [1,1,1,1,1],
					 [1,1,1,1,1],
					 [1,1,1,1,1],
					 [1,1,1,1,1],
					 [1,1,1,1,1]];

就少了一个维度的数组了,为什么我不这样呢,因为后面的代码都写好了,我懒得改。。。哈哈,原谅我的懒癌犯了,好了,这里掠过。接下来看stick
var stick = function(){
	this.color = "#f0f0f0";
	this.w = 100;
	this.h = 10;
	this.init()

}

stick.prototype.init = function(){
	this.x = p.x - (this.w / 2)
	this.draw()

}

stick.prototype.draw = function(){ // draw the stick
	var flag = this.bound();
	cxt.beginPath();
	cxt.fillStyle = this.color;
	if(flag == "left"){
		this.move(0,c_height-this.h,this.w,this.h)
		this.x = 0;
	}else if(flag == "right"){
		this.move((c_width - this.w),c_height-this.h,this.w,this.h)
		this.x = (c_width - this.w);
	}else{
		this.move(this.x,c_height-this.h,this.w,this.h)
	}
}

stick.prototype.bound = function(){
	if(this.x < 0){
		return "left"
	}else if(this.x > (c_width - this.w)){
		return "right"
	}
}

stick.prototype.move = function(x,y,w,h){
	cxt.fillRect(x,y,w,h)
	cxt.strokeRect(x,y,w,h)
}


stick就是下面用来接小球的棍子 这里定义了棍子的颜色 高度 宽度 和棍子碰到画布边缘时不超出的碰撞检测 看代码就ok
接下来的那颗小球,我觉得整个的难点就在这里
var ball = function(){
	this.r = 6;
	this.speed = 4;
	this.isMove = false
	this.color = "#ff0"
	this.top = 0
	this.init()
}

ball.prototype.init = function(){

	this.draw()
	this.begin()
}

ball.prototype.draw = function(){
	cxt.save()
	cxt.beginPath()
	cxt.fillStyle = this.color
	cxt.strokeStyle = this.color
	if(!this.isMove){
		cxt.arc(stick.x+(stick.w/2),c_height-(stick.h+this.r),this.r,0,Math.PI * 2, false)
	}else{
		this.move()
	}
	cxt.fill()
	cxt.stroke()
	cxt.closePath()
	//console.log(0)
	cxt.restore()
}

ball.prototype.move = function(){
	var sqrArr = sqr.level;
	var n = sqrArr[0].length;
	this.x+=this.a;
	this.id = Math.ceil((this.x+this.r)/sqr.w - 1) == n ? (n-1) : Math.ceil((this.x+this.r)/sqr.w - 1)
	//if(this.speed > 0){
		for(var i=sqrArr.length;i>0;i--){
			if(sqrArr[i-1][this.id][0]){  // 遇到数组内容为0的方块时直接穿透
				this.top = (i-1) * sqr.h
				var site = this.id * sqr.w
				var f = Math.sqrt( (Math.pow((this.y-this.r-this.top),2) + Math.pow((this.x-site),2)) ) //获取小球圆心+r到方块基点距离
				var p = Math.sqrt( (Math.pow(sqr.h,2) + Math.pow((this.x-site),2)) ) //方块基点到小球圆心+r发生碰撞时候的距离
				if(f < p){ //碰撞检测
					sqr.level[i-1][this.id][0] = 0  // 小球碰撞方块时,方块数组内容置0
					this.speed = -this.speed
					var m = i == sqrArr.length ? i-1 : i;
					if(sqr.level[m][this.id][0] && m < sqrArr.length ){
						this.a = -(this.a)
					}
					break
				}
				
			}
		}
	//}
	
	this.y-=this.speed;
	if( (this.x - this.r) < 0 || (this.x + this.r) > c_width){ // 边框反弹
		this.a = -(this.a)
	}else if(this.y-this.r < this.top){  // 顶部边框反弹
		this.speed = -(this.speed)
	}else if((this.y+this.r) > (c_height-stick.h) && this.x > stick.x && this.x < (stick.x + stick.w) ){ // 球和棍子反弹
		this.a = (this.a) + (this.x - (stick.x + stick.w/2))/30   // 判断小球在木棍落点位置,添加加速度
		this.speed = -(this.speed)
	}

	if(this.y - this.r > c_height + this.r){	
		play = false;
		alert("YOU LOSE")
	}
	cxt.arc(this.x,this.y,this.r,0,Math.PI * 2, false)

}

ball.prototype.begin = function(){
	var root = this
	canvas.addEventListener("click",function(e){
		if(!root.isMove){
			root.x = stick.x+(stick.w/2);
			root.y = c_height-(stick.h+root.r);
			root.a = (root.x - c_width/2)/50;
		}
		root.isMove = true
	},false)
}


卧槽,这个我要怎么说。。。我感觉自己都说不清楚,总之整个的关键在这里
for(var i=sqrArr.length;i>0;i--){
			if(sqrArr[i-1][this.id][0]){  // 遇到数组内容为0的方块时直接穿透
				this.top = (i-1) * sqr.h
				var site = this.id * sqr.w
				var f = Math.sqrt( (Math.pow((this.y-this.r-this.top),2) + Math.pow((this.x-site),2)) ) //获取小球圆心+r到方块基点距离
				var p = Math.sqrt( (Math.pow(sqr.h,2) + Math.pow((this.x-site),2)) ) //方块基点到小球圆心+r发生碰撞时候的距离
				if(f < p){ //碰撞检测
					sqr.level[i-1][this.id][0] = 0  // 小球碰撞方块时,方块数组内容置0
					this.speed = -this.speed
					var m = i == sqrArr.length ? i-1 : i;
					if(sqr.level[m][this.id][0] && m < sqrArr.length ){
						this.a = -(this.a)
					}
					break
				}
				
			}
		}

开始的碰撞检测我只是简单的根据 top 和 left 来做检测,但是后来发现这样的话如果小球碰撞的方块下面还有方块的话就会一起被消掉,直到前几天看了一个教程,里面的碰撞检测是用的勾股定理来算出两点之间的距离小于会碰撞的距离的时候我才豁然开朗,还能这样玩,然后我就写了这个碰撞检测,如下图:

简单的画布打方块小游戏~

如图,根据勾股定理分别算出 两条黄线 d 和 D 的长度(这两个值是一直变化的),当 D 小于 d 时,就说明了方块的小球发生了变化,当然如果方块在小球左边时候也有 D 小于 d 的情况,不过已经在之前的判断里过滤掉了~

最后 就是 main.js 了

window.onload = function(){
	loop()
}

var canvas = document.getElementById("canvas")
var c_width = 400
var c_height = 600
canvas.width = c_width
canvas.height = c_height
var cxt = canvas.getContext("2d")
var delata = 0;
var p = {x:0};
var play = true;
//loop()
function start(){
	this.init()
}


start.prototype.init = function(){  // init
	this.draw()
}


function setbg(){   // draw background image 
	var bg = new Image();
	bg.src = "../images/bg.jpg";
	cxt.drawImage(bg,0,0,c_width,c_height)
}

var sqr = new sqr()
var stick = new stick()
var ball = new ball()

function loop(){   // loop function	
	setbg()
	sqr.init()
	stick.init()
	ball.init()
	if(play){
		play = requestAnimationFrame(loop)
	}	
}

canvas.addEventListener("mousemove",function(e){
	p = getPos(canvas,e)
},false)

function getPos(canvas,e){
	var rect = canvas.getBoundingClientRect();
	return{
		x: e.clientX - rect.left
	}
}



main里其实就是定义了全局变量和一个不断执行的loop函数,然后会一直将 小球 棍子 和方块 以及背景不停的进行重绘,来完成动画的效果,当然可能会影响一些性能,如果大家有更好的方法记得告诉我哦~

嗯,完了~~


个人网站: http://mikoshu.me
谢谢
z
给个赞 6 人点赞
收藏 0 人收藏
评论 已有 5 条评论;以下用户言论只代表其个人观点,不代表 前端网(QDFuns) 的观点或立场。
登录 以后才能发表评论
最新评论
gxp5189468
gxp51894682015-12-26 08:25:345F
   //@fanbuxie:大神 你好
举报 支持 (0) 回复 (0)
wocacaca
wocacaca2015-12-22 11:27:164F
叫我小菜~~ //@fanbuxie:大神 你好
举报 支持 (0) 回复 (0)
wocacaca
wocacaca2015-12-22 11:26:563F
怪我怪我,我总是说不清楚自己的想法,哈哈
举报 支持 (0) 回复 (0)
Ordinary
Ordinary2015-12-22 11:16:012F
牛逼  太长了  看不懂 哈哈哈~~~
举报 支持 (0) 回复 (0)
fanbuxie
fanbuxie2015-12-19 10:45:501F
大神 你好
举报 支持 (0) 回复 (2)
wocacaca wocacaca 作者

快闪开,我要帅炸了!

作者最新