Mandy

Mandy 查看完整档案

北京编辑  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑

我是一名勤劳的搬运工

个人动态

Mandy 发布了文章 · 9月27日

电商小游戏火爆,开发者如何快速接入?看这里

电商+小游戏火爆的趋势已愈发明显,为了帮助商家更好的留住用户、促进活跃,淘宝购物小程序已率先支持商家店铺发布创意互动小游戏,进一步实现电商与小游戏的紧密结合,抢占消费者注意力!

对于游戏开发者而言,则意味着休闲品类的小游戏与电商结合的应用场景将会更加广阔,大家可以脑洞大开、尝试做更多的营销互动类小游戏!

现在,Egret Engine已与淘宝创意互动实现底层技术对接,开发者只需要将引擎版本升级到5.3.10、Egret Launcher升级至1.2.22,即可轻松实现将游戏一键发布至淘宝购物平台!

淘宝创意互动接入指南见下:

一、开发环境准备

1.注册商家应用账号;

2.下载淘宝开发工具;

3.关于用户授权,用户信息等系统功能,请调用平台提供的 API;

4.白鹭引擎版本 5.3.10 以上;

5.EgretLauncher 版本 1.2.22 以上。

二、创建小游戏和可视化编译打包小游戏

1.使用测试版的 Egret Launcher 创建一个 Egret 游戏项目,或者将原有的 Egret 项目导入;

2.导入或者创建完成后,会在 Egret Launcher 的列表里看到该项目。点击发布设置:

3.选择“淘宝创意互动”标签,点击确定,创建淘宝项目;

4.创建成功后,点击发布标签,可以可视化的发布小游戏包;

5.游戏代码类型:把白鹭工程里的代码编译淘宝项目里;

  • debug:js 代码不进行uglify 混淆,便于 debug 调试;
  • release:js 代码进行 uglify 混淆压缩;

6.淘宝创意互动项目结构文件说明:

  • app.css :应用的全局样式文件,一般不需要修改。
  • app.js:注册应用,获取应用的启动、显示、隐藏等消息。
  • app.json:应用的配置文件。
  • js 目录:白鹭项目编译出来的游戏代码
  • manifest.js:用于加载依赖的 js 文件
  • mini.project.json:用于配置项目用到的文件格式,如果用到了特殊的文件格式,需要在这配置
  • package.json:项目描述文件
  • pages/index 文件夹:

    *   egret.tbgame.js:白鹭适配层文件
    *   index.axml:入口的页面结构
    *   index.js:入口类
    *   tools 文件夹:一些工具类,不要修改
    
  • resource : 游戏的图片、音频等资源文件

三、安装到手机

1.下载开发者工具;

2.点击【商家应用】->【打开项目】,选择刚才创建好的淘宝创意互动项目;

3.项目类型,选择商家应用;

4.在面板的左上方关联应用,点击右上方的真机调试,编译完成后,使用手机淘宝APP,扫码调试;

四、注意事项

  1. 平台因为安全问题,不支持 my.request 这个网络请求的 API。我们通过其他 API 支持了大部分的网络请求方法,如果你的游戏还有问题,请使用云开发
  2. 加载远程资源时,资源要放在阿里系域名下,具体情况请咨询淘宝的技术支持;
  3. 平台提供的文字输入功能很弱,请先测试查看效果;
  4. 创建的 egret.Sound ,在不用的时候,一定要调用 sound.close() 方法来销毁;
  5. 不支持横屏游戏;
  6. iOS 暂时不支持 websock 真机调试,预览模式可以使用;
  7. iOS 暂时不支持本地声音播放,网络加载的声音可以;
  8. 不能直接调用 window 对象,需要使用 $global.window;
  9. 模拟器暂时不支持声音播放等功能,请以真机测试为准。

五全局变量的使用

淘宝创意互动项目不支持全局变量,具体使用方式,请查阅Egret官方教程文档-《关于全局变量的使用》!

查看原文

赞 0 收藏 0 评论 0

Mandy 发布了文章 · 9月25日

Egret Engine 5.3.10版本发布,主要修复基于 iOS14 系统的卡顿问题

今天Egret Engine5.3.10版正式发布,主要内容是修复iOS14 系统上 mesh 卡顿、htmlsound 声音挂载到后台后无法返回以及龙骨模型显示异常三个问题。

截至目前,虽然Egret Engine5.3系列依然属测试版,但产品功能已趋于稳定,建议有卡顿问题的开发者升级处理!

如若您的上线项目使用的是Egret Engine 5.2系列的稳定版,且不想升级引擎版本解决卡顿问题,我们为您提供了第二套解决方案,需要您在Egret Engine 5.2.X版本中手动修改以下2个位置的代码:

位置1:WebGLVertexArrayObject.ts

cacheArrays方法

 .......
 if (meshVertices) {
 let vertData = [];
 // 计算索引位置与赋值
 const vertices = this.vertices;
 const verticesUint32View = this._verticesUint32View;
 let index = this.vertexIndex * this.vertSize;
 // 缓存顶点数组
 let i = 0, iD = 0, l = 0;
 let u = 0, v = 0, x = 0, y = 0;
 for (i = 0, l = meshUVs.length; i < l; i += 2) {
 iD = index + i * 5 / 2;
 x = meshVertices[i];
 y = meshVertices[i + 1];
 u = meshUVs[i];
 v = meshUVs[i + 1];
 if (rotated) {
 vertData.push([
 a * x + c * y + tx,
 b * x + d * y + ty,
 (sourceX + (1.0 - v) * sourceHeight) / textureSourceWidth,
 (sourceY + u * sourceWidth) / textureSourceHeight,
 ]);
 } else {
 vertData.push([
 a * x + c * y + tx,
 b * x + d * y + ty,
 (sourceX + u * sourceWidth) / textureSourceWidth,
 (sourceY + v * sourceHeight) / textureSourceHeight,
 ]);
 }
 verticesUint32View[iD + 4] = alpha;
 }
 for (let i = 0; i < meshIndices.length; i += 3) {
 let data0 = vertData[meshIndices[i]];
 vertices[index++] = data0[0];
 vertices[index++] = data0[1];
 vertices[index++] = data0[2];
 vertices[index++] = data0[3];
 verticesUint32View[index++] = alpha;
 let data1 = vertData[meshIndices[i + 1]];
 vertices[index++] = data1[0];
 vertices[index++] = data1[1];
 vertices[index++] = data1[2];
 vertices[index++] = data1[3];
 verticesUint32View[index++] = alpha;
 let data2 = vertData[meshIndices[i + 2]];
 vertices[index++] = data2[0];
 vertices[index++] = data2[1];
 vertices[index++] = data2[2];
 vertices[index++] = data2[3];
 verticesUint32View[index++] = alpha;
 // 填充数据
 vertices[index++] = data2[0];
 vertices[index++] = data2[1];
 vertices[index++] = data2[2];
 vertices[index++] = data2[3];
 verticesUint32View[index++] = alpha;
 }
 let meshNum = meshIndices.length / 3;
 this.vertexIndex += 4 * meshNum;
 this.indexIndex += 6 * meshNum;
 } else {
 ......

位置2:WebGLRenderContext.ts

drawTexture方法

let buffer = this.currentBuffer;
 if (this.contextLost || !texture || !buffer) {
 return;
 }
 let meshNum = meshIndices && (meshIndices.length / 3) || 0;
 if (meshIndices) {
 if (this.vao.reachMaxSize(meshNum * 4, meshNum * 6)) {
 this.$drawWebGL();
 }
 } else {
 if (this.vao.reachMaxSize()) {
 this.$drawWebGL();
 }
 }
 if (smoothing != undefined && texture["smoothing"] != smoothing) {
 this.drawCmdManager.pushChangeSmoothing(texture, smoothing);
 }
 // if (meshUVs) {
 //     this.vao.changeToMeshIndices();
 // }
 let count = meshIndices ? meshNum * 2 : 2;
 .........

以上2种方案均可解决基于iOS14系统带来的卡顿问题,大家可根据项目情况自行选择。使用Egret Engine期间如若遇到问题,可联系官方客服微信号:egretengine,我们会第一时间帮您解决!

查看原文

赞 1 收藏 0 评论 1

Mandy 发布了文章 · 9月8日

Egret Engine 5.3.9版本发布,支持华为快游戏平台

诸位开发者朋友下午好,今天我们正式发布了Egret Engine 5.3.9版本,在这一版本中主要完成了华为快游戏平台的对接支持,方便开发者一键发布游戏至华为快游戏平台。同时,我们修复了大家反馈的Webgl 模式显示模糊问题和360小游戏导出龙骨库失败问题,有项目需求的朋友可下载更新!

现在,Egret Engine 5.3系列的社区体验版开发已接近尾声,稍后我们会正式推出Egret Engine 5.4系列稳定版,届时开发者朋友们可关注、下载更新!

在使用Egret Engine过程中,如果您遇到问题可以联系官方客服微信号:egretengine,我们会帮您尽快解决!

以下是今天的重点华为快游戏平台接入指南(建议收藏):

一、开发环境准备

  • 注册华为快游戏账号;
  • 账号登陆、用户信息等系统功能,请调用平台提供的 API。
  • 注意 最终发布的 rpk 文件总大小不能超过 10 MB。

备注:账号注册地址、快游戏平台API说明文档, 前往官网/Egret Engine/使用手册/发布项目/华为快游戏接入指南查看!

二.创建小游戏和可视化编译打包小游戏

1.使用 Egret Launcher 创建一个游戏项目,或者将原有的 Egret 项目导入;

2.导入或者创建完成后,会在 Egret Launcher 的列表里看到该项目,点击发布设置;

3.选择华为快游戏标签,点击确定,创建快游戏项目;

4.创建成功后,点击发布标签,可以可视化的发布小游戏包;

编译游戏代码到华为快游戏:把白鹭工程里的代码编译到快游戏的项目里;

  • 游戏代码类型 - debug:js 代码不进行uglify 混淆,便于 debug 调试;
  • 游戏代码类型 - release:js 代码进行 uglify 混淆压缩;

5.点击发布后,会把编译好的 rpk 包生成到 dist 文件夹内;

6.华为快游戏项目结构:

  • build 目录:
  • egret.fastgame.js:白鹭引擎与快游戏的适配层代码;
  • game.js:快游戏的入口文件;
  • icon 目录:游戏图标;
  • js 目录:游戏的 js 代码;
  • manifest.js:用于加载依赖的 js 文件;
  • manifest.json:快游戏的配置文件(具体说明文档前往官网/Egret Engine/使用手册/发布项目/华为快游戏接入指南查看!
  • resource: 游戏的图片、音频等资源文件;
  • dist 目录:用于存放编译好的 rpk 文件;
  • sign:用于存放签名文件;
  • signtool:快游戏的编译工具;
  1. 通过 Launcher 的“修改配置”标签页,可以修改快游戏的相关参数(参数说明文档前往官网/Egret Engine/使用手册/发布项目/华为快游戏接入指南查看!)。
  • 注意 修改参数后,需要重新发布一次 rpk,新的参数才会生效;
  • 最小平台版本号为1075;

三.安装到手机

  • 下载快应用加载器助手windows版/ mac 版;
  • 点击 选择文件 选择刚才编译好的 rpk 包,然后点击 加载 安装到手机

四.关于签名文件

华为快游戏的签名分为 debug 和release 两种。我们提供了默认的 debug 签名,便于开发者打包调试。但如果要使用登陆、用户信息等平台功能,则必须使用 release 签名,生成方式点击阅读原文同一位置查看。

  • 在 Launcher 的发布标签页,签名类型选择 Release ,点击右侧的“打开”按钮,会打开一个文件夹,然后将生成好的签名文件放入;
  • 再次发布后,生成出来的就是使用 release 签名的 rpk 包;
  • 注意 ,使用华为工具生成的签名,必须将证书指纹,填到快游戏的后台的项目设置中。

查看原文

赞 0 收藏 0 评论 0

Mandy 发布了文章 · 8月25日

《迷你世界》3D小游戏版仅用2个月时间上线,且实现数据互通

《迷你世界》作为国内第一的放置类3D沙盒游戏,依靠三四线城市的游戏市场及垂直媒体的传播途径,研发团队用了短短3年时间就创造出了8000万活跃玩家、5000万玩家原创作品,仅2020年上半年,关于《迷你世界》的短视频点击量已超600亿。在开发团队和玩家们的共同努力下,现在《迷你世界》已经形成了一个非常完整的游戏生态。

在小游戏成为新型流量入口的的今天,《迷你世界》开发团队也发现了这片“新的生态世界”,他们希望在这个世界中继续延续创造之旅。

经过多方考察、慎重考虑,开发团队决定研发一款适合小游戏平台的沙盒游戏,他们希望这款小游戏不仅可以与《迷你世界》有所区别,同时可以与《迷你世界》实现互补、导流,能够成为《迷你世界》内容创作生态的一部分,进而打通手游、小游戏用户群的壁垒。

《迷你世界创造板》3D小游戏因此而诞生,开发团队从筛选小游戏引擎,决定使用白鹭引擎,到游戏开发上线大概用了两个月。

今天,我们与《迷你世界创造板》研发团队接洽,一起聊聊这款小游戏的开发故事。

坚守初衷,精准获取用户群

随着小游戏引擎能力逐步变强,开始支持了3D能力的研发,而《迷你世界》中“微缩方块”的功能特别受到玩家的欢迎,研发团队在创作这个点上做更多方便、快捷、有趣的尝试。同时多维度的服务《迷你世界》内容生态中的游戏创作者与开发者,让他们能够纯粹的体会到游戏乐趣,而不需要为工具发愁。

因此,在《迷你世界》游戏基础上衍生出的官方创造工具——《迷你世界创造板》,这款游戏研发的初衷主要是给广大青少年提供一个更健康的像素场景搭建环境,脱离必须在游戏场景中进行像素作品的搭建桎梏,同时基于小游戏平台打造更便携的创作入口,即开即玩,并且更方便的将自己的作品分享给好友,共享创作乐趣。

《迷你世界创造板》核心用户群主要聚焦在:迷你世界的玩家和所有体素爱好者。

而项目团队成员则汇聚了拥有各种项目经历的策划同学,制作多款小游戏的资深程序员,大家基于相同的愿望和爱好聚集在一起,希望共同开发一个有趣的创作平台,让众多玩家一起会因为爱好聚集在一起,分享自己的作品。

携手白鹭引擎提高开发效率、快速上线

由于《迷你世界创造板》研发团队第一次使用白鹭引擎,对其熟悉度并不高,这次做的又是兼容2D/3D创造场景的项目,因此研发团队在正式开工前已经做出预判:过程不会特别的顺利,会遇到一些问题。

研发团队在确认引擎后的第一时间就与白鹭引擎的技术支持团队联系并达成合作,希望帮助他们解决项目开发中的难题,从而提高开发效率,节约时间进而压缩成本,实现项目快速上线。

我们通过具体开发问题实例来看下《迷你世界创造板》研发团队开发过程中遇到的问题及白鹭引擎技术支持团队给予的解决方案:

第一个是游戏的DrawCall过高导致游戏比较卡的问题。

《迷你世界创造板》游戏中存在着大量的立方体对象,在最初的版本中,研发团队是将每一个立方体对象作为一个 GameObject 进行维护。由于游戏中的场景可以达到 100*100*100,这样的话 GameObject 的理论值就会高达一百万。研发团队在测试一个场景采用60*60*60的尺寸时发现:游戏的DrawCall 已经达到了二十万,根本无法渲染。

白鹭引擎技术支持根据此需求提供了定制技术Demo,建议研发团队将立方体修改为使用自定义Mesh顶点绘制的方式来去实现。这样每个场景中的模型不再是一群立方体模型的集合,而是仅一个通过算法自定义生成的模型。由于WebGL 1.0 版本一次绘制仅支持 65535 个顶点,所以最终绘制并不是一个模型,而是根据定点数量动态添加。

通过这项优化,在上述60*60*60的游戏场景中,DrawCall 从20万降低至60,游戏帧频可以60帧流畅运行,顺利解决了此问题。

第二个是光影效果问题。

《迷你世界创造板》研发团队最开始采用的是白鹭引擎官方提供的平行光源进行灯光阴影处理,但是这种方式在游戏场景中有些不协调。在白鹭引擎技术团队的帮助及建议下,我们采用了 Ambient Occlusion 的技术,并将其进行进一步的简化,通过自定义顶点信息和自定义Shader,实现了完全不依赖于平行光实现了光影效果。具体的技术原理和效果预览如下所示:

第三个是 2D/3D渲染结合。

《迷你世界创造板》游戏中分别为用户提供了2D和3D的创造场景,因此研发团队对2D/3D游戏画面的兼容及互相切换要求比较高。

而在Egret Pro 早期提供的技术方案是在 3D 场景中创建一个Stage2D节点用于显示2D内容,这个2D节点中可以使用现有的 Egret2D API。但是这种方式结合 2D/3D代码书写相对比较生硬,在一开始还有一些BUG。

为了改善这一开发体验,白鹭引擎技术支持团队提供了一种新的方案,将 Egret Pro 打包为一个库项目,然后在现有 2D 项目中可以直接引用这个库,这种方式我们认为对开发体验改善非常大,未来的项目中我们会继续采用这种新方案。

此外,白鹭研发团队还将 Egret Inspector 适配到了 Egret Pro 中,大大改善了3D游戏场景中的2D UI的开发效率,带给我们一个小小的惊喜!让我们印象深刻!

《迷你世界创造板》是 Egret Pro早期版本用户,相比于初期版本,现在的Egret Pro在功能及发布平台支持方面已经有了很大提升,已经可以同时支持发布Web 版本与微信小游戏、EgretNative,OPPO小游戏,vivo小游戏等多个平台,帮助游戏企业多渠道获取用户。我们也相信未来白鹭引擎研发及技术支持团队会不断的优化提升开发体验。

感谢《迷你世界创造版》研发团队的分享以及对白鹭引擎研发及技术支持团队的认可,也希望他们可以继续延续创造体验,帮助迷你世界的玩家和所有体素爱好者在这里展示一个又一个创意设计!

查看原文

赞 0 收藏 0 评论 0

Mandy 发布了文章 · 8月5日

网易经典IP大作《梦幻西游网页版》开发经验分享

基于白鹭引擎研发的网易经典IP大作《梦幻西游网页版》仅用时数天步入iOS免费版TOP3,截至目前,这款产品将近20天位列畅销榜Top 10,目前基本稳定在Top 20,首月仅iOS平台流水便破亿,其表现甚至超过了很多原生手游,让很多从业者对H5游戏的上限有了新的认识。

据了解,《梦幻西游网页版》与大部分H5游戏的不同之处在于:算上调优,其研发阶段经历了近1年半的时间。为了更多的了解这款游戏的开发故事,白鹭引擎团队有幸联系到了《梦幻西游网页版》项目组团队成员并与之进行交流。

以下是相关内容:

1.咱们这部经典大作的项目成员由哪些人组成呢?

我们成立了专项组,共有数十个名成员,主要职能分别有策划、程序、测试、UI和GUI。团队主要成员皆来自梦幻西游团队,有多年MMO开发运营经验。高品质的基础人员和随时可获取的大团队支持,是我们成功的关键。

2.咱们研发耗时1年半,不知在开发和调优哪部分用时比较多,主要是解决哪些问题?

开发和调优两部分的耗时差不多,开发阶段主要是搭建功能基础框架和实现具体功能,后续调优阶段主要是完善各种功能细节和针对各种性能指标(设备兼容性,执行效率,启动速度,服务器负载等)进行优化。

我们认为,开发只是完成了游戏的一部分,而一款好的游戏,是需要持续进行玩法创新、功能调优和测试提升,秉持匠人精神,精心打磨,才能最终面世。这也是我们从立项到上市,整体研发耗时1年半的原因。

3.咱们这款游戏中的社交机制相对要重些,不知是如何实现的,有哪些开发技巧可以分享下?

游戏的社交机制,是基于不同情境和玩法,引导玩家去与其他玩家进行交互。例如:师徒系统,帮派系统,情缘系统等。通过建立玩家之间的多维度关系,让玩家在虚拟世界中享受丰富的社交乐趣,更有参与感和归属感。

此外,多样化的PK玩法增强了游戏内的竞技氛围。其中多种PK玩法中的场景已实现了实时AOI的同步,而动态阻挡、实时战斗等机制,也大幅提升了PK玩法的丰富度和整体效果。

4.5M小包体是咱们这款游戏的最大特色,咱们游戏同时继承了IP经典元素,图片非常精美(也意味着素材包相对比较大),咱们如何做到5M小包体的,是否可以分享点经验?

跟大家讲讲我们做的3件事:

第一,我们对素材资源进行了压缩和整合处理,从而减少了资源量的大小和内存占用。

第二,我们对egret引擎的资源管理系统进行了大幅迭代,极大提升了资源使用和回收的效率, 这块我们很自然的借鉴了端游及互通版的成熟经验,但是为了将原本很方便的与操作系统对话的原生C++代码转成JS实现,我们还是做了很多艰苦工作的。

第三,我们还对android和ios包的运行环境进行针对性优化,进一步压缩了包体发布之后的大小。

5.咱们在iOS平台上取得了非常棒的成绩,对于某些开发者而言上iOS渠道则非常困难,对于这部分开发者,您是否方便给点小建议?

1、了解清楚ios的提审规则;

2、尽早提审,预留充足时间进行修改;

3、根据功能适时选择用native原生接口还是H5的javascript接口,兼容执行效率和开发效率;

4、产品本身品质还是要过硬,才能打动苹果公司。

6.在多端(PC、手机)互通方面,咱们的细节做的很好,不知做了哪些优化调整?

我们主要是实现了数据互通和充值互通,做到PC桌面版、PC网页版、手机网页版、安卓APP、iOS APP等多端实时完美互通,给跨端玩家创造最优、最便捷的游戏体验。

7.基于哪些原因您选择了白鹭引擎?

H5市场上有不少产品是基于egret引擎开发,其中不乏成功的案例。同时,egret引擎有相对完善的工具链和完备的开发文档,能提供比较高效的H5游戏开发环境。

8.您对于白鹭引擎在开发过程中的表现是否满意,整体的使用体验感受如何?

Egret引擎使用过程中的整体表现优良,尤其在工具链方面(代码编辑器,UI编辑器,动效编辑器,texture制作工具等)基本能有效地支持整体的项目开发。

以上是我们聊的全部内容,感谢《梦幻西游网页版》项目组朋友的配合,也希望《梦幻西游网页版》能在今后取得更辉煌的成果,同时也期待项目组给我们带来更多精品的H5游戏。

对这款游戏感兴趣的老铁们可以私信我要下载地址!

查看原文

赞 0 收藏 0 评论 0

Mandy 发布了文章 · 7月2日

教程文档 | 3D 跑酷小游戏实战开发

本教程带领大家从零开始开发一款完整的3D跑酷游戏,主要面向读者是有一定Egret2D开发经验的小伙伴,手把手教你学习EgretPro开发,快速开启您的EgretPro开发之旅。

下面是整个游戏的制作过程。

游戏制作

工欲善其事必先利其器,在开始制作游戏之前,您需要检查您是否安装了以下开发环境:

  1. 检查你的EgretPro是否更新到了1.6以及以上版本;
  2. 检查下是否安装了5.3.7以及以上的Egret2d引擎。

创建项目

首先,打开EgretPro,项目--库项目--新建。

其次,创建完项目之后,EgretPro会自动打开刚才创建的库项目RunningGame,在resource/scenes目录下面创建一个场景RunningScene,双击在场景编辑中打开该场景。如下图所示:

创建跑道

跑道是通过3个实体Cude拼接而成的,并且随着主角向前奔跑,跑道需要滚动起来,我们再这里通过组件的方式动态的创建跑道。

使用Vscode打开自己刚才创建的项目,然后在src目录下面创建一个文件夹game用来存放我们的组件代码,然后在game目录中创建RoadController.ts文件。

import { component } from "@egret/ecs";
import { Behaviour, GameEntity, EngineFactory, Vector3 } from "@egret/engine";
import { MeshFilter, DefaultMeshes, MeshRenderer, Material } from "@egret/render";
import { ResourceManager } from "@egret/core";

@component()
class RoadController extends Behaviour{
  
    private roads:GameEntity[] = [];
    private roadSize:Vector3 = Vector3.create(5,1,10);
    async onStart(){
        const RoadMaterial:Material = (await ResourceManager.instance.loadUri("assets/materials/ground.mat.json")).data;

        //创建3个实体拼接成跑道
        for (let i = 0; i < 3; i++) {
            const road:GameEntity = EngineFactory.createGameEntity3D("road"+i);
            road.addComponent(MeshFilter).mesh = DefaultMeshes.CUBE;
            road.addComponent(MeshRenderer).material = RoadMaterial;
            road.transform.localScale = this.roadSize;
            road.transform.setPosition(0,0,i*this.roadSize.z);
            this.roads.push(road);
            
        }
    }

    onUpdate(){

    }
}

然后把RoadController组件添加在场景的Root实体上,

最后点击预览(内置)(或者预览浏览器)按钮,就可以看到下面的效果了。

摄像机的这个角度看上去有点别扭,你可以在运行界面,通过调试摄像机的TransForm参数来调整摄像机的位置与角度达到画面看上去比较舒服。

添加主角

将主角添加到场景中,并且向前奔跑,效果图如下:

第一步,将美术同学给的游戏素材BakedAnimation拷贝到项目目录resource/assets/animations中。

第二步,在EgretPro编辑器资源管理器中打开resource/assets/animations/BakedAnimation/Boy_standby_out目录,拖拽Boy_standby.gltf.prefab.json文件到场景中。

第三步,播放主角奔跑动画。有两种处理办法:

方法1:直接在pro编辑中进行操作。具体如下:

方法2:在pro编辑中去掉勾选autoPlay,通过脚本去实现,在game目录下面创建PlayerController文件;(记得把PlayerController组件挂在到主角实体上哦)

import { component } from "@egret/ecs";
import { Behaviour} from "@egret/engine";
import { Animation } from "@egret/animation";
@component()
class PlayerController extends Behaviour{


onStart(){
        const animation = this.entity.getComponentInChildren(Animation);
        animation.play("Boy_run_0");
}
}

到这步为止,我们的主角就在跑道上奔跑起来了,但是我们还需要让我们的玩家往前移动,我们需要在onUpdate函数中不断的更新主角的位置。同时我们还需要让摄像机跟随这主角进行同速度的移动,否则你会发现你的主角在你的屏幕中越跑越远,越来越小啦~

import { component } from "@egret/ecs";
import { Behaviour} from "@egret/engine";
import { Animation } from "@egret/animation";
@component()
class PlayerController extends Behaviour{

...
onUpdate(dt){
  this.entity.transform.translate(0,0,this.moveSpeed*dt);
  this.camera.transform.translate(0,0,this.moveSpeed*dt);
}
}

随着主角往前移动,我们发现走着走着,我们脚下的跑道没了~

这个时候我们需要在主角向前移动的同时不断的往前铺路,打开我们的RoadController.ts组件,

@component()
class RoadController extends Behaviour{
         ...    

    onUpdate(){    
        if(this.roads.length == 0) return;

        const currentRoad = this.roads[0];
              //当玩家跑过跑道之后,将跑道再次利用
        if( this.player.transform.position.z > currentRoad.transform.position.z ){
            const changeRoad = this.roads.shift();
            changeRoad.transform.setPosition(0,0, this.roads[this.roads.length-1].transform.position.z+this.roadSize.z);
            this.roads.push(changeRoad);
        }
    }
}

最后我们需要通过鼠标左键来控制主角左右移动。我们需要在onUpdate函数中,根据鼠标的移动来改变主角的位置。

@component()
class RoadController extends Behaviour{

  onUpdate(dt){

       
        let moveX = 0;

        this.entity.transform.translate(0,0,this.moveSpeed*dt);
        this.camera.transform.translate(0,0,this.moveSpeed*dt);

        const _leftMouse = this.inputManager.getInput(InputCode.LeftMouse);
        // 鼠标左键按下的时候记录下主角的位置
        if(_leftMouse.isDown){
            this.startPostionX = this.entity.transform.position.x;
        }
        //获取鼠标移动的距离
        if(_leftMouse.isHold){
            const point = _leftMouse.entity.getComponent(Pointer);
            moveX = point.position.x - point.downPosition.x;
            
        }
        
        if (moveX) {
          //增加一些跑道边界的限制
            let playerNextPostionX = this.startPostionX + moveX/100;
            if (playerNextPostionX > this.roadBound) {
                playerNextPostionX = this.roadBound;
            }

            if (playerNextPostionX < -this.roadBound) {
                playerNextPostionX = -this.roadBound;
            }
                        //设置主角的位置
            this.entity.transform.setPosition( playerNextPostionX,
                this.entity.transform.position.y,
                this.entity.transform.position.z);
        }

        }
}

添加金币

预制体是一个游戏对象及其组件的集合,目的是使游戏对象及资源能够被重复使用,相同的游戏对象可以通过一个预制体来创建,此过程可以理解为实例化

游戏中的金币散落在整个跑道上,在这里使用预制体来做金币是最合适的!

如何创建预制体?

  1. 打开(或者创建)resource/perfab目录,然后在资源管理器模块,右键--》创建预制体coin.perfab.json。
  2. 双击刚刚创建的预制体,在层级栏中右键-->3D-->球体;
  3. 选中刚才创建的球体,在属性栏给其选择material项,选择,coin.mat.json;

首先,我们先来创建一个金币组件Coin.ts

import { component } from "@egret/ecs";
import { Behaviour, GameEntity } from "@egret/engine";

@component()
export class Coin extends Behaviour{
//因为金币需要在其他类中引用,所以需要将该类export出去
}

我们的金币都是散落在跑道上的,所以每创建一截跑道,我们就在该跑道上随机创建一些金币,金币的数量是随机的,位置也是随机的。接下来,需要在RoadController.ts组件中添加如下逻辑代码:

import { component } from "@egret/ecs";
import { Behaviour, GameEntity, EngineFactory, Vector3 } from "@egret/engine";
import { MeshFilter, DefaultMeshes, MeshRenderer, Material } from "@egret/render";
import { ResourceManager, serializedField, property, EditType } from "@egret/core";
import { Coin, CoinPool } from "./Coin";

@component()
class RoadController extends Behaviour{
        ...
    private coinPerfabUrl:string = "assets/perfab/coin.prefab.json";

    async onStart(){
        const RoadMaterial:Material = (await ResourceManager.instance.loadUri("assets/materials/ground.mat.json")).data;

        //创建3个实体拼接成跑道
        for (let i = 0; i < 6; i++) {
            ...
            //在每截跑道上创建金币
            this.createCoins(road);
            
        }
    }

    onUpdate(){
        
        if(this.roads.length == 0) return;
        const currentRoad = this.roads[0];       
        if( this.player.transform.position.z > currentRoad.transform.position.z ){
           ...
            //添加金币
            this.createCoins(changeRoad);
            
        }


    }


    async createCoins(road:GameEntity){
      //数量随机
        const coindCnt = Math.floor(Math.random()*3) + 1;
        for (let i = 0; i < coindCnt; i++) {
            // 创建金币---预制体
            coin = await EngineFactory.createPrefab(this.coinPerfabUrl) as GameEntity;
            coin.addComponent(Coin);
          
          //位置随机
            coin.transform.setPosition(Math.random() * this.roadSize.x - this.roadSize.x / 2, 1, road.transform.position.z + i * 1.5)
        }
    }
}

这样子我们就可以在道路上面看见很多随机的金币啦!

但是如果是有一定开发经验的小伙伴肯定知道我们还需要一个金币池,来回收金币,避免一直创建金币。

接下来我们再来创建一个金币缓冲池。我直接在Coin.ts文件中添加一个CoinPool类。

// Coin.ts

export class CoinPool{
    static coinPool:GameEntity[] = [];
}

当金币离开摄像机的渲染范围,我们就应该把金币放入到缓冲池中,同时金币实体不在参与渲染,使金币处于休眠状态。这些对金币的处理我们都放在系统类中去做。

系统便是来处理拥有一个或多个相同特征组件的实体集合的工具,其只拥有行为(即在系统中没有任何状态)。

我们系统类中获取所有的金币。那么如何在系统中获取所有的金币呢?

实体匹配器是用来定义具有某种组件特征的实体集合的规则,通过一个匹配器实例,就可以定义一个明确的实体集合的规则。
//举列子,我们通过实体匹配器获取场景中所有具有Transform 和MeshRender组件的实体集合
Matcher.create(GameEntity, true, Transform, MeshRenderer);

回归到我们的案例中,我们先创建一个金币系统类 CoinSystem.ts,在其中,我们要获取所有的金币,然后在每一帧中检查金币是否被玩家甩到背后,不需要渲染了,那么我们就把它回收到金币池中。具体看下面的代码:

import { System, system, Matcher } from "@egret/ecs";
import { GameEntity } from "@egret/engine";
import { Coin, CoinPool } from "./Coin";


@system()
export class CoinSystem extends System{

    player:GameEntity = null;
    
  //实体匹配器
    getMatchers(){
      //获取所有金币,返回集合,返回的集合存储在 this.grounps[0]中
        return  [
            Matcher.create(GameEntity,true,Coin)
        ];
    }
  
    onFrame(){
        const coins = this.groups[0].entities as GameEntity[];
        for (const coin of coins) {
          //如果金币远离了主角
            if(coin.transform.position.z < this.player.transform.position.z-5){
                coin.enabled = false;
                coin.getComponent(Coin).enabled = false;
                CoinPool.coinPool.push(coin);
            }
        }
    }

}

系统并不像组件直接添加到实体上就可以起作用,我们需要在组件注册系统。接下来,在PlayerController中,添加如下两行代码。

//PlayerController.ts 
...
onAwake(){
          
        Application.instance.systemManager.registerSystem(CoinSystem);
        Application.instance.systemManager.getSystem(CoinSystem).player = this.entity;
    }
...

当创建金币的时候,我们首先考虑从缓冲池中获取。修改RoadController.ts中createCoins()函数

//RoadController.ts

async createCoins(road:GameEntity){
        const coindCnt = Math.floor(Math.random()*3) + 1;
        for (let i = 0; i < coindCnt; i++) {
            let coin:GameEntity = null;
            if(CoinPool.coinPool.length>0){
              //获取缓冲池中的金币
                coin = CoinPool.coinPool.pop();
                coin.enabled = true;
                coin.getComponent(Coin).enabled = true;
                console.log("-----------");
                
            }else{
            // 创建金币---预置体
            coin = await EngineFactory.createPrefab(this.coinPerfabUrl) as GameEntity;
            coin.addComponent(Coin);
            
            }

            coin.transform.setPosition(Math.random() * this.roadSize.x - this.roadSize.x / 2, 1, road.transform.position.z + i * 1.5)
        }
    }

处理碰撞

接下来,我们要做的就是处理金币与主角之间的碰撞了,我们需要检查每一个金币,如果和主角发生了碰撞,那么我们的金币就有一个缓动动画然后消失。那么对金币与主角碰撞处理的这一个行为我们还是放在CoinSystem.ts系统类中去处理。

//CoinSystem.ts
    onFrame(){
       ...

            //判断玩家与金币的碰撞
            if (coin.transform.position.getDistance(this.player.transform.position)<1) {
                console.log("-----+++++");
                
                coin.getComponent(Coin).enabled = false;
                
                Tween.toPosition(coin.transform,1,{
                    y:3,
                    ease:Elastic.easeOut,
                    onComplete:()=>{
                        coin.enabled = false;
                        CoinPool.coinPool.push(coin);
                    }
                })    
            }

添加UI界面

到这一步,我们的3D场景就完成啦!

接下来,我们需要给案例添加一个UI界面,也就是要加入一些2d的内容。在这里我需要给读者讲解一下如何在3d场景中添加UI界面?具体参考这里:Egret2d与EgretPro整合

第一步,将3d场景导出成第三方库pro-library;

第二步,创建一个2d项目,将第三库pro-library添加到2d项目中;

第三步,升级2D项目,修改index.html

egret.runEgret({
    renderMode: "webgl",
    audioType: 0,
calculateCanvasScaleFactor: function (context) {
const backingStore = context.backingStorePixelRatio ||
            context.webkitBackingStorePixelRatio ||
            context.mozBackingStorePixelRatio ||
            context.msBackingStorePixelRatio ||
            context.oBackingStorePixelRatio ||
            context.backingStorePixelRatio || 1;
return (window.devicePixelRatio || 1) / backingStore;
},
    pro: true, // 需要修改为true,以启动 EgretPro 环境
});

第四步,EgretPro 中的场景渲染为一个egret.Texture对象,Egret引擎只需要将egret.Texture添加到Bitmap对象当中,即可渲染到舞台。

const texture = await egret.pro.createTextureFrom3dScene("assets/scenes/animations/test.scene.json", 640, 640);
const bitmap = new egret.Bitmap(texture);
this.addChild(bitmap);

结合本案例,我们处理完上面的第一、二、三步,我的项目目录如下图:

然后我点击开始游戏按钮,添加跑酷的场景。具体看Main.ts文件。

//Main.ts文件 
private async onButtonClick(e: egret.TouchEvent) {
       const texture = await egret.pro.createTextureFrom3dScene("assets/scenes/RunningScene.scene.json",640,1136);
       const bitmap = new egret.Bitmap(texture);
       this.addChild(bitmap);
    }

但是这个时候,大家发现我们的主角无法左右移动了,这个时候需要我们将2d的触摸事件传递到3d场景中。那么就需要通过egret.pro去完成通信。

    //Main.ts

        private createGameScene(){
       //...
                this.addEventListener(egret.TouchEvent.TOUCH_BEGIN,this.onTouchBegin,this);
        this.addEventListener(egret.TouchEvent.TOUCH_MOVE,this.onTouchMove,this);
    }

    private startPostionX:number;

    private onTouchBegin(e:egret.TouchEvent){
        this.startPostionX = e.stageX;
          //派发消息
        egret.pro.dispatch("2dTouchBegin",1);
    }

    private onTouchMove(e:egret.TouchEvent){
        const moveX = e.stageX - this.startPostionX;
      //派发消息
        egret.pro.dispatch("2dTouchMove",1,moveX);

    }

那么我们需要在3d场景的PalyerContrller中接受消息并且处理消息。具体见下:

//PlayerController.ts  
onStart(){
      ...

        //监听2d的消息
        Application.instance.egretProUtil.addEventListener("2dTouchBegin",1,this.touchBeginFrom2D,this);
        Application.instance.egretProUtil.addEventListener("2dTouchMove",1,this.touchMoveFrom2D,this);

    }

    touchBeginFrom2D(){
        
        this.startPostionX = this.entity.transform.position.x;
    }

    touchMoveFrom2D(messag:any){

        let moveX = this.startPostionX + messag/100;
        if(moveX > this.roadBound){
            moveX = this.roadBound
        }
        if(moveX < -this.roadBound){
            moveX = -this.roadBound;
        }

        this.entity.transform.setPosition(
            moveX,
            this.entity.transform.position.y,
            this.entity.transform.position.z
        );
    }

然后,我们控制台输入指令:egret run -a 就可以运行你的项目啦!

小结

恭喜你完成了使用EgretPro制作的第一款游戏,在这里你可以下载完整的游戏源码。

通过本示例你可以学到手势识别、动画系统、金币系统、碰撞处理、UI系统、EgretPro与Egret2d项目交互等知识点同时你也可以学习了解到EgretPro与Egret2d之间的交互--使用EgretPro制作3D场景,然后把制作好的3D场景导出为第三库的形式添加到Egret2D项目,在Egret2D项目中处理UI系统,使用Egret.pro中的方法进行3D与2D之间的通信。

最后,您还可以继续在本示例的基础上添加功能继续完善您的游戏。期待您的完美作品!

查看原文

赞 0 收藏 0 评论 0

Mandy 发布了文章 · 6月15日

视频教程| Egret Pro入门学习笔记(3):输入示例

今天我们继续Egret Pro 示例项目的学习,内容包括:实例演示、输入示例:键盘/鼠标、编写组件3块,话不多说,详细内容见视频:

Egret Pro 入门学习笔记3 输入示例

查看原文

赞 0 收藏 0 评论 0

Mandy 发布了文章 · 6月4日

Egret 5.3.6 正式发布,大幅改进编译速度

各位开发者大家好,

我们今天正式发布 Egret 5.3.6 版本。Egret 5.3.6 仍然是一个抢先预览版,在这个版本中我们为各位开发者带来如下功能:

  • JavaScript模块支持
  • 全新的 EuiCompiler
  • 运行时改进
  • Inspector更新

其中 JavaScript模块支持和EuiCompiler我们建议正在开发中尚未上线的项目使用,运行时以及 Inspector 更新所有项目均可使用。

JavaScript 模块支持,大幅改进编译速度(beta)

这项技术我们率先使用在 EgretPro中,在这个版本我们将其移植到了 Egret 5.3 版本中,以保证尽可能多的存量开发者可以使用此功能。

在不支持模块的老式浏览器中,如果一个 JavaScript 文件要想给另外一个文件暴露出去一部分数据或者一个变量,那只能将它定义在全局的作用域下,并根据他们的依赖关系来决定加载顺序。

白鹭引擎构建管线中的 IncrementBuild 插件将会分析您的游戏逻辑依赖关系,并生成一个 manifest.json 文件,游戏在调试时会加载这个 manifest.json ,根据其中的脚本顺序逐个加载 JavaScript 代码。

这种方式带来的问题是,随着项目不断变大,IncrementBuild 插件的依赖关系检查会使游戏的编译速度会越来越慢,而 JavaScript 模块中,由于所有的依赖关系都是显式设置的,所以不存在此问题。

在 5.3.6 版本中,我们允许开发者使用 JavaScript模块,并提供了 webpack 打包器,它会将多个 JavaScript 模块文件打包为一个文件,使得其可以在不支持JavaScript模块的旧式浏览器上运行。

经过与白鹭合作的开发者抢先测试,将一个代码总量20万行,包含1700个 TypeScript 文件的重度挂机游戏项目迁移至 JavaScript Module 格式花费了一人一个星期时间,而这份投入非常的值得。经过开发者的实际反馈,在修改前编译速度大约为40秒一次,修改后仅需3-4秒,这可以为每位前端开发人员每天节省一小时的时间。

如果您对这项改动感兴趣,但是担心项目过大而感觉无从下手,可以联系白鹭引擎的官方技术支持(微信号:egretengine),寻求白鹭引擎官方团队的支持。

全新的 EuiCompiler (beta)

在使用白鹭引擎开发的游戏中,UI以及相关逻辑是工作量最大的部分之一。在 Egret 5.3 系列版本中,我们决定全面改进 UI的 开发体验。为此我们先是发布了全新的 Egret UI Editor,并逐步迭代至1.9版本。除此之外,我们将在这个版本中为大家带来全新的 EuiCompiler。

EuiCompiler 是引擎中的 ExmlPlugin 的升级版本,他实现了和 ExmlPlugin 一致的功能,但是内部代码结构更加清晰并具备可扩展性。开发者可以扩展 EuiCompiler,为其加入符合自己游戏需求的定制功能,诸如:浮点数值擦除,国际化语言包、资源文件检查等。

EuiCompiler的第一个版本暂时只支持发布为JavaScript格式的皮肤,我们后续将会为其添加JSON以及ArrayBuffer格式的皮肤支持。

运行时改进

除了 JavaScript模块以及 EuiCompiler带来的开发效率改进外,我们也对引擎的运行时进行持续优化,具体包括:

  • vivo小游戏平台支持小游戏引擎插件功能
  • 修复部分设备浏览器上切换页面后,任意点击都会触发输入法的问题
  • 修复滤镜的父节点矩阵变化后,子节点显示异常问题
  • 修复ttf字体注册方法在EgretNative失效的问题
  • 修复EgretNative开启原生加速后,MovieClip生成的显示对象使用多滤镜渲染存在的错误
  • 修复5.3.5版本引擎在EgretNative上开启原生渲染后显示错位的问题

Inspector 改进

在这次更新中我们也更新了 Egret Inspector 至 3.5.1,版本。主要修复如下问题:

  • 修复 TOUCH_END 事件不能触发的问题
  • 修复显示对象 visible = false 时,还能被选取的问题
  • 修复游戏的 url 路径中有特殊符号时,不能正确解析的问题

后续更新

在这次版本发布后,白鹭引擎后续研发重点主要集中在如下几个方面:

  • Egret Native 的使用体验
  • 在现有2D项目中更方便的引入3D内容
  • EUI 相关功能的进一步优化
查看原文

赞 0 收藏 0 评论 0

Mandy 发布了文章 · 6月1日

视频教程| Egret Pro入门学习笔记(1、2)

今天我们推出了大家期待已久的Pro使用教程:入门学习笔记!为何命名为入门学习笔记,因为第一,这是我们的技术支持童靴学习Egret Pro的过程记录,第二,我们的技术童靴跟部分开发者的起点一样,拥有白鹭引擎2D开发经验,同时需要将这些知识和经验应用于Egret Pro。

今天是我们第一期的内容,主要讲Egret Pro使用前的准备工作,包含2个视频,分别讲述开发环境的搭建、认识/使用Egret Pro编辑器以及3D游戏开发中常用的概念等内容。
Egret Pro 入门学习笔记 1 搭建开发环境 认知Pro

Egret Pro 入门学习笔记2 常用概念

下周我们从输入示例入手,陆续讲述3D示例、拖拽、摄像机、灯光、材质、动画、粒子、UI等内容,希望在接下来的时间里大家相帮共勉,一起学习3D游戏开发!

查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 21 次点赞
  • 获得 0 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 0 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2017-07-20
个人主页被 419 人浏览