您好,登錄后才能下訂單哦!
HTML5中新增了Canvas元素,這個元素非常好玩,使用Canvas,我們可以使用代碼繪制出我們想要的圖形,用代碼繪圖,光是想想就興奮啊。
于是我在學習了Canvas的部分內容后,動手制作了一款小游戲,這也是本人第一次獨立開發web項目,所以內行人看到細節肯定忍不住吐槽,希望大家批評指正,給出寶貴意見,我們共同進步。
一、游戲介紹:
這個游戲的界面非常簡單,左邊一塊用Canvas繪制的畫布,右邊有4個按鈕,左邊的畫布上有一個紅色的方塊和一個黑色的方塊,紅色的方塊是我們操作的對象,它是一個1×1×2的長方體,現在它正立在畫布上,將1×1的面朝向玩家,我們可以點擊右側的四個按鈕操作這個長方體,讓這個長方體在畫布上滾動,根據用戶的點擊,這個長方體會將不同的面朝向玩家,而玩家的目標就是通過操作這個長方體將它插入到畫布上黑色方塊所代表的洞中,另外,如果玩家的操作會導致長方體的任何部位懸空,那操作是無法執行的,會提示“無法前進”!目前這個游戲的功能比較簡單,難度也不大,如果經過后期修改完善,增加更多無法前進的區域,這個游戲是很有挑戰性的。
按下向下按鈕,長方體向下滾動,原來的圖案變成了這樣:
如果此時按左鍵,會彈出錯誤警告:
按下右鍵,也會導致長方體的部分懸空,所以也會彈出同樣的警告
最終我們要將長方體完整無誤地插入洞中,也就是大概做到這樣:
這時,只要按下向上,就能將長方體插入洞中,完成目標:
下面來談談具體實現。
二、設計思路及代碼實現
游戲的實現主要是利用了Csnvas元素的繪圖方法,通過用戶點擊按鈕,產生指令,將指令傳遞給特定的函數,通過函數判斷長方體是否可以前進,將會產生怎樣的結果,然后通過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的控制區域。
然后為以上元素添加樣式:
<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()函數中,用于以后調用
然后,繪制我們操作的長方體,初始狀態下,長方體是立著的,代碼如下:
var tangle = document.getElementById("map").getContext("2d"); tangle.fillStyle = "#FF00FF"; tangle.fillRect(0,0,100,100);
至此,我們繪制出了游戲所需要的游戲界面,下面我們通過代碼實現游戲的操作
2、定義對象
我們可以定義一個對象來代表這個長方體,這個對象應該包含以下屬性:
狀態:表示長方體當前是直立、橫躺還是豎躺的字符串變量。
坐標:表示長方體在畫布上的位置(這里用長方形左上角的點)的Number類型變量。
長、寬、高:用于重繪時進行計算的數字常量。
對象還應包含表示向各個方向滾動的4個方法,與四個按鈕的響應事件向對應
具體如下:
var oTangle = new Object; oTangle.sErect = "erect"; /*長方體的狀態*/ oTangle.x = 2; /*當前坐標x*/ oTangle.y = 2; /*當前坐標y*/ /*代表的顯示在地圖上的長方形的左上角的坐標*/ 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"); };
然后,我們要抽象化這張畫布,方便長方體對象進行路徑判定,這里可以使用一個數組表示:
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個坐標,我還把外圍2層也加入到數組中去了,這樣是為了應對向外翻滾兩格的情況,當然,也可以使用instanceof運算符,判斷坐標是否為number類型,這樣就只需要建立一個5×5的二維數組就可以了,如果翻滾導致坐標變成數組的length以外,將會返回Undefined,以此進行判定。
3、對象的方法——move()函數
我們創建一個函數,接受oTangle對象的屬性作為參數,然后將參數傳遞到其他子程序中
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("無法前進!"); } } 其他情況的判定...
在這個move()函數中,函數接受從對象的方法傳遞來的參數,調用一個判定前方是否為路徑的函數,然后判斷函數的返回值是否為true,即路徑合法,如果路徑合法,執行draw()函數和map()函數重繪圖形,并讓posiX、posiY與被修改的oTangle對象的坐標屬性同步,如果路徑不合法,則彈窗報錯。根據長方體狀態的不同,共有3種判定情況,這里只給出豎直情況的方法。
4、路徑判定函數——ifSuspend()函數
此函數接受從move()函數傳遞過來的oTangle對象屬性值,根據對象狀態的不同使用其坐標(不是當前坐標,而是玩家點擊操作后的坐標值)和表示地圖的二維數組進行判定:
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; } } } 其他判斷情況。。。
在函數的開始,新建了2個變量,將傳遞來的參數的值賦值給它們,因為參與判定的是oTangle對象操作后的坐標(此時還未判定是否允許操作),而不是當前的坐標。
上面給出了豎直情況下的判定,豎直狀態下,向左和向上滾動會導致長方形左上角的坐標發生2個單位的偏移,而向右和向下滾動則會產生1個單位的偏移。如圖:
紅色的點是當前坐標,其他四個點的是將因玩家操作導致變化的結果,黑點相對紅點左移2個單位(arrX-2),黃點相對紅點右移2個單位(arrX+2),綠點相對紅點上移2個單位(arrY-2),紫點相對紅點下移1個單位(arrY-1).
在橫躺和豎躺的情況下,還要考慮插入黑洞的情況,如果操作將導致長方形的坐標等于黑洞的坐標,將退出判定,彈窗告訴玩家游戲結束。
5、重繪圖形——draw()函數
draw()函數使用JavaScript代碼繪制圖形,這里要調用前面繪制的tangle圖形對象。
首先調用save()方法保存當前狀態,主要是避免下次繪圖時改變原點的位置
然后調用clearRect()方法清除現在的圖形,接受4個參數,表示要清除的圖形的區域坐標,(會一并清除地圖上的網格線,所以在上面的move()函數中再次調用了map(),事實上,在下面的代碼中,在clear()方法后面緊接著調用map(),就不會出現游戲中網格線在長方體上的BUG了,不過,不要在意這些細節是不是?)
重繪的實現:首先,清除的區域是
((posiX4-2)*oTangle.width,(posiY4-2)*oTangle.width,oTangle.width,oTangle.length)
這個區域表示長方體當前的圖形,posiX4-2是因為初始的坐標是(2,2)(如果是用instanceof來判定,就不用這樣了,罪孽啊)
fillRect()方法重繪矩形,同樣接受4個參數,表示描繪矩形的區域,不同的狀態,不同的方法,作為參數的公式也不相同,這里只給出豎直狀態下左滾情況下的公式。
然后,回到前一個save()方法的狀態,避免繪圖導致原點偏移。
最后,修改長方體對象當前的坐標,修改長方體對象當前的狀態,滾動完成。
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"; } 其他判斷情況。。。
使用以上代碼,就實現了游戲流程,這個游戲也就完成了
三、學習心得
這個游戲功能(我實現的部分)很簡單,流程也不復雜,主要是使用了Canvas的繪制矩形的功能,很好理解,可以改進的地方也非常多,包括BUG也不少,不過畢竟這只是一個小小的作業,還有很多東西要學,所以后續的開發智能擱淺了。。。。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。