东莞高端建站:将Flash游戏转换为HTML5时需要了解的内容?

2019.08.13 mf_web

130

随着HTML5使用的兴起,许多公司开始重做他们最受欢迎的游戏,以摆脱过时的Flash并将其产品与最新的行业标准相匹配。这种变化在赌博/娱乐场和娱乐行业中尤为明显,并且已经发生了好几年,所以已经转换了一些不错的标题。

不幸的是,在浏览互联网时,你经常会偶然发现一个看似仓促的工作的例子,这会导致最终产品的爱好者质量。这就是为什么游戏开发人员花费一些时间来熟悉Flash到HTML5转换的主题并学习在开始工作之前要避免哪些错误的好主意。

东莞高端建站除了明显的技术问题之外,选择JavaScript而不是Flash的原因之一是,将游戏设计从SWF改为JavaScript可以产生更好的用户体验,从而使其具有现代外观。但怎么办呢?你需要一个专门的JavaScript游戏转换器来摆脱这种过时的技术吗?好吧,Flash到HTML5的转换可能是件小事 - 这就是如何处理它。

如何改善HTML5游戏体验

将游戏转换为另一个平台是改善它,解决问题和增加受众的绝佳机会。以下是一些可以轻松完成并且值得考虑的事情:

  • 支持移动设备
    从Flash转换为JavaScript可以覆盖更广泛的受众(移动设备用户); 通常也需要在游戏中实现对触摸屏控件的支持。幸运的是,Android和iOS设备现在也支持WebGL,因此通常可以轻松实现30或60 FPS渲染。在许多情况下,60 FPS不会导致任何问题,只会随着时间的推移而改善,因为移动设备的性能越来越高。

  • 提高性能
    在比较ActionScript和JavaScript时,后者比第一个更快。除此之外,转换游戏是重新审视游戏代码中使用的算法的好机会。使用JavaScript游戏开发,您可以优化它们或完全删除原始开发人员留下的未使用的代码。

  • 修复错误并改进游戏玩法
    让新开发人员查看游戏的源代码可以帮助修复已知的错误或发现新的和非常罕见的错误。这样可以减少对玩家的游戏刺激,这会让他们在你的网站上花更多的时间,并鼓励你尝试其他游戏。

  • 添加网络分析
    除了跟踪流量之外,网络分析还可用于收集有关玩家在游戏中的行为方式以及在游戏过程中遇到困难的知识。

  • 添加本地化
    这会增加观众,对于来自其他国家/地区的孩子来说非常重要。或者你的游戏可能不是英文,你想支持那种语言?

为什么在游戏内UI中跳过HTML和CSS会提高游戏性能

在JavaScript游戏开发方面,可能很有可能将HTML和CSS用于游戏内按钮,小部件和其他GUI元素。我的建议是在这里要小心。这是违反直觉的,但实际上利用DOM元素在复杂游戏中的表现较差,这在移动设备上具有更大的意义。如果要在所有平台上实现恒定的60 FPS,则可能需要从HTML和CSS重新签名。

通过使用常规图像(Phaser.Image类),利用.crop属性进行修剪和使用Phaser.Text简单文本标签的类,可以在Phaser中轻松实现非交互式GUI元素,例如健康条,弹药条或分数计数器。

按钮和复选框等交互式元素可以使用内置Phaser.Button类实现。其他更复杂的元素可以由不同的简单类型组成,例如组,图像,按钮和文本标签。

注意: 每次实例化Phaser.Text或PIXI.Text对象时,都会创建一个新纹理以将文本渲染到其上。这个额外的纹理打破了顶点批处理,所以要注意不要有太多的纹理。

如何确保自定义字体已加载

如果要使用自定义矢量字体(例如TTF或OTF)渲染文本,则需要确保在渲染任何文本之前浏览器已经加载了该字体。Phaser v2没有为此提供解决方案,但可以使用另一个库:Web Font Loader。

假设您有一个字体文件并在页面中包含Web Font Loader,那么下面是一个如何加载字体的简单示例:

创建一个将由Web Font Loader加载的简单CSS文件(您不需要将其包含在HTML中):

@font-face {
    // This name you will use in JS
    font-family: 'Gunplay';
    // URL to the font file, can be relative or absolute    src: url('../fonts/gunplay.ttf') format('truetype');
    font-weight: 400;}
复制

现在定义一个名为的全局变量WebFontConfig。像这样简单的东西通常就足够了:

var WebFontConfig = {
   'classes': false,
   'timeout': 0,
   'active': function() {
       // The font has successfully loaded...
   },
   'custom': {
       'families': ['Gunplay'],
       // URL to the previously mentioned CSS
       'urls': ['styles/fonts.css']
   }};
复制

最后,请记住将代码放在上面显示的“活动”回调中。就是这样!

如何让用户更轻松地保存游戏

要在ActionScript中持久存储本地数据,您将使用SharedObject类。在JavaScript中,简单的替换是localStorage API,它允许存储字符串以供以后检索,幸存的页面重新加载。

保存数据非常简单:

var progress = 15;localStorage.setItem('myGame.progress', progress);
复制

请注意,在上面的示例中,progress变量(数字)将转换为字符串。

加载也很简单,但请记住,检索到的值将是字符串或者null如果它们不存在。

var progress = parseInt(localStorage.getItem('myGame.progress')) || 0;
复制

这里我们确保返回值是一个数字。如果它不存在,那么将为该progress变量分配0 。

您还可以存储和检索更复杂的结构,例如,JSON:

var stats = {'goals': 13, 'wins': 7, 'losses': 3, 'draws': 1};localStorage.setItem('myGame.stats', JSON.stringify(stats));…var stats = JSON.parse(localStorage.getItem('myGame.stats')) || {};
复制

在某些情况下,localStorage对象将不可用。例如,使用file://协议时或在私有窗口中加载页面时。您可以使用try和catch语句来确保代码将继续工作并使用默认值,如下例所示:

try {
    var progress = localStorage.getItem('myGame.progress');} catch (exception) {
    // localStorage not available, use default values}
复制

另一件需要记住的事情是存储的数据是按域保存的,而不是按URL保存的。因此,如果存在许多游戏托管在单个域上的风险,那么在保存时最好使用前缀(命名空间)。在上面的示例中'myGame.'是这样的前缀,您通常希望将其替换为游戏名称。

注意:如果您的游戏嵌入在iframe中,则localStorage将不会在iOS上保留。在这种情况下,您需要将数据存储在父iframe中。

如何利用替换默认片段着色器

当Phaser和PixiJS渲染你的精灵时,他们使用一个简单的内部片段着色器。它没有很多功能,因为它是为速度量身定制的。但是,您可以为您的目的替换该着色器。例如,您可以利用它来检查透支或支持更多渲染功能。

下面是如何向Phaser v2提供您自己的默认片段着色器的示例:

function preload() {
    this.load.shader('filename.frag', 'shaders/filename.frag');}function create() {
    var renderer = this.renderer;
    var batch = renderer.spriteBatch;
    batch.defaultShader = 
        new PIXI.AbstractFilter(this.cache.getShader('filename.frag'));
    batch.setContext(renderer.gl);}
复制

注意: 重要的是要记住默认着色器用于所有精灵以及渲染到纹理时。此外,请记住,对所有游戏中的精灵使用复杂着色器将大大降低渲染性能。

如何使用默认着色器更改着色方法

自定义默认着色器可用于替换Phaser和PixiJS中的默认着色方法。

在Phaser和PixiJS中着色通过将纹理像素乘以给定的颜色来工作。乘法总是使颜色变暗,这显然不是问题; 它与Flash着色完全不同。对于我们的某个游戏,我们需要实现类似于Flash的着色,并决定可以使用自定义默认着色器。下面是这种片段着色器的示例:

// Specific tint variant, similar to the Flash tinting that adds// to the color and does not multiply. A negative of a color// must be supplied for this shader to work properly, i.e. set// sprite.tint to 0 to turn whole sprite to white.precision lowp float;varying vec2 vTextureCoord;varying vec4 vColor;uniform sampler2D uSampler;

void main(void) {
    vec4 f = texture2D(uSampler, vTextureCoord);
    float a = clamp(vColor.a, 0.00001, 1.0);
    gl_FragColor.rgb = f.rgb * vColor.a + clamp(1.0 - vColor.rgb/a, 0.0, 1.0) * vColor.a * f.a;
    gl_FragColor.a = f.a * vColor.a;}
复制

此着色器通过向色调添加基色来减轻像素。为此,您需要提供所需颜色的负片。因此,为了获得白色,您需要设置:

sprite.tint = 0x000000;  // This colors the sprite to whiteSprite.tint = 0x00ffff;  // This gives red
复制

我们游戏中的结果看起来像这样(注意坦克在击中时如何闪现白色):

游戏开发中自定义默认着色器的示例
自定义默认着色器(坦克闪烁白色)。

如何检查透支以检测填充率问题

也可以利用替换默认着色器来帮助调试。下面我解释了如何使用这样的着色器检测过度绘制。

当屏幕上的许多或所有像素被多次渲染时,会发生过度绘制。例如,许多对象占据相同的位置并且一个在另一个上呈现。GPU每秒可以渲染多少像素被描述为填充率。现代桌面GPU对于通常的2D目的而言具有过高的填充率,但是移动的GPU要慢得多。

通过使用以下方法替换PixiJS和Phaser中的默认全局片段着色器,有一种简单的方法可以找出屏幕上每个像素的写入次数:

void main(void) {
    gl_FragColor.rgb += 1.0 / 7.0;}
复制

此着色器可淡化正在处理的像素。数字7.0表示转动像素白色需要多少次写入; 你可以根据自己的喜好调整这个数字。换句话说,屏幕上的较亮像素被写入数次,而白色像素被写入至少7次。

此着色器还有助于找到由于某种原因仍然呈现的“不可见”对象以及需要剥离的具有过多透明区域的精灵(GPU仍需要处理纹理中的透明像素)。

游戏开发中的Overdraw着色器示例
在操作中透视着色器。(大预览)

左边的图片显示了玩家如何看到游戏,而右边的图片显示了将透支着色器应用于同一场景的效果。

为什么物理引擎是你的朋友

物理引擎是一个中间件,负责模拟物理实体(通常是刚体动力学)及其碰撞。物理引擎模拟2D或3D空间,但不能同时模拟两者。典型的物理引擎将提供:

  • 通过设定速度,加速度,关节和马达来移动物体;

  • 检测各种形状类型之间的碰撞;

  • 计算碰撞响应,即两个物体碰撞时应如何反应。

在Merixstudio,我们是Box2D物理引擎的忠实粉丝,并在几次使用它。有一个Phaser插件可以很好地用于此目的。Box2D也用于Unity游戏引擎和GameMaker Studio 2。

虽然物理引擎会加速您的开发,但您需要付出代价:降低运行时性能。检测冲突和计算响应是CPU密集型任务。您可能会限制在手机场景中的数十个动态对象或面临降级性能,以及低于60 FPS的帧速率降低。

与顶部显示的Phaser物理调试叠加层的游戏场景差异示例
Phaser的物理调试叠加。(大预览)

图像的左侧部分是游戏中的场景,而右侧则显示相同的场景,顶部显示Phaser物理调试叠加层。

如何从.Fla文件导出声音

如果您在.fla文件中有Flash游戏声音效果,则无法从GUI导出它们(至少在Adobe Animate CC 2017中没有),因为缺少用于此目的的菜单选项。但还有另一种解决方案 - 专用脚本就是这样做的:

function normalizeFilename(name) {
   // Converts a camelCase name to snake_case name
   return name.replace(/([A-Z])/g, '_$1').replace(/^_/, '').toLowerCase();}function displayPath(path) {
   // Makes the file path more readable
   return unescape(path).replace('file:///', '').replace('|', ':');}fl.outputPanel.clear();if (fl.getDocumentDOM().library.getSelectedItems().length > 0)
   // Get only selected items
   var library = fl.getDocumentDOM().library.getSelectedItems();else
   // Get all items
   var library = fl.getDocumentDOM().library.items;// Ask user for the export destination directoryvar root = fl.browseForFolderURL('Select a folder.');var errors = 0;for (var i = 0; i < library.length; i++) {
   var item = library[i];
   if (item.itemType !== 'sound')
       continue;
   var path = root + '/';
   if (item.originalCompressionType === 'RAW')
       path += normalizeFilename(item.name.split('.')[0]) + '.wav';
   else
       path += normalizeFilename(item.name);
   var success = item.exportToFile(path);
   if (!success)
       errors += 1;
   fl.trace(displayPath(path) + ': ' + (success ? 'OK' : 'Error'));}fl.trace(errors + ' error(s)');
复制

如何使用脚本导出声音文件:

  1. 将上面的代码保存为计算机上的.jsfl文件;

  2. 使用Adobe Animate 打开.fla文件;

  3. 从顶部菜单中选择“命令”→“运行命令”,然后在打开的对话框中选择脚本;

  4. 现在弹出另一个对话文件以选择导出目标目录。

并做了!您现在应该在指定的目录中有WAV文件。剩下要做的就是将它们转换为MP3,OGG或AAC。

如何在Flash到HTML5转换中使用MP3

好的旧MP3格式又回来了,因为一些专利已经过期,现在每个浏览器都可以解码和播放MP3。这使得开发变得更容易,因为最终不需要准备两种单独的音频格式。以前你需要OGG和AAC文件,而现在MP3就足够了。

尽管如此,您还需要记住有关MP3的两个重要事项:

  • MP3需要在加载后进行解码,这可能非常耗时,尤其是在移动设备上。如果在加载所有资源后看到暂停,则可能意味着MP3正在被解码;

  • 无间隙播放循环MP3有点问题。解决方案是使用mp3loop,您可以在Compu Phase发布的文章中阅读。

那么,为什么要将Flash转换为JavaScript?

如您所见,如果您知道该怎么做,Flash到JavaScript的转换并非不可能。凭借知识和技能,您可以停止与Flash的挣扎,享受用JavaScript创建的流畅,有趣的游戏。不要试图修复Flash - 在每个人都被迫这样做之前摆脱它!

想了解更多?

东莞高端建站在本文中,我主要关注Phaser v2。但是,现在有了更新版本的Phaser,我强烈建议您查看它,因为它引入了大量新鲜,酷炫的功能,例如多个摄像头,场景,平铺图或Matter.js物理引擎。

如果你足够勇敢并希望在浏览器中创造真正卓越的东西,那么从头开始学习WebGL是正确的。它比各种游戏构建框架或工具具有更低的抽象级别,但即使您处理2D游戏或演示,也可以实现更高的性能和质量。在学习WebGL基础知识时,您可能会发现许多有用的网站是WebGL基础知识(使用交互式演示)。除此之外,要了解有关WebGL功能采用率的更多信息,请查看WebGL统计信息。

永远记住,没有太多的知识 - 特别是在游戏开发方面!


最新案例

寒枫总监

来电咨询

400-6065-301

微信咨询

寒枫总监

TOP