zoukankan      html  css  js  c++  java
  • function类html5游戏开发零基础开发《圣诞老人送礼物》小游戏

    这段时光一直在查找function类之类的问题,今天正好有机会和大家分享一下.

        

    开言:

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

        你可以先测试一下游戏:

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

        

        function和类

        

    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外部

        游戏界面宽

        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

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

        function和类
    光有界面也不能叫游戏,接下来就是游戏主体部份。

        我们先前提到过类,当初就来用类实战一下。首先来看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);
    }

        其中有一个LAnimation方法,它是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和类

    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();
    }

        好了,运行一下代码:

        function和类

        哈哈~~,还不错吧。

        

        

    3,源代码下载

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

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


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

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

        欢迎大家转载我的文章。

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

        http://blog.csdn.net/yorhomwang

        欢迎继承关注我的博客

    文章结束给大家分享下程序员的一些笑话语录: Borland说我很有前途,Sun笑了;Sun说我很有钱,IBM笑了;IBM说我很专业,Sybase笑了;Sybase说我数据库很牛,Oracle笑了;Oracle说我是开放的,Linux笑了;Linux说我要打败Unix,微软笑了;微软说我的系统很稳定,我们都笑了。

    --------------------------------- 原创文章 By
    function和类
    ---------------------------------

  • 相关阅读:
    4、提取看似无用的委托变量,减少构造开销
    Cloud Foundry buildpack
    mysql中engine=innodb和engine=myisam的区别
    Maven中dependencyManagement的作用
    bean
    servlet
    web服务器 应用服务器区别 web框架
    Java和Python的Web开发
    spring mvc controller 高并发问题
    es 批量添加数据
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3112969.html
Copyright © 2011-2022 走看看