搜索
首页web前端js教程javascript高仿热血传奇游戏代码分享

游戏的第一个版本开发于14年,浏览器端使用html+css+js,服务端使用asp+php,通讯采用ajax,数据存储使用access+mySql。不过由于一些问题(当时还不会用node,用asp写复杂的逻辑真的会写吐;当时对canvas写的也少,dom渲染很容易达到性能瓶颈),已经废弃。后来用canvas重制了一版。

本文主要和大家介绍了javascript高仿热血传奇游戏的实现代码,非常不错,具有参考借鉴价值,需要的朋友可以参考下,希望能帮助到大家。

 

1.开发前的准备

为什么要用Javascript来实现一款比较复杂的PC端游戏

1.js实现PC端网游是可行的。随着PC、手机硬件配置的升级和浏览器的更新换代,以及H5各种库的发展,js实现一款网游的难度越来越低。这里的难度主要是两方面:浏览器的性能;js代码是否足够易于扩展,以满足于一款逻辑极其复杂的游戏的迭代。

2.现阶段的js游戏里,很少有规模较大的可供参考。涉及到多人联机、服务端数据存储、复杂交互的游戏,大多数(几乎全部)都是用flash开发的。但是flash毕竟在衰落,而js发展迅速,并且只要有浏览器就可以运行。

为什么选择了一款2001年的热血传奇游戏

第一个原因是对老游戏的情怀; 当然更重要的另一个原因是,别的游戏要么我不会玩、要么我会玩但没有素材(图片、音效等)。花很大精力去收集一个游戏的地图、人物怪物模型、物品和装备图,然后去处理、解析一遍再用于js开发,我觉得是浪费时间。

由于我以前搜集了一些传奇游戏的素材,并且幸运地找到了提取热血传奇客户端资源文件的方法( github地址 ),所以可以直接开始写码,省去了一些准备时间。

可能的困难

1.浏览器的运行性能:这个应该是最困难的一点。假如游戏要保持40帧,那么每帧只有25ms的时间留给js计算。并且由于渲染通常比计算耗性能,实际上留给js的时间只有10毫秒左右。

2.防作弊:如何避免用户直接调用接口或者篡改网络请求数据?由于目标是用js实现比较复杂的游戏,并且任何网络游戏都需要考虑这一点,一定会有相对成熟的方案。此处不是本文重点。

2.整体设计

浏览器端

画面渲染使用canvas。

相比dom(p)+css,canvas可以处理比较复杂的场景渲染和事件管理,例如下面这个场景,涉及了四张图片:玩家、动物、地上的物品、最下层的地图图片。(实际还有地上的影子,鼠标指向人物、动物、物品时出现的相应名称,以及地面上的阴影。为了方便读懂,先不考虑这么多内容。)

 

这时,如果希望实现“点击动物、攻击动物;点击物品、捡起物品”的效果,那么需要对动物和物品进行事件监听。如果采用dom的方式,那么会出现几点难于处理的问题:

a.渲染的顺序和事件处理的顺序不同(有时候z-index小的需要先处理事件),需要额外处理。例如这个上面的例子里:点击怪物、点击物品的时候也容易点到人物,那么需要给人物做“点击事件穿透”的处理。而且事件处理的顺序不固定:假如我有一个技能(例如游戏里的治疗)需要点人物才可以释放,那么这时人物又需要有事件监听。所以一个元素是否需要处理事件、处理事件的先后,是随着游戏状态的不同而变化的,而 dom的事件绑定已经不能满足需要 。

b.有关联的元素难以放在同一个dom节点中:例如玩家的模型、玩家的名字和玩家身上的技能画效,理想情况下是放在一个 e388a4556c0f65e1904146cc1a846bee 或者 2f8332c8dcfd5c7dec030a070bf652c3 容器里,便于管理(这样几个元素的定位就可以继承父元素,不用分别处理位置了)。但是这样,z-index会很难处理。例如玩家A在玩家B的上面,那么A会被B遮挡,因此需要A的z-index小一些,但是又需要让玩家A的名字不会被B的名字或者影子遮挡,就无法实现。简单点说, dom结构的可维护性会牺牲画面展示的效果,反之亦然 。

c.性能问题。即使牺牲了效果,用dom渲染,势必出现很多嵌套关系,所有元素的style都在频繁变化,连续触发浏览器的repaint甚至reflow。

canvas渲染逻辑与项目逻辑分离

如果将canvas的各种渲染操作(如 drawImage 、 fillText 等)与项目代码放在一起,那么势必导致项目后期无法维护。翻了一下几款现有的canvas库,结合vue的数据绑定+调试工具的方式,搞了一个全新的canvas库Easycanvas( github地址 ),并且像vue一样支持通过一个插件来调试canvas中的元素。

这样,整个游戏的渲染部分就容易很多,只需要管理游戏当前的状态、并且根据服务端从socket传回来的数据去更新数据就可以。 “数据的变化引起视图的变化”这个环节由Easycanvas负责 。例如下图的玩家包裹物品的实现,我们只需要给出包裹容器的位置、背包里每个元素的排布规则,然后将每个包裹的物品绑定到一个array上,然后去管理这个array即可(数据映射到画面的过程由Easycanvas负责)。

 

例如,5行8列共计40个物品的样式可以通过如下的形式传递给Easycanvas(index为物品索引,物品x方向间距36,y方向间距32)。而这个逻辑是一成不变的,无论物品的数组怎样变化、包裹被拖拽到什么位置,每个物品的相对位置都是固定的。至于canvas上的渲染则完全不需要项目本身来考虑,所以可维护性较好。


style: {
 tw: 30, th: 30,
 tx: function () {
 return 40 + index % 8 * 36;
 },
 ty: function () {
 return 31 + Math.floor(index / 8) * 32;
 }
}

canvas分层渲染

假设:游戏需要保持40帧,浏览器宽800高600,面积48万(后面称48万为1个屏幕面积)。

如果用同一个canvas来呈现,那么这个canvas的帧数40,每秒至少需要绘制40个屏幕面积。但是同一个坐标点很可能出现多个元素重叠的情况,例如底部的UI、血条、按钮就是重叠放置,他们又共同遮挡了场景地图。所以这些加在一起,每秒浏览器的绘制量很容易达到100个屏幕面积以上。

这个绘制是很难优化的,因为整个canvas画布的任何一处都在进行视图的更新:可能是玩家和动物的移动、可能是按钮的特效、可能是某个技能效果的变化。这样的话,即使玩家不动,由于衣服“随风飘飘”的效果(其实是精灵动画播放到下一张图),或者是地面上出现了一瓶药水,都要引起整个canvas的重绘。因为 游戏中几乎不可能出现某一帧的画面与上一帧毫无区别的情况,即使是游戏画面的一个局部,也很难保持不变 。整个游戏的画面永远在更新。

因为 游戏中几乎不可能出现某一帧的画面与上一帧毫无区别的情况 ,画面永远在更新。

因此,这次我采用了3个canvas重叠排布的方式。由于Easycanvas的事件处理支持传递,因此即使点到了最上面的canvas,如果没有任何元素结束了某一次点击,后面的canvas也可以接到这次事件。3个canvas分别负责UI、地面(地图)、精灵(人物、动物、技能特效等):

 

这样分层的好处是,每层最大帧数可以根据需要来调整:

例如UI层,因为很多UI平时是不动的,即使动也不会需要太精密的绘制,所以可以适当降低帧数,例如降低到20。这样假如玩家的体力从100降低到20,那么可以在50ms内更新视图,而50ms的切换是玩家感觉不出来的。因为像体力这种 UI层数据的变化很难在很短的时间内连续变化多次,而50ms的延迟是人很难感知的,所以不需要频繁的绘制 。假如我们每秒节约了20帧,那么很可能可以节约10个屏幕面积的绘制。

再如地面,只有玩家移动的时候,地图才会变化。这样,如果玩家不动,那么每帧可以省去1个屏幕面积。由于需要保证玩家移动时的流畅感,地面的最大帧数不宜太低。假如地面为30帧,那么玩家不动时,每秒就可以节约30个屏幕面积的绘制(这个项目中,地图是几乎绘满屏幕的)。而且其它玩家、动物的移动不会改变地面,也不需要重绘地面这一层。

精灵层最大帧数不能降低,这层会展示游戏的人物动作等核心部分,所以最大帧数设置为40.

这样,每秒绘制的面积,玩家移动时可能是80~100个屏幕面积,而玩家不移动时可能只有50个屏幕面积。游戏中,玩家停下来打怪、打字、整理物品、释放技能都是站立不动的,因此 大量的时间里都不会触发地面的绘制,对性能的节约很大 。

服务器端

由于目标是js实现一款多人网游,所以服务端使用Node,使用socket与浏览器通讯。这样做还有一个好处,就是一些 公用的逻辑可以在两端复用 ,例如判断地图上某个坐标点是否存在障碍物。

Node端的玩家、场景等游戏相关数据全部存储与内存中,定期同步至文件。每次Node服务启动时,将数据从文件读取至内存。这样可以玩家较多时,文件读写的频率成指数级上升,从而引发的性能问题。(后来为了提高稳定,为文件读写增加了一个缓冲,“内存-文件-备份”的方式,以免读写过程中服务器重启导致的文件损坏)。

Node端分接口、数据、实例等多层。“接口”负责和浏览器端交互。“数据”是一些静态数据,例如某个药品的名称和效果、某个怪物的速度和体力,是游戏规则的一部分。“实例”是游戏中的当前状态,例如某个玩家身上的一个药品,就是“药品数据”的一个实例。再举个例子,“鹿的实例”拥有“当前血量”这个属性,鹿A可能是10,鹿B可能是14,而“鹿”本身只有“初始血量”。

3.场景地图的实现

地图场景

下面开始介绍地图场景部分,仍然是依赖 Easycanvas 进行渲染。

思考

由于玩家是始终固定在屏幕中心的,所以玩家的移动,实际上是地图的移动。例如玩家像左跑,地图就向右平移即可。刚才已经提到,玩家处于3个canvas中的中间一层,而地图属于底层,因此玩家一定遮挡地图。

这样看起来是合理的,但是假如地图中有一棵树,那么“玩家的层次始终高于树”就不对了。这时,有2种大的解决方案:

地图分层,“地面”与“地上”拆开。将玩家处于两层之间,例如下图,左侧是地上、右侧是地面,然后重叠绘制,把人物夹在中间:

 

这样看似解决了问题,其实引入了2个新的问题:第一个是,玩家有时可能会被“地上”的东西遮挡(例如一棵树),有时又需要能够遮挡“地上”的东西(例如站在这棵树的下方,头部会遮挡住树)。另一个问题是渲染的性能消耗会增加。由于玩家是时刻在变的,“地上”这一层需要频繁重绘。这样做也打破了最初的设计——尽量节约地面大地图的渲染,从而导致canvas的分层更加复杂。

地图不分层,“地面”与“地上”在一起绘制。当玩家处于树后的时候,将玩家的透明度设置为0.5,例如下图:

 

这样做只有一个坏处:玩家的身体要么都不透明、要么都半透明(怪物在地图上行走也会有这个效果),不会完全真实。因为理想的效果是存在玩家的身体被遮挡住一部分的场景的。但是这样做对性能友好,并且代码易于维护,目前我也采用了这个方案。

那么如何判断“地图”这张图片哪些地方是树呢?游戏通常会有一个大的地图描述文件(其实就是一个Array),通过0、1、2这样的数字来标识哪些地方可以通过、哪些地方存在障碍物、哪些地方是传送点等等。热血传奇中的这个“描述文件”就是48x32为最小单位进行描述的,所以玩家在传奇中的行动会有一种“棋盘”的感觉。单位越小越流畅,但是占用的体积越大、生成这个描述的过程也就越耗时。

下面开始正题。

实现

我找了一个朋友帮我导出热血传奇客户端中“比奇省”的地图,宽33600、高22400,是我电脑的几百倍大。为了避免电脑爆炸,需要拆分成多块加载。由于传奇的最小单元是48x32,我们以480x320将地图拆成了4900(70x70)个图片文件。

canvas的尺寸我们设定为800x600,这样玩家只需要加载3x3共计9张图片就可以铺满整个画布。800/480=1.67,那么为什么不是2x2?因为有可能玩家当前的位置正好导致有的图片只展示了一部分。如下图:

 

相关推荐:

JavaScript打字小游戏代码示例

2小时完成HTML5拼图小游戏代码图文介绍

JavaScript 打地鼠游戏代码说明_游戏娱乐

以上是javascript高仿热血传奇游戏代码分享的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
超越浏览器:现实世界中的JavaScript超越浏览器:现实世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

使用Next.js(后端集成)构建多租户SaaS应用程序使用Next.js(后端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

如何使用Next.js(前端集成)构建多租户SaaS应用程序如何使用Next.js(前端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:22 AM

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

JavaScript:探索网络语言的多功能性JavaScript:探索网络语言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

JavaScript的演变:当前的趋势和未来前景JavaScript的演变:当前的趋势和未来前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

神秘的JavaScript:它的作用以及为什么重要神秘的JavaScript:它的作用以及为什么重要Apr 09, 2025 am 12:07 AM

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

Python还是JavaScript更好?Python还是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。 1.Python以简洁语法和丰富库生态着称,适用于数据分析和Web开发。 2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

如何安装JavaScript?如何安装JavaScript?Apr 05, 2025 am 12:16 AM

JavaScript不需要安装,因为它已内置于现代浏览器中。你只需文本编辑器和浏览器即可开始使用。1)在浏览器环境中,通过标签嵌入HTML文件中运行。2)在Node.js环境中,下载并安装Node.js后,通过命令行运行JavaScript文件。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器