1. 程式人生 > >html5遊戲開發-彈幕+仿雷電小遊戲demo

html5遊戲開發-彈幕+仿雷電小遊戲demo

本遊戲使用的是html5的canvas,運行遊戲需要瀏覽器支援html5。

本篇文章詳細講解如何用html5來開發一款射擊遊戲,雷電可以說是射擊遊戲中的經典,下面就來模仿一下。

先看一下游戲截圖


演示地址

遊戲開發,需要用到開源引擎:lufylegend.js

lufylegend.js引擎下載地址

遊戲預計用到下面幾個檔案

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>
<div id="mylegend">loading……</div>

</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
);

效果分別為





lufylegend.js引擎包內包含這個demo,請直接下載lufylegend.js引擎,檢視引擎包內原始碼

lufylegend.js引擎下載地址