是英雄就下100层是一款经典的手机小游戏,以前是在诺基亚手机上十分有名。今天我们就用HTML5和lufylegend一步步地实现它。

一,准备工作

首先,你需要下载lufylegend,下载地址如下:

http://lufylegend.googlecode.com/files/lufylegend-1.7.0.rar

接着你需要了解lufylegend,API介绍如下:

http://lufylegend.com/lufylegend/api

接下来我们准备几张图片:

人物图片

游戏背景

游戏旁边的墙

顶部的钉子

有朋友也许看了就喷血了,内心坚强的估计都想打我了。因为我的人物图片是三国志曹操传里的。其实在下也是没办法呀,找不到图了,只有用这一张稍微长得帅一点的士兵哥哥了。

接着让我们来做初始化,首先我们需要几个层用来放人物,背景,建筑物,障碍等,所以首先定义了几个层变量。

var backLayer,loadingLayer,mapLayer,stageLayer,buildingLayer,charaLayer,overLayer;

另外一些杂七杂八的变量,都添了注释,应该能看懂的:

//加载图片用的数组
var imglist = {};
var imgData = [
{name:"player",path:"./images/player.png"},
{name:"back",path:"./images/gameback.png"},
{name:"apron",path:"./images/apron.png"},
{name:"nail",path:"./images/nail.png"}
];
//人物变量
var hero;
var charaIniX = 100;
var charaIniY = 100;
var isMirror = false;

然后进行游戏初始化:

init(30,"mylegend",stageWidth,stageHeight,main);

init是lufylegend中初始化函数,用法可以到api里面查,这里不多啰嗦了,接下来看看main函数里的东西:

function main(){
//初始化加载层
loadingLayer = new LoadingSample1();
addChild(loadingLayer);
//载入图片,并显示进度条
LLoadManage.load(
imgData,
function(progress){
loadingLayer.setProgress(progress);
},
function(result){
imglist = result;
removeChild(loadingLayer);
loadingLayer = null;
//开始游戏初始化
gameInit();
}
);
}

这个main函数是在做游戏中的图片加载,加载完后调用gameInit。可以在上面定义的变量中找到imgData,不难看出它是装有图片路径的数组,加载时就加载就能将游戏中的图片一张张地加入到了游戏中。至于LLoadManage的方法可以在api里看看,因为即使我来解释,我也只能抄抄api里的东西。

接下来看看gameInit:

function gameInit(){
//初始化层
initLayer();
//加入游戏人物
addChara();
//加入游戏事件
addEvent();
//加入游戏背景
addGameBack();
//加入游戏挡板
addApron();
//加入顶部钉子
addNail();
}

上面的代码都加了注释,应该不难看懂。(其实也应该看懂,因为全是调用函数)

到此,游戏初始化搞定。

二,游戏背景的实现

刚才我们看了gameInit,里面的动西我们还讲完,我们挨着挨着看里面调用的函数。

首先是initLayer,看英语就能知道是初始层,具体代码如下:

function initLayer(){
//加入底层
backLayer = new LSprite();
addChild(backLayer);
//加入地图层
mapLayer = new LSprite();
backLayer.addChild(mapLayer);
//加入障碍层
stageLayer = new LSprite();
backLayer.addChild(stageLayer);
//加入建筑层
buildingLayer = new LSprite();
backLayer.addChild(buildingLayer);
//加入人物层
charaLayer = new LSprite();
backLayer.addChild(charaLayer);
//加入其他层
overLayer = new LSprite();
backLayer.addChild(overLayer);
}

首先我将刚刚定义的层变量通通实例化为LSprite,可能懂点ActionScript的朋友们知道这个东西(虽然我不懂ActionScript),它就相当于一个容器,里面可以放图片,文字,按钮,绘制的图……凡所能放的,无所不能放,这就是LSprite。LSprite可以理解成一个层,因为用它可以轻易地实现层次化效果。

由于引擎是仿照Actionscript语法开发的,所以用法和ActionScript中的一样。当然不懂这玩儿意的朋友可以再去翻翻api,里面的介绍很详细。

添加好层了之后,我们开始加入人物。

看看addChara里的代码:

function addChara(){
//创建一个人物
hero = new Charactor();
//确定人物位置
hero.x = charaIniX;
hero.y = charaIniY;
//加入到人物层
charaLayer.addChild(hero);
}

这里的代码一会儿单独讲,这里不作细讲。

接着是加入事件,大家可以看看代码:

function addEvent(){
//加入鼠标事件
backLayer.addEventListener(LMouseEvent.MOUSE_DOWN,onDown);
backLayer.addEventListener(LMouseEvent.MOUSE_UP,onUp);
//加入onframe调用
backLayer.addEventListener(LEvent.ENTER_FRAME,onframe);
}
function onDown(event){
//取出鼠标坐标
var mouseX = event.offsetX;
//判断人物移动方向【点击人物右边,让人物向右移动;点击人物左边,让人物向左移动】
if(mouseX > hero.x+20){
//角色向右移动
charaMove("right");
}else if(mouseX < hero.x+20){
//角色向左移动
charaMove("left");
}else{
hero.mode = "stand";
}
}
function onUp(){
//松开鼠标后改变造型
hero.mode = "stand";
//改变站立时的方向和样子
hero.anime.setAction(0,0,1,isMirror);
}
function onframe(){
//使用Charactor中run函数,让人物动起来
hero.run();
}

至于addEventListener的使用方法可以看看api,它和js原来的addEventListener的用法不一样。另外提一下,LMouseEvent.MOUSE_DOWN是鼠标点击事件,LMouseEvent.MOUSE_UP是鼠标弹起事件。LEvent.ENTER_FRAME是时间轴事件,由于我们的界面在不断的刷新,那么每刷新一次我们就调用这个事件所对应的函数。

接下来3个函数全是绘画背景,addNail是加入顶部的钉子,addApron是加入游戏两边的墙,addGameBack是贴背景图。代码如下:

function addGameBack(){
//循环显示背景块,以便用来平铺背景
for(var i=0;i<4;i++){
for(var j=0;j<4;j++){
var backBitmapdata = new LBitmapData(imglist["back"],0,0,130,130);
var backBitmap = new LBitmap(backBitmapdata);
//每画一块后移背景块
backBitmap.x = j*130;
backBitmap.y = i*130;
mapLayer.addChild(backBitmap);
}
}
}
function addApron(){
//循环显示挡板块,以便用来铺出两条挡板
for(var i=0;i<15;i++){
for(var j=0;j<2;j++){
var apronBitmapdata = new LBitmapData(imglist["apron"],0,0,17,34);
var apronBitmap = new LBitmap(apronBitmapdata);
//每画一块后移挡板块
apronBitmap.x = j*383;
apronBitmap.y = i*34 + 20;
buildingLayer.addChild(apronBitmap);
}
}
}
function addNail(){
//循环显示钉子,以便用来铺出钉条
for(var i=0;i<30;i++){
var nailBitmapdata = new LBitmapData(imglist["nail"],0,0,14,14);
var nailBitmap = new LBitmap(nailBitmapdata);
//每画一块后移钉子
nailBitmap.x = i*14 + 5;
nailBitmap.y = 0;
buildingLayer.addChild(nailBitmap);
}
}

addGameBack中可以看见LBitmap和LBitmapData两个类,它们分别是用来贴图的,LBitmapData里是装图片数据,LBitmap是将LBitmapData里的数据画出。用法可以看看api。由于我们的背景图很小,所以我们为了添满画布,我不得不采用平铺和拉伸两种方法。在考虑采用平铺还是拉伸时,我认为平铺更能将效果处理好一些,拉伸后图片就不好看了。因此我尝试平铺,没想到lufylegend中没有平铺,没办法只有我自己写了。

我计算出有要铺满画布,我们需要横着画四次,竖着画四次。

看代码:

for(var i=0;i<4;i++){
for(var j=0;j<4;j++){
var backBitmapdata = new LBitmapData(imglist["back"],0,0,130,130);
var backBitmap = new LBitmap(backBitmapdata);
//每画一块后移背景块
backBitmap.x = j*130;
backBitmap.y = i*130;
mapLayer.addChild(backBitmap);
}
}

我弄一个循环套循环的方法,让它每铺一块就移动到下一块的位置再继续铺,这样一来就可以铺出背景了。

添加钉子和围墙的方法与其类似,不一一说了。

运行代码,效果很理想:

三,英雄降临(Hero Fall)

这一小节的名字有点奇怪。当然所谓的奇怪当然是后面的那一串英文Hero Fall。其实这个Hero Fall来自最新上映的电影007天幕杀机,它的英文是Sky fall,所以我也借此多打两三个字符。当然,我可不是来和大家交谈电影的,也不是来交谈如何多打写字符。主要目的是开发游戏。哈!

刚刚废话了一下,现在回到游戏中。

首先我们建立一个人物类Charactor,代码如下:

/**
*Charactor人物类
*/
function Charactor(){
base(this,LSprite,[]);
var self = this;
//初始化人物模式为"stand"
self.mode = "stand";
//将图片分解为装满坐标的二维数组
var list = LGlobal.divideCoordinate(192,256,4,4);
var data = new LBitmapData(imglist["player"],0,0,48,64);
//添加动画类
self.anime = new LAnimation(self,data,list);
//调整动画
self.anime.setAction(1,0,1,false);
//调整动画频率的相关变量
self.step = 2;
self.stepindex = 0;
}

首先一来就可能有朋友不懂了,base是神马?告诉你吧,是lufylegend中的继承函数,参数分别是:需要继承的类,基类(被继承的类),传给被继承类的参数,当然,api里也有介绍,想了解更多的朋友可以看看。接着我们将目光跳到self.mode这一行,这个mode在游戏中的作用很大,它包括判断是否碰到障碍物,以及任务的方向,这些都归它管。接下来来我们再看看LGlobal.divideCoordinate这个东西,它是专门用来切坐标的,用它可以把一张图片分解成一个二维数组,这样可以用来方便动画处理,可以看看api了解更多。

构造好了就可以在addChara函数中用变量hero实例化。并加到charaLayer中。

再说说LAnimation类,它是一个播放动画的类,它和LGlobal.divideCoordinate用法可以举例说明:

init(100,"legend",800,450,main);
var imgData = [ {name:"player",path:"player.png"} ];
var imglist;
var backLayer,hero;
function main(){
LLoadManage.load(imgData,null,gameInit);
}
function gameInit(result){
imglist = result;
backLayer = new LSprite();
addChild(backLayer);
var list = LGlobal.divideCoordinate(256,256,4,4);
var data = new LBitmapData(imglist["player"],0,0,64,64);
hero = new LAnimation(backLayer,data,list);
backLayer.addEventListener(LEvent.ENTER_FRAME,onframe);
}
function onframe(){
hero.onframe();
}

LAnimation类官方说明:

LAnimation类 LAnimation(layer,data,list)

■作用:
实现简单动画的播放,原理是将一张大的图片,按照保存有坐标的二维数组保存的坐标来逐个显示。
■参数:
layer:LSprite显示层
data:LBitmapData对象
list:装有坐标的二维数组
 

上面的三个参数中,layer是一个LSprite对象,data是一个LBitmapData对象,这些都比较好理解,第三个参数list是一个二维数组,它的格式如下:

[
[{x:0,y:0},{x:0,y:0},{x:0,y:0}],
[{x:0,y:0},{x:0,y:0},{x:0,y:0}],
[{x:0,y:0},{x:0,y:0},{x:0,y:0}]
]

LAnimation对象的setAction函数,有四个参数,分别为:

LAnimation.setAction(rowIndex,colIndex,mode,isMirror)
参数:
rowIndex:播放动画的行号
colIndex:播放动画的列号
mode:(1,0,-1)分别代表(正序播放,静止,倒序播放)
isMirror:Boolean型,当设定为true的时候,图片显示为水平翻转后的镜像

详细的使用方法还可以看看api。

接着添加Charactor中的run,再在run里加入动画,这样的话,人物就可以动起来了。

看看run方法:

Charactor.prototype.run = function (){
var self = this;
//将人物不断下落
self.y += fallSpeed;
//减少动画切换的频率
if(self.stepindex++ > self.step){
self.stepindex = 0;
self.anime.onframe();
}
//判断人物模式,以便用来移动人物
if(self.mode == "left"){ //向左移动时的处理
//判断人物是否到了最左画布边缘
if(self.x > 10){
self.x -= heroSpeed;
}
}else if(self.mode == "right"){ //向右移动时的处理
//判断人物是否到了最右画布边缘
if(self.x < LStage.width - self.getWidth()-20){
self.x += heroSpeed;
}
}else if(self.mode == "stand"){
return;
}
}

再定义控制下降速度和行走速度变量:

var heroSpeed = 10;
var fallSpeed = 10;

结合注释看看,其实也不难理解。首先,我们的英雄要不断下降,所以将他的y坐标不断地加。接下来播放人物动画,播放人物动画的代码还是值得我们看看:

if(self.stepindex++ > self.step){
self.stepindex = 0;
self.anime.onframe();
}

是什么意思呢?由于这个run方法是在界面每刷新一次时调用的,刷新频率由于太高了,而我们的人物动画速度是根据这个频率决定的,所以,频率有多快这个人物动画就动得这么快。因此我们假如想每100ms播放一下人物动画,就必须设定两个变量,一个是刷新次数变量另一个是限定变量。限定变量 = 要求频率÷刷新频率,刷新次数变量初始值 为0。让刷新次数变量在每次刷新后加一,然后判断是否大于那个限定变量,如果是就将刷新次数变量设为0,并播放一帧。这样就可以限定动画频率了。

接下来我们根据mode来判断人物行走方向,以及是否是行走。再看一遍代码;

if(self.mode == "left"){ //向左移动时的处理
//判断人物是否到了最左画布边缘
if(self.x > 10){
self.x -= heroSpeed;
}
}else if(self.mode == "right"){ //向右移动时的处理
//判断人物是否到了最右画布边缘
if(self.x < LStage.width - self.getWidth()-20){
self.x += heroSpeed;
}
}else if(self.mode == "stand"){
return;
}

当mode为left时,人物就往左移,减x坐标就可以;当mode为right时,人物就往右移,加x坐标就可以;当mode为right时,人物就不动。

不过mode在哪里去改呢?这还要追溯到addEvent中调用的函数。

再看一下addEvent中调用的函数:

function onDown(event){
//取出鼠标坐标
var mouseX = event.offsetX;
//判断人物移动方向【点击人物右边,让人物向右移动;点击人物左边,让人物向左移动】
if(mouseX > hero.x+20){
//角色向右移动
charaMove("right");
}else if(mouseX < hero.x+20){
//角色向左移动
charaMove("left");
}else{
hero.mode = "stand";
}
}
function onUp(){
//松开鼠标后改变造型
hero.mode = "stand";
//改变站立时的方向和样子
hero.anime.setAction(0,0,1,isMirror);
}
function onframe(){
//使用Charactor中run函数,让人物动起来
hero.run();
}

当按下鼠标时,我们在addEvent中调用的是onDown函数。接着看看onDown函数:

function onDown(event){
//取出鼠标坐标
var mouseX = event.offsetX;
//判断人物移动方向【点击人物右边,让人物向右移动;点击人物左边,让人物向左移动】
if(mouseX > hero.x+20){
//角色向右移动
charaMove("right");
}else if(mouseX < hero.x+20){
//角色向左移动
charaMove("left");
}else{
hero.mode = "stand";
}
}

首先我们取出鼠标坐标,然后判断这个位置是在人物的哪个方向,也就是判断x坐标哪个大。如果鼠标x坐标大,说明在右边,接着调用charaMove并给参数赋值为right;如果人物x坐标大,说明在左边,接着调用charaMove并给参数赋值为left;如果不大不小就就站在原地。

看看charaMove里的代码:

function charaMove(direction){
switch(direction){
case "right":
//改变人物模式"right",使其转换方向
hero.mode = "right"
hero.anime.setAction(1,0,1,true);
//改变站立时的方向变量
isMirror = true;
break;
case "left":
//改变人物模式为"left",使其转换方向
hero.mode = "left"
hero.anime.setAction(1,0,1,false);
//改变站立时的方向变量
isMirror = false;
break;
}
}

这段代码进入后就判断参数是什么,当为right就将人物的mode设定right,并改变人物样式。当为left就将人物的mode设定left,并改变人物样式。

当松开鼠标时就调用onUp,如下:

function onUp(){
//松开鼠标后改变造型
hero.mode = "stand";
//改变站立时的方向和样子
hero.anime.setAction(0,0,1,isMirror);
}

代码很简单,也就是当松开鼠标后便改变人物的样子和方向。

接下来看看onframe:

function onframe(){
//使用Charactor中run函数,让人物动起来
hero.run();
}

由于onframe是界面每刷新一次就调用一次,所以如果人物的mode改了,就会马上做出反应。

好了,运行一下看看:

按下鼠标:

测试地址:http://www.cnblogs.com/yorhom/archive/2013/04/06/3002850.html

还不错吧,英雄果然是不断下降,并且如果按下鼠标英雄会移动。

现在这个英雄是一个拿给我们玩弄的傀儡,因为这里没有他想看到的跳板。

下一次就来完成跳板和减血这一方面的内容。希望大家多支持。

本次源码下载:http://files.cnblogs.com/yorhom/jump(1).rar

『HTML5挑战经典』是英雄就下100层-开源讲座(一)从天而降的英雄的更多相关文章

  1. 『HTML5挑战经典』是英雄就下100层-开源讲座(二)危险!英雄

    本篇为<『HTML5挑战经典』是英雄就下100层-开源讲座>第二篇,需要用到开源引擎lufylegend,可以到这里下载: 下载地址:http://lufylegend.googlecod ...

  2. HTML5游戏开发_是男人就下100层

    项目流程 市场调研(可行性分析)--> 可行性报告书  需求分析师.客户经理 需求分析--> 需求说明书  项目经理.需求分析师 概要设计--> 概要设计说明书(ER图, UML)  ...

  3. 超多经典 canvas 实例,动态离子背景、移动炫彩小球、贪吃蛇、坦克大战、是男人就下100层、心形文字等等等

    超多经典 canvas 实例 普及:<canvas> 元素用于在网页上绘制图形.这是一个图形容器,您可以控制其每一像素,必须使用脚本来绘制图形. 注意:IE 8 以及更早的版本不支持 &l ...

  4. 『HTML5实现人工智能』小游戏《井字棋》发布,据说IQ上200才能赢【算法&代码讲解+资源打包下载】

    一,什么是TicTacToe(井字棋) 本游戏为在下用lufylegend开发的第二款小游戏.此游戏是大家想必大家小时候都玩过,因为玩它很简单,只需要一张草稿纸和一只笔就能开始游戏,所以广受儿童欢迎. ...

  5. HTML5小游戏【是男人就下一百层】UI美化版

    之前写的小游戏,要么就比较简单,要么就是比较难看,或者人物本身是不会动的. 结合了其它人的经验,研究了一下精灵运动,就写一个简单的小游戏来试一下. 介绍一下几个主要的类: Frame:帧的定义,主要描 ...

  6. Unity经典游戏教程之:是男人就下100层

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  7. 『HTML5梦幻之旅』-缤纷多姿的烟花效果

    天花无数月中开,五采祥云绕绛台.堕地忽惊星彩散,飞空旋作雨声来.怒撞玉斗翻晴雪,勇踏金轮起疾雷.更漏已深人渐散,闹竿挑得彩灯回. ——明·瞿佑·<烟火戏> 记得每年过春节的那段时间,除了欣 ...

  8. 关于『HTML5』:第二弹

    关于『HTML5』:第二弹 建议缩放90%食用 咕咕咕咕咕咕咕!!1 (蒟蒻大鸽子终于更新啦) 自开学以来,经过了「一脸蒙圈的 半期考试」.「二脸蒙圈的 体测」的双重洗礼,我终于有空肝 HTML5 辣 ...

  9. 关于『HTML5』第一弹

    关于『HTML5』:第一弹 建议缩放90%食用 祝各位国庆节快乐!!1 经过了「过时的 HTML」.「正当时的 Markdown」的双重洗礼后,我下定决心,好好学习HTML5  这回不过时了吧(其实和 ...

随机推荐

  1. notification 报错the method build() is undefined for the type Notificatin.Builder

    notification 报错the method build() is undefined for the type Notificatin.Builder 这事api版本号太低导致的 Notifi ...

  2. php url配置项

  3. git fork同步是什么意思?

    这篇文章主要介绍了git fork同步是什么意思?fork到了哪里?有什么用?怎样用?跟clone有什么差别?本文就一一解释这些问题,须要的朋友能够參考下 官方文档:http://help.githu ...

  4. C# 将MSMQ消息转换成Json格式

    PS:主要就是一个配置文件和一个转换函数 配置文件app.config  之前要ADD reference -->   system.configuration & using.syst ...

  5. LoadRunner检查点实战之运行查看器

    一.为什么要使用检查点 为什么要使用检查点,那就要说明一下LR如何判断脚本是否执行成功.LR判断脚本是否执行成功是根据服务器返回的状态来确定的,如果服务器返回的HTTP状态为 200 OK ,那么Vu ...

  6. Objective-C Runtime初探:self super

    题目 上题目,已知A是爷爷,B是爸爸,C是孙子. @interface A : NSObject - (void)f; @end @interface B : A - (void)f; - (void ...

  7. Linux JAVA 配置

    wget http://download.oracle.com/otn-pub/java/jdk/7u25-b15/jdk-7u25-linux-x64.tar.gz tar zxvf jdk-7u2 ...

  8. C#中动态调用DLL动态链接库

    其中要使用两个未公开的Win32 API函数来存取控制台窗口,这就需要使用动态调用的方法,动态调用中使用的Windows API函数主要有三个,即:Loadlibrary,GetProcAddress ...

  9. UIWindow和UIScreen

    UIWindow和UIScreen 目录 概述 职责 实用操作 概述 UIWindow职责 包含了应用程序的可视化的内容 为视图和其他应用程序对象在触摸事件中提供了关键性的作用 与视图控制器一起协作来 ...

  10. PHP mysql基本语句指令

    /*选择数据库 use test; */ /* 显示所有的数据库 show databases; */ /*删除表/数据库 drop database test1; delete from user1 ...