溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

【HTML】【實踐】使用Canvas制作網(wǎng)頁小游戲

發(fā)布時間:2020-03-01 20:07:37 來源:網(wǎng)絡(luò) 閱讀:1722 作者:wanghaz 欄目:移動開發(fā)

    HTML5中新增了Canvas元素,這個元素非常好玩,使用Canvas,我們可以使用代碼繪制出我們想要的圖形,用代碼繪圖,光是想想就興奮啊。

    于是我在學(xué)習(xí)了Canvas的部分內(nèi)容后,動手制作了一款小游戲,這也是本人第一次獨立開發(fā)web項目,所以內(nèi)行人看到細(xì)節(jié)肯定忍不住吐槽,希望大家批評指正,給出寶貴意見,我們共同進(jìn)步。

    一、游戲介紹:

這個游戲的界面非常簡單,左邊一塊用Canvas繪制的畫布,右邊有4個按鈕,左邊的畫布上有一個紅色的方塊和一個黑色的方塊,紅色的方塊是我們操作的對象,它是一個1×1×2的長方體,現(xiàn)在它正立在畫布上,將1×1的面朝向玩家,我們可以點擊右側(cè)的四個按鈕操作這個長方體,讓這個長方體在畫布上滾動,根據(jù)用戶的點擊,這個長方體會將不同的面朝向玩家,而玩家的目標(biāo)就是通過操作這個長方體將它插入到畫布上黑色方塊所代表的洞中,另外,如果玩家的操作會導(dǎo)致長方體的任何部位懸空,那操作是無法執(zhí)行的,會提示“無法前進(jìn)”!目前這個游戲的功能比較簡單,難度也不大,如果經(jīng)過后期修改完善,增加更多無法前進(jìn)的區(qū)域,這個游戲是很有挑戰(zhàn)性的。

【HTML】【實踐】使用Canvas制作網(wǎng)頁小游戲    按下向下按鈕,長方體向下滾動,原來的圖案變成了這樣:

【HTML】【實踐】使用Canvas制作網(wǎng)頁小游戲


如果此時按左鍵,會彈出錯誤警告:

【HTML】【實踐】使用Canvas制作網(wǎng)頁小游戲

按下右鍵,也會導(dǎo)致長方體的部分懸空,所以也會彈出同樣的警告

最終我們要將長方體完整無誤地插入洞中,也就是大概做到這樣:

【HTML】【實踐】使用Canvas制作網(wǎng)頁小游戲

這時,只要按下向上,就能將長方體插入洞中,完成目標(biāo):

【HTML】【實踐】使用Canvas制作網(wǎng)頁小游戲

下面來談?wù)劸唧w實現(xiàn)。



    二、設(shè)計思路及代碼實現(xiàn)

    游戲的實現(xiàn)主要是利用了Csnvas元素的繪圖方法,通過用戶點擊按鈕,產(chǎn)生指令,將指令傳遞給特定的函數(shù),通過函數(shù)判斷長方體是否可以前進(jìn),將會產(chǎn)生怎樣的結(jié)果,然后通過Canvas重繪圖形。

    1、首先,我們將游戲界面繪制出來,

    

<canvas id="map"  width="500px" height="500px">你的瀏覽器不支持canvas</canvas>
<!--按鈕-->
<br />
<div id="control">
<div class="up"  onClick="oTangle.moveUp()"><img src="arrow_up_128px_1137748_easyicon.net.png" /></div>
<br />
<div class="left" onClick="oTangle.moveLeft()"><img src="arrow_left_128px_1137746_easyicon.net.png" /></div>
<div class="down" onClick="oTangle.moveDown()"><img src="arrow_down_128px_1137745_easyicon.net.png" /></div>
<div class="right" onClick="oTangle.moveRight()"><img src="arrow_right_128px_1137747_easyicon.net.png" /></div>

</div>

    以上代碼制作了界面的主體布局,包括一張畫布,和包含4個作為按鈕的div的控制區(qū)域。

    然后為以上元素添加樣式:

<style>
div#control {
	float:left;
	width:500px;
	height:500px;
	position:absolute;
	left:500px;
	top:0;
}
div#control div {
	width:100px;
	height:100px;
	border-radius:25px;
	text-align:center;
	padding : 0px;
	box-shadow:2px 2px 1px #CCC;	
}
div.up {
position:absolute;
left:200px;
top:80px;
}
div.left {
position:absolute;
left:80px;
top:200px;
}
div.right {
position:absolute;
left:320px;
top:200px;
}
div.down {
position:absolute;
left:200px;
top:320px;
}
img {
opacity:0.2;
filter:alpha(opacity=40); 
}
img:hover
{
opacity:1.0;
filter:alpha(opacity=100);
}
</style>

    然后,使用以下代碼繪制地圖和黑洞:

var oLines = document.getElementById("map").getContext("2d");

for(var i =0;i<4; i++)
{
oLines.moveTo(100+100*i,0);
oLines.lineTo(100+100*i,500);
oLines.stroke();
oLines.moveTo(0,100+100*i);
oLines.lineTo(500,100+100*i);
oLines.stroke();
}
oLines.save();
oLines.fillStyle="#000000";
oLines.fillRect(100,100,100,100);
oLines.restore();

    將以上代碼封裝到一個map()函數(shù)中,用于以后調(diào)用

    然后,繪制我們操作的長方體,初始狀態(tài)下,長方體是立著的,代碼如下:

var tangle = document.getElementById("map").getContext("2d");
tangle.fillStyle = "#FF00FF";
tangle.fillRect(0,0,100,100);

    至此,我們繪制出了游戲所需要的游戲界面,下面我們通過代碼實現(xiàn)游戲的操作

    2、定義對象

    我們可以定義一個對象來代表這個長方體,這個對象應(yīng)該包含以下屬性:

    狀態(tài):表示長方體當(dāng)前是直立、橫躺還是豎躺的字符串變量。

    坐標(biāo):表示長方體在畫布上的位置(這里用長方形左上角的點)的Number類型變量。

    長、寬、高:用于重繪時進(jìn)行計算的數(shù)字常量。

    對象還應(yīng)包含表示向各個方向滾動的4個方法,與四個按鈕的響應(yīng)事件向?qū)?yīng)

    具體如下:

var oTangle = new Object;
oTangle.sErect = "erect";  /*長方體的狀態(tài)*/
oTangle.x = 2;			/*當(dāng)前坐標(biāo)x*/
oTangle.y = 2;			/*當(dāng)前坐標(biāo)y*/
/*代表的顯示在地圖上的長方形的左上角的坐標(biāo)*/
oTangle.length = 100;
oTangle.width = 100;
oTangle.height = 200;

oTangle.moveRight = function()/*長方體的4個方法*/
{
	move(oTangle.x,oTangle.y,oTangle.sErect,"right");	
};
oTangle.moveLeft = function()
{
	move(oTangle.x,oTangle.y,oTangle.sErect,"left");
};
oTangle.moveUp = function()
{
	move(oTangle.x,oTangle.y,oTangle.sErect,"up");
};
oTangle.moveDown = function()
{
	move(oTangle.x,oTangle.y,oTangle.sErect,"down");
};

    然后,我們要抽象化這張畫布,方便長方體對象進(jìn)行路徑判定,這里可以使用一個數(shù)組表示:

var mapArray = new Array();
mapArray[0] = new Array(0,0,0,0,0,0,0,0,0);
mapArray[1] = new Array(0,0,0,0,0,0,0,0,0);
mapArray[2] = new Array(0,0,1,1,1,1,1,0,0);
mapArray[3] = new Array(0,0,1,1,1,1,1,0,0);
mapArray[4] = new Array(0,0,1,1,1,1,1,0,0);
mapArray[5] = new Array(0,0,1,1,1,1,1,0,0);
mapArray[6] = new Array(0,0,1,1,1,1,1,0,0);
mapArray[7] = new Array(0,0,0,0,0,0,0,0,0);
mapArray[8] = new Array(0,0,0,0,0,0,0,0,0);

    在這里,除了畫布本身的5×5個坐標(biāo),我還把外圍2層也加入到數(shù)組中去了,這樣是為了應(yīng)對向外翻滾兩格的情況,當(dāng)然,也可以使用instanceof運算符,判斷坐標(biāo)是否為number類型,這樣就只需要建立一個5×5的二維數(shù)組就可以了,如果翻滾導(dǎo)致坐標(biāo)變成數(shù)組的length以外,將會返回Undefined,以此進(jìn)行判定。

    3、對象的方法——move()函數(shù)

    我們創(chuàng)建一個函數(shù),接受oTangle對象的屬性作為參數(shù),然后將參數(shù)傳遞到其他子程序中

    

function move(posiX,posiY,state,direction) {
if(state=="erect")
	{
		
		if(ifSuspend(posiX,posiY,"erect",direction))
		{
			
			draw(posiX,posiY,"erect",direction);
			map();
			
			posiX=oTangle.x;
			posiY=oTangle.y;
			
		}
		else
		{
			alert("無法前進(jìn)!");
		}
	}
其他情況的判定...

     在這個move()函數(shù)中,函數(shù)接受從對象的方法傳遞來的參數(shù),調(diào)用一個判定前方是否為路徑的函數(shù),然后判斷函數(shù)的返回值是否為true,即路徑合法,如果路徑合法,執(zhí)行draw()函數(shù)和map()函數(shù)重繪圖形,并讓posiX、posiY與被修改的oTangle對象的坐標(biāo)屬性同步,如果路徑不合法,則彈窗報錯。根據(jù)長方體狀態(tài)的不同,共有3種判定情況,這里只給出豎直情況的方法。

    4、路徑判定函數(shù)——ifSuspend()函數(shù)

    此函數(shù)接受從move()函數(shù)傳遞過來的oTangle對象屬性值,根據(jù)對象狀態(tài)的不同使用其坐標(biāo)(不是當(dāng)前坐標(biāo),而是玩家點擊操作后的坐標(biāo)值)和表示地圖的二維數(shù)組進(jìn)行判定:

function ifSuspend(posiX2,posiY2,state2,direction2){

var arrX=posiX2,arrY=posiY2;	

	if(state2=="erect")
	{
		
		if(direction2=="left")
		{
			if(mapArray[arrX-2][arrY])
			{
				if((posiX2==4 && posiY2==3)||(posiX2==5 && posiY2==3))
				{
					return 0;
				}
				else
				{
					return 1;
				}
			}
			else
			{
				return 0;
			}
		}
		if(direction2=="right")
		{
			
			if(mapArray[arrX+2][arrY])
			{
				
				if((posiX2==1 && posiY2==3)||(posiX2==2 && posiY2==3))
				{
					return 0;
				}
				else
				{
					return 1;
				}
			}
			else
			{
				return 0;
			}
		}
		if(direction2=="up")
		{
			if(mapArray[arrX][arrY-2])
			{
				if((posiX2==3 && posiY2==4)||(posiX2==3 && posiY2==5))
				{
					return 0;
				}
				else
				{
					return 1;
				}
			}
			else
			{
				return 0;
			}
		}
	
		if(direction2=="down")
		{
			if(mapArray[arrX][arrY+2])
			{
				if((posiX2==3 && posiY2==2)||(posiX2==3 && posiY2==1))
				{
					return 0;
				}
				else
				{
					return 1;
				}
			}
			else
			{
				return 0;
			}
		}
	}
	其他判斷情況。。。

    在函數(shù)的開始,新建了2個變量,將傳遞來的參數(shù)的值賦值給它們,因為參與判定的是oTangle對象操作后的坐標(biāo)(此時還未判定是否允許操作),而不是當(dāng)前的坐標(biāo)。

    上面給出了豎直情況下的判定,豎直狀態(tài)下,向左和向上滾動會導(dǎo)致長方形左上角的坐標(biāo)發(fā)生2個單位的偏移,而向右和向下滾動則會產(chǎn)生1個單位的偏移。如圖:

【HTML】【實踐】使用Canvas制作網(wǎng)頁小游戲

    紅色的點是當(dāng)前坐標(biāo),其他四個點的是將因玩家操作導(dǎo)致變化的結(jié)果,黑點相對紅點左移2個單位(arrX-2),黃點相對紅點右移2個單位(arrX+2),綠點相對紅點上移2個單位(arrY-2),紫點相對紅點下移1個單位(arrY-1).

    在橫躺和豎躺的情況下,還要考慮插入黑洞的情況,如果操作將導(dǎo)致長方形的坐標(biāo)等于黑洞的坐標(biāo),將退出判定,彈窗告訴玩家游戲結(jié)束。

    5、重繪圖形——draw()函數(shù)

    draw()函數(shù)使用JavaScript代碼繪制圖形,這里要調(diào)用前面繪制的tangle圖形對象。

    首先調(diào)用save()方法保存當(dāng)前狀態(tài),主要是避免下次繪圖時改變原點的位置

    然后調(diào)用clearRect()方法清除現(xiàn)在的圖形,接受4個參數(shù),表示要清除的圖形的區(qū)域坐標(biāo),(會一并清除地圖上的網(wǎng)格線,所以在上面的move()函數(shù)中再次調(diào)用了map(),事實上,在下面的代碼中,在clear()方法后面緊接著調(diào)用map(),就不會出現(xiàn)游戲中網(wǎng)格線在長方體上的BUG了,不過,不要在意這些細(xì)節(jié)是不是?

    重繪的實現(xiàn):首先,清除的區(qū)域是

((posiX4-2)*oTangle.width,(posiY4-2)*oTangle.width,oTangle.width,oTangle.length)

    這個區(qū)域表示長方體當(dāng)前的圖形,posiX4-2是因為初始的坐標(biāo)是(2,2)(如果是用instanceof來判定,就不用這樣了,罪孽?。?/p>

    fillRect()方法重繪矩形,同樣接受4個參數(shù),表示描繪矩形的區(qū)域,不同的狀態(tài),不同的方法,作為參數(shù)的公式也不相同,這里只給出豎直狀態(tài)下左滾情況下的公式。

    然后,回到前一個save()方法的狀態(tài),避免繪圖導(dǎo)致原點偏移。

    最后,修改長方體對象當(dāng)前的坐標(biāo),修改長方體對象當(dāng)前的狀態(tài),滾動完成。

function draw(posiX3,posiY3,state3,direction3)
{
var posiX4=oTangle.x,posiY4=oTangle.y;
if(state3=="erect")
{
if(direction3=="left")
{
tangle.save();
tangle.clearRect((posiX4-2)*oTangle.width,(posiY4-2)*oTangle.width,oTangle.width,oTangle.length);
tangle.fillRect((posiX4-4)*oTangle.width,(posiY4-2)*oTangle.width,oTangle.height,oTangle.width);
tangle.restore();
oTangle.x-=2;
oTangle.sErect="cross";
}
其他判斷情況。。。

    使用以上代碼,就實現(xiàn)了游戲流程,這個游戲也就完成了

    三、學(xué)習(xí)心得

    這個游戲功能(我實現(xiàn)的部分)很簡單,流程也不復(fù)雜,主要是使用了Canvas的繪制矩形的功能,很好理解,可以改進(jìn)的地方也非常多,包括BUG也不少,不過畢竟這只是一個小小的作業(yè),還有很多東西要學(xué),所以后續(xù)的開發(fā)智能擱淺了。。。。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI