原生面向对象的简单金山打字游戏

金山打字小游戏

在这里插入图片描述

1.介绍及效果图

这是一个练习打字的游戏,当游戏开始后,界面从顶部不断落下内容为随机字母的方块,当按下相对应的按键时,就会清除对应方块

在这里插入图片描述

2.思路

1、如何确定难度?
2、方块如何生成?生成位置?如何移动?
3、如何键盘检测?对应后如何移除?
4、移除之后分数的累加?
5、游戏失败?弹窗,结算分数?

3.代码

1、body部分:
<div id="box">
			<div id="changeBox">
				<ul class="change">
					<p>金山打字</p> //标题
					<li>初级</li> //难度选项
					<li>中级</li>
					<li>高级</li>
				</ul>
			</div>
		</div>
2、css部分:
<style type="text/css">
   //清除默认margin、padding值
	*{margin: 0;padding: 0;box-sizing: border-box;}
	//大盒子样式设置
	#box{width: 500px;height: 800px;background: black;position: relative;/* overflow: hidden; */padding-top: 200px;}
	//方块样式设置
	.block{width: 30px;height: 30px;background: blue;position: absolute;top: 0px;text-align: center;
	       line-height: 30px;color:white;font-weight: bold;}
	//标题框样式设置
	#changeBox{width: 300px;height: 200px;background: #ADFF2F;margin: 0 auto;}
	选项样式设置
	li{list-style: none;height: 50px;text-align: center;line-height: 50px;border-top: 1px solid red;cursor: pointer;}
	//标题样式设置
	p{line-height: 50px;text-align: center;background: #666666;font-size: 18px;font-weight: bold;color: white;}
</style>
3、js部分详解:
****1. 初始标题框元素获取、选项卡索引获取以及实例的创建:****
这里要获取选项卡的li以及其所在的盒子
var ul = document.querySelectorAll('li'); //获取所有li,存放在ul这个集合中
var changBox = document.getElementById('changeBox');
****2. 用for循环遍历li,并取得对应li的下标****
        for(var i=0;i<ul.length;i++){
			ul[i].x = i;  //给每一个li定义一个自定义属性x,属性值为i;此时,属性x的值与其索引值是相等的
			ul[i].onclick=function(){ //当点击li的时候
				var index = this.x;   //新建一个变量,让他等于当前点击的li的属性x的值;
				changeBox.style.display = 'none';  //选择之后,隐藏标题框
				new game({ind:index});   //新建一个实例game,并且将当前li的索引值以对象方式进行传参
			}			
		}
		!!!核心:给li定义属性,通过this指向当前被点击的li,并取到索引值
****3.实例game初始的设置****
        function game(p){  //用p来接受传进来的实参,也就是被点击的li的索引值
			this.box = document.getElementById('box');
			this.plane = document.querySelector('.plane');
			this.block = document.querySelector('.block');
			this.t; //定时器,后面在方块生成中会用到
			this.text=0;  //记录分数
			this.blockArr = [];//存放生成的方块
			this.number=p.ind;// 拿到索引,确定难度
			switch(this.number){
				case 0:this.number = 500;break;
				case 1:this.number = 300;break;
				case 2:this.number = 100;break;
			}  //这里的更新的this.number的值代表了后面定时器的事件,毫秒级
			this.blockCreat() //调用生成方块的函数
		}
		这里没有用var来声明变量,而是用了this,是为了后面作用域会用到
****4.方块的生成,这里用到了定时器,每隔多少秒就会有一个方块生成,从上方落下****
        game.prototype.blockCreat = function(){	
			that = this;  新建变量that=this,因为this跟着函数走,在定时器里有写了一个函数,防止拿不到外面的this
			clearInterval(this.t)  //每次执行都要先清除定时器,不然会越来越快,速度会叠加
			this.t = setInterval(function(){ //开启定时器
				var count = random(0,that.box.offsetWidth-30);//方块初始水平位置,random为封装好的函数,根据传的参数,
				                                              会取到 0 ~(盒子宽度-方块宽度),【封装的函数在后面】
				var val;   //val是用来存随机生成的数字转换后的字母
				that.oblock = document.createElement('div');   //创建方块(div)
				that.oblock.className = 'block';  //设置方块的class名
				that.oblock.style.left = count + 'px'; //方块左偏移量
				that.box.appendChild(that.oblock);  //将生成的方块(div)追加到界面中
				val = String.fromCharCode(random(65,90)); //ASCII码转换,这里由于不区分大小写,所以之选一种【65~90】
				that.oblock.innerHTML = val;  //将随机生成的字母设置为方块的内容
				that.blockArr.push(that.oblock);  //将生成的元素存入数组blockArr中去
				that.keyDown() //按键检测函数
				that.blockMove();//方块移动函数
			},this.number);  //上面提到的,根据索引确定难度后设置的时间
		}
		这里关键的其实就是随机字母的生成以及转换,以及要想到讲方块元素存入数组,因为后面移除的时候要找到指定的这个元素
****5.键盘检测,根据按下的键,取到对应的值,判断和方块的内容是否一致,一致就移除****
        game.prototype.keyDown = function(){
			that = this;   //同理
			document.onkeydown=function(e){  //键盘函数
				e = e || window.which   //这里是兼容处理
				for(var i=0;i<that.blockArr.length;i++){ // 遍历数组,取到每一个创建的方块元素
					if(String.fromCharCode(e.keyCode) == that.blockArr[i].innerHTML){  //判断,按下的值与数组中的某一位值相等,
					                                                                   若相等,则:
						that.blockArr[i].remove();   //移除对应元素
						that.blockArr.splice(i,1);   //删除数组的对应位置,防止出现空值,不删除的话,下次按到同样的按键是,
						                               就会找到空值,没有效果
						that.text += 1;  //分数+1
						break;   //找到后就结束循环,避免同时删除多个,只删除最下面的一个
					}
				}
			}
		}
		这里主要的就是数组遍历来进行方块元素和数组的操作,还有就是循环的结束,不能让循环正常结束,除非是没有找到
		对应的,不然就会删掉数组中所有满足条件的值,这样的话就感觉不太好玩了。所以要在找到第一个满足条件的时候,
		删除对应元素,然后就要结束循环。
		还有一个要注意的就是当删除了数组索引对应元素时,一定要删除数组中这个位置的值,不然会一直占据这个位置,而且
		还是一个空值。
		【可以自行尝试不写‘that.blockArr.splice(i,1)’写上后的区别,以及不加‘break’的区别】
6.方块的移动
        game.prototype.blockMove = function(){
			var otop = this.box.offsetHeight-this.oblock.offsetHeight; //方块距离顶部的距离
			move1(this.oblock,{top:otop},()=>{ //方块到底了,游戏结束,计算总分
			                                    这里调用了封装好的move函数,有三个参数:
			                                    第一个是元素
			                                    第二个参数是要进行的动作(可以以对象形式传参)
			                                    第三个参数是一个函数,是动作完成之后要做的事
				alert('总分'+this.text+'分'); //弹出弹窗,显示分数
				window.history.go(0) //结束后刷新界面
			});
		}
4、封装的函数
****move函数,控制元素的移动以及一些属性变化****
//获取非行内样式
    function getStyle(obj,attr){    //获取非行内样式,obj为对象,attr是值
		if(obj.currentStyle){          //针对IE浏览器获取非行内样式,因为有兼容
			return obj.currentStyle[attr];   
		}else{
			return getComputedStyle(obj,false)[attr];    //针对非IE浏览器的非行内样式获取
		};
	};


****//move函数(多元素多属性的链式缓冲),会接受三个参数****
	function move1(ele,json,callback){
	       clearInterval(ele.t);
	       ele.t = setInterval(() => {  //在计时器每次开启后,for-in每次遍历前,创建状态,用来记录是否有属性没到终点
	           var onoff = true;
	           for(var i in json){
	               var iNow = parseInt(getStyle(ele,i));
	               var speed = 2;
	               speed = speed<0 ? Math.floor(speed) : Math.ceil(speed);
	               //如果有一个属性到目标,不一定清除计时器
	               //如果有一个属性没有到目标,一定不清楚计时器
	               //如果没有属性没到目标,一定要清楚定时器
	               //状态,记录,所有属性有没有到目标
	               //只要有属性没到终点,改变状态
	               if(iNow != json[i]){
	                   onoff = false;
	               }
	               ele.style[i] = iNow + speed + "px";
	           }
				//for-in结束后(每个属性都遍历一次后),如果状态没有被改变,意味着没有属性到终点,可以结束了
	           if(onoff){
	               clearInterval(ele.t);
	               callback && callback();
	           }
	       }, 30);
	   }


****随机数****
       function random(max,min){  //就收参数,两个数值
	   	   return Math.round(Math.random()*(max-min)+min)  //利用了Math.random()函数,然后取整
	   }

【这里封装好的move、获取非行内样式以及随机数的函数,有需要的朋友可以拿去使用,本次案例到此结束,欢迎交流。网页文件会上传到资源,有需要的可以自行下载!】

猜你喜欢

转载自blog.csdn.net/BookstoreSpirit/article/details/100740174