亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

JavaScript實現俄羅斯方塊游戲過程分析及源碼分享

2019-11-20 12:52:50
字體:
來源:轉載
供稿:網友

觀摩一下《編程之美》:“程序雖然很難寫,卻很美妙。要想把程序寫好,需要寫好一定的基礎知識,包括編程語言、數據結構與算法。程序寫得好,需要縝密的邏輯思維能力和良好的梳理基礎,而且熟悉編程環境和編程工具?!?/p>

學了幾年的計算機,你有沒有愛上編程。話說,沒有嘗試自己寫過一個游戲,算不上熱愛編程。

俄羅斯方塊曾經造成的轟動與造成的經濟價值可以說是游戲史上的一件大事,它看似簡單但卻變化無窮,令人上癮。相信大多數同學,曾經為它癡迷得茶不思飯不想。

游戲規則

1、一個用于擺放小型正方形的平面虛擬場地,其標準大?。盒袑挒?0,列高為20,以每個小正方形為單位。

2、一組由4個小型正方形組成的規則圖形,英文稱為Tetromino,中文通稱為方塊共有7種,分別以S、Z、L、J、I、O、T這7個字母的形狀來命名。

I:一次最多消除四層

J(左右):最多消除三層,或消除二層

L:最多消除三層,或消除二層

O:消除一至二層

S(左右):最多二層,容易造成孔洞

Z (左右):最多二層,容易造成孔洞

T:最多二層

方塊會從區域上方開始緩慢繼續落下。玩家可以以90度為單位旋轉方塊,以格子為單位左右移動方塊,讓方塊加速落下。方塊移到區域最下方或是著地到其他方塊上無法移動時,就會固定在該處,而新的方塊出現在區域上方開始落下。當區域中某一列橫向格子全部由方塊填滿,則該列會消失并成為玩家的得分。同時刪除的列數越多,得分指數上升。

分析與解法

每塊方塊落下的過程中,我們可以做:

1)旋轉到合適的方向

2)水平移動到某一列

3)垂直下落到底部

首先,需要用一個二維數組,area[18][10]表示18*10的游戲區域。其中,數組中值為0表示空,1表示有方塊。

方塊一共7種,每種有4種方向。定義activeBlock[4],在編譯之前這個數組的值預定算好,在程序中直接使用。

難點

 1)邊界檢查。

 //檢查左邊界,嘗試著朝左邊移動一個,看是否合法。function checkLeftBorder(){   for(var i=0; i<activeBlock.length; i++){     if(activeBlock[i].y==0){       return false;     }     if(!isCellValid(activeBlock[i].x, activeBlock[i].y-1)){       return false;     }   }   return true; } //同理,需要檢測右邊界和底邊界

 2)旋轉, 需要數理邏輯, 一個點相對另外一個點旋轉90度的問題。
 3)定時和監聽鍵盤事件機制讓游戲自動運行下去。

//開始 function begin(e){   e.disabled = true;   status = 1;   tbl = document.getElementById("area");   if(!generateBlock()){     alert("Game over!");     status = 2;     return;   }   paint();   timer = setInterval(moveDown,1000); } document.onkeydown=keyControl;

程序過程

1)用戶點開始->構造一個活動圖形, 設置定時器。

//當前活動的方塊, 它可以左右下移動, 變型。當它觸底后, 將會更新area; var activeBlock; //生產方塊形狀, 有7種基本形狀。 function generateBlock(){   activeBlock = null;   activeBlock = new Array(4);   //隨機產生0-6數組,代表7種形態。  var t = (Math.floor(Math.random()*20)+1)%7;   switch(t){     case 0:{       activeBlock[0] = {x:0, y:4};       activeBlock[1] = {x:1, y:4};       activeBlock[2] = {x:0, y:5};       activeBlock[3] = {x:1, y:5};       break;     }     //省略部分代碼..............................    case 6:{       activeBlock[0] = {x:0, y:5};       activeBlock[1] = {x:1, y:4};       activeBlock[2] = {x:1, y:5};       activeBlock[3] = {x:1, y:6};       break;     }   }   //檢查剛生產的四個小方格是否可以放在初始化的位置.   for(var i=0; i<4; i++){     if(!isCellValid(activeBlock[i].x, activeBlock[i].y)){         return false;       }     }   return true; }

2)每次向下移動后, 都檢查是否觸底, 如果觸底了, 則嘗試消行。

//消行 function deleteLine(){   var lines = 0;   for(var i=0; i<18; i++){     var j=0;     for(; j<10; j++){       if(area[i][j]==0){         break;     }   }   if(j==10){     lines++;     if(i!=0){       for(var k=i-1; k>=0; k--){         area[k+1] = area[k];       }     }     area[0] = generateBlankLine();     }   }   return lines; }

3)完了之后再構造一個活動圖形, 再設置定時器。


效果圖

有待優化

1)設置不同形狀方塊的顏色。

  思路:在創建方塊函數內,設定activeBlockColor顏色,七種不同形態方塊顏色各異(除了修改generateBlock方法之外,還需要修改paintarea方法。因為一開始考慮不周全,消除一行后,重繪方塊的同時將顏色統一,因此可以考慮移除表格n行,然后在頂部增添n行,以保證沒消除方塊的完整性)。

2)當當前方塊下落時,可以提前查看下一個方塊。

  思路:將generateBlock方法拆分成兩部分,一部分用于隨機嘗試下一個方塊,一部分用于緩存當前所要描繪的方塊。當當前方塊碰到底部被固定后,下一方塊開始描繪,同時又再次隨機產生新方塊。如此反復。

完整HTML源碼:

<!DOCTYPE><html> <head> <title>Tetris</title> <meta charset="UTF-8"><style> *{	font-family: "微軟雅黑";}.tetrisContainer{	width: 230px;	height: 400px;	position: relative;	left: 50%;	margin-left: -115px;	top: 40%;	margin-top: -200px;}#area tr td{ 	width: 20px; 	height: 20px; 	border:1px solid #ccc;} </style> </head> 	<body> 		<div class = "tetrisContainer">			<input type="button" value="開始游戲" onclick="begin(this);"/> 得分: <span id="score"> 0</span>			<table id="area" cellspacing="0" cellpadding="0" border="1" style="border-collapse:collapse"><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr></table>		</div>	</body> 	<script type="text/javascript" src="script/tetris.js"></script></html> 

完整tetris.js源碼:

/** * JS俄羅斯方塊游戲 v 1.0*/ //表示頁面中的table, 這個table就是將要顯示游戲的主面板 var tbl; //游戲狀態 0: 未開始;1 運行; 2 中止; var status = 0; //定時器, 定時器內將做moveDown操作 var timer; //分數 var score = 0; //area是一個18*10的數組,也和頁面的table對應。初始時都為0, 如果被占據則為1 var area = new Array(18); for(var i=0;i<18;i++){ 	area[i] = new Array(10); } for(var i=0;i<18;i++){ 	for(var j=0; j<10; j++){ 		area[i][j] = 0; 	} } //當前活動的方塊, 它可以左右下移動, 變型。當它觸底后, 將會更新area; var activeBlock; //生產方塊形狀, 有7種基本形狀。 function generateBlock(){ 	activeBlock = null; 	activeBlock = new Array(4); 	//隨機產生0-6數組,代表7種形態。	var t = (Math.floor(Math.random()*20)+1)%7; 	switch(t){ 		case 0:{ 			activeBlock[0] = {x:0, y:4}; 			activeBlock[1] = {x:1, y:4}; 			activeBlock[2] = {x:0, y:5}; 			activeBlock[3] = {x:1, y:5}; 			break; 		} 		case 1:{ 			activeBlock[0] = {x:0, y:3}; 			activeBlock[1] = {x:0, y:4}; 			activeBlock[2] = {x:0, y:5}; 			activeBlock[3] = {x:0, y:6}; 			break; 		} 		case 2:{ 			activeBlock[0] = {x:0, y:5}; 			activeBlock[1] = {x:1, y:4}; 			activeBlock[2] = {x:1, y:5}; 			activeBlock[3] = {x:2, y:4}; 			break; 		} 		case 3:{ 			activeBlock[0] = {x:0, y:4}; 			activeBlock[1] = {x:1, y:4}; 			activeBlock[2] = {x:1, y:5}; 			activeBlock[3] = {x:2, y:5}; 			break; 		} 		case 4:{ 			activeBlock[0] = {x:0, y:4}; 			activeBlock[1] = {x:1, y:4}; 			activeBlock[2] = {x:1, y:5}; 			activeBlock[3] = {x:1, y:6}; 			break; 		} 		case 5:{ 			activeBlock[0] = {x:0, y:4}; 			activeBlock[1] = {x:1, y:4}; 			activeBlock[2] = {x:2, y:4}; 			activeBlock[3] = {x:2, y:5}; 			break; 		} 		case 6:{ 			activeBlock[0] = {x:0, y:5}; 			activeBlock[1] = {x:1, y:4}; 			activeBlock[2] = {x:1, y:5}; 			activeBlock[3] = {x:1, y:6}; 			break; 		} 	} 	//檢查剛生產的四個小方格是否可以放在初始化的位置. 	for(var i=0; i<4; i++){ 		if(!isCellValid(activeBlock[i].x, activeBlock[i].y)){ 				return false; 			} 		} 	return true; } //向下移動 function moveDown(){ 	//檢查底邊界. 	if(checkBottomBorder()){ 		//沒有觸底, 則擦除當前圖形, 		erase(); 		//更新當前圖形坐標 		for(var i=0; i<4; i++){ 			activeBlock[i].x = activeBlock[i].x + 1; 		} 		//重畫當前圖形 		paint(); 	} 	//觸底, 	else{ 		//停止當前的定時器, 也就是停止自動向下移動. 		clearInterval(timer); 		//更新area數組. 		updatearea(); 		//消行 		var lines = deleteLine(); 		//如果有消行, 則 		if(lines!=0){ 			//更新分數 			score = score + lines*10; 			updateScore(); 			//擦除整個面板 			erasearea(); 			//重繪面板 			paintarea(); 		} 		//產生一個新圖形并判斷是否可以放在最初的位置. 		if(!generateBlock()){ 			alert("Game over!"); 			status = 2; 			return; 		} 		paint(); 		//定時器, 每隔一秒執行一次moveDown 		timer = setInterval(moveDown,1000) 	} } //左移動 function moveLeft(){ 	if(checkLeftBorder()){ 		erase(); 		for(var i=0; i<4; i++){ 			activeBlock[i].y = activeBlock[i].y - 1; 		} 		paint(); 		} 	} 	//右移動 function moveRight(){ 	if(checkRightBorder()){ 		erase(); 		for(var i=0; i<4; i++){ 			activeBlock[i].y = activeBlock[i].y + 1; 		} 		paint(); 	} } //旋轉, 因為旋轉之后可能會有方格覆蓋已有的方格. //先用一個tmpBlock,把activeBlock的內容都拷貝到tmpBlock, //對tmpBlock嘗試旋轉, 如果旋轉后檢測發現沒有方格產生沖突,則 //把旋轉后的tmpBlock的值給activeBlock. function rotate(){ 	var tmpBlock = new Array(4); 	for(var i=0; i<4; i++){ 		tmpBlock[i] = {x:0, y:0}; 	} 	for(var i=0; i<4; i++){ 		tmpBlock[i].x = activeBlock[i].x; 		tmpBlock[i].y = activeBlock[i].y; 	} 	//先算四個點的中心點,則這四個點圍繞中心旋轉90度。 	var cx = Math.round((tmpBlock[0].x + tmpBlock[1].x + tmpBlock[2].x + tmpBlock[3].x)/4); 	var cy = Math.round((tmpBlock[0].y + tmpBlock[1].y + tmpBlock[2].y + tmpBlock[3].y)/4); 	//旋轉的主要算法. 可以這樣分解來理解。 	//先假設圍繞源點旋轉。然后再加上中心點的坐標。 	for(var i=0; i<4; i++){ 		tmpBlock[i].x = cx+cy-activeBlock[i].y; 		tmpBlock[i].y = cy-cx+activeBlock[i].x; 	} 	//檢查旋轉后方格是否合法. 	for(var i=0; i<4; i++){ 	if(!isCellValid(tmpBlock[i].x,tmpBlock[i].y)){ 		return; 	} } //如果合法, 擦除 erase(); //對activeBlock重新賦值. for(var i=0; i<4; i++){ 	activeBlock[i].x = tmpBlock[i].x; 	activeBlock[i].y = tmpBlock[i].y; } //重畫. paint(); } //檢查左邊界,嘗試著朝左邊移動一個,看是否合法。function checkLeftBorder(){ 	for(var i=0; i<activeBlock.length; i++){ 		if(activeBlock[i].y==0){ 			return false; 		} 		if(!isCellValid(activeBlock[i].x, activeBlock[i].y-1)){ 			return false; 		} 	} 	return true; } //檢查右邊界,嘗試著朝右邊移動一個,看是否合法。function checkRightBorder(){ 	for(var i=0; i<activeBlock.length; i++){ 		if(activeBlock[i].y==9){ 			return false; 		} 		if(!isCellValid(activeBlock[i].x, activeBlock[i].y+1)){ 			return false; 		} 	} 	return true; } //檢查底邊界,嘗試著朝下邊移動一個,看是否合法。function checkBottomBorder(){ 	for(var i=0; i<activeBlock.length; i++){ 		if(activeBlock[i].x==17){ 			return false; 		} 		if(!isCellValid(activeBlock[i].x+1, activeBlock[i].y)){ 			return false; 		} 	} 	return true; } //檢查坐標為(x,y)的是否在area種已經存在, 存在說明這個方格不合法。function isCellValid(x, y){ 	if(x>17||x<0||y>9||y<0){ 		return false; 	} 	if(area[x][y]==1){ 		return false; 	} 	return true; } //擦除 function erase(){ 	for(var i=0; i<4; i++){ 		tbl.rows[activeBlock[i].x].cells[activeBlock[i].y].style.backgroundColor="white"; 	} } //繪活動圖形 function paint(){ 	for(var i=0; i<4; i++){ 		tbl.rows[activeBlock[i].x].cells[activeBlock[i].y].style.backgroundColor="#CC3333"; 	} } //更新area數組 function updatearea(){ 	for(var i=0; i<4; i++){ 		area[activeBlock[i].x][activeBlock[i].y]=1; 	} } //消行 function deleteLine(){ 	var lines = 0; 	for(var i=0; i<18; i++){ 		var j=0; 		for(; j<10; j++){ 			if(area[i][j]==0){ 				break; 		} 	} 	if(j==10){ 		lines++; 		if(i!=0){ 			for(var k=i-1; k>=0; k--){ 				area[k+1] = area[k]; 			} 		} 		area[0] = generateBlankLine(); 		} 	} 	return lines; } //擦除整個面板 function erasearea(){ 	for(var i=0; i<18; i++){ 		for(var j=0; j<10; j++){ 			tbl.rows[i].cells[j].style.backgroundColor = "white"; 		} 	} } //重繪整個面板 function paintarea(){ 	for(var i=0;i<18;i++){ 		for(var j=0; j<10; j++){ 			if(area[i][j]==1){ 				tbl.rows[i].cells[j].style.backgroundColor = "#CC3333"; 			} 		} 	} } //產生一個空白行. function generateBlankLine(){ 	var line = new Array(10); 	for(var i=0; i<10; i++){ 		line[i] = 0; 	} 	return line; } //更新分數 function updateScore(){ 	document.getElementById("score").innerText=" " + score; } //鍵盤控制 function keyControl(){ 	if(status!=1){ 		return; 	} 	var code = event.keyCode; 	switch(code){ 		case 37:{ 			moveLeft(); 			break; 		} 		case 38:{ 			rotate(); 			break; 		} 		case 39:{ 			moveRight(); 			break; 		} 		case 40:{ 			moveDown(); 			break; 		} 	} } //開始 function begin(e){ 	e.disabled = true; 	status = 1; 	tbl = document.getElementById("area"); 	if(!generateBlock()){ 		alert("Game over!"); 		status = 2; 		return; 	} 	paint(); 	timer = setInterval(moveDown,1000); } document.onkeydown=keyControl; 
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品国产综合久久| 国产一区二区日韩| 日本高清久久天堂| 热久久视久久精品18亚洲精品| 中文字幕国产亚洲2019| 欧美日韩第一页| 久久亚洲精品一区二区| 精品久久香蕉国产线看观看gif| 欧美精品手机在线| 亚洲精品视频在线播放| 欧美国产日韩一区二区三区| 精品国产成人av| 欧美国产精品va在线观看| 国产精品久久久久秋霞鲁丝| 亚洲毛茸茸少妇高潮呻吟| 久久久精品国产亚洲| 亚洲国产精久久久久久| 国产精品一区二区三区免费视频| 国产视频久久久久| 77777亚洲午夜久久多人| 成人激情春色网| 亚洲免费福利视频| 黑人巨大精品欧美一区二区三区| 国产精品爽黄69| 久久成年人免费电影| 国产精品久久久久久久久久新婚| 精品国产一区二区三区久久久狼| 日韩激情av在线免费观看| 97在线看免费观看视频在线观看| 色综合久久中文字幕综合网小说| 国产免费一区二区三区香蕉精| 中文字幕少妇一区二区三区| 午夜精品一区二区三区在线视频| 青草青草久热精品视频在线网站| 亚洲free性xxxx护士hd| 欧美三级欧美成人高清www| 亚洲欧洲在线视频| 尤物tv国产一区| 久久久精品影院| 色综合久综合久久综合久鬼88| 青青草国产精品一区二区| 久久躁狠狠躁夜夜爽| 98午夜经典影视| 亚洲性夜色噜噜噜7777| 欧美性猛交xxxx久久久| 亚洲欧美日韩一区二区在线| 91成人在线播放| 亚洲国产欧美在线成人app| 中文字幕欧美日韩va免费视频| 国产精品久久久久久亚洲调教| 欧美一区二区三区……| 久久影院免费观看| 欧美成人国产va精品日本一级| 4k岛国日韩精品**专区| 色与欲影视天天看综合网| 国产精品视频yy9099| 国产精品自拍偷拍视频| 成人两性免费视频| 裸体女人亚洲精品一区| 欧美亚洲在线观看| 欧美成人午夜影院| 久久久亚洲国产| 国产精品扒开腿做爽爽爽视频| 亚洲第一页中文字幕| 日本亚洲欧洲色α| 欧美日韩在线观看视频小说| 国产97免费视| 久热精品视频在线观看| 91精品国产91久久久久久| 狠狠色噜噜狠狠狠狠97| 日韩精品免费在线视频观看| 这里只有精品视频| 88国产精品欧美一区二区三区| 成人国产在线激情| 国产成人精品免高潮费视频| 久久91超碰青草是什么| 亚洲一区第一页| 欧美在线视频网| 亚洲国产精品视频在线观看| 国产在线视频91| 久久综合九色九九| 成人性生交大片免费看视频直播| 亚洲精品视频在线观看视频| 亚洲美女av在线| 久久久久久久久国产| 国产成人精品久久| 国产精品久久久久久久av电影| 日韩电影中文字幕| 亚洲jizzjizz日本少妇| 欧美精品一区二区三区国产精品| 久久久久久有精品国产| 亚洲高清免费观看高清完整版| 一区二区三区国产视频| 亚洲人成欧美中文字幕| 久久成人精品视频| 欧美性极品少妇精品网站| 欧美视频在线观看免费| 欧美中文字幕精品| 岛国av午夜精品| 最新亚洲国产精品| 欧美激情videos| 国产一区二区三区在线| 国产精品白丝jk喷水视频一区| 欧美人与性动交| 久久久久久香蕉网| 欧美日韩国产页| 91国内揄拍国内精品对白| 欧美日韩国产精品一区二区三区四区| 8090成年在线看片午夜| 亚洲成人精品久久久| 久久99久久99精品免观看粉嫩| 欧洲成人午夜免费大片| 欧美激情三级免费| 国产精品夫妻激情| 日本精品视频在线观看| 国产午夜精品全部视频播放| 国产精品久久9| 色av中文字幕一区| 97av在线视频免费播放| 最近2019年手机中文字幕| 26uuu国产精品视频| 亚洲日韩中文字幕| 久久香蕉精品香蕉| 91久久国产精品| 久久久999成人| 亚洲欧美另类中文字幕| 91av视频在线观看| 欧美日韩ab片| 成人国产精品日本在线| 欧美午夜片欧美片在线观看| 亚洲成人在线网| 亚洲四色影视在线观看| 亚洲网站视频福利| 亚洲成人动漫在线播放| 国产精品久久久久久久久久| 久久亚洲精品小早川怜子66| 国产精品久久久亚洲| 欧美一级成年大片在线观看| 人九九综合九九宗合| 亚洲精品成人久久电影| 亚洲区免费影片| 黑人精品xxx一区| 欧美人与性动交| 少妇高潮久久77777| 神马久久桃色视频| 成人做爽爽免费视频| 欧美精品在线极品| 欧美日韩免费看| 亚洲精品成人久久久| 亚洲欧美日韩国产精品| 欧美性猛交xxxx黑人| 日韩激情片免费| 亚洲电影免费在线观看| 亚洲国产精品久久久久久| 欧美电影免费观看电视剧大全| 国产亚洲激情在线| 国产精品丝袜视频| 亚洲成人久久一区| 久久国产视频网站| 影音先锋欧美在线资源| 日本一区二区不卡| 国产一区二区三区视频| 岛国av一区二区| 国产热re99久久6国产精品|