Native object-oriented simple Jinshan typing game

Kingsoft typing games

Insert picture description here

1. Introduction and renderings

This is a game for practicing typing. When the game starts, blocks with random letters are continuously dropped from the top of the interface. When the corresponding button is pressed, the corresponding block will be cleared.

Insert picture description here

2. Ideas

1. How to determine the difficulty?
2. How to generate squares? Generate location? How to move?
3. How to check the keyboard? How to remove after mapping?
4. The accumulation of scores after removal?
5. The game fails? Pop-up window to settle the score?

3. Code

1. Body part:
<div id="box">
			<div id="changeBox">
				<ul class="change">
					<p>金山打字</p> //标题
					<li>初级</li> //难度选项
					<li>中级</li>
					<li>高级</li>
				</ul>
			</div>
		</div>
2. The css part:
<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. Detailed explanation of js part:
****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. Encapsulated functions
****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()函数,然后取整
	   }

[The functions of move, non-inline style and random number encapsulated here can be used by friends in need. This case is over. Welcome to communicate. The web page file will be uploaded to the resource, you can download it if you need it!

Guess you like

Origin blog.csdn.net/BookstoreSpirit/article/details/100740174