功能說明:
遊戲中在躲避敵人攻擊的同時,需要收集三種不同的鑰匙,開啟對應的門,最後到達目的地。
該遊戲同樣基於自己開發的HTML5遊戲框架cnGameJS。
建議用chrome瀏覽器查看。
效果預覽:
方向鍵控制移動,空白鍵射擊,shift鍵開啟閘。
實作分析:
在上一篇文章《HTML5實現3D迷宮》中,透過放射線法模擬出3D場景的效果,而本文則在3D效果的基礎上,加入更多的遊戲元素,建構成一個較完整的第一人稱射擊遊戲。
關於如何模擬出3D場景效果上文中已經有較詳細的描述,本文則主要介紹如何實現遊戲互動部分。
1.遊戲元素在地圖上的物件和螢幕上的物件的對應關係?
首先,每個遊戲元素都對應兩個遊戲對象,一個遊戲對象為左邊地圖上的對象,另一個則為右邊螢幕上的對象。例如,一個敵人的位置,是否射擊狀態等資訊都由左邊的地圖物件來表示,而敵人在螢幕上的顯示,則是根據在左邊地圖上物件的資訊進行繪製。 簡而言之,左邊的地圖物件負責遊戲元素位置,狀態的判別,它真正儲存遊戲資訊。而右邊的螢幕物件則只負責遊戲元素的呈現。
newEnemy.relatedObj= enemy2({src:srcObj.enemy,context:screenContext}); newEnemy.relatedObj.relatedParent=newEnemy;
如上,地圖上的物件和螢幕上的物件保持互相引用的關係,這樣就可以輕易透過地圖物件存取螢幕對象,反之亦然。
2.如何使敵人在發現玩家後進行射擊?
要實現該功能,我們需要知道玩家相對於敵人的角度,該參數我們可以根據敵人到玩家的距離和它們x,y的差值求出。之後我們就可以在敵人對象的位置向該方向發射出一條射線,如果該射線能在不觸碰牆壁的時候觸碰到玩家,就證明敵人可以看到玩家。這時候敵人就可以向玩家射擊了。
nextX = enemyCenter[0]; nextY = enemyCenter[1]; while (this.map.getPosValue(nextX, nextY) == 0) { distant += 1; x = nextX; y = nextY; if (cnGame.collision.col_Point_Rect(x, y, playerRect)&&!spriteList[i].relatedObj.isCurrentAnimation("enemyDie")) { //如果地图上敌人能看到玩家,则向玩家射击 spriteList[i].isShooting = true; if (spriteList[i].lastShootTime > spriteList[i].shootDuration) {//检查是否超过射击时间间隔,超过则射击玩家 spriteList[i].shoot(player); spriteList[i].relatedObj.setCurrentImage(srcObj.enemy1); spriteList[i].lastShootTime = 0; } else { if (spriteList[i].lastShootTime > 0.1) { spriteList[i].relatedObj.setCurrentImage(srcObj.enemy); } spriteList[i].lastShootTime += duration; } break; } else { spriteList[i].isShooting = false; } nextX = distant * Math.cos(angle) + enemyCenter[0]; nextY = enemyCenter[1] - distant * Math.sin(angle); } }
3.如何偵測是否獲得鑰匙?
偵測鑰匙取得其實就是簡單地偵測玩家物件和鑰匙物件是否產生碰撞,產生碰撞則取得到鑰匙。碰撞檢測同樣發生在左邊的地圖對象。
/* 检测是否获得钥匙 */ var checkGetKeys = function() { var list = cnGame.spriteList; var playerRect= this.player.getRect(); for (var i = 0, len = list.length; i < len; i++) { if (list[i] instanceof key) { if (cnGame.collision.col_Between_Rects(list[i].getRect(),playerRect)) { this.keysValue.push(list[i].keyValue); list.remove(list[i]); i--; len--; } } } }
4.如何同時把遊戲元素和遊戲場景同時繪製在螢幕上並且保持正確的先後關係?
在css裡,我們可以使用z-Index使元素保持正確的層級關係,但是我們現在需要在canvas上繪製圖形,因此只能模擬出z-Index效果。
在之前那篇文章中說過,3D場景是由一條不同長短的像素線的繪製而成,因此在加入了其他遊戲元素之後,若要保持正確的層級關係,就需要為每個元素和像素線自訂zIndex屬性,並存放在陣列中。 每次繪製的時候數組會根據zIndex排序,使繪製有一個先後順序,從而確保層級正確。 zIndex的值會根據玩家到該元素或像素線的距離計算所得:
zIndex= Math.floor(1 / distant * 10000)
之後每次繪製就可以產生近的圖像覆蓋在遠的圖像上的效果:
# 排序:
colImgsArray.sort(function(obj1, obj2) { if (obj1.zIndex > obj2.zIndex) { return 1; } else if (obj1.zIndex < obj2.zIndex) { return -1; } else { return 0; } });
繪製:
//画出每条像素线和游戏元素 for (var i = 0, len = colImgsArray.length; i < len; i++) { var obj = colImgsArray[i]; if(obj.draw){ obj.draw(); } else{ context.drawImage(obj.img, obj.oriX, obj.oriY, obj.oriWidth, obj.oriHeight, obj.x, obj.y, obj.width, obj.height); } }
5.如何判斷玩家擊中敵人?
玩家擊中敵人的判別其實也是利用碰撞偵測,不過這次是利用元素在螢幕上的物件進行碰撞偵測。 我們只需要偵測準星(螢幕中點)與敵人物件所形成的矩形是否產生碰撞,就可以偵測到是否擊中了敵人。
for (var i = list2.length - 1; i >= 0; i--) { if (list2[i] instanceof enemy2 && list2[i].relatedParent.isShooting) { var obj = list2[i]; var enemyRect = obj.getRect();//构造敌人在屏幕上形成的矩形对象 if (cnGame.collision.col_Point_Rect(starPos[0], starPos[1], enemyRect)) { obj.setCurrentAnimation("enemyDie"); break; } } }
擊中敵人之後,需要break跳出循環,停止偵測,防止擊中在該敵人後面的敵人。
以上是HTML5第一人稱射擊遊戲實現的程式碼分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!