【JavaScript】黑点捉红点并躲绿点游戏

我知道这个游戏命名得很烂,你喜欢的话,叫“亲贤人远小人”也行,黑点就是玩家,红点就是“贤臣”,绿点就是“小人”,反正是个游戏吧!游戏的剧本怎么写那是汉语言文学的问题~

自上次《【JavaScript】贪吃蛇》(点击打开链接)时隔两个月终于有时间再写写游戏了~

JavaScript真的是一门碉堡的语言,简单的一个js就可以写出一个游戏!没有c++与java写很久都没有把游戏写出来,而且里面的线程实在是烦死了~

据说这个游戏非常符合所谓OOP面向对象设计思想……其实这些软件工程的思想说多了也是放屁,关键是你懂得怎么一步一步,不看任何资料把程序写出来,

估计是因为面向对象设计思想,好记,再大型的程序也能写出来,所以也就应用广泛……


一、基本目标

是这样的一个游戏:

1、首先在一个400x400px的区域内,有三个点,一个黑、一个绿、一个红,你控制的黑点,目标是不让绿点碰到,并在被绿点碰到之前尽可能地碰到红点,Gameover之后显示所得积分,并且自动刷新页面,重新开始


2、你可以用左上角的上下左右来控制黑点,也可以用键盘的WASD或者←↑↓→去控制黑点的移动,当然,如果黑点碰到墙也会Gameover的,至于红点与绿点的移动当然是AI来控制,而且这红点与绿点如果一旦移出黑框会自动跳回进来,AI会做好控制。


3、黑点碰到红点之后就不停地加分,我认为这个游戏如果挂到手机也就是个Flappy Bird的游戏,问题,本猿猴不像高富帅那样有自己的云服务器~也就能这样教教后来者罢了



二、基本思想

纯粹的html+css+javascript无须任何库,兼容主流浏览器,

1、用html+css布置好游戏场景

2、写好javascript的键盘响应事件,此事件与黑点diva类分离,通过调用diva中的各种move方法,改变黑点的位置,黑点在移动过程中注意判断是否遇到红点、绿点与墙

3、写好红点类divb与绿点类的divc方法,开两个计时器,不停地调用他们的自移动方法,让这两点随机移动,绿点与红点在移动过程中也要注意判断是否遇到黑点,如果已经移动到墙角,注意要重新产生随机数,让其不出墙,不然一枝红杏出墙来,你就等着笑话吧


三、制作过程

1、用html+css布置好游戏场景,注意所有使用到position:absolute;,也就一个黑色框、黑点、红点、绿点,还有一句游戏说明与控制方向的表格,注意黑点、红点、绿点是要设定超过12px的宽与高,不然会变形,怎么用css布局图层在《【CSS】关于div的对齐与网页布局》(点击打开链接)已经说过了~这里不再大篇幅讲解,代码如下,我习惯在<script></script>之间完成脚本,所以没有用<script type="text/javascript" src="xx.js" ></script>,这鬼东西还不能写成<script type="text/javascript" src="xx.js" />,一个小游戏不是大工程就不要这样引用了,看得不爽:

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
</head>
<body>
黑点捉红点游戏,积分:<span id="count">0</span>,不要被绿点碰到!
<table border="1">
<tr>
<td></td>
<td><input type="button" value="上" onClick="move(this)" /></td>
<td></td>
</tr>
<tr>
<td><input type="button" value="左" onClick="move(this)" /></td>
<td></td>
<td><input type="button" value="右" onClick="move(this)" /></td>
</tr>
<tr>
<td></td>
<td><input type="button" value="下" onClick="move(this)" /></td>
<td></td>
</tr>
</table>
<div style="position:absolute; left:100px; top:100px; width:400px; height:400px; border:1px solid #000000;" ></div>
<div id="diva" style="position:absolute; left:101px; top:120px; background-color:#000000; width:20px; height:20px;"></div>
<div id="divb" style="position:absolute; left:200px; top:200px; background-color:#900000; width:20px; height:20px;"></div>
<div id="divc" style="position:absolute; left:200px; top:200px; background-color:#009000; width:20px; height:20px;"></div>
</body>
</html>


2、然后就是<scirpt></script>部分,大家注意到控制方向的按钮有个onClick调用move()这个函数,那么就在javascript中就先写move这个控制黑点上下左右的函数

function move(obj){
	switch(obj.value){
		case "上":
			diva.move_up();
			break;
		case "左":
			diva.move_left();
			break;
		case "右":
			diva.move_right();
			break;
		case "下":
			diva.move_down();
			break;
	}
}

这里move的参数是obj,也就会把整个按钮传递过来,然后再用obj.value来取这个按钮的值,如果是上,则调用黑点类diva中的move_up()方法,如此类推


3、键盘响应函数也这个函数也是这样的道理,与《【JavaScript】贪吃蛇》(点击打开链接)中的那个完全一模一样

document.onkeydown = function(event) {
	var code;
	if (window.event) {
		code = window.event.keyCode;
	} else {
		code = event.keyCode;
	}
	switch(code){
		case 38:
			diva.move_up();
			break;
		case 37:
			diva.move_left();
			break;
		case 39:
			diva.move_right();
			break;
		case 40:
			diva.move_down();
			break;
		case 87:
			diva.move_up();
			break;
		case 65:
			diva.move_left();
			break;
		case 68:
			diva.move_right();
			break;
		case 83:
			diva.move_down();
			break;
	}
}

相应的键值则调用相应diva中的移动方法,

	var code;
	if (window.event) {
		code = window.event.keyCode;
	} else {
		code = event.keyCode;
	}

这句纯粹为了兼容主流浏览器的键盘响应,至少在ie与谷歌是没问题了,你的浏览器或者拉到手机就非主流那再想想办法吧……本文不是讨论兼容性的


4、好,上面说了这么多黑点类diva,那么这个类到底是如何呢?

function Diva(x,y){
	this.x=x;
	this.y=y;
	this.move_up=function(){
		this.y--;
		document.getElementById("diva").style.top=this.y+"px";
		this.ifredcatch();
		this.ifgreencatch();
		this.ifcross();
	}
	this.move_left=function(){
		this.x--;
		document.getElementById("diva").style.left=this.x+"px";
		this.ifredcatch();
		this.ifgreencatch();
		this.ifcross();
	}
	this.move_right=function(){
		this.x++;
		document.getElementById("diva").style.left=this.x+"px";
		this.ifredcatch();
		this.ifgreencatch();
		this.ifcross();
	}
	this.move_down=function(){
		this.y++;
		document.getElementById("diva").style.top=this.y+"px";
		this.ifredcatch();
		this.ifgreencatch();
		this.ifcross();
	}
	this.ifredcatch=function(){
		if((this.x>divb.x-20)&&(this.x<divb.x+20)&&(this.y>divb.y-20)&&(this.y<divb.y+20)){
			count++;
			document.getElementById("count").innerHTML = count.toString(); 
		}
	}
	this.ifgreencatch=function(){
		if((this.x>divc.x-20)&&(this.x<divc.x+20)&&(this.y>divc.y-20)&&(this.y<divc.y+20)){
			alert("Game Over," + "积分:" + count); 		
            		history.go(0);
			clearTimeout(timer1);
			clearTimeout(timer2);
		}
	}
	this.ifcross=function(){
		if(!((this.x>100)&&(this.x<480)&&(this.y>100)&&(this.y<480))){
			alert("Game Over," + "积分:" + count);  		
            		history.go(0);
			clearTimeout(timer1);
			clearTimeout(timer2);	
		}	
	}
}

首先在开头有构造方法,我们一会儿自然要在开头声明一个这样的东西:

var diva=new Diva(101,120);

表示黑点一开始在101,120这个位置,这里也与html中的布局代码,黑点的最初位置left:101px; top:120px;相对应:

<div id="diva" style="position:absolute; left:101px; top:120px; background-color:#000000; width:20px; height:20px;"></div>

然后这个类的各个移动方法很简单,

首先是这个类的x,y要自减,使得在脚本中黑点类diva的位置变化,然后控制上面css使得在外观上这个黑点发生变化,例如:

	this.move_up=function(){
		this.y--;
		document.getElementById("diva").style.top=this.y+"px";
		this.ifredcatch();
		this.ifgreencatch();
		this.ifcross();
	}
向上移就是把y的坐标减1嘛,如果更新一下html+css中的黑点的位置

之后黑点自己每移动一次都要判断是否碰到红点、绿点、墙

(1)碰到红点的方法:

	this.ifredcatch=function(){
		if((this.x>divb.x-20)&&(this.x<divb.x+20)&&(this.y>divb.y-20)&&(this.y<divb.y+20)){
			count++;
			document.getElementById("count").innerHTML = count.toString(); 
		}
	}
如果黑点的坐标不超过红点的坐标的20px,那么黑点也就碰到红点,这个不用给大家画图了吧,高中甚至是初三的两点距离问题而已~

然后积分变量count+1,更新一下上面前台的count行内文本

当然,要在头部声明一个

var count = 0;
Javascript没有public与privated的概念,要声明类中成员请用this,反正任何东西都是public,黑点可以如上所示地调用红点里面的x,


(2)碰到绿点方法:

同理(1)碰到红点的方法,可得:

	this.ifgreencatch=function(){
		if((this.x>divc.x-20)&&(this.x<divc.x+20)&&(this.y>divc.y-20)&&(this.y<divc.y+20)){
			alert("Game Over," + "积分:" + count); 		
            <span style="white-space:pre">		</span>history.go(0);
			clearTimeout(timer1);
			clearTimeout(timer2);
		}
	}
当然,切记碰到绿点是结束游戏的动作,history.go(0);是刷新本页,清理红点与绿点计时器,不要红点与绿点再继续移动了,当然不清也没关系,毕竟已经刷新了嘛,还是清清把,当然,要在头部声明两个计时器,一个是红点每1毫秒动一次,绿点每1毫秒动一次,看gif就知道这个间隔并不快,而且游戏还挺好玩~

timer1 = setInterval("divb.move()", 1);
timer2 = setInterval("divc.move()", 1);

(3)是否碰墙

哎呀,这个太简单了,就是判断黑点的坐标是不是等于在墙里面,当然,这里要判断是否在100~480之类,因为div的坐标在其左上角,如果不是再结束游戏:

	this.ifcross=function(){
		if(!((this.x>100)&&(this.x<480)&&(this.y>100)&&(this.y<480))){
			alert("Game Over," + "积分:" + count);  		
            history.go(0);
			clearTimeout(timer1);
			clearTimeout(timer2);	
		}	
	}

5、红点类divb

function Divb(x,y){
	this.x=x;
	this.y=y;
	this.move=function(){
		var random=Math.floor(Math.random() * 5);
		switch(random){
			case 1:
				if(!(this.y<100)){
					this.y=this.y-5;
					document.getElementById("divb").style.top=this.y+"px";
					diva.ifredcatch();
					break;
				}
			case 2:
				if(!(this.x<100)){
					this.x=this.x-5;
					document.getElementById("divb").style.left=this.x+"px";
					diva.ifredcatch();
					break;
				}
			case 3:
				if(!(this.x>480)){
					this.x=this.x+5;
					document.getElementById("divb").style.left=this.x+"px";	
					diva.ifredcatch();
					break;
				}
			case 4:
				if(!(this.y>480)){
					this.y=this.y+5;
					document.getElementById("divb").style.top=this.y+"px";
					diva.ifredcatch();
					break;
				}					
		}
	}
}

由于有构造方法要在头部声明:

var divb=new Divb(200,200);
里面的移动方法,首先用

var random=Math.floor(Math.random() * 5);
产生一个1~4的随机数

之后,做任意方向的移动,而且移动的幅度要大一点,否则黑点太容易碰到你就不好~

当然如果可以预见到这样的移动会出墙的话,则不移动了。

这里配合上面定义的计时器,那么红点就会不停地移动,

在红点移动的过程中要调用黑点类的ifredcatch()判断红点是否碰到黑点,做相应的处理。


6、绿点类divc

同理,红点类divb可得,当然,绿点的移动幅度要比红点更大,这样才更好地碰到黑色,让玩家更快输掉:

function Divc(x,y){
	this.x=x;
	this.y=y;
	this.move=function(){
		var random=Math.floor(Math.random() * 5);
		switch(random){
			case 1:
				if(!(this.y<100)){
					this.y=this.y-10;
					document.getElementById("divc").style.top=this.y+"px";
					diva.ifgreencatch();
					break;
				}
			case 2:
				if(!(this.x<100)){
					this.x=this.x-10;
					document.getElementById("divc").style.left=this.x+"px";
					diva.ifgreencatch();
					break;
				}
			case 3:
				if(!(this.x>480)){
					this.x=this.x+10;
					document.getElementById("divc").style.left=this.x+"px";	
					diva.ifgreencatch();
					break;
				}
			case 4:
				if(!(this.y>480)){
					this.y=this.y+10;
					document.getElementById("divc").style.top=this.y+"px";
					diva.ifgreencatch();
					break;
				}					
		}
	}
}
当然,不要忘记在头部加入红点与绿点的声明哦,因为有构造方法!

var divb=new Divb(200,200);
var divc=new Divc(200,200);


四、总结与展望

综上所述,整个程序就写完了,全代码如下,复制到一个记事本,保存为*.html就可以玩了,注意保存的编码不要用ANSI,用Unicode最好用utf-8哦!原因在《【HTML】明明加了<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />却还是乱码的可能原因》(点击打开链接)已经说过

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
</head>
<body>
黑点捉红点游戏,积分:<span id="count">0</span>,不要被绿点碰到!
<table border="1">
<tr>
<td></td>
<td><input type="button" value="上" onClick="move(this)" /></td>
<td></td>
</tr>
<tr>
<td><input type="button" value="左" onClick="move(this)" /></td>
<td></td>
<td><input type="button" value="右" onClick="move(this)" /></td>
</tr>
<tr>
<td></td>
<td><input type="button" value="下" onClick="move(this)" /></td>
<td></td>
</tr>
</table>
<div style="position:absolute; left:100px; top:100px; width:400px; height:400px; border:1px solid #000000;" ></div>
<div id="diva" style="position:absolute; left:101px; top:120px; background-color:#000000; width:20px; height:20px;"></div>
<div id="divb" style="position:absolute; left:200px; top:200px; background-color:#900000; width:20px; height:20px;"></div>
<div id="divc" style="position:absolute; left:200px; top:200px; background-color:#009000; width:20px; height:20px;"></div>
</body>
</html>
<script>
var diva=new Diva(101,120);
var divb=new Divb(200,200);
var divc=new Divc(200,200);
var count = 0;
timer1 = setInterval("divb.move()", 1);
timer2 = setInterval("divc.move()", 1);
function Diva(x,y){
	this.x=x;
	this.y=y;
	this.move_up=function(){
		this.y--;
		document.getElementById("diva").style.top=this.y+"px";
		this.ifredcatch();
		this.ifgreencatch();
		this.ifcross();
	}
	this.move_left=function(){
		this.x--;
		document.getElementById("diva").style.left=this.x+"px";
		this.ifredcatch();
		this.ifgreencatch();
		this.ifcross();
	}
	this.move_right=function(){
		this.x++;
		document.getElementById("diva").style.left=this.x+"px";
		this.ifredcatch();
		this.ifgreencatch();
		this.ifcross();
	}
	this.move_down=function(){
		this.y++;
		document.getElementById("diva").style.top=this.y+"px";
		this.ifredcatch();
		this.ifgreencatch();
		this.ifcross();
	}
	this.ifredcatch=function(){
		if((this.x>divb.x-20)&&(this.x<divb.x+20)&&(this.y>divb.y-20)&&(this.y<divb.y+20)){
			count++;
			document.getElementById("count").innerHTML = count.toString(); 
		}
	}
	this.ifgreencatch=function(){
		if((this.x>divc.x-20)&&(this.x<divc.x+20)&&(this.y>divc.y-20)&&(this.y<divc.y+20)){
			alert("Game Over," + "积分:" + count); 		
            history.go(0);
			clearTimeout(timer1);
			clearTimeout(timer2);
		}
	}
	this.ifcross=function(){
		if(!((this.x>100)&&(this.x<480)&&(this.y>100)&&(this.y<480))){
			alert("Game Over," + "积分:" + count);  		
            history.go(0);
			clearTimeout(timer1);
			clearTimeout(timer2);	
		}	
	}
}
function Divb(x,y){
	this.x=x;
	this.y=y;
	this.move=function(){
		var random=Math.floor(Math.random() * 5);
		switch(random){
			case 1:
				if(!(this.y<100)){
					this.y=this.y-5;
					document.getElementById("divb").style.top=this.y+"px";
					diva.ifredcatch();
					break;
				}
			case 2:
				if(!(this.x<100)){
					this.x=this.x-5;
					document.getElementById("divb").style.left=this.x+"px";
					diva.ifredcatch();
					break;
				}
			case 3:
				if(!(this.x>480)){
					this.x=this.x+5;
					document.getElementById("divb").style.left=this.x+"px";	
					diva.ifredcatch();
					break;
				}
			case 4:
				if(!(this.y>480)){
					this.y=this.y+5;
					document.getElementById("divb").style.top=this.y+"px";
					diva.ifredcatch();
					break;
				}					
		}
	}
}

function Divc(x,y){
	this.x=x;
	this.y=y;
	this.move=function(){
		var random=Math.floor(Math.random() * 5);
		switch(random){
			case 1:
				if(!(this.y<100)){
					this.y=this.y-10;
					document.getElementById("divc").style.top=this.y+"px";
					diva.ifgreencatch();
					break;
				}
			case 2:
				if(!(this.x<100)){
					this.x=this.x-10;
					document.getElementById("divc").style.left=this.x+"px";
					diva.ifgreencatch();
					break;
				}
			case 3:
				if(!(this.x>480)){
					this.x=this.x+10;
					document.getElementById("divc").style.left=this.x+"px";	
					diva.ifgreencatch();
					break;
				}
			case 4:
				if(!(this.y>480)){
					this.y=this.y+10;
					document.getElementById("divc").style.top=this.y+"px";
					diva.ifgreencatch();
					break;
				}					
		}
	}
}

function move(obj){
	switch(obj.value){
		case "上":
			diva.move_up();
			break;
		case "左":
			diva.move_left();
			break;
		case "右":
			diva.move_right();
			break;
		case "下":
			diva.move_down();
			break;
	}
}

document.onkeydown = function(event) {
	var code;
	if (window.event) {
		code = window.event.keyCode;
	} else {
		code = event.keyCode;
	}
	switch(code){
		case 38:
			diva.move_up();
			break;
		case 37:
			diva.move_left();
			break;
		case 39:
			diva.move_right();
			break;
		case 40:
			diva.move_down();
			break;
		case 87:
			diva.move_up();
			break;
		case 65:
			diva.move_left();
			break;
		case 68:
			diva.move_right();
			break;
		case 83:
			diva.move_down();
			break;
	}
}
	

</script>

这个游戏当然还有改进的地方,就是红点与绿点中的移动方法move()中的随机数产生问题,怎么以不同概率产生随机数是要思考的。不如收到玩家黑点的移动动作,我们的红点与这个移动动作相同的移动,概率要大一点,为了更多地远离黑点,绿点则与这个移动动作相反的移动,概率大一点,为了更多地接近黑点,反之亦然。



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值