html5游戏开发-弹幕+仿雷电小游戏demo
本游戏使用的是html5的canvas,运行游戏需要浏览器支持html5。
本篇文章详细讲解如何用html5来开发一款射击游戏,雷电可以说是射击游戏中的经典,下面就来模仿一下。
先看一下游戏截图
演示地址
http://fsanguo.comoj.com/html5/barrage/index.html
游戏开发,需要用到开源库件:LegendForHtml5Programming。
LegendForHtml5Programming1.1下载地址:
http://legendforhtml5programming.googlecode.com/files/LegendForHtml5Programming1.1.zip
游戏预计用到下面几个文件
index.html
js文件夹|---Main.js
|---Plain.js//飞机
|---Bullet.js//子弹
|---Global.js//共通
images文件夹|--图片
我简单说一下制作过程,源代码在最下面
首先建立index.html文件,
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>弹幕</title>
<!--
<meta name="viewport" content="width=480,initial-scale=0.5, minimum-scale=0.5, maximum-scale=1.0,user-scalable=no" />
-->
<meta name="viewport" content="width=480,initial-scale=0.6" />
<script type="text/javascript" src="../legend/legend.js"></script>
<script type="text/javascript" src="./js/Global.js"></script>
<script type="text/javascript" src="./js/Bullet.js"></script>
<script type="text/javascript" src="./js/Plain.js"></script>
<script type="text/javascript" src="./js/Main.js"></script>
</head>
<body>
<p id="mylegend">loading……</p>
</body>
</html>
打开Main.js
在里面添加代码,先将图片全部读取,并显示进度条
以及,将一些可能会用到的变量添加进去
/**
* Main
* */
//设定游戏速度,屏幕大小,回调函数
init(50,"mylegend",480,800,main);
/**层变量*/
//显示进度条所用层
var loadingLayer;
//游戏最底层
var backLayer;
//控制层
var ctrlLayer;
/**int变量*/
//读取图片位置
var loadIndex = 0;
//贞数
var frames = 0;
//BOOS START
var boosstart = false;
//GAME OVER
var gameover = false;
//GAME CLEAR
var gameclear = false;
//得分
var point = 0;
/**对象变量*/
//玩家
var player;
//得分
var pointText;
/**数组变量*/
//图片path数组
var imgData = new Array();
//读取完的图片数组
var imglist = {};
//子弹数组
var barrage = new Array();
//子弹速度数组
var barrageSpeed = [5,10];
//储存所有敌人飞机的数组
var enemys = new Array();
function main(){
//准备读取图片
imgData.push({name:"back",path:"./images/back.jpg"});
imgData.push({name:"enemy",path:"./images/e.png"});
imgData.push({name:"player",path:"./images/player.png"});
imgData.push({name:"boss",path:"./images/boss.png"});
imgData.push({name:"ctrl",path:"./images/ctrl.png"});
imgData.push({name:"item1",path:"./images/1.png"});
//实例化进度条层
loadingLayer = new LSprite();
loadingLayer.graphics.drawRect(1,"black",[50, 200, 200, 20],true,"#ffffff");
addChild(loadingLayer);
//开始读取图片
loadImage();
}
function loadImage(){
//图片全部读取完成,开始初始化游戏
if(loadIndex >= imgData.length){
removeChild(loadingLayer);
legendLoadOver();
gameInit();
return;
}
//开始读取图片
loader = new LLoader();
loader.addEventListener(LEvent.COMPLETE,loadComplete);
loader.load(imgData[loadIndex].path,"bitmapData");
}
function loadComplete(event){
//进度条显示
loadingLayer.graphics.clear();
loadingLayer.graphics.drawRect(1,"black",[50, 200, 200, 20],true,"#ffffff");
loadingLayer.graphics.drawRect(1,"black",[50, 203, 200*(loadIndex/imgData.length), 14],true,"#000000");
//储存图片数据
imglist[imgData[loadIndex].name] = loader.content;
//读取下一张图片
loadIndex++;
loadImage();
}
现在,所用到的图片已经全部都加载完毕,先添加背景,显示一张图片
用legend库件显示图片非常简单
function gameInit(event){
//游戏底层实例化
backLayer = new LSprite();
addChild(backLayer);
//添加游戏背景
bitmapdata = new LBitmapData(imglist["back"]);
bitmap = new LBitmap(bitmapdata);
backLayer.addChild(bitmap);}
效果如下
射击游戏,子弹是亮点,如何添加多种子弹是游戏的关键
要使子弹有变化,必须要设定相应的角度,加速度,等多种变量
下面为了实现这些变化,我们来建立一个子弹类
/**
* 子弹类
* */
function Bullet(belong,x,y,angle,xspeed,yspeed,aspeed,speed){
base(this,LSprite,[]);
var self = this;
//子弹所属
self.belong = belong;
//出现位置
self.x = x;
self.y = y;
//角度
self.angle = angle;
//移动速度
self.speed = speed;
//xy轴速度
self.xspeed = xspeed;
self.yspeed = yspeed;
//旋转角度加成
self.aspeed = aspeed;
//子弹图片
var bitmapdata,bitmap;
bitmapdata = new LBitmapData(imglist["item1"]);
bitmap = new LBitmap(bitmapdata);
self.bitmap = bitmap;
//显示
self.addChild(bitmap);
}
然后,在子弹移动过程中,根据这些变量来实现多种变换
在共通类中,加入一个子弹数组,用来区分各种子弹
/**
* 子弹类型数组
* 【开始角度,增加角度,子弹速度,角度加速度,子弹总数,发动频率,枪口旋转】
* */
Global.bulletList = new Array(
{startAngle:0,angle:20,speed:5,aspeed:0,count:1,shootspeed:10,sspeed:0},//1发
);
游戏最基本的子弹,当然就是每次发一个子弹
在共通类里建一个发射子弹的函数
/**
* 发射子弹
* @param 飞机
* */
Global.setBullet = function(plainObject){
var i,j,obj,xspeed,yspeed,kaku;
//获取子弹属性
var bullet = Global.bulletList[0];
//开始发射
for(i=0;i<bullet.count;i++){
//发射角度
kaku = i*bullet.angle + bullet.startAngle;
//子弹xy轴速度
xspeed = bullet.speed*Math.sin(kaku * Math.PI / 180);
yspeed = barrageSpeed[0]*Math.cos(kaku * Math.PI / 180);
//子弹实例化
obj = new Bullet(0,210,300,kaku,xspeed,yspeed,bullet.aspeed,bullet.speed);
//显示
backLayer.addChild(obj);
barrage.push(obj);
}
};
这里,最终需要根据发射的飞机不同而不同,所以我加入了参数飞机
那现在建立飞机类,如下
/**
* 飞机类
* */
function Plain(name,belong,x,y,bullets){
base(this,LSprite,[]);
var self = this;
//飞机名称
self.name = name;
//飞机位置
self.x = x;
self.y = y;
//飞机所属
self.belong = belong;
//子弹数组
self.bullets = bullets;
//初始子弹
self.bullet = self.bullets[Math.floor(Math.random()*self.bullets.length)];
self.shootspeed = Global.bulletList[self.bullet].shootspeed;
//枪口旋转角度
self.sspeed = 0;
//射击频率控制
self.shootctrl = 0;
//获取飞机属性
self.list = Global.getPlainStatus(self);
//飞机图片
self.bitmap = self.list[0];
//显示
self.addChild(self.bitmap);
//枪口位置
self.shootx = self.list[1];
self.shooty = self.list[2];
//移动速度
self.speed = self.list[3];
//飞机hp
self.hp = self.list[4];
//移动方向
self.move = [0,0];
//发射子弹数
self.shootcount = 0;
//是否发射子弹
self.canshoot = true;
if(name=="player")self.canshoot = false;
}
/**
* 循环
* */
Plain.prototype.onframe = function (){
var self = this;
//移动
self.x += self.move[0]*self.speed;
self.y += self.move[1]*self.speed;
switch (self.name){
case "player":
//自机移动位置限制
if(self.x < 0)self.x = 0;
else if(self.x + self.bitmap.getWidth() > LGlobal.width)self.x = LGlobal.width-self.bitmap.getWidth();
if(self.y < 0)self.y = 0;
else if(self.y + self.bitmap.getHeight() > LGlobal.height)self.y = LGlobal.height-self.bitmap.getHeight();
break;
case "boss":
//敌机BOSS移动
if(self.y < 0){
self.y = 0;
self.move[1] = 1;
}else if(self.y + self.bitmap.getHeight() > LGlobal.height){
self.y = LGlobal.height-self.bitmap.getHeight();
self.move[1] = -1;
}
//碰撞检测
self.hitTest();
break;
case "enemy":
default:
//碰撞检测
self.hitTest();
}
//射击
if(self.canshoot)self.shoot();
};
/**
* 碰撞检测
* */
Plain.prototype.hitTest = function (){
var self = this;
var disx,disy,sw,ew;
sw = (self.bitmap.getWidth() + self.bitmap.getHeight())/4;
ew = (player.bitmap.getWidth() + player.bitmap.getHeight())/4;
disx = self.x+sw - (player.x + ew);
disy = self.y+self.bitmap.getHeight()/2 - (player.y + player.bitmap.getHeight()/2);
if(disx*disx + disy*disy < (sw+ew)*(sw+ew)){
player.visible = false;
gameover = true;
}
};
/**
* 射击
* */
Plain.prototype.shoot = function (){
var self = this;
if(self.shootctrl++ < self.shootspeed)return;
self.shootctrl = 0;
if(self.name == "boss"){
if(self.shootcount++ % 20 > 5)return;
}else{
if(self.shootcount++ % 10 > 5)return;
}
Global.setBullet(self);
if(self.name == "boss"){
if(self.shootcount % 20 < 5)return;
}else{
if(self.shootcount % 10 < 5)return;
}
if(self.bullets.length <= 1)return;
self.bullet = self.bullets[Math.floor(Math.random()*self.bullets.length)];
self.shootspeed = Global.bulletList[self.bullet].shootspeed;
};
代码已经加入了详细的注释,不难理解吧
完善子弹类如下
/**
* 子弹类
* */
function Bullet(belong,x,y,angle,xspeed,yspeed,aspeed,speed){
base(this,LSprite,[]);
var self = this;
//子弹所属
self.belong = belong;
//出现位置
self.x = x;
self.y = y;
//角度
self.angle = angle;
//移动速度
self.speed = speed;
//xy轴速度
self.xspeed = xspeed;
self.yspeed = yspeed;
//旋转角度加成
self.aspeed = aspeed;
//子弹图片
var bitmapdata,bitmap;
bitmapdata = new LBitmapData(imglist["item1"]);
bitmap = new LBitmap(bitmapdata);
self.bitmap = bitmap;
//显示
self.addChild(bitmap);
}
/**
* 循环
* @param 子弹序号
* */
Bullet.prototype.onframe = function (index){
var self = this;
//子弹移动
self.x += self.xspeed;
self.y += self.yspeed;
//子弹角度变更
if(self.aspeed != 0){
self.angle += self.aspeed;
//子弹角度变更后,重新计算xy轴速度
self.xspeed = self.speed*Math.sin(self.angle * Math.PI / 180);
self.yspeed = self.speed*Math.cos(self.angle * Math.PI / 180);
}
//子弹位置检测
if(self.x < 0 || self.x > LGlobal.width || self.y < 0 || self.y > LGlobal.height){
//从屏幕移除
backLayer.removeChild(self);
//从子弹数组移除
barrage.splice(index,1);
}else{
self.hitTest(index);
}
};
/**
* 子弹碰撞检测
* @param 子弹序号
* */
Bullet.prototype.hitTest = function (index){
var self = this;
var disx,disy,sw,ew,obj,i;
if(self.belong == player.belong){
//自机子弹
for(i=0;i<enemys.length;i++){
obj = enemys[i];
sw = self.bitmap.getWidth()/2;
ew = obj.bitmap.getWidth()/2;
disx = self.x+sw - (obj.x + ew);
disy = self.y+self.bitmap.getHeight()/2 - (obj.y + obj.bitmap.getHeight()/2);
//距离检测
if(disx*disx + disy*disy < ew*ew){
obj.hp--;
if(obj.hp == 0){
point += 1;
pointText.text = point;
//从屏幕移除
backLayer.removeChild(obj);
//从敌机数组移除
enemys.splice(i,1);
if(obj.name == "boss"){
gameclear = true;
}
}
//从屏幕移除
backLayer.removeChild(self);
//从子弹数组移除
barrage.splice(index,1);
}
}
}else{
//敌机子弹
obj = player;
sw = self.bitmap.getWidth()/2;
ew = obj.bitmap.getWidth()/2;
disx = self.x+sw - (obj.x + ew);
disy = self.y+self.bitmap.getHeight()/2 - (obj.y + obj.bitmap.getHeight()/2);
//距离检测
if(disx*disx + disy*disy < ew*ew - 10){
obj.visible = false;
gameover = true;
//从屏幕移除
backLayer.removeChild(self);
//从子弹数组移除
barrage.splice(index,1);
}
}
};
子弹发射函数,修改如下
/**
* 发射子弹
* @param 飞机
* */
Global.setBullet = function(plainObject){
var i,j,obj,xspeed,yspeed,kaku;
//获取子弹属性
var bullet = Global.bulletList[plainObject.bullet];
//设定枪口旋转
plainObject.sspeed += bullet.sspeed;
//开始发射
for(i=0;i<bullet.count;i++){
//发射角度
kaku = i*bullet.angle + bullet.startAngle + plainObject.sspeed;
//子弹xy轴速度
xspeed = bullet.speed*Math.sin(kaku * Math.PI / 180);
yspeed = barrageSpeed[0]*Math.cos(kaku * Math.PI / 180);
//子弹实例化
obj = new Bullet(plainObject.belong,plainObject.x+plainObject.shootx,plainObject.y+plainObject.shooty,kaku,xspeed,yspeed,bullet.aspeed,bullet.speed);
//显示
backLayer.addChild(obj);
barrage.push(obj);
}
};
在Main文件里添加循环
/**
* 循环
* */
function onframe(){
var i;
//循环子弹
for(i=0;i<barrage.length;i++){
barrage[i].onframe(i);
}
//循环敌机
for(i=0;i<enemys.length;i++){
enemys[i].onframe();
}
}
现在,我只需要添加飞机,就可以发射子弹了
plain = new Plain("enemy",1,200,300,[0]);
看效果
修改,子弹的相应参数,如下
/**
* 子弹类型数组
* 【开始角度,增加角度,子弹速度,角度加速度,子弹总数,发动频率,枪口旋转】
* */
Global.bulletList = new Array(
{startAngle:0,angle:20,speed:5,aspeed:0,count:1,shootspeed:10,sspeed:0},//1发
{startAngle:-20,angle:20,speed:5,aspeed:0,count:3,shootspeed:10,sspeed:0},//3发
{startAngle:0,angle:20,speed:5,aspeed:0,count:1,shootspeed:1,sspeed:20},//1发旋转
{startAngle:0,angle:20,speed:5,aspeed:0,count:18,shootspeed:3,sspeed:0},//环发
{startAngle:0,angle:20,speed:5,aspeed:1,count:18,shootspeed:3,sspeed:0},//环发旋转
{startAngle:180,angle:20,speed:5,aspeed:0,count:1,shootspeed:5,sspeed:0},//1发up
{startAngle:160,angle:20,speed:5,aspeed:0,count:3,shootspeed:5,sspeed:0}//3发up
);
效果分别为
最后附上所有源码下载