html5游戏开发-零基础开发《圣诞老人送礼物》小游戏

开言:以前lufy前辈写过叫“ html5游戏开发-零基础开发RPG游戏”的系列文章,在那里面我学习了他的引擎以及了解了游戏脚本。自从看了那几篇文章,我便对游戏开发有了基本的认识。今天我也以零基础为视点,为大家讲述如何开发一款简单的游戏。希望大家看了这篇文章,能使你对理解游戏开发有帮助。

你可以先测试一下游戏:

http://lufylegend.com/lufylegend_developers/yorhom_Christmas/index.html


html5游戏开发-零基础开发《圣诞老人送礼物》小游戏

1,如何进行游戏开发


1.1游戏开发思想

本文依然要运用OOP思想(Object Oriented Programming,面向对象编程),毕竟它很重要,很方便。

首先,为了让大家了解游戏开发的一些思想,我不妨说一下我对游戏开发的理解:

在游戏开发中,不是需要一个角色就要去立刻手动建设一个角色的。倘若是一个不断变化的游戏,用手慢慢改,那还不得累死。因此我们就需要用到循环或者时间轴事件。具体用循环还是时间轴事件,要看你是如何设计游戏。循环不要说,我们主要说说时间轴事件。

时间轴事件相当于一个循环,在它内部要执行的内容会不断地执行,也就是说是一个死循环。既然是死循环,那要改变游戏里的内容就会变得相当简单。只需要在外部更改界面上的属性,然后在时间轴事件内不断判断属性,执行变化即可。

1.2类的使用

 

另外还需要注意的是,游戏开发需要用到类。javascript定义类很简单,只用定义一个函数就行,属性用this来加。如下:

 

function people(){

	this.name = "yorhom";

	this.age = "13";

}

类的作用很大,加入有界面上有3个角色,我们只用循环3次,每循环一次就用局部变量来实例化一个角色类即可。

类操作里面比较重要一项的就是继承。比如说在lufylegend.js中,如果你的类继承自LSprite类,那就拥有show方法,到时候你在使用你的类时,只用更改属性,不用手动重绘就可以更新界面。除了方便以外,它还可以替你免去一些多余的代码。假如父类有个加鼠标事件的方法,而子类想要也,那就不需要在重新写一遍了,直接继承就行了。

2,开始游戏开发


2.1开发准备

由于本次开发用到了lufylegend.js开源引擎,所以首先需要下载它。

下载地址:http://lufylegend.com/lufylegend

API 文档:http://lufylegend.com/lufylegend/api

另外,由于是html5游戏,所以你需要一个支持html5的浏览器。当然,如果你已经有了这样的浏览器,那就直接开始吧。

2.2开始编程

首先来看一下Main.js。首先定义一些层变量:

 

var backLayer,

loadingLayer,

logoLayer,

sceneLayer,

snowLayer,

stageLayer,

charaLayer,

overLayer,

gameoverLayer;


另外一些闲杂变量:

 

 

var point = 0,time = 1000*30;

var showTime;

var plopSound,backSound;

var playerName;

var pointText,timeText,resultText;


还有几个散乱的家伙藏在角落里,也被我给找到贴出来:

 

 

var snowingSpeed = 0;

var snowingSpeedIndex = 20;

var snowChildList = [];

var canSnowing = true;

var showChara = false;

 

接下来初始化引擎

 

init(50,"mylegend",600,400,main);

LSystem.screen(LStage.FULL_SCREEN);

init是引擎初始化函数,用法如下:

 

------------------------------------------------------------------------------

 

init( 
    speed, 
    divid, 
    width, 
    height, 
    completeFunc, 
    type 
)


 


■作用:

 

库件初始化

 

■参数:

speed:游戏速度设定

divid:传入一个div的id,库件进行初始化的时候,会自动将canvas加入到此div内部

width:游戏界面宽

height:游戏界面高

completeFunc:游戏初始化后,调用此函数

type:当为null时,会先进行页面的onload操作,如果你的init函数调用是在onload之后,那么需要将此参数设为LEvent.INIT

------------------------------------------------------------------------------


LSystem.screen是一调整屏幕大小的方法。如果参数写LStage.FULL_SCREEN说明调整为全屏。

接下来是加载图片:

 

var imglist = [];

var imgData = [

	{path:"./js/gameLogo.js",type:"js"},

	{path:"./js/Charactor.js",type:"js"},

	{path:"./js/Stage.js",type:"js"},

	{name:"player",path:"./images/airplane.png"},

	{name:"logoback",path:"./images/logoback.jpg"},

	{name:"background",path:"./images/background.png"},

	{name:"house",path:"./images/house.png"},

	{name:"costume0",path:"./images/costume0.png"},

	{name:"costume1",path:"./images/costume1.png"},

	{name:"costume2",path:"./images/costume2.png"},

	{name:"costume3",path:"./images/costume3.png"},

	{name:"costume4",path:"./images/costume4.png"},

	{name:"costume5",path:"./images/costume5.png"},

	{name:"costume6",path:"./images/costume6.png"},

	{name:"costume7",path:"./images/costume7.png"}

];

上面是加载图片列表,以下是加载时用的代码:

 

 

//开始加载图片

LLoadManage.load(

	imgData,

	function(progress){

		//绘制进度条

		loadingLayer.setProgress(progress);

	},

	function(result){

		imglist = result;

		removeChild(loadingLayer);

		loadingLayer = null;

		//初始化游戏

		gameInit();

		//加入开始界面

		addLogo();

	}

);

将以上代码写到main函数中,就可以实现加载图片了。LLoadManage类是lufylegend中一个加载图片的类,用它可以方便地加载图片。用法如下:

 

------------------------------------------------------------------------------

 

load($list,$onupdate,$oncomplete)


■作用:

 

读取文件组

 

■参数:

$list:文件数组

$onupdate:读取中调用函数,一般用来显示游戏进度

$oncomplete:全部文件读取完成后调用函数

 

■详细说明:

这个函数可以接收一个数组,然后加载数组里的所有文件

------------------------------------------------------------------------------

这样做的好处是可以在使用图片时更方便,只用写path对应的name上去就行了。

整个main函数代码如下:

 

function main(){

	//初始化加载层

	loadingLayer = new LoadingSample3();

	addChild(loadingLayer);

	//开始加载图片

	LLoadManage.load(

		imgData,

		function(progress){

			//绘制进度条

			loadingLayer.setProgress(progress);

		},

		function(result){

			imglist = result;

			removeChild(loadingLayer);

			loadingLayer = null;

			//初始化游戏

			gameInit();

			//加入开始界面

			addLogo();

        }

	);

	//加载声效音乐

	plopSound = new LSound();

    var plopUrl = "./sounds/plop.mp3";

    plopSound.load(plopUrl);

	//加载背景音乐

	backSound = new LSound();

    var backsoundUrl = "./sounds/back_music.mp3";

    backSound.load(backsoundUrl);

}

在上面的代码中,我用LSound类加了背景音乐,这样一来顺便试一下新功能。看看gameInit里代码:

 

 

function gameInit(){

	//初始化层

	initLayer();

	//加入时间轴事件

	backLayer.addEventListener(LEvent.ENTER_FRAME,onframe);

	//加入鼠标事件

	backLayer.addEventListener(LMouseEvent.MOUSE_DOWN,onmousedown);

}

initLayer和onmousedown中的代码:

 

 

function onmousedown(event){

	//播放声效音乐

	plopSound.play();

	if(showChara == true && stageLayer.childList.length < 6){

		//加入障碍物

		addStage();

	}

}

function initLayer(){

	//加入底板层

	backLayer = new LSprite();

	addChild(backLayer);

	//加入图标层

	logoLayer = new LSprite();

	backLayer.addChild(logoLayer);

	//加入雪花层

	snowLayer = new LSprite();

	backLayer.addChild(snowLayer);

	//加入场景层

	sceneLayer = new LSprite();

	backLayer.addChild(sceneLayer);

	//加入礼物层

	stageLayer = new LSprite();

	backLayer.addChild(stageLayer);

	//加入人物层

	charaLayer = new LSprite();

	backLayer.addChild(charaLayer);

	//加入输出层

	overLayer = new LSprite();

	backLayer.addChild(overLayer);

	//加入游戏结束层

	gameoverLayer = new LSprite();

	backLayer.addChild(gameoverLayer);

}

以上代码都添加了注释,很容易看懂。有几个引擎中的类的用法提一下,LSprite用法:

 

------------------------------------------------------------------------------

 

LSprite()


 

■作用:

 

LSprite 类是基本显示列表构造块,一个可显示图形并且也可包含子项的显示列表节点。

 

■可用属性:

type:类型

x:坐标x

y:坐标y

scaleX:X坐标方向上的缩放比例

scaleY:Y坐标方向上的缩放比例

alpha:透明度

rotate:旋转角度

visible:是否可见,当设为false的时候,该LBitmap对象不可视,且内部所有处理都将停止

childList:该对象的所有子项

graphics:指定属于此 LSprite 的 LGraphics 对象,在此 LSprite 中可执行矢量绘图命令。

box2dBody:结合box2dweb后,创建的body2d

mask:遮罩

filters:光晕效果,具体可参照LDropShadowFilter类的介绍

------------------------------------------------------------------------------

addEventListener的用法:

------------------------------------------------------------------------------

 

addEventListener(type,listener)


 

■作用:

 

注册事件侦听器对象,以使侦听器能够接收事件通知。

 

■参数:

type:事件的类型。

listener:处理事件的侦听器函数。

------------------------------------------------------------------------------

在加载函数中,我调用了addLogo,它是用来显示开场界面的。由于游戏本身很简单,所以要加一个很绚丽的开场界面。

addLogo的代码如下:

 

var logoText;

var startBtn;

function addLogo(){

	//加入背景

	var bitmapData = new LBitmapData(imglist["logoback"],0,0,1024,768);

	var bitmap = new LBitmap(bitmapData);

	bitmap.scaleX = 0.6;

	bitmap.scaleY = 0.6;

	logoLayer.addChild(bitmap);

	//加入文字

	addLogoText();

}

在其中我给背景添上图片,用到了LBitmapData和LBitmap。用法很多,大家可以自己去API里看看。这里就先不多说了。

 

addLogoText里的代码:

 

function addLogoText(){

	//大标题

	logoText = new LTextField();

    logoText.size = 50;

    logoText.color = "white";

	logoText.font = "HG行書体";

    logoText.text = "Christmas";

	logoText.stroke = true;

	logoText.lineWidth = 2;

	logoText.x = 50;

	logoText.y = 20;

    logoLayer.addChild(logoText);

	//加入滤镜效果

	var titleShadow = new LDropShadowFilter(5,45,"red");

	for(var i=0;i<2;i++){

		logoText.filters = [titleShadow];

		logoLayer.addChild(logoText);

	}

	//开始指示

	logoText = new LTextField();

    logoText.size = 30;

    logoText.color = "white";

	logoText.font = "HG行書体";

    logoText.text = "Tap to Start Game";

	logoText.x = 150;

	logoText.y = 190;

    logoLayer.addChild(logoText);

	//加入开始游戏事件

	logoLayer.addEventListener(LMouseEvent.MOUSE_UP,startGame);

	//加入滤镜效果

	var shadow = new LDropShadowFilter(5,45,"black",0);

	logoText.filters = [shadow];

}

界面运行出来后,得到了一个静态的结果,游戏嘛就得富有动态,于是我做了一个下雪效果。它在onframe函数中,也就是我们说的时间轴事件中:

 

 

if(canSnowing == true){

	//加入雪花

	addSnow();

}

接着看addSnow函数:

function addSnow(){

	snowLayer.graphics.clear();

	var snowx = Math.random()*(LStage.width-10)+10;

	var n = snowChildList.length;

	while(n--){

		var s = snowChildList[n];

		s.y += s.s;

		snowLayer.graphics.drawArc(2,"white",[s.x,s.y,2,0,2*Math.PI],true,"white");

	}

	snowChildList.push({x:snowx,y:0,s:10});

}


它实现的方法在上一篇文章中提到过,可以看看,这里就不多讲了:

 

如何制作一款HTML5 RPG游戏引擎——第二篇,烟雨+飞雪效果

http://blog.csdn.net/yorhomwang/article/details/8915020

运行代码得到一个相当酷的界面,大家可以看一下:

html5游戏开发-零基础开发《圣诞老人送礼物》小游戏
光有界面也不能叫游戏,接下来就是游戏主题部分。

我们先前提到过类,现在就来用类实战一下。首先来看charactor人物类:

 

function Charactor(data){

	base(this,LSprite,[]);

	//设定x和y坐标

	this.x = 0;

	this.y = 0;

	//设定模式

	this.mode = "right";

	this.speed = 5;

	//加入图片

	this.data = data;

	var list = LGlobal.divideCoordinate(227,158,1,1);

	var bitmapdata = new LBitmapData(imglist[this.data]);

	//加入动画

	this.anima = new LAnimation(this,bitmapdata,list);

	this.anima.setAction(0,1,0,false);

}

其中有一个LAnimationg方法,它是lufylegend中播放动画的类,使用说明如下:

 

------------------------------------------------------------------------------

 

LAnimation(layer,data,list)


 

■作用:

 

实现简单动画的播放,原理是将一张大的图片,按照保存有坐标的二维数组保存的坐标来逐个显示。

 

■参数:

layer:LSprite显示层

data:LBitmapData对象

list:一个存有坐标的2维数组

 

■详细说明:

LAnimation类实现简单动画的播放,用于制作人物行走等效果非常方便

 

■可用属性:

layer:动画显示时,LAnimation的父级层

data:LBitmapData对象

list:坐标数组。

------------------------------------------------------------------------------
其他的就很容易懂了,Charactor类有个move方法,用于人物移动,如下:

 

Charactor.prototype.move = function(){

	//当向右飞行时

	if(this.mode == "right" && this.x < LStage.width-149){

		this.anima.setAction(0,1,0,false);

		this.x += this.speed;

	}else{

		this.mode = "left";

	}

	//当向左飞行时

	if(this.mode == "left" && this.x > 0){

		this.anima.setAction(0,1,0,true);

		this.x -= this.speed;

	}else{

		this.mode = "right";

	}

}


这段代码可以使人物移动,将这段代码放在onframe中就可以实现让人物来回移动了。逻辑很简单,大家可以看看。

 

接着就是实例化人物了。代码如下:

 

function addChara(){

	oldMan = new Charactor("player");

	showChara = true;

	charaLayer.addChild(oldMan);

}

接着是onframe中的代码:

 

 

if(showChara == true){

	//使人物动起来

	oldMan.move();

	//改变时间显示

	timeText.text = "Time:" + showTime;

	if(time>0){

		time -= 30000/(30000/50);

	}else{

		playerName = getName();

		gameOver();

	}

}

在这里我门判断时间是否为0,如果为0就游戏结束。当然,这是后话,这里只提一下。

 

接下来看Stage类,这个很重要,大家一定要认真看哦!

 

var stageSpeed = 5;

function Stage(){

	base(this,LSprite,[]);

	//取出一个整数,使0<=index<=7成立

	var index = Math.floor(Math.random()*7);

	//将index的值取出对应的图片

	var bitmap = new LBitmap(new LBitmapData(imglist["costume"+index]));

	//定义礼物的模式

	this.mode = "";

	this.addChild(bitmap);

}

这是Stage类构造器。和Charactor差不多。主要是其方法:

 

 

Stage.prototype.run = function(){

	//让礼物不断下降

	this.y += stageSpeed;

	//判断是否到达边缘

	if(this.y > LStage.height){

		this.mode = "die";

	}

	this.cheackHit();

}

Stage.prototype.cheackHit = function(){

	if(this.y > 170 && this.x > 132 - 33 && this.x < 166){

		this.mode = "die";

		point++;

		changeText();

	}else if(this.y > 170 && this.x > 293 - 33 && this.x < 330){

		this.mode = "die";

		point++;

		changeText();

	}else if(this.y > 178 && this.x > 475 - 33 && this.x < 508){

		this.mode = "die";

		point++;

		changeText();

	}

}

其实很好理解,在run中,我们让礼物向下移5格,虽然只移5格,但是如果是在onframe中调用,它将不断下降。为了判断礼物是否已经送到家,我用加入cheackHit方法。我们可以用判断坐标的方法来实现。每碰到一次就更改分数,并将mode设置为die,然后在onframe中判断mode,如果mode是"die"就移除这个对象。

 

实例化Stage类:

 

function addStage(){

	var stage = new Stage();

	if(oldMan.mode == "left"){

		stage.x = oldMan.x + 70;

	}else{

		stage.x = oldMan.x + 30;

	}

	stage.y = 30;

	stageLayer.addChild(stage);

	stageLayer.scaleX = 0.8;

	stageLayer.scaleY = 0.8;

}

onframe完整代码:

 

function onframe(event){

	showTime = Math.floor(time/1000) + "s";

	if(canSnowing == true){

		//加入雪花

		addSnow();

	}

	if(backSound.playing == false){

		//播放背景音乐

		backSound.play();

	}

	if(showChara == true){

		//使人物动起来

		oldMan.move();

		//改变时间显示

		timeText.text = "Time:" + showTime;

		if(time>0){

			time -= 30000/(30000/50);

		}else{

			playerName = getName();

			gameOver();

		}

	}

	for(var key in stageLayer.childList){

		//使用Stage中run函数,让障碍物动起来

		stageLayer.childList[key].run();

		if(stageLayer.childList[key].mode == "die"){ 

			//移除该成员

			stageLayer.removeChild(stageLayer.childList[key]);

		}

	}

}

首先我们新加了一个遍历方法,遍历LSprite成员而获取每对象的状态,每遇见一个mode是die的就将它移除。

 

接下来是加入分数以及时间的函数,没有任何逻辑。大家慢慢看就能看懂的。微笑

function addText(){

	//加入分数文字

	pointText = new LTextField(); 

    pointText.size = 15;

	pointText.x = 10;

	pointText.y = 340;

    pointText.color = "white";

    pointText.text = "Point:" + point;

	pointText.font = "HG行書体";

	overLayer.addChild(pointText);

	//加入时间文字

	timeText = new LTextField(); 

    timeText.size = 15;

	timeText.x = 10;

	timeText.y = LStage.height - 30;

    timeText.color = "white";

    timeText.text = "Time:" + showTime;

	timeText.font = "HG行書体";

	overLayer.addChild(timeText);

	//加入滤镜

	var shadow = new LDropShadowFilter(0,45,"white",0);

	overLayer.filters = [shadow];

}

function changeText(){

	pointText.text = "Point:" + point;

}

以下是游戏结束调用的函数,同样是很简单:

 

 

function gameOver(){

	backLayer.die();

	//绘制成绩板

	gameoverLayer.graphics.drawRect(2,"dimgray",[0,0,400,300],true,"lightgray");

	gameoverLayer.x = 100;

	gameoverLayer.y = 50;

	gameoverLayer.scaleX = 0.5,

	gameoverLayer.scaleY = 0.5,

	gameoverLayer.alpha = 0.5,

	gameoverLayer.rotate = 50;

	var shadow = new LDropShadowFilter(5,45,"black",0);

	gameoverLayer.filters = [shadow];

	//通过缓动显示成绩板

	LTweenLite.to(gameoverLayer,1,{

		alpha:0.7,

		scaleX:1,

		scaleY:1,

		rotate:0,

		ease:Back.easeInOut,

		onComplete:resultFont

	});

}

function resultFont(){

	var resultArr = ["GAME OVER","Tap to Restart Game","分数:"+point,"评价:"+playerName];

	for(var i=0;i<resultArr.length;i++){

		//公有属性

		resultText = new LTextField();

		resultText.weight = "bold";

		resultText.text = resultArr[i];

		//私有有属性

		if(i==0){

			resultText.size = 30;

  			resultText.color = "white";

			resultText.font = "HG行書体";

			resultText.x = 70;

			resultText.y = 20;

		}else if(i==1){

			resultText.size = 15;

  			resultText.color = "white";

			resultText.font = "HG行書体";

			resultText.x = 105;

			resultText.y = 60;

		}else{

			resultText.size = 20;

  			resultText.color = "white";

			resultText.font = "HG行書体";

			resultText.x = 35;

			resultText.y = 100 + (i-1)*32;	

		}

		gameoverLayer.addChild(resultText);

	}

	//加入鼠标事件

	backLayer.addEventListener(LMouseEvent.MOUSE_DOWN,function(){

		//变量清空

		point = 0;

		time = 1000*30;

		showChara = false;

		//清空全局

		backLayer.removeAllChild();

		removeChild(backLayer);

		//游戏重开

		gameInit();

		startGame()

	});

}

重开游戏的函数:

 

 

function startGame(){

	//清空画布

	logoLayer.die();

	logoLayer.removeAllChild();

	canSnowing = false;

	//加入背景

	var backBitmapdata = new LBitmapData(imglist["background"],0,0,480,360);

	var backBitmap = new LBitmap(backBitmapdata);

	backBitmap.scaleX = 1.4;

	backBitmap.scaleY = 1.4;

	sceneLayer.addChild(backBitmap);

	//加入房屋

	var houseBitmapdata = new LBitmapData(imglist["house"],0,0,480,228);

	var houseBitmap = new LBitmap(houseBitmapdata);

	houseBitmap.scaleX = 1.4;

	houseBitmap.y = 200;

	sceneLayer.addChild(houseBitmap);

	//加入人物

	addChara();

	//加入文字

	addText();

}

 

好了,运行一下代码:

html5游戏开发-零基础开发《圣诞老人送礼物》小游戏

哈哈~~,还不错吧。


3,源代码下载

本次开发就到这里,想了解详细代码的朋友可以看看。

下载地址:http://files.cnblogs.com/yorhom/Christmas.rar


谢谢大家阅读本文。支持就是最大的鼓励。

 

----------------------------------------------------------------

欢迎大家转载我的文章。

转载请注明:转自Yorhom's Game Box

http://blog.csdn.net/yorhomwang

欢迎继续关注我的博客

 

你可能感兴趣的:(html5)