您好,登錄后才能下訂單哦!
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)性的。
按下向下按鈕,長方體向下滾動,原來的圖案變成了這樣:
如果此時按左鍵,會彈出錯誤警告:
按下右鍵,也會導(dǎo)致長方體的部分懸空,所以也會彈出同樣的警告
最終我們要將長方體完整無誤地插入洞中,也就是大概做到這樣:
這時,只要按下向上,就能將長方體插入洞中,完成目標(biāo):
下面來談?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個單位的偏移。如圖:
紅色的點是當(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ā)智能擱淺了。。。。
免責(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)容。