Ein kleines Tetris-Spiel in JavaScript (sehr einfach und detailliert)

bewirken

Schreiben Sie ein externes Framework

<!DOCTYPE html>
<html>
	<head lang="en">
		<meta charset="UTF-8">
		<title></title>
		<style>
*{
    margin: 0;
    padding: 0;
}
#box{
	width:320px;
	height:450px;
	position:absolute;
	margin:0 auto;
	left:0;
	top:20px;
	right:0;
	bottom:0;
	background:gray;
	border-radius:10px;
}
#mainDiv{
	width:300px;
	height:400px;
	position:absolute;
	margin:0 auto;
	left:0;
	top:10px;
	right:0;
	bottom:0;
}
.bottom{
	width:600px;
    height:30px;
	position:absolute;
	bottom:1px;
	right:1px;
}
.bottom .button1{
	position: absolute;
    right: 55px;
    width: 50px;
    font-size: 14px;
}
.bottom .button2{
	position: absolute;
    right: 5px;
    width: 50px;
    font-size: 14px;
}
.bottom .span1{
	position: absolute;
    right: 155px;
    color: white;
    font-size: 8px;
}
.bottom .span2{
	position: absolute;
    right: 255px;
    color: white;
    font-size: 8px;
}
</style>
	</head>
	<body>
		<div id='box'>
			<div id='mainDiv'>
			</div>
			<div class='bottom'>
				<span id='score' class='span1'>分数:0</span>
				<span id='time' class='span2'>时间:0</span>
				<button onclick='start()' class='button1'>开始</button>
				<button onclick='stop()' class='button2'>结束</button>
			</div>
		</div>
		
	<script type="text/javascript" src='tetris.js'></script>
	<script type="text/javascript">

	
</script>
	</body>
</html>

bewirken:

Fügen Sie eine interne Leinwand hinzu und zeichnen Sie eine Karte

Erstellen Sie zuerst den Linienkonstruktor Line

function Line(ctx,o){
		this.x=0,//x坐标
		this.y=0,//y坐标
		this.startX=0,//开始点x位置
		this.startY=0, //开始点y位置
		this.endX=0,//结束点x位置
		this.endY=0;//结束点y位置
		this.thin=false;//设置变细系数
		this.ctx=ctx;
		
		this.init(o);
	}
	Line.prototype.init=function(o){
		for(var key in o){
			this[key]=o[key];
		}
	}
	Line.prototype.render=function(){
		innerRender(this);
		
		function innerRender(obj){
			var ctx=obj.ctx;
			ctx.save()
			ctx.beginPath();
			ctx.translate(obj.x,obj.y);
			if(obj.thin){
				ctx.translate(0.5,0.5);
			}
			if(obj.lineWidth){//设定线宽
				ctx.lineWidth=obj.lineWidth;
			}
			if(obj.strokeStyle){
				ctx.strokeStyle=obj.strokeStyle;
			}
			//划线
		  	ctx.moveTo(obj.startX, obj.startY);
		  	ctx.lineTo(obj.endX, obj.endY);
		  	ctx.stroke();
		  	ctx.restore();
		}
	  	
	  	return this;
	}

Stellen Sie Parameter ein, führen Sie das Zeichnen und andere verwandte Methoden aus

function Game(el){
		this.renderArr=[];//待渲染对象存储数组
		this.aliveModel=[];//用来存到底的model组合
		
		this.score=0;//分数
		this.time=0;//时间
		this.moveCount=1;//计时控制器
	}
	
	Game.prototype.init=function(el,score,time){
		if(!el) return ;
		this.el=el;
		this.scoreEL=score;
		this.timeEL=time;
		var canvas = document.createElement('canvas');//创建画布
		canvas.style.cssText="background:darkgrey;border:1px solid grey;";//设置样式
		var W = canvas.width = 300; //设置宽度
		var H = canvas.height = 400;//设置高度
		
		el.appendChild(canvas);//添加到指定的dom对象中
		
		this.ctx = canvas.getContext('2d');
		this.canvas=canvas;
		this.w=W;
		this.h=H;
		
		this.disX=20;//每个格子的x方向大小
		this.disY=20;//每个格子的y方向大小
		this.maxX=15;//x方向格子总数
		this.maxY=20;//y方向格子总数
		
		this.control();//
		this.draw();//绘制
	}
	
	//绘制地图
	Game.prototype.createMap=function(){
		var renderArr = this.renderArr;
		var disX = this.disX;
		var disY = this.disY;
		var maxX=this.maxX;
		var maxY=this.maxY;
		var rectW = this.w;
		var rectH = this.h;
		var rect=null;
		var color;
		
		for(var i=1;i<maxY;i++){//20行
			var line = new Line(this.ctx,{
				x:0,
				y:0,
			 	startX:0,
			 	startY:i*disY,
			 	endX:this.w,
			 	endY:i*disY,
			 	thin:true,
			 	strokeStyle:'white',
			 	lineWidth:0.2
			})
			renderArr.push(line);
		}
		
		for(var i=1;i<maxX;i++){//15列
			var line = new Line(this.ctx,{
				x:0,
				y:0,
			 	startX:i*disX,
			 	startY:0,
			 	endX:i*disX,
			 	endY:this.h,
			 	thin:true,
			 	strokeStyle:'white',
			 	lineWidth:0.2
			})
			renderArr.push(line);
		}
	}
	
	Game.prototype.draw=function(){
		this.createMap();//绘制地图
		
		this.render();//渲染
	}

Zu diesem Zeitpunkt sind das Raster und die Zeichnung des Spielbereichs wie folgt:

Lassen Sie uns das Modell noch einmal zeichnen

Modelldefinition: Es gibt 7 Typen, einschließlich einer Form, Feldform, zwei Formen, zwei Formen, zwei Formen, geprägten Formen usw.

Definition der Verformung: 1 Form kann in 2 Arten verformt werden, Tian-Form kann nicht verformt werden und andere Formen können in 4 Arten verformt werden.

Die Zusammensetzung des Modells: Das Modell besteht aus 4 kleinen Quadraten, und jedes Modell verfügt über eine Reihe von Blöcken, um auf die x- und y-Koordinaten der 4 kleinen Quadrate zuzugreifen und sie dann als Modell zu zeichnen.

Modellverformung: Bei der Verformung müssen Sie nur die X \ Y-Koordinaten jedes Quadrats ändern, um den Verformungseffekt zu erzielen.

Erstellen wir den Konstruktor des Modells

	//模型构造函数
	function Model(o){
		this.blocks=[],//存储方块的数组,绘制的时候根据数组来绘制
		this.type=1,//模型的形状,默认是一字形(共7种)
		this.dir=1,//方向默认为1,总共4种,其中一字形为2种,田字形为1种,其他为4种
		this.x=0,//x坐标(只传入第一个x,根据这个x来生成其他的x)
		this.y=0,//y坐标(只传入第一个y,根据这个y来生成其他的y)
		
		this.init(o);
	}
	//初始化
	Model.prototype.init=function(o){
		for(var key in o){
			this[key]=o[key];
		}
	}

Zum Beispiel

Fügen Sie eine Methode hinzu, um eine siebenförmige Form zu erstellen (da es vier Möglichkeiten gibt, die siebenförmige Form zu platzieren, sodass es ein Verzeichnis gibt, um sie zu unterscheiden und wie sie platziert wird).

//创建七字形1
	Model.prototype.createQi1=function(){
		var blocks=this.blocks,x=this.x,y=this.y;
		switch(this.dir){
			case 1://
				blocks.push({x:x,y:y});
				blocks.push({x:x,y:y-1});
				blocks.push({x:x,y:y-2});
				blocks.push({x:x+1,y:y-2});
				break;
			case 2://
				blocks.push({x:x+2,y:y});
				blocks.push({x:x+1,y:y});
				blocks.push({x:x,y:y});
				blocks.push({x:x,y:y-1});
				break;	
			case 3://
				blocks.push({x:x+1,y:y-2});
				blocks.push({x:x+1,y:y-1});
				blocks.push({x:x+1,y:y});
				blocks.push({x:x,y:y});
				break;	
			case 4://
				blocks.push({x:x-2,y:y-1});
				blocks.push({x:x-1,y:y-1});
				blocks.push({x:x,y:y-1});
				blocks.push({x:x,y:y});
				break;	
		}
	}

Versuchen Sie, eine Form mit sieben Zeichen zu erstellen (das eingehende x und y sind der erste Ort, an dem sie platziert werden).

	var model = new Model({//创建1字
			x:6,y:6,fillStyle:'#0370BD',fill:true,game:this,type:5,dir:1
		});
		this.renderArr.push(model);
		//当前的模型
		this.currentModel=model;

Schreiben Sie die Verformungsmethode auf (jede Verformung wird entsprechend dem vorherigen Erscheinungsbild um 90 Grad gegen den Uhrzeigersinn gedreht, und ändern Sie jedes kleine Quadrat x, y, um es zu ändern).

   ------------------------ >>> 

Wie ändere ich die Abbildung links, um zur Abbildung rechts zu wechseln?

   -------------------- >>>   

Es ist leicht zu verstehen, wenn Sie die Zahl markieren, 1 entspricht 1, 2 oder 2 usw., außer dass sich X \ Y geändert hat.

1 Quadrat: Solange x + 2 ist, können Sie sich an die angegebene Position bewegen.

2 Quadrate: Sowohl x als auch y müssen um 1 erhöht werden

3 Quadrate: y + 2 ist in Ordnung

4 Quadrate: x-1 und y + 1 sind genug

Die anderen sind die gleichen. Lassen Sie uns über die Verformungsmethode schreiben

//七1变形
	Model.prototype.transformQi1=function(){
		var blocks = this.blocks,block2=blocks[1];
		switch(this.dir){
			case 1://竖着的
				tran1();
				this.dir=2;
				break;
			case 2://横着的
				tran2();
				this.dir=3;
				break;	
			case 3://竖着的
				tran3();
				this.dir=4;
				break;
			case 4://横着的
				tran4();
				this.dir=1;
				break;			
		}

		function tran1(){//变成横着的
			for(var i=0;i<blocks.length;i++){
				block=blocks[i];
				if(i==0){
					block.x+=2;
				}else if(i==1){
					block.x+=1;
					block.y+=1;
				}else if(i==2){
					block.y+=2;
				}else if(i==3){
					block.x-=1;
					block.y+=1
				}
			}
		}
		
		function tran2(){//竖着的
			for(var i=0;i<blocks.length;i++){
				block=blocks[i];
				if(i==0){
					block.x-=1;
					block.y-=2;
				}else if(i==1){
					block.y-=1;
				}else if(i==2){
					block.x+=1;
				}else if(i==3){
					block.y+=1
				}
			}
		}
		
		function tran3(){//变成横着的
			for(var i=0;i<blocks.length;i++){
				block=blocks[i];
				if(i==3){
					block.x+=2;
				}else if(i==2){
					block.x+=1;
					block.y-=1;
				}else if(i==1){
					
				}else if(i==0){
					block.x-=1;
					block.y+=1
				}
			}
		}
		
		function tran4(){//竖着的
			for(var i=0;i<blocks.length;i++){
				block=blocks[i];
				if(i==3){
					block.x-=1;
					block.y-=2;
				}else if(i==2){
					block.x-=2;
					block.y-=1;
				}else if(i==1){
					block.x-=1;
				}else if(i==0){
					block.y+=1;
				}
			}
		}
	}

Fügen Sie w- und up-Tasten als Verformungsereignisse hinzu und fügen Sie Ereignisse für Linksbewegung, Rechtsbewegung und Abwärtsbeschleunigung hinzu

//按键的控制
	Game.prototype.control=function(){
		var that=this;
		global.addEventListener('keydown',function(e){
			//if(!that.timmer) return ;
			switch (e.keyCode){
				case 87://w
				case 38://上
					that.currentModel.transform();//变形
					break;
				case 83://s
				case 40://下
					that.currentModel.move('d');//移动
					break;
				case 65://a
				case 37://左
					that.currentModel.move('l');//移动
					break;
				case 68://d
				case 39://右
					that.currentModel.move('r');//移动
					break;
			
			}
			//测试用,记得删除
			that.render();
		});
	}

Versuchen Sie als nächstes, sich zu verformen

 

Mobile Methode hinzufügen

//移动
	Model.prototype.move=function(dir){
		var cur = this.game.currentModel,dis=1,blocks = this.blocks;
		if(dir=='r'||dir=='ld'){
			dis=1
		}else if(dir=='l'){
			dis=-1;
		}else if(dir=='d'){
			dis=3;
		}
		
		var stopMoveObj = this.stopMove(dir,dis),
			val=stopMoveObj.val,resDis=stopMoveObj.resDis;
		if(val) {
			if(dir=='d'||dir=='ld'){//到底了
				[].push.apply(this.game.aliveModel,cur.blocks);//放到已到底的组合中
				this.game.renderArr.pop();//当前模型弹出
				this.game.clearBlock();//消除
				this.game.createModel();//绘制一个新图形
			}
			
			return ;//如果返回true 则不能再往这个方向移动
		}

		if(resDis>0){
			dis=resDis;
		}
		//更新每一个block的位置
		for(var i=0;i<blocks.length;i++){
			block=blocks[i];
			if(dir=='d'||dir=='ld'){
				block.y+=dis;
			}else{
				block.x+=dis;
			}
		}
	}

Fügen Sie eine Grenzbeurteilung und eine Kollisionserkennung hinzu (die Grenzerkennung ist relativ einfach, und die Kollisionserkennung sollte beim schnellen Vorlauf sorgfältig behandelt werden, siehe Code).

//停止移动
	Model.prototype.stopMove=function(dir,dis){
		var cur = this.game.currentModel,blocks = this.blocks;
		
		var maxX = this.game.maxX,maxY = this.game.maxY,res,temp;
		for(var i=0;i<blocks.length;i++){
			block=blocks[i];
			if(dir=='d'||dir=='ld'){
				if(block.y>=maxY-1){//到底了
					return {val:true};
				}
			}else if(dir=='r'){
				if(block.x>=maxX-1){//到右边界了
					return {val:true};
				}
			}else if(dir=='l'){
				if(block.x<=0){//到左边界了
					return {val:true};
				}
			}
			//碰撞检测
			temp=this.collide(block,dis,dir);
			if(temp.val){
				return temp;
			}
			if(!res || res.resDis==0 || (temp.resDis!=0 && temp.resDis<res.resDis)){
				res=temp;
			}
		}
		
		return res;
	}
	//检查当前模型是否与其他存底的模型相触碰
	Model.prototype.collide=function(block,dis,dir){
		var aliveModel = this.game.aliveModel,item;
		var res={},val=false,resDis=0,maxY = this.game.maxY;
		
		if(dir=='r'){//向右判断
			for(var i=0;i<aliveModel.length;i++){
				item = aliveModel[i];
				if(!item) continue;
				if(item.y==block.y && item.x==block.x+1){
					val= true;
					break;
				}
			}
		}else if(dir=='l'){//向左判断
			for(var i=0;i<aliveModel.length;i++){
				item = aliveModel[i];
				if(!item) continue;
				if(item.y==block.y && item.x==block.x-1){
					val= true;
					break;
				}
			}
		}else {//向下判断
			if(aliveModel.length>0){
				for(var i=0;i<aliveModel.length;i++){
					item = aliveModel[i];
					if(!item) continue;
					if(item.x==block.x){//下方有存在的方块
						if(item.y==block.y+1){
							val= true;
							break;
						}else if(item.y<=block.y+Math.abs(dis)){
							var temp=item.y-block.y-1;
							if(resDis==0 || temp<resDis){
								resDis = temp;
							}
						}
					}else{//下发不存在方块
						if(maxY<=block.y+Math.abs(dis)){
							var temp=maxY-block.y-1;
							if(resDis==0 || temp<resDis){
								resDis = temp;
							}
						}
					} 
				}
			}else{//第一个模型
				if(maxY<=block.y+Math.abs(dis)){
					var temp=maxY-block.y-1;
					if(resDis==0 || temp<resDis){
						resDis = temp;
					}
				}
			}
		}
		res.resDis=resDis;
		res.val=val;
		return res;
	}

 

Behandlung nach dem Ende

1. Geben Sie dem livingModel-Array des aktuellen Spielobjekts die 4 kleinen Quadrate, die dem aktuellen Modell entsprechen (es wird gezeichnet, wenn die Rendermethode ausgeführt wird). 

2. Dieses Modell muss im renderArr-Array gelöscht werden

3. Jedes Mal, wenn Sie einen Tiefpunkt erreichen, müssen Sie ein Eliminierungsurteil hinzufügen. Dieses wird eliminiert, wenn die Bedingungen erfüllt sind

4. Zeichnen Sie ein neues Modell

Zeichnen Sie den Modellblock mit Boden

//绘制存底的图形
	Game.prototype.aliveModelRender=function(){
		var context=this.ctx;
		var disX=this.disX,disY=this.disY;
		context.save();
		context.beginPath();
		_.each(this.aliveModel,function(item){
			if(item){
				context.rect(item.x*disX+1,item.y*disY+1,disX-1,disY-1);
				//context.fillStyle='';
				context.fill();
			}
		});
		context.restore();
	}

Beseitigen Sie Linien, Punkte und Tropfen

//消除行
	Game.prototype.clearBlock=function(){
		var maxX=this.maxX,aliveModel=this.aliveModel;
		//将y相同的放在一起
		var rowArr=[],rowObj={};
		_.each(aliveModel,function(item,index){
			if(item) {
				if(!rowObj[item.y]){
					rowObj[item.y]=[];
				}
				rowObj[item.y].push(index);
			}
		});
		
		var that=this;
		var keys = Object.keys(rowObj),row,num=0;
		_.each(keys,function(k){
			row = rowObj[k];
			if(row.length>=maxX){//消除这行
				_.each(row,function(r){
					aliveModel.splice(r,1,undefined);//先用undefined代替
				})
				
				num++;//行数计数器
				that.down(k,1);//清楚当前行
			}
		})
		
		//完成消除
		for(var i=0;i<aliveModel.length;i++){
			if(!aliveModel[i]) {
				console.log(123)
				aliveModel.splice(i,1);
			}
		}
		
		var score = 0;
		switch (num){
			case 1:
				score=100;//1行100分
				break;
			case 2:
				score=300;//2行300分
				break;
			case 3:
				score=600;//3行600分
				break;
			case 4:
				score=1000;//4行1000分
				break;
		}
		//积分
		this.calcuScore(score);
	}
	
	//消除后的下降
	Game.prototype.down=function(y,num){
		var aliveModel=this.aliveModel;
		_.each(aliveModel,function(item){
			if(item && item.y<y){
				item.y+=num;
			}
		});
	}

Automatisch nach unten bewegen, aktualisieren, Zeit anzeigen, Punktzahl

//显示分数
	Game.prototype.calcuScore=function(s){
		this.score+=s;
		this.scoreEL.innerText='分数:'+this.score;
	}
	//显示时间
	Game.prototype.calcuTime=function(){
		if(this.moveCount%4==0){
			this.time++;
			this.time_flag=false;
			this.timeEL.innerText='时间:'+this.time;
		}
		
		this.moveCount++;
	}
	//向下移动
	Game.prototype.move=function(dir){
		var curModel= this.currentModel;
		this.calcuTime();
		
		var endFlag = this.end();
		if(endFlag) {
			this.stop();
			this.hasEnd=true;
			return ;
		} 
		
		this.update();
		this.render();
	}
	//更新
	Game.prototype.update=function(){
		this.currentModel.move('ld');
	}

Fügen Sie den Start- und Endschaltflächen Ereignisse hinzu

	var mainDiv = document.getElementById('mainDiv');
	var score= document.getElementById('score');
	var time= document.getElementById('time');
	
	game.init(mainDiv,score,time);
	
	function start(){
		game.start()
	}
	
	function stop(){
		game.stop()
	}
Game.prototype.start=function(){
		if(this.timmer) return ;
		if(this.hasEnd){//如果是结束则需要重新开始,暂停的话就继续游戏
			this.restart();
		}
		this.hasEnd=false;
		this.timmer = setInterval(this.move.bind(this),250);//开始定时任务
	}
	
	//重新开始
	Game.prototype.restart=function(){
		this.renderArr=[];//待渲染对象存储数组
		this.aliveModel=[];//用来存到底的model组合
		
		this.score=0;//分数
		this.time=0;//时间
		this.moveCount=1;//计时控制器
		
		this.clearCanvas();
		this.draw();
	}
	//停止任务	
	Game.prototype.stop=function(){
		if(!this.timmer) return ;
		clearInterval(this.timmer);//清除定时任务
		this.timmer=null;
	}
	//结束
	Game.prototype.end=function(){
		var aliveModel = this.aliveModel;
		for(var i=0;i<aliveModel.length;i++){
			item = aliveModel[i];
			if(item&&item.y==0){
				alert('结束了')
				return true;
			}
		}
		return false
	}

 

Quellcode herunterladen, keine Punkte erforderlich

Gib es drei Firmen, Brüder!

Ich denke du magst

Origin blog.csdn.net/dkm123456/article/details/114103563
Empfohlen
Rangfolge