javascript打字游戏

学一门语言光看书是不够的,最好是边练边学,所以这次我就用javascript写了这个简单的打字游戏,虽然说起来简单,但是对于第一次写游戏的我还是小小捉急了一把,就让我来介绍下游戏是怎样实现的吧~~介绍完代码之后还会讲讲我在写的过程中遇到的困难,解决的bug。

首先,我们来看下效果

在此输入图片描述

左上角是开始和暂停的按钮,点击开始就进入游戏,后面的是玩家的血,可以自由设定,每次漏过一个字母就会失去一滴血,失去三滴血游戏就结束了,每次玩家的成绩即消灭的字母数都会在右上角统计

接着,说一下我是怎么实现的

##1.对象的创立 游戏中共有三个对象,游戏对象、字母组对象和字母对象

游戏对象是一开始初始化的对象,用于游戏难度的设置,在游戏对象中,将相关参数传给字母组对象并创建该对象,字母组用来不断产生一个个字母,每个字母是一个对象,每个对象的具体代码如下:

  • 游戏对象

游戏对象有三个参数,speed、life 和 proTime,分别对应字母下落的速度、玩家的生命数和每两个字母产生的间隔时间,可以自由设置。其中需要创建letterAry对象,即字母组对象,稍后介绍:

<!-- lang: js -->
//游戏对象
function game(speed,life,proTime) {
	this.speed = speed;
	this.life = life;
	this.proTime = proTime;
	//设置玩家生命
	this.setLife = function() {
		document.getElementById("life").innerText = "";
		for(var i = 0;i<this.life;i++){
			var img = document.createElement("img");
			img.src = "images/life.png";
			document.getElementById("life").appendChild(img);
		}
		if(this.life == 0) {
			this.over();
		}
	},
	//失去一滴血
	this.removeLife = function() {
		var lastImg = document.getElementById("life").lastChild;
		document.getElementById("life").removeChild(lastImg);
	},
	//获取浏览器宽度
	this.clientWidth = function(){
		var width = window.innerWidth;
		if (typeof width != "number") {
			if (document.compatMode == "CSS1Compat") {
				width = document.documentElement.clientWidth;
			} else {
				width = document.body.clientWidth;
			}
		}
		return width-20;
	},
	//获取浏览器高度
	this.clientHeight = function(){
		var height = window.innerHeight;
		if (typeof width != "number") {
			if (document.compatMode == "CSS1Compat") {
				width = document.documentElement.clientHeight;
			} else {
				width = document.body.clientHeight;
			}
		}
		return height;
	},
	//游戏开始的入口
	this.begin = function() {
		this.letterAry = new letterAry(this,this.speed,
			this.proTime,this.clientWidth(),this.clientHeight());
		this.letterAry.start();
		this.setLife();
		document.getElementById("num").innerText = 0;
	},
	//游戏结束,用户选择是否重来
	this.over = function() {
		this.letterAry.stop();
		var again = confirm("游戏结束,是否重新开始?");
		if(again) {
			var g = new game(this.speed,life,this.proTime);
			g.begin();
		}
	}
}
  • 字母组对象

即负责产生字母的对象letterAry,共有5个属性,分别为

<!-- lang: js -->
//字母组对象
//@param game object 游戏对象
//@param speed int 降落速度
//@param proTime int 每两个字母产生的间隔时间
//@param clientWidth int 浏览器宽度
//@param clientHeight int 浏览器高度
function letterAry(game,speed,proTime,clientWidth,clientHeight) {
	this.game = game;
	var letterAry = this;
	this.speed = speed;
	this.proTime = proTime;
	this.letters = new Array();
	this.keys = new Array("A","B","C","D","E","F","G",
			"H","I","J","K","L","M","N","O","P","Q","R","S",
			"T","U","V","W","X","Y","Z");
	this.more;
	this.add = true;
	//开始产生字母的入口
	this.start = function() {
		this.more = true;
		this.produceLetter();
	},
	//产生字母
	this.produceLetter = function() {
		if(letterAry.more) {
			var left = Math.floor(Math.random()*clientWidth);
			var index = Math.floor(Math.random()*26);
			var key = letterAry.keys[index];
			var keyCode = key.charCodeAt(0);
			var ler = new letter(letterAry.game,left,true,letterAry.speed,clientHeight,key,keyCode);
			ler.create();
			letterAry.letters[letterAry.letters.length] = ler;
			//判断letterAry的长度,第一次>10后字母下落速度加快、字母产生速度加快
			if(letterAry.add && letterAry.letters.length > 10) {
				letterAry.proTime -= 200;
				letterAry.speed += 1; 
				letterAry.add = false;
			}
			window.setTimeout(letterAry.produceLetter,letterAry.proTime);
		}
	},
	//停止
	this.stop = function() {
		if(this.more) {
			for(var i = 0;i < this.letters.length;i++) {
				this.letters[i].clear();
			}
		}
		this.more = false;
	},
	//键盘监听事件,点击正确时将字母清除
	document.onkeydown = function(e) {
		var e = e?e:event;
		for(var i = 0;i < letterAry.letters.length;i++) {
			if(letterAry.letters[i].isLive && letterAry.letters[i].keyCode==e.keyCode) {
				letterAry.letters[i].clear();
				document.getElementById("num").innerText =
				parseInt(document.getElementById("num").innerText)+1;
				return;
			}
		}
	}
} 
  • 字母对象

即letter对象,为游戏中不断下降的字母,共有7个属性(哇塞好多啊,没办法,这都是必须用到的==),分别为

<!-- lang: js -->
// letter对象
// @param game object 游戏对象
// @param left int 左边距
// @param isLive boolean 是否存在
// @param speed int 降落速度
// @param clientHeight int 浏览器高度
// @param content string 字母
// @param keyCode string 字母对应的编码

function letter(game,left,isLive,speed,clientHeight,content,keyCode) {
	this.game = game;
	var letter = this;
	this.left = left;
	this.isLive = isLive;
	this.speed = speed;
	this.clientHeight = clientHeight;
	this.content = content;
	this.keyCode = keyCode;
	this.top;
	this.div;
	//字母的产生
	this.create = function() {
		this.div = document.createElement("div");
		this.div.innerText = content;
		this.div.className = "letter";
		this.setTop(25);
		this.setLeft(this.left);
		document.body.appendChild(this.div);
		this.drop();
	},
	//字母的下降
	this.drop = function() {
		if(letter.isLive){
			if(letter.top <= letter.clientHeight) {
				var top =letter.top + letter.speed;
				letter.setTop(top);
				window.setTimeout(letter.drop,20);
			}else {
				letter.clear();
				letter.game.life--;
				letter.game.removeLife();
				if(letter.game.life == 0) {
					letter.game.over();
				}
			}
		}
	},
	//字母的清除
	this.clear = function() {
		if(this.isLive) {
			this.isLive = false;
			this.div.parentNode.removeChild(this.div);
		}
	},
	//设置字母的顶边距
	this.setTop = function(top) {
		this.top = top;
		this.div.style.top = this.top + "px";
	},
	//设置字母的左边距
	this.setLeft = function(left) {
		this.left = left;
		this.div.style.left = this.left + "px";
	}
}

##2.遇到的问题

  • setTimeout函数的作用域和this指向问题

在对象letter中,用到的setTimeout函数如下

<!-- lang: js -->
//字母的下降
this.drop = function() {
	if(letter.isLive){
		if(letter.top <= letter.clientHeight) {
			var top =letter.top + letter.speed;
			letter.setTop(top);
			window.setTimeout(letter.drop,20);
		}else {
			letter.clear();
			letter.game.life--;
			letter.game.removeLife();
			if(letter.game.life == 0) {
				letter.game.over();
			}
		}
	}
},

一开始,我是这样写的:

<!-- lang: js -->
//字母的下降
this.drop = function() {
	if(this.isLive){
		if(this.top <= this.clientHeight) {
			var top =this.top + this.speed;
			this.setTop(top);
			window.setTimeout(this.drop,20);
		}else {
			this.clear();
			this.game.life--;
			this.game.removeLife();
			if(this.game.life == 0) {
				this.game.over();
			}
		}
	}
},

运行时出错,drop函数没起效果,后来找到了原因,原来是setTimeout函数的this指向问题。首先,setTimeout调用的代码是在全局作用域中执行的,因此函数中this的值指向window对象。为了解释清楚,写了个简单的例子来说明:

<!-- lang: js -->
function Foo(){
    this.name= 1,
    this.method = function(){
        alert(this);
        alert(this.name);
    },
    setTimeout(this.method,1000);
}
new Foo();

当我们new一个Foo对象时,输出的不是 [object object] 和 1 ,而是输出 [object window] 和 undefined,因为在setTimeout中的this.method中的this指的是上下文的this,即new的对象,因此就会调用method方法,但是进入method方法后,方法中的this指的是window对象,所以输出window,window环境中没有name变量,所以是undefined。所以为了可以输出Foo对象和其name的值,应该改为:

<!-- lang: js -->
function Foo(){
    var Foo = this;
    this.name= 1,
    this.method = function(){
        alert(Foo);
        alert(Foo.name);
    },
    setTimeout(this.method,1000);
}
new Foo();

将Foo中的环境变量保存到Foo中,以后就用Foo代替Foo中的this,就解决了。

转载于:https://my.oschina.net/sini/blog/204715

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值