热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

html5Game开发系列文章之三搭建基本游戏框架(代码封装)

在之前的二节中,我做出一个基本的游戏精灵--一条红色的飞行的小飞龙,但是在进行下一步开发前,我觉得有必要对现有的代码进行封装!在这一节中,我将封装一些基本的方法,并演示如何在JS中实现继承!

    在之前的二节中,我做出一个基本的游戏精灵--一条红色的飞行的小飞龙,但是在进行下一步开发前,我觉得有必要对现有的代码进行封装!在这一节中,我将封装一些基本的方法,并演示如何在JS中实现继承!

    首先了解下什么叫立即调用的函数:

(function(){
//你的代码
})();

  顾名思义,即函数定义完后会立即调用或执行自己,在这里,它相当于

function 函数名(){
//你的代码;
}

函数名();


  封装在里面的代码,外部是无法访问的,这样能确保不会因为外面的同名变量而产生不可预料的异常!然后可以通过一个全局变量来访问相关内容!网上一些JS库都是这种方式封装的,包括jQuery!在这里我们建一个立即调用函数并将上一节用到的几个方法,封装进去,然后通过一个全局变量window.j2d来访问里面的方法!

 

(function(window){
var j2d={
//canves context对象
Context:undefined,
//坐标
Point:function(x,y){
if(isNaN(x)){
x=0;
}
if(isNaN(y)){
y=0;
}
return {"X":x,"Y":y};
},
//每秒帧数
FPS:10,
//精灵容器
Containet:new Array(),
//八个方向
Directions:{
North:0,
NorthEast:1,
East:2,
SouthEast:3,
South:4,
SouthWest:5,
West:6,
NorthWest:7
},
//获取两点之间距离
GetDistance:function(x,y) {
return Math.sqrt(Math.pow((x.X - y.X), 2) + Math.pow((x.Y - y.Y), 2));
},

//计算当前坐标与目标点之间的正切值以获取朝向
GetDirection:function(current,target){
//...略
},

//是否到达指定坐标

RatherPoint:function(direction,p1,p2){
//...略
}
//
};
window.j2d=j2d;
})(window);


    封装好后,我们可以直接通用j2d来调用相关方法了!不过在这里要先改进一下计算移动步长GetMovePoint这个方法,上一节中没有细致考虑导致方法过于冗余!在这里改进调整下!

    如果精灵是横向或者纵向移动,每次移动步长直接是当前移动速度即可,如果是斜向移动,则需要计算目标点的长度,并根据对应的比例获取x坐标长度与y坐标长度!

    根据勾股定理:两条直角边的长度的平方之和等于斜边的平方,则得出获取两个坐标点的距离为Math.sqrt(Math.pow((point2.X - point1.X), 2) + Math.pow((point2.Y - point1.Y), 2));

    因为同号两数相乘得正数,异号两数相乘得负数,所以这里得出的结果永远是正数!再根据 斜边/长(高) = 速度/x步长(y步长) (两者比例一致的,斜边上的移动步长即为当前速度)就能得出对应的x轴移动步长或者y轴移动步长了!优化后方法如下(方法名调整为GetMoveStep):

GetMoveStep:function(point1,point2,speed){
var length = j2d.GetDistance(point1,point2);
var p = j2d.Point(0,0);
if(length==0){
return p;
}
p.X= (point2.X - point1.X) * speed / length;
p.Y= (point2.Y - point1.Y) * speed / length;
return p;
}


  下面我将实现精灵对象的基类封装,每个精灵都有一个Draw方法,用来绘制精灵对象,一个Update方法,用来实现相关逻辑处理

 

    ObjectEntity:function(){
this.DrawObject=undefined;//绘制对象
this.ID=undefined;//编号
this.Name=undefined;//名字
this.Offset={"X":0,"Y":0};//偏移量
this.COntainet=new Array();//子对象集合
this.X":0,"Y":0};//绘制起始坐标
this.Coordinate={"X":0,"Y":0};//当前所在坐标
this.Draw=function(){
if(j2d.Context&&this.DrawObject){
var point = this.Coordinate;
var w = this.Width;
var h = this.Height;
j2d.Context.drawImage(this.DrawObject,//绘制对象
parseInt(this.DrawPoint.X),//
parseInt(this.DrawPoint.Y),//
parseInt(w),//裁剪尺寸
parseInt(h),//裁剪的尺寸
parseInt(point.X-this.Offset.X),//
parseInt(point.Y-this.Offset.Y),
parseInt(w),//绘制大小。
parseInt(h) //绘制大小。
);
for(var n=0;n<this.Containet.length;n++){//执行子集合里面的Draw方法
if(this.Containet[n]&&this.Containet[n].Draw){
this.Containet[n].Draw(gameTime);
}
}
}
}
}

 

  然后,我们再定义一个地图对象,继承自ObjectEntity,其实Javascript中并不存在类,继承等东西,但是我们可以通过一些方法来实现继承等功能,实现继承有多种方法,这里使用call来实现(其它还有原型继承等,更多请自行搜索了解)!

 

Map:function(){
j2d.ObjectEntity.call(this);
this.Update=function(gameTime){
for(var n=0;n<this.Containet.length;n++){
if(this.Containet[n]){
if(this.Containet[n].Update){
this.Containet[n].Update(gameTime);
}
}
}
};
}

 

  Map里面只新增一个Update方法,遍历子集合里面的所有对象并运行其Update方法(注:随着后面更多的功能增加,会有更多的方法增减,但是目前为了方便理解与突出重点,用不到的方法暂时不放出来)

  OK,地图定义完了,再定义一个Sprite类,在之前的演示中,我们的精灵只有一个动行,即飞行,但是这远远不够的,可能我还要有站立,行走,攻击,死亡,打坐,受伤,施法...等很多动作,在这里我不想把这些动作写死,我打算在实际开发中动态添加,在这里我定义一个AddAnimation方法,来用添加动作动画,再定义一个SetAnimation,来设置当前动作。但是精灵的基本图片要求不变,即每个方向为一行!其实在一般的游戏中,精灵图片一般都是单张单张分开的,但是为了减少HTTP请求,我将所有图片都拼合到一张图片里面了,加载的时候慢点,但是不需要频繁的去请求,智者见智,仁者见仁,如果不想一次加载的,可以自己更改相关方法,但是原理还是一致的!

 

 

    Sprite:function(){
j2d.ObjectEntity.call(this);
this.Speed=100;//速度
var action="",//当前动作
list,//动作列表
index=0,//当前动作的帧索引
timeStep=0;//距上次更新时的时间步长
this.AddAnimation=function(key,value){
if(!list){
list=new Object();
}
list[key]=value;
return true;
};

this.SetAnimation=function(key){
if(action!=key){
index=0;
action=key;
timeStep=3600000;//这里将时间设为一个较大的数值是为了切换动作后能马上更换图片
}
};

this.Update=function(gameTime){
if(action&&action!=""&&list[action]){
timeStep+=gameTime;
if(timeStep>=list[action].Interval){//是否达到每帧的切换时间
timeStep=0;
this.DrawPoint=j2d.Point(list[action].Frames[index]*this.Width,this.Direction*this.Height);
if(list[action].Callback){
list[action].Callback(index,action);
}
if(index>=list[action].Frames.length-1){
index=0;
}else{
index++;
}
}
}

for(var n=0;n<this.Containet.length;n++){
if(this.Containet[n]){
if(this.Containet[n].Update){
this.Containet[n].Update(gameTime);
}
}
}
};
}

 

  实现了封装后,下面的开发中我们将大大简化相关代码,在下面,我将再次实现一个会行走的精灵,这次我不再打算用上次的小龙了,必竟这是老外们的龙,咱们中国人,当然要用中国元素,所以我决定用一个小美女,嗯,现在美女大家都喜欢,不是吗,特别对于代码老是报“找不到对象”的错误的同学们来说!

  先展示一下我们要用到的精灵素材(这里只有部分,全图放在下载文件中,站立10帧,行走10帧,8个方向,计160张图片拼合而成,说实话,处理图片真是一个很麻烦的过程!原图可都是一张一张零散的图片)

 

};
mapImg.src = "Data/Map/1.gif";

 

  好,我们来运行一下结果吧:


  冰山上一个漂亮的美女正在孤独的行走,慢慢前行...,冰山上的美女,简称冰女,要是石头上的美女,简称...咳咳,我什么都没有说啊...

  今天本节到此为止,开发已经渐入佳境了,不过,还有很多功能没有出来,比如地图没有障碍,人物没有阴影,2.5D效果处理,地图切换,怪物,技能等,不过别急,请关注本人的Html5 Game开始系列文章,让我们一起走近html5,感受html5的魅力,享受html5之神奇之旅...

    作者:翅膀的初衷
    QQ:4585839
    总目录:点击进入
    本章代码下载:点击下载
    本系列效果演示:http://www.iis0.com/html5

 

  这篇文章是旧历2011年的最后一篇文章了,过两天要回家过年了,下面的更新将在节后回来继续。如果代码与文章中存在不足之处,欢迎大家指点(本代码在IE9,火狐(中国版)9.01中测试通过)!

  本文(包括本系列其它文章)为原创作品,如有转载请保留作者信息与出处,其中涉及到的图片,来源于网络,仅供学习研究目的使用,请勿用于其它用途,否则由此产生的任何后果均与本人无关!


推荐阅读
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 如何在HTML中获取鼠标的当前位置
    本文介绍了在HTML中获取鼠标当前位置的三种方法,分别是相对于屏幕的位置、相对于窗口的位置以及考虑了页面滚动因素的位置。通过这些方法可以准确获取鼠标的坐标信息。 ... [详细]
  • 单页面应用 VS 多页面应用的区别和适用场景
    本文主要介绍了单页面应用(SPA)和多页面应用(MPA)的区别和适用场景。单页面应用只有一个主页面,所有内容都包含在主页面中,页面切换快但需要做相关的调优;多页面应用有多个独立的页面,每个页面都要加载相关资源,页面切换慢但适用于对SEO要求较高的应用。文章还提到了两者在资源加载、过渡动画、路由模式和数据传递方面的差异。 ... [详细]
  • 本文介绍了解决mysql 5.1启动问题的方法,通过修改my.ini文件中的相关配置,包括innodb_data_home_dir和skip-innodb等,可以解决启动问题。同时还介绍了如何调整内存池来存储metadata信息。 ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
  • Android获取app应用程序大小的方法
    Android获取app应用程序大小的方法-Android对这种方法进行了封装,我们没有权限去调用这个方法,所以我们只能通过AIDL,然后利用Java的反射机制去调用系统级的方法。 ... [详细]
author-avatar
雨滴儿茶业_455
这个家伙很懒,什么也没留下!
Tags | 热门标签
RankList | 热门文章
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有