【CSON原创】HTML5第一人称射击游戏发布
功能说明:
游戏中在躲避敌人攻击的同时,需要收集三种不同的钥匙,开启对应的门,最后到达目的地。
该游戏同样基于自己开发的HTML5游戏框架cnGameJS。
推荐用chrome浏览器查看。
效果预览:
方向键控制移动,空格键射击,shift键打开门。
实现分析:
在上一篇文章《HTML5实现3D迷宫》中,通过放射线法模拟出3D场景的效果,而本文则在3D效果的基础上,添加更多的游戏元素,构建成一个较完整的第一人称射击游戏。
关于如何模拟出3D场景效果上文中已经有较详细的描述,本文则主要介绍如何实现游戏互动部分。
1.游戏元素在地图上的对象和在屏幕上的对象的对应关系?
首先,每个游戏元素都对应两个游戏对象,一个游戏对象为左边地图上的对象,另一个则为右边屏幕上的对象。例如,一个敌人的位置,是否射击状态等信息都由左边的地图对象来表示,而敌人在屏幕上的显示,则是根据在左边地图上对象的信息进行绘制。简而言之,左边的地图对象负责游戏元素位置,状态的判别,它真正存储游戏信息。而右边的屏幕对象则只负责游戏元素的呈现。
newEnemy.relatedObj=new 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跳出循环,停止检测,防止击中在该敌人后面的敌人。
最后给出所有源码下载:点击下载
欢迎转载,请标明出处:http://www.cnblogs.com/Cson/archive/2012/03/05/2380963.html