关于游戏开发:从0到1开发管理后台

<article class=“article fmt article-content”><p>开发程序,最难的其实不是基础知识,而是怎么应用基础知识做出货色来。</p><p>本课程的目标,就是应用最简略的常识,开发最简单的零碎。学习完本课程,基本上就能够单独开发一个后盾管理系统了。</p><p>治理后盾是一个用于治理和控制系统的后盾界面。它通常由管理员或经营人员应用,用于配置零碎设置、监视系统状态、治理用户权限、公布内容、解决数据等。治理后盾提供了对系统各个方面的全面管制和治理性能,使管理员可能无效地管理系统并进行必要的操作和决策。</p><p>一款游戏的开发,不仅仅是客户端的开发和服务端的开发,还包含治理后盾。治理后盾能够说是一款网络游戏的标准配置,然而给人的感觉往往又是没有它也行,理论没有它又不行。</p><p>PHP以其易学易用、跨平台运行、与MySQL数据库联合严密等个性,成为构建后盾管理系统的重要工具。通过PHP开发的后盾管理系统能够实现用户治理、权限管制、数据处理、业务逻辑管制等一系列外围性能。</p><p><strong>田吉亮:</strong>从事游戏开发工作十五年无余</p><p>2008年开始从事游戏开发工作,全程参加多款大型游戏我的项目研发,积攒了丰盛的游戏开发教训。现就职于完满世界,负责游戏研发相干工作。已经负责过的局部产品《大明浮生记》、《找你妹》、《狂暴之翼》以及《战神陈迹》。</p><hr/><h3>目录</h3><p>1|开场白<br/>2|搭建开发环境<br/>3|PHP从入门到精通<br/>4|常量<br/>5|函数<br/>6|类和对象<br/>7|调试PHP的个别办法<br/>8|PHP最善于的畛域<br/>9|Windows上装置MySQL<br/>10|应用快捷键<br/>11|Linux-装置-MySQL<br/>12|PHP的依赖管理器<br/>13|HTML模版<br/>14|业务逻辑与体现拆散<br/>15|URL申请和业务逻辑对应<br/>16|在命令行中执行PHP<br/>17|登录验证<br/>18|设置默认页面<br/>19|捕捉错误信息<br/>20|布告(1)<br/>21|布告(2)<br/>22|布告(3)<br/>23|布告(4)<br/>24|布告(5)<br/>25|导航<br/>26|邮件(1)<br/>27|邮件(2)<br/>28|分页<br/>29|配置文件<br/>30|权限治理<br/>31|类的主动加载</p><hr/><p>本篇转载自《从0到1开发治理后盾》的第1节。<br/>https://www.youku.com/video/XNjM3MzEyODYyNA==</p><p>以上就是《从0到1开发治理后盾》的第1节,此课程比拟适宜从事游戏开发的人员、心愿晋升Web开发能力和对Web开发感兴趣的同学/读者。</p><p>读完全篇后你会取得:<br/>1、游戏治理后盾的开发教训;<br/>2、零根底Web开发的能力。</p></article>

February 29, 2024 · 1 min · jiezi

关于游戏开发:作业2游戏案例分析

本次作业须要从三项与游戏设计相干的工作中择一实现。经探讨与投票表决,咱们小组选定工作1:游戏案例剖析。之后便按照如下流程开展了学习:在本次工作中,我的分工是对游戏中的戏剧元素进行剖析。以下是我基于教材中的三个练习所作的剖析:问题1:在《动物大战僵尸》,须要应用哪些技巧。1、针对关卡环境、敌人品种抉择适合的动物搭配。如白天和夜晚环境别离抉择向日葵和阳光菇,泳池关卡抉择睡莲,面对矿工僵尸抉择决裂豌豆、杨桃、香蒲等具备后向打击能力的动物。2、正当调配阳光以应答关卡内不同阶段的敌人。在关卡初期,敌人数量较少,能够应用低消耗一次性动物(如海草、土豆地雷、窝瓜)来击杀,阳光次要用于种植向日葵、阳光菇等,扩充阳光产量。中期有了肯定数量的阳光后,便可大量种植攻击性动物,造成主动攻打防线。而在前期,因为种植得越前的动物越容易被僵尸吃掉,因而持续扩张防线收益不大,能够抉择保留阳光给樱桃炸弹、火爆辣椒等高威力一次性动物,防止某些路因火力有余导致崩盘。3、合理安排动物地位以充分发挥其作用。射程较短的动物,如大小喷菇,该当搁置在前排;向日葵、阳光菇一开始该当被爱护,须要种植在后排,但前期阳光充足时,也可种植于前排充当爱护;萝卜伞该当种植于次要火力动物旁。 问题2:《动物大战僵尸》中为玩家提供哪些反馈1、重叠反馈。与个别游戏罕用的数值重叠不同,《动物大战僵尸》的重叠体现在抉择上。随着游戏的停顿,玩家会逐步解锁更多的动物。因为绝大多数动物间并不存在齐全的上位代替,动物品种的增多也意味着攻关可用的动物搭配相应增多。取得选择权即成为了玩家攻关的能源。2、认知反馈。《动物大战僵尸》中大多数规定并非以图文形式动态展示,而是融入在游戏关卡中。譬如游戏的第一个关卡,除了搁置动物、收集阳光和阻挡僵尸外,便再无文字提醒,而余下的常识,如豌豆射手会主动攻打、小推车能够一次性革除一条道上的所有僵尸等,则都是玩家玩耍过程中自发发现的。又比方游戏中一些对策,例如大喷菇的穿透挫伤能够轻易击杀门板僵尸,也是通过关卡的承接来告知玩家的(取得大喷菇后下一关的新敌人即是门板僵尸)。玩家玩得越深刻,对动物个性、搭配办法的了解水平就越高。因此谋求对游戏的了解,摸索游戏的全副机制也成了玩家玩耍的能源。3、指标反馈。《动物大战僵尸》的指标反馈非常明显,每过一个关卡都会有相应的处分,或是一株新动物,或是解锁一个新游戏模式,或是一段起到剧情推动作用的信。而玩耍过程中积攒下来的货币,也可用于购买动物或游戏模式。这些指标便成为了玩家玩耍的能源。 问题3:《动物大战僵尸》的故事设定是怎么的,这个设定对游戏起到了什么帮忙《动物大战僵尸》的故事设定如下:主人公住在一栋危机四伏的房子中,常常有僵尸试图入侵房子,吃掉主人公的大脑。主人公要做的便是种植动物,阻止僵尸,并逐步找到僵尸入侵的源头,彻底终结这场危机。除了动物,主人公还有一个疯疯癫癫的帮手——街坊戴夫。他会卖给配角一些有用的物品。这个设定有助于玩家疾速了解游戏典型的塔防玩法。即使玩家可能并不理解塔防游戏,不晓得这类游戏的玩法吗,但当常常象征危险的僵尸缓缓走向主人公的房子时,玩家会很天然的试图阻止它,从而迅速地体会游戏的基本操作。同时,这个略显荒谬的设定也奠定了游戏的轻松基调,配合上游戏的卡通画风,营造了一种轻松愉快的气氛,肯定水平上均衡了塔防游戏时常会有的紧张感。

September 24, 2023 · 1 min · jiezi

关于游戏开发:翻译Godot-是独立游戏的新宠儿吗Godot-API-绑定系统的大讨论

最近,因为 Unity 的谜之操作,大量的 Unity 开发者外流寻找可代替 Unity 的游戏引擎。Godot 因为反对 C# 开发,4.0 版本后性能绝对欠缺起来,所以国内外 Unity 开发者对其关注度十分高,因而也开展了不少对于 Godot 是否代替 Unity 的探讨。 其中流传最广的探讨之一就是 Sam pruden 在 Reddit 论坛上对于 Godot API 调用过程性能的质疑。文章中具体钻研并测试了 Godot 射线检测的性能,并对引擎外围和各语言 API 间的绑定层的设计提出了质疑。 随后,Godot 的外围开发人员之一 —— Juan Linietsky 对其质疑进行了回复和解释,并解说了 Godot 对绑定层和 GDExtension 的定位和设计思路。 译者在围观吃瓜的过程中受害颇多,学习了很多对于游戏性能优化方面的思路,所以赶紧翻译了两位的文章,供大家一起交流学习。 直到译者熬夜翻译完的第二天,这场交换探讨还在炽热地进行着,想要围观的小伙伴能够去 Github Gist 和 Reddit 围观各路大佬的探讨。 Sam pruden 对 Reddit 论坛中观点的总结: Godot 不是新的 Unity - 对 Godot API 调用的分析By Sam Pruden 原文地址:Godot is not the new Unity - The anatomy of a Godot API call ...

September 22, 2023 · 10 min · jiezi

关于游戏开发:如何判断自己是否适合游戏开发

引言游戏开发是一个充斥创意和技术挑战的畛域,吸引着越来越多的年轻人投身其中。然而,要想在游戏开发畛域获得成功,首先须要明确本人是否适宜这个畛域。本文将为你介绍一些判断本人是否适宜游戏开发的关键因素。 1. 技术趣味和编程能力游戏开发离不开编程,对编程语言的了解和把握是至关重要的。如果你对计算机编程有浓重的趣味,喜爱解决问题、挑战逻辑难题,并且违心花工夫学习不同的编程语言和开发工具,那么你曾经迈出了胜利的第一步。 2. 数学和逻辑思维能力游戏中经常波及到简单的数学计算和逻辑推理,例如物理引擎模仿、碰撞检测等。如果你喜爱数学,善于解决问题,并且可能灵活运用数学知识来优化游戏性能,那么你在游戏开发中会更具劣势。 3. 创意和设计能力游戏不仅仅是代码的堆砌,还须要独特的创意和精心的设计。如果你有丰盛的想象力,长于构思乏味的玩法、引人入胜的故事情节和魅力四射的角色,那么你在游戏开发中可能奉献独特的价值。 4. 团队单干和沟通能力游戏开发通常须要多人单干,波及到程序员、美术设计师、音效工程师等多个畛域的单干。如果你喜爱与别人单干,可能无效地沟通和协调,具备团队单干精力,那么你可能更好地融入游戏开发团队。 5. 急躁和毅力游戏开发是一个充斥挑战的过程,可能会遇到各种问题和艰难。如果你领有足够的急躁和毅力,可能继续一直地解决问题,不被艰难击倒,那么你可能在游戏开发的路线上走得更远。 6. 继续学习和趣味驱动游戏开发畛域在一直变动和倒退,须要继续学习新的技术和工具。如果你放弃着对新常识的渴望,违心一直学习和摸索,那么你可能跟上行业的最新动静,放弃竞争力。 7. 趣味和激情最重要的是,游戏开发须要投入大量的工夫和精力,如果你对游戏开发充满热情,违心为之付出致力,那么你就曾经具备了胜利的根底条件。 总结综上所述,判断本人是否适宜游戏开发须要思考技术趣味、编程能力、数学逻辑思维、创意设计、团队单干、急躁毅力、继续学习和趣味激情等多个因素。如果你在这些方面都具备劣势,那么祝贺你,游戏开发可能是一个适宜你的畛域。无论抉择何种路线,放弃学习和不断进步都是要害,愿你在游戏开发的世界中获得骄人的成就! 本文的重点内容次要有以下几点,不晓得小伙伴们是否曾经了解: 如何判断本人是否适宜游戏开发。AD:笔者曾经上线的小游戏《填色之旅》《贪吃蛇掌机经典》《重力迷宫球》大家能够自行搜寻体验。 感兴趣的小伙伴记得关注我哦,一位有着8年游戏行业教训的主程。学习游戏开发不迷路。感谢您的关注,心愿能给到您帮忙, 也心愿通过您能帮忙到大家。 喜爱的能够点个赞、点个在看哦!请把文章分享给你感觉有须要的其余小伙伴。谢谢。 浏览原文关注我

August 19, 2023 · 1 min · jiezi

关于游戏开发:探索游戏开发中的Socket和HTTP网络通信含主流引擎的代码示例

引言在游戏开发中,实现无效的通信是确保玩家取得无缝体验的要害之一。两种常见的通信形式是 Socket 和 HTTP,它们各自在不同场景下施展着重要作用。本文将深入探讨这两种通信形式的特点、劣势以及在游戏开发中的利用。 Socket:实时性与灵活性的代表Socket 是一种基于 TCP 或 UDP 协定的底层通信形式,它容许游戏客户端和服务器之间建设持久性的连贯,实现实时数据传输。这种通信形式特地适宜须要高实时性和灵活性的场景,如多人在线游戏。 劣势: 实时性: Socket 能够实现实时的双向通信,使得玩家可能在游戏中即时地与其余玩家互动,从而发明更加身临其境的游戏体验。灵活性: Socket 提供了对数据包的精密管制,游戏开发者能够依据须要自定义通信协议和数据格式,以满足特定游戏的要求。低提早: 因为 Socket 的实时性,通信提早绝对较低,这对于须要高度敏感的游戏操作至关重要。利用场景: 多人在线游戏: 在 MMO 游戏中,Socket 能够用于实时同步玩家之间的地位、动作和交互,发明出一个共享的虚拟世界。实时策略游戏: 实时策略游戏须要玩家即时的决策和操作,Socket 能够反对实时指令传输,确保玩家命令的疾速反馈。HTTP:稳定性与跨平台的抉择HTTP(超文本传输协定)是一种宽泛应用的协定,用于在客户端和服务器之间传输数据。在游戏开发中,尽管 HTTP 不如 Socket 那样实时,但它在某些方面具备独特的劣势。 劣势: 稳定性: HTTP 基于 TCP 协定,具备较高的可靠性和稳定性,实用于那些不须要即时传输的游戏情境。跨平台: HTTP 是基于规范的网络协议,简直所有平台和设施都反对它,这使得游戏能够轻松实现跨平台的数据传输。利用场景: 数据存储与同步: HTTP 能够用于玩家数据的存储和同步,如玩家角色、成就和统计数据等,保障玩家在不同设施上的一致性。游戏更新与资源下载: 游戏能够应用 HTTP 协定下载更新和资源文件,确保玩家能够及时取得最新的游戏内容各支流引擎的代码示例1.Unity 游戏引擎Socket 模块Unity 应用 .NET 的 Socket 类库,上面是一个简略的基于 TCP 的 Socket 通信示例: HTTP 模块在 Unity 中应用 UnityWebRequest 进行 HTTP 申请的示例: 2.LayaAir 游戏引擎Socket 模块LayaAir 引擎应用 WebSocket 实现 Socket 通信,以下是一个简略的 WebSocket 通信示例: ...

August 18, 2023 · 1 min · jiezi

关于游戏开发:仙梦奇缘游戏详细图文架设教程

前言最近我发现了一款十分不错的仙侠手游,安卓苹果双客户端,双区可跨服,画面十分精美,玩法超级丰盛,而且 BUG 很少,不出意外我会长期开服,它就是仙梦奇缘~ 本文解说仙梦奇缘手游架设教程,置信这款仙侠手游相对让你爱不释手,游戏长期保护,欢送来玩~ 游戏客户端和源码下载请关注我的公众号 echeverra 回复“仙梦奇缘”下载。后盾 GM 回复“仙梦奇缘GM”获取。 同样举荐另外几款我架设的H5游戏:H5游戏整顿汇总,欢送来游玩~ 游戏截图: 架设1. 架设条件仙梦奇缘架设须要筹备: linux服务器,倡议CentOs 7.6版本,举荐轻量应用服务器,性价比高。游戏源码,关注我的公众号 echeverra,发送 “仙梦奇缘” 获取。服务器举荐 2H4G 配置,游戏运行会占用 2.8G 左右的内存。 2. 装置宝塔及环境宝塔是一个服务器运维管理软件,装置命令: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh装置完后,依照提示信息登录宝塔(如果无法访问可能是因为服务器没有凋谢8888端口,参考步骤凋谢端口),并在宝塔软件商店中搜寻以下软件装置: web服务器:Nginx1.18数据库:Mysql 5.6编程语言:PHP 5.6数据库管理工具:phpMyAdmin 4.43. 敞开防火墙通过宝塔菜单终端,执行敞开防火墙命令: systemctl stop firewalld.servicesystemctl disable firewalld.service4. 凋谢端口咱们间接凋谢所有端口1-65535,阿里云服务器在平安组中配置规定。 腾讯云服务器在防火墙中配置规定。 而后在宝塔菜单平安中凋谢所有端口。 5. 上传源码拿到源码后,将服务端目录下的 xmqy.tar.gz 压缩文件通过宝塔上传到根目录(如果宝塔禁止上传到根目录,可上传其余门路后剪切粘贴到根目录)。 上传胜利后终端命令进行解压。 cd /tar zxvf xmqy.tar.gz解压实现后,命令授予777权限: chmod -R 777 /www/wwwroot/xmqychmod -R 777 /home/sqlchmod -R 777 /home/xmqychmod 777 /home/sk6. 配置环境装置 gcc 动静库: ...

July 13, 2023 · 2 min · jiezi

关于游戏开发:促进协作提高生产力育碧选择Perforce-Helix-Core的原因

Perforce Helix Core成为育碧(Ubisoft)的次要源代码管制工具曾经超过六年了,被团队中的程序员和美术人员在大部分我的项目中应用。在育碧蒙特利尔工作室,有超过1,200名的开发人员应用Perforce Helix Core来贮存源代码和数字资产,包含图形和动画文件、建模、纹理以及声音和视频片段。 为什么应用了六年,育碧仍然如此称心Perforce Helix Core?  API易用性和灵活性  现实的分支机制  代理服务器的效率https://www.bilibili.com/video/BV1PX4y1e7Li/?aid=358127626&ci... “Perforce Helix Core曾经成为存储每个人工作的外围且要害的工具。咱们的团队在一直壮大。Perforce Helix Core的速度、可靠性和可扩展性对育碧来说至关重要,有超过1,000名用户依赖它。”——Nicolas Beaufils,育碧技术架构师开发环境一览公司名称:育碧(Ubisoft)总部:法国巴黎行业:游戏开发,包含游戏、PC和便携式游戏机的开发成为Perforce客户的工夫:2001年Perforce Helix Core用户数:超2,000人(蒙特利尔工作室有1,210人)连贯环境:多千兆位链路开发地点数量:一处位于加拿大蒙特利尔(魁北克)。寰球其余地点包含法国巴黎、蒙彼利埃和中国上海文件数量:5TB(24,070,195个文件)变更数量:166,642,479次订正(337GB元数据)管理员人数:2人客户端平台:Windows主服务器:蒙特利尔三台:一台IBM x3655和两台Compaq/HP DL580育碧是寰球当先的互动娱乐产品生产商、发行商和分销商。该公司领有1,000多款游戏,在50多个国家/地区发行。该公司的15个外部制作工作室遍布11个国家/地区。 育碧的蒙特利尔工作室领有1,600名员工,并且打算减少到3,000人以上。这将使蒙特利尔工作室成为寰球最大的创意力量之一,并推动主机和PC电子游戏的概念与开发。育碧旗下品牌包含《波斯王子》、《刺客信条》、《雷曼》、《细胞分裂》以及《彩虹六号》。 倒退中的挑战从一开始,育碧就决定将所有的创意和游戏开发工作保留在外部。当初,该公司认为这一战略决策是让他们走向胜利的要害,并帮忙他们轻松过渡到下一代主机。 在育碧,每款游戏都作为一个独立的公司进行开发,领有本人的团队。依据游戏规模和开发阶段,团队规模从15人到150人不等。每个团队负责本人的工具和引擎,并领有本人的Perforce Helix Core服务器。 育碧的指标是共享工具和游戏引擎,这样它们就能够反对一系列的游戏平台,以便在制作游戏时缩小对特定平台的定制和批改。 育碧面临的次要开发挑战之一是改善开发团队之间的工具共享,并通过新工具和流程进步生产力。 解决方案:育碧的源代码管制Perforce Helix Core成为育碧的次要源代码管制工具曾经超过六年了,被团队中的程序员和美术人员在大部分我的项目中应用。在育碧蒙特利尔工作室,有超过1,200名的开发人员应用Perforce Helix Core来贮存源代码和数字资产,包含图形和动画文件、建模、纹理以及声音和视频片段。 美术人员和建模师应用Helix可视化客户端(P4V)及其相干的图形工具来跟踪每天提交的最小更改。Perforce Helix Core图形工具插件(P4GT)让他们能够从Photoshop和3ds Max中轻松与Perforce Helix Core进行交互。 育碧技术架构师Beaufils说:“Perl、C#和C++中简略灵便的API使咱们可能将源代码治理性能集成到大部分的外部工具中,从而简化了美术人员和建模师的工作流程。” 通过应用Perforce Helix Core变更列表,能够在提交前对逻辑单元中的代码变更进行分组,程序员可能轻松抉择他们想要解决的内容,并且在独自的工作之间进行切换也更简略。“Perforce的变更列表十分受欢迎,因为它们让程序员可能依照他们认为适合的形式工作。” “此外,Perforce Helix Core的分支机制也很适宜在不同的指标游戏平台上共享雷同的代码,“Beaufils说。育碧将Helix Reporting System(P4Report)性能集成到了其生产工作流程中,简化了应用SQL查问、创立数字资产和代码报告的过程。“P4Report让我能轻松地将咱们的生产数据库与Perforce连贯,创立已实现工作的具体报告,”Beaufils补充道。 为了放慢开发速度,育碧团队还利用了Perforce代理(P4P),它为开发人员提供了他们最罕用的文件缓存,并使更多的用户可能在地方Perforce服务器上工作。 P4P还改良了分布式开发。近程工作室能够轻松拜访保留在各种Perforce服务器上的代码和其余数字资产,并且每个更改都会立刻在所有我的项目中反映进去。 “Perforce比它的前身VSS更好治理,咱们有1,200个用户,只须要一名专门的管理员,”Beaufils补充道。“Perforce易于备份,并且比VSS更稳固。与其余工具相比,它也更易于扩大。” 总结随着育碧的发展壮大,越来越多的开发人员将迁徙到Perforce Helix Core上。Beaufils示意:“咱们的团队在一直壮大。Perforce Helix Core的速度、可靠性和可扩展性对育碧来说至关重要,有超过1,000名用户依赖它。Perforce Helix Core曾经成为了存储每个人工作的外围且要害的工具。” 随着越来越多的外部工具被开发进去,育碧须要一个灵便的API来与源代码治理进行交互。Beaufils总结道:“应用Perforce Helix Core API将咱们的工具与Perforce Helix Core严密集成,生产力有了大幅晋升。 文章起源:https://bit.ly/43eQ7ly

July 10, 2023 · 1 min · jiezi

关于游戏开发:如何充分利用制作游戏原型的免费资产加速游戏开发

在一款电子游戏公布之前,它通常会经验屡次迭代,以确保其外围机制和性能都能失常运行。在这个过程中,一个重要局部是电子游戏原型,它有助于测试游戏的各个方面。 在往年的《Unity Gaming报告》中有一个乏味的发现,在投入任何特定性能或游戏机制前,工作室会应用预制的收费游戏资产来帮忙他们更快迭代。本篇文章将探讨如何将收费的游戏资产(例如Unity收费资产)作为您电子游戏的原型,以及数字资产管理工具Perforce Helix DAM如何为您提供帮忙。 游戏资产概述在议论游戏开发时,资产指的是能够增加到游戏中的任何组件,包含角色模型、对象、特效、环境,甚至是人工智能。个别是将许多独自的文件(例如独自的模型和纹理)合在一起应用,造成一个繁多的资产文件。什么是资产包? 资产包是游戏资产的汇合,设计人员能够应用这些资产来填充游戏世界。通常,资产包会有一个主题,用来确保一致性。 应用收费游戏资产的劣势电子游戏原型的制作可能十分耗时,这具体取决于测试的内容和机制。然而,应用预制的收费游戏资产能够简化这个过程。在电子游戏原型中应用预制的收费游戏资产,能够帮忙您: 让开发人员可能简略地向美术人员展现他的愿景概念;轻松、疾速地制作游戏各个方面的原型,例如关卡和机制;节约工夫,因为预制的资产无需创立每个环境对象(比方雾、岩石、树木、云、垃圾桶等);与从头开始创立新资产相比,编辑预制资产更容易;通过在实现愿景之前疾速制作原型,收费游戏资产能够节俭资金;帮忙新开发人员学习如何制作功能性游戏。应用收费游戏资产的弊病尽管应用预制的收费游戏资产对电子游戏原型制作是无益的,但在开始之前,您应该意识到这也存在一些弊病: 除非是一款简略的游戏,不然资产包很少领有足够的内容。因而,您无奈构建出整个游戏的原型; 如果应用来自多个不同包的预制资产,则原型可能不足一致性; 预制资产可能无奈齐全模仿预期的成果或机制。 如何将游戏资产用于电子游戏原型与其花工夫开发新的资产,不如应用预制的收费游戏资产,在预生产和晚期制作阶段提供可用的占位符。这样,您就能专一于欠缺游戏机制和物理成果,确保游戏不仅能运行,而且能给玩家带来乐趣。一旦机制和玩法被设计进去,占位符就能够被替换掉了。 在开发游戏的视觉和感觉局部时,预制的收费游戏资产能够让开发人员更分明地向团队美术和设计师表白他们对环境和角色的冀望。 数字资产管理工具如何提供帮忙像Perforce Helix DAM这样的数字资产管理工具能够通过资产回收,让制作电子游戏原型变得简略。 资产回收是指将雷同的游戏资产从一个游戏重复使用到下一个游戏的过程。这意味着,通过应用数字资产管理工具,您能够疾速查找并重复使用以前构建的游戏资产,来填充环境、测试游戏机制或游戏的其余方面,以进行原型的制作。 此外,随着您外部定制资产库的增长,它们能够通过Perforce Helix DAM进行集中存储、索引和轻松搜寻。而主动标记、高级过滤器和汇合分组等性能能够让资产跟踪更便捷。 领有一个现成的资产库可帮忙您在构建电子游戏原型时,节约工夫和金钱。 应用Perforce Helix DAM改良您的电子游戏原型Perforce Helix DAM建设在Perforce Helix Core之上,提供了一个基于Web的可视化UI,具备可视化界面和智能标记性能,让团队可能轻松查找、应用、存储、审查、从新调整用处和共享所有创意资产。 文章起源:https://bit.ly/3Jo9Icb

June 28, 2023 · 1 min · jiezi

关于游戏开发:实时渲染常用纹理技术总结视差映射

【USparkle专栏】如果你深怀绝技,爱“搞点钻研”,乐于分享也博采众长,咱们期待你的退出,让智慧的火花碰撞交错,让常识的传递生生不息! 一、概述视差映射(Parallax Mapping)是一种相似于法线贴图的纹理技术,它们都能显著加强模型/纹理外表细节并赋予其凹凸感,但法线贴图所带来的凹凸感不会随着视角扭转,也不会彼此阻挡。例如,如果你看实在的砖墙,在越垂直于墙面朝向的视角,你是看不到砖之间的缝隙的,砖墙的法线贴图永远不会显示这种类型的遮挡,因为它只会扭转法线来影响间接光照的后果。仅应用法线贴图、没有正确的遮挡关系的谬误成果 所以最好让凹凸感理论影响外表上每个像素的地位,咱们能够通过高度贴图来实现这个需要。举例 最简略的办法莫过于应用大量顶点,而后依据从上图中采样的高度值去偏移顶点地位坐标——位移映射(Displayment Mapping),能够失去下图中左图的成果(顶点密度为100*100)。然而这样的顶点数量并非实时渲染的游戏所能接受(或者说值得优化),而顶点数量过少的话就会呈现十分不平滑的块状景象,如下图中右图的成果(顶点密度为10*10)。于是就有聪慧的人想出了能够偏移顶点纹理坐标——视差映射(Parallax Mapping),这样咱们用一个Quad也能做出下图中左图的实在成果,先放上源码。不同顶点密度下位移映射技术的成果比照 二、原理那怎么偏移纹理坐标来做出凹凸感呢?咱们必须从察看到的景象动手: 假如咱们真有这样一个毛糙、凹凸不平的外表(比方通过密集顶点偏移后失去),那么当咱们以某一眼帘方向V看向外表时,咱们应该看到的是B点(即眼帘和高度图的交点)。但咱们后面也说了,咱们用的是一个Quad,所以理论看到的应该是A点。视差映射的作用就是偏移A处的纹理坐标到B处的纹理坐标,这样即使咱们看到的点是A,采样后果却是B处,从而模拟出高度差别,所以咱们要解决的就是如何在A处获取B处的纹理坐标。原理 仔细观察上图,其实A、B均在眼帘方向V所在的直线上,所以咱们的偏移方向就是归一化的眼帘方向,偏移量则为A处采样高度图的后果H(A),所以偏移向量为图中P¯,并且咱们须要沿着纹理坐标(UV)所在的立体偏移,所以偏移量为P¯在立体上的投影,那么理论向A点看到的是图中的H(P),这意味着咱们失去的其实是近似B点的后果。 因为咱们须要沿着纹理坐标(UV)所在的立体偏移,那么就有必要抉择切线空间(也就是把眼帘方向转到切线空间再去偏移纹理坐标),这样咱们也就不必放心模型有任何的旋转时偏移量不沿着UV立体上了。原理见法线贴图,这就是结尾强烈建议你先理解法线贴图的起因。 对任意一点的纹理坐标P、归一化的眼帘方向V、高度贴图采样后果h失去的偏移后果Padj: 除以Z重量是为了归一化:因为当眼帘越垂直于立体时,Z重量越大。然而当眼帘靠近平行于立体,Z重量很小,除以Z重量会使得偏移量过大,留神下图的缝隙处(应用的是最开始的高度贴图例图)。当眼帘越靠近平行于立体时偏移量越大 为了改善这个问题,咱们能够限度偏移量,使其永远不大于理论的高度(如下图中偏移量本应是灰色箭头线示意的向量,而限度后则是彩色箭头线示意的向量)。方程为Padj=P+h*Vxy(也就是不除以Z重量,计算速度也更快)。 能够和下面偏移量过大的后果做比照 然而因为眼帘方向的XY重量仍会随着眼帘方向越平行于立体而变大,所以偏移量仍会变大。 还有一个问题:在大多状况下,咱们下面的做法都能失去好的后果,然而当高度疾速变动时后果可能不尽如人意:失去的后果H(P)与B点(蓝点)相差甚远。 三、实现1. 视差映射咱们能够依据前一个Part所讲的基本原理来进行简略的尝试,这里咱们仍会应用法线贴图,因为我在总结法线贴图的文章中也说过,法线贴图常常依据高度贴图计算失去,但法线贴图影响的是法线,通过光照来体现凹凸细节,而视差映射是利用偏移纹理坐标来获取其余地位的采样后果来体现高度,所以二者配合就如同双剑合璧,威力大增。 float2 ParallaxMapping(float2 uv, half3 viewDir){ float height = tex2D(_HeightMap, uv).r * _HeightScale; float2 offset = 0;#if _OFFSETLIMIT //为了比照是否限度偏移量的成果 offset = viewDir.xy;#else offset = viewDir.xy / viewDir.z;#endif float2 p = offset * height; return uv - p;}half3 viewDirWS = normalize(UnityWorldSpaceViewDir(positionWS));float2 uv = i.uv.xy;#ifdef _PARALLAXMAPPING half3 viewDirTS = normalize(mul(viewDirWS, float3x3(i.T2W0.xyz, i.T2W1.xyz, i.T2W2.xyz))); uv = ParallaxMapping(uv, viewDirTS);#endif//而后用偏移后的纹理坐标采样各种贴图即可左图为仅应用法线贴图的成果,右图为退出视差映射的成果 ...

June 15, 2023 · 4 min · jiezi

关于游戏开发:独立游戏开发掌握成功的五大关键技巧

无论您是刚刚起步开发本人的第一款游戏,还是曾经制作了几款游戏,本篇文章中的5大独立游戏开发技巧都能够帮忙您更好地设计下一款游戏。 技巧一:设立明确的指标无论你对游戏有着什么样的概念,都应该将其还原到最根本的因素,而后答复这几个根底问题: 您想制作什么类型的游戏?例如:这是一个角色扮演游戏,还是一个平台游戏或约会模拟游戏?游戏的获胜条件是什么?例如:取得最高分,收集特定的物品,还是击败最终Boss?什么对您的游戏对玩家来说很乏味?例如:是帮忙他们获取积分的机制,是循环的游戏玩法,还是你在游戏世界中塑造的角色?一旦您有了这些问题的答案,就能够开始构思游戏机制和特点了。 通过花工夫清晰地构思和布局游戏,您能够更明确地定义构建游戏的每个外围所需的内容。 技巧二:定义工具集您能够在脑海中构建出十分独特且具备娱乐性的游戏,但如果没有适合的工具,您可能永远也无奈让其他人体验到你的游戏。因而,咱们倡议为游戏我的项目装备以下三种根本工具。 版本控制 版本控制是每个工作室都须要的一个工具,不论是独立游戏工作室还是3A游戏公司。因为它能够确保您辛勤劳动的成绩永远不会失落。此外,版本控制还可能跟踪游戏的代码、文件和数字资产的所有更改,有助于减速开发。 尽管有许多抉择,但Perforce Helix Core是公认的版本控制的行业标准,因为它能够随着您的我的项目和团队的壮大而无缝扩大,确保您在扩张的路线上不会呈现任何加速的状况。更重要的是,Perforce Helix Core能够在几分钟内对大文件进行版本控制,而其余版本控制软件可能须要几个小时。 我的项目待办事项和打算工具 游戏有许多不同的组成部分,可能放弃工作进度并按时实现工作对于游戏开发至关重要。 项目管理工具(如Hansoft)能够帮忙您更好地构建生产Sprint和游戏开发大赛(Game Jam),并使你的逾期工作失去合理安排。 此外,一个好的项目管理工具还应可能克服开发过程中可能遇到的任何挑战或阻碍,以便您能够放弃在正规上并实现目标。 游戏引擎 在形容游戏时,您须要首先做出的最重要决策之一是抉择什么游戏引擎来驱动它。 有许多不同的游戏引擎可供选择,空幻引擎(Unreal)和Unity是最受欢迎的两种。然而,你抉择哪个引擎取决于你想制作什么样的游戏。 例如:一些游戏引擎在3D方面体现更杰出(如空幻引擎),而另一些引擎在2D方面更现实(如Unity和Godot)。这齐全取决于您的想法。 数字内容创作工具 数字内容创作(DCC)工具能够帮忙创立游戏资产,包含模型和模型动画、环境,甚至游戏物理成果。有许多DCC工具可供选择,其中最受欢迎的包含: PhotoshopMayaBlender所有这些都能够与Perforce Helix Core和Helix DAM无缝集成。 数字资产管理工具 一旦您扩充团队规模,领有更多的美术人员和设计师,数字资产管理工具——比方Helix DAM——将是团队的价值连城。简略来说,数字资产管理工具就像美术人员和设计师的版本控制工具,它能够轻松地查找、应用、存储、审查、从新利用和共享所有的创意资产。这使您的团队可能简化创意工作流程并放慢审查过程。 技巧三:在晚期建设原型即便是最简略的游戏也会有一些须要一直迭代的游戏机制。然而,与其对整个游戏进行迭代,创立独自的游戏机制原型并一一欠缺它们会更无效。 这样做能让您确保要害的游戏机制合乎您的构想。更重要的是,通过专一于单个组件而不是整个游戏,您能够更轻松地辨认、区隔和解决问题,而后再将它们整合在一起。 构建游戏机制原型的最简略办法之一是应用收费的预制游戏资产,这些资产会帮忙您占住固定的地位。而且,应用预制资产让您能够不用再花工夫创立那些须要在前期替换的资产。 或者,如果您曾经有一系列可用的资产,您能够进行资产回收和重复使用。 除了帮忙您欠缺游戏机制,开发原型还能够让别人更好地了解您的游戏,包含它是什么、它是如何运作的以及获胜条件是什么。所有的这些都能帮忙您意识到本人游戏的乐趣所在,并可能激发进步可玩性的新思路。 技巧四:尽量简化当开发游戏的不同方面时(无论是游戏机制、视觉组件还是关卡设计),都要回顾一下游戏外围因素的形容。有雄心壮志是能够的,但不要将游戏设计得过于简单。 如果你想增加更多内容,要慢慢来,一次只退出一个元素,并从游戏的外围元素开始小规模尝试。一旦这些因素失去欠缺,你能够在此基础上进行扩大。如果某些内容不起作用,你至多晓得游戏最根本的外围因素和机制是无效的。 技巧五:放弃积极态度无论您是一个人还是一个团队,开发游戏都不是一件容易或简略的工作。无论筹备得如许充沛,您依然会遇到挑战和阻碍——但这些都没关系。 因为遇到的每一个阻碍都是您学习新技能或进步能力的机会。更理论地说,遇到这些阻碍将帮忙您理解在游戏开发中什么是无效的。 因而,当您因为游戏中颇具挑战性的局部感到丧气和困惑时,请试着放弃踊跃的态度。将注意力集中在让游戏失常运作的个性和机制上,并在此基础上进行改良。您的游戏可能和最后构想的不一样,但它依然可能十分杰出。 Perforce Helix Core如何帮忙独立游戏开发20大3A工作室中有19家信赖Perforce Helix Core,它能够依据您团队的需要进行扩大,并帮忙你轻松治理所有美术和游戏资产,将它们集中寄存在一个平安的地位,帮忙减速开发。此外,Perforce Helix Core还与一些最风行的游戏引擎集成,包含: 空幻引擎UnityLumberyardCryEngine更重要的是,您能够收费应用Perforce Helix Core,享受3A工作室应用的所有性能和个性,而且没有完结日期限度。只需几次点击,你就能够获取Perforce Helix Core,包含代码审查、Git反对、有限集成和客户端选项,最多可反对五个用户和20个工作区。 文章起源:https://bit.ly/3IGPMR9

May 31, 2023 · 1 min · jiezi

关于游戏开发:游戏中的动态阴影上

暗影对于进步游戏真实感十分重要,简略总结下游戏中的暗影实现。 先来看下暗影的组成部分,咱们能够将暗影大抵分成两个局部:全影(Umbra)和半影(Penumbra)。半影区域就是暗影的过渡区,也就是软暗影,有半影的暗影过渡时,视觉效果会好很多。暗影的组成部分 对于动态的场景,咱们能够抉择将暗影烘焙到Lightmap中,或者间接画在贴图上。这篇文章,咱们次要来介绍下动静暗影的相干技术,因为暗影是实时渲染中比拟重要的技术,实现的形式也十分多。本篇文章,尽量笼罩到各种罕用的暗影渲染技术。 一、简略的手绘假暗影在手游或者2D游戏中常常能看到这种做法,对于动静的角色,将暗影做成一张贴图,而后贴到脚下的高空上,尽管是很简略的模式,也能极大地加强真实感。繁难的暗影 二、立体投射暗影1. 立体投射暗影的计算立体投射暗影,就是将须要投射暗影的物体再渲染一次,投射到高空上,来产生暗影。依据立体的地位,咱们能够计算出一个投射的矩阵,间接将物体的坐标变换到立体上。 咱们先来看简略的状况,如下图右边所示将暗影投射到x轴上的状况,咱们在光源l的照耀下,须要从点v投射暗影到点p,依据三角形类似原理,咱们能够简略地失去: 相应地,咱们还能够算出z轴上的坐标为:pz =(lyvz-lzvy)/(ly-vy) ,将后果整顿成投影矩阵为: 这样能够通过矩阵计算投影坐标为:p=Mv 。 当初,咱们看上图中左边这种更加个别的状况,在这种状况下,咱们同样能够依据三角形类似原理,推导出投射暗影的坐标变换方程为: 从v点映射到p点: 令p=Mv推导后写成矩阵的模式: 如果是平行光源,计算的形式也是大致相同,并没有特地的难度。 在进行渲染时,咱们能够抉择先来渲染暗影,将投射暗影的物体,通过上述矩阵的变换到立体上,而后失去没有光照的彩色高空,此时同时把深度写入。而后再失常渲染高空和投射暗影的物体,为了使高空和暗影之间不会抵触,此时能够为深度值增加一些偏移。 增加偏移的形式能够间接通过图形API来增加,比方OpenGL中的glPolygonOffset和DirectX中的DepthBias设置。当然,你也能够抉择在绘制暗影时增加偏移,绘制高空时失常绘制,最终的后果都是雷同的。前面咱们讲到的各种暗影技术,常常会用到增加偏移(Bias)的技术。 另外一种平安的做法是,先失常渲染高空,而后渲染高空上的暗影,渲染暗影时将深度测试敞开,就不会产生深度抵触的问题。最初再渲染投射暗影的物体,这样能够避免暗影投射到非高空的区域。 如果承受暗影的高空不是一个无穷大的立体,则可能须要通过Stencil Buffer标记出须要承受暗影的局部,这样能够只让暗影产生在须要产生的立体上。 另外一个须要留神的,是如下图所示的状况,在进行计算时,须要保障投射暗影的物体位于光源和承受暗影的高空之间,否则就会呈现谬误的暗影成果。左边的情景下不应该绘制出暗影 总的来说,这种间接投射暗影的形式,简略间接,适宜间接投射在立体上的暗影。目前在手机游戏中,依然有宽泛的利用。 这种间接投射的暗影无奈实现软暗影成果。而且因为咱们是先渲染出的高空,再将影子的色彩乘以高空的色彩,这样其实并不是完全符合暗影产生的原理。 咱们晓得,暗影是因为高空没有受到光照而产生的,如果间接将高空的色彩乘以暗影,可能会产生不正确的暗影成果,特地是高空上有高光成果时。这类暗影叫做调制暗影(Modulated shadow),绝对一般的暗影,开销要小一些。游戏中的立体投射暗影 2. 借助Texture的投射暗影下面咱们说到的投射暗影,是间接渲染到被投射的立体上,这样咱们就无奈实现软暗影的成果,因而咱们这里将暗影先保留在一张贴图中,再从贴图中投射到立体上。这样还能够先失去暗影图,再渲染高空,失去正确的暗影成果。 和后面的间接投射相比,这种形式因为两头通过了一层转变,如果保留暗影的贴图分辨率很低,就可能会造成投射进去的后果有锯齿感。 这样,咱们就能够将贴图中的暗影先进行边缘含糊,再进行投射,就能够十分不便地失去软暗影成果。投射暗影实现的软暗影,先将暗影投射到贴图中,而后进行含糊,再投射至立体,实现软暗影成果 为了晋升运行效率,咱们还能够将多个物体的Texture打包到一个Shadow Atlas中,这样每个物体的投射暗影,占用整个大贴图的一部分。如果光源和投射暗影的物体都没有扭转,咱们甚至能够不必更新暗影,实现帧间暗影的复用。 三、Shadow Volume暗影Shadow Volume以前是一种十分风行的暗影实现计划,目前在游戏中也有肯定的利用,特地是前面咱们将要讲到的PerObject暗影,因而理解其原理是十分重要的。Shadow Volume须要依赖Stencil Buffer来进行实现。 1. Shadow VolumeShadow Volume就是从光源沿着模型边缘拉伸至有限远处加上前盖后盖造成的形态。能够说,位于Shadow Volume外部的物体,在渲染时具备暗影,在Shadow Volume内部的物体,在渲染时没有暗影。shadow volume 2. ZPass算法Shadow Volume暗影的原理就是取一条从视点到指标点的线,每次进入Shadow Volume,Stencil模板计数加一,每次来到计数减一,这样计数为0的局部就是无暗影的中央,计数不为0的中央就是有暗影的中央。 Shadow Volume的实现须要两个Pass,第一个Pass是标记具备暗影的区域,第二个Pass是进行暗影渲染。 第一个Pass,从视点渲染Shadow Volume几何体,屏幕中被Shadow Volume笼罩的区域,就是所有可能产生暗影的地位。咱们这里应用Stencil Buffer来标记出理论具备暗影的地位:开启Z-Test,设置Stencil模式为侧面局部+1,反面局部-1。这样渲染实现后,Stencil Buffer为0的局部就是无暗影的中央,Stencil Buffer中不为0的局部就是有暗影的中央。ZPass的原理 第二个Pass,同样也是渲染Shadow Volume的几何体,不过此时间接敞开深度测试,应用模板测试,间接在上一步中标记出的地位渲染出暗影。 3. Z-Fail算法ZPass算法有个缺点,当摄影机在Shadow Volume中的时候,就会产生谬误的后果。当摄影机位于Shadow Volume中时,ZPass标记暗影区域生效 所以就有了Z-Fail的算法,Z-Fail算法和ZPass算法相似,只是改成从物体反面计数,在Z-Test fail的几何体局部,在进入Shdow Volume时计数-1,来到时计数+1,这样就能够躲避这个缺点。应用Z-Fail算法,标记处正确的暗影地位 不过一般来说Z-Fail算法广泛要比ZPass算法慢,因为从反面渲染Shadow Volume,通常会笼罩更多的像素点。 因而在实践中,咱们能够先做一个摄影机是否位于Shadow Volume中的判断,来决定应用ZPass或者是Z-Fail算法来进行标记暗影区域。 ...

May 4, 2023 · 3 min · jiezi

关于游戏开发:UE5新功能StateTree源码解析

StateTree 是一种UE5中新增的通用分层状态机,其组合了行为树中的 选择器(Selectors) 与状态机中的 状态(States) 和 过渡(Transitions) 。用户能够创立十分高效、放弃灵便且颠三倒四的逻辑。StateTree蕴含以树结构布局的状态。状态抉择能够在树中的任意地位触发。相比行为树,其组织形式更为自在,灵便,能够在任意两个状态之间过渡。相比状态机,其树状的分层构造更加清晰和高效。这样一个非常好用乏味的新货色天然未免让人想进入源码一探到底。次要文件的组织StateTree的次要逻辑在UE5源码中大抵分为如下几个文件:StateTree.h 次要蕴含UStateTree类,作为StateTree的定义StateTreeComponent.h 次要蕴含UStateTreeComponent 类 作为在Actor上运行指定StateTree的组件StateTreeExecutionContext.h 次要蕴含 FStateTreeExecutionContext 作为更新和拜访 StateTree的helper类StateTree的更新,状态切换和转换逻辑根本都在这个外面其余的还有诸如StateTree中条件,工作,评估器的基类,用于编辑器资源创立的类等,在此不多加叙述 执行流程开始进入游戏后,对于启用了UStateTreeComponent组件的Actor,在组件的BeginPlay()期间,执行FStateTreeExecutionContext的Start()函数。开启StateTree的执行,该函数次要执行初始化和状态抉择,一开始的状态抉择从根部开始,后续会具体讲到状态抉择的逻辑。以下为Start()函数增加了具体的正文,能够帮忙各位了解。// 开始状态树的执行,返回状态执行的状态EStateTreeRunStatus FStateTreeExecutionContext::Start(){ // 记录函数执行工夫CSV_SCOPED_TIMING_STAT_EXCLUSIVE(StateTree_Start);// 如果上下文没有被正确初始化,则返回失败并记录日志if (!IsValid()){ STATETREE_LOG(Warning, TEXT("%s: StateTree context is not initialized properly ('%s' using StateTree '%s')"), ANSI_TO_TCHAR(__FUNCTION__), *GetNameSafe(&Owner), *GetFullNameSafe(&StateTree)); return EStateTreeRunStatus::Failed;}// 如果实例数据有效,则初始化if (!InstanceData.IsValid()){ const FStateTreeActiveStates Empty; UpdateInstanceData(Empty, Empty); if (!InstanceData.IsValid()) { STATETREE_LOG(Warning, TEXT("%s: Failed to initialize instance data on '%s' using StateTree '%s'. Try to recompile the StateTree asset."), ANSI_TO_TCHAR(__FUNCTION__), *GetNameSafe(&Owner), *GetFullNameSafe(&StateTree)); return EStateTreeRunStatus::Failed; }}// 获取共享实例数据const TSharedPtr<FStateTreeInstanceData> SharedInstanceData = StateTree.GetSharedInstanceData();check(SharedInstanceData.IsValid());// 获取执行状态,并记录为指针以便稍后从新获取FStateTreeExecutionState* Exec = &GetExecState(); // Using pointer as we will need to reacquire the exec later.// 如果之前有状态正在运行,则进行if (Exec->TreeRunStatus == EStateTreeRunStatus::Running){ Stop();}// 调用所有评估器的TreeStart办法StartEvaluators();// 第一次调用TickEvaluatorsTickEvaluators(0.0f);// 初始化为未设置状态Exec->TreeRunStatus = EStateTreeRunStatus::Running;Exec->ActiveStates.Reset();Exec->LastTickStatus = EStateTreeRunStatus::Unset;static const FStateTreeStateHandle RootState = FStateTreeStateHandle(0);// 抉择状态,从RootState开始FStateTreeActiveStates NextActiveStates;if (SelectState(*SharedInstanceData.Get(), RootState, NextActiveStates)){ if (NextActiveStates.Last() == FStateTreeStateHandle::Succeeded || NextActiveStates.Last() == FStateTreeStateHandle::Failed) { // 如果抉择的是终止状态,阐明状态执行实现 // 记录日志并更改状态 STATETREE_LOG(Warning, TEXT("%s: Tree %s at StateTree start on '%s' using StateTree '%s'."), ANSI_TO_TCHAR(__FUNCTION__), NextActiveStates.Last() == FStateTreeStateHandle::Succeeded ? TEXT("succeeded") : TEXT("failed"), *GetNameSafe(&Owner), *GetFullNameSafe(&StateTree)); Exec->TreeRunStatus = NextActiveStates.Last() == FStateTreeStateHandle::Succeeded ? EStateTreeRunStatus::Succeeded : EStateTreeRunStatus::Failed; } else { // 如果不是终止状态,进入抉择的状态 // Enter state能够失败或胜利,并且与Tick中的矗立雷同 FStateTreeTransitionResult Transition; Transition.TargetState = RootState; Transition.CurrentActiveStates = Exec->ActiveStates; Transition.CurrentRunStatus = Exec->LastTickStatus; Transition.NextActiveStates = NextActiveStates; // EnterState将更新Exec.ActiveStates const EStateTreeRunStatus LastTickStatus = EnterState(Transition); // 须要从新获取执行状态,因为EnterState可能会更改调配 Exec = &GetExecState(); Exec->LastTickStatus = LastTickStatus; // 如果状态已实现,则在此时报告 if (Exec->LastTickStatus != EStateTreeRunStatus::Running) { StateCompleted(); } }}// 如果没有沉闷状态,则返回失败,这应该不会产生if (Exec->ActiveStates.IsEmpty()){ STATETREE_LOG(Error, TEXT("%s: Failed to select initial state on '%s' using StateTree '%s'. This should not happen, check that the StateTree logic can always select a state at start."), ANSI_TO_TCHAR(__FUNCTION__), *GetNameSafe(&Owner), *GetFullNameSafe(&StateTree)); Exec->TreeRunStatus = EStateTreeRunStatus::Failed;}// 返回状态执行的状态return Exec->TreeRunStatus;}更新StateTree的更新逻辑次要在FStateTreeExecutionContext 的Tick()函数里进行。该函数次要负责更新评估期和tick事件,依据条件触发状态转换等,以下为代码增加了正文帮忙了解。EStateTreeRunStatus FStateTreeExecutionContext::Tick(const float DeltaTime){ ...

April 22, 2023 · 8 min · jiezi

关于游戏开发:爆肝200小时总结出的-Creator-3x-入门修炼指南全免费

大家好,我是晓衡! 为了写这篇文章,给反对公众号的读者们一个交代,我筹备了200+小时,公众号断更11天。我决定,不再抉择回避,不想再坑骗本人了。 2023新年动工,不到十天工夫,接踵而至有小伙伴找到晓衡,请求举荐一些 Cocos Creator 3.x 的学习办法或入门课程,而且课程最好是付费的。 承蒙老铁们的信赖,让我倍受打动,但又让我感到异样难堪! 因为有好多货色,我也不会。 还有就是,偌大的一个 Cocos 社区,据我所理解的付费课程,却是沧海一粟。 而我实在体验过的 Creator 付费课程,那是我本人曾在 2020 年时搞的 Creator 修仙训练营了。遗憾的是,那是基于 Creator 2.x 的,Creator 3.x 对晓衡来说,我也只能算是个老手。 付费的课程没有,但 Cocos 社区收费的教程,我倒是晓得不少: 放空老师的《快上车》、《3D打飞机》麒麟子的《方块学生》Blake老师的《幽灵射手—源码实战剖析》sli97的《Cramped Room Of Death》巧哥的《3D仰视角割草游戏》......不过有小伙伴示意,下面的视频有些也尝试学习过,像引擎装置、下载、换皮......倒是学会了好几遍。 然而,要本人去实现一个性能时,总是在各种小问题上,就被卡住了。 学习材料找了不少,但大佬们分享的游戏源码、技术文章,依然是看不懂、学不会......只能在大佬背后喊666! 01下面这些问题,晓衡自问,本人也何尝不是如此? 自从 2020 年开始,我从一名程序员转型自媒体+经营,尽管始终社区中分享 Cocos Creator 相干的教程、案例、资源,但我集体的游戏开发程度,基本上还停留在 Creator 2.x 的时代。 随着 Creator 3.x 的越发遍及,越来越多的 3D 相干的游戏、利用、教程、资源等需要一直增涨......我那点技术水平,到底还能帮忙到大家些什么呢? 为此,晓衡再三思量,翻遍了B站上成体系的 Creator 3.x 视频教程,齐全以初学者的姿势,去亲自体验、观摩、学习...惊喜地发掘出一条适宜 Creator 3.x 初学者的学习门路和修炼办法。 整顿出 5 套收费视频教程,来源于 B 站。 请留神,晓衡这里提供的是一条学习门路!需按从上到下的程序顺次学习。 选出的这5套视频教程,我是从内容的宽度、深度、课程节奏感,并联合多年来理解到的老手常见问题,等诸多方面去感触和评估。 遵循由浅入深,循序渐进准则,只有你对游戏开发感兴趣,会应用计算机软件,能够大胆撒手去尝试。 可能有人会尖叫,要学5门课程啊?入门教程找一个适宜本人段位的,不行吗?为什么要搞这么多呢? 起初我也是这么想的,但正本文结尾所说,一些老铁们遇到的状况,以及晓衡这两年来的切身感受。 ...

March 2, 2023 · 2 min · jiezi

关于游戏开发:文章转载-紫龙上海CTO王琦我们对游戏工业化的探索

2月13日,2022年度中国游戏产业年会在广州召开。本次大会以“奋进十年路,再搏新征程”为主题,并围绕游戏出海、国风游戏、游戏工业化等话题,深入开展了16场分论坛探讨。 当天下午,在以“国内察看——游戏制作工业化降级趋势主题论坛”上,紫龙游戏上海研发核心首席技术官王琦,现场发表题为《咱们对工业化的摸索——抛砖引玉》的主题演讲。 以下是演讲实录:王琦:咱们其实是一支十分强的团队,从PC时代始终开发到当初,核心成员始终在一起单干。这么长时间以来,咱们积攒下了一些本人对于工业化方面的摸索和实际。首先,咱们团队的理念是缺点驱动——当产生了一个问题,咱们会尝试去了解这个问题如何产生的,而后再去思考如何解决这个问题。那么面向工业化:工业化到底是要解决什么问题呢? 在咱们的视角里,首先是工作后果的交付一致性较差。比方做一个角色模型,不同的美术工作人员产出的面数差别、或者是贴图材质差别,都代表了它的一致性比拟差。 另一方面,工业化的背面其实是作坊化,这会导致工作过程的一致性较差,从而带来产出效率较低,以及信息传递的缺失、低效和失真。比方策动向美术传递信息的时候,如果产生了一些失真,使得有些信息没有传递到,就会导致最初产出后果肯定会产生重复和迭代,这对于老本来说都是节约。 同时在传统作坊工作形式下,流程通常来说很难放弃十分高的一致性。不同工作人员工艺的不统一,肯定会导致最终出现的后果呈现差别,并带来品质方面的错落。 基于上述内容,咱们其实很难去定义,开发过程中某一个工作是否被实现,以及它被实现的界定准则和参数到底是什么。所以会导致咱们无奈形容这个工作应该在什么时候实现,以及实现后还会不会迭代。 因而,开发过程的治理信息会变得十分凌乱,同时导致开发过程的可控性变得极差,最终后果就是工夫、老本失控,交付品质不现实。 而咱们视角下的游戏开发工业化由哪些方面形成?第一,是要保障工作过程和后果的正确性和一致性;第二,在这个根底之上须要保障工作过程和后果输入的效率。 为了保障一致性,咱们有两个方面:第一是开发过程治理标准,相比传统的软件开发大家应该比拟相熟,毕竟传统开发会十分重视项目管理机制和规定。第二个是针对游戏行业自身,咱们会存在具体的工件制作工业流程的标准。在局部标准的状况下,咱们是可能靠人力去保障它的一致性。 通常来讲,标准定得越细,查看得越严格的话,工作效率整体会降落。这就须要靠一些开发过程治理的数据化和工具链,以及制作工艺流程环境下的数据化和工具,来使效率失去一个正当的晋升。 这里咱们合成一下开发过程治理标准。首先,它是以通常意义上的软件我的项目过程治理为根底。像咱们以前做传统软件,也会用到一些项目管理的软件,比如说微软的Project这些货色。 第二,最开始要解决的一个根本问题,是信息流和决策流的治理。整个开发过程的治理,它的人员组织构造应该是会造成一个树状构造,就像军队指挥打仗一样。 如果没有造成一个很好的树状构造,你的信息流不是在树下面通过根节点能力流向叶子节点的话,比方在执行环节,策动会间接和执行层面的程序和美术沟通。这个有可能会导致你的Leader不晓得,因而他们对于这些信息是否和原有体系自洽,并没有做出判断。而且在他们不晓得的状况下,后续QA流程必定也被断开的,这都是问题,所以咱们须要把信息流和决策流的治理做好。 第三,开发过程治理标准和工业化的关系,后面其实曾经提到了。开发标准其实并不依赖工业化存在,在咱们没有波及到工业化概念的时候,就曾经在用简略的标准在操作。同时,工业化肯定会带来一些流程线的制作老本,针对这些新的流程建设,咱们须要对原有的开发标准进行一些适配和调整。 再者,咱们即便在有布局的参加状况下,其实随着我的项目过程的倒退,以及同一套工业化流程线在不同我的项目中的利用,具体的开发标准其实还须要做调整。这里特地须要去防止:一般来说,咱们执行开发标准的具体执行人都是PM团队,但PM团队常常有时候会有一些工作导向的偏向。就是说标准里规定了我有abc,下面流程做了那就算没责任了,尽到了本人任务。 但事实上,咱们其实须要互相灌输:做这个标准、做某一个条例的指标是什么?它是为了实现什么样的目标?那在具体的某个环境中,如果没有达成相应的目标,咱们是不是应该去剖析一下,到底是执行环境出了问题还是说标准有问题。 而后第四个,就是开发过程治理须要数据化。数据化其实是工业化的根底,如果咱们不能用数据化的形式去形容整个开发过程,就没有方法以数据化的形式去定义每个工作,以及每个工作的分类是什么。 在咱们的工具外面其实给每一个工作打了很多标签,它有性能领域方面的标签,比方是某某零碎的、是属于战斗还是属于技能的;还有一个就是它在岗位上的标签,因为咱们做某个性能领域的工作常常会流转很多岗位,而这个工作到底是属于哪个岗位,就须要把整个开发过程元数据化,去定义它。 最初一项,就是咱们如何保障下面这些来执行。其实咱们会在开发标准下来定义立项的各个阶段,每一个版本要达成的指标是什么、它要验证什么?在达成了某个指标后能力持续往下走。这其实是为了在后期尽量减少老本,解决一些未知问题,前面会更具体地去解释这个问题。 那工业化和流水线之间的关系,在咱们的观点外面,工业化的实质就是建设流水线,既然是建设流水线,就会波及到一个老本问题,一般来讲老本都是很高的。所以估算比拟小的我的项目,那就要须要问问本人值不值得动员它来做事。 既然它老本高,改变它的时候老本也高,那它就肯定会有某种局限性,即只适应于为了咱们这个指标特地定制的流水线。所以,流水线模式和游戏翻新实际上是存在人造矛盾的。能够通过咱们我的项目过程治理标准里对于每个版本的要求,去缓解这样一个矛盾。 这里谈到咱们搭建流水线的过程,提到了一个叫做Alpha0阶段。Alpha0阶段其实是一个版本,这个版本之前有两个重要的版本阶段。 第一个版本阶段,是所谓的外围游戏验证阶段。在这个阶段中,咱们个别很少有美术来参加,基本上尽量采纳白模和既有的美术资源来进行外围游戏性和3C的验证。这个阶段过了当前,咱们认为达成了验证指标,就会进入第二个阶段。 第二个阶段,是美术的原型阶段,咱们须要确定美术格调,去给美术的每一种工件制订它的规范。基于规范,就会阐明这个美术工件的复杂度,标记着它的生产成本。可能掂量游戏中对于这种复杂度资产须要的量是多少,也就是美术内容格调的制订、定标和定量。这几件事是进入Alpha0阶段的前提。 那在Alpha0阶段中要解决的问题,第一是为形成游戏的每个“整机”制订最终要求和标准、以及定量,而后再为每个“整机”制订工序环节和每个环节上的查看标准,并制订是哪个岗位的人来做这个事件。这个问题,前面会再具体解释。 这里拿了几个咱们外部工件制作的图解,给大家奉献例子。 在UI零碎制作下面,首先咱们会画一张流程图,来定义对于制作某一个美术或内容的资产,咱们要把它合成为哪些步骤?其实这个步骤曾经合成得十分细了。蓝色方框的局部最终会体现在你的工单零碎里,会变成某一个人身上的一个Task,会去定到人、定到工夫、定到时长。灰色的局部基本上属于一些非工作性的环节,比方某种沟通、或者某种会议。这个图上曾经蕴含了制作流程中很多check的步骤,以及一些迭代、整合、调试的步骤。 另一边和这个流程图配套的,就是咱们针对每一个环节的标准,这个标准也是听从于咱们缺点驱动的开发。当咱们发现某个中央呈现问题的时候,须要去为它拟定一条新标准,增加到原有的体系当中。当咱们一直地去做这种事件,就会使得你的标准越来越欠缺。比方UI规定了字体应该怎么用,你的按钮控件应用的一些规定是什么。 下一个就是机甲部件制作,要经验一个什么样的流程。咱们的标准其实还蕴含要应用哪些工具,因为咱们针对工具有做很多二次开发,因而不能胡乱地遵循你的爱好安顿工具装置,必须依照咱们本人规定的这些货色。包含工具环境要用什么,机甲的一些比例范畴,面数等,都是在这个标准外面。 这是场景相干的制作标准,这个只是形容纯正的美术方面场景,因为场景利用到游戏当中,还会变成其余的内容,这个标准在前面大家会看到。 这个是场景做完了后,把它利用到游戏当中的策动外部流转。蕴含关卡策动、文案策动,一些主策动验收,数值策动填充数值等过程的流转,以及他们一条条迭代演绎进去的一些步骤和规定。 而后是开发过程治理的数据化和工具链,咱们大略应用的项目管理是Jira或Project。每个工具都有他本人的专长,比方,Jira比拟适宜每个人只关注本人能看到的工作条目;Project比拟适宜让整个我的项目的管理者可能看到工作和工作之间的依赖关系、工夫等。 版本治理咱们用的是Perforce,也是在做过重复调研后,最终选定的Perforce。它最吸引咱们的一个性能是和Swarm的联动,迁入当前能够主动做review环节的联动,等一会我会具体的介绍。 CI环节,咱们用Jenkins和一些自研资源查看工具。还有一个就是咱们本人开发的音讯告诉软件,叫DevMsg,这个货色是为了解决什么问题呢?就是咱们常常会遇到的在我的项目中信息失落。 比如说我开了个分支,要求前面针对某个版本的迁入必须在另外一分支上做,这个时候往往就有美术说“我不晓得”、“你没告诉我”,他也不看QQ,你也没方法专门找人去盯着他、问他确认。最好的形式就做个软件,把这个Messagebox以模态窗口的形式弹在他脸上,他不点确认这个窗口永远不会隐没,彻底消除他们说任何“我不晓得”的状况。 **这个是Jira和Project的互通。咱们整个开发流程的终点,是每个版本的一个Excel。在这个Excel外面去定义了这个版本的Featurelist,而后各个组长会在Featurelist上进行工作拆分。只拆分这个工作节、某个Feature要分解成哪几个工作条目,不安顿工夫、也不安顿人,而后这个Excel会被一个工具导成一个出最后版本的Project的杆状图。**在杆状图上,咱们可能非常明显地得悉一个工作在工夫上的关系。当咱们安顿了人之后,我发现哪个中央成为长板,须要把它调整一下,负责人就把工作调到其他人身上去,使得每一个资源的阶梯化应用十分清晰明了。从Leader的角度来看,咱们整个工作的b型开发流程和故事开发流程会十分的清晰。**做完这一步当前,咱们用本人做的Jira拓展工具导入到Jira里上,会造成每个人身上挂的一些工作条目。这些人每天实现工作之后,就把对应的Jira上的工单设置为已实现。咱们每天会再做一次同步回Project,杆状图的实现状态也会跟着更新。**与此同时,咱们每天会在Jira上做一个主动报表,把所有类型的工作、每一个大的性能分类工作的实现状况和实现比例,以及迁延状况统计进去发给所有的Leader,让公司领导也能很明确的理解。同时咱们也会把同步好了的杆状图收回来,可能以一个比拟有效率的形式去理解以后我的项目进度。** 这个是Perforce和Swarm的联动。当咱们在Perforce下来迁入一个资源或代码的时候,咱们有一些强制性的要求。就咱们通过二级开发Perforce去规定迁入的时候必须提供哪些信息,其中一个十分重要的信息就是:你针对的Jira工单的工单号是什么?一般来说,开发人员是没有方法间接去迁入的,他只能提交一个review的request,会在Swarm下来丢给你的Leader。 一般来说,这丢给Swarm之后会触发咱们一个制订的CI流程,它会依据你的工单的类型,这个就波及到咱们后面那个元素的作用了。咱们得晓得这个工单是为了什么目标、它到底会波及哪些资源、咱们要做哪些查看,以及依据你迁入的资源在咱们工程目录外面的匹配规定,它到底属于哪种资源。去做相应的查看后,咱们会把查看后果贴到那个Swarm。 当你的Leader去看的时候,他首先看一下主动查看的后果,有没有一些不适合,或者尽管不太适合然而能够忍耐的局部。这个中央和咱们代码编译过程会有warning和error的局部一样,然而在某一个比拟正式的版本分支下面,这些就曾经迁不进去了,而后你的Leader看完当前会决定要打回或者是承受。通过这种形式,咱们可能最大水平上的去保障每一个工作环境上的人提交的货色是非法。 这个是DevMsg产品。 这是制作工艺流程中,基本上是美术生产过程的数据化和工具链,咱们要谈到它的特殊性和通用性。 特殊性,意味着每一个我的项目的美术规格都有差别,格调也不一样,有的写实、有的是卡通。游戏类型不同,跨平台的估算调配也不一样。咱们可能有的游戏须要在特效上多调配,它容许每一帧所耗费特效的GPU工夫会多一点,有的是整个场景的植被渲染要多一点。这个货色都是依据咱们中台在Alpha0阶段去做的一些掂量,和项目组做一些沟通后去重复测试,批下来的规范。很多我的项目也存在自定义的美术资源,特地是一些预制件。在别的游戏中不存在,只在他这里存在,也有本人的一些标准。 有特殊性,它也有通用性。通用性是为了保障,咱们不能独自为了一个我的项目开发一整套工具链和流水线,老本都太高了。在通用性上,咱们个别是通过把整个性能和要落地的过程切分很多档次。 首先,咱们会存在跨我的项目的数据规定框架和工具链框架,落实到具体我的项目中,咱们会把数据规定框架进行一些配置,就是数据驱动的规定模板。比方咱们每个我的项目都会去审查某个资产的面数,面数的值由项目组本人来治理。还有工具的组件化部署,你的整个工具链必须是要思考好组件化,不能间接来个“全家桶”,你得容许我的项目去抉择某些组建来部署。这个中央咱们也做了一些像腾讯的共事们做的那些部署框架之类的,有些环境上面是咱们把部署好的环境一股脑全迁到珍藏库外面,其余工作人员间接盖下来就是最新的,这样的话咱们更新的时候也很不便。 前面会举两个例子来阐明,美术方面的数据化和工具链。一个是美术资源解决流程,就是美术资源进口资源的导入;还有一个是材质的验证。 这个是美术资产的导入。首先,美术资产生产完了当前,第一件事是要导出。在导出的时候,就会利用咱们做的二次开发的一些工具,来查看这个资产。比方一些命名规定、层级构造,顶点数据有没有废数据,在一些变数参数下面有没有合乎咱们的要求……裸资源导出了当前,第二步就是导入。 在那个裸资源导入引擎的时候,咱们在引擎外面做的二次开发会对资源进行二次解决。比方贴图的跨平台压缩设置,针对不同的规格品质要求的包的贴图的设置。比方《钢岚》我的项目,他机器人咱们导进来的裸资源其实是一套的机甲部件,在满足肯定的那个命名规定的前提下,咱们会让程序那个主动去做一些预制件的生成。就间接把它组装成最初程序会调用的一些货色。 而后这些资源进入了零碎之后,比方咱们在场景外面把这些资源放上去了后,咱们会做一些profiling的工具来去做初步验证,这些货色组合在一起是否符合要求,这些profiling工具前面咱们会再具体介绍一下。 引擎当中的生产过程实现了之后,咱们上传的时候就会去做CI检测,以及保障进入source control资源的合法性,这个后面曾经说过了。 这里再谈材质一致性的问题。咱们以前会遇到的一个问题是什么呢?比方在一个游戏当中,两个不同的场景可能一个是晴天,一个是阴天,不同的美术、哪怕是同一个美术有时候也会犯这样的谬误:他为了达成最初美术画面的出现成果,有的中央是靠调建筑物的材质和色彩来达成,有的中央是靠调光的达成……就十分的不统一。当你想去做一些全局的前期解决时,这件事件就立马凸显呈现。而后你想返过来搞,老本又很高。 所以在解决这种问题的时候,一个前提是要去搞清楚最初画面像素的色彩,在光照着色渲染下面到底分哪几个步骤,每个步骤的奉献到底是什么?以此来针对每个步骤进行计算机制的对齐,以及最终奉献后果的对齐。 比方PBR的渲染,咱们首先要确定的是物理晚期模型。再就是光照环境的一个确认HDRI天光的拍摄和改正,物理光照和曝光,而后再是GI烘焙。还有一个GroundTruth是咱们本人定义的,他的作用是什么呢?比方你要验证材质模型,必须要有个规范场景,这个规范光照场景咱们如何保障正确呢?咱们首先把它渲一遍,而后咱们再用本人光栅化的渲染形式再把它渲一遍,再比拟每一个局部的色彩差别是否在可接受程度内。如果ok,阐明咱们这个光栅化的货色曾经达到了指标要求,当然这个货色只适宜做PBR渲染。 ...

February 27, 2023 · 1 min · jiezi

关于游戏开发:虚幻引擎UE4如何实现打包后播放片头其实超简单

空幻引擎作为一款全球性的3D实时开发工具,不仅在游戏行业,其在修建、影视、医疗等行业也被宽泛应用。作为开发人员,有时开发的UE空幻引擎我的项目比拟大,开始运行我的项目时须要期待较长的工夫,还有些公司要求增加片头对公司先进行肯定的介绍才开始进入我的项目,这时咱们就能够增加片头。那么如何在UE4实现打包后播放片头?其实很简略! UE4打包后播放片头实现办法筹备H.264编码的MP4片头文件。新建文件夹。在工程文件夹Content中新建一个文件夹命名为Movies,将片头视频文件放在此门路下,留神文件夹命名肯定要是Movies,这样打包后能力胜利。(项目名称\Content\Movies)在编辑器中的操作 勾选“期待影片实现”,则会播放完片头才会进入我的项目。 勾选“可跳过影片”,则我的项目资源加载实现后主动跳过影片进入我的项目。 提醒:能够新建一个空我的项目。按以上设置好后,点击“独立过程游戏”测试片头是否能够失常播放哦! 怎么样,是不是很简略,学到就赶快用起来吧! 3DCAT实时云渲染助力畅享元宇宙2022年4月Epic官网发表,空幻引擎5曾经正式推出。绝对于空幻引擎4来说,空幻引擎5更多的是面向于影视行业,VR行业等,置信Epic也是嗅到了元宇宙这股热潮,十分看好元宇宙的发展前景。 3DCAT元宇宙实时渲染云基于云计算理念,将XR利用部署在云端运行,云端资源进行图形数据的实时计算和输入,并把运行后果用“流(Streaming)”的形式推送到终端进行出现,终端用户可随时随地交互式拜访各种XR利用,无论何时何地,均可突破时空枷锁,畅享元宇宙的世界。 当初注册立赠79分钟实时云渲染收费体验!点击注册 本文《空幻引擎UE4如何实现打包后播放片头?其实超简略!》内容由3DCAT实时云渲染解决方案提供商整顿公布,如需转载,请注明出处及链接:https://www.3dcat.live/share/...

February 17, 2023 · 1 min · jiezi

关于游戏开发:Y-分钟速成-GDScript

源代码下载: learngdscript-cn.gd GDScript 是一种动静类型的脚本语言,专门为收费开源游戏引擎 Godot 制作。 GDScript 的语法相似 Python。 它的次要长处是易于应用和与引擎深度集成。 它非常适合游戏开发。 根底# 单行正文应用 # 号书写。""" 多行 正文 是 应用 文档字符串(docstring) 书写。"""# 脚本文件自身默认是一个类,文件名为类名,您也能够为其定义其余名称。class_name MyClass# 继承extends Node2D# 成员变量var x = 8 # 整型var y = 1.2 # 浮点型var b = true # 布尔型var s = "Hello World!" # 字符串var a = [1, false, "brown fox"] # 数组(Array) - 相似于 Python 的列表(list), # 它能够同时保留不同类型的变量。var d = { "key" : "value", 42 : true} # 字典蕴含键值对。var p_arr = PoolStringArray(["Hi", "there", "!"]) # 池数组只能蕴含繁多类型。 # 放入其余类型会被转换为指标类型# 内置向量类型:var v2 = Vector2(1, 2)var v3 = Vector3(1, 2, 3)# 常量const ANSWER_TO_EVERYTHING = 42const BREAKFAST = "Spam and eggs!"# 枚举enum { ZERO, ONE , TWO, THREE }enum NamedEnum { ONE = 1, TWO, THREE }# 导出的变量将在查看器中可见。export(int) var ageexport(float) var heightexport var person_name = "Bob" # 如果设置了默认值,则不须要类型注解。# 函数func foo(): pass # pass 关键字是未书写的代码的占位符func add(first, second): return first + second# 打印值func printing(): print("GDScript ", "几乎", "棒呆了") prints("这", "些", "字", "被", "空", "格", "分", "割") printt("这", "些", "字", "被", "制", "表", "符", "分", "割") printraw("这句话将被打印到零碎控制台。")# 数学func doing_math(): var first = 8 var second = 4 print(first + second) # 12 print(first - second) # 4 print(first * second) # 32 print(first / second) # 2 print(first % second) # 0 # 还有 +=, -=, *=, /=, %= 等操作符,但并没有 ++ 和 -- . print(pow(first, 2)) # 64 print(sqrt(second)) # 2 printt(PI, TAU, INF, NAN) # 内置常量# 控制流func control_flow(): x = 8 y = 2 # y 最后被设为一个浮点数, # 但咱们能够利用语言提供的动静类型能力将它的类型变为整型! if x < y: print("x 小于 y") elif x > y: print("x 大于 y") else: print("x 等于 y") var a = true var b = false var c = false if a and b or not c: # 你也能够用 &&, || 和 ! print("看到这句阐明下面的条件判断为真!") for i in range(20): # GDScript 有相似 Python 的 range 函数 print(i) # 所以这句将打印从 0 到 19 的数字 for i in 20: # 与 Python 略有不同的是,你能够间接用一个整型数开始循环 print(i) # 所以这行代码也将打印从 0 到 19 的数字 for i in ["two", 3, 1.0]: # 遍历数组 print(i) while x > y: printt(x, y) y += 1 x = 2 y = 10 while x < y: x += 1 if x == 6: continue # continue 语句使 x 等于 6 时,程序跳过这次循环前面的代码,不会打印 6。 prints("x 等于:", x) if x == 7: break # 循环将在 x 等于 7 处跳出,后续所有循环不再执行,因而不会打印 8、9 和 10 match x: 1: print("match 很像其余语言中的 switch.") 2: print("然而,您不须要在每个值之前写一个 case 关键字。") 3: print("此外,每种状况都会默认跳出。") break # 谬误!不要在 match 里用 break 语句! 4: print("如果您须要跳过后续代码,这里也应用 continue 关键字。") continue _: print("下划线分支,在其余分支都不满足时,在这里书写默认的逻辑。") # 三元运算符 (写在一行的 if-else 语句) prints("x 是", "正值" if x >= 0 else "负值")# 类型转换func casting_examples(): var i = 42 var f = float(42) # 应用变量构造函数强制转换 var b = i as bool # 或应用 as 关键字# 重载函数# 通常,咱们只会重载以下划线结尾的内置函数,# 但实际上您能够重载简直任何函数。# _init 在对象初始化时被调用。# 这是对象的构造函数。func _init(): # 在此处初始化对象的外部属性。 pass# _ready 在脚本节点及其子节点进入场景树时被调用。func _ready(): pass# _process 在每一帧上都被调用。func _process(delta): # 传递给此函数的 delta 参数是工夫,即从上一帧到以后帧通过的秒数。 print("Delta 工夫为:", delta)# _physics_process 在每个物理帧上都被调用。# 这意味着 delta 应该是恒定的。func _physics_process(delta): # 应用向量加法和乘法进行简略挪动。 var direction = Vector2(1, 0) # 或应用 Vector2.RIGHT var speed = 100.0 self.global_position += direction * speed * delta # self 指向以后类的实例# 重载函数时,您能够应用 . 运算符调用父函数# like here:func get_children(): # 在这里做一些额定的事件。 var r = .get_children() # 调用父函数的实现 return r# 外部类class InnerClass: extends Object func hello(): print("来自外部类的 Hello!")func use_inner_class(): var ic = InnerClass.new() ic.hello() ic.free() # 能够自行开释内存拜访场景树中其余节点 ...

November 28, 2022 · 4 min · jiezi

关于游戏开发:爆火小游戏羊了个羊我偏不玩

近日,一款名为《羊了个羊》的小游戏,在各社交平台频频刷屏,霸占热搜。几天工夫,《羊了个羊》一共登上微博热搜 11 次,话题浏览量达 25 亿。更是传出半天支出就达到 468 万元的天价收益,后经腾讯创始人马化腾核实为假。 依据官网介绍,这是一款超难的闯关打消小游戏,通关率不到 0.1%。游戏首页还设置了玩家排行榜,将不同地区的玩家分区进行排行,游戏通关后能够进入地区榜单,从而助力地区排名。不得不说,这是一个玩法简略、且同类游戏不可胜数的游戏。然而就是这一类游戏却有着十分宏大的用户群。 单说《开心消消乐》上线至今 8 年,月沉闷用户仍然放弃在 1 亿左右,玩家总数达 8 亿。《羊了个羊》在通关设置上增加了随机性和运气成分,并且使通关的概率升高。而官网偏偏把第一关设置的极为简略,第二关又卡住了有数人。于是,玩家有了一种“第一关羞辱智商,第二关智商被羞辱”的感觉。反而越来越沉迷,颇有一种,区区小游戏,也能难住我的气愤。而后,就被难住了。 事实上,这一类小游戏,如《合成大西瓜》《号召神龙》等都不会继续太长的热度,随同着社交话题的潮水,收割一批玩家后,就会出现生命周期越来越短的趋势。这些游戏都不足以在人们心中留下印记。 回顾历史上那些大火长销的游戏,无疑不在特定的期间,代表着最高的游戏制作水准。任天堂、世嘉、索尼、微软的主机游戏大战;甚至于中国市场的《仙剑奇侠传》、《剑网叁》、《阴阳师》等,都曾在一段时间占据着整个市场的热度。因而,与其停留在短暂的清静中,不如来看看真正顶尖的游戏,以及那个再也回不去的夏天。 中国游戏风波作者:王亚晖上架工夫:9月22日 | 豆瓣高分图书《中国游戏风波》,全新订正再版| 收录中国游戏杂志、国产游戏等各方面材料,让玩家理解游戏回顾背地的故事| 分畛域剖析中国游戏倒退轨迹,记录游戏圈的关键人物与事件| 收录中国游戏历史相干新闻图片,全书为升黑白印刷 单机游戏、网络游戏、网页游戏、手机游戏、电子竞技、游戏直播……一部视线宏阔、史料翔实的中国游戏发展史。一份笔触细腻、充斥温情的中国玩家回忆录。 游戏机图鉴:一部游戏机进化的视觉史作者:[美]埃文·阿莫斯译者:小宁子 王亚晖 | 一场游戏机进化史的“视觉盛宴”| 出现属于游戏玩家的回顾与浪漫| 入选英国《卫报》“游戏玩家不可错过的20本的经典图书” 书中以工夫为线索,用极具艺术性的高清摄影图片出现了 120 余款游戏设施的宝贵影像,全面记录了从第一世代到第九世代(1972—2020)的游戏机倒退历史。此外,本书还收录了游戏机的硬件配置信息、周边设备、销售数据、游戏发售数据、相干商业史以及幕后趣闻,不仅是一场游戏机进化史的视觉盛宴,更是一部硬件视角下的游戏行业兴衰史。 游戏剧本怎么写作者:[日]佐佐木智广译者:支鹏浩 日本长销 12 年,是有数游戏策动、编剧的入门宝典!本书从人物、世界体系、台词等角度动手,通过解析多部经典游戏、动漫作品的剧本细节,艰深而又系统地解说了游戏剧本的构建之法,是游戏设计的入门佳作。 巨匠谈游戏设计:创意与节奏作者:[日]吉泽秀雄译者:支鹏浩 | 揭示让游戏好玩的秘诀| 披露人气游戏创作背地的故事万代南梦宫首席制作人、《忍者龙剑传》《皇牌空战3》设计师吉泽秀雄执笔。 游戏设计的236个技巧:游戏机制、关卡设计和镜头诀窍作者:[日]大野功二译者:支鹏浩 | 荣获游戏开发者奥斯卡 CEDEC AWARDS 2015 著述奖 !| 如何让游戏百玩不厌、骑虎难下?如何让玩家失败后仍想持续挑战?如何实现电影般酷炫的画面成果? 本书从游戏设计者和玩家的双重角度登程,以大量游戏为例,并联合丰盛的配图,从“玩家角色”“敌人角色”“关卡设计”“碰撞检测”“镜头”这五个角度来探讨如何让 3D 游戏更加乏味,解明其中暗藏的技巧,为各位读者揭开游戏的“实质”。 Unity游戏设计与实现:南梦宫一线程序员的开发实例(修订版)作者:加藤政树译者:罗水东 游戏开发者奥斯卡 CEDEC AWARDS 2013 最优良著述奖,旧版豆瓣 9.3 分好评图书,基于 Unity5 全面降级!本书的作者是日本出名游戏公司万代南梦宫的资深开发人员,书中通过 10 个不同类型的游戏实例,展现了真正的游戏设计和实现过程。 游戏开发:世嘉新人培训教材作者:[日]平山尚译者:罗水东 本书由世嘉一线开发者执笔,并被选为世嘉新人培训教材,荣获游戏开发者奥斯卡 CEDEC AWARDS 2009 著述奖。全面介绍了游戏开发人员须要把握的相干技术常识。 内容由浅入深,从命令行游戏开发讲起,而后介绍如何开发简略的 2D 游戏,最初介绍如何开发出一个蕴含模型和动画的3D游戏,涵盖了计算机图形学(3DCG、2DCG、字体、光照、动画)、计算机运算(碰撞解决、计算误差)、编程(模块化、bug预防、性能优化)、游戏解决(状态迁徙、实时处理、加载)和声音解决等常识。 Unity 3D游戏开发(第2版)作者:宣雨松 ...

September 18, 2022 · 1 min · jiezi

关于游戏开发:游戏资产复用更快找到所需游戏资产的新方法

游戏资产再利用是一种常见且有价值的技术,能够更高效地开发场景巨大的游戏。就如同《艾尔登法环》中构筑的巨大凋谢世界一样,游戏开发者充分利用了前几次游戏的资源,使设计效率更高。 然而,如何疾速找到之前应用过的适合、优质的游戏资产,以及如何跨团队和我的项目分享游戏开发资产?浏览本篇文章,您将失去答案。 立刻分割Perforce受权合作伙伴——龙智,获取更多对于游戏资产复用、游戏大型文件版本治理,以及减速游戏开发的倡议。 即便是对于最大的工作室来说,跟上游戏发行和发明新游戏资产的步调也是一项挑战。为了满足市场对新款电子游戏日益增长的需要,开发团队须要比以往口头更迅捷。 为了在不就义品质的前提下减速开发,许多团队会利用过来的我的项目及其相应的游戏资产。游戏资产复用能够节省时间,便于程序员和创意人员利用现有素材进行翻新。但你该如何跨团队和我的项目分享游戏开发资产?欢送持续浏览理解具体的办法。 何为游戏资产?游戏资产是一个概述电子游戏中各种内容的术语。游戏资产包含纹理、角色、声音、对象、平台、构建、工件等。图片△ 游戏资产示例 面向游戏开发的资产复用资产复用在游戏开发畛域并不陈腐。通过游戏资产复用,创作者能够在另一款游戏中应用之前的动画、工件等。尽管有些开发者可能会认为这是一种懈怠的做法,但也有人认为,如果没有游戏资产的复用,构建就会破费太长时间。在一个要求新内容产出速度超过团队执行速度的世界中,复用游戏开发资产是必要的。 随着游戏工作室建设特许经营权,资产复用变得更加重要,也更容易。就像电视的续集提供了批改故事情节的机会,但也放弃了类似的角色和背景。建设一个全新的世界并不总是有意义的。相同,团队能够在不同的版本上实现统一的游戏体验,而且通常估算较少。 对粉丝而言,资产复用就像寻找复活节彩蛋一样乏味。对于开发者来说,寻找可复用的优良游戏资产是一项工作。 游戏资产复用面临的挑战那么,是什么因素妨碍了团队利用旧事物发明新事物呢? 不足可见性 单干是游戏胜利的要害。当团队还比拟小的时候,你很容易晓得其余团队成员在做什么。但随着我的项目变得更简单,工作室规模扩充,理解其他人正在做的事件就更难了。 工具差别 团队不足可见性的一个起因是他们应用不同的工具。对于游戏资产复用,开发者和设计师须要整合他们的工具集,从而理解团队和我的项目的最新进展。可能获取团队资产,并晓得哪些资产能够复用是第一步。 浪费时间去搜寻 假如你晓得另一个团队在做什么,你须要在他们的资产中进行搜寻。但他们的存档文件是怎么命名的?资产最初一次应用是在何时何地?大多数零碎都无奈追踪游戏资产的倒退,所以咱们简直不可能正确地找到或复用游戏资产,这就意味着团队成员将跳过搜寻,间接创立新内容。 游戏资产复用不只是复制粘贴须要留神的是,游戏资产复用并不是简略的复制粘贴,而是一个在重复使用中不断完善的理念。为了进行批改,而不毁坏其余版本,并促成团队之间的合作,您须要正确的版本控制系统。应用正确的工具,团队能够治理所有游戏开发资产的迭代并实现复用。 在二十大游戏开发工作室中,有19家应用的这一工具就是Perforce Helix Core。它成为媒体和游戏开发的标杆是有起因的,因为它不仅可能无缝地治理产品和版本的迭代,而且还可能让团队中的每个人疾速找到并复用游戏资产。 Perforce Helix Core如何帮忙你实现资产复用Perforce Helix Core提供各项性能、集成和客户端,能够帮忙任何团队成员进行资产复用。 Perforce Streams 在Perforce Helix Core中有一个弱小的分支机制,叫做Perforce Streams。Streams会跟踪分支之间的关系,在构建和复用代码时给予领导。团队中的每个人都分明地晓得正在做什么,当有新的更改可用时,Streams就会告诉终端用户。你将很容易找到之前工作过的Streams,并在游戏的不同局部从新应用。另外,有了互斥签出和文件锁定等性能,就不会影响任何人。这加强了团队间的可见性,使游戏资产比以往更容易复用。 游戏引擎集成 游戏引擎是古代游戏开发的根底。Perforce Helix Core集成了最风行的游戏引擎,这包含: Unreal集成Unity集成Lumberyard集成CryEngine集成在游戏引擎中很容易找到和复用来自Perforce Helix Core的资产。只有转到源代码管制,就可能浏览可用文件(如果有正确的权限)。借助这些严密的集成,动画师不须要浪费时间切换工具来复用资产,从久远来看节俭了工夫。****Helix Sync 桌面客户端 代码只是电子游戏的一个组成部分。图像、动画、声音和其余感官组件才是真正让玩家沉迷其中的元素。借助Helix Sync这一拖曳式版本控制客户端,创意人员能够持续应用本人的工具。但文件都在Perforce Helix Core外部进行存储和版本控制。 这便于工作室可能爱护和复用数字游戏开发资产,而无需减缓节奏。Perforce Helix Core能够解决游戏中的所有超大文件。当初,美术人员和设计师能够很容易地找到他们须要的货色。应用Helix Sync,团队取得了繁多事实起源,实现更快的构建和无缝合作。 Helix DAM用于复用游戏资产Helix DAM(现处于测试阶段)可让美工和设计师更轻松地复用游戏资产。凭借可视化界面和智能标记性能,它可能疾速找到之前制作的游戏资产。Helix DAM是基于Perforce Helix Core构建的,后者是一个失去20家顶级AAA游戏开发工作室中19家信赖的版本控制系统,因为它能以团队所需的速度来治理大型且简单的二进制文件。 △ 通过Helix DAM Beta进行标记除了让游戏开发资产更容易复用外,Helix DAM还助力创意团队: 轻松存储、查找、应用和共享所有美术素材通过看板来跟踪每个美术素材的进度间接对素材进行反馈,以便更快地批改简化创意工作流程,打消瓶颈将全副创意IP集中保留在一处如需理解对于如何通过Perforce Helix Core如何帮助您治理游戏开发中的大型文件,轻松复用游戏资产,减速游戏开发,请分割Perforce受权合作伙伴——龙智:电话:400-775-5506邮箱:marketing@shdsd.com 文章起源:https://bit.ly/3xCNhsU

June 24, 2022 · 1 min · jiezi

关于游戏开发:MMO服务器从零开始1-Beacon-Server

明天来实现服务器的第一个部件 - beacon_server。 性能解析为了建设Elixir集群,须要所有 Beam 节点在启动之时就曾经晓得一个固定的节点用来连贯,之后 Beam 会主动实现节点之间的链接,即默认的全连贯模式,所有节点两两之间均有连贯。对于这一点我还没有深刻思考过有没有必要进行调整,之后看状况再说 因而,为了让服务器集群内的所有节点在启动时都可能连贯一个固定节点从而组成集群,这个固定节点就是beacon_server。 beacon_server须要有什么性能呢?在通过一番简略思考后,至多须要具备以下几个性能: 承受其余节点的连贯承受其余节点的注册信息相应其余节点的需要,返回需要节点的信息这里有两个重要概念:资源(Resource) 和 需要(Requirement)。资源指某个节点本身的内容类型,也就是在集群中所处的角色,比方网关服务器的资源就是网关(gate_server);需要指某个节点须要的其余节点,比方网关节点须要网关治理节点(gate_manager)来注册本人,数据服务节点须要数据分割节点(data_contact)来把数据库同步到本身。 当一个节点向beacon_server节点注册时,咱们心愿它可能向beacon_server提供本人的节点名称、资源、需要等数据,不便beacon_server在收到别的节点注册时,可能把曾经注册过的节点当做需要返回给别的节点。 数据结构我用一个 GenServer 线程负责下面所说的所有工作,利用线程的 state 来保留来往节点信息。以后粗略想了想,权且定义信息存储格局如下: %{ nodes: %{ "node1@host": :online, "node2@host": :offline }, requirements: [ %{ module: Module.Interface, name: [:requirement_name], node: :"node@host" } ], resources: [ %{ module: Module.Interface, name: :resoutce_name, node: :"node@host" } ]}我用一个字典存储所有信息,分为 nodes、requirements以及resources三局部。 nodes存储所有曾经连贯的节点和他们的状态,:online示意在线失常连贯,:offline示意节点断开连接; requirements存储每个节点注册时提供的需要信息。应用列表存储,列表中每个项代表一个节点。项应用字典,存储模块(module)、名称(name)、节点(node)信息。其中名称字段,因为有些节点可能会有不只一个需要,因而应用列表存储。模块字段是为了留着以备后用,目前没什么用……节点字段用于获取的节点应用该字段对指标节点发送音讯,必不可少。 resources存储每个节点注册时提供的资源信息,字段与requirements完全相同,有一个不同的中央是名称字段的数据类型不再是列表,而是原子,因为每个节点只可能属于惟一的一种资源,不可能属于两种以上,因而用一个繁多的原子就能够代表了。 简要实现建设我的项目这是第一个实现,在实现之前,咱们先建设一个umbrella我的项目,用来寄存之后的所有代码: mix new cluster --umbrella而后创立本节的beacon_server我的项目: cd apps/mix new beacon_server --sup--sup用来生成监督树。 有了我的项目之后,咱们须要建设一个GenServer,用来充当其余节点用来通信的接口,咱们就把他叫做Beacon好了。 性能函数依据后面的构想,咱们须要上面这么几个函数: register(credentials, state) - 用于把注册来的节点信息记录在 state 中,并将新的 state 返回。get_requirements(node, requirements, resources) - 用于向已注册的节点返回其需要。上面贴上我粗略实现的代码,当然这不会是最终版本,将来还有优化的空间: ...

June 11, 2022 · 2 min · jiezi

关于游戏开发:MMO服务器从零开始0-开篇

引言始终想做 MMORPG 游戏,始终在学习,开一个系列把服务器开发的过程记录下来。 始终以来搜寻了许多材料,然而都四分五裂,短少一个残缺具体的概念,要么就是只对架构泛泛而谈,要么就是对某个算法的夸夸其谈。我作为纯正的业外人士,这些形象的材料根本无奈对我造成特地重要的指导作用,所以我还是得亲自尝试重构所有内容。 根本构想查阅过泛滥材料之后,我对 MMORPG 服务器的整体架构有了一个根本的概念。恰好之前深刻理解了一下 Erlang 和 Elixir,它们人造反对高并发的个性以及监督树和尽早解体的思维深深感动了我,所以我决定用 Elixir 实现服务器的各个部件。 我的想法中服务器的大抵架构如下: |----------| | client | x N |----------|-----------------------------------------|-----|----------------------------------------------|-------------| |--------------| |-------------| |--------------|| auth_server | x N | auth_manager | x 1 | gate_server | x N | gate_manager | x 1|-------------| |--------------| |-------------| |--------------|-----------------------------------------|-----|---------------------------------------------- |--------------| |---------------| | agent_server | x N | agent_manager | x 1 |--------------| |---------------|-----------------------------------------|-----|---------------------------------------------- |-------------------| |--------------| | scene_server(TBD) | x N | world_server | x 1 |-------------------| |--------------|-----------------------------------------|-----|---------------------------------------------- |--------------| |------------| |--------------| | data_service | x N | data_store | x N | data_contact | x 1 |--------------| |------------| |--------------|-----------------------------------------|-----|---------------------------------------------- |---------------| | beacon_server | x 1 |---------------|auth_server - 用户登录游戏用auth_manager - 用于治理 auth_server,做负载平衡gate_server - 网关服务器,用于承受客户端的tcp连贯,加解密音讯,并转发流量gate_manager - 用于治理 gate_server,做负载平衡agent_server - 用于执行非场景的用户逻辑(待定)agent_manager - 用于治理 agent_server,做负载平衡scene_server - 用于执行场景逻辑,如 AOI、地图区块治理等world_server - 用于兼顾治理 scene_server 的调配,以及解决世界级逻辑data_server - 数据库内存存储节点,用来对其余服务器提供服务data_store - 数据库长久化存储节点,用来保留数据库数据data_contact - 用来分割各个数据库节点,同时为其余服务器调配数据库节点,做负载平衡beacon_server - 灯塔服务器,用于分割各个服务器,替换资源,在节点间建设连贯数据库 打算采纳 Mnesia,人造具备集群能力,能够动静横向扩大。 ...

June 8, 2022 · 1 min · jiezi

关于游戏开发:游戏交互精选系列

为什么喜爱打游戏?每个游戏爱好者都有不同的起因,但往往起因都很美妙,是获胜后的高兴、领有在日常生活中不可能或者不太容易领有的体验、与其余玩家的互动分割等。于是游戏交互成了玩家取得更好体验的技术实现手法,本系列课程以多款游戏作为案例剖析了游戏交互设计的特点与优劣,以及介绍如何理解用户意识、惯性操作模式,而后使用到游戏交互中以给用户更好的体验。 文章简介本系列共有四篇课程: 第一篇《游戏体验精选:带你剖析出名游戏的外围体验设计》蕴含了对《哈利波特》、《巫师3:狂猎》、《塞尔达无双:灾厄启示录》、《塞尔达传说:旷野之息》、《花亦山心之月》、《Florence》和《浮生为卿歌》等七款游戏的体验剖析,从外围设计玩法、设计特点与优劣以及交互模式开展形容。 第二篇《对症下药-游戏老手教程梳理与剖析》,以《原神》为主,剖析梳理了一些常见的疏导模式与表现形式,并总结了不同表现形式的实用状况和利用办法。 第三篇《手游界面设计如何向主机游戏学习》,从高界面清晰性、丰盛的界面动静、叙事化的界面、界面变动晦涩、应用故事内界面以及器重声音设计六个方面开展形容手游界面设计该如何向优等生主机游戏学习。 第四篇《理清意识流——游戏设计中的大禹治水》,旨在通过剖析意识流来达到诸如Supercell系列游戏中交互流程上的晦涩感和刺激感。 适宜读者 1、适宜游戏用户体验设计者,蕴含策动、交互、美术和动效等 2、适宜与游戏行业相干的从业者,蕴含游戏测评、鉴赏等自媒体UP主 3、适宜对游戏互动艺术感兴趣的高校同学 长按辨认二维码下载APP

May 16, 2022 · 1 min · jiezi

关于游戏开发:视频回放-维塔士龙智数字化打造游戏行业头号玩家

2022年4月22日 ,Atlassian在线举办的 Team ’22 嘉年华流动圆满闭幕。本次流动中,龙智资深销售经理孙雅坤对话维塔士团体 IT 总监戴宇晓,与大家分享维塔士是如何应用 Atlassian 产品搭建团体 DevOps 平台,分享在 DevOps 平台搭建过程中的产品选型、施行上线等方面的实战经验。 大家好,我是龙智的孙雅坤。 **龙智 —— DevSecOps解决方案提供商,专一于该畛域近10年,集成平安研发经营一体化畛域的寰球支流工具,帮忙企业按时、平安、高速地公布软件和经营软件,已为寰球800多家企业提供了服务。龙智同时也是Atlassian寰球白金合作伙伴,Atlassian插件生产商,龙智领有Atlassian寰球认证集体19名,其中两名是Atlassian认证专家。** 很荣幸咱们明天邀请到了上海维塔士电脑软件有限公司的戴宇晓与大家交换与分享。戴总您好,欢迎您来到了咱们 Team ‘22 嘉年华流动,请您先和咱们的观众打个招呼。 大家好,我是维塔士的戴宇晓。 咱们晓得维塔士是当先的视频游戏和娱乐内容制作公司,您能给大家介绍具体地介绍下吗? 维塔士成立于2004年,是一家当先的视频游戏和娱乐内容制作公司,在新加坡、中国、越南、加拿大、法国、日本、 爱尔兰和美国都设有工作室和经营团队。维塔士领有2500多名全职游戏制作专家,多年来致力于AAA级主机游戏、PC游戏和手机游戏的开发与3D美术制作,帮忙客户实现支出的增长和制作效率的晋升。 多年来维塔士在游戏和电影畛域积攒了丰盛的成功经验,参加了泛滥AAA游戏和电影我的项目的合作开发及美术工作,咱们的客户包含泛滥驰名独立工作室,以及世界顶级数码娱乐公司20强中的18家。 通过您的介绍,咱们更理解了维塔士的业务和企业文化,咱们晓得维塔士很早就开始应用 Atlassian 产品,应用 Atlassian 产品或解决方案之前,公司/团队次要面临了哪些问题或挑战? 咱们很早就开始关注Atlassian的产品了,最早是在2010年试用过Bamboo作为咱们的代码管理工具。 在2012年,咱们通过了一年多的试用,开始应用Jira Software。在应用Jira Software来做咱们的BUG治理前,咱们应用了几款开源软件。次要的问题有很难取得反对,定制化比拟麻烦,可视化水平较低,平安方面也存在很多问题。过后可能还不必思考大型团队的单干,然而能够晓得,很多开源计划无奈撑持几百人的团队的工作,效率和可靠性都会有很多影响。 在做产品选型时您还思考了哪些产品? 和其余产品相比您认为 Atlassian 的劣势在哪里? 咱们过后的确是和几款软件进行比拟,在BUG追踪方面,咱们比拟过当初还有很多版本的开源的Redmine。在软件项目管理方面,咱们比拟过MS的Project Server。和这些产品相比,首先,Atlassian的劣势就是整合,咱们能够在一个平台里治理咱们的我的项目,工作,发行版本,BUG,知识库。 其次就是灵活性,咱们能够定制各种不同的流程来适宜不同的我的项目,不同的模板来标准咱们的操作,项目经理有充沛的施展空间来应用这些工具进行治理,一个很好的例子就是咱们在JIRA治理中有各种仪表盘来监控我的项目状态。Jira的字段、工作流都是能够自定义的,比方,咱们不同的工作室有不同的流程,应用Jira就能够进行定制,满足各个工作室的个性化需要。 最初就是安全性,咱们的开发波及多个不同工作室的团队,有时候也会有咱们的客户染指。咱们须要保障各个我的项目间,工作间足够细粒度的权限治理,并且用一种易于了解的形式来治理。零碎架构方面,咱们当初应用了DATA CENTER版本,能保障肯定的可用性。 另外,Jira还提供规范API接口,买通其他软件,比方与通过龙智引进的Perforce,Gitlab配置管理工具进行了集成,大大提高了开发效率,让整个DevOps的实际更进了一步。 当初维塔士应用了那几款 Atlassian 的产品呢?又有哪些部门/团队在应用?又有多少员工应用 Atlassian 产品呢? 咱们当初应用了Jira Software,Confluence,大量在应用一些Trello。Jira宽泛应用在开发团队和我的项目团队,而Confluence作为企业的知识库,被咱们寰球多个工作室的所有人在应用。 您施行的第一个 Atlassian 产品是Jira,您又是如何从第一个产品扩大到 Atlassian工具集的? 如刚刚所述,咱们施行的第一个产品就是Jira Software了。咱们过后只有不到40个用户,在咱们的游戏QA部门应用,次要用来做游戏我的项目开发中的BUG治理。在治理我的项目BUG的这个过程中,又逐步扩大到了整个开发团队。接着,在公司推广麻利开发的时候,咱们又进一步应用到了其余项目管理团队,比方,IT的项目管理。 当咱们的美术团队想找一个软件来治理咱们知识库的时候,咱们又开始同样的从一个部门开始推广Confluence,当初咱们全公司都开始应用这个工具来治理咱们的知识库和我的项目阐明,并和Jira联合在一起应用。 是什么促使您决定寻找解决方案合作伙伴?您又是怎么理解及抉择咱们龙智的呢? 咱们在应用这些工具的时候,会遇到很多问题,咱们以前是尝试去分割原厂近程,大部分状况下通过邮件进行解决,然而很多状况下,咱们可能须要现场的一些沟通交流,更好理解咱们的需要或者做出更快的响应。 因为咱们最大的开发团队都在中国,咱们须要在中国找到一个合作伙伴来帮忙咱们更好更平安地应用这些工具。咱们是通过原厂意识了龙智数码,作为官网举荐的寰球白金合作伙伴,有泛滥的Atlassian认证专家,咱们理解比拟当前晓得,龙智客户的行业宽泛,口碑也不错,咱们能够充沛的信赖你们能够提供有质量保证的服务。 此外,你们代理的产品也不仅仅是Atlassian的工具,还能够提供更多工具,给咱们落地整个DevOps计划。这也是咱们考量的一个方面。 您认为咱们在Atlassian工具的落地,包含整个DevOps的落地、运维方面是如何帮忙到您的呢?也对咱们服务做一个评估。 咱们公司和龙智在Atlassian在几个层面进行过单干,比方在基础架构层,帮忙咱们从繁多的服务器模式转变到当初的数据中心版本,咱们也在探讨如何应用云的部署或者版本。比方在应用层,咱们应用很多插件、很多DevOps工具,或者须要建设一些新的流程,咱们会向咱们的合作伙伴征询最佳实际。 龙智的服务很到位,后期龙智都会与咱们做屡次计划探讨,深刻地理解咱们的现状和痛点,依据咱们的需要,做出计划,并且在施行的过程中,给了咱们很多帮忙,最终帮忙咱们胜利落地。 一方面,龙智响应及时,有问题都能第一工夫回应。另一方面,龙智团队比拟业余,而且经验丰富,能疾速地帮咱们定位并解决问题,为咱们的稳固运行保驾护航。 ...

April 27, 2022 · 1 min · jiezi

关于游戏开发:PONG-100行代码写一个弹球游戏

大家好,欢送来到 Crossin的编程教室 ! 明天跟大家讲一讲:如何做游戏 https://www.bilibili.com/vide... 游戏的主题是弹球游戏《PONG》,它是史上第一款街机游戏。因而选它作为我这个游戏开发系列的第一期主题。 游戏引擎用的是 Python 的一个游戏库:pgzero。它是对 pygame 的一个封装,让你不须要写多余的套路代码,只有配置游戏的内容逻辑即可。 咱们这个游戏用它来写,一共只须要100行代码。 首先须要装置 python 环境。这一步没搞定的同学,能够参考咱们 python 入门教程:http://python666.cn,下面有具体图文介绍。 而后须要装置 pgzero 库,能够命令行下通过 pip 命令装置: pip install pgzero 装置完,运行一句 pgzrun.go()咱们的游戏世界之门就曾经关上了。 当初下面还是混沌初开,一片乌黑。 设定一个矩形的左上角坐标和长宽,在游戏的绘制函数 draw 中用指定色彩填充,咱们就失去了一个矩形。 pad_1 = Rect((20, 20), (10, 100))def draw(): screen.clear() screen.draw.filled_rect(pad_1, 'white')适当调整一下,就失去了一块游戏中用来挡球的板。 在游戏的更新函数中减少判断,当键盘上的“上”、“下”按键被按下时,批改挡板的y坐标,就能够在游戏中管制挡板的挪动了。 PAD_SPEED = 10def update(dt): if keyboard.up: pad_1.y -= PAD_SPEED elif keyboard.down: pad_1.y += PAD_SPEED这样就曾经实现 PONG 游戏中的玩家操控角色:一块可高低挪动的挡板。而当初咱们用到的代码仅仅10行。 有的小伙伴可能留神到了,这里有两个函数,一个叫 draw,它是负责游戏中的画面绘制,另一个叫 update,它负责游戏中的逻辑更新。 咱们常常听到说游戏运行时速度是每秒30帧、60帧之类,或者叫做 FPS(Frames Per Second)。draw 和 update 就是在游戏的“一帧”画面中所要做的事件。你的计算机或者游戏主机的性能越高,每一帧所破费的计算工夫就越少,游戏帧数就能够更高,游戏体验也就更晦涩。 ...

March 28, 2022 · 2 min · jiezi

关于游戏开发:2022GWB腾讯独立游戏大奖赛正式启动让游戏的创意与价值被更多人看到

3月21日,由腾讯游戏学堂发动的2022 GWB腾讯独立游戏大奖赛正式开启报名。本届大赛将聚焦独立游戏畛域,挖掘并出现优质的游戏产品与团队,帮忙有情怀的开发者获得成功。同时,赛事也将连续“Game Without Borders(游戏无界)”的主旨,为寰球游戏开发者搭建一个凋谢的游戏创意单干平台,助推行业多元生态与游戏价值传递。 往年大赛邀请了47位游戏制作人、学者专家及资深玩家参加评比,在奖项设置的维度更加丰盛,心愿挖掘更多在玩法创意、叙事表白、美术设计,以及社会价值等方面的高后劲作品,并给予奖金与资源加持,让更多优良的独立游戏作品被看到。 [大赛报名二维码][大赛官网报名地址:https://gwb.tencent.com/award...] 深耕独立游戏赛道,帮忙开发者面对时机与挑战 当下独立游戏畛域时机与挑战并存。得益于市场倒退和用户需要的一直降级,游戏产品在细分品类上更加多元化倒退,创新型玩法与垂直赛道的机会开始增多。同时,像《戴森球打算》《阴影火炬城》等越来越多国内开发者的优秀作品,受到了寰球玩家的青睐。 但对国内数以万计的独立开发者来说,能真正实现商业胜利的仍是多数。毕竟在独立游戏作品强烈的自我表白背地,往往意味着更小的团队、更大的危险,如何在当下饱和、混淆的游戏市场中突出重围,成为悬在他们头上的“达摩克利斯之剑”。 作为旨在助力游戏人成就幻想的腾讯游戏学堂,从2016年开始间断举办GWB腾讯游戏创意大赛,并从2021年开始重点加码独立游戏畛域,吸引了来自寰球45个国家,超过2470个游戏作品参赛,挖掘并搀扶了泛滥优秀作品。 其中,前段时间刚上线Steam便播种94%好评率的《文字游戏》,在去年GWB腾讯独立游戏大赛中取得金奖与最佳玩法冲破奖。这是一款以汉字解谜为外围玩法的游戏,通过对汉字语序、笔画的拆解组合,加上富裕感染力的故事、印象粗浅的音乐,让经典RPG冒险有了全新的体验,也为扎根中国外乡文化的游戏设计与表白开辟了新的方向。 【《文字游戏》】 另一款在去年大赛中取得铜奖,以及最佳音乐音效奖、最佳国风文化奖的2D冒险解谜游戏《山海旅人》,不仅塑造了泛滥耳熟能详的妖怪故事,还融入了算盘、杆秤这些极具中古特色的元素,搭配联合水墨画与像素风的视觉设计,造成了属于本人的独特格调。这款游戏在去年9月发售后,就立即引发了微博、Taptap等平台玩家的不错反应,B站上《山海旅人》相干视频最高点击量超过了100万,在Steam上至今仍然放弃着97%的好评率。 【《山海旅人》】 除此之外,历届大赛获奖者中不乏口碑与翻新双赢的精品之作,例如由胖布丁工作室开发的解谜冒险游戏《南瓜学生2:九龙城寨》,国产Roguelike匠心之作《霓虹深渊》,以及在海内播种大量玩家好评的《Liberated》《Cloudpunk》等作品。 【《南瓜学生2:九龙城寨》】 【《霓虹深渊》】 【《Cloudpunk》】 47位资深专家评委参加,帮忙更多优质作品怀才不遇 往年,大赛别离邀请了来自腾讯互娱多个工作室群的游戏专家、国内出名游戏厂商创始人、具备丰盛教训的独立游戏制作人、资深游戏媒体人及主播,以及从事相干畛域钻研的高校学者,对参赛作品进行多维度、多视角评审,让每一个参赛作品失去充沛展现机会。 本届大赛携手WeGame和微博,首次推出用户抉择奖。让公众玩家通过参加内测体验,投票选出本人所青睐的游戏作品。用户抉择奖的设置,让优秀作品在较量期间即走进公众视线,也能让更多玩家参加到GWB腾讯独立游戏大赛的赛程中,见证参赛团队的成长。 赛事奖项全面降级,摸索游戏创意的更多潜能 为了激励更多游戏玩法的翻新,挖掘不同垂直赛道的优秀作品,本届赛事的奖项评委维度将更加丰盛,共设立了12个奖项。其中蕴含金、银、铜与社会价值4个特地奖项,最高奖金达50万元。另外,还设立最佳玩法冲破、最佳叙事表白、最佳视觉格调、最佳迷你团队、最受商业化期待、制作标杆奖等,以帮忙更多具备翻新亮点的游戏作品被更多人看到。 同时,往年大赛首次将社会价值奖的处分金额进步到30万元,以激励开发者将游戏的技术能力与玩法叙事与现实生活相结合,挖掘游戏的社会正向价值与利用后劲。 长线资源加持,全周期助推产品取得成功 随着市场与玩家的一直成熟,独立游戏想要取得商业胜利,不仅须要晋升研发实力、丰盛游戏内容,还须要应答产品上市后的推广经营等压力。 大赛期间,腾讯游戏学堂与GWB组委会将不定期举办开发者沙龙、激励开发者与行业专家面对面交换,解决游戏研发中的难题,帮忙产品实现更好优化。此次较量的获奖作品与高后劲我的项目,将取得优先签约机会。在游戏研发到成熟上线的全过程中,GWB还将提供更全面、业余的技术及资源反对。 赛事组委会将对优良的参赛作品继续报道,理解研发背地的故事,帮忙其晋升玩家认知与行业曝光。并联动腾讯游戏、腾讯游戏学堂、Wegame、微博、好游快爆等合作伙伴,通过打造乏味的玩家经营流动,帮忙好游戏走向台前,与用户连贯。 正如腾讯游戏副总裁、腾讯游戏学堂院长夏琳在此前采访中曾示意:“游戏行业的良性衰弱倒退,离不开对创意土壤的耕耘。咱们心愿从翻新、创意、创作等不同维度,为中国游戏行业的可继续倒退添砖加瓦。” GWB腾讯独立游戏大奖赛与腾讯独立游戏孵化器也将判若两人,通过丰盛的行业赛事流动与资源搀扶,为独立游戏团队排除胜利路上的各种妨碍,让有情怀的游戏开发者取得更多商业回报,让优质的独立游戏作品被更多人看到。 对于腾讯独立游戏孵化器促成游戏行业生态多元化倒退腾讯独立游戏孵化器是腾讯游戏学堂在2020年底新成立的组织,负责协调腾讯游戏各相干部门的孵化资源,实现高潜独立游戏的全程孵化。帮忙独立游戏团队解决难题、晋升品质、获得成功,促成游戏行业多元生态的整体倒退。 对于腾讯游戏学堂助力游戏人“成就游戏幻想”腾讯游戏学堂成立于2016年12月,致力于打造游戏常识分享和行业交换的平台,通过游戏行业业余人才培养、高校产学研单干、行业交换及开发者生态建设等,推动游戏行业良性倒退,助力游戏人“成就游戏幻想”。 学堂五周年视频:每一程都不让你落单https://v.qq.com/x/page/k3327...

March 21, 2022 · 1 min · jiezi

关于游戏开发:Unity资产管理与更新系统的一种实现方式

一、详情这个实现来自于我的集体开源我的项目 UnityGameWheels(以下简称 UGW),并已在理论生产中有肯定的利用。UGW 的代码地址: Core:纯C#局部。其中资产治理和更新相干内容位于Asset。 Unity:和Unity联合的局部。其中资产治理和更新相干内容位于Asset,编辑器相干位于Editor。 Demo:一些示例代码。 此间一些设计形式参考了我一位老友的GameFramework。此外,玩具代码颇多(比方有个玩具版IOC容器),请见谅并忽视。 1.1 希图 心愿为挪动平台(次要是iOS和Android零碎)实现具备肯定通用性的资产治理与更新零碎。在应用时不用过多顾及资产包(AssetBundle),而是关注单个资产(Asset)。对更新的内容,做出肯定水平的分组,实现边玩边下。1.2 名词 资产和资产包:即Unity中的Asset和AssetBundle。两种模式: 编辑器模式:在编辑器下开发时,通过UnityEditor.AssetDatabase中的办法间接拜访资产文件。资产包模式:构建资产包应用的模式。这种模式为后文的次要探讨对象。资源(Resource):在Core中指资产包。这用法也来自GameFramework。索引(Index)文件:专指收集、记录资产和资产包根本信息(相似于Unity提供的资产包manifest文件的性能)的文件。 CR:安装包索引文件。RR:远端索引文件。PR:长久化索引文件。Manifest 文件:Unity构建资产包时生成的数据文件,蕴含资产包和资产的关系以及资产包间的依赖关系。资产零碎:指本文所形容的资产治理和更新零碎。1.3 次要组成部分 Core(纯C#)局部AssetService类(实现IAssetService接口)是资产包模式的主入口,提供资产治理与更新的入口。 通过Prepare办法来进行资产零碎的筹备工作。通过CheckUpdate办法来查看是否须要进行更新以及哪些内容须要更新。通过IResourceUpdater接口(实现为AssetService.ResourceUpdater)来进行资产包(资源)的更新。通过LoadAsset,LoadSceneAsset,UnloadAsset等办法来加载和卸载资源。Unity 局部: Asset 文件夹提供依赖于 Unity 库的实现,和编辑器模式下应用的IAssetService8的实现。Editor/AssetBundle 文件夹提供构建资产包相干的编辑器工具。二、一些重要概念2.1 资产包的分组在Unity中,每个资产文件至少显式打入一个资产包,所以对资产包分组(Group),就相当于对显式打入资产包的每个资产都分组。为什么要分组呢?一方面,是为了按组为单位做资产包更新;另一方面,是管制依赖关系的复杂度。 应用非负整数来标记每个资产包的组号。 0 代表公共组,能够被其余组依赖。正整数代表其余组,不容许组间依赖,然而都能够依赖 0 组。在分组更新的根底上,这样的限度带来的益处是,不须要为了更新一个分组的内容而大量更新其余分组的内容。当然,这种抉择同时也是一种局限。 在利用启动过程中,“正式”进入游戏之前,应将 0 组的内容更新结束。 2.2 索引文件Unity本身在构建资产包时,提供了manifest文件,用于指明每个资产包中蕴含哪些资产以及依赖于哪些其余资产包。索引文件,在此基础上退出了包含资产之间的依赖关系、资产包分组(后文解释)在内的若干其余信息。编辑器工具构建资产包时会生成三个文件夹: Client:用于放在StreamingAssets中、打入首包的资产包;ClientFull:用于放在StreamingAssets中的全量资产包,适宜调试或者敞开更新性能的情景。Server:用于放在CDN上用于更新的全量资产包。这三个文件夹中各自会有一个索引文件。前两者天然格局统一,称为安装包索引文件(记为CR,其中C代表Client,R代表Resource),随首包公布。Server文件夹中的索引文件称为远端索引文件(记为RR,其中第一个R代表Remote)。在资源更新和应用的过程中,本地长久化目录中会寄存一份索引文件,称为长久化索引文件(记为PR,其中P代表Persistent),它记录的是本地保留的那些资产包的信息。 留神,在Server文件夹中的每个文件都会后缀它本身的CRC-32校验和,用于下载之后的校验。 2.3 版本号资产零碎应用的资产包版本号包含两局部,是由应用程序版本号VerApp (其实是UnityEngine.Application.version的值)和资源外部版本号 VerRes 拼接而成,对于每一个VerApp,在每个平台上,打包的时候VerRes最好从 1 开始自增。如VerApp为 1.0.1,在这个应用程序版本下,Android平台第19次资产包构建,其版本号为1.0.1.19。如果应用程序版本升为1.1.0,则再度打Android资源包的时候版本号就是1.1.0.1。这也是后文讲的资产包构建器的默认行为。 利用程序运行时,如果开启了资源更新,则本零碎只是依据输出的信息来断定应该下载哪个RR,而不会去查看版本的新旧。规范的做法,是应用程序从某个服务器获取以后VerApp 对应的最新的VerRes,以及相应的文件尺寸、CRC-32 等信息,来断定是否须要下载这个版本的RR。 三.更新资产包3.1 初始化和筹备阶段结构AssetService对象时须要传入一些配置信息,包含但不限于CDN服务器的根目录、同时进行的资产加载工作数量限度、同时进行的资产包加载工作数量限度等内容。 零碎初始化之后,通过AssetService.Prepare办法进行的筹备工作,其实就是要把CR和PR从各自所在的文件系统中载入内存。CR是必须要存在的,而PR一开始的时候不存在,就认为存在一个空的PR。 3.2 更新检测阶段在筹备阶段实现之后,就要通过AssetService.CheckUpdate来检测是否有须要更新的内容。这里须要传入一个AssetIndexRemoteFileInfo(索引文件信息)对象,是使用者从相干服务器获取的对于RR的信息,其中包含如下一些字段:<img src='remote_index_info.jpg' height=150/> 其中nternalAssetVersion就是后面所说的VerRes,指这个RR对应的资产包版本,Crc32是该RR的CRC-32校验和,FileSize是该文件的大小(字节)。前面这两个字段都是为了下载之后的校验。 更新检测又有几种状况。 如果敞开了更新,则间接应用CR作为PR。此时,认为安装包中StreamingAssets目录下的内容是残缺可用的(即从前述之ClientFull文件夹复制而来,如果之前下载了任何资源,咱们都认为是没用的。如果关上更新,且本地缓存的RR的Crc32和FileSize均和AssetIndexRemoteFileInfo中提供的数据统一,阐明不须要从服务器下载RR,用本地缓存的即可。其余状况,须要从远端下载RR。UGW中有反对文件下载零碎的实现,超出本文领域,不赘述。对于上述后两种情景,零碎会对CR、RR和PR做三方比拟,来决定哪些资产包是须要下载的,哪些资产包是须要(从长久化目录删除的)。具体地: RR中没有的资产包(阐明曾经没用了),如果PR中有,则应该从本地长久化目录中删除。RR中有和CR中雷同(通过比拟Unity生成的Hash值和文件尺寸来决定)的资产包,则删去PR中蕴含的那个版本(如果有的话)。对RR中有,然而CR中短少或内容不同(通过比拟Unity生成的Hash值和文件尺寸来决定)的资产包,须要更新。在三方比拟的同时,零碎还会对每个资产包分组结构资产包更新摘要信息。这摘要由ResourceGroupUpdateSummary类形容,蕴含其所指向的资产包分组中的资产包总量、残余下载量等信息。这些摘要对象将用于前面的资产包更新。 3.3 更新前述筹备工作实现后,就能够应用AssetService.ResourceUpdater更新器对象进行更新了,通过它(实现IResourceUpdater接口)能够: 获取可用的资产包分组都有哪些。对给定的资产包分组,获取其中资源状态(须要更新、正在更新、曾经最新)。对某一组的资产包开始、进行更新;通过前述ResourceGroupUpdateSummary类,获取各组资产包更新进度和状态(是否在更新、是否曾经最新等)。更新资产包的过程中,会更新PR中的内容并在适当的时候保留到长久化目录中。对于每个资产包分组,肯定要全副更新完才可应用其中的内容。 四.应用资产资产零碎中提供了一些辅助办法,来断定资产是否曾经能够应用,也就是判断资产的存在性、以及所属的资产包分组是否曾经更新结束。在此基础上,使用者能够应用(逻辑层面的)加载、卸载接口来应用和开释资产。 4.1 加载接口与资产拜访器AssetService提供LoadAsset和LoadSceneAsset办法来加载个别资产和场景资产。鉴于后者没有进行认真测试,此处临时仅对前者做出阐明。LoadAsset的函数签名为 IAssetAccessor LoadAsset(string assetPath, LoadAssetCallbackSet callbackSet, object context);使用者将资产门路(从 "Assets/" 开始)、回调函数和可选的自定义上下文对象传入,即可同步地取得一个IAssetAccessor,即资产拜访器(简称AA)。AA的引入,是因为加载资产操作在概念上是异步的(只管因为外部缓存等起因可能实际上是同步实现的)。如果在加载未实现的状况下,使用者不想用这个资产了,通过这个拜访器能够卸载资产。通过IAssetAccessor接口,使用者能够获取资产门路、资产对象(如果曾经加载实现)以及其状态。 ...

March 14, 2022 · 1 min · jiezi

关于游戏开发:NFT预约平台源码搭建NFT系统开发剧本杀预约APP案例

随着体验经济的倒退,人们对新生产业接受度比拟高,剧本杀游戏胜利出圈,成为当下比拟热门的休闲娱乐活动之一。这款预约APP就能够线上预约,节俭了工夫,不便了用户。这款APP能够线上看简洁,预约想玩的剧本,约本流程简略,线上剧本杀,组队拼车,语音群聊约本,通过玩的过程意识新的敌人。剧本杀游戏的强体验感和社交属性正吸引越来越多年老消费者参加,这款APP能够通过多维度标签筛选可疾速过滤出适宜的剧本类型,使用户好感度晋升。

November 9, 2021 · 1 min · jiezi

关于游戏开发:区块链游戏NFT游戏开发DAPP模式定制

什么是NFT?为什么一件纯数字作品能以靠近7000万美元的价格被拍卖?NFT对我有什么益处?我置信很多人对这些问题充斥狐疑。目前,游戏产业是世界上倒退最快的产业之一。技术提高是影响电子游戏市场快速增长的重要因素之一。随着新兴信息技术的不断创新倒退,游戏进行市场的一直整合,使得网络游戏市场的竞争日趋激烈。区块链是最新的技术之一,有可能扭转寰球游戏市场。当初区块链技术仿佛颠覆了传统的电子游戏市场。事实上,目前的游戏行业面临着许多解放,包含不足运行一些游戏所需的弱小硬件。这一社会问题和其余一些问题咱们能够通过从传统的集中式硬件平台转变为分布式生态经济零碎来解决。

November 8, 2021 · 1 min · jiezi

关于游戏开发:WICC-广州开启报名包揽最in社交泛娱乐出海话题

往年 7 月,融云在北京召开了第三届寰球互联网通信云大会(WICC),千余位开发者相聚现场,另有近万人通过网络直播的模式独特参加到这场盛会中。一探到底吧! 只管流动曾经闭幕 3 个月,但相干话题热度始终居高不下,一直有当地敌人私信咱们,征询 WICC 什么时候能够去到他们的城市。于是,通过谨慎的思考,咱们决定突破“一年一会”的解放,来一局返场的惊喜! 这次,再度启航的 WICC 将亮相“花城”,以「“语”你同行,“视”界有限」为主题,聚焦通信云畛域的新技术、新场景、新利用,分享社交泛娱乐、出海、元宇宙、游戏社交化等多畛域的最新实际思考,并关注跨境电商、数字化营销起量、出海合规、本地化经营等前沿通信技术下的热点话题,让开发者播种丰盛的技术与实战经验。 自即日起,大会报名通道限时开启,点击【上方图片】或关注【融云寰球互联网通信云】,即可收费预约流动席位。11 月 20 日(周六),广州天河希尔顿酒店,WICC 开发者 Party,咱们不见不散~(文末有彩蛋哦!!) 扫盲:WICC 的“前世今生”WICC 是业内首个围绕互联网通信云技术发展研究的技术盛会,全称 World Internet Communication Cloud Conference(寰球互联网通信云大会),由融云于 2019 年首次发动,至今已走过 3 个年头。 WICC 开办的初衷,是融云作为通信云技术服务领军企业,心愿担当起“桥梁”的重任,搭建一个行业多方交换的平台,聚合产学研用最优良的技术人员,从科学研究到技术倒退、再到产业利用,让从业者可能获取最新的技术灵感,同时给开发者带来更多可能的新场景落地方向,引领通信云行业的整体倒退与提高。 2019 年 11 月,WICC 首发上海,来自 AWS、阿里、百度、京东、bilibili 等出名互联网公司的数十位技术首领齐聚一堂,在 5G 商用元年之际,带来了一场对于 5G 典型场景下行业将来趋势的探讨与瞻望。现在随着《5G 利用“扬帆”行动计划(2021-2023年)》的公布回头看,咱们很快慰地发现,当初的很多“预感”都有了时代回响。 2020 年 10 月,WICC 走进深圳。这一年,新冠疫情突袭寰球,疫情的不可抗因素,主观克制了线下面对面交互,催生了线上的不可逆凋敝,引爆以近程化、无接触、社交化为特色的新常态体验,叠加 5G、XR、AI、边缘计算等相干技术的倒退冲破,让互联网通信云倒退领有了更大的设想空间,也为这届 WICC 赋予了更多事实的意义。 2021 年 7 月,WICC 回归到融云的“大本营”北京。这一届 WICC 创造性地引入了学术界的声音,为促成产学研用的深度交融,构建了成效显著的交换互动平台;同时首次提出“开发者服务生态”的视角与思考,在技术之上探寻以人为本的“内生驱动力”,又一次引领了产业向更高层次的纵深递进。 能够看出,作为 WICC 主办方,融云在每一届流动中都力争焕新、加量加料,诚意满满。也正因如此,每一场原定几百人的流动,最初都会爆场成为千人盛会。无论是流动现场密集的干货输入、台上台下沉闷的交换碰撞,还是会后来自嘉宾与观众自发的点赞和流传,都让咱们深信,这是一件正确的事,有意义的事。 现在,WICC 把第四站、也是 2021 年度返场秀选在“花城”广州,心愿可能在社交场景化、出海全球化的趋势之下,给大家减少更多“经验值”,为业务的破圈增长引航之路。置信这一次,咱们仍然会共创一场“不虚此行”的行业盛会。 剧透:本届 WICC 筹备了哪些惊喜?因循 WICC 一贯的议程构造,本届 WICC 依旧会设立高峰论坛和技术分论坛,高峰论坛中既有主题演讲,也有让表白更加充沛的圆桌对话值得期待。 与此同时,和之前相比,本届 WICC 的翻新之处在于: ...

October 12, 2021 · 1 min · jiezi

关于游戏开发:游戏工程师成长四-做事情的4层境界你达到了哪一层-知乎

在工作过程中,做事件分为以下4个境界,别离是做了、做完、做好、做对,难度和耗时都顺次递增。 第一层境界--做了:被动执行,不关注后果处于这个阶段的研发,他人说什么就做什么,不会为这项工作做整体的思考。 这类人大抵能够分为以下几种: 第一种人没谋求的,得过且过,只是想在公司混混日子。他们会感觉事件只有可能实现就好,至于最终成果怎么样,跟他们没有关系。这类人很难援救,因为他们基本不想成长。 第二种人有谋求,然而没有意识到须要把事件做到更好,他们认为只有实现了工作就曾经是完美实现工作了,上头就曾经很称心了。这类人还是能够援救的,因为他们只是不晓得要做得更好而已,有可能是因为他们以前工作的中央给他留下了这种不好的观点。只有正当地对这类人进行疏导,他们会明确之后应该怎么去做得更好。 第三种人有谋求、无意识到须要做得更好,然而因为工夫不够等起因被逼得只能勉强实现工作。呈现这样的状况,责任并不齐全在执行者身上,还有一部分起因在leader或者pm身上。游戏行业研发压力大,工夫常常会被压得很紧,要把事件做得更好须要破费的工夫天然是更多的。 如果真的要把这件事件做得更好的话,可能须要执行者就义私人工夫。偶然就义一下私人工夫也还能够承受,如果这种状况常常产生,执行者也不可能始终就义本人的私人工夫。从这一点来看,年轻人比中年人更有劣势。因为年轻人,特地是刚刚进去工作的人,私人工夫个别都是闲暇的。然而中年人的私人工夫个别都是有事件要做的。这也是35岁中年危机会呈现的其中一个起因。 更好的解决办法是执行者找leader或者pm沟通重现沟通工夫,让执行者有更多的工夫去把事件做好。不要不好意思闭口申请更多的研发工夫,的确须要更多工夫就要及时汇报,不须要什么货色都本人默默背负着,搞得本人压力很大,不仅影响工作状态,还可能影响生存状态。 事件只做到这个水平的话,其实是有点搪塞的,做进去的货色不太能放得上台面。工夫长了,leader也能看进去,对本人的倒退倒退十分不利。 第二层境界--做完:高质量、高标准实现工作处于这个阶段的研发算是负责任的,起码实现的内容齐备稳固,能够良好地接入到以后的零碎中。 把事件做到这个水平只能说是比及格线略微高一丢丢,实现的内容算是能看了。执行者实现工作之后不会有太大的成就感,只会舒一口气。 leader对这类人地印象不好也不坏,只会感觉这是个还能干活的人。 第三层境界--做好:实现的内容质量上乘这个阶段的人不仅可能完完整整地把事件做完,还会被动为性能作出更多角度的思考,关注性能的长期倒退。 即便在大厂中,能把事件做到这个水平的人也不多。因为不止要把事件做完,还要额定思考更多的事件,如可维护性、扩展性、内存占率、cpu占用率、FPS。其实可能思考到其中一两点曾经很不错,我到当初也没有碰到可能把这些点全副思考到的研发。 可能有些研发认为本人思考到了,但那只是他认为,其实并没有。 例如可维护性,有些研发认为本人的代码写得十分好,但其实很多人都看不懂他的代码,而后他可能还会说:“不是都写得很分明了吗”。过了一段时间之后他本人都看不懂,而后他就会说:“必定有人改过我的代码了”,其实并没有人改过。。。 例如扩展性,有些研发认为本人的架构写得贼牛逼,感觉本人整了几个manager就很厉害,蜜汁自信。认真看一下他写的manager就会发现这几个manager之间的耦合度贼高,没有一个是能够独自运行的,这种并不叫封装,只能说是把本来的一坨代码强行拆开到多个模块中。 内存占用率、cpu占用率、FPS个别都是在性能实现之后再对立思考。在开发过程中也能够略微关注一下,然而不倡议投入太多精力,因为过早的优化并不见得是一件坏事。 诚实说,如果本人想做,又真的有足够的工夫为性能作多方面的思考,应该是很享受的一件事件。因为能够看着本人的性能变得越来越好,就像本人的孩子长大一样。 要想得心应手地解决好额定地事件,须要长期的积攒,厚积薄发。平时多浏览经典书籍,例如《计算组成原理》、《代码大全》等。 第四层境界--做对:实现的内容真的能解决用户的问题处于这一层的人会具备更强的主动性,具备主人翁精力,参加工作方向的决策。 实践上,把握工作方向这件事件应该由专门的共事负责,在游戏公司中就是策动。把握方向是策动的本职工作。他们必须要达到这个境界。因为方向不对,致力徒劳。 把握方向跟研发没有太大关系。然而咱们能够影响策动,对方向进行轻微的调整。如果在某些设定上,你和策动没有方法达成统一,而你动摇地认为策动地想法是不合理地。那能够和直属leader沟通给方向,某些状况下甚至能够请leader去和策动沟通。 一个差的研发只是做了客户须要他做的事。而一个好的研发发明了客户心愿他发明的价值,能够通过客户外表的语言帮客户找到深层次的需要是什么,而后提出一个更好的计划。咱们要发明价值而不是发明代码。 然而做这样一件事其实不容易被leader留神到,而且须要额定破费工夫。leader只能看到你在花工夫跟策动聊天,也不晓得你是在聊八卦还是聊闲事。 但我认为这件事是有意义的,因为这项工作的实现后果能不能被下级认可,很大水平上要看这个性能在游戏中的最终体现。如果最初体现不行,甚至这个性能最初不上线,代码写得再好,下级对你的评估也不会高。 你的苦劳能不能被抵赖,还得看功绩够不够。所以为了不做无用功,还是要多关注一下方向。当你的性能被一次次颠覆的时候,是很受打击的。因为没有什么成就感,在其他人看来,很多货色你做了跟没做一样。 这个阶段须要的是较强的沟通能力,可能和策动的思维碰撞出火花,然而又不会毁坏关系。能够学习一下沟通方面的常识,举荐《非暴力沟通》。 分明本人以后的能力定位是很重要的,这样能力晓得本人要往哪个方向去晋升。 你的反对是我创作的最大能源 点赞+珍藏,让更多人也能看到这篇内容关注我和专栏xxx,让咱们独特成长微信搜一搜「三年游戏人」关注这个有情怀的游戏人,文章继续更新,第一工夫浏览我是Rouder,一个有情怀的游戏制作者,专一分享游戏制作相干内容谢谢你的反对,咱们下期再见!

September 25, 2021 · 1 min · jiezi

关于游戏开发:游戏工程师成长三要想发展快只需要知道3个做事态度

凡事有交代,件件有着落,事事有回音咱们做的每一件事件都应该闭环,有头有尾。有时候leader可能只是简略跟你说要去做某件事情,不要因为说得比较简单而不器重它。 例如leader可能会发个截图过去跟你说:“这个地方性能有点问题,去跟进一下看看。”你可能会稍后找个工夫来查一下,确定问题之后就开始修复,提交代码的时候也没有给leader去review一下。 过了很长一段时间之后,leader纳闷怎么这么就都没有回应,是不是哪里卡住了不晓得怎么修 。于是被动来问你性能问题跟进得怎么样了。这时你有可能忘了修复的具体细节,或者阐明具体修复细节之后,leader看出了这个修复计划存在问题。这个时候就会给leader留下一种不靠谱的心里印象。 诚实说,要做到这一点挺不容易的。因为游戏行业的研发节奏自身就很快,平时开发压力很大,要顾上所有的事件不是一件简略的事件。然而无论无何,leader交代下来的事件要比其余事件更踊跃一点,单单是做到这一点,你的升迁速度就曾经快很多了。 前三年是成长最快的三年,工作工夫以外也要多花工夫晋升本人新人刚刚来到职场须要学习的货色还很多,有些技能以前在学校读书的时候没有意识到它的重要性。退职场工作的过程中会缓缓须要用到一些比拟重要的技能,当发现自己这一块技能程度存在有余时,就给本人布局好工夫去学习晋升。 工作工夫以外能够花点工夫去学习,能够利用晚期的工夫、午休工夫、上班后的工夫。当然不是要将这些工夫全副用上,能充分利用其中一个时间段就曾经很不错了。把本人逼得太紧,成果反而不太现实,娱乐工夫还是要有一点的。只会学习不游玩,聪慧孩子也变傻。 这样保持几年工夫下来会比不做这些事件会累很多,然而我感觉还是值得的。可能有人会说:“这跟加班有什么区别?工贼”我感觉差异很是很大的,加班的产出是给公司的,而常常时对本人成长晋升不大的内容。然而本人学习晋升失去的货色都是本人的,能够跟着你一辈子(不要说工夫长了把它搞忘了= =)。 置信我,只有能保持住,你的成长速度是飞快的。 不能只做一个杂家,要先做一个专家刚刚进入到职局面对浩如烟海的技术会顿感迷茫,不要想着一下子抓住所有的技术。咱们应该确定一个方向,这个确定过程能够是被动的,也能够是被动的。被动选本人喜爱的,被动选工作须要的。 锁定了方向之后,咱们要深刻学习这个方向的内容,要从原理下来理解做过的每一个货色,而不仅仅是满足于实现需要。同时也能够去学习其余技术点,随着主攻方向学习的深刻,你可能就会发现其实很多货色是相通的。缓缓地,你的技能树就会造成一超多强的局势。这时就成为了一个T型人才。 如果有一个确定的方向,在面临岔路口的时候就不会茫然,你会很动摇地抉择一个方向。这同样节俭了很多工夫。因为引诱还是很多的,每次做抉择都纠结很久的话会消耗很多心力,每个人每天的心力都是无限的,心力耗尽之后做事效率会降落很多。 欢送关注公众号「三年游戏人」,第一工夫浏览系列最新文章

September 22, 2021 · 1 min · jiezi

关于游戏开发:游戏工程师成长二-积极主动

人手永远是不够的,事件是永远做不完的很多人会认为工作都只能被安顿,这可能跟始终以来我的项目进度都比拟赶无关。每个工作都是由上头派发下来的,长此以往就会认为只能被动接受任务。然而其实是能够被动去找事件做的的。 人手永远是不够的,事件永远是做不完的,如果有本人想做的事件,不要想着等忙完以后的工作,我就去做。这样可能永远也等不到,因为工作会一个接着一个来,能够早点去申请本人想要的工作,或者本人发明工作(不是说去搞个问题进去,而是去发现问题,提出问题) 反正都是要打工,不如本人去找点有意思的事件做,这样起码死也要死在本人手里。 理解leader须要解决什么问题,本人能够帮上什么忙在实现了本人当前任务的状况下,能够被动去理解leader有什么问题须要解决(有些部门会有一个需要池),从中找到本人感兴趣又有肯定挑战性的工作承接下来。这样做的益处是,leader能够看到你的工作积极性,同时能够肯定水平上把握本人的倒退方向。 工夫长了,leader也会缓缓明确你想往哪个方向去倒退,日后leader安顿下来的工作也不会偏离本人心仪的方向太远。 理解共事的工作,拓展本人的知识面。说不定本人还能够帮到他们在有闲暇的时候能够关注一下共事的工作,能够在工作内容上进行比照,想想本人是否能够承接共事的工作。如果不能够,要如何晋升才能够承接。这样做还能够拓宽本人的知识面,晋升本人对技术的敏感度。 如果能够的话,还能够和共事一起进行探讨,为共事提供解决问题的思路。这样能够疾速拉近本人和共事之间的关系。 工作量较少的状况下,多理解业界中经典或前沿的技术,写写demo平时多抽点工夫理解业界的经典或者前沿技术,能够的话入手写写demo,有些常识只有真正实际过能力扎实把握。其实大部分公司是激励员工能够抽出工夫来学习的,这样做有利于工程师的长期成长。然而我待过的工作室很难让我抽出工夫来做这些事件,业务开发量过大。 体验公司的产品,比照竞品,提出改良点能够的话,要偶然被动体验下公司的产品,有些工作室会组织大家一起来体验产品。 像咱们做游戏的,体验产品其实就是玩游戏,在玩耍的过程中记录下有待改良的中央。能够进步本人对公司产品的了解水平,不便之后开发新内容时更好地匹配以后地设定。 尽管新需要匹配旧设定这样一件事件是游戏策动的职责,然而咱们还是多本人把关一下,算是对本人付出工夫的一种负责。其实接到的新需要和旧设定不匹配的状况还是不少的,可能是因为策动不停批改、多个策动提出改良意见,导致次要负责策动本人都记不清性能以后变成什么样了,然而咱们研发能够看代码精确把握性能的最新状况。 在体验产品的过程中,能够多个竞品比照一下。多想想他人的产品有哪些比咱们做得好的中央,能够将这些好的点记录下来。而后找工夫去钻研下他人是怎么做到的,咱们有没有可能向这个好的方向扭转。 如果适合的话,咱们就能够排期去优化咱们的产品。如果咱们能够始终向其余产品学习优良的点,咱们的产品就能够变得更好,集百家之所长。然而须要留神的是不要一味地模拟,不然最初咱们的产品可能变成一只缝合怪。 如果有我想做或须要做的事件,就去踊跃推动尽管咱们是个打工人、新时代的农名工,但如果咱们有本人想做的事件,能够被动承接,甚至发动自主工作去解决本人在我的项目中发现的问题。不必始终被动地接受任务,否则你会常常接到你不喜爱的工作,这样无论是实现工作的效率还是对于本人的晋升可能都不会很高。 因为主动性不够强,工作常常只能做到做完的水平,而没有做好。能做到被动承接工作能够给leader留下一个敢于担当的好印象,这是领导力的一种侧面体现。 能做到被动发动自主工作,能够看出这个工程师长于发现我的项目中的潜在问题,洞察力强,这是工程能力的一种体现。在积极主动执行一项工作的时候,工程师可能会暴发本人的小宇宙,最终把工作实现到做好的水平。

September 16, 2021 · 1 min · jiezi

关于游戏开发:思维引导村棍游戏测试员方向规划

作为一个刚入门的测试员,必须要当初思维上达到测试,能力找出绝对的BUG。 1、逆向思维形式 · 逆向思维在测试中用的很多,比方将依据后果逆推条件,从而得出输出条件的等价类划分 · 其实逆向思维在调试当中用到的也比拟多,当发现缺点时,进一步定位问题的所在,往往就是逆流而上,进行剖析 · 逆向思维是绝对的,就是依照与惯例思路相同的方向进行思考,测试人员往往可能使用它发现开发人员思维的破绽 2、组合思维形式 · 很多货色繁多的思考都没有问题,当将相干的事物组合在一起却能发现很多问题;如多过程并发,让程序的复杂度上了一个台阶,也让程序的缺陷率随之而增长 · 依照是否排序组合能够分为:排列(有序)和组合(无序);针对不同的利用,能够酌情思考应用“排列”或者“组合” · 为了充分利用组合思维而不致于让本人的思维混乱,要留神“分维”,将相干的因素划分到不同的维度上,而后再思考其相关性 3、全局思维形式 · 事物往往存在多面性,当咱们把握了越多的层面,咱们对它的意识就越分明,越有利于咱们把握其本质,全局思维形式就是让咱们从多角度剖析待测的零碎;试着以不同角色去看零碎,剖析其是否可能满足需要 · 其实平时咱们在软件开发过程中,进行的各种评审,就是借助全局思维的形式,让更多的人参加思考,脑力激荡,尽可能的实现全方位审查某个解决方案的正确性以及其余个性 4、两极思维形式 · 边界值剖析是两极思维形式的榜样 · 为了看零碎的稳定性,咱们采纳了压力测试 · 两极思维形式,是在极其的状况下,看是否存在缺点? · 留神是两极,不是一极 · 测试人员做久了,往往容易走极端——职业病,不利于与人沟通 5、简略思维形式 · 剥离一些非关键特色,追赶事物的实质,让事物简略的只剩下“基本” · 针对事物本质(解决问题的实质)的测试,让咱们不至于偏离方向 6、比拟思维形式 · 意识事物时,人们往往都是通过和头脑中的某些概念进行比拟,找出雷同、相异之处,或者归类,从而将其退出大脑中的常识体系,可能的话,再建设好的搜寻形式,以便当前应用 · 利用模式是“比拟思维”很常见的例子,当初模式很火,有设计模式、体系结构模式、测试模式、等等,一些专家针对一些相干问题的共性找进去的解决办法,取完名字后,能够让大家不便的复用 · 让教训在这里发挥作用,测试中教训很重要,比拟思维是应用教训的形式 7、动起来,让测试这个村棍游戏更精彩 · 关注程序的运行时状态,比方http://www.cungun.com这个动态网址 · 传统的基于构造的程序能够更多的在代码中反映未来程序的运行形式;而面向对象将代码和运行时显著拆散 · 让咱们在关注代码动态构造(如类构造)的同时,也要审慎关注其动静(对象交互网)体现 其实这些思维形式,大家都在无意识或者有意识的应用着,它们各自都有本人的妙处,将咱们的思维发散,无意识的将他们用在问题的思考上,有时能够给咱们一种“柳暗花明又一村”的感觉

August 30, 2021 · 1 min · jiezi

关于游戏开发:机会痛点难点中国游戏泛娱乐企业出海攻略全解析

8月26日 19:00邀您观看环信第55期线上公开课《机会!痛点!难点!中国游戏泛娱乐企业出海攻略全解析》,一起摸索出海新生代中国游戏泛娱乐企业出海攻略全解析。锁定环信公开课直播间,看直播同时还能抽取惊喜好礼! 疫情期间,在“宅经济”的影响下,游戏泛娱乐企业出海浪潮席卷全行业,寰球陌生人社交市场将来五年无望达到千亿美金规模;中国开发商在海内游戏市场份额已跃升至世界第一,达到23.4%;出海创业者曾经获得斐然成就,市场广大,云服务厂商也纷纷推出合规平安等海内服务,为创业者赋能。以即时通讯、实时音视频为根底的社交、游戏、直播等泛娱乐行业迎来了出海守业的策略机遇期。 国内流量红利褪去,各赛道竞争均呈红海之势,寰球泛娱乐行业“风口”正起。着眼当下,出海企业如何在当下时点抓住机遇,乘风而起呢?本次公开课将面向游戏泛娱乐行业从业人员及开发者们,分享环信在游戏泛娱乐畛域的技术实际,与大家独特探讨落地难题及行业倒退机会,邀您来一次不一样的思维碰撞! 流动详情 本期主题:机会!痛点!难点!中国游戏泛娱乐企业出海攻略全解析 直播工夫:8月26日(周四)19:00-20:00 报名地址:https://mudu.tv/live/watch?id... 听众收益 1、理解出海游戏、社交行业的现状; 2、游戏、社交行业有哪些赛道、产品值得特地关注?都具备什么样的特点? 3、中国企业出海进入“合规双向时代”,有哪些细节须要特地留神? 4、将来的出海之路中可能存在哪些“暗礁”须要防止? 5、在现有的玩法根底上,游戏/社交企业出海能够尝试做怎么的翻新? 福利流动 合作伙伴

August 17, 2021 · 1 min · jiezi

关于游戏开发:HMS-Core-Sparkle游戏应用创新沙龙诚邀您参与

流动简介随着互联网基础设施的欠缺和“宅经济”效应凸显,游戏行业逆势上扬,迎来微小消费市场。同时,用户需要更加多样化,如何进一步翻新和技术升级、晋升外围竞争力已成为游戏开发与经营的重要课题。 HMS Core. Sparkle翻新沙龙,是华为围绕各畛域挪动利用开发的翻新解决方案以及HMS Core的差异化能力,为利用开发者提供摸索交换的平台,以洞察挪动利用发展趋势,使能开发者利用开发、用户增长及商业胜利。目前已陆续围绕金融、影音娱乐、社交等畛域在各大城市开展了沙龙流动,赋能行业倒退。 面向游戏畛域,HMS Core. Sparkle游戏利用翻新沙龙将于2021年 8月1日在上海举办。本次沙龙以“智玩新体验 游戏新风向”为主题,围绕3D图形、网络减速、精准经营等话题与泛滥游戏行业搭档进行交换,独特探讨技术驱动下的游戏翻新,助力游戏行业晋升开发和经营效率。此外,华为还将介绍HMS生态及HMS Core凋谢能力停顿,期待与更多合作伙伴同行,实现生态共赢。 报名形式点击上方图片报名,或点击此处到官网报名>> 理解更多相干内容拜访华为开发者联盟官网获取开发领导文档华为挪动服务开源仓库地址:GitHub、Gitee关注咱们,第一工夫理解 HMS Core 最新技术资讯~

July 22, 2021 · 1 min · jiezi

关于游戏开发:游戏中的图像识别CV的新战场

概述CV(Computer Vision)在事实世界的利用绝对比拟胜利,如日常生活中的人脸识别,车牌辨认,指纹比对,电子稳像,行人,车辆的跟踪,等等。那么在其余畛域呢,比方大家常玩的手机游戏,CV又能够有哪些利用呢?游戏场景的图像和事实场景的图像还是有差异的,有些游戏的场景绝对比较复杂,如特效烦扰、游戏人物不似真人一样有规定,艺术字体也不像车牌一样字体固定,并且有对立底色等等;有些元素是绝对比较简单的,如游戏中的固定地位的固定图标等等。简略的游戏元素能够用传统图像检测的办法,也能够获得比拟好的成果。本篇文章,将率领大家一起剖析常见的游戏场景的辨认。 1. 解决流程游戏场景的辨认能够次要分为两个模块,GameClient和CVServer, GameClient模块负责从手机或是PC端实时获取图像,并转发给CVServer。CVServer解决收到的游戏图像,后果返给Game Client。Game Client依据需要进一步解决后,再反馈给游戏端。流程如图1所示。图1游戏场景辨认主流程 2. 利用举例上一大节次要跟大家分享了游戏场景辨认的次要流程,这一大节咱们将次要剖析图像识别在游戏中的利用。 2.1 游戏状态的确定每个游戏UI称为一个游戏状态。游戏可被认为有很多不同的UI组成。先建设好这些UI的样本库,实时获取一张游戏画面时,比对以后的图像和样本图像,可判断出以后的游戏状态。比对两张图像是否类似的办法很多,这里咱们以特色点匹配为例,次要步骤如下: Step1:样本图像的特色点提取,测试图像的特色点匹配图2特色点提取 Step2:特色点匹配图3特色点匹配 Step3:匹配筛选图4依据ratio-test进行匹配筛选 ORB特色点匹配是绝对比拟成熟的技术。在采集到的测试数据集中,会因为手机分辨率,刘海或渲染的不同,导致图像的大小或UI渲染地位等差别比拟大,罕用的模板匹配很难适配这种状况。基于特色点的匹配计划则不会存在这种状况,特色点个别是指图像中的角点,或是显著点。跟图像中物体元素所在的地位和大小关系不显著,所以适用性更强。ORB特色点是将FAST特色点的检测办法与BRIEF特征描述子联合起来,并在它们原来的根底上做了改良与优化。ORB特色点具备旋转不变性和尺度不变性。上面别离介绍特色点提取、特色点形容、特色点匹配和特色点筛选。 2.1.1 特色点提取:FAST FAST的根本思维,若某像素p与其四周邻域内(1到16),足够多的像素点相差较大,则该像素可能是角点。原始的FAST特色点是没有尺度不变性的,OPENCV中的ORB的实现通过构建高斯金字塔,而后在每一层金字塔图像上检测角点,来实现尺度不变性。原始的FAST也不具备方向不变性,ORB的论文中提出了一种利用灰度质心法来解决这个问题。对于任意一个特色点p来说,定义p的邻域像素的矩为,其中 I(x,y)为点(x,y)处的灰度值,图像的质心为:,特色点和质心的夹角,即为FAST特色点的方向:图5 FAST 特色点图示(图像来自论文:Faster and better: A machine learning approach to corner detection) 2.1.2 特色点形容:BRIEF BRIEF算法的核心思想是在关键点P的四周以肯定的形式选取N个点对,而后把这N个点对的比照后果组合成一个长度为n的二值码串,作为该关键点的形容子。ORB在计算BRIEF形容子的时候,建设的坐标系是以关键点为圆心,以特色点P和取点区域的质心(Q)的连线为X轴建设的二维坐标系。圆心是固定的,以PQ为x轴坐标,垂直方向为y轴坐标,在不同的旋转角度下,同一特色点取出来的点对是统一的,这就解决了旋转一致性的问题。 2.1.3 特色点匹配:Hamming Distance 两个等长二进制串的汉明间隔是两个二进制串对应地位的不同字符的个数。ORB中用Hamming Distance来掂量两个形容子之间的间隔。 2.1.4 特色点筛选:Ratio-Test Ratio-Test用来剔除间隔比例(最近邻间隔/第二近邻间隔)近似的含糊匹配点对。这里应用一个参数ratio来管制剔除间隔比例在肯定范畴之外的特色点。由下图所示,可知ratio为0.75左右时,能够把正确匹配和谬误匹配状况的最好的拆散。图 7 最近邻间隔和第二近邻间隔的ratio图,实线为匹配正确时的ratio的pdf,虚线为谬误匹配时的ratio的pdf。图像来自论文:D. G. Lowe. Distinctive imagefeatures from scale-invariant keypoints, 2004 2.2 场景覆盖率 基于特色点匹配的办法,也可用在场景覆盖率的利用上。首先是加载外围场景的模板图像,AI在运行过程中会采集大量的游戏运行中的游戏截图。基于这些游戏截图造成的测试数据集,遍历每一张测试数据集,别离基于局部图像的特色点算法匹配外围场景图像和测试图像,全图像的特色点匹配办法匹配外围场景图像和测试图像,最终筛选出匹配后果,过滤失去匹配到的外围场景的图像。通过匹配到的外围场景的图像和数目,揣测AI运行过程中的场景笼罩状况。 2.3 游戏中数字的辨认 游戏中的数字图像很多,如关卡数,得分数,倒计时数等,咱们能够基于CNN的办法对数字进行辨认。基于CNN的分类办法很早就被提出,晚期比拟经典的CNN网络是1998年提出的Lenet网络,Lenet网络采纳2层卷积,2层池化层,2层全连贯层,最初一层softmax层组成。输出的是数字图像,输入的是数字图像的类别。图 6 Lenet网络 咱们能够先对全数字图像进行宰割,宰割成一个一个独立的数字,而后通过Lenet网络对每一个数字图像进行预测,输入的数字图像类别即为辨认出的数字,最初再对全数字进行组装,失去最初的全数字辨认后果。图 7 数字辨认过程 随着网络结构加深,卷积性能的增强,以及GPU和大数据带来的历史时机,CNN近些年出现爆炸式倒退。而且CNN不仅用于分类,还能够用来对物体检测,即最初一层由原来的输入物体的类别,到输入物体在图像中的地位和在此地位处的物体的类别。咱们能够采纳折中速度和准确度的算法YOLOV3,并基于工程的图像特色,基于缩小网络层个数和缩小特色图个数两个方向去优化网络,近一步优化网络速度。图 9 数字辨认和重组的过程 2.4 固定地位固定图标的辨认 模板匹配的利用很多,咱们就固定按钮的辨认,提示信息的辨认,卡住状态的检测这三个方面举例说明。游戏主界面中,英雄的技能,配备,操作键等这些按钮个别都是在固定地位。提取按键为可用状态时的按钮图标作为模板,实时获取的游戏界面检测到模板,检测到就阐明以后这个按钮可用。游戏AI获取这些按键的信息后,即可采取相应的策略,如开释技能,购买配备等。游戏提示信息也是相似,游戏界面中固定地位呈现一些提示信息,如图7中显示的路线批示信息,游戏完结状态(胜利/失败)等,游戏运行状态(开始)等。咱们先采集这些提示信息呈现的地位,以及这些提醒图标模板,在游戏实时运行过程中,在呈现的地位处,实时匹配是否和采集的图标模板匹配,如果匹配到了,阐明以后呈现了此提示信息。如匹配到游戏胜利图标,则在此局中的AI策略应该给予处分,相同应该给予惩办等。图 10 固定Button的辨认图 11 游戏提醒图标的辨认 ...

July 20, 2021 · 1 min · jiezi

关于游戏开发:1-猜密码游戏

题目1、编程实现猜明码游戏,要求如下:(1) 预置字符串Passtr=”0123456789abcdefghijklmnopqrstuvwxyz”。(2) 编写明码生成函数code(str,n)``从字符串str中随机挑选出6个字符生成6位明码。(3) 调用code()函数从预置的字符串中生成6位明码(4) 用户通过键盘输入所猜明码。如果明码输出正确,显示“明码正确”,完结程序;如果明码输出谬误,显示“明码谬误,从新输出明码进行验证。(预置3次机会) #encoding=utf-8*encoding=utf-8意思是编码格局为UTF-8格局from random import *Passtr="0123456789abcdefghijklmnopqrstuvwxyz"#预置的字符串def code(str): #生成6位明码 Pas=""#空字符串 for i in range(6): Pas += str[randint(0, len(str) - 1)]#随机筛选6个字符造成明码 return Pas#循环断定明码输出的正确与否Pas=code(Passtr)print(Pas)#这一句删掉不影响程序运行for Count in range(1,4): Guess=input("输出猜的明码:") if Guess==Pas: print("明码正确") break else: print("明码谬误,你还有{}次机会".format(3-Count))print("游戏完结!")

July 9, 2021 · 1 min · jiezi

关于游戏开发:protobuf三个关键字requiredoptionalrepeated的理解

required关键字顾名思义,就是必须的意思,数据发送方和接管方都必须解决这个字段,不然还怎么通信呢 optional关键字字面意思是可选的意思,具体protobuf外面怎么解决这个字段呢,就是protobuf解决的时候另外加了一个bool的变量,用来标记这个optional字段是否有值,发送方在发送的时候,如果这个字段有值,那么就给bool变量标记为true,否则就标记为false,接管方在收到这个字段的同时,也会收到发送方同时发送的bool变量,拿着bool变量就晓得这个字段是否有值了,这就是option的意思。 这也就是他们说的所谓平滑降级,无非就是个兼容的意思。 其实和传输参数的时候,给出数组地址和数组数量是一个情理。 repeated关键字字面意思大略是反复的意思,其实protobuf解决这个字段的时候,也是optional字段一样,另外加了一个count计数变量,用于表明这个字段有多少个,这样发送方发送的时候,同时发送了count计数变量和这个字段的起始地址,接管方在承受到数据之后,依照count来解析对应的数据即可。

July 7, 2021 · 1 min · jiezi

关于游戏开发:数据结构实践项目之俄罗斯轮盘赌小游戏

俄罗斯轮盘赌,想必很多人都据说过,一种仁慈的游戏。游戏的道具是一把左轮手枪,其规定也很简略:在左轮手枪中的 6 个弹槽中随便放入一颗或者多颗子弹,在任意旋转转轮之后,关上转轮。游戏的参加者轮流把手枪对着本人,扣动扳机:中枪或是怯场,即为输的一方;保持到最初的即为胜者。 本节实际我的项目同轮盘赌相似,游戏规则:n 个参加者排成一个环,每次由主持向左轮手枪中装一颗子弹,并随机转动关上转轮,游戏从第一个人开始,轮流拿枪;中枪者退出赌桌,退出者的下一个人作为第一人开始下一轮游戏。直至最初残余一个人,即为胜者。要求:模仿轮盘赌的游戏规则,找到游戏的最终胜者。 设计思路 解决相似的问题,应用线性表的顺序存储构造和链式存储构造都能实现,依据游戏规则,在应用链式存储构造时只需应用循环链表即可轻松解决问题。顺序存储构造模仿轮盘赌采纳顺序存储构造时,同样要在脑海中将数组的首尾进行连贯,即当须要从数组中最初一个地位寻找下一个地位时,要可能跳转到数组的第一个地位。 #include <stdio.h>#include <stdlib.h>#include <time.h>typedef enum {false,true} bool; typedef struct line{ int No; struct line * next;}line; //依照赌徒人数,初始化循环链表void initLine(line ** head,int n){ *head=(line*)malloc(sizeof(line)); (*head)->next=NULL; (*head)->No=1; line * list=*head; for (int i=1; i<n; i++) { line * body=(line*)malloc(sizeof(line)); body->next=NULL; body->No=i+1; list->next=body; list=list->next; } list->next=*head;//将链表成环}//输入链表中所有的结点信息void display(line * head){ line * temp=head; while (temp->next!=head) { printf("%d ",temp->No); temp=temp->next; } printf("%d\n",temp->No);} int main() { line * head=NULL; srand((int)time(0)); int n,shootNum,round=1; printf("输出赌徒人数:"); scanf("%d",&n); initLine(&head,n); line* lineNext=head;//用于记录每轮开始的地位 //仅当链表中只含有一个结点时,即头结点时,退出循环 while (head->next!=head) { printf("第 %d 轮开始,从编号为 %d 的人开始,",round,lineNext->No); shootNum=rand()%n+1; printf("枪在第 %d 次扣动扳机时会响\n",shootNum); line *temp=lineNext; //遍历循环链表,找到将要删除结点的上一个结点 for (int i=1; i<shootNum-1; i++) { temp=temp->next; } //将要删除结点从链表中删除,并开释其占用空间 printf("编号为 %d 的赌徒退出,残余赌徒编号顺次为:\n",temp->next->No); line * del=temp->next; temp->next=temp->next->next; if (del==head) { head=head->next; } free(del); display(head); //赋值新一轮开始的地位 lineNext=temp->next; round++;//记录循环次数 } printf("最终胜利的赌徒编号是:%d\n",head->No); return 0;}

July 7, 2021 · 1 min · jiezi

关于游戏开发:手把手教你用MATLAB制作一款-狗头翻牌子-小游戏点灯游戏

0 游戏成果就是点击一个牌子时,该牌子和四周四个牌子也会相应发生变化,想方法让所有牌子都在同一面即为游戏胜利。1 fig界面和背景板这一段比较简单,次要是对界面和背景板的属性设置,咱们采纳编程的形式调用app designer控件: ddooggFig=uifigure('units','pixels',... 'position',[320 120 360 400],... 'Numbertitle','off',... 'menubar','none',... 'resize','off',... 'name','ddoogg',... 'color',[0.98 0.98 0.98]);bkgLabel=uilabel(ddooggFig);bkgLabel.Position=[10 10 340 340];bkgLabel.Text='';bkgLabel.BackgroundColor=[193 214 232]./255;2 狗狗牌子与胜利标记2.1 狗狗牌子绘制咱们用1代表一种狗狗,2代表另一种狗狗,dogMat一开始全为1示意所有牌子上都是第一种狗狗,imgSource代表两种狗狗图片地位,bkgColor代表狗狗卡牌的背景色彩 dogMat=ones(5,5); %数据矩阵imgSource={'images\doga.png','images\dogb.png'}; %狗狗图片链接bkgColor=[[252 251 238]./255;[222 248 252]./255];%狗狗图背景色彩应用两层for循环算好地位结构控件: %绘制5x5个uiimage控件for i=1:5 for j=1:5 dogMatHdl(i,j)=uiimage(ddooggFig); dogMatHdl(i,j).Position=[20+65*(j-1),280-65*(i-1),60,60]; dogMatHdl(i,j).ImageSource=imgSource{1}; dogMatHdl(i,j).BackgroundColor=bkgColor(1,:); dogMatHdl(i,j).UserData=[i,j]; endend留神咱们为每个图片设置一个UserData属性,这能够示意图片的地位,不便咱们之后辨认点击的是哪个图片。!2.2 游戏胜利标签绘制一个标签显示游戏胜利: %获胜标签win=false; %是否实现游戏winLabel=uilabel(ddooggFig);winLabel.Position=[15 150 330 60];winLabel.Text='祝贺你解出谜题,请点击从新开始';winLabel.BackgroundColor=[238 236 225]./255;winLabel.FontSize=19;winLabel.FontWeight='bold';winLabel.HorizontalAlignment='center';winLabel.FontColor=[113 106 63]./255;游戏一开始标签式是暗藏的赢了之后才会显示进去,因而咱们先将标签暗藏: winLabel.Visible='off';2.3 鼠标点击牌子回调 %创立uiimage回调set(dogMatHdl,'ImageClickedFcn',@clickDog) function clickDog(~,event) if ~win %游戏赢了不做任何操作 objNum=event.Source.UserData; %点击事件的起源图片的UserData属性,与图片地位相干 crossList=[-1 0;0 1;1 0;0 -1;0 0]; %点击地位上下左右和本身 for ii=1:5 changePos=crossList(ii,:)+objNum;%要扭转的牌子的地位 if all(changePos>=1&changePos<=5)%如果该地位在范畴内,扭转图片显示和数据矩阵 dogMat(changePos(1),changePos(2))=mod(dogMat(changePos(1),changePos(2)),2)+1; dogMatHdl(changePos(1),changePos(2)).ImageSource=imgSource{dogMat(changePos(1),changePos(2))}; dogMatHdl(changePos(1),changePos(2)).BackgroundColor=bkgColor(dogMat(changePos(1),changePos(2)),:); end end %如果所有卡牌都一样,游戏完结 if all(all(dogMat==1))||all(all(dogMat==2)) win=true; winLabel.Visible='on'; end end end3 游戏难度按钮组3.1 按钮绘制绘制三个按钮,初始 [高级] 按钮为被选中状态,即难度等级为一级,咱们将gameLevel设置为1,并将 [高级] 按钮色彩和其余按钮做辨别,示意被选中状态: ...

July 2, 2021 · 2 min · jiezi

关于游戏开发:1-猜密码游戏

题目1、编程实现猜明码游戏,要求如下:(1) 预置字符串Passtr=”0123456789abcdefghijklmnopqrstuvwxyz”。(2) 编写明码生成函数code(str,n)``从字符串str中随机挑选出6个字符生成6位明码。(3) 调用code()函数从预置的字符串中生成6位明码(4) 用户通过键盘输入所猜明码。如果明码输出正确,显示“明码正确”,完结程序;如果明码输出谬误,显示“明码谬误,从新输出明码进行验证。(预置3次机会) #encoding=utf-8*encoding=utf-8意思是编码格局为UTF-8格局from random import *Passtr="0123456789abcdefghijklmnopqrstuvwxyz"#预置的字符串def code(str): #生成6位明码 Pas=""#空字符串 for i in range(6): Pas += str[randint(0, len(str) - 1)]#随机筛选6个字符造成明码 return Pas#循环断定明码输出的正确与否Pas=code(Passtr)print(Pas)#这一句删掉不影响程序运行for Count in range(1,4): Guess=input("输出猜的明码:") if Guess==Pas: print("明码正确") break else: print("明码谬误,你还有{}次机会".format(3-Count))print("游戏完结!")

July 1, 2021 · 1 min · jiezi

关于游戏开发:从零开发一个灰太狼游戏是什么样的体验

先上一张效果图:开发思路开发一个游戏,首先你须要晓得游戏的规定。 这个游戏名为狂拍灰太狼。 规定: 游戏工夫 60 s游戏角色为灰太狼、小灰灰拼手速殴打灰太狼殴打灰太狼 + 10 分,殴打小灰灰 - 10 分开发技术 htmlcssjq实现思路 1.利用 html + css 布局游戏界面2.导入 jq 库3.实现狂拍灰太狼游戏逻辑外围逻辑 封装 60 s 进度条办法封装解决灰太狼动画的办法游戏按钮点击监听 HTML代码<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>狂拍灰太狼</title> <link rel="stylesheet" href="css/index.css"> <script src="js/jquery-1.12.4.js"></script> <script src="js/index.js"></script></head><body><div class="container"> <h1 class="score">0</h1> <div class="progress"></div> <button class="start">开始游戏</button> <div class="rules">游戏规则</div> <div class="rule"> <p>游戏规则:</p> <p>1.游戏工夫:60s</p> <p>2.拼手速,殴打灰太狼+10分</p> <p>3.殴打小灰灰-10分</p> <a href="#" class="close">[敞开]</a> </div> <div class="mask"> <h1>GAME OVER</h1> <button class="reStart">从新开始</button> </div></div></body></html>css 代码*{ margin: 0; padding: 0;}.container{ width: 320px; height: 480px; background: url("../images/game_bg.jpg") no-repeat 0 0; margin: 50px auto; position: relative;}.container>h1{ color: white; margin-left: 60px;}.container>.progress{ width: 180px; height: 16px; background: url("../images/progress.png") no-repeat 0 0; position: absolute; top: 66px; left: 63px;}.container>.start{ width: 150px; line-height: 35px; text-align: center; color: white; background: linear-gradient(#E55C3D,#C50000); border-radius: 20px; border: none; font-size: 20px; position: absolute; top: 320px; left: 50%; margin-left: -75px;}.container>.rules{ width: 100%; height: 20px; background: #ccc; position: absolute; left: 0; bottom: 0; text-align: center;}.container>.rule{ width: 100%; height: 100%; background: rgba(0,0,0,0.5); position: absolute; left: 0; top: 0; padding-top: 100px; box-sizing: border-box; text-align: center; display: none;}.rule>p{ line-height: 50px; color: white;}.rule>a{ color: red;}.container>.mask{ width: 100%; height: 100%; background: rgba(0,0,0,0.5); position: absolute; left: 0; top: 0; padding-top: 200px; box-sizing: border-box; text-align: center; display: none;}.mask>h1{ color: #ff4500; text-shadow: 3px 3px 0 #fff; font-size: 40px;}.mask>button{ width: 150px; line-height: 35px; text-align: center; color: white; background: linear-gradient(#74ACCF,#007DDC); border-radius: 20px; border: none; font-size: 20px; position: absolute; top: 320px; left: 50%; margin-left: -75px;}jq 代码$(function () { // 1.监听游戏规则的点击 $(".rules").click(function () { $(".rule").stop().fadeIn(100); }); // 2.监听敞开按钮的点击 $(".close").click(function () { $(".rule").stop().fadeOut(100); }); // 3.监听开始游戏按钮的点击 $(".start").click(function () { $(this).stop().fadeOut(100); // 调用解决进度条的办法 progressHandler(); // 调用解决灰太狼动画的办法 startWolfAnimation(); }); // 4.监听从新开始按钮的点击 $(".reStart").click(function () { $(".mask").stop().fadeOut(100); // 调用解决进度条的办法 progressHandler(); // 调用解决灰太狼动画的办法 startWolfAnimation(); }); // 定义一个专门解决进度条的办法 function progressHandler() { // 从新设置进度条的宽度 $(".progress").css({ width: 180 }); // 开启定时器解决进度条 var timer = setInterval(function () { // 拿到进度条以后的宽度 var progressWidth = $(".progress").width(); // 缩小以后的宽度 progressWidth -= 1; // 从新给进度条赋值宽度 $(".progress").css({ width: progressWidth }); // 监听进度条是否走完 if(progressWidth <= 0){ // 敞开定时器 clearInterval(timer); // 显示从新开始界面 $(".mask").stop().fadeIn(100); // 进行灰太狼的动画 stopWolfAnimation(); } }, 100); } var wolfTimer; // 定义一个专门解决灰太狼动画的办法 function startWolfAnimation() { // 1.定义两个数组保留所有灰太狼和小灰灰的图片 var wolf_1=['./images/h0.png','./images/h1.png','./images/h2.png','./images/h3.png','./images/h4.png','./images/h5.png','./images/h6.png','./images/h7.png','./images/h8.png','./images/h9.png']; var wolf_2=['./images/x0.png','./images/x1.png','./images/x2.png','./images/x3.png','./images/x4.png','./images/x5.png','./images/x6.png','./images/x7.png','./images/x8.png','./images/x9.png']; // 2.定义一个数组保留所有可能呈现的地位 var arrPos = [ {left:"100px",top:"115px"}, {left:"20px",top:"160px"}, {left:"190px",top:"142px"}, {left:"105px",top:"193px"}, {left:"19px",top:"221px"}, {left:"202px",top:"212px"}, {left:"120px",top:"275px"}, {left:"30px",top:"295px"}, {left:"209px",top:"297px"} ]; // 3.创立一个图片 var $wolfImage = $("<images src='' class='wolfImage'>"); // 随机获取图片的地位 var posIndex = Math.round(Math.random() * 8); // 4.设置图片显示的地位 $wolfImage.css({ position: "absolute", left:arrPos[posIndex].left, top:arrPos[posIndex].top }); // 随机获取数组类型 var wolfType = Math.round(Math.random()) == 0 ? wolf_1 : wolf_2; // 5.设置图片的内容 window.wolfIndex = 0; window.wolfIndexEnd = 5; wolfTimer = setInterval(function () { if(wolfIndex > wolfIndexEnd){ $wolfImage.remove(); clearInterval(wolfTimer); startWolfAnimation(); } $wolfImage.attr("src", wolfType[wolfIndex]); wolfIndex++; }, 300); // 6.将图片增加到界面上 $(".container").append($wolfImage); // 7.调用解决游戏规则的办法 gameRules($wolfImage); } function gameRules($wolfImage) { $wolfImage.one("click",function () { // 批改索引 window.wolfIndex = 5; window.wolfIndexEnd = 9; // 拿到以后点击图片的地址 var $src = $(this).attr("src"); // 依据图片地址判断是否是灰太狼 var flag = $src.indexOf("h") >= 0; // 依据点击的图片类型增减分数 if(flag){ // +10 $(".score").text(parseInt($(".score").text()) + 10); }else{ // -10 $(".score").text(parseInt($(".score").text()) - 10); } }); } function stopWolfAnimation() { $(".wolfImage").remove(); clearInterval(wolfTimer); }});最终成果根本制作过程不是很难,外围是了解其中的业务逻辑。 ...

June 29, 2021 · 3 min · jiezi

关于游戏开发:GUI开发那点事

 每个项目组的GUI开发流程都不太雷同。有些项目组的流程十分落后,根本没有框架设计,都是间接代码设置UI控件,不利于迭代。做的比拟好的会采纳MVC相干模式进行设计,上面也只讲应用了MVC的工作流程。C由客户端同学负责实现。V由GUI同学进行制作。M和V的连贯工作在现实的状况下应该也是由GUI同学进行设置,然而因为上手有些难度,没有很好地落地,所以这块最终由客户端同学进行设置。  总体来看,GUI开发流程分为以下几个阶段。 策动会先提出界面需要,客户端程序须要认真浏览需要文档,确保需要是残缺。因为我之前遇到过策动给出不残缺的需要文档,需要前后矛盾、需要细节失落、需要模糊不清。有一次特地离谱,商城需要文档居然不给出具体的数值设计。在需要不残缺的状况下就开始做性能的工作效率是很低的,须要一边做一边问策动,有时候一个问题要半天工夫策动能力给回答。千万不要在需要不残缺的状况下开展前面的工作,跟策动和PM提了之后没有理睬就提多几次。肯定要让策动和PM器重后期布局工作,不然前面就会变成策动想到什么就做什么,想到一点内容就加一点内容进入,加到最初发现和后面的货色有点矛盾,又删除后面的内容。这会带来不必要的工夫节约,在极其状况下可能要颠覆重来。  需要明确之后就由GUI同学输入效果图。  等策动确认成果之后,客户端同学也要来看一下效果图。看看有没有比拟奇怪的成果,对这些成果进行探讨,确定实现计划或者换成果。如果界面比较复杂,须要跟GUI同学对一下层级构造。  进行界面资源输入。一般来说,界面资源输入工作交给GUI同学来负责,然而有些我的项目会将这个工作交给客户端同学。已经待过的一个项目组就是这么干的,须要将一张半透的效果图叠在界面最上层,一点一点的拼出来。有时一个界面能够拼一天,眼睛要爆炸,我都不晓得我是程序还是GUI了。无论是由谁来输入,都须要留神一下UI控件的命名,不要应用a、b、c、1、2、3之类的名字。最好能够表白出这个UI控件的类型、作用,比方LoginBtn代表这是个按钮,点击之后开始登录。 客户端同学拿到界面资源之后,首先须要做的事件是查看UI控件摆放的层级构造是否正当。层级构造能够依照区域或者功能模块来划分,这么做的益处是能够疾速定位到本人想要的UI控件,之后做UI资源迭代会轻松很多。个别一个界面的UI控件量都不会很少,即便结尾很少,随着性能、成果的迭代优化也会变得越来越多。如果没有解决好UI控件摆放的层级构造,做资源迭代时寻找资源会让你狐疑人生的。  UI界面资源解决好之后,就能够开始进行数据绑定工作了。这个过程须要将V和M关联起来,个别都会提供可视化编辑工具,不须要写代码。所以这项工作其实GUI同学也能够做的。然而因为数据绑定须要对业务需要有更深刻的了解,大部分GUI同学都会感觉这不是他们应该做的内容,他们应该只负责输入难看的、满足性能需要的界面。如果能够由GUI同学来负责设置的话,客户端程序能够同步开始写业务逻辑代码,生产速度会更快。然而这要做好后期沟通的工作,确保大家对数据的认知是保持一致的,这个沟通的工作可能也要花费工夫。综合来看,这项工作还是交给客户端程序来解决会比拟好。  客户端程序这个时候就能够开始写逻辑代码了。这里须要恪守一个准则,既然都应用了MVC框架,就不容许通过通过代码间接操作UI控件,只容许批改UI控件对应的绑定数据。在实现性能的过程中个别也不能够在批改UI界面的款式。如果非要批改,在改变比拟小的状况下能够客户端程序本人改一下,而后让GUI同学过去确认下。如果改变比拟大,就间接交给GUI同学进行批改。GUI开发工作整体难度不大,只有踊跃沟通就好。一般来说,如果开发工夫超出预期,大部分都是因为开发过程中呈现了莫名微妙的Bug,由UI框架设计引起。针对这种状况,如果容易修复的bug能够间接进行修复。比拟难修复的bug能够记录到一个专门的文档中。不便他人遇到同样的问题时能够疾速找到解决方案,晋升整体的开发效率,也作为之后修复bug的checklist。

June 29, 2021 · 1 min · jiezi

关于游戏开发:UE5渲染技术简介Nanite篇

一、前言在今年初Epic放出了UE5技术演示Demo之后,对于UE5的探讨就始终未曾进行,相干技术探讨次要围绕两个新的feature:全局照明技术Lumen和极高模型细节技术Nanite,曾经有一些文章[1][2]比拟具体地介绍了Nanite技术。本文次要从UE5的RenderDoc剖析和源码登程,联合一些已有的技术材料,旨在可能提供对Nanite直观和总览式的了解,并理清其算法原理和设计思维,不会波及过多源码级别的实现细节。 二、次世代模型渲染,咱们须要什么?要剖析Nanite的技术要点,首先要从技术需要的角度登程。近十年来,3A类游戏的倒退都逐步趋向于两个要点:互动式电影叙事和凋谢大世界。为了真切的电影感cutscene,角色模型须要纤毫毕现;为了足够灵便丰盛的凋谢世界,地图尺寸和物件数量呈指数级增长,这两者都大幅度晋升了场景精密度和复杂度的要求:场景物件数量既要多,每个模型又要足够精密。 简单场景绘制的瓶颈通常有两个: 每次Draw Call带来的CPU端验证及CPU-GPU之间的通信开销;因为剔除不够准确导致的Overdraw和由此带来的GPU计算资源的节约;近年来渲染技术优化往往也都是围绕这两个难题,并造成了一些业内的技术共识。针对CPU端验证、状态切换带来的开销,咱们有了新一代的图形API(Vulkan、DX12和Metal),旨在让驱动在CPU端做更少的验证工作;将不同工作通过不同的Queue派发给GPU(Compute/Graphics/DMA Queue);要求开发者自行处理CPU和GPU之间的同步;充分利用多核CPU的劣势多线程向GPU提交命令。得益于这些优化,新一代图形API的Draw Call数量相较于上一代图形API(DX11、OpenGL)进步了一个数量级[3]。 另一个优化方向是缩小CPU和GPU之间的数据通讯,以及更加准确地剔除对最终画面没有奉献的三角形。基于这个思路,诞生了GPU Driven Pipeline。对于GPU Driven Pipeline以及剔除的更多内容,能够读一读笔者的这篇文章[4]。 得益于GPU Driven Pipeline在游戏中越来越宽泛的利用,把模型的顶点数据进一步切分为更细粒度的Cluster(或者叫做Meshlet),让每个Cluster的粒度可能更好地适应Vertex Processing阶段的Cache大小,并以Cluster为单位进行各类剔除(Frustum Culling、Occulsion Culling和Backface Culling)曾经逐步成为了简单场景优化的最佳实际,GPU厂商也逐步认可了这一新的顶点解决流程。 但传统的GPU Driven Pipeline依赖Compute Shader剔除,剔除后的数据须要存储在GPU Buffer内,经由Execute Indirect这类API,把剔除后的Vertex/Index Buffer从新喂给GPU的Graphics Pipeline,无形中减少了一读一写的开销。此外顶点数据也会被反复读取(Compute Shader在剔除前读取以及Graphics Pipeline在绘制时通过Vertex Attribute Fetch读取)。 基于以上的起因,为了进一步提高顶点解决的灵便度,NVidia最先引入了Mesh Shader[5]的概念,心愿可能逐渐去掉传统顶点解决阶段的一些固定单元(VAF,PD一类的硬件单元),并把这些事交由开发者通过可编程管线(Task Shader/Mesh Shader)解决。 Cluster示意图传统的GPU Driven Pipeline,剔除依赖CS,剔除的数据通过VRAM向顶点解决管线传递基于Mesh Shader的Pipeline,Cluster剔除成为了顶点解决阶段的一部分,缩小没必要的Vertex Buffer Load/Store 三、这些就够了吗?至此,模型数、三角形顶点数和面数的问题曾经失去了极大的优化改善。但高精度的模型、像素级别的小三角形给渲染管线带来了新的压力:光栅化和重绘(Overdraw)的压力。 软光栅化是否有机会战胜硬光栅化?要弄清楚这个问题,首先须要了解硬件光栅化到底做了什么,以及它构想的个别利用场景是什么样的,举荐感兴趣的读者读一读这篇文章[6]。简略来说:传统光栅化硬件设计之初,构想的输出三角形大小是远大于一个像素的。基于这样的构想,硬件光栅化的过程通常是档次式的。 以N卡的光栅器为例,一个三角形通常会经验两个阶段的光栅化:Coarse Raster和Fine Raster,前者以一个三角形作为输出,以8x8像素为一个块,将三角形光栅化为若干块(你也能够了解成在尺寸为原始FrameBuffer 1/8*1/8大小的FrameBuffer上做了一次粗光栅化)。 在这个阶段,借由低分辨率的Z-Buffer,被遮挡的块会被整个剔除,N卡上称之为Z Cull;在Coarse Raster之后,通过Z Cull的块会被送到下一阶段做Fine Raster,最终生成用于着色计算的像素。在Fine Raster阶段,有咱们相熟的Early Z。因为Mip-Map采样的计算须要,咱们必须晓得每个像素相邻像素的信息,并利用采样UV的差分作为Mip-Map采样层级的计算根据。为此,Fine Raster最终输入的并不是一个个像素,而是2x2的小像素块(Pixel Quad)。 对于靠近像素大小的三角形来说,硬件光栅化的节约就很显著了。首先,Coarse Raster阶段简直是无用的,因为这些三角形通常都是小于8x8的,对于那些狭长的三角形,这种状况更蹩脚,因为一个三角形往往横跨多个块,而Coarse Raster岂但无奈剔除这些块,还会减少额定的计算累赘;另外,对于大三角形来说,基于Pixel Quad的Fine Raster阶段只会在三角形边缘生成大量无用的像素,相较于整个三角形的面积,这只是很少的一部分;但对于小三角形来说,Pixel Quad最坏会生成四倍于三角形面积的像素数,并且这些像素也蕴含在Pixel Shader的执行阶段,使得WARP中无效的像素大大减少。小三角形因为Pixel Quad造成的光栅化节约 基于上述的起因,在像素级小三角形这一特定前提下,软光栅化(基于Compute Shader)确实有机会战胜硬光栅化。这也正是Nanite的外围优化之一,这一优化使得UE5在小三角形光栅化的效率上晋升了3倍[7]。 Deferred Material重绘的问题长久以来都是图形渲染的性能瓶颈,围绕这一话题的优化也层出不穷。在挪动端,有咱们相熟的Tile Based Rendering架构[8];在渲染管线的进化历程中,也先后有人提出了Z-Prepass、Deferred Rendering、Tile Based Rendering以及Clustered Rendering,这些不同的渲染管线框架,实际上都是为了解决同一个问题:当光源超过肯定数量、材质的复杂度晋升后,如何尽量避免Shader中大量的渲染逻辑分支,以及缩小无用的重绘。无关这个话题,能够读一读我的这篇文章[9]。 ...

June 28, 2021 · 2 min · jiezi

关于游戏开发:代码解析双向链表实现贪吃蛇游戏简单易学开发自己第一个游戏

如何利用双向链表实现一个繁难的 C 语言版贪吃蛇游戏(如下图所示)。 其中,黄色框代表贪吃蛇,红色 ★ 代表食物!应用双向链表实现此游戏,有以下几点须要做重点剖析。 1) 咱们晓得,双向链表中各个节点的规范形成是一个数据域和 2 个指针域,但对于实现贪吃蛇游戏来说,因为各个节点的地位是随贪吃蛇的挪动而变动的,因而链表中的各节点还须要随时进行定位。 在一个二维画面中,定义一个节点的地位,至多须要所在的行号和列号这 2 个数据。 由此,咱们能够得出形成贪吃蛇的双向链表中各节点的形成: //创立示意蛇各个节点的构造体 typedef struct SnakeNode {     int x, y;//记录节点所在的行和列     struct SnakeNode *pre;//指向前驱节点的指针     struct SnakeNode *next;//指向后续节点的指针 }Node, *pNode;2) 贪吃蛇的挪动,实质上就是对链表中各个节点的从新定位。 换句话说,除非贪吃蛇吃到食物,否则无论怎样挪动,都不会对双向链表的整个构造(节点数)产生影响,惟一受影响的就只是各个节点中 (x,y) 这对定位数据。 由此,咱们能够试着设计出实现贪吃蛇挪动的性能函数,本节所用的实现思维分为 2 步:         ▶ 从蛇尾(双向链表尾节点)开始,挪动向前遍历,过程中顺次将以后节点的 (x,y) 批改为前驱节点的 (x,y),由此可实现整个蛇身(除首元节点外的其它所有节点)的向前挪动;         ▶ 接管用户输出的挪动指令,依据用户批示贪吃蛇向左、向右、向上还是向下挪动,首元节点中的 (x,y) 别离做 x-1、x+1、y-1 和 y+1 运算。 如下所示,move() 函数就实现了贪吃蛇的挪动: //贪吃蛇挪动的过程,即链表中所有节点从尾结点开始一一向前挪动一个地位 bool Move(pNode pHead, char key) {     bool game_over = false;     pNode pt = pTail;     while (pt != pHead) { // 每个节点顺次向前实现蛇的挪动         pt->x = pt->pre->x;         pt->y = pt->pre->y;         pt = pt->pre;     }     switch (key) {         case'd': {             pHead->x += 1;             if (pHead->x >= ROW)                 game_over = true;             break;         }         case'a': {             pHead->x -= 1;             if (pHead->x < 0)                 game_over = true;             break;         }         case's': {             pHead->y += 1;             if (pHead->y >= COL)                 game_over = true;             break;         }         case'w': {             pHead->y -= 1;             if (pHead->y < 0)                 game_over = true;;             break;         }     }     if (SnakeDeath(pHead))         game_over = true;     return game_over; }留神,此段代码中还调用了 SnakeDeath() 函数,此函数用于判断贪吃蛇挪动时是否撞墙、撞本身,如果是则游戏完结。3) 当贪吃蛇吃到食物时,贪吃蛇须要减少一截,其本质也就是双向链表减少一个节点。然而实现这个性能惟一的难点在于:如何为该节点初始化 (x,y)? ...

June 1, 2021 · 4 min · jiezi

关于游戏开发:游戏开发-lua读取bytes文件并解析proto

【游戏(手游,页游,端游等)开发】C#序列化proto后生成bytes文件,在lua层解析成proto function Process_RunBattle:GetProto(path) local result = read_bytes(path) --字节流转换成字符串 local str = string.char(unpack(result)) --protobuf解析字符串 local proto = NetStruct_BattleCommand_pb.BattleCommand() proto:ParseFromString(str) return protoend --输出path,返回字节流tablefunction read_bytes(path) local file = io.open(path, "rb") if not file then return nil end local t = {} repeat local str = file:read(4 * 1024) for c in (str or ''):gmatch('.') do if c:byte() == 126 then t = {} else table.insert(t, c:byte()) end end until not str file:close() return tend

April 21, 2021 · 1 min · jiezi

关于游戏开发:游戏开发网络篇-Net框架

前言:本篇文章主题Tcp连贯Socket套接字相干内容,对根底局部、优化补充局部做了阐明,最终目标是让阅读者看完本篇文章后能写一个功能完善的网络框架。 首先明确一下网络连接的根底模块有哪些 [根底局部2]数据接管客户端Socket连贯后开始接收数据,客户端接收数据的形式个别有两种 [数据接管第一种]开线程,为何开线程:数据接管不须要和Mono交互,仅仅是对byte[]数据的操作,开线程提高效率,上面是代码示例这个没什么好说的,四个重载接口区别不大 //数据初始化uint ReceiveMaxByteCount;byte[] bufferTemp = new byte[ReceiveMaxByteCount]; pubvoid void Connect(string _ip,int _port){ SocketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress ip = IPAddress.Parse(_ip); IPEndPoint point = new IPEndPoint(ip, _port); SocketClient.NoDelay = true; SocketClient.Connect(point); }[根底局部2]数据接管客户端Socket连贯后开始接收数据,客户端接收数据的形式个别有两种 [数据接管第一种]开线程,为何开线程:数据接管不须要和Mono交互,仅仅是对byte[]数据的操作,开线程提高效率,上面是代码示例 pubvoid void Connect(string _ip,int _port){ SocketClient = new Socket() //........... //这是第一种形式,开线程接管 Thread c_thread = new Thread(Received); c_thread.IsBackground = true; c_thread.Start();}void Received(){ while (true) { try { int len = _SocketClient.Receive(bufferTemp); //len 理论接管到的无效字节数 if (len <= 0) { //异样解决 break; } //把收到的字节解析或者塞入接管缓存池中 } catch { } }}[数据接管第二种]简略粗犷的写在Update里,如果是框架则应该有tick 接管和发送缓存池的机制,这里是根底局部,只介绍外围代码 ...

April 21, 2021 · 1 min · jiezi

关于游戏开发:瞎聊一下游戏行业技术岗技术领域

游戏逻辑程序员的将来在哪里?Gameplay Programmer(游戏逻辑程序员)会不会慢慢隐没?游戏逻辑程序员的成长前途?

April 20, 2021 · 1 min · jiezi

关于游戏开发:游戏开发-XNAGame003-拖放控件vs会自动添加代码

拖放一个标签,三个按钮,属性栏中设定各自的属性,最终造成的代码,就和咱们本人手动写代码是一样的。 form1.cs using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms; namespace XNAGame_003{ public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { label1.ForeColor = Color.Blue; } private void button2_Click(object sender, EventArgs e) { label1.ForeColor = Color.Black; } private void button3_Click(object sender, EventArgs e) { this.Close(); } }}控件是拖放的,属性是属性栏中设定的。 参考一下主动的代码 form1.design.cs namespace XNAGame_003{ partial class Form1 { /// <summary> /// 必须的设计器变量。 /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// 清理所有正在应用的资源。 /// </summary> /// <param name="disposing">如果应开释托管资源,为 true;否则为 false。</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows 窗体设计器生成的代码 /// <summary> /// 设计器反对所需的办法 - 不要 /// 应用代码编辑器批改此办法的内容。 /// </summary> private void InitializeComponent() { this.label1 = new System.Windows.Forms.Label(); this.button1 = new System.Windows.Forms.Button(); this.button2 = new System.Windows.Forms.Button(); this.button3 = new System.Windows.Forms.Button(); this.SuspendLayout(); // // label1 // this.label1.AutoSize = true; this.label1.Font = new System.Drawing.Font("宋体", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.label1.ForeColor = System.Drawing.SystemColors.ActiveCaptionText; this.label1.Location = new System.Drawing.Point(39, 34); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(104, 16); this.label1.TabIndex = 0; this.label1.Text = "我是一个标签"; // // button1 // this.button1.Location = new System.Drawing.Point(42, 68); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(75, 23); this.button1.TabIndex = 1; this.button1.Text = "蓝色"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click); // // button2 // this.button2.Location = new System.Drawing.Point(42, 110); this.button2.Name = "button2"; this.button2.Size = new System.Drawing.Size(75, 23); this.button2.TabIndex = 2; this.button2.Text = "彩色"; this.button2.UseVisualStyleBackColor = true; this.button2.Click += new System.EventHandler(this.button2_Click); // // button3 // this.button3.Location = new System.Drawing.Point(42, 153); this.button3.Name = "button3"; this.button3.Size = new System.Drawing.Size(75, 23); this.button3.TabIndex = 3; this.button3.Text = "退出"; this.button3.UseVisualStyleBackColor = true; this.button3.Click += new System.EventHandler(this.button3_Click); // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(284, 262); this.Controls.Add(this.button3); this.Controls.Add(this.button2); this.Controls.Add(this.button1); this.Controls.Add(this.label1); this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.Label label1; private System.Windows.Forms.Button button1; private System.Windows.Forms.Button button2; private System.Windows.Forms.Button button3; }} 图片起源:http://www.laoshoucun.com/ 页游 ...

April 20, 2021 · 2 min · jiezi

关于游戏开发:游戏开发-XNAGame001-空白窗体

vs2012,新建winform应用程序,第一个练习,空白窗体。 app.config <?xml version="1.0" encoding="utf-8" ?><configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup></configuration>program.cs using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using System.Windows.Forms; namespace XNAGame_001{ static class Program { /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } }}form1.cs using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms; namespace XNAGame_001{ public partial class Form1 : Form { public Form1() { InitializeComponent(); } }}大家留神,以上代码均是vs主动生成的,没有增加一行手动的代码,目标是开始学习游戏,h5游戏等的开发,先相熟一下windows利用程序开发。

April 20, 2021 · 1 min · jiezi

关于游戏开发:UE4游戏开发之-如何获取启动时设置的启动参数

以PS设置启动参数为例: 要在游戏中获取启动参数值,须要晓得启动参数,保留的地位:须要理解【Engine\Source\Runtime\Core\Public\Misc\CommandLine.h】 /** * Returns an edited version of the executable's command line * with the game name and certain other parameters removed * 获取启动参数字符串. */ static const TCHAR* Get(); /** * Parses a string into tokens, separating switches (beginning with -) from * other parameters * 解析命令字符串 * * @param CmdLine the string to parse * @param Tokens [out] filled with all parameters found in the string * @param Switches [out] filled with all switches found in the string */ static void Parse(const TCHAR* CmdLine, TArray<FString>& Tokens, TArray<FString>& Switches);应用形式 ...

April 15, 2021 · 1 min · jiezi

关于游戏开发:游戏优化系列二Android-Studio制作图标教程

背景谷歌在Android8.0后就推出了圆形图标,并在AndroidStudio中提供了制作工具。那么如果不制作圆形工具会怎么样?在局部设施上图标会呈现适配问题,UI上不美观。本文将介绍Image Asset Studio工具的应用,介绍如何制作圆形图标 1、对于Image Asset Studio Android Studio 蕴含一个名为 Image Asset Studio 的工具,可帮忙您依据素材图标、自定义图片和文本字符串生成本人的利用图标。它会针对您的利用反对的每种像素密度以适当的分辨率生成一组图标。Image Asset Studio 会将新生成的图标搁置在我的项目中 res/ 目录下的特定于密度的文件夹中。在运行时,Android 将依据运行利用的设施的屏幕密度来应用适当的资源。 Image Asset Studio 可帮忙您生成以下图标类型: 启动器图标操作栏和标签页图标告诉图标运行 Image Asset Studio 如需启动 Image Asset Studio,请按以下步骤操作: 在 Project 窗口中,抉择 Android 视图。右键点击 res 文件夹,而后顺次抉择 New > Image Asset。 2、自适应和旧版启动器图标 关上 Image Asset Studio 后,您能够依照以下步骤增加自适应和旧幅员标: (1)在 Icon Type 字段中,抉择 Launcher Icons (Adaptive & Legacy)。 (2)在 Foreground Layer 标签页的 Asset Type 中抉择一种资源类型,而后在上面的字段中指定资源: 抉择 Image 以指定图片文件的门路。抉择 Clip Art 以指定 Material Design 图标集中的图片。抉择 Text 以指定文本字符串并抉择字体。(3)在 Background Layer 标签的 Asset Type 中抉择一种资源类型,而后在上面的字段中指定资源。您能够抉择一种色彩或指定一张图片作为背景图层。 ...

April 14, 2021 · 2 min · jiezi

关于游戏开发:游戏优化系列一海外谷歌应用适配相关

背景游戏上架谷歌申请举荐时,谷歌会给予一些优化倡议。这些倡议实际上都是比拟不错的游戏体验优化方向。以下依据app上架谷歌利用商店的规范,列举须要适配的中央并提供了批改样例。 1. 谷歌利用图标游戏icon:5个不同尺寸的icon,4848, 7272, 9696, 144144, 192*192别离放在mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi上面。 推送icon(只能由红色+通明组成):(白底通明字)5个不同尺寸的icon,2424, 3636, 4848, 7272, 96*96别离放在mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi上面。 示例: 2. 状态栏音讯推送在游戏利用中进行版本迭代时,如果游戏自身有音讯推送,且SDK中也有推送的状况下,发送音讯的notify办法中,id有可能不同,此时会呈现两条音讯(游戏的和SDK的),有可能会被Google利用商店回绝举荐。 NotificationManager.notify(int id, Notification notification)呈现两条音讯: 须要做到的成果--同一个利用的音讯重叠: 开展后: 批改示例: private void mergeNotifications(){ int mergeId = 0; String groupKey = "com.android.example.WORK_EMAIL"; String channelId = "1"; Notification notification1 = new NotificationCompat.Builder(MainActivity.this, channelId) .setSmallIcon(R.drawable.ic_launcher_background) .setContentTitle("推送须要重叠") .setContentText("这是一条SDK的告诉") .setGroup(groupKey) .build(); Notification notification2 = new NotificationCompat.Builder(MainActivity.this, channelId) .setSmallIcon(R.drawable.ic_launcher_background) .setContentTitle("推送须要重叠") .setContentText("这是一条游戏的告诉") .setSmallIcon(R.drawable.ic_stat_name) .setGroup(groupKey) .build(); Notification mergeNotification = new NotificationCompat.Builder(MainActivity.this, channelId) .setContentTitle("推送须要重叠") .setContentText("2条未读信息") .setSmallIcon(R.drawable.ic_stat_name) .setStyle(new NotificationCompat.InboxStyle() .addLine("这是一条游戏的告诉") .addLine("这是一条SDK的告诉") .setBigContentTitle("2条未读信息") .setSummaryText("推送测试")) .setGroup(groupKey) .setGroupSummary(true) .build(); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.notify(1, notification1); notificationManager.notify(2, notification2); notificationManager.notify(mergeId, mergeNotification);}3. 零碎主题格调 ...

April 13, 2021 · 1 min · jiezi

关于游戏开发:实时联网游戏后台服务技术选型和挑战网络接入篇

概述:本文尝试从开发者角度梳理开发实时联网游戏后盾服务过程中可能面临的挑战,并针对性地提供相应解决思路,冀望帮忙开发者根据本身游戏特点做出正当的技术选型。 维基百科对于网络游戏的定义:通过计算机网络,将专用服务器和用户的客户端设施(手机、PC、游戏主机等)相连,让多名玩家同时联机进行游戏的娱乐模式,由此可知网络游戏波及三个角色:客户端、网络、服务器,从网络架构上来讲网络游戏可分为C/S 架构和P2P架构(特指客户端间直连通信),在理论开发中还有一种C/S和P2P架构混合:C/M架构。 P2P架构不在本文探讨范畴,C/M架构和C/S架构相似,和经典的LAMP网站架构相似个别C/S架构的游戏后盾也可划分为如下三层:(1)网络接入层;(2)游戏逻辑层;(3) 数据存储层。 网络接入、游戏逻辑、数据存储层各自所面临的问题域及对应技术栈都大为不同,做此划分不仅有助于模块解耦、技术分工、组件复用,也可不便服务的运维部署。本文也着重从这三个方面来论述游戏服务器的开发。 1、网络接入层 网络接入层的次要工作是建设客户端和后盾服务以及客户端之间的信道,接管来自客户端大量并发申请,考核该层的次要性能指标是:高吞吐、低提早。因此网络接入层开发考验的是开发者高性能网络编程的功底,即解决C10K甚至C10M的能力。 1.1协定抉择 依据OSI的七层网络参考模型,咱们可将网游网络也做如下7层划分: 其中4层以下都由操作系统来负责,开发者无需为此操心,在理论的开发过程中开发者首要面临的问题便是传输层是采纳TCP还是UDP,下表简要比照了两者的优劣。 综合两者优劣,简略来说除非对提早有极致要求(例如FPS、MOBA类游戏)需采纳UDP外,TCP可应答大部分游戏。在理论游戏开发中不论是采纳TCP还是UDP形式,都很少间接通过 Socket编程形式来进行,一来因为开发工作量大,品质性能难以保障;二来平台兼容性不好(比方H5并没有提供socket编程能力),而是基于更下层的通信协定比方基于TCP的HTTP、Websocket协定,GRPC,以及基于UDP实现的QUIC,WebRTC协定等。 值得注意的是基于安全性思考,浏览器规范未提供UDP收发能力,QUIC协定也只在chrome失去了反对,WebRTC也还不是浏览器事实标准且协定初始目标是用于实现点对点的音视频通信,协定内容过于庞杂不容易提炼利用于游戏开发中,因此现阶段H5游戏还只能采纳HTTP或Websocket形式通信。 通信协定确定后,随后要思考的便是游戏对象的序列化,序列化次要有基于文本、基于二进制两种,其优劣如下表所示。在开发过程中个别会先采纳文本序列化形式,便于前后端开发联调,在游戏正式上线前切换至二进制序列化形式以缩小传输流量、晋升编解码效率。 至于数据安全性问题,为了爱护敏感数据平安开发者能够抉择平安的https或WSS通信协定,而对于间接基于TCP协定通信,可采纳先用RSA协商加密秘钥,而后应用对称加密形式将数据加密后发送。 通过以上剖析,对于游戏协定类型的抉择咱们给出有以下准则: 1、弱联网类游戏:诸如休闲、卡牌类游戏可间接HTTP协定,对安全性有要求的话就应用HTTPS; 2、实时性,交互性要求较高:这类游戏个别须要放弃长连贯,优先选择规范的ws协定(同时应用二进制序列化形式),如思考安全性可应用wss协定。而对于提供socket接口的native平台也可应用TCP协定,同时对数据做对称加密加强安全性; 3、实时性要求极高:不仅须要和服务器放弃长连贯,且提早和网络抖动都要求极高(如FPS,赛车类游戏),可应用基于UDP的实现流传输协定如QUIC,KCP等。 1.2并发模型 为了解决来自客户端的并发申请,服务端有4种常见的并发模型。 1.2.1过程 过程是最早采纳的并发模型,过程作为操作资源分配、调度的单位,领有独立的运行空间。过程并发模型中每个申请由独立的过程来解决,过程一次只能解决一个申请,该模型最大的长处就是简略。如果解决申请的过程因为零碎调用而阻塞或过程的工夫片用完,抢占式的过程调度器就会暂停旧过程执行,调度执行新的过程,这个过程波及大开销的上下文切换,过程并发模型的毛病是比拟低效。最典型的采纳过程模型的服务有Apache。 1.2.2线程 线程并发模型是过程模型的改良,线程从属于过程,是零碎更小粒度的执行调度单元。不同申请可由过程内多个并发执行的线程来解决,这些线程由操作系统内核主动调度。线程绝对过程的次要劣势在于,调度上下文切换开销更小,但因为多个线程共享地址空间,须要额定的线程间互斥、同步机制来保障程序性正确性。典型的采纳线程模型的服务有Tomcat。 1.2.3 IO多路复用 利用操作系统提供的epoll等IO多路复用机制,能同时监控多个连贯上读、写事件, IO多路复用也称事件驱动模型,网络程序执行逻辑可形象为事件驱动的状态机。 IO多路复用防止了读写阻塞,缩小了上下文切换,晋升了CPU利用率和零碎吞吐率。但IO多路复用它将本来“同步”、线性的解决逻辑变成事件驱动的状态机,解决逻辑扩散于大量的事件回调函数。这种异步、非线性的模型,极大地减少了编程难度,如nodeJs的常见的回调天堂问题。典型的采纳IO复用模型的服务有Nginx,netty。 1.2.4 协程 协程也称为轻量级线程,是一种协同的、非抢占式的多任务并发模型。 协程运行在用户空间,当遇到阻塞或特定入口时,通过显式调用切换办法被动让出CPU,由任务调度器选取另一个协程执行。 协程切换只是简略地扭转执行函数栈,不波及内核态与用户态转化,也波及上下文切换,开销远小于过程/线程切换。协程的概念虽早已提出,随着近些年年越来越多的语言(go、 Haskell)内置对协程反对才被开发者所熟知,协程极大的优化了开发者编程体验,在同步、程序编程格调能疾速实现程序逻辑,还领有IO多路复用异步编程的性能。典型的采纳协程模型的服务有openresty(Lua), gevent(Python), golang。 以上总结了目前4种罕用的并发模型,它们在工作原理、运行效率、编程难度等方面有显著区别,各自有实用场景,在理论应用时应该依据需要认真评估。在理论开发过程中如果没有可复用的现成网络组件或历史包袱咱们倡议应用协程并发模式开发网络接入层服务。图片起源:http://www.hp91.cn/ h5游戏

April 7, 2021 · 1 min · jiezi

关于游戏开发:Egret-游戏开发投篮

前段时间为了推广一个新的公众号,开发了一款名为「投篮达人」(已下线)的小游戏,公布上线之后失去了不错的成果,胜利为公众号吸引了很多粉丝。上面就来跟大家分享下开发这款游戏的历程。 需要剖析游戏自身其实很简略,只是一个投篮游戏,实现篮球的投射,篮筐静止,篮球与篮筐撞击,游戏完结后的排行榜记录以及公众号的辨认。但因为游戏是2D游戏,却有一个仿3D成果(篮球投出后离咱们越来越远以及穿透篮网),同时要让篮球与篮筐进行碰撞检测且模仿一个晦涩天然的反弹成果,所以须要一直填坑。 技术选型思考到开发速度,找一个成熟且文档齐全的HTML5 游戏开发引擎就非常重要了,在国内大多数人用的都是Cocos2d-x-js 或Egret,phaser 或 Hilo 这些不足比拟棘手的开发工具就跳过了,Cocos 在网页上的性能不太现实,所以最初抉择了Egret 2D 至于物理引擎方面,Egret 是举荐应用P2 引擎的,因为其性能相较于Box 2D 或者Matter.js 都好,不过毛病是不足中文文档。 实现思路伪3D 静止 近大远小的显示以篮球初始地位(或底部)为原点确立一个视觉焦点,在篮球运动的过程中依据篮球在Y轴上的地位计算其缩放比例,计算公式如下: ``scale = (curY - startY) / ( endY - startY);``另外,在物理世界中,任何刚体都是形态和大小都放弃不变的物理模型,也就意味着,咱们能让篮球的贴图的缩放,但无奈让篮球的刚体进行缩放。为了让篮球和篮筐撞击时,篮球的大小是精确的,咱们能够依据上图的缩放比例公式,计算篮球到达篮筐(篮筐地位确定,比例必然是固定的)时的比例,在初始地位让篮球的贴图和刚体大小放弃这一比例,当篮球运动到篮筐时大小就正好是其刚体的理论大小。篮球与篮筐的交互因为篮球上升时,在2D 的物理世界中,篮球和篮筐实际上是同一立体,球和篮筐的刚体默认会产生碰撞,同时,篮球的纵深须要在上升时大于篮筐而着落时小于篮筐;为了解决第一个问题,能够利用P2 提供的碰撞分组来防止碰撞。在P2 中,刚体须要一个或多个Shape 决定刚体的形状,而Shape 又具备collisionGroup 和 collisionMask 两个属性,前者决定了Shape 的碰撞分组,后者决定了Shape 会与哪些碰撞分组产生碰撞。须要留神的是,collisionGroup 的取值是 Math.pow(2,0) 到 Math.pow(2,32)。 // 创立篮球刚体的形态ballShape = new p2.Circle({radius: GlobalData.ballRadius / factor}); // 设置篮球的碰撞分组ballShape.collisionGroup = this.FLYBALL;// 这样设置 collisionMask 篮球就能与篮筐交互,留神多个分组分隔的是 | 不是 ||ballShape.collisionMask = this.BASKET | this.GROUND;因而,在篮球上升时,设置其碰撞分组为FLYBALL,其collisionMask 为高空,此时篮球只会和高空碰撞,不与篮筐碰撞,当下落时,将其分组设置为DROPBALL,collisionMask 为高空和篮筐,此时篮球就会和篮筐产生碰撞了。为了解决第二个问题,思路相似,上升时将篮球的回升设置最高,着落时与篮筐替换纵深值即可; 二维码辨认在微信网页中,常常须要提供长按二维码辨认性能,但二维码须要是一张理论的图片,内嵌于Canvas 的二维码是不反对长按辨认的,为了让微信可能辨认到图片,只须要在Canvas 下面笼罩一张图片即可。示意图如下:在设置图片时,大小尺寸须要依据浏览器尺寸和Canvas 的理论尺寸进行计算缩放,能力让图片看起来像是和Canvas 一起的; ...

April 7, 2021 · 1 min · jiezi

关于游戏开发:pygame-游戏开发

简略的战旗游戏开发学习在网上找寻教程之后搞出了这么个雏形 游戏介绍游戏实现了战斗场景的回合制玩法: 对战单方每个生物每一轮有一次口头机会,能够行走或攻打对方。 每个生物属性有:行走范畴,速度,生命,挫伤,进攻,攻打 和 是否是近程兵种。 当把对方生物都毁灭时,即胜利。 代码介绍对于战旗类游戏的外围还是地图,尽管网上有六边形的地图教程然而没看太懂就做正方形的吧 首先定义函数,width 和 height 为地图的宽度和长度,bg_map 设置方格的背景色彩, entity_map 保留哪个方格上有生物。active_entity示意以后要口头的生物。 class Map(): def __init__(self, width, height, grid): self.width = width self.height = height self.bg_map = [[0 for x in range(self.width)] for y in range(self.height)] self.entity_map = [[None for x in range(self.width)] for y in range(self.height)] self.active_entity = None self.select = None self.setupMapImage(grid) self.setupMouseImage()当我方生物抉择口头时,设置生物可行走范畴内的方格背景为 c.BG_RANGE 。active_entity 的 inRange 函数判断一个方格是否在行走范畴内。 def updateMap(self): for y in range(self.height): for x in range(self.width): self.bg_map[y][x] = c.BG_EMPTY if self.entity_map[y][x] is not None and self.entity_map[y][x].isDead(): self.entity_map[y][x] = None if self.active_entity is None or self.active_entity.state != c.IDLE: return map_x, map_y = self.active_entity.map_x, self.active_entity.map_y self.bg_map[map_y][map_x] = c.BG_ACTIVE for y in range(self.height): for x in range(self.width): if not self.isMovable(x,y) or not self.isValid(x,y): continue if self.active_entity.inRange(self, x, y): self.bg_map[y][x] = c.BG_RANGE mouse_x, mouse_y = pg.mouse.get_pos() self.checkMouseMove(mouse_x, mouse_y)接下来欠缺下咱们的map代码 ...

April 6, 2021 · 9 min · jiezi

关于游戏开发:五项python小游戏代码测试

测试的我的项目别离为:1,猜单词 2,发牌游戏 3,猜数字游戏 4,图形版发牌程序 5,拼图游戏以下为测试代码及其后果:1:猜单词代码如下: # Word Jumble 猜单词游戏import random# 创立单词序列WORDS = ('python','easy','difficult','answer','continue','jumble','phone','desktop', 'position','game','quick','find','apple','banana','orange','stream')print( """ 欢送加入猜单词游戏 把字母组合成一个正确的单词, """)iscontinue="y"while iscontinue == "y" or iscontinue == "Y": # 从序列中随机挑选出一个单词 word = random.choice(WORDS) # 一个用于判断玩家是否参对的变量 correct = word # 创立乱序后的单词 jumble = "" while word: # Word不是空串时循环 # 依据word长度,产生word的随机地位 position = random.randrange(len(word)) # 将position地位字母组合到乱序后单词 jumble += word[position] # 通过切片,将position地位字母从原单词中删除 word = word[:position] + word[(position + 1):] print("乱序后单词:",jumble) guess = input("\n请你猜:") while guess != correct and guess != "": print("对不起你猜的不正确") guess = input("持续猜:") if guess == correct: print("祝贺你,猜对了!\n") iscontinue = input("\n是否持续(Y/N):")运行后果:2,发牌游戏代码如下: ...

April 6, 2021 · 4 min · jiezi

关于游戏开发:pygame写游戏常用代码记录

pygame写起游戏(页游等)来还是挺不错的,不过我也没用过别的什么货色写,所以也没什么发言权。上面是一些罕用的代码片段,记录下来,给他人看,也用来给我想不起来的时候看看。 pygame的常见结尾 # 1 - Import libraryimport mathimport randomimport pygamefrom pygame.locals import *# 2 - Initialize the gamepygame.init()pygame.mixer.init() # music initialwidth, height = 640, 480screen=pygame.display.set_mode((width, height))加载图片和声音 player = pygame.image.load("resources/images/dude.png")screen.blit(player, (100, 100))hit = pygame.mixer.Sound("resources/audio/explode.wav")hit.set_volume(0.05)碰撞检测 bullrect=pygame.Rect(arrow.get_rect())bullrect.left=bullet_xbullrect.top=bullet_ybadrect = pygame.Rect(badguyimg.get_rect())badrect.left = badguy_xbadrect.top = badguy_yif badrect.colliderect(bullrect): print 'Shooted'常见事件循环 while True:for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit(0) if event.type == pygame.KEYDOWN: if event.key == K_q: pygame.quit() exit(0)# refresh screen pygame.display.flip()显示文字 pygame.font.init()font = pygame.font.Font(None, 24)text = font.render("Good job", True, (255,0,0))textRect = text.get_rect()textRect.centerx = screen.get_rect().centerxtextRect.centery = screen.get_rect().centery+24screen.blit(gameover, (0,0))screen.blit(text, textRect)

April 6, 2021 · 1 min · jiezi

关于游戏开发:Android游戏开发之二剖析游戏开发用view还是surfaceView

在Android游戏当中充当次要的除了管制类外就是显示类,在J2ME中咱们用Display和Canvas来实现这些,而Google Android中波及到显示的为view类,Android游戏开发中比拟重要和简单的就是显示和游戏逻辑的解决。  这里咱们说下android.view.View和android.view.SurfaceView。SurfaceView是从View基类中派生进去的显示类,间接子类有GLSurfaceView和VideoView,能够看出GL和视频播放以及Camera摄像头个别均应用SurfaceView,到底有哪些劣势呢? SurfaceView能够管制外表的格局,比方大小,显示在屏幕中的地位,最要害是的提供了SurfaceHolder类,应用getHolder办法获取,相干的有Canvas lockCanvas() Canvas lockCanvas(Rect dirty) 、void removeCallback(SurfaceHolder.Callback callback)、void unlockCanvasAndPost(Canvas canvas) 管制图形以及绘制,而在SurfaceHolder.Callback 接口回调中能够通过重写上面办法实现。  应用的SurfaceView的时候,个别状况下要对其进行创立,销毁,扭转时的状况进行监督,这就要用到 SurfaceHolder.Callback. class XxxView extends SurfaceView implements SurfaceHolder.Callback {  public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){} //看其名知其义,在surface的大小产生扭转时激发 public void surfaceCreated(SurfaceHolder holder){} //同上,在创立时激发,个别在这里调用画图的线程。 public void surfaceDestroyed(SurfaceHolder holder) {} //同上,销毁时激发,个别在这里将画图的线程进行、开释。  }  对于Surface相干的,Android底层还提供了GPU减速性能,所以个别实时性很强的利用中次要应用SurfaceView而不是间接从View构建,同时起初做android 3d OpenGL中的GLSurfaceView也是从该类实现。  SurfaceView和View最实质的区别在于,surfaceView是在一个新起的独自线程中能够从新绘制画面而View必须在UI的主线程中更新画面。 那么在UI的主线程中更新画面 可能会引发问题,比方你更新画面的工夫过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无奈响应按键,触屏等音讯。 当应用surfaceView 因为是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比方你触屏了一下,你须要surfaceView中thread解决,个别就须要有一个event queue的设计来保留touch event,这会稍稍简单一点,因为波及到线程同步。  所以基于以上,依据游戏特点,个别分成两类。  1 被动更新画面的。比方棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,能够间接应用 invalidate。 因为这种状况下,这一次Touch和下一次的Touch须要的工夫比拟长些,不会产生影响。  2 被动更新。比方一个人在始终跑动。这就须要一个独自的thread不停的重绘人的状态,防止阻塞main UI thread。所以显然view不适合,须要surfaceView来管制。   3.Android中的SurfaceView类就是双缓冲机制。因而,开发游戏时尽量应用SurfaceView而不要应用View,这样的话效率较高,而且SurfaceView的性能也更加欠缺。    思考以上几点,所以我始终都选用 SurfaceView 来进行游戏开发。 那么在当前源码实例中,我都会以继承surfaceView框架来进行演示。下一章将具体分析sarfaceview ,以及附上自己写的游戏开发架构。文章起源:http://www.laoshoucun.com/ 传奇

April 6, 2021 · 1 min · jiezi

关于游戏开发:2d游戏设计pygame-游戏开发自主开发

此次作业是应用pygame模块自主设计一款2D游戏。 此次制作的游戏灵感来源于jumpKing,这是一款发售于steam的高技术游戏。 咱们抉择了他们的操作形式: 需A、D键来管制人物的挪动,以及空格键使人物跳跃,并且空格键蓄力工夫越长跳的越高 上面开始介绍一下,咱们此次游戏的制作过程吧。 一,设计游戏的根本逻辑和界面。这是在草稿本下面,画的一些根底的界面和事件的触发断定等等。 残缺的游戏设计并没有在外面齐全展现。 二,游戏中的class设计1,player类在Player类中,咱们给了根底的本身属性: rect为人物呈现的初始地位,咱们将人物的初始地位搁置于随机呈现的第一个平台的两头上方,所以须要创立人物时来导入,不便绘制人物的初始地位。 faceR属性判断人物的静止方向,1代表向右静止,2代表向左静止。 speed属性为人物在x轴上的静止速度。 gravity属性为人物在y轴上的起飞速度。 live属性为判断人物是否存活。 Drop函数来管制人物起飞。 Move函数管制人物的y轴挪动,须要输出time,这个time是玩家按住空格键的工夫,以此来管制人物y轴挪动的长短。 class Player():def __init__(self, pos): self.rect = pos self.faceR = 1 #1为向右,2为向左 self.speed = 2 self.gravity = 10 self.live = True #是否存活def Drop(self): self.rect.top += self.gravitydef Move(self, time): tmp = 0.2*self.speed*time*time - self.gravity if tmp <= 0: tmp = 0 self.rect.top -= tmp self.rect.left += self.speed*time*self.faceR #### **2,Land类**这个class中,咱们给了land类的根本属性: image属性是用来存储land的图片, rect属性设定了land的Rect属性,通过前面随机函数产生不同的left值,来管制land呈现的不同地位。 rect.topleft接管外界给的init_pos值,即land的left值。 gravity属性为land在y轴上的起飞速度。 Move函数即管制land类的起飞。 class Land(pygame.sprite.Sprite):def __init__(self, land_img, init_pos): pygame.sprite.Sprite.__init__(self) self.image = land_img self.rect = pygame.Rect(0,0,100,20) self.rect.topleft = init_pos self.gravity = 4def Move(self): self.rect.top += self.gravity三,程序的根本代码上面是依照pygame的根底设置,来给定画面的宽和高,和接下来会用到的一些属性值。应该会在上面具体用到时再具体讲述。 ...

April 6, 2021 · 3 min · jiezi

关于游戏开发:从逃离到成为游戏开发40岁了我才学会编程

1“不想成为 Logo 明星程序员后再被派去加入较量” 我的编程生涯始于 20 世纪 80 年代时领有的第一台电脑。那是一台叫做 ADAM 计算机的怪兽,就是下图这样的: 这是一种个人电脑、ColecoVision 游戏零碎和打字机的混合体:两个磁带机代替了磁盘驱动器 / 磁带盒、一台电视机代替了显示器,还有一台乏味的打印机,下面有个开关能够将它变成一台残缺的打字机。很多其余 ADAM 计算机用户都有理论的磁盘驱动器,但这个没有,磁带要花很长时间能力加载进去。 咱们刚失去它的时候,我父亲在地下室里录了很多磁带,但我不晓得为什么会有这么多的游戏。我最喜爱的一款游戏叫做《Gateway to Apshai》(一款战斗电子游戏),这是一品种 Rogue 的游戏(迷宫摸索式电子游戏)。起初他解释说,他是用 Forth 实现的。上面是他的原话: 当咱们有了 Coleco Adam 计算机时,它有一个 Zilog Z80 CPU,因而,我用过一点 Forth。不晓得你是否还记得,我从美国订购了一盘磁带(用于磁带机的),外面有几个黑客程序和一本名为《Adam 黑客指南》(The Hackers Guide to the Adam)的书,它容许咱们将 ColecoVision 的游戏下载到空白磁带上,这样咱们就失去了大量的游戏。我本人并没写过任何程序,然而磁带上的程序都附有源代码,所以你能够依照逻辑来写。在某些状况下,我须要调整参数并从新保留,以便优化任何须要破解的程序。这很乏味,也很好玩。 要害是他给我看了一种叫做 BASIC 的语言,过后的我认为 BASIC 是世界上惟一的编程语言。我开始学习这门编程语言,并跟着读了像《银山之谜》(Mystery of Silver Mountain)和《捕捉狮头象》(Hunt the Wumpus)这样的书,很快就学会了如何编程。我开始依据 Steve Jackson 的《巫术!》(Sorcery!)这本书制作我本人的小型 RPG 游戏。 它们最初就像上面这段从 Wikipedia 上抄来的代码的一个较大版本,其中有很多 RAND 的掷骰子和 GOTO 调用。随着工夫的推移,我不得不增加越来越细的行号(比方,在 60 行和 70 行之间增加了一个 65 行,而后是 64 行,最初当我用完空间就得给整段代码从新编号)。 ...

April 5, 2021 · 2 min · jiezi

关于游戏开发:什么是3D模型学习3D游戏建模都需要掌握什么工具

什么是3D模型 3D模型是物体的多边形示意,通常用计算机或者其它视频设施进行显示。显示的物体能够是事实世界的实体,也能够是虚构的物体。任何物理自然界存在的货色都能够用三维模型表示。 二、什么是游戏3D? 游戏3D则是通过大型的3D游戏引擎制作游戏世界和各种物件的3D模型,并有计算机解决后失去真实感较强的3D图像。 1、3D场景美术师 场景则是游戏中的环境、机械、道具等死物。场景开始对美术的要求没有那么高,只有纯熟使用3D软件就行了。 逐渐把握游戏场景元素设计理念,不同格调游戏的制作方法。着重训练学员材质解决技法,能使学员依据原画制作出精密真切的场景元素。适应各大公司的游戏制作要求,网络游戏、次世代游戏、影视动画公司皆能胜任。 场景美术师会接触很多其余的专业知识,要察看生存,积攒很多的教训。比方做一个城市的街道,你须要理解城市规划方面的常识,甚至要去钻研下水道怎么安排是实在的。 2、3D角色美术师 角色就是游戏中的人物、动物等活物,角色的终点要求比拟高,要求有比拟好的美术根底,对人体构造有娴熟的理解,当然还要会用3D软件。 因为角色不论做什么,原理都是一样的,就是人体组织构造,你会越做越纯熟,到最初甚至闭着眼睛都能做;场景是学无止尽的。所以总的来说,角色上手难,越做越容易;场景上手绝对容易,然而要做好须要一直的学习进步各方面的素养。 次世代游戏与影视角色高面模建模,Zbrush雕刻工具使用与实际,次世代游戏贴图剖析与绘制,法线贴图技术。 三、3D建模的工具 1、建模软件 (老手软件)3D Studio Max,常简称为3d Max或3ds MAX,是Discreet公司开发的(后被Autodesk公司合并)基于PC零碎的三维动画渲染和制作软件。首先开始使用在电脑游戏中的动画制作,后更进一步开始参加影视片的特效制作,例如X战警II,最初的武士等。在Discreet 3Ds max 7后,正式更名为Autodesk 3ds Max 最新版本是3ds max 2020! 在利用范畴方面,广泛应用于广告、影视、工业设计、建筑设计、三维动画、多媒体制作、游戏、以及工程可视化等畛域。 3D MAX 容易上手,3D MAX的制作流程非常简洁高效,能够使你很快的上手,所以先不要被它的大堆命令吓倒,只有你的操作思路清晰上手是非常容易的,后续的高版本中操作性也非常的简便,操作的优化更有利于初学者学习。 (进阶软件)Autodesk Maya是美国Autodesk公司出品的世界顶级的三维动画软件,利用对象是业余的影视广告,角色动画,电影特技等。Maya功能完善,工作灵便,易学易用,制作效率极高,渲染真实感极强,是电影级别的高端制作软件。 很多三维设计人利用Maya软件,因为它能够提供完满的 3D 建模、动画、特效和高效的渲染性能。Maya软件的弱小性能正是那些设计师、影视制片人、网页游戏开发者、视觉艺术设计专家极为推崇的起因。Maya 将他们的规范晋升到了更高的档次。 (大佬软件)ZBrush 是一个数字雕刻和绘画软件,它以弱小的性能和直观的工作流程彻底改变了整个三维行业。在一个简洁的界面中,ZBrush 为当代数字艺术家提供了世界上最先进的工具。以实用的思路开发出的性能组合,在激发艺术家创作力的同时,ZBrush 产生了一种用户感触,在操作时会感到十分的顺畅。ZBrush可能雕刻高达 10 亿多边形的模型,所以说限度只取决于的艺术家本身的想象力。 ZBrush软件是世界上第一个让艺术家感到无约束自在创作的 3D 设计工具!它的呈现齐全颠覆了过来传统三维设计工具的工作模式,解放了艺术家们的双手和思维,辞别过来那种依附鼠标和参数来蠢笨创作的模式,齐全尊重设计师的创作灵感和传统工作习惯。 (衣料解算软件)Marvelous designer能够制作出和实在服装一样的虚构服装。利用Marvelous Designer进行作品创作的话,在进步品质的同时还能够节约工夫。 Marvelous Designer的变革性板片基础理论曾经在EA,Konami等最优良的游戏工作室应用, 维塔数码的’霍比特人’和’丁丁历险记’等影片里也利用了该技术。为角色制作的布料衣服提供解决方案。 四、贴图绘制软件 (手绘流程制作)BodyPaint 3D 是当初最为高效、易用的实时三维纹理绘制,须要配合ps应用,是当初手绘贴图制作的支流软件。同类型还有3D-coat 图片起源:页游www.hp91.cn页游 (次世代流程)Substance Painter是目前互联网上最优良的次世代游戏贴图绘制软件,该软件提供了构建3D素材所需的所有工具,包含粒子笔刷,能够模仿天然粒子着落,粒子的轨迹造成纹理。 与其相配合的还有substance designer、Bitmap2Material、Quixel等材质,贴图转换软件。 ...

March 3, 2021 · 1 min · jiezi

关于游戏开发:大型游戏服务器架构该怎么设计

一、游戏服务器特色游戏服务器,是一个会长期运行程序,并且它还要服务于多个不定时,不定点的网络申请。所以这类服务的特点是要特地关注稳定性和性能。这类程序如果须要多个合作来进步承载能力,则还要关注部署和扩容的便利性;同时,还须要思考如何实现某种程度容灾需要。因为多过程协同工作,也带来了开发的复杂度,这也是须要关注的问题。 性能束缚,是架构设计决定性因素。基于游戏业务的性能特色,对服务器端零碎来说,有以下几个非凡的需要: 游戏和玩家的数据存储落地对玩家交互数据进行播送和同步重要逻辑要在服务器上运算,做好验证,避免外挂。针对以上的需要特色,在服务器端,咱们往往会关注对电脑内存和CPU的应用,以求在特定业务代码下,能尽量满足高承载低响应提早的需要。最根本的做法就是“空间换工夫”,用各种缓存的形式来以求得CPU和内存空间上的均衡。另外还有一个束缚:带宽。网络带宽间接限度了服务器的解决能力,所以游戏服务器架构也必然要思考这个因素。 二、游戏服务器架构因素对于游戏服务端架构,最重要的三个局部就是,如何应用CPU、内存、网卡的设计: 内存架构:次要决定服务器如何应用内存,以最大化利用服务器端内存来进步承载量,升高服务提早。逻辑架构:设计如何应用过程、线程、协程这些对于CPU调度的计划。抉择同步、异步等不同的编程模型,以进步服务器的稳定性和承载量。能够分辨别服,也能够采纳世界服的形式,将雷同功能模块划分到不同的服务器来解决。通信模式:决定应用何种形式通信。基于游戏类型不同采纳不同的通信模式,比方http,tcp,udp等。三、服务器演变过程1、卡牌等休闲游戏弱交互游戏服务器基于游戏类型不同,所采纳的架构也有所不同,咱们先讲一下简略的模型,采纳http通信模式架构的服务器:这种服务器架构和咱们罕用的web服务器架构差不多,也是采纳nginx负载集群反对服务器的程度扩大,memcache做缓存。惟一不同的地点不同的在于通信层须要对协定再加工和加密,个别每个公司都有本人的一套基于http的协定层框架,很少采纳开源框架。 2、长链接游戏服务器长连贯游戏和弱联网游戏不同的中央在于,长连贯中,玩家是有状态的,服务器能够时时和client交互,数据的传送,不像弱联网个别每次都须要从新创立一个连贯,音讯传送的频率以及速度上都快于弱联网游戏。长链接网游的架构通过几代的迭代,类型也变得日益丰盛,以下为每一代服务器的特点以及架构模式。 1)、第一代网游服务器(单线程无阻塞)最早的游戏服务器是1978年,英国驰名的财经学校University of Essex的学生 Roy Trubshaw编写了世界上第一个MUD程序,叫做《MUD1》。 MUD1 是一款纯文字的世界,没有任何图片,然而不同计算机前的玩家能够在游戏里独特冒险、交换。与以往具备网络联机性能的游戏相比, MUD1是第一款真正意义上的实时多人交互的网络游戏,它最大的特色是可能保障整个虚拟世界和玩家角色的继续倒退——无论是玩家退出后从新登录还是服务器重启,游戏中的场景、宝箱、怪物和谜题仍放弃不变,玩家的角色也仍然是上次的状态。MUD中文版 MUDOS应用单线程无阻塞套接字来服务所有玩家,所有玩家的申请都发到同一个线程去解决,主线程每隔1秒钟更新一次所有对象(网络收发,对象状态,刷新地图,刷新NPC)。用户应用 Telnet之类的客户端用 Tcp协定连贯到 MUDOS上,应用纯文字进行游戏,每条指令用回车进行宰割。这样的零碎在过后每台服务器承载个4000人同时游戏。从1991年的 MUDOS公布后,寰球各地都在为他改良,裁减,推出新版本。 MUDOS中游戏内容通过 LPC脚本进行定制,逻辑解决采纳单线程tick轮询,这也是第一款服务端架构模型,起初被利用到不同游戏上。后续很多游戏都是跟《UO》一样,间接在 MUDOS上进行二次开发,直到 现在,一些回合制游戏,以及对运算量小的游戏,仍然采纳这种服务器架构。 第一代服务器架构图:线程模型 2)、第二代网游服务器(分辨别服)<span style="color: rgb(85, 85, 85);">2000年左右,随着图形界面的呈现,游戏更多的采纳图形界面与用户交互。此时随着在线人数的减少和游戏数据的减少,服务器变得不抗重负。于是就有了分服模型。分服模型构造如下:</span><span style="color: rgb(85, 85, 85);"></span>分服模型是游戏服务器中最典型,也是历久最悠久的模型。在晚期服务器的承载量达到下限的时候,游戏开发者就通过架设更多的服务器来解决。这样提供了很多个游戏的“平行世界”,让游戏中的人人之间的比拟,产生了更多的空间。其特色是游戏服务器是一个个独自的世界。每个服务器的帐号是独立的,每台服务器用户的状态都是不一样的,一个服就是一个世界,大家各不牵扯。 起初游戏玩家呐喊要跨服打架,于是就呈现了跨服战,再加上随着游戏的运行,单个服务器的游戏沉闷玩家越来越少,所以前期就有了服务器的合并以及迁徙,缓缓的以服务器的凋谢、合并造成了一套成熟的经营伎俩。目前少数游戏还采纳分服的构造来架设服务器,少数页游还是采纳这种模式。 线程调度 分服尽管能够解决服务器扩大的瓶颈,但单台服务器在以前单线程的形式来运行,没方法充分利用服务器资源,于是又演变出了以下2种线程模型。 异步-多线程,基于每个场景(或者房间),调配一个线程。每个场景的玩家同属于一个线程。游戏的场景是固定的,不会很多,如此线程的数量能够保障不会一直增大。每个场景线程,同样采纳tick轮询的形式,来定时更新该场景内的(对象状态,刷新地图,刷新NPC)数据状态。玩家如果跨场景的话,就采纳投递和告诉的形式,告知两个场景线程,以此更新两个场景的玩家数据。 多过程。因为单过程架构下,总会存在承载量的极限,越是简单的游戏,其单过程承载量就越低,因而肯定要冲破过程的限度,能力撑持更简单的游戏。多过程零碎的其余一些益处:可能利用上多核CPU能力、更容易进行容灾解决。 多过程零碎比拟经典的模型是“三层架构”,比方,基于之前的场景线程再做改良,把网络局部和数据库局部拆散为独自的过程来解决,逻辑过程分心解决逻辑工作,不合IO打交道,网络IO和磁盘IO别离交由网路过程和DB过程解决。 3)、第三代网游服务器之前的网游服务器都是分辨别服,玩家都被划分在不同的服务器上,每台服务器运行的逻辑雷同,玩家不能在不同服务器之间交互。想要更多的玩家在同一世界,放弃玩家的活跃度,于是就有了世界服模型了。世界服类型也有以下3种演变: 一类型(三层架构) 网关局部拆散成单端的gate服务器,DB局部拆散为DB服务器,把网络性能独自提取进去,让用户对立去连贯一个网关服务器,再有网关服务器转发数据到后端游戏服务器。而游戏服务器之间数据交换也对立连贯到网管进行替换。所有有DB交互的,都连贯到DB服务器来代理解决。二类型(cluster) 有了一类型的教训,后续必定是拆分的越细,性能越好,就相似当初微服务,每个雷同的模块散布到一台服务器解决,多组服务器集群独特组成一个游戏服务端。个别地,咱们能够将一个组内的服务器简略地分成两类:场景相干的(如:行走、战斗等)以及场景不相干的(如:公会聊天、不受区域限度的贸易等)。常常能够见到的一种计划是:gate服务器、场景服务器、非场景服务器、聊天管理器、AI服务器以及数据库代理服务器。如下模型:以上中咱们简略的讲下常见服务器的三种类型性能: 场景服务器:它负责实现次要的游戏逻辑,这些逻辑包含:角色在游戏场景中的进入与退出、角色的行走与跑动、角色战斗(包含打怪)、工作的认领等。场景服务器设计的好坏是整个游戏世界服务器性能差别的次要体现,它的设计难度不仅仅在于通信模型方面,更次要的是整个服务器的体系架构和同步机制的设计。非场景服务器:它次要负责实现与游戏场景不相干的游戏逻辑,这些逻辑不依附游戏的地图零碎也能失常进行,比方公会聊天或世界聊天,之所以把它从场景服务器中独立进去,是为了节俭场景服务器的CPU和带宽资源,让场景服务器可能尽可能快地解决那些对游戏流畅性影响较大的游戏逻辑。网关服务器: 在类型一种的架构中,玩家在多个地图跳转或者场景切换的时候采纳跳转的模式,以此进行跳转不同的服务器。还有一种形式是把这些服务器的节点都通过网关服务器治理,玩家和网关服务器交互,每个场景或者服务器切换的时候,也有网关服务器对立来替换数据,如此玩家操作会比拟晦涩。通过这种类型服务器架构,因为压力扩散了,性能会有显著晋升,负载也更大了,包含目前一些大型的 MMORPG游戏就是采纳此架构。不过每减少一级服务器,状态机复杂度可能会翻倍,导致研发和找bug的成本上升,这个对开发组挑战比拟大,没有教训,很容出错。 三类型(无缝地图) 魔兽世界的中无缝地图,想必大家印象粗浅,整个世界的挪动没有像以往的游戏平台一样,在切换场景的时候须要loading期待,而是间接行走过来,体验晦涩。 当初的游戏大地图采纳无缝地图少数采纳的是9宫格的款式来解决,因为地图没有魔兽世纪那么大,所以采纳单台服务器多过程解决即可,不过相似魔兽世界这种大世界地图,必须思考2个问题: 1、多个地图节点如何无缝拼接,特地是当地图节点比拟多的时候,如何保障无缝拼接2、如何反对动静散布,有些区域人多,有些区域人少,保障服务器资源利用的最大化为了解决这个问题,比拟以往依照地图来切割游戏而言,无缝世界并不存在一块地图下面的人有且只由一台服务器解决了,此时须要一组服务器来解决,每台 Node服务器用来治理一块地图区域,由 NodeMaster(NM)来为他们提供总体治理。更高层次的 World则提供大陆级别的治理服务。 一个 Node所负责的区域,天文上没必要连贯在一起,能够对立交给一个Node去治理,而这些区块在天文上并没有分割在一起的必要性。一个 Node到底治理哪些区块,能够依据游戏实时运行的负载状况,定时保护的时候进行更改 NodeMaster 下面的配置。 对象的无缝迁徙玩家A、B、C别离代表3种不同的状态,以及不同的迁徙形式,咱们别离来看。 玩家A: 玩家A在node1地图服务器上,由node1管制,如果迁徙到node2上,须要将其数据复制到node2上,而后从node1移除。玩家B: 玩家B在node1和node2两头,此时由node1和node2保护,若是从node1行走到node2的过程中,会向1申请,同时向2申请,待全副挪动过来了再移除。玩家C:玩家C在node2地图服务器上,由node2管制,如果迁徙到node1上,须要将其数据复制到node1上,而后从node2移除。具体魔兽世界服务器的剖析,篇幅过多,咱们当前再聊。 3、房间服务器(游戏大厅)房间类玩法和MMORPG有很大的不同,在于其在线播送单元的不确定性和播送数量很小。而且须要匹配一台房间服务器让多数人进入一个服务器。 这一类游戏最重要的是其“游戏平台大厅”的承载量,每个“游戏房间”受逻辑所限,须要维持和播送的玩家数据是无限的,然而“游戏大厅”须要维持相当高的在线用户数,所以一般来说,这种游戏还是须要做“分服”的。典型的游戏就是《英雄联盟》这一类游戏了。而“游戏大厅”外面最有挑战性的工作,就是“主动匹配”玩家进入一个“游戏房间”,这须要对所有在线玩家做搜寻和过滤。 玩家先登录“大厅服务器”,而后抉择组队游戏的性能,服务器会告诉参加的所有游戏客户端,新开一条连贯到房间服务器上,这样所有参加的用户就能在房间服务器里进行游戏交互了。 四、最初游戏行业绝对于互联网利用来说,其开放性和标准化并不欠缺,这就导致了很其余行业看游戏有一种神秘面纱,隐秘而关闭。 造成这个起因有很多,游戏业务的复杂性以及受众群体小是次要起因,它不像web利用天生有开源组织和社区基因的反对,也没有互联网行业的如此大的受众面和影响力,除了一些比拟闻名的游戏引擎以外其余的性能组建都是有各个游戏公司基于本人业务逻辑本人搭建,每个公司业务方向不同又加大了常识的流通以及规范的建设,这对整个生态的倒退曾经产生了制约,特地是那些想退出游戏行业的新人来说,准入门槛较高,网上可找到的学习材料也很少。————————————————

March 1, 2021 · 1 min · jiezi

关于游戏开发:UE4Unity绘制地图基础元素面和体

前言基于UE4/Unity绘制地图根底元素-线(上篇) 基于UE4/Unity绘制地图根底元素-线(下篇) 搞定地图画线之后,接下来就是绘制面和体了: 面作为地图渲染的根本元素之一,在地图中能够代表各种模式的区域,例如海面、绿地等。面数据通常以离散点串模式存储,因而渲染时最关注的是如何将其展示为闭合的图形。 体能够了解为带有高度的面,在地图中代表各种修建,通常是由其顶部面数据和高度数据处理失去。 本文记录了绘制面和体的流程以及解决闪动问题的计划。 绘制多边形区域面面数据通常以离散点串模式存储,面的绘制与线的绘制原理相似。渲染的根本单位是三角形,线是通过扩大线宽结构三角形后渲染,而面是通过将多边形拆分为多个三角形后渲染。 拆分为三角形的过程被称为三角剖分,罕用的三角剖分算法是耳切法(Ear Clipping),比拟成熟的计划是Mapbox的earcut,对于有 [公式] 个顶点的多边形,其工夫复杂度为 [公式] ,值得注意的是,三角剖分的解可能是不惟一的,任何一种剖分形式都可能渲染失去面,但细小的三角形更容易使面中的同一像素绘制屡次,造成适度绘制(Overdraw),因而依据多边形特色做一些剖分秩序的调整能够作为一个优化点。 剖分实现的多边形区域,在指定了每一个顶点的色彩之后,就能绘制失去纯色的面。和道路线的Z-fighting问题相似,区域面也须要解决同一高度叠加显示的问题。同时,二维的道路线和区域面整体也处于同一个高度上,因而也须要对立思考层级关系,将所有的道路线置于区域面之上。对立解决实现就能够失去二维的地图底板了。 绘制多边形修建体二维地图底板实现后,就轮到地图上的楼块修建了。为了缩小数据量,通常的存储形式是顶面点串和其对应的拔起高度,在渲染时减少顶点形成闭合体。 顶面渲染流程和闭合区域面统一,侧面则是依据楼高进行绘制,在每两个相邻顶点间渲染一个矩形从而形成闭合体的侧面,为了缩小绘制次数通常只绘制朝向外侧的侧面,底面在失常视角下看不到,也能够酌情抉择是否绘制。 修建体的渲染只比区域面多了拔高产生的侧面,逻辑比较简单,解决失去所有三角形数据后,配置好顶点色彩即可实现渲染。 奇怪的修建体Z-fighting问题实践上来说,修建体数据的顶面通常不会重合,因而在拔起渲染后不会呈现Z-Fighting问题,但奇怪的是,渲染后依然发现一些体存在侧面闪动问题。通过全链路的排查,才查出是多边形数据的问题。 三角剖分在应用时有一个前置条件:应用对象必须为简略多边形,即多边形中的任何两条边仅能够在顶点处相交。下图(a)多边形为满足定义的简略多边形,图(b)多边形边01和23在非顶点处相交,因而是非简略多边形。 对于非简略多边形,应用三角剖分只能得出较为称心的后果,但不能保障其正确性。从下图四个顶点形成的非简略多边形的三角剖分后果能够看到,多边形渲染时会失落顶点并且产生谬误的三角形,无奈还原数据真实情况。 依照这种想法对现有数据进行了边的相交检测,的确存在一小部分的多边形不是简略多边形。而体元素的立面拔起是依照原始数据在每一组相邻顶点间绘制矩形,因而会产生问题。以上述的非简略多边形(b)为例,边12拔起生成矩形1245,边23拔起生成矩形2364,两个侧面矩形在面1245上齐全重合,当外立面贴上不同的纹理后就会产生Z-Fighting景象。同时,因为外立面仅仅绘制朝向外侧一面,面1245在对侧查看时会隐没,产生十分诡异的成果。 针对这个问题,比拟容易想到的解决办法次要是以下三个: 1、间接过滤,简略粗犷。 2、依据多边形计算外接矩形,缩小细节 3、依据三角剖分后果剔除多余顶点,从新生成简略多边形 以上三个计划对于多边形的细节保留由少到多,但并不是齐全还原实在数据。尤其对于一些简单修建,某一个面的谬误会导致最终拼装失去的渲染后果谬误。因而比拟现实的形式是修复非简略多边形,将其合成为多个简略多边形,别离渲染还原细节。 简略多边形的断定与修复依据简略多边形的定义,很容易想到采纳暴力解法进行断定:一个 边形有 条边,每条边只须要和其余的 条不相邻边判断是否相交即可达到目标,其工夫复杂度为 ,对于仅须要进行一遍数据荡涤的静态数据来说曾经足够。但对于须要实时处理的动态数据来说,其须要遍历所有组合,尤其对于可能仅存在大量相交点的状况,冗余计算太多,因而能够引入工夫复杂度更低的相交断定算法进行解决。 对于一个非简略多边形,在合成为多个简略多边形后,绘制所有面积不为0的图形就能够了。这种计划能够最大限度还原原始数据,并且躲避闪动问题。 小结解决了数据造成的闪动问题后,就能够在修建的侧面和顶面应用纯色或者纹理贴图进行装璜,搭配天空盒和一些纯色元素去装璜,曾经能够简略模拟出城市的成果。但在以后的修建拔起渲染形式下,只能通过贴图的模式去表白修建细节,如果须要更精密的表白成果,例如玻璃窗体构造、楼顶设施等,须要减少额定的三角形去进行出现。 作者:程序员阿Tu链接:https://zhuanlan.zhihu.com/p/... 起源:知乎 著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。

February 5, 2021 · 1 min · jiezi

关于游戏开发:电子游戏设计与制作游戏编程概述

1 根底概念游戏=逻辑+数据 把游戏类比为一个带有前置终端的实时数据库,该终端实时地承受用户(玩家)输出的各种交互指令,取出相应的数据,并“优雅”地将这些数据以各种模式(视觉、听觉等)展示给用户。 游戏的根本部件游戏的运行流程该图片起源:www.laoshoucun.com Unity应用脚本组件管制游戏对象:拜访本身组件、拜访其余物体(变量链接、查找子物体、查找名字标签)计算机游戏的开发过程个别开发过程: 产生创意实现调整、测试并公布2 游戏开发的根本理念和办法2.1 数据驱动理念把程序中的管制信息从程序中分离出来,造成形象控制程序与管制信息表两局部: 形象控制程序是可重用的,在具体的利用中不用扭转;逻辑管制信息表是可变的,其内容不同,程序的运行后果就不同。数据数据驱动的根本策略 事后开发专门的数据获取和管理工具保障游戏数据的动静可调整性如何保障游戏数据的动静可调整性 创立一个能够解析文本文件或者命令的子系统。对游戏的初始化数据/参数进行动静地解释和配置一些常数搁置在文本文件中。很容易地对这些参数进行批改所有的数据都不放在代码内应用脚本来管制游戏的流程2.2 开发游戏软件的无效办法原型法一直地运行零碎“原型”来进行启发、揭示、判断、批改和欠缺的零碎开发方法。 建设原型的劣势1、发现游戏的可行性。2、尝试不同的构想。3、均衡游戏规则。4、促成沟通交流。5、获取反馈。 原型的类别1、纸笔原型2、桌面游戏3、绘图程序4、程序原型 原型零碎包含1、可玩性测试2、用户界面3、子系统4、算法测试 中间件可复用软件,处于操作系统软件与用户的应用软件的两头。 作用:为处于本人下层的应用软件提供运行与开发的环境,帮忙用户灵便、高效地开发和集成简单的应用软件。 瀑布式开发流程特色:不须要迭代、须要更多工夫打算与设计、违反循环法令、简单程序无奈实用 游戏的迭代开发该图片起源:页游www.laoshoucun.com网页游戏 游戏的测试与调试对游戏设计阶段的BUG的修改,找出游戏设计自身存在的缺点 对游戏参数的调整 游戏开发的基本准则游戏开发都必须为今后的重用作好筹备齐备的开发文档先设计,后编程。设计工作随着开发过程的推动而逐渐地进行粗劣和欠缺灵便无效地安顿开发过程及时地发现错误

January 6, 2021 · 1 min · jiezi

关于游戏开发:游戏应用中的非易失性SRAMnvSRAM

数年来,诸如投币游戏机和视频扑克机等游戏机始终是游戏行业的根底。通常这些游戏机的遍及水平取决于赢钱的可能性,游戏机的可靠性以及游戏机的娱乐价值。绝对于其余可用游戏选项的游戏机。 以后基于微处理器的游戏机应用动态随机存取存储器(ram)来存储要害且间断变动的运行时解决数据,机器状态以及与游戏相干的其余配置详细信息。处理器能够轻松地将RAM连贯到其规范地址,数据和管制I/O,并且能够以起码的固件开销拜访设施,而磁盘驱动器或其余闪存则不是这种状况。因为RAM存储所有重要配置,因而该内存的内容通常对游戏机的运行至关重要。 要害数据的示例可能包含以下一项或多项:•获胜后果的数量•机器付款•下注细节(例如,下注次数或下注硬币数量)•货币刷卡详细信息•硬币金额和面额•每个玩家的游戏记录,例如游戏级别,应用的物品和工夫•计时器数据 RAM存储器的一个弱点是它的易失性,在断电时会导致内容失落。在许多要害利用中,当没有零碎电源时应保留RAM内容,电池或可充电Supercap用来维持SRAM的电源以保持数据。通常游戏法规还要求部署备用电池配置,以在任何断电或电源故障期间放弃游戏状态。部署电池选件的固有危险是电池的可靠性。零碎电源稳定或电源故障会重大影响电池性能,如果保护不当会导致电池齐全故障。在游戏应用程序中,如果在要害数据传输期间游戏机的电源失落,并且如果备用电池也失败或不可用,则零碎RAM将失落所有内容,这可能导致系统齐全敞开或呈现故障。 为了防止这种灾难性的故障,游戏机设计师会审慎设计电池反对的RAM解决方案。赛普拉斯的nvSRAM可提供规范RAM的性能,并且无需应用电池.NV-SRAM不会遇到与电池无关的问题,并且能够在所有断电状况下平安保留要害数据,这使其成为电池后备非易失性RAM的现实抉择解决方案。 图1显示了游戏机架构的典型框图

December 17, 2020 · 1 min · jiezi

关于游戏开发:网页游戏是怎样开发出来的网页游戏开发的流程以及常用的技术

网页游戏又叫Web游戏,无端的网游。简称页游,是基于Web浏览器的网络在线多人互动游戏,无需下载客户端,任何中央任何工夫任何一台能上网的电脑就能够嗨皮的游戏。网页游戏开发的程序形成能够分为三大部分:第一:数据流程。第二:美术。第三:程序。 1、数据的流程 数据流程其中,数据流程包含了性能。也只有在性能中能力体现数据流程。 比方最简略的卖买产品。要实现这个性能,那么须要有产品根底表、产品具体表、商店表、背包表。如果扩展性更强,相应的双表是少不不了的。 表的问题都简略了,要害是这个物品有什么用,这样物品的起源,一大堆数据,物品的走向,又是一大堆数据。最初,这些数据得绕成一个圈。绕圈是一件艰难的事件,特地是性能和道具多了起来的时候。难度是2的n次方。 2、美术 UI:简洁丑陋的界面总会有益处。 小图标:道具,地图,配备,一类至多10个吧?大体上百把个是须要的。 3、程序分5个局部: 服务器定时器:(C语言或本人设定服务器)定时循环执行某一段代码。而这段代码次要是依据数据库的数据进行更新。这个能够找个C语言程序员来做。对于C语言程序员来讲,这个性能是相当的简略。当然,具体的解决数据的判断和操作数据库,须要你本人写。让C语言程序员给你段规范代码就行了。齐全反对sql语句的。 性能页面、性能函数。次要就是数据存取,判断,数据走向。 ajax函数:(可选)某些须要伪即时的性能要用到。 javascript函数:(可选)模仿客户端的数据计算。也就是webgame的与工夫相干的数据。分为两局部。一部分是实在数据,是由服务器端的定时器计算的。另一部分是只有初始值,客户端显示用的。不须要即时同步,仅仅须要模仿同步就行。 数据库:一大堆根底数据表和具体数据表。根底数据表:比方等级1到等级100的用户的属性初始值。具体数据表:每个用户的具体属性。 新开的网页游戏的开发工具和技术新开的网页游戏开发技术有很多,但罕用的开发工具和技术次要有以下几个: 1)ASP技术 Actieserver Paga(ASP)意为“动静服务器页面”。ASP是微软公司开发用来代替CGI脚本城府的编程工具,当用于设计动静网站。ASP脚本集成于HTML中,无需编译即可间接解释执行,独立于浏览器(能解释LTML码的浏览器即可浏览ASP网页),爱护源码(ASP脚本在服务器上执行,传到浏览器端的只是ASP执行后果所生成的惯例HLML代码)。 2)Flex技术Flex是Adobe的服务器端产品。该技术提供了一个新的,基于规范的语言和编程模型,其编程模型反对罕用的设计模式,可能使企业创立许多有吸引力的,交互的疾速利用,争强了用户对网页的体验。传统网页游戏开发的局限是体现层受到肯定的束缚,而Flex技术能轻松地解决这一技术难题。网游Small World就是基于Flex技术开发的。 3)Ajax技术 Asynchronousjavascript and xml(Akax)意为“异步 JavaScript和XML”。Ajax是一种创立交互式网页利用的网页开发技术,它不是一个新的编程语言,而是一个编程技术。Ajax的自卑长处就是能再吧刷新整个页面的前提下更新数据,使得Web应用程序更为迅速的响应用户的交互需要。 4)JSP技术Java ServerPages(JSP)是一种动静网页技术标准,它可在传统的网页HTML文件(_.htm,_.html)中插入java程序段和JSP标记,其生成的内容的逻辑被封装在标识和JavaBeans或者Enterprise JavaBeans TM组件)可能执行应用程序所要求的更为简单的解决。因为Java在移植性、扩展性、多线程方面的特点使它成为目前网页游戏的开发语言。由Java技术开发的高端网页游戏,能解决各类与服务器的交互和简单图形,开发大型网络游戏。目前国内网游《倾城》就是一款基于Java语言开发的游戏。 5)PHP技术 HypertextPreprocessor(PHP)意义“超级文本预处理语言”。PHP是一种在服务器端执行的嵌入HRML文档的脚本语言,格调相似C语言,利用宽泛。PHP于CGI或Perl相比,能更疾速地执行动静网页。PHP是将程序嵌入到HTML文档中去执行,跨平台性强,程序开发快,执行相率高,可编译以达到加密和优化代码,反对简直所有风行的数据库,以及操作系统。 显然在网页游戏开发前,还要组织相干的专业人才,制作一款网络游戏须要的最外围人才是原画、2D、3D、程序设计、策动等这些方面的人才是必不可少的,因而,要开发一个网页游戏除了要程序员以外,千万不要忘了筹备以上人才。

November 18, 2020 · 1 min · jiezi

关于游戏开发:Among-Us火爆全球实时语音助力派对游戏开启第二春

往年在寰球“宅经济”的影响下,社交派对类游戏意外的迎来了暴发。8月份,《糖豆人:终极淘汰赛》忽然爆火,发明了首日150万玩家、首周Steam 200万销量、单周Twitch累计观看2300万小时的数据。在糖豆人之后,另一款社交派对类游戏《Among Us》开始发力,截止到目前《Among Us》观看时长曾经超过4千万小时,稳居全网站第一。STEAM玩家人数峰值在8月翻了近十倍,日活人数超过6000万。挪动平台上,游戏挪动版拿下63个国家的苹果商店下载榜首,达到总榜前10的国家超过108个。 一、《AmongUs》爆火,引爆社交派对类游戏《AmongUs》在Steam销量周榜上间断霸榜,同时还是油管上最受关注的游戏直播题材。这款2年前就诞生的小众游戏,在韩国、巴西、英国、美国等多个国家的大V主播的“直播带货”下,拉开了社交派对类游戏席卷寰球的尾声。 线上社交派对类游戏在2018年就已经暴发过,以狼人杀、剧本杀为代表的多人发言推理类游戏饱受关注,因此玩法和格调与狼人杀相似的《AmongUs》被国内玩家称为“太空狼人杀”或“太空杀”。但与狼人杀不同的是,《AmongUs》中所有玩家都全程参加,多种角色,更重视逻辑和策略,比狼人杀游戏更烧脑更刺激。《AmongUs》的游戏玩法是所有玩家在一艘太空飞船上,船员须要找出藏身于众人中的“内鬼”,而“内鬼”则有两种取得游戏的胜利,第一种是一直搞破坏,让玩家所乘坐的飞船故障,不能顺利出航;第二种则是一直地杀死船员,直到残余船员数量小于或等于内鬼数量。 当发现被杀死的船员尸体后,游戏进入发言投票环节。所有成员开启演技和逻辑的较量,投出本人认为的凶手。“死亡玩家”也不会出局,而是持续存在游戏中,能够仍旧修理或毁坏飞船,只是无奈与存活玩家进行交换。《AmongUs》采纳非回合制玩法,游戏过程中做工作和发言投票交叉进行,没有固定的发言环节,更具随机性。与狼人杀相比,玩家即便在不发言阶段也能够进行各类小工作,这些小工作没有太大难度,能够与唇枪舌剑的发言投票环节互为补充,让游戏兼顾娱乐休闲和感性逻辑两面。 飞船工作的退出,也让《AmongUs》防止了呈现玩家因不发言而挂机、溜号景象。能够看到,退出了“太空船”背景后,“太空狼人杀”更好的兼顾了每位玩家的体验,游戏中减少的工作设计,让游戏气氛更强,玩家能更好的沉迷其中。 二、实时语音+派对游戏,让玩家体验降级无论是狼人杀、剧本杀还是太空狼人杀,游戏过程的推动都依赖参与者的线上实时沟通。相比IM文字,实时语音能让游戏玩家取得更好的体验。 沟通效率最高,不影响游戏过程低提早的实时语音,能疾速实现玩家间的信息替换,沟通效率最高。相比之下IM聊天须要工夫去打字和浏览,实时性有余,一来一回耗时过久,影响游戏节奏和过程; 以语音带剧情,让游戏更刺激语音互动中,发言者的语气、腔调变动能够成为玩家判断的根据,让线上互动交换更具真实感。对于老手局或陌生人局,逻辑紧密的发言,能将玩家迅速代入剧情中,从而缩小“无脑投票”、“随便投人”,让玩家更全情投入。 与游戏共生,带来更好的游戏体验社交派对类游戏中,实时语音是次要的沟通工具,而内置语音,则能让游戏体验取得最大化晋升。以《AmongUs》为例,游戏自身是没有零碎语音的,玩家要么通过零碎内的IM要么通过第三方语音工具进行沟通。在应用性能第三方语音工具时,则容易呈现玩家泄密、身份泄露等问题。 比方,游戏中零碎设定死亡玩家能够持续做工作但不能与存活玩家交换,可在第三方语音沟通工具中,无奈对死亡玩家的发言做限度,存在“剧透”的危险。 因而在派对游戏中,实时语音不仅充当了次要沟通工具,也是影响玩家体验的重要性能。这股在寰球范畴内刮起的“派对游戏热”中,绕不开实时语音的加持。为了帮忙客户疾速的将更多创意派对游戏落地,音视频云服务商即构科技提供了贴合场景和业务的实时语音计划。 三、全面的性能+丰盛的服务教训,即构提供派对游戏语音整体化计划基于弱小的自研音视频技术,即构提供仅需四行代码接入,就能轻松地将高清语音嵌入到游戏中的游戏语音计划。 超低提早基于寰球部署的200+BGP节点,即构可实现超低100ms提早的游戏语音互动。最高反对32路实时音视频互动,实现多人低提早晦涩互动,满足派对游戏多人发言互动的需要。 高音质基于优良的自研音视频引擎和成熟的语音3A前解决技术,即构语音计划可实现一流的互动双讲体验,打造清晰透亮的游戏音质;同时提供多种变声变调特效,例如萝莉音、机器人音等;并反对叠加播放多个气氛音,营造趣味游戏体验。 低性能耗费背靠19年音视频技术积淀,即构在音频编解码、视频编解码等信号处理算法方面寰球当先。可实现轻量集成,安装包体积优化,CPU占用低,耗电发热低。 麦位治理即构游戏语音计划反对多样化的麦位治理,提供上麦、下麦、换麦、抱麦、禁麦、封麦等多样化操作,可满足多角色沟通须要。 疾速切换房间通过更简略易用的“switch room”单接口调用、多种音频设备模式,升高了玩家切换房间推拉流耗时,保障了玩家疾速切换房间,并且切换房间后放弃对麦克风和扬声器的占用,让音频不中断。 在服务了“狼人杀”、“我是谜”等多家派对游戏客户后,即构积攒了丰盛的教训,在全面的语音性能外还提供了贴合业务场景的方案设计。 防炸麦在游戏语音计划根底上,提供防炸麦、防黑麦计划,防止非正常用户利用外挂或者破绽绕开麦位治理,非法抢麦或者上麦,在游戏中歹意发言,影响游戏过程和秩序。 内容审核作为强社交互动类产品,派对游戏须要进行内容审核,降平台经营危险。即构与业余的内容辨认服务商数美深度单干,提供“音频互动+鉴定审核”的残缺闭环,帮忙客户污染业务环境,平安稳固的线上经营。 从狼人杀到剧本杀再到太空狼人杀,社交派对游戏不再满足照搬线下玩法,通过多样化的游戏内容设定,造成集“逻辑推理与社交娱乐”于一体的轻松休闲新玩法。 即构作为音视频云服务商,以优质的实时音视频技术和丰盛的行业服务,致力于帮忙更多的派对游戏客户实现产品翻新和落地,为用户带来更多新游戏玩法,不断丰富人们的娱乐生存。

November 4, 2020 · 1 min · jiezi

关于游戏开发:多重福利加码-2020-Ohayoo游戏开发者沙龙走进广州站

多重福利加码 “2020 Ohayoo游戏开发者沙龙”走进广州站日前,“2020 Ohayoo游戏开发者沙龙”在成都站顺利举办,流动现场共有200余位游戏开发者与嘉宾进行了交换互动,播种了满满的游戏研发经营教训,也进一步了解了Ohayoo开放平台对开发者的助力。 在各地开发者热烈期盼下,11月5日“2020 Ohayoo游戏开发者沙龙”将走进广州站。届时,Ohayoo商务经理金男佶、Ohayoo华南区发行负责人马森、Ohayoo海内市场与单干商务负责人王雨帆、 Ohayoo定制经理孙沁思等嘉宾将独特缺席流动,为广州游戏开发者带来单干模式干货分享,以及“春风打算”平台搀扶政策解读,助力开发者发力休闲游戏赛道。 (请增加微信:ohayoogames2,备注“沙龙”进入报名群,也可在文末扫码报名广州站沙龙) 轻量团队如何抓住泛娱乐时代的休闲游戏红利?在以后泛娱乐文化昌盛的背景下,碎片化用户行为凸显,休闲游戏市场沉闷用户激增,轻量化休闲游戏正值红利期。 统计显示,往年第一季度,休闲游戏沉闷用户量涨幅超过了300%,月沉闷用户数量冲破4个亿,这样的用户基数给予了休闲游戏市场更多可能,也给了休闲游戏研发上更好的机会。尤其是Ohayoo发行的数款游戏流水过亿之后,更是让泛滥迫切获得成就的游戏开发者看到了这一行业时机。 广州作为华南游戏行业重镇,汇集了大量不同体量的游戏研发团队,其中以体量小且研发架构残缺的腰部、尾部研发团队居多,这些团队与休闲游戏轻量化、低成本、高流水的劣势十分符合。此次广州站沙龙,Ohayoo将通过分享游戏开发干货和平台服务政策,进而帮忙开发者升高对资金投入、人力老本、创意稀缺等一系列危险的顾虑,帮忙开发者更好的把握行业风口。 一站式服务 助力开发者发力休闲游戏为了帮忙广州地区开发者做好游戏,Ohayoo商务经理金男佶将在现场解说Ohayoo以代理单干、定制单干为主的多种单干模式;线上线下联合提供多个开发者交换服务渠道;以热门素材、平台IP、吸量测试辅助开发者立项的服务模式。Ohayoo将为开发者提供一站式服务,在游戏研发的各个环节进行业余的领导。 麻利开发 小团队的高效掘金模式 以后很多开发者的痛点在于产品的成功率,Ohayoo华南区发行负责人马森将在广州站分享“麻利开发”单干研发模式,帮忙开发者降本提效,晋升游戏研发成功率。对轻量化团队而言,能够通过大量的投入,最大效率的实现每个环节的研发。 这一模式整个单干流程仅须要3到6个月,后期吸量测试仅需一个30秒的录屏,次留版本筹备2-3天内容就能够测试。Ohayoo会以吸量水平、在线时长、留存等数值作为测试量化指标,给出调优倡议,帮忙研发团队更新内容、迭代游戏版本。开发者抉择这种模式能够实现变现率80%以上,防止研发失败危险的同时,也能疾速实现资金回笼。 定制单干 全方位游戏研发辅助Ohayoo定制经理孙沁思将带来定制单干模式分享。以毁灭病毒为例,Ohayoo以泛娱乐平台热门元素为根底,帮忙创意稀缺的团队把控产品方向赢在立项,实现游戏内容创作迭代,实现长线经营,广告变现。同时,流动现场嘉宾还将分享Ohayoo定制模式下的业余策动对接服务及资金搀扶、分成政策,为参会成员进行更加粗疏的解说。 游戏出海 泛娱乐时代海内掘金Ohayoo海内市场与单干商务负责人王雨帆将引领开发者海内掘金。从去年7月海内发行的产品曾经取得了靠近一亿的下载,很多国内失去验证的外围玩法,在海内也播种了很多用户的青眼。 为了更好满足广州站不同类型开发者的出海需要,Ohayoo还将提供寰球代理和定制模式两种出海搀扶政策,更有多重福利重磅加码,流动现场将由嘉宾为大家带来更加具体的解释,助力开发者腾龙出海。 广州站限定福利 限时凋谢无门槛吸量视频打算此次沙龙流动还将提供广州限定福利,开启限时凋谢无门槛吸量视频打算。在11月5日14点-11月8日0点时段内注册Ohayoo.cn并提交吸量视频的前10名广州当地游戏开发者,能够取得限时凋谢无门槛吸量视频测试计划资格。吸量测试完结后,Ohayoo将会提供吸量测试报告以及专属经营团队的产品反馈倡议。 “2020 Ohayoo游戏开发者沙龙”广州站将于11月5日正式开启,期待您的光临!赶快扫描二维码报名吧!

October 30, 2020 · 1 min · jiezi

关于游戏开发:用-Shader-写个完美的波浪

前言皮皮最近接到了一个小需要: ????美术小姐姐:皮皮皮皮,你能不能做奶茶?????我:??? ????美术小姐姐:就是那种,奶茶的轮廓加上动静水波纹~ ????我:吓死我还认为让我做喝的奶茶... ????美术小姐姐:炒鸡多图片都须要这种成果,用动画的话工作量太大了! ????我:波浪成果是吧,小意思,一个月的奶茶就够了,或者扫码提需要~ ????美术小姐姐:皮????????????? ????我:卒~ 俗话说:遇事不决,量子力学写虽得儿。 依据我多年喝奶茶的教训,像这种成果用 Shader 做就再简略不过了,最终的成果如下: 趁此机会,本篇文章就来与小伙伴们分享动静波浪 Shader 的原理和制作思路吧。 要留神的是,这是一篇偏入门的文章,写得会绝对比拟具体,尽量让不懂 Shader 的小白也能够看懂,这也是我写文章的一贯格调。 好了,话不多说,进入正题~ 注释????整体思路看到波浪的体现特点我第一工夫想到的就是正弦曲线(或者说是正弦波,又让我想起了示波器)。????正弦曲线(Sinusoid)正弦曲线是三角函数中的一种正弦(Sine)比例的曲线。正弦曲线体现为一条波浪线,形态犹如海上完满的波浪。 规范的正弦函数公式为: y = sin(x) 正弦函数属于周期函数,其值域为 [-1, 1]。 如下图就是一个纯正规范的正弦曲线: 而个别咱们罕用的正弦曲线公式为: y = A · sin(x ± ) + k 这条公式比规范公式多了几个常数,含意如下: A:振幅(Amplitude),曲线最高点与最低点的差值,体现为曲线的整体高度:角速度(Angular Velocity),管制曲线的周期,体现为曲线的严密水平:初相(Initial Phase),即当 x = 0 时的相位,体现为曲线在坐标系上的程度地位k:偏距(Offset),体现为曲线在坐标系上的垂直地位相位(Phase):上方公式中的 x± 局部称为相位,相位产生在周期性的静止之中,最间接的了解就是角度。☕稍加考虑有了公式之后,咱们能够尝试调整其中的常数来扭转函数曲线的状态。 在查看下方的示例时,请尝试将曲线状态的变动与图中右上角公式的变动关联起来。扭转曲线的高度咱们能够调整常数 A(振幅)来扭转曲线的值域(值域为 [-A, A]): 扭转曲线的周期咱们能够调整常数 (角速度)来扭转曲线的周期: 扭转曲线的程度地位咱们能够调整常数 (初相)来扭转曲线的程度地位: 多说一句其实对于“曲线的程度地位”这个形容是不太精确的,因为初相实际上扭转的是当 x = 0 时的相位,也就间接影响函数曲线在 x = 0 处的地位。 ...

September 9, 2020 · 2 min · jiezi

四叉树与碰撞检测-Cocos-Creator

四叉树与引擎内置碰撞检测的结合运用。效果预览绿色为参加检测的对象(当前四叉树节点),红色为碰撞对象。 如何使用引入脚本 QuadtreeCollision.ts , 新建一个 QuadtreeCollision ,并初始化为世界坐标系下的对齐轴向的包围盒(AABB)。 // 这边是挂载在canvas下的脚本,用canvas的rect初始化创建。this._quadCollision = new QuadtreeCollision(this.node.getBoundingBoxToWorld())传入待检测的碰撞数组 cc.Collider[] 和测试对象的 cc.Collider。 返回准备测试的 cc.Collider[] 和发生碰撞的 cc.Collider[]。 // check(colliders: cc.Collider[], testCollider: cc.Collider)const { retrieve, contacts } = this._quadCollision.check(this._all_collider, this.collider_role);// retrieve 准备测试的对象(预览图中的绿色) cc.Collider[]// contacts 碰撞对象(预览图中的红色) cc.Collider[]实现原理四叉树是什么? 白玉无冰是这样理解的,四叉树本身是树结构的一种,如果物体过多的话,先根据物体所处位置划分成四块,如果每个块的中的物体数量还是很多的话,继续划分成四块。如下图红线所示。 检测的时候,就是根据待测试对象的位置,去找属于哪个块,再把这个块中的物体告诉你。如下图中的绿色物体。 那么怎么实现四叉树呢?用好 github 就行了(误),搜了一下,找到一个库,直接拿来改改就行了。 https://github.com/timohausma... //export default class QuadtreeCollision {private _tree;constructor(rect: { x: number, y: number, width: number, height: number }) { this._tree = new Quadtree(rect);} ...

July 7, 2020 · 2 min · jiezi

Cocos谁学谁会制作会跑动的地板

版权申明:本文原创首发于以下网站,您可以自由转载,但必须加入完整的版权声明博客园:https://www.cnblogs.com/Mogoo... csdn博客:https://blog.csdn.net/nmjkl001/ 知乎:https://www.zhihu.com/people/... 简书:https://www.jianshu.com/u/954... segmentfault:https://segmentfault.com/u/mo...最后效果 源码分享以下步骤详细内容可能跟源码中有出入,一切以源码为准CocosCreator版本:2.1.2,务必使用大于此版本的引擎运行源码地址: https://github.com/MogooStudio/Runningfloor简单步骤1. 创建工程(略)2. 材质box创建材质box设置材质box的effect属性为builtin-unit(内置的无光照)勾选USE_DIFFUSE_TEXTURE(实用漫反射纹理),点击应用拖动texture纹理到diffuseTexture中 3. 预制件box创建3D节点Box,命名为box创建box.js脚本,脚本内容见源码拖动box.js脚本到预制件box下拖动材质box到预制件MeshRanderer组件下面的Materials中拖到prefab文件夹下生成预制件 4. 管理节点mgr创建空节点mgr,设置节点为3D节点 设置节点x左右为480,y坐标为300,z坐标为05. Canvas节点创建main.js脚本,脚本内容见源码拖动main.js脚本到Canvas节点下拖动mgr节点到main.js脚本组件相应中拖动box预制件到main.js脚本组件相应中6. 摄像机设置主摄像机的模式改为3D,z坐标设置为800去掉ortho勾选,设置fov为60我的联系方式:QQ:2161044579 邮箱:mogoostudio@outlook.com Github:https://github.com/MogooStudio

October 4, 2019 · 1 min · jiezi

为什么说SO加固无源码VMP是最佳的Android手游安全保护方案

本文作者为易盾实验室工程师。 随着移动互联网的高速发展,移动游戏市场也得到了快速发展,与之对应的移动游戏外挂和破解市场也是风生水起,外挂和破解的发展对游戏的玩家体验,以及厂商收益产生了极大的消极影响。为维护游戏运营安全,保障玩家公平的游戏环境,对游戏的保护必不可少。 移动游戏最重要的是部分是资源和逻辑,而游戏引擎则是处理资源和逻辑的关键所在。恶意玩家可以通过游戏引擎获取解密后的游戏脚本或游戏资源,然后修改脚本或资源到达破解的目的;也能通过修改引擎的逻辑达到破解的目的;还可以通过引擎插入自己的脚本或资源实现外挂功能。 因此游戏引擎的保护是迫切的,在Android 游戏中游戏引擎是SO文件,如何保护SO文件成了游戏需要面临的问题。游戏,再怎么考虑安全,也必须要考虑到游戏体验,顺畅的游戏体验对玩家至关重要,一切安全解决方案必须在不影响游戏性能和玩家体验的基础上进行。 目前SO文件保护方案大概可以分为有源保护和无源保护,有源保护分为自解密、混淆、源码VMP等,无源保护分为加壳、VMP保护。 有源保护中的自解密保护的原理是:先加密需要加密的函数或者段,然后再加载SO文件,解密先前加密的函数和段。由于运行后需要解密相关的逻辑,因此破解者只需要在SO文件运行后,DUMP内存,即可获取解密后的逻辑,破解门槛低,因此自解密的保护方式存在安全强度低、维护成本高的缺点。 市面上常用SO源码保护是基于LLVM的混淆,通过指令替换、控制流扁平化和虚假控制流等角度去混淆源码。如下源码为测试源码,试试一个简单的校验函数,测试程序是ARMV7A架构下的编译。 下面是混淆前的控制流程图展示: 对上面的源码进行一些混淆,在增加了虚假控制流、指令替换和控制流平坦化的处理后,控制流的复杂度增加。如下图所示,增加了控制流程图复杂度,加大了逆向分析的难度。基于LLVM的源码混淆比较灵活,可以根据不同的安全需求配置不同的安全策略,混淆程度越高,则性能影响越大,文件膨胀越多。在对游戏影响很小的前提下,混淆能做的比较有限,导致安全强度不够,混淆存在安全强度和性能不可兼得的问题,不好找到平衡点。 由于源码混淆的方案在安全强度方面不够,因而出现源码VMP的解决方案。 相对基于LLVM的混淆,VMP安全强度更高,并且对SO文件的体积影响也较小,加固后的SO主要分为虚拟数据VMData和解释器handler,如下图所示为例子的VMData数据。 解释器handler的控制流 采用VMP保护对原函数执行的性能有比较大的影响,对所有方法VMP是无法满足游戏方对性能的要求。VMP的在不了解VMData和handler的对应关系的情况下,安全强度非常高,若相关的对应关系被破解者掌握,则也可以被还原,不过handler的复杂性一般比较高,并且对应关系可以做到随机处理,因此安全强度是完全满足游戏方的要求。 上面说的基于源码的保护都存在一个相同的问题是接入成本高,需要处理源码就需要有本地工具,特别有些游戏引擎非开源,那基于源码的保护则无法接入。 无源码保护的加壳,市面上对应的加壳的方式有很多,安全强度差异也较大,不过核心是自定义linker。在壳SO文件被执行后需要先解密、还原被保护的SO文件,然后使用自定义linker加载被保护的SO,最后将执行权还给被保护的SO。加固的静态保护强度很高,原SO的蛛丝马迹完全抹去,但是动态执行后会还原部分内容,开发者也可以配合反调试、反Dump等技术使用,弥补SO加固在内存安全强度上的弱点。虽然加固存在着比较明显的弱点,然而加固也存在极大的优势,加固是对游戏性能影响最小,在游戏运行中不会增加任何开支,并且接入成本低,不需要有任何接入的成本。 无源码VMP与基于源码的VMP原理上是相通的,加固处理后最关键的部分依然是虚拟数据VMData和指令解释执行器handler。VMP处理时需要将原指令处理成VMData虚拟数据,并且插入解释器handler,如下图所示为无源VMP的handler。 VMP处理的安全强度高,逆向分析成本高,当然同样存在性能的问题。 根据上面对目前SO文件保护方案的说明,可以发现SO加壳是性能影响最小,VMP是安全强度最高,无源码方案是接入成本最低的方案。采用SO加固+无源码VMP结合的方式即可满足游戏对性能影响最小化的需求,最大程度的减少安全措施对游戏性能的影响,同时满足对游戏引擎的保护需求,在游戏引擎关键地方采用VMP防止破解者逆向分析,保障了游戏的安全。 点击免费体验网易易盾手游智能反外挂服务。

September 19, 2019 · 1 min · jiezi

额外加分制作你的第一个游戏一基础篇

额外加分:制作你的第一个游戏(一)基础篇额外加分 是关于游戏设计的教学影片系列。这个系列在探讨电子游戏与游戏研究的议题,特别关于游戏开发,解决“视游戏为艺术”的合理性,并提出对游戏文化有深度的重要议题。PS:本文是对该视频的一个概括总结,作为自己的一个学习记录。原视频可以在 YouTube 订阅 Extra Credits 的频道。 制作你的第一款游戏:基础-如何开始你的游戏开发有很多人在某个时刻雄心勃勃的决定要开始做游戏。他们找到了一个游戏引擎,开始潜心钻研。然后再游戏做出来之前就早早放弃了。这是一件十分可惜的事情,这简直就是徒劳无功。这篇文章希望能帮到你们避免这种情况。 1. 控制你的游戏规模将你的第一款游戏作为练习而不是拘泥于细节做出所谓的”杰作“。有许多人,拿起一款游戏引擎就想做出像 “战神” 、“最终幻想” 这样的 3A 大作。显然是不可能,这种 3A 级大作背后的团队往往超过40人,并且花上好几年的时间。即使你非常厉害并且毕生投入到游戏开发中去,你也不可能做出一款像 “战神” 、“最终幻想” 这样的 3A 大作,特别是在处女作的情况下。你甚至无法达到 “马里奥兄弟” 的水准,你也许能完成 “马里奥兄弟” 一关的量,并且你已经很棒了。 在你的第一款游戏中,你应该做出一个可玩的东西,即使十分的粗糙。将你的第一款游戏作为练习而不是杰作。如果一开始你就面对一个巨大的工程,你将无从下手,并且你会深陷在没有明显反馈的细节之中。你可能会在原地踏步,可能碰上了超出你能力范围的障碍,你只能不足所措的挣扎。 相信我,简单就好。如果你的第一款游戏是一个简单粗糙的平台跳跃类游戏,并且花费了你三周的时间。应该为你自己感到自豪,因为你做了,并且把它完成了,你做出了一款游戏!这已经是很多人无法做到的了。把你的游戏介绍给你的朋友,别担心他们会吐槽你的游戏。你知道你为了做这个游戏付出了多少,更重要的是你知道你下次会做得更好更快,很快你就会做出让那些玩家争先试玩的游戏。 2. 不要抱着某个明确的想法去做第一款游戏从小事开始,专注于基本的游戏玩法,选择一个你能完成的项目。了解自己会什么,基于这些去设计。不要把自己局限在某个想法中,而日复一日的纠结于它。去看几个教程,然后开始确定你能实现的。任何一款主流的游戏引擎都有大量的人去做教程,你只要去找、去看、去学。遇到困难或找不到问题的答案,就去提问,会有很热心的人帮助你。很多人担心自己的编程能力,只要你的设计合理,你会发现问题是如此的简单。总而言之,确保你的游戏小而简单。 3. 量力而行了解你的局限,就是了解你的资源如果你是一个没写过一行代码的艺术大师,那你就将你游戏的重心放在艺术表现上,同时给自己一些编程的压力来促使自己学习。 你对绘画、建模一窍不通?没有关系,有很多游戏以极简风格来问世的。 如果真的有什么你觉得不可或缺的,那就去素材商店看看,哪里有许多素材。 相信许多人都有全日制的工作或课程或其他琐事,使你的游戏搁置几天甚至几周的时间。这是一件非常折磨的事情。我可以说所有事情都是折磨的,如果你坚持住了,或许有一天你会有选择能以游戏制作”代替“其他琐事。 制作你的第一款游戏可能很难。记住你的目标是创造一款游戏,任何游戏。从小事开始,专注于基本的游戏玩法,选择一个你能完成的项目。这样,你就可以完成一款可玩的游戏,而不是像许多第一次做游戏的人那样纠结于细节。结束 4. 关注我的微信公众号,查看更多文章,第一时间收到我的文章。

September 8, 2019 · 1 min · jiezi

游戏行业买量卖量指南

破局广告主买量、助力开发者提收——6月26日,在优量沙龙深圳专场上,众多游戏行业从业者受邀与腾讯优量汇、优量广告共同针对游戏行业广告投放与流量变现的现状进行交流探讨。 用户碎片化时间的增多,为游戏行业带来了又一阵热潮。腾讯广告-联盟广告部总经理、信息流与QQ广告部总经理黄磊在开场时表示:“游戏市场规模持续增长,广告投放与流量变现的发展空间在进一步扩大。作为中国乃至全球体量最大的游戏公司,腾讯在这个领域有着天然的优势,依托这一优势和技术能力的腾讯优量汇、优量广告,希望通过此次沙龙为大家带来专业、硬核的分享,并与各位行业同仁进行更深入的探讨。” 图片描述买量优势显著 优量广告渗透率极高对于游戏行业广告主而言,优量广告具有流量充沛、覆盖广、成本低的特点。在开屏图文广告和视频类广告两个规格上,优量广告具有非常突出的竞争力。 “新纳入优量版图的‘快手流量’优势不可小觑,”腾讯广告高级运营经理薛竹表示,“所拥有的数十亿的流量具有游戏属性强、付费能力强、城市覆盖广泛的特点,其中50%的流量都带有游戏标签。结合腾讯广告的特点,对游戏产品极为利好。” 据数据统计,越来越多的广告主在优量广告发力,部分广告主超过50%的预算都投放在这里。买量市场竞争越发激烈,优量广告更推出流量筛选工具帮助广告主精准触达,通过科学的投放决策以低成本收获高转化。针对游戏全生命周期,优量广告提出了三步投放方法论: 变现链路追踪 助力流量收益提升数据翔实的游戏行业变现图谱,令流量主们对行业变现特点、用户属性及广告主的行业构成有了较为清晰的理解。针对开屏广告、原生广告、插屏广告、横幅广告及激励视频几大广告场景,优量汇逐一给出了优化建议,并指出影响评估变现情况指标ARPU的四大因素: 用户量 - 游戏本身的用户量级 变现利用率 - 游戏用户能触发广告的比例 人均曝光次数 - 单用户观看广告的数量 每次曝光收入 - 主要受广告eCPM影响 图片描述 “变现链路追踪以及用户分层非常重要。”腾讯优量汇高级商务经理唐倩这样强调,并通过下图为流量主进行了链路上各关键节点的详细解读,建议流量主根据具体的用户分层情况,通过按UV、刷次或在不同平台用户之间切换的方式来调整变现策略。 针对备受流量主关注的“出海”需求,优量汇提供了完整的新模式探索——腾讯数字媒体资源管理平台TSSP。该平台可以通过最大化收益、最小化成本、最高效率,实现从用户增长到变现的完整闭环,为流量主带来包括供应侧管理、业务管理、收益管理、广告投放服务四个维度的服务。 避免踩坑 优量汇助力买量卖量双赢“在投放过程中,任何一个环节出问题都会造成买量达不到目标。”腾讯优量汇高级运营经理徐婧这样开场,“广告的基础是算法,算法的核心是数据。” 图片描述 对于广告主而言,优量汇总结了五大投放过程中容易出现的误区,呼吁广告主扎实数据内功,正确回传数据以获得更为精准的投放分析,结合归因、避免“踩坑”,打败对手登顶投放高峰。 图片描述优量汇总结广告主投放过程中的五大误区对于流量主,徐婧强调要重视“看数”,并通过发现异常、对比差距、清理广告位来让数据更真实。谈及广告策略的运营优化之道,除了A/B test,她还给出了如下建议: 针对场景进行激励点的设计,注意数值体系自洽,激励视频与插屏视频动态结合针对用户要了解用户为何而来以及用户分层策略针对频次要明确其与收益和吸量的关系,并找到最佳平衡点全球游戏营收上涨 持审慎乐观态度作为第三方大数据公司,TalkingData关注移动广告的归因数据监测。“移动应用与产业和生活高度融合,总体呈现发展态势。”TalkingData华南开发者业务总监史晓晓评价道,“渗透率最高的是衣食住行,其次就是手机游戏。中国移动网民数量已达8.29亿,手机游戏用户大约达6亿之多。” 据TalkingData数据显示,国际市场游戏行业营收仍有上涨,国内市场仍在一、二线城市以外区域下沉,与移动互联网下沉趋势保持一致。此外,史晓晓还为“热血汉子”与“游戏佳人”两个典型游戏玩家人群进行了多维画像分析,并解读了各类型游戏健康度曲线排名。 从行业动态、买量策略到变现优化的十八般武艺,腾讯优量汇为广大从业者带来了全面丰富的方法论。敬请关注优量汇,获取专业、成熟、精准的策略建议和实战指导。

July 1, 2019 · 1 min · jiezi

搭建我的世界游戏服务器-让游戏更high

搭建我的世界游戏服务器 让游戏更high当“吃鸡”成为年轻人社交的主题词,“荣耀”成为学生的日常语,我们可以看到,网游影响并改变着我们的娱乐和社交方式。你知道为何现在游戏体验在日益提升吗?你想提高自己的游戏部署能力吗?华为云微认证《搭建我的世界游戏服务器》将解答你的疑问。游戏上云成为趋势在游戏风行的时代,高并发、高性能、安全风险高和精准定位难等成为游戏行业所面临的一系列挑战,不过这些在云上都可以找到完善的解决方案。在Cloud 2.0时代,游戏与云结合已成为一种趋势。游戏对云计算的要求是:稳、安、快、新。为满足游戏行业客户的开发需求,华为开放30年的研发实践经验,正式发布华为云游戏解决方案。华为云游戏解决方案发挥华为云软硬件协同的优势,帮助游戏行业开发敏捷、高效、协同的游戏,构筑端到端企业级防护能力、全场景护航游戏安全。一个游戏的好坏,除了游戏本身更应该注重硬件的要求,游戏服务器显得尤为重要,可以为用户提供良好的用户体验。揭秘游戏背后的服务器游戏服务器,简单来说就是指游戏发行商上线游戏时所使用的服务器。游戏服务器一般负责处理玩家与玩家之间或玩家与游戏世界间的交互信息,同时维护整个游戏的逻辑。游戏客户端是指与游戏服务器相对应,为客户提供本地服务的程序,一般安装在普通的用户电脑上,需要与游戏伺服端互相配合运行,展示华丽的画面。游戏服务器不可能呈现华丽的画面,但因其发挥大脑作用,所以在制作服务器时不可以发生一丝误差,以减少‘死机’或‘卡壳’的概率。游戏服务器的原理是Client主动给Server发送数据,Server也可能主动往Client发送数据,每次发送的数据比较少,但是频率比较高,和常见的Request-Response模式不同,因此它比较突出的一点是客户端和服务器端要进行较长时间的连接,几乎是不间断的。 个华为云助力打造高品质游戏《三国志2017》于2017年8月底正式上线;华为云游戏解决方案保障《三国志2017》顺利开服,保证了玩家的游戏体验,玩家数量稳定上升。2017年,华为云助力三国志2017首月流水突破1个亿。为何能有这么好的效果?首先:华为云开服速度快,网络稳定,保证了玩家的体验,满足业务激增的需求;其次,华为精准运营,给三国志2017带来了大量的有效流量,促进其业务迅速增长。第三:华为云组织起有效的防护恶意攻击。看了这个案例,是否对华为云有了更多的信心?想获得更高的游戏体验吗?华为云微认证《搭建我的世界游戏服务器》面向游戏行业相关人员,对云计算感兴趣的社会大众和高校师生,通过游戏行业解决方案的解析完成我的世界云端部署实践,助力你掌握游戏云端部署解决方案及其优势,通过实践提升游戏部署能力。点击现在开始:https://edu.huaweicloud.com/c...学习《搭建我的世界游戏服务器》云微认证吧,你将获得意想不到的游戏体验! 【互动活动】1、 关于华为云微认证的任何问题,均可在下方评论区留言。2、 精选留言将获得1个华为云微认证免费体验机会,可用于任何一门华为云微认证的学习和考试(本次赠送不包含实验代金券)。3、 华为云微认证将总共送出10个免费机会,奖项公布时间:6月10日。

June 21, 2019 · 1 min · jiezi

用Swoole来写个联机对战游戏呀八创建游戏房间

联机逻辑开发进度:■■■■■■■□□□□□ 本章结束开发进度:■■■■■■■■■□□□ 上一章的答案:Logic类: <?php...class Logic{ public function matchPlayer($playerId) { ... //发起一个Task尝试匹配 DataCenter::$server->task(['code' => TaskManager::TASK_CODE_FIND_PLAYER]); }}Server类: <?php...class Server{ ... public function onTask($server, $taskId, $srcWorkerId, $data) { DataCenter::log("onTask", $data); $result = []; switch ($data['code']) { case TaskManager::TASK_CODE_FIND_PLAYER: $ret = TaskManager::findPlayer(); if (!empty($ret)) { $result['data'] = $ret; } break; } if (!empty($result)) { $result['code'] = $data['code']; return $result; } } ...}...童鞋们的作业完成情况如何呢? 我们来再次梳理一下目前的匹配功能进度: 前端连接时发送player_id服务端连接时保存玩家信息前端发送code为600的指令服务端将player_id放入匹配队列服务端发起一个task进行玩家匹配,当寻找到两个玩家时返回两个player_id到worker进程那下一步就很明显了,就是创建游戏房间。 创建房间分析在Server类的onFinish()方法中,根据传入的code,执行Logic的createRoom()方法。Server类: <?php...class Server{ ... public function onFinish($server, $taskId, $data) { DataCenter::log("onFinish", $data); switch ($data['code']) { case TaskManager::TASK_CODE_FIND_PLAYER: $this->logic->createRoom($data['data']['red_player'], $data['data']['blue_player']); break; } }}...显然,下一步就是完成这个createRoom()方法匹配机制就大功告成了。但是真的这么简单吗?下面我们要思考一件事情。 ...

May 12, 2019 · 2 min · jiezi

一步步教你用-WebVR-实现虚拟现实游戏

翻译:疯狂的技术宅https://www.smashingmagazine.... 本文首发微信公众号:前端先锋欢迎关注,每天都给你推送新鲜的前端技术文章 在本教程中,我们将创建三维对象并为它们添加简单的交互。此外,你还可以学到如何在客户端和服务器之间建立简单的消息传递系统。 虚拟现实(VR)是一种依赖计算机生成环境的体验,其应用范围广泛:美国利用虚拟现实进行冬季奥运会的运动训练;外科医生正在试验用虚拟进行医学培训;把虚拟现实用于游戏是最常见的一种应用。 我们将把目光放在最后一类程序上,并将专注于点击式冒险游戏。这是一种休闲类游戏,游戏的目标是通过选择场景中的三维对象来完成拼图。在本教程中,我们将在虚拟现实中构建一个简单的版本。这是一篇关于三维编程的介绍,是在 Web 上部署虚拟现实模型的独立入门指南。你将使用 webVR 进行构建,这个框架具有双重优势 —— 用户可以在VR中玩游戏,而没有VR眼镜的用户也可以在手机或桌面上玩。 在本教程的后半部分中,你将为桌面构建一个“镜像”。这意味着在移动设备上进行的所有移动都将会在桌面预览中进行镜像。这样你可以看到玩家所看到的内容,允许你提供指导、记录游戏,或只是让客人娱乐。 前提条件在开始之前你需要准备以下内容。对于本教程的后半部分,你将需要一台Mac OSX。虽然代码可以应用于任何平台,但下面依赖项的安装说明适用于Mac。 互联网接入,特别是glitch.com;VR 眼镜(可选,推荐)。我用的是Google Cardboard,每个售价15美元。步骤1:设置虚拟现实(VR)模型在此步骤中,我们将设置一个包含单个静态 HTML 页面的网站。这样可以允许你从桌面进行编码并自动部署到Web上,然后可以将部署的网站加载到手机上并放入VR眼镜内。或者部署的网站可以由独立的 VR 眼镜加载。首先打开https://glitch.com/。然后 单击右上角的 “New Project” 。单击下拉列表中的“hello-express”。 接下来,单击左侧边栏中的 views/index.html。我们将此称为你的“编辑器”。 要预览网页,请单击左上角的“Preview”。我们将此作为你的预览。请注意,编辑器中的任何更改都将会自动反映在预览中,除非出现错误或不受支持的浏览器。 返回编辑器,将当前HTML替换为下面 VR 模型的代码框架。 <!DOCTYPE html><html> <head> <script src="https://aframe.io/releases/0.7.0/aframe.min.js"></script> </head> <body> <a-scene> <!-- blue sky --> <a-sky color="#a3d0ed"></a-sky> <!-- camera with wasd and panning controls --> <a-entity camera look-controls wasd-controls position="0 0.5 2" rotation="0 0 0"></a-entity> <!-- brown ground --> <a-box shadow id="ground" shadow="receive:true" color="#847452" width="10" height="0.1" depth="10"></a-box> <!-- start code here --> <!-- end code here --> </a-scene> </body></html>之后可以看到以下内容: ...

May 10, 2019 · 5 min · jiezi

用Swoole来写个联机对战游戏呀七异步匹配玩家

联机逻辑开发进度:■■■■■□□□□□□□ 本章结束开发进度:■■■■■■■□□□□□ 上一章的答案:DataCenter类: <?php...class DataCenter{ const PREFIX_KEY = "game"; ... public static function getPlayerWaitListLen() { $key = self::PREFIX_KEY . ":player_wait_list"; return self::redis()->lLen($key); } public static function pushPlayerToWaitList($playerId) { $key = self::PREFIX_KEY . ":player_wait_list"; self::redis()->lPush($key, $playerId); } public static function popPlayerFromWaitList() { $key = self::PREFIX_KEY . ":player_wait_list"; return self::redis()->rPop($key); } public static function getPlayerFd($playerId) { $key = self::PREFIX_KEY . ":player_fd:" . $playerId; return self::redis()->get($key); } public static function setPlayerFd($playerId, $playerFd) { $key = self::PREFIX_KEY . ":player_fd:" . $playerId; self::redis()->set($key, $playerFd); } public static function delPlayerFd($playerId) { $key = self::PREFIX_KEY . ":player_fd:" . $playerId; self::redis()->del($key); } public static function getPlayerId($playerFd) { $key = self::PREFIX_KEY . ":player_id:" . $playerFd; return self::redis()->get($key); } public static function setPlayerId($playerFd, $playerId) { $key = self::PREFIX_KEY . ":player_id:" . $playerFd; self::redis()->set($key, $playerId); } public static function delPlayerId($playerFd) { $key = self::PREFIX_KEY . ":player_id:" . $playerFd; self::redis()->del($key); } public static function setPlayerInfo($playerId, $playerFd) { self::setPlayerId($playerFd, $playerId); self::setPlayerFd($playerId, $playerFd); }}我们先来测试一下,前面所写的代码有没有问题,重新运行Server.php,并在浏览器打开游戏前端页面。 ...

May 9, 2019 · 2 min · jiezi

用Swoole来写个联机对战游戏呀六游戏匹配机制

联机逻辑开发进度:■■□□□□□□□□□□ 本章结束开发进度:■■■■■□□□□□□□ 上一章的答案:index.html: var app = new Vue({ el: '#app', data: { message: 'Hello Vue!', websock: null, }, created() { this.initWebSocket(); }, destroyed() { this.websock.close() //离开路由之后断开websocket连接 }, methods: { initWebSocket() { //初始化websocket const wsuri = "ws://192.168.3.41:8811"; this.websock = new WebSocket(wsuri); this.websock.onmessage = this.websocketonmessage; this.websock.onopen = this.websocketonopen; this.websock.onerror = this.websocketonerror; this.websock.onclose = this.websocketclose; }, websocketonopen() { //连接建立之后执行send方法发送数据 let actions = {"test": "12345"}; this.websocketsend(actions); }, websocketonerror() {//连接建立失败重连 this.initWebSocket(); }, websocketonmessage(e) { //数据接收 let message = JSON.parse(e.data); }, websocketsend(Data) {//数据发送 this.websock.send(JSON.stringify(Data)); }, websocketclose(e) { //关闭 console.log('断开连接', e); }, }})记得将192.168.3.41改为你的IP地址哦。Server类: ...

May 7, 2019 · 2 min · jiezi

用Swoole来写个联机对战游戏呀五联机初始化

联机逻辑开发进度:□□□□□□□□□□□□ 本章结束开发进度:■■□□□□□□□□□□ Swoole开发环境教程使用Swoole 4.3.0版本开发,但并没有使用协程等功能,只是使用了WebSocket Server,理论上安装旧版也是没问题的。环境需要大家自行安装,这个也是学习的一个过程。 以下是一些有可能有帮助的资料: CentOS中一键安装PHP开发环境:https://lnmp.org/install.htmlSwoole安装教程:https://wiki.swoole.com/wiki/...Redis安装教程:https://redis.io/downloadphp-redis扩展包:http://pecl.php.net/package/r...童鞋们也可以像我一样在Windows使用PHPStorm进行开发,再通过一些方法如共享文件夹、WinSCP等工具将项目在CentOS中运行起来。 安装swoole-ide-helper扩展使用PHPStorm来开发Swoole项目的童鞋,如果不想面向运气编程的话,最好安装一个swoole-ide-Helper扩展来协作开发。 在项目根目录运行以下命令: composer require --dev "eaglewu/swoole-ide-helper:dev-master"安装完毕我们就可以愉快地编写Swoole代码了。 服务端基本架构赵童鞋设想的基本架构需要三个层,他们分别是: 网络层:管理Swoole WebSocket对象,主要负责接收前端消息,传递到逻辑层进行处理。逻辑层:接收网络层传递的消息,主要负责游戏房间创建、玩家移动、结束检测等游戏逻辑。数据层:用于管理玩家ID、房间ID、匹配队列等数据。管理这三个层分别需要三个类:Server、Logic、DataCenter。 其中最重要的就是Server类,它的作用就是作为服务端和客户端的消息交换中心,我们先来写一个初始化的Server类,在项目app目录新建Server.php。 使用面向对象的方式实现一个WebSocket Server类。分别绑定start、workerStart、open、message、close回调方法在类中引入composer自动加载机制。为WebSocket对象设置4个worker进程。Swoole Websocket:https://wiki.swoole.com/wiki/...Server类: <?phprequire_once __DIR__ . '/../vendor/autoload.php';class Server{ const HOST = '0.0.0.0'; const PORT = 8811; const CONFIG = [ 'worker_num' => 4, ]; private $ws; public function __construct() { $this->ws = new \Swoole\WebSocket\Server(self::HOST, self::PORT); $this->ws->set(self::CONFIG); $this->ws->on('start', [$this, 'onStart']); $this->ws->on('workerStart', [$this, 'onWorkerStart']); $this->ws->on('open', [$this, 'onOpen']); $this->ws->on('message', [$this, 'onMessage']); $this->ws->on('close', [$this, 'onClose']); $this->ws->start(); } public function onStart($server) { swoole_set_process_name('hide-and-seek'); echo sprintf("master start (listening on %s:%d)\n", self::HOST, self::PORT); } public function onWorkerStart($server, $workerId) { echo "server: onWorkStart,worker_id:{$server->worker_id}\n"; } public function onOpen($server, $request) { } public function onClose($server, $fd) { } public function onMessage($server, $request) { }}new Server();我们来运行一下Server.php文件,顺便检验一下Swoole扩展是否运行正常,在项目app目录下,运行php Server。 ...

May 7, 2019 · 2 min · jiezi

用Swoole来写个联机对战游戏呀四游戏结束判断

游戏逻辑开发进度:■■■■■■■■□□□□ 本章结束开发进度:■■■■■■■■■■■■ 上一章的答案:在我们的$mapData数组中,0就是墙,1就是路,canMoveToDirection()方法主要就是获取方向,计算得出目标坐标,检测一下目标坐标能不能走,所以当数组中是0的时候就返回false,否则返回true。 Game类: private function canMoveToDirection($player, $direction){ $x = $player->getX(); $y = $player->getY(); $moveCoor = $this->getMoveCoor($x, $y, $direction); $mapData = $this->gameMap->getMapData(); if (!$mapData[$moveCoor[0]][$moveCoor[1]]) { return false; } return true;}private function getMoveCoor($x, $y, $direction){ switch ($direction) { case Player::UP: return [--$x, $y]; case Player::DOWN: return [++$x, $y]; case Player::LEFT: return [$x, --$y]; case Player::RIGHT: return [$x, ++$y]; } return [$x, $y];}增加canMoveToDirection()方法后再次运行test.php文件输出地图数据: 墙,墙,墙,墙,墙,墙,墙,墙,墙,墙,墙,墙,墙, 墙,墙, 墙, 墙,墙,墙,墙,墙,墙, 墙, 墙, 墙,墙,墙,追, 墙, 墙,墙, 墙,墙,墙,墙,墙, 墙, 躲,墙,墙, 墙,墙, 墙, 墙,墙, 墙, 墙, 墙,墙,墙, 墙,墙, 墙, 墙, 墙,墙, 墙,墙,墙,墙,墙,墙,墙,墙,墙,墙,墙,墙,墙,可以看到,即使经过了三次的up操作,追捕者都没有再跑到墙上面去。 ...

May 5, 2019 · 2 min · jiezi

用Swoole来写个联机对战游戏呀三完善游戏功能

游戏逻辑开发进度:■■■■□□□□□□□□ 本章结束开发进度:■■■■■■■■□□□□ 上一章的答案createPlayer方法其实就是创建一个Player对象,然后指定坐标,放入$players数组中,但是怎么区分追捕者和躲藏者呢?我们可以用最简单粗暴的方法,先来后到。 Game类: public function createPlayer($playerId, $x, $y){ $player = new Player($playerId, $x, $y); if (!empty($this->players)) { $player->setType(Player::PLAYER_TYPE_HIDE); } $this->players[$playerId] = $player;}第一个添加的将会使用Player类默认的追捕者,第二个添加的将$player对象设置为躲藏者。 playerMove()方法也很简单,通过传入的$direction变量,增减对应$player的x或y坐标,应该直接调用$player的移动方法,所以需要新增两部分代码: Game类: public function playerMove($playerId, $direction){ $this->players[$playerId]->{$direction}();}Player类: public function up(){ $this->x--;}public function down(){ $this->x++;}public function left(){ $this->y--;}public function right(){ $this->y++;}尝试打印地图目前我们三个实体类的基础游戏逻辑就写得差不多了,但是我们的游戏到现在都还没运行过,我们需要一个能直观看到地图、玩家的画面。 请童鞋们自己尝试在Game类中新增printGameMap()方法,打印游戏地图。 在Game类中有一个变量$gameMap就是我们的游戏地图对象。Map类中也有了getMapData()方法能够获取地图数组数据,Game类: public function printGameMap(){ $mapData = $this->gameMap->getMapData(); foreach ($mapData as $line) { foreach ($line as $value) { if (empty($value)) { echo "墙,"; } else { echo " "; } } echo PHP_EOL; }}打印地图的代码很简单,就是遍历我们的地图数据,当数组里的元素值为0的时候就是墙,否则就是路,路就不用输出文字啦~ ...

May 4, 2019 · 2 min · jiezi

我很喜欢玩游戏那么我就适合做游戏程序员吗

作者:黄小斜 文章来源:微信公众号【程序员江湖】 游戏在今天的普及度已经不是端游时代可以比肩的了。如今人手一台手机、平板就可以吃鸡、打农药,不仅是男生,也有很多女生加入了游戏圈。相信现在在看文章的你也玩游戏,虽然爱玩的程度不同,但是至少都是感兴趣的,当然你也知道,手游行业利润高,游戏程序员自然也吃香,能一边赚钱一边玩游戏,岂不是人生一大幸事呢?其实当年我也是这么想的。 为成为游戏程序员而读研大学的时候学的专业和计算机不太沾边,对学的东西不太感兴趣,每天的生活就是上课开黑打游戏,在大学的男生宿舍里,这样的情况确实也比较普遍。恰逢做毕业设计的时候,在课题列表上看到了一个关于“unity3D游戏开发”的课题,我特别感兴趣,于是果断选择了它。当时的水平就是刚刚c语言入门,有多菜可想而知,于是跟着网上的视频撸了一个劣质的《炉石传说》出来,连一局游戏都打不完的那种。 但是从那时候开始,我就感觉游戏开发确实挺有趣的。这么多年来,国内的游戏大厂也只有腾讯网易两家,网易游戏的游戏研发招聘要求就是至少要985研究生,腾讯虽然没有指定学历要求,但是要求也绝对不低。 除了学历要求之外,最要命的就是技术要求了,精通C++、精通计算机图形学,最好有游戏引擎经验,对算法等计算机基础课程也要非常熟悉。 简直和我毫不沾边嘛,好吧,既然我一穷二白,想要翻身的话,不是一时半会能做得到的,就算我挤破头准备一年的校园招聘,可能也离这个要求还很远,于是干脆选择读研,三年后,准备好了再来,也许胜算就比较大了吧。 兴趣和职业,有时候要有所取舍刚开始读研的时候,我还一心想着做游戏开发,想着实在不行的话,靠着之前的那些基础,做做Android或者Java也可以吧,于是我的简历上有着各个方向的经验,项目经验既有游戏开发、Android开发,也有Java Web的项目。现在想想是非常可笑的,因为我每个方向都不精,经验也都很水,求职意向不明确,这样的简历在大公司的面试官看来简直就是笑话。 那时候我还不明白这个道理,只希望自己的求职方向大而全,能够多覆盖几个岗位,每个岗位都投一次简历,广撒网多捞鱼,殊不知投简历最忌讳的就是这个事情,公司找的是能胜任某个岗位的人才,而不是啥都不精的半吊子。还好,没过多久我就明白了这个道理,于是分别做了三个方向的简历,每份简历只写和岗位相关的经历。 那时候发现一个问题,身边的同学罕有做移动端和游戏开发的,大多数是做Java或者C++后台开发的,除此之外还有一些人做的方向我之前听都没听过,什么机器学习、数据挖掘,这都是我在读研的时候才知道的岗位。后来才发现,这几年这个方向很火,薪资很高,做游戏、移动端的越来越少,也和行业状况有很大的关系。 当时我还是比较纠结的,是继续做小众的游戏开发或者移动端,找小众的游戏公司,还是做需求量更大的Java方向,去尝试更多的大公司呢。想来想去,游戏大厂就那么两家,反观Java方向能去的互联网公司,BAT、TMD不说,还有很多二线的企业、银行,甚至是国企,这完全是两条路啊,一条是圈子很小,选择很少的游戏程序员路线,一条是机会多,公司多的,很多人也在走的Java程序员路线,考虑到未来的岗位机会、工作机会、职业发展,最终我还是选了后者。 再谈选择技术方向的关键因素如今我已经在Java这条路上走了很久了,回顾过去,其实也不知道当初做的这个选择是不是对的,虽然现在也是在一线大厂,但是如果当初还是做游戏开发,现在又会在哪呢,说不准,谁也不知道。 所以,选择了一个技术方向,可能也意味着你今后要在这条路上走很久,走很远,可能无法回头。就像是选专业一样,大学四年不能白学,专业课不是白上的,很多人虽然不喜欢自己的专业,但是再去尝试其他专业的成本实在太高,所以半推半就也只好接受了不太喜欢的工作。 选择技术方向,比高考选专业要灵活多了,没有分数要求,也不用权衡学校和专业,只要考虑自己的兴趣、能力、未来发展路线,就可以确定好自己的一个方向。这里不再大谈各个技术方向,因为上次的那篇文章已经讲了够多了,有兴趣的可以回头去看看。 如今还是有很多同学来问我,怎么选方向,大数据还是Java、Python还是Java、前端还是后端、计算机还是软件。其实你们问我,不如问问自己,到底喜欢什么方向,其实这些岗位都不错,未来也大有可为,大厂的需求也很大,短期看来算法和大数据还是很火,但是前端后端仍然是常青树,测试、运维等岗位需求不算大但是却是进大厂的一种不错方式,游戏开发和移动端虽然没有以前那么火,但是小众的人才更稀缺。 不管怎么说,选好一个方向,是很重要的,未来你必须在这个方向深挖,积累,成为这个方向的技术专家,这是每一个程序员都需要面对的挑战。

April 30, 2019 · 1 min · jiezi

用Swoole来写个联机对战游戏呀二单机游戏架构

游戏逻辑开发进度:□□□□□□□□□□□□ 本章结束开发进度:■■■■□□□□□□□□ 开发环境教程需要PHP-7.x版本支持,由于不是面向基础小白,PHP环境需要童鞋们自行安装配置,以下是一些有可能有帮助的资料: Windows:https://www.apachefriends.org...Linux:https://lnmp.org/install.htmlMac:不存在的。。赵童鞋没玩过引入Composer在合适的位置新建一个文件夹HideAndSeek作为我们的项目根目录。 为了后续开发的方便,我们需要为我们的项目引入composer的自动加载机制,并在项目根目录运行以下命令: composer init小提示:没有安装composer的童鞋需要自行安装喔:https://pkg.phpcomposer.com/#...启用国内镜像地址,下载速度更快。国内镜像一:composer config -g repo.packagist composer https://packagist.phpcomposer.com国内镜像二:composer config -g repo.packagist composer https://packagist.laravel-china.org经过几次回车之后,composer就会为我们生成一个composer.json文件,需要在这个文件中增加以下代码: "autoload": { "psr-4": { "App\\": "app" }},再运行一次composer命令: composer installcomposer就会为我们创建vendor文件夹,里面会有一个autoload.php文件,这个文件就是用来实现类自动加载机制。 建立项目结构下一步就是编写游戏的逻辑,实现一个单机版的捉迷藏。 在上面创建的文件夹HideAndSeek中新建一个test.php文件 HideAndSeek└─test.php为什么要新建这个test.php呢?因为我们现在对整个项目的架构毫无头绪,所以需要将这个游戏逻辑拆分成几个步骤,并且将逻辑预先写在test.php文件中。 赵童鞋设想的游戏逻辑是这样的: 每个玩家要有一个ID,用来区别玩家。要有一个游戏控制器,用来创建玩家、执行移动逻辑、判断游戏是否结束。使用游戏控制器创建玩家,游戏开始。使用游戏控制器控制某个玩家进行移动。test.php文件: $redId = "red_player";$blueId = "blue_player";//创建游戏控制器$game = new Game();//添加玩家$game->createPlayer($redId, 6, 1);//添加玩家$game->createPlayer($blueId, 6, 10);//移动坐标$game->playerMove($redId, 'up');现在就很明显了,我们首要任务就是先实现这样一个游戏控制器。 在HideAndSeek文件夹中创建app文件夹,app文件夹用来存放我们项目的各种类文件。并在app文件夹中创建Manager文件夹用来存放所有管理者类的类文件,在Manager文件夹中创建Game游戏控制器类。 为了composer能够自动加载类文件,需要在Game类编写命名空间代码:namespace App\Manager,细心的童鞋已经发现了,我们上面在composer.json文件中新增代码时,就有提到App这个词,不了解自动加载机制的童鞋可以自行搜索一下composer psr-4。 <?phpnamespace App\Manager;class Game{}我们现在要思考一下游戏还需要哪些实体类,我们捉迷藏游戏有玩家,有地图,所以游戏还需要两个实体类:一个是玩家类,另一个是地图类,没错,这就是面向对象编程,而不是面向运气编程。 在app文件夹下新建Model文件夹,用来存放各种游戏实体类,并在其中新建Player类和Map类: <?phpnamespace App\Model;class Player{}<?phpnamespace App\Model;class Map{}完善各类代码现在我们需要思考一下,这三个类各自的属性和方法需要有哪些。 Map类我们先从最简单的Map类开始: Map对象应该在创建的时候可以指定长和宽,并生成一个地图。Map对象中应该有一个数组,用来保存完整的地图数据,我们假设这个数组中,0是墙,1是路。Map类中需要有一个方法来获取地图数据。由于生成一个地图的算法有点复杂,我们现在的重点只在于编写游戏逻辑,所以地图数据可以先写死。 <?phpnamespace App\Model;class Map{ private $width; private $height; private $map = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0], [0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0], [0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0], [0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ]; public function __construct($width, $height) { $this->width = $width; $this->height = $height; } public function getMapData() { return $this->map; }}Player类第二个轮到我们的Player类: ...

April 30, 2019 · 2 min · jiezi

北京 | 游戏出海技术指南:海外网络实践及优化专场

国内对游戏版号的限制,让「出海」成了游戏行业的热门词汇。但一款游戏如果想要平稳出海却不是件容易的事,无论是文化、设备还是推广方式都有着明显的差异。而技术方面,单海外网络一项就让不少游戏开发人员感到头疼。本期活动,我们邀请了资深媒体人罗斯基、IPIP.NET 创始人高春辉、LeanCloud 运维工程师缪思源以及 UCloud 互动娱乐事业部架构师沈皓,围绕海外市场趋势及网络优化等,分享他们的实践经验。01.活动流程13:20 - 14:00 签到开场14:00 - 14:40 游戏出海那些事(海外市场、渠道、产品以及趋势机会判断)14:40 - 15:20 网络地理之东南亚篇15:20 - 15:30 茶歇15:30 - 16:10 海外网络优化及故障排除实践16:10 - 16:50 出海游戏那些坑(出海及全球服游戏的技术要求及门槛)16:50 - 17:10 现场抽奖交流02.嘉宾介绍嘉宾一主题: 游戏出海那些事内容简介:海外市场、渠道、产品以及趋势机会判断。罗斯基资深媒体人十年行业经历。目前关注小游戏和游戏出海,喜欢写稿,希望探求分享有料、有趣、有价值的内容。嘉宾二主题:网络地理之东南亚篇内容简介:老高去了趟东南亚,对东南亚的互联网市场做了一次比较全面的考察,到底东南亚的互联网世界跟我们有啥不同,那边对互联网又有啥不一样的需求?且听老高一一给大家分享。高春辉IPIP.NET 创始人中国第一个个人站长,也是一位连续创业者,先后创办金山卓越电脑资讯站、天下网、手机之家、ECSHOP软件,《爱壁纸HD》应用和 IPIP.NET。嘉宾三主题:海外网络优化及故障排除实践内容简介:以切身经验分享在部署海外节点及境内节点的海外访问遇到的问题,以及日常优化监测使用的工具。缪思源LeanCloud 运维工程师主要从事运维自动化相关的工作,对网络性能监控和优化有一定的研究。目前就职于 LeanCloud,主要负责海外业务的规划及运维等工作。嘉宾四主题:出海游戏那些坑内容简介:通过沉淀多年的业务经验,将与参会者重点分享出海及全球服游戏的技术要求及门槛。并且详细解析海外网络基建情况及各地域的特殊要求。沈皓UCloud 互动娱乐事业部架构师PathX产品早期方案设计者之一,深耕全球服游戏领域,对出海、全球化业务客户的架构、产品需求有深刻理解。曾全面负责SC、盖娅、趣加等多个知名游戏出海项目的全球/跨国业务对接、部署及落地。对于MOBA、RTS、FPS等各类游戏的出海全球化的需求、难点、架构实现等深入分析并有独到见解。03.活动信息点击此处报名时间:2019 年 4 月 20 日 13:00 ~ 17:30地点:北京朝阳工体东路20号百富国际大厦-B座三层(WeWork)

April 1, 2019 · 1 min · jiezi

Matchvs多节点功能上线

为了满足不同区域的用户需求,Matchvs现已正式上线多节点功能(正式版),本次上线的服务器节点包括北京、上海、广州三个国内节点。部分游戏类型(如fps、格斗及竞速类等)对于延迟容忍极低,就近节点连接可以有效降低延迟。Matchvs开放了自选多节点服务,开发者可以根据游戏要求给游戏开通该服务。开通多节点服务后,可以实现:1.玩家根据节点延迟情况,手动切换节点进行游戏。2.游戏里可以根据匹配情况,自动做节点切换策略。需注意是,玩家会在各节点分别匹配。若游戏内玩家数量过少,可以让游戏内自动做节点切换策略,以兼顾匹配成功率与低延时。若游戏对延时要求不高(如棋牌,回合制游戏等),则不建议您开启多节点服务。1. 多节点开通教程如需开启多节点服务,可以前往控制台 - 游戏列表 - 设置:成功启用后,即可对接 SDK 多节点功能,gameServer 无变化。在 Matchvs SDK中 使用接口获取节点信息,并切换到指定的节点。2. 多节点接口说明initinit 接口和之前的 init 接口是同一个,这里只是在 init 接口中新增了一个参数 threshold,只有传了该参数,才能获取节点列表和使用指定节点登录。getNodeList获取节点列表信息。在 init 成功后才能使用,并且init必须传入 threshold参数。否则返回值为 null。engine.getNodeList()无请求参数返回值说明 登录接口和前面 API文档描述的登录接口是同一个。只是加了一个 nodeID 参数,如果不传这个参数或者传入的参数为0,login 则使用默认节点登录。否则会使用指定的 nodeID登录,nodeID 必须是从 getNodeList 接口获取的有效ID。changeNode切换到指定节点中,切换节点只能在拥有多个节点的情况下使用,并且只能切换到 getNodeList 获取到的节点中。所有在 init 的时候设置好 threshold 参数。切换节点是指在使用 login 接口登录了默认节点后,想换一个节点就可以使用 changNode 接口切换到指定节点,所以,要使用 changeNode 接口必须是在登录后。engine.changeNode(args)返回值说明开发者如需体验过节点功能,需要下载SDK v3.7.9及以上版本,后续其它国内与国外的区域节点也将陆续上线。返回值说明开发者如需体验过节点功能,需要下载SDK v3.7.9及以上版本,后续其它国内与国外的区域节点也将陆续上线。Matchvs,24H轻松打造标准多人实时在线游戏,一个SDK解决服务器购买、联网&数据库开发、后期运维、高并发稳定问题。

March 13, 2019 · 1 min · jiezi

如何实现手游中的账户系统|游戏后端

作者:崔毅然在这篇文章中,我们使用 LeanCloud 作为后端来实现游戏内的账户系统。这篇文章以 Unity 游戏引擎中的 C# 语言为示例,主要讲解如何实现几种主流的登录方式,包括游客登录、游客账号升级、手机号验证码登录、用户名密码注册及登录。接入 SDK首先要接入 LeanCloud 的 SDK,接入方式可以参考文档。游客登录为了让玩家尽快体验游戏,每一个游戏都会有游客登录的功能。游客登录在 LeanCloud 中可以这样来实现:var user = await AVUser.LogInAnonymouslyAsync();调用上述代码成功后,LeanCloud 会自动生成一个游客用户登录,进入「控制台」 - 「存储」-「_User」表就可以看到表中新增了一条数据。在客户端登录的游客信息会一直被 SDK 存在本地,直到玩家删除游戏或主动退出登录。但就像所有游戏中的游客登录一样,当该游客退出登录后会丢失自己全部的游戏数据,为了保存游戏数据,需要将游客账号升级为正式账号。游客账号升级为了不丢失玩家的数据,我们会在游戏内建议玩家升级账号为正式玩家。例如绑定微信登录、绑定用户名密码及手机号,绑定成功后玩家就能以正式的登录方式获取到自己的游戏数据。升级为微信登录假设我们已经通过某些方法(例如使用 ShareSDK)拿到了微信的 openId、access_token、unionId 等,可以这样在 LeanCloud 中将游客账号关联到微信登录中:var authData = new Dictionary<string, object> { { “access_token”, “ACCESS_TOKEN” }, { “expires_in”, 7200 }, { “openid”, “OPENID” },// openId 是用户在当前微信应用下的唯一 Id}; // unionId 是用户在整个微信内的唯一 Idvar unionId = “ox7NLs06ZGfdxbLiI0e0F1po78qE”; AVUserAuthDataLogInOption options = new AVUserAuthDataLogInOption{ UnionIdPlatform = “weixin”,// 这里指定用微信平台 AsMainAccount = true}; var user = AVUser.CurrentUser;// 绑定微信登录,第二个参数 weixinapp1是自定义的当前微信应用的标识await user.AssociateAuthDataAndUnionIdAsync(authData, “weixinapp1”, unionId, options);关联成功后,玩家以后就可以用微信登录了,登录代码见下文的第三方账户登录。绑定用户名、密码及手机号var currentUser = AVUser.CurrentUser;currentUser.Username = “username”;currentUser.Password = “password”;user.MobilePhoneNumber = “186xxxxxxxx”;await currentUser.SaveAsync();如果保存了手机号,保存成功后 LeanCloud 会自动向该手机号发送一条验证码,用户输入验证码后验证手机号:await AVUser.VerifyMobilePhoneAsync(“6位数字验证码”);手机号码验证成功后,该玩家以后就能以手机号登录了,这样就保证了游戏数据不会丢失。手机号+验证码登录、用户名及密码登录的代码见下文。手机号 + 验证码登录这种登录方式下,如果 _User 表中没有这个手机号,则视为新用户,会自动注册账号并登录;如果 _User 表中某个用户已经有了这个手机号(例如曾使用过该手机号登录,或通过游客账号升级绑定的信息),则直接登录。首先,调用发送登录验证码的接口:await AVCloud.RequestSMSCodeAsync(“18611111111”);然后使用验证码来登录var user = await AVUser.SignUpOrLogInByMobilePhoneAsync(“18611111111”, “6位短信验证码”);用户名 + 密码注册登录这种是最常见的登录方式,稍微有一点麻烦的是,需要玩家记住自己的用户名和密码。注册如果 _User 表中没有相应的用户名密码信息,例如从未注册过,也没有通过游客升级的方式增加用户名密码,需要先注册。var user = new AVUser();user.Username = “Tom”;user.Password = “cat!@#123”;await user.SignUpAsync();Debug.Log(user.Username);登录var user = await AVUser.LogInAsync(“username”, “password”);Debug.Log(user.Username);第三方登录微信或 QQ 登录可以让玩家更便捷的登录游戏。利用 LeanCloud 第三方登录的模块就可以完成这种场景。微信登录假设现在开发者已经通过某些方法(例如使用 ShareSDK)拿到了微信的 openId、access_token、unionId 等,无需注册就可以在 LeanCloud 中直接登录。如果游客已经升级绑定了微信信息,也可以通过这种方式来登录。var authData = new Dictionary<string, object> { { “access_token”, “ACCESS_TOKEN” }, { “expires_in”, 7200 }, { “openid”, “OPENID” },// openId 是用户在当前微信应用下的唯一 Id};// unionId 是用户在整个微信内的唯一 Id var unionId = “ox7NLs06ZGfdxbLiI0e0F1po78qE”; AVUserAuthDataLogInOption options = new AVUserAuthDataLogInOption{ UnionIdPlatform = “weixin”,// 这里指定用微信平台 AsMainAccount = true}; // 绑定微信登录,第二个参数 weixinapp1 是自定义的当前微信应用的标识var user = await AVUser.LogInWithAuthDataAndUnionIdAsync(authData, “weixinapp1”, unionId, options);在 LogInWithAuthDataAndUnionIdAsync 这个方法中,第二个参数是自己定义的微信应用的名字,第三个参数 unionId 是用户在多个微信应用之间互通的唯一 id。如果我们有多个微信应用,就可以通过 unionId 登录来实现多个微信应用之间的账号互通。其他平台如果是其他平台,例如 facebook 是没有 unionId 的,这个时候只需要 access_token、expires_in、uid 三个自定义字段就可以了。var authData = new Dictionary<string, object> { { “access_token”, “ACCESS_TOKEN” }, { “expires_in”, 7200 }, { “uid”, “FACEBOOK_UID” },};var user = await AVUser.LogInWithAuthDataAsync(authData, “facebook”);由于 LeanCloud 默认只支持微信、QQ、新浪微博登录,因此对 Facebook 需要额外去设置一下唯一索引,设置唯一索引的方式非常简单,只需要进入控制台,在 _User 表中选择「其他」-「索引」,将 authData.facebook.uid 建立唯一索引,并且勾选上「允许缺失值」选项,这样 Facebook 登录也完成了。 ...

March 7, 2019 · 2 min · jiezi

学习 PixiJS — 动画精灵

说明看完官方教程中提到的这本书 — Learn Pixi.js ,准备写写读后感了,官方教程中所说的内容,基本上就是书的前4章,所以我就从第5章开始写写吧。动画精灵指的是按顺序使用一系列略有不同的图像,创建的精灵,之后一帧一帧的播放这些图像,就可以产生运动的幻觉。也就是说用这种图片做出这样的效果 要制作动画精灵我们需要用到 PixiJS 的 AnimatedSprite 方法。PIXI.extras.AnimatedSprite定义:使用纹理数组创建动画精灵的方法。用法:new PIXI.extras.AnimatedSprite(textures,autoUpdate)参数 :名称类型默认值描述texturesarray 用一系列略有不同的图像做的纹理数组。autoUpdatebooleantrue用来判断是否使用 PIXI.ticker.shared 自动更新动画时间。返回值: 返回一个对象,对象会有一些属性和方法,用于控制动画精灵。返回值对象的属性:名称类型描述animationSpeednumber动画精灵的播放速度。越高越快,越低越慢,默认值是1currentFramenumber(只读)正在显示的当前帧编号onCompletefunction当loop属性为false时,一个动画精灵完成播放时调用playingBoolean确定当前动画精灵是否正在播放onFrameChangefunction当一个动画精灵更改要呈现的纹理时调用loopboolean动画精灵是否在播放后重复播放onLoopfunction当loop属性为true时调用的函数texturesarray用于这个动画精灵的纹理数组totalFramesnumber (只读)动画中的帧总数返回值对象的方法:名称参数描述play 播放动画精灵gotoAndPlayframeNumber,number类型,开始帧的索引转到特定的帧并开始播放动画精灵stop 停止播放动画精灵gotoAndStopframeNumber,number类型,停止帧的索引转到特定的帧并停止播放动画精灵使用返回值中的这些属性和方法,我们就可以控制动画精灵了,比如播放动画精灵,设置动画的速度,设置是否循环播放等,除此之外,还要知道就是 PIXI.extras.AnimatedSprite 方法继承自 PIXI.Sprite 方法,所以动画精灵也可以用普通精灵的属性和方法,比如x,y,width,height,scale,rotation 。好的,我们开始试试这个方法。<!doctype html><html lang=“zn”><head> <meta charset=“UTF-8”> <title>动画精灵</title></head><body> <div id=“px-render”></div> <script src=“https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.8.2/pixi.min.js"></script> <script> // 创建一个 Pixi应用 需要的一些参数 let option = { width: 400, height: 300, transparent: true, } // 创建一个 Pixi应用 let app = new PIXI.Application(option); // 获取渲染器 let renderer = app.renderer; let playground = document.getElementById(‘px-render’); // 把 Pixi 创建的 canvas 添加到页面上 playground.appendChild(renderer.view); //设置别名 let TextureCache = PIXI.utils.TextureCache; let Texture = PIXI.Texture; let Rectangle = PIXI.Rectangle; let AnimatedSprite = PIXI.extras.AnimatedSprite; //需要加载的雪碧图的地址(该图片服务器端已做跨域处理) let imgURL = “https://www.kkkk1000.com/images/learnPixiJS-AnimatedSprite/dnf.png"; //加载图像,加载完成后执行setup函数 PIXI.loader.add(imgURL).load(setup); function setup() { //获取纹理 let base = TextureCache[imgURL]; //第一个纹理 let texture0 = new Texture(base); texture0.frame = new Rectangle(0, 0, 80, 143); //第二个纹理 let texture1 = new Texture(base); texture1.frame = new Rectangle(80, 0, 80, 143); //第三个纹理 let texture2 = new Texture(base); texture2.frame = new Rectangle(160, 0, 80, 143); //第四个纹理 let texture3 = new Texture(base); texture3.frame = new Rectangle(240, 0, 80, 143); //创建纹理数组 let textures = [texture0, texture1, texture2,texture3]; //创建动画精灵 let pixie = new PIXI.extras.AnimatedSprite(textures); //设置动画精灵的速度 pixie.animationSpeed=0.1; //把动画精灵添加到舞台 app.stage.addChild(pixie); //播放动画精灵 pixie.play(); } </script></body></html>查看效果 上面这个例子中,创建纹理数组时似乎点麻烦,要解决这个问题,我们可以用名叫 SpriteUtilities 的库,该库包含许多有用的函数,用于创建Pixi精灵并使它们更易于使用。安装:直接用 script 标签,引入js 文件就可以<script src=“https://www.kkkk1000.com/js/spriteUtilities.js"></script>安装好之后,我们需要创建一个新实例,代码如下let su = new SpriteUtilities(PIXI);之后就可以用 su 对象访问所有方法了。我们这里需要用到的就是 su 对象的 filmstrip 方法。定义:filmstrip 方法可以自动将雪碧图转换为可用于制作精灵的纹理数组用法:su.filmstrip(“anyTilesetImage.png”, frameWidth, frameHeight, optionalPadding);参数:名称类型描述anyTilesetImagestring雪碧图的路径frameWidthnumber每帧的宽度(以像素为单位)frameHeightnumber每帧的高度(以像素为单位)optionalPaddingnumber每帧周围的填充量(可选值,以像素为单位)返回值: 返回一个数组,可用于制作动画精灵的纹理数组。现在我们使用 SpriteUtilities 来改写下刚才的示例代码。<!doctype html><html lang=“zn”><head> <meta charset=“UTF-8”> <title>动画精灵</title></head><body> <div id=“px-render”></div> <script src=“https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.8.2/pixi.min.js"></script> <script src=“https://www.kkkk1000.com/js/spriteUtilities.js"></script> <script> //创建一个 Pixi应用 需要的一些参数 var option = { width: 400, height: 300, transparent: true, } //创建一个 Pixi应用 var app = new PIXI.Application(option); //获取渲染器 var renderer = app.renderer; var playground = document.getElementById(‘px-render’); //把 Pixi 创建的 canvas 添加到页面上 playground.appendChild(renderer.view); let su = new SpriteUtilities(PIXI); //需要加载的雪碧图的地址(该图片服务器端已做跨域处理) let imgURL = “https://www.kkkk1000.com/images/learnPixiJS-AnimatedSprite/dnf.png"; PIXI.loader.add(imgURL).load(setup); function setup() { //创建纹理数组 let frames = su.filmstrip(imgURL, 80, 143); //创建动画精灵 let pixie = new PIXI.extras.AnimatedSprite(frames); //设置动画精灵的速度 pixie.animationSpeed=0.1; //把动画精灵添加到舞台 app.stage.addChild(pixie); //播放动画精灵 pixie.play(); } </script></body></html>查看效果 filmstrip 方法自动将整个雪碧图转换为可用于制作动画精灵的纹理数组。但是,如果我们只想使用雪碧图中的一部分帧呢?这时候需要用到 frames 方法了。定义:frames 方法使用雪碧图中的一组子帧,来创建纹理数组。用法:su.frames(source, coordinates, frameWidth, frameHeight)参数:名称类型描述sourcestring雪碧图的路径coordinatesarray包含每帧的 x 和 y 坐标的二维数组frameWidthnumber每帧的宽度(以像素为单位)frameHeightnumber每帧和高度(以像素为单位)返回值: 返回一个数组,可用于制作动画精灵的纹理数组。示例代码:<!doctype html><html lang=“zn”><head> <meta charset=“UTF-8”> <title>动画精灵</title></head><body> <div id=“px-render”></div> <script src=“https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.8.2/pixi.min.js"></script> <script src=“https://www.kkkk1000.com/js/spriteUtilities.js"></script> <script> //创建一个 Pixi应用 需要的一些参数 var option = { width: 400, height: 300, transparent: true, } //创建一个 Pixi应用 var app = new PIXI.Application(option); //获取渲染器 var renderer = app.renderer; var playground = document.getElementById(‘px-render’); //把 Pixi 创建的 canvas 添加到页面上 playground.appendChild(renderer.view); let su = new SpriteUtilities(PIXI); //需要加载的雪碧图的地址(该图片服务器端已做跨域处理) let imgURL = “https://www.kkkk1000.com/images/learnPixiJS-AnimatedSprite/dnf.png"; PIXI.loader.add(imgURL).load(setup); function setup() { //创建纹理数组 let frames = su.frames(imgURL, [[0,0],[80,0],[160,0],[240,0]],80, 143); //创建动画精灵 let pixie = new PIXI.extras.AnimatedSprite(frames); //设置动画精灵的速度 pixie.animationSpeed=0.1; //把动画精灵添加到舞台 app.stage.addChild(pixie); //播放动画精灵 pixie.play(); } </script></body></html>查看效果除了上面提到的方式,还可以用纹理贴图集来创建动画精灵。使用纹理贴图集来创建动画精灵,就是先通过json文件,加载所有纹理,然后把需要的纹理再放进一个数组中,最后把这个数组当参数,传入PIXI.extras.AnimatedSprite 方法中,来创建动画精灵。 代码:<!doctype html><html lang=“zn”><head> <meta charset=“UTF-8”> <title>动画精灵</title></head><body> <div id=“px-render”></div> <script src=“https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.8.2/pixi.min.js"></script> <script> //创建一个 Pixi应用 需要的一些参数 var option = { width: 400, height: 300, transparent: true, } //创建一个 Pixi应用 var app = new PIXI.Application(option); //获取渲染器 var renderer = app.renderer; var playground = document.getElementById(‘px-render’); //把 Pixi 创建的 canvas 添加到页面上 playground.appendChild(renderer.view); //需要加载的纹理贴图集的地址 let textureURL = “https://www.kkkk1000.com/images/learnPixiJS-AnimatedSprite/dnf.json"; //加载纹理贴图集,加载完成后执行setup函数 PIXI.loader.add(textureURL).load(setup); function setup() { let id = PIXI.loader.resources[textureURL].textures; //创建纹理数组 let frames = [ id[“dnf0.png”], id[“dnf1.png”], id[“dnf2.png”], id[“dnf3.png”] ]; //创建动画精灵 let pixie = new PIXI.extras.AnimatedSprite(frames); //设置动画精灵的速度 pixie.animationSpeed=0.1; //把动画精灵添加到舞台 app.stage.addChild(pixie); //播放动画精灵 pixie.play(); } </script></body></html>查看效果上面的代码创建纹理数组时,是把纹理一个一个的放进数组中,如果数量比较少还好,多一点呢?假如有100个呢?一个一个的放就太麻烦了,这时候我们可以用 SpriteUtilities 库中提供的 frameSeries 方法。定义:frameSeries 方法可以通过已加载的纹理贴图集,使用一系列编号的帧ID来创建动画精灵。用法:su.frameSeries(startNumber, endNumber, baseName, extension)参数:名称类型描述startNumbernumber起始帧序列号(默认值是0)endNumbernumber结束帧序列号(默认值是1)baseNamestring可选的基本文件名extensionstring可选的文件扩展名返回值: 返回一个数组,可用于制作动画精灵的纹理数组。注意: 使用 frameSeries 方法时,要确保在 json 文件中,定义的每帧的名称都是按顺序来的,比如 frame0.png frame1.png frame2.png 这种。因为 frameSeries 方法的源码是这样写的 frameSeries(startNumber = 0, endNumber = 1, baseName = “”, extension = “”) { //创建一个数组来存储帧名 let frames = []; for (let i = startNumber; i < endNumber + 1; i++) { let frame = this.TextureCache[${baseName + i + extension}]; frames.push(frame); } return frames; }源码中其实是用 for 循环把帧名拼接起来的。所以要保证帧名是按顺序来的,不然就获取不到了。下来我们就试试 frameSeries 方法吧。<!doctype html><html lang=“zn”><head> <meta charset=“UTF-8”> <title>动画精灵</title></head><body> <div id=“px-render”></div> <script src=“https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.8.2/pixi.min.js"></script> <script src=“https://www.kkkk1000.com/js/spriteUtilities.js"></script> <script> //创建一个 Pixi应用 需要的一些参数 var option = { width: 400, height: 300, transparent: true, } //创建一个 Pixi应用 var app = new PIXI.Application(option); //获取渲染器 var renderer = app.renderer; var playground = document.getElementById(‘px-render’); //把 Pixi 创建的 canvas 添加到页面上 playground.appendChild(renderer.view); let su = new SpriteUtilities(PIXI); //需要加载的纹理贴图集的地址 let textureURL = “https://www.kkkk1000.com/images/learnPixiJS-AnimatedSprite/dnf.json"; PIXI.loader.add(textureURL).load(setup); function setup() { //创建纹理数组 let frames = su.frameSeries(0,7,“dnf”,".png”); //创建动画精灵 let pixie = new PIXI.extras.AnimatedSprite(frames); //设置动画精灵的速度 pixie.animationSpeed=0.1; //把动画精灵添加到舞台 app.stage.addChild(pixie); //播放动画精灵 pixie.play(); } </script></body></html>查看效果注意版本问题: 1、PIXI.extras.AnimatedSprite 这个方法原来叫PIXI.extras.MovieClip ,是在 4.2.1 版本的时候修改的,本文示例代码中用 PixiJS 的版本是 4.8.2,所以没有问题,如果你在使用过程中发现调用PIXI.extras.AnimatedSprite 这个方法有问题,可以先检查下版本是否正确。2、 SpriteUtilities 目前支持的 PixiJS 的版本是 3.0.11,而 SpriteUtilities 中用的就是PIXI.extras.MovieClip 方法,所以你如果用了比较高的 PixiJS 的版本,需要在SpriteUtilities 中修改下方法的别名。在 spriteUtilities.js 文件中需要把 renderingEngine.extras.MovieClip 改成renderingEngine.extras.AnimatedSprite,把 renderingEngine.ParticleContainer 改成 PIXI.particles.ParticleContainer 。这个 spriteUtilities.js 就是修改后的。当然你也可以使用低版本的 PixiJS,这样就不用改 spriteUtilities.js 的代码了。总结动画精灵就是逐帧动画,通过一帧一帧的播放图像来产生运动的幻觉。本文就是聊了聊创建动画精灵的一些方式和如何使用动画精灵。如果文中有错误的地方,还请小伙伴们指出,万分感谢。 ...

January 14, 2019 · 4 min · jiezi

如何通过服务端控制游戏逻辑

在如何开发答题对战小游戏中给大家展示了对战开发的基础结构:拥有多个房间类型的游戏,每个房间有两个玩家的情况下,游戏过程中玩家之间的通信均通过 LeanCloud Play 实时对战转发。游戏中,我们还使用了 MasterClient ,作为一个裁判或上帝视角的角色,用于出题及判断每个玩家的分数。Play 实时对战默认房间的创建者为 MasterClient,也就是说,创建房间的 Client 会有两种身份,一个是普通的玩家,另一个是 MasterClient 裁判角色。MasterClient 除了在答题小游戏中出题之外,还可以在卡牌类游戏中洗牌、控制刷怪的时机或等级、判断游戏胜负等等。它掌握着房间内整个游戏逻辑。既然 MasterClient 是个这么重要的角色,那么我们把他放在客户端就会有一个重要问题:安全隐患。例如客户端的代码被破解之后,MasterClient 身份的玩家可以篡改游戏数据,指定本该输掉的人胜利等。为了解决这个问题,我们把控制游戏逻辑的 MasterClient 从客户端移到服务端,这样从客户端就拿不到游戏逻辑代码,进而也无法控制游戏逻辑。我们把每个房间的 MasterClient 托管在一个叫 Client Engine 的后端服务上,MasterClient 在 Client Engine 中通过实时对战后端服务和客户端进行交互。产生了新的架构:这里 Client Engine 和实时对战云都是 LeanCloud 的服务,同在 LeanCloud 的后端内网中。实战开发目标 Demo下面我们感受下如何基于这种架构开发小游戏,在这次分享中我们的目标是开发一个剪刀石头布对战小游戏。你可以用两个浏览器打开这个页面,感受下整个小游戏。在这个小游戏中,两个客户端点击「快速开始」,进入到同一个房间内,游戏开始后进行猜拳,一轮猜拳后判断胜负,游戏结束。游戏逻辑我们把游戏逻辑拆解为以下步骤:1.进入房间:客户端点击「快速开始」时,MasterClient 及玩家客户端 A 和 B 进入同一房间2.双方开始游戏:玩家 A 选择手势玩家 B 界面展示:对方已选择玩家 B 选择手势玩家 A 界面展示:对方已选择玩家 A 及 B 的界面展示结果3.游戏结束,双方离开房间,房间销毁。服务和语言1.服务选择:选择已经搭建好的后端服务 LeanCloud Play,不需要我们再自己去搭建后端整体架构。服务端逻辑控制:Client Engine游戏内通信:实时对战服务2.语言选择:JavaScript(这样我们一个人就能搞定前端和后端的代码)明确服务端及客户端的分工服务端:托管 MasterClient 代码,控制游戏逻辑。客户端:根据情况展示 UI准备项目框架服务端 Client Engine 初始项目客户端项目游戏逻辑开发下面我们进入写代码的模块。进入房间客户端点击「快速开始」时,MasterClient 及玩家客户端 A 和 B 进入同一房间Client Engine 服务端:维护 MasterClient 并创建房间,下发 roomName 给客户端客户端:加入服务端创建的房间中我们先看一下 Client Engine 中的逻辑:Client Engine 负责维护 MasterClient 并创建房间,通过一个名为 /reservation 的自定义 API 接口为客户端提供 roomName,在这个接口中我们实现逻辑「快速开始」。「快速开始」中创建房间的功能是使用 Client Engine SDK 中的 GameManager 来实现的。在 Client Engine 中,我们使用到的 Client Engine SDK 提供以下两个组件。Game:每个房间对应一个 Game 实例,Client Engine 中有 N 个 Game。GameManager:GameManager 负责创建、管理、销毁 Game。我们只需要根据情况组合这两个组件的功能就可以实现自己的需求。接下来我们写「快速开始」的逻辑:随机为客户端找到一个房间,如果没有空房间,就创建一个新房间。import { Game, GameManager, ICreateGameOptions } from “@leancloud/client-engine”; export default class Reception<T extends Game> extends GameManager<T> { public async makeReservation(playerId: string) { let game: T; const availableGames = this.getAvailableGames(); if (availableGames.length > 0) { game = availableGames[0]; this.reserveSeats(game, playerId); } else { game = await this.createGame(playerId); } return game.room.name; } }在这段代码中,我们创建了一个 Reception 类继承自 GameManager 来管理 Game。在这个类中,我们写了一个 public 方法 makeReservation 实现「快速开始」:首先调用 GameManager 自身的 getAvailableGames() 方法查看有没有可用的空房间,如果有,就取第一个空房间,返回 roomName ;如果没有空房间,则使用 GameManager 的 createGame() 方法创建一个新房间,返回新房间的 roomName。从上面的代码中我们还可以看到,Reception 管理了一个 T 类型的 Game 对象,因此我们还需要为 Reception 准备 Game。下面我们继续自定义一个自己的 Game :import { Game } from “@leancloud/client-engine”;import { Event, Play, Room } from “@leancloud/play”;export default class RPSGame extends Game { constructor(room: Room, masterClient: Play) { super(room, masterClient); }}在这段代码中,我们自定义了一个名为 RPSGame 的类继承自 Game,之后会在 RPSGame 中撰写房间内的游戏逻辑,在这里我们先简单的将这个类构造出来。接下来我们把这个类给到 Reception,让 Reception 来管理这个类。import PRSGame from “./rps-game”;const reception = new Reception( PRSGame, APP_ID, APP_KEY, {concurrency: 2});在这段代码中,我们创建了一个 reception 对象,在创建对象的第一个参数中,我们传入了刚才创建的 RPSGame,这样 Reception 就可以管理 RPSGame 了,到现在为止「快速开始」的逻辑就可以跑起来了。下面我们写一个 API 接口来提供「快速开始」功能:app.post("/reservation", async (req, res, next) => { try { const {playerId} = req.body as {playerId: any}; // 调用我们在 Reception 类中准备好的 makeReservation() 方法 const roomName = await reception.makeReservation(playerId); return res.json({roomName}); } catch (error) { next(error); }}到这里,服务端「快速开始」就准备好了,当客户端调用该 /reservation 接口时,服务端会执行快速开始的逻辑,给客户端随便返回一个有空位的房间。客户端调用 /reservation 的示例代码如下:// 向 Client Engine 请求快速开始。// 这里通过 HTTP 调用在 Client Engine 中实现的 /reservation 接口const { roomName } = await (await fetch( ${CLIENT_ENGINE_SERVER}/reservation, { method: “POST”, headers: {“Content-Type”: “application/json”}, body: JSON.stringify({ playerId: play.userId }) } )).json(); // 加入房间return play.joinRoom(roomName);当客户端 A 和 客户端 B 都运行加入房间的代码,进入同一个房间后,就可以开始游戏了,接下来是实现房间内的逻辑。自定义游戏逻辑限定房间人数export default class RPSGame extends Game { public static defaultSeatCount = 2;}在这段代码中,我们给 RPSGame 设定一个静态属性 defaultSeatCount = 2,当房间玩家数量为两个人时,GameManager 会认为房间已满,不再是可用房间;GameManager 管理的 MasterClient 向实时对战服务请求创建新房间时,也会以这里的数量为标准,限定房间最大玩家数量是 2 个人,满 2 个人时不得有新玩家再加入房间。房间人满,广播游戏开始当房间内的玩家数量等于 defaultSeatCount 时,我们可以通过以下代码来监听房间人满事件:@watchRoomFull()export default class RPSGame extends Game { public static defaultSeatCount = 2; constructor(room: Room, masterClient: Play) { super(room, masterClient); // 游戏创建后立刻监听房间人满事件 this.once(AutomaticGameEvent.ROOM_FULL, this.start); } protected start = async () => { // 标记房间不再可加入 this.masterClient.setRoomOpened(false); // 向客户端广播游戏开始事件 this.broadcast(“game-start”); …… }}在这段代码中,@watchRoomFull 装饰器会让 Game 在人满时抛出 ROOM_FULL 事件,我们在 constructor() 方法中监听到这个事件后,调用了自己的 start 方法。在 start 方法中,我们将房间关闭,然后向客户端广播 game-start 事件,客户端收到这个事件后,在界面上展示:游戏开始。双方开始游戏我们再看一下双方游戏的逻辑:玩家 A 选择手势玩家 B 界面展示:对方已选择玩家 B 选择手势玩家 A 界面展示:对方已选择玩家 A 及 B 的界面展示结果将游戏逻辑对应到开发逻辑上,过程如下图所示:从图中可以看到,这里涉及到三方:客户端 A 、客户端 B、处在 Client Engine 中的 MasterClient。当客户端 A 出拳时,发送一个名为 play 的事件给 MasterClient,MasterClient 接收事件后,记录下来客户端 A 的选项,然后抹掉选项数据将事件转发给客户端 B,这样客户端 B 只知道客户端 A 出拳,但是并不知道具体手势是什么。接着客户端 B 出拳发送 play 事件,MasterClient 转发给客户端 A。这时 MasterClient 发现双方都已经出拳了,判定游戏结果,并通过广播 game-over 事件通知双方客户端游戏结束。首先我们看一下客户端 A 的出拳代码:play.sendEvent(“play”, {index}, {receiverGroup: ReceiverGroup.MasterClient});在这段代码中,客户端 A 使用实时对战 SDK 发送了 play 事件,在事件中附带了手势数据 {index},指定这个事件的接收对象为 MasterClient。处在 Client Engine 中的 MasterClient 收到 play 事件后转发事件给客户端 B:this.masterClient.on(Event.CUSTOM_EVENT, event => { const eventId = event.eventId; if (eventId === ‘play’) { this.forwardToTheRests(event, (eventData) => {}); }});在这段代码中,我们使用了 SDK 中 Game 提供的 forwardToTheRests() 方法,这个方法会转发事件给房间内其他人,第一个参数是原始事件 event,在第二个参数中,我们修改了原始 event 中的数据,将 eventData 设置为了空数据,这样客户端 B 收到事件时无法知道具体的手势信息。当客户端 B 收到事件后,就可以在界面上展示:对方已选择。相关代码如下:play.on(Event.CUSTOM_EVENT, ({ eventId, eventData, senderId }) => { const eventId = event.eventId; if (eventId === ‘play’) { //这里写客户端 UI 展示的代码 }});接着游戏逻辑是,客户端 B 选择手势,MasterClient 转发手势给客户端 A,这里的逻辑和上面的一样,不再赘述,我们直接跳到判断游戏胜负并广播游戏结束。相关代码如下:this.masterClient.on(Event.CUSTOM_EVENT, event => { const eventId = event.eventId; if (eventId === ‘play’) { …… if (answerArray.length === 2) { const winner = this.getWinner(answerArray); this.broadcast(“game-over”, {winnerId: winner.userId}); } }});在这段代码中可以看到,每次 MasterClient 收到 play 事件时,都会保存玩家的手势,当发现两个玩家都出拳后,根据两个玩家的出拳结果判断胜负,然后广播 game-over 事件,在 game-over 事件中告诉所有人胜负。客户端收到 game-over 事件后,在界面上展示游戏结束。客户端相关代码如下:play.on(Event.CUSTOM_EVENT, ({ eventId, eventData, senderId }) => { const eventId = event.eventId; if (eventId === ‘play’) { …… } if (eventId === ‘game-over’) { //展示游戏结束 }});离开房间当两个客户端都离开房间后,房间会被 GameManager 自动销毁,不需要我们再写额外的代码。总结在本次分享中,我们把负责游戏逻辑的 MasterClient 放在服务端来保证安全性。MasterClient 被托管到 Client Engine 中,通过实时对战后端云与同房间内的客户端传递消息,保证游戏正常运行。参考资料如果你希望有更详细的资料来帮助你一步一步开发猜拳小游戏,或更进一步了解 Client Engine,可以参考以下文档Client Engine 快速入门你的第一个 Client Engine 小游戏上期分享补充增加倒计时可以自己尝试为剪刀石头布游戏增加倒计时功能,例如某个客户端在限定时间内没有做出选择,则输掉本局比赛。RxJS如果希望对事件有更好的代码组织方式,可以学习下 RxJS。Q & A1.Client Engine SDK 和 Play SDK 有什么不一样?Play SDK 指的是实时对战 SDK,玩家客户端和处在 Client Engine 中的 MasterClient 都要使用这个 SDK 与实时对战服务交互,进而互相传递消息。为了方便大家撰写 Client Engine 中的代码,Client Engine SDK 提供了两方面的功能:对 Play SDK 更进一步的封装,提供了作为 MasterClient 便利的方法:广播、转发消息等。额外提供了 GameManager 及 Game,方便对多个房间进行管理。2.使用 Client Engine 开发游戏逻辑,和在客户端开发游戏逻辑相比,各自有什么优缺点。在一开始的时候有讲到,将代码放到 Client Engine 中会更安全,避免客户端被破解,进而篡改游戏逻辑。可能有的同学认为有一个缺点是需要部署并运维服务端,但 Client Engine 的使用方式十分便捷,全部交给 LeanCloud 来部署运维,自己只需要写游戏逻辑就可以,所以不存在自己部署以及运维困难的问题。3.如今都原生支持异步的情况下,还需要学习 RxJS 吗?RxJS 会将异步及事件组合为一个流式操作,在大型项目上逻辑性会更好,对工程师要求的抽象水平更高,代码也会更加简洁。参考资料中《你的第一个 Client Engine 小游戏》使用的是 Play SDK 事件代码,github 的 repo 中使用了 Client Engine 封装的 RxJS 的方法,建议自己亲自动手写一写代码,会感受到其中的不同。 ...

January 10, 2019 · 4 min · jiezi

tcp没用吗?为什么MOBA、“吃鸡”游戏不推荐用tcp协议

本文由云+社区发表作者:腾讯云游戏行业资深架构师 余国良MOBA类和“吃鸡”游戏为什么对网络延迟要求高?我们知道,不同类型的游戏因为玩法、竞技程度不一样,采用的同步算法不一样,对网络延迟的要求也不一样。例如,MOBA类游戏多使用帧同步为主要同步算法,竞技性也较高,无论从流畅性,还是从公平性要求来说,对响应延迟的要求都最高,根据业内经验,当客户端与服务器的网络延迟超过150ms时,会开始出现卡顿,当延迟超过250ms时,会对玩家操作造成较大影响,游戏无法公平进行。类似地,“吃鸡”游戏(如《绝地求生》)玩法对玩家坐标、动作的同步要求极高,延迟稍大导致的数据不一致对体验都会造成较大影响,其实时性要求接近MOBA类游戏。而对于传统mmorpg来说,多采用状态同步算法,以属性养成和装备获取为关注点,也有一定竞技性,出于对游戏流畅性的要求,对延迟也有一定要求,同步算法的优化程度不一样,这一要求也不一样,一般情况下为保证游戏正常进行,需要响应延迟保持在300ms以下。相比之下,对于炉石传说、斗地主、梦幻西游等回合制游戏来说,同时只有一个玩家在操作双方数据,无数据竞争,且时间粒度较粗,甚至可通过特效掩盖延迟,因此对网络延迟的要求不高,即便延迟达到500ms~1000ms,游戏也能正常进行。这里,我们不对同步算法做进一步说明,重点说一下协议的问题。传输层协议和延迟不同传输层协议在可靠性、流量控制等方面都有差别,而这些技术细节会对延迟造成影响。tcp追求的是完全可靠性和顺序性,丢包后会持续重传直至该包被确认,否则后续包也不会被上层接收,且重传采用指数避让策略,决定重传时间间隔的RTO(retransmission timeout)不可控制,linux内核实现中最低值为200ms,这样的机制会导致丢包率短暂升高的情况下应用层消息响应延迟急剧提高,并不适合实时性高、网络环境复杂的游戏。加速方案基于udp定制传输层协议,引入顺序性和适当程度或者可调节程度的可靠性,修改流控算法。适当放弃重传,如:设置最大重传次数,即使重传失败,也不需要重新建立连接。比较知名的tcp加速开源方案有:quic、enet、kcp、udt。其中,quic是源自google的tcp替代方案,其主要目的是为了整合TCP协议的可靠性和udp协议的速度和效率,其主要特性包括:避免前序包阻塞、减少数据包、向前纠错、会话重启和并行下载等,然而QUIC对标的是TCP+TLS+SPDY,相比其他方案更重,目前国内用于网络游戏较少。kcp的作者是国内优秀开发者,社区也发展良好,kcp的作者和社区开发者对enet、kcp、udt做了性能测试,详情可参见:https://github.com/skywind300…, 从测试情况可以看到,kcp表现不错,其次是enet,表现最差的是udt。不过,这里也提出一个问题,原始enet保留了tcp重传的指数避让特性,每次重传间隔还是乘以2,默认rto也较高,这可能是测试中enet表现不如kcp的主要原因,如果对enet代码稍作调整,结果又当如何?这里,我们先排除传输性能,从其他方面对enet和kcp做一对比(满分5分):我们对libenet略微做一些调整——默认rtt从500ms调整成50ms, 去除超时重传的指数避让策略。Linux下用TC命令模拟网络延迟和丢包率,控制延迟分别为30ms, 50ms, 70ms,控制丢包率分别为1%, 3%, 5%, 7%, 10%,在模拟出的不同网络环境下,对tcp, 原始enet和改进后的enet进行了对比测试。测试中考察两个性能指标:1)平均响应时间;2)响应时间超过300ms的包的比例。libenet的代码调整: 图 1 调整默认RTT为50ms 图 2 取消指数避让tc命令如下:模拟延迟100ms(rtt为200ms): tc qdisc add dev eth0 root netem delay 100ms模拟1%丢包率:tc qdisc add dev eth0 root netem loss 1%对比结果数据如下:图 3 不同丢包率和网络延迟下TCP协议、ENET、优化后ENET的平均响应时间对比图 4 不同丢包率和网络延迟下TCP协议、ENET、优化后ENET的超时响应比例对比从图中可见,在平均响应方面,TCP协议的劣势不明显,在延迟为30ms,丢包率为1%时,改进后的ENET平均RTT为69ms, 原始ENET平均RTT为67ms, TCP平均RTT为67ms;但是从响应时间超过300ms的比例看,在延迟为30ms,丢包率为1%时,改进后的ENET RTT超过300ms的包为0,而TCP RTT超过300ms的比例则超过了2%,如果是在游戏中,这个表现已经能明显影响游戏体验了。结果表明,TCP在网络稍不稳定的情况下就已经有比较大的问题了,改进后的ENET有明显优势。总结测试结果符合预期,在实时性方面,TCP协议的网络抗性欠佳,对MOBA类或其他实时性要求较高的游戏,我们不建议使用TCP作为协议载体。事实上,王者荣耀,乱斗西游的通信协议也确实是基于UDP封装的,别问我是怎么知道的。后话对于开发人员来说,优化协议和同步算法是在已有网络环境下提升用户体验的可用方法,也是较平民化的方法,在网络抖动有限、丢包并不频繁、网络环境不至于太差的情况下,的确能有效提高游戏体验;然而这种方法也存在局限性,在网络环境超出可控范围,如在地铁上、商场里等人潮拥挤、存在网络热点,延迟或丢包率极高的环境中,还是无法解决问题,所谓“巧妇难为无米之炊”,再牛X的协议和算法,也无法点石成金,要从根本上解决问题,最终还是要回到网络质量上。此文已由作者授权腾讯云+社区在各渠道发布获取更多新鲜技术干货,可以关注我们腾讯云技术社区-云加社区官方号及知乎机构号v

January 9, 2019 · 1 min · jiezi

Cocos Creator 教程(1)——第一个游戏:一步两步

第一个游戏这节我们从头做一个比较有意思的小游戏——一步两步。下面是最终效果(跳一步得一分,跳两步得三分,电脑端左右键12步):一步两步写在前面这是本教程第一个游戏,所以我会讲的详细一点,但是也不能避免遗漏,所以有什么问题你可以先尝试查阅文档自己解决或者在下方留言,后面我会跟进完善。另外这个游戏并非原创,参照的是腾讯的微信小游戏《一步两步H5》,请不要直接搬过去,微信里重复的游戏太多了。创建工程选择空白项目创建工程你可以从这里下载游戏素材,然后将素材导入工程(直接拖进编辑器,或者放在工程目录)也可以从https://github.com/potato47/one-two-step下载完整代码进行参照。准备工作做完后,我会把这个游戏制作过程分为若干个小过程,让你体会一下实际的游戏制作体验。从一个场景跳转到另一个场景在res文件夹下新建一个scenes文件夹,然后在scenes里新建两个场景menu和game(右键->新建->Scene)。然后双击menu进入menu场景。在层级管理器中选中Canvas节点,在右侧属性检查器中将其设计分辨率调整为1280x720,然后将background图片拖入Canvas节点下,并为其添加Widget组件(添加组件->UI组件->Widget),使其充满画布。在Canvas下新建一个Label节点(右键->创建节点->创建渲染节点->Label),然后调整文字大小,并添加标题文字我们知道节点和组件通常是一起出现的,带有常见组件的节点在编辑器里可以直接创建,比如刚才的带有Label组件的节点和带有Sprite组件的节点,但是我们也可以新建一个空节点然后为其添加对应的组件来组装一个带有特殊功能的节点。新建节点->UI节点下有一个Button,如果你直接创建Button,你会发现它是一个带有Button组件的节点,并且有一个Label的子节点。现在我们用另一种方法创建Button:在Canvas右键新建一个空节点,然后为其添加Button组件,这时你会发现按钮并没有背景,所以我们再添加一个Sprite组件,拖入资源中的按钮背景图片,最后添加一个Label子节点给按钮添加上文字。下面我们给这个按钮添加点击事件。在资源管理器中新建src文件夹用来存放脚本,然后新建一个TypeScript脚本,名字为Menu(注意脚本组件名称区分大小写,这里建议首字母大写)。双击用VS Code打开脚本,更改如下:const { ccclass } = cc._decorator;@ccclass // 让编辑器能够识别这是一个组件export class Menu extends cc.Component { private onBtnStart() { cc.director.loadScene(‘game’); //加载game场景 }}一个类只有加上@ccclass才能被编辑器识别为脚本组件,如果你去掉@ccclass,你就不能把这个组件拖到节点上。另外可以看到代码中出现了几次cc这个东西,cc其实是Cocos的简称,在游戏中是引擎的主要命名空间,引擎代码中所有的类、函数、属性和常量都在这个命名空间中定义。很明显,我们想在点击开始按钮的时候调用onBtnStart函数,然后跳转到game场景。为了测试效果我们先打开game场景,然后放一个测试文字(将Canvas的设计分辨率也改为1280x720)。保存game场景后再回到Menu场景。Button组件点击后会发出一个事件,这个事件可以跟某个节点上的某个脚本内的某个函数绑定在一起。听着有点绕,动手做一遍就会明白这个机制。首先将Menu脚本添加为Canvas节点的组件,然后在开始按钮的Button组件里添加一个Click Event,将其指向Canvas节点下的Menu脚本里的onBtnStart函数。我们再调整一下Button的点击效果,将Button组件的Transition改为scale(伸缩效果),另外还有颜色变化和图片变化,可以自己尝试。最后点击上方的预览按钮,不出意外的话就可以在浏览器中看见预期效果。组织代码结构现在我们来编写游戏逻辑。首先我来讲一下我看到的一种现象:很多新手非常喜欢问,“看代码我都能看懂啊,但是要我自己写我就没思路啊”这时一位经验颇多的长者就会甩给他一句,“多写写就有思路了“不知道你们发现没有,这竟然是一个死循环。对于一个刚开始学习做游戏的人,首先要了解的是如何组织你的代码,这里我教给大家一个最容易入门的代码结构——单向分权结构(这是我想了足足两分钟的自认为很酷炫的一个名字)脚本分层:这个结构最重要的就是“权”这个字,我们把一个场景中使用的脚本按照“权力”大小给它们分层,权力最大的在最上层且只有一个,这个脚本里保存着它直接控制的若干个脚本的引用,被引用的脚本权力就小一级,被引用的脚本还会引用比它权力更小的脚本,依此类推。脚本互操作:上一层的脚本由于保存着下一层脚本的引用,所以可以直接操作下一层的脚本。下一层的脚本由上一层的脚本初始化,在初始化的时候会传入上一层的引用(可选),这样在需要的时候会反馈给上一层,由上一层执行更具体的操作。同层的脚本尽量不要互相操作,统一交给上层处理,同层解耦。不可避免的同层或跨层脚本操作可以使用全局事件来完成。具有通用功能的脚本抽离出来,任意层的脚本都可以直接使用。写了这么多,但你肯定没看懂,现在你可以翻到最上面再分析一下游戏的game场景,如何组织这个场景的脚本结构?首先,一个场景的根节点会挂载一个脚本,通常以场景名命名,这里就是Game。然后跳跃的人物也对应着一个脚本Player。跟Player同层的还应该有Block也就是人物踩着的地面方块。因为Player和Block之间互相影响并且我想让Game脚本更简洁,所以这里再加一个Stage(舞台)脚本来控制Player和Block。最终它们的层级关系如下:GameStagePlayerBlock上面这些都是我们的思考过程,下面我们落实到场景中。先新建几个脚本现在搭建场景,先添加一个跟menu场景一样的全屏背景然后添加一个空节点Stage,在Stage下添加一个Player节点和一个Block节点在Stage同层添加两个按钮来控制跳一步两步先添加第一个按钮,根据实际效果调整文字大小(font size)颜色(node color)和按钮的缩放倍数(scale)第二个按钮可以直接由第一个按钮复制这两个按钮显然是要放置在屏幕左下角和右下角的,但是不同屏幕大小可能导致这两个按钮的位置跑偏,所以最好的方案是给这两个按钮节点添加Widget组件,让它们跟左下角和右下角保持固定的距离,这里就不演示了,相信你可以自己完成(其实是我忘录了。。。)添加一个Label节点记录分数,系统字体有点丑,这里替换成我们自己的字体最后把脚本挂在对应的节点上。场景搭建到这里基本完成了,现在可以编写脚本了。Game作为一个统领全局的脚本,一定要控制关键的逻辑,,比如开始游戏和结束游戏,增加分数,还有一些全局的事件。Game.tsimport { Stage } from ‘./Stage’;const { ccclass, property } = cc._decorator;@ccclassexport class Game extends cc.Component { @property(Stage) private stage: Stage = null; @property(cc.Label) private scoreLabel: cc.Label = null; private score: number = 0; protected start() { this.startGame(); } public addScore(n: number) { this.score += n; this.scoreLabel.string = this.score + ‘’; } public startGame() { this.score = 0; this.scoreLabel.string = ‘0’; this.stage.init(this); } public overGame() { cc.log(‘game over’); } public restartGame() { cc.director.loadScene(‘game’); } public returnMenu() { cc.director.loadScene(‘menu’); } private onBtnOne() { this.stage.playerJump(1); } private onBtnTwo() { this.stage.playerJump(2); }}Stage作为Game直接控制的脚本,要给Game暴露出操作的接口并且保存Game的引用,当游戏状态发生改变时,通知Game处理。Stage.tsimport { Game } from ‘./Game’;import { Player } from ‘./Player’;const { ccclass, property } = cc._decorator;@ccclassexport class Stage extends cc.Component { @property(Player) private player: Player = null; private game: Game = null; public init(game: Game) { this.game = game; } public playerJump(step: number) { this.player.jump(step); }}而Player作为最底层的一个小员工,别人让你做啥你就做啥。Player.tsconst {ccclass, property} = cc._decorator;@ccclassexport class Player extends cc.Component { public jump(step: number) { if (step === 1) { cc.log(‘我跳了1步’); } else if (step === 2) { cc.log(‘我跳了2步’); } } public die() { cc.log(‘我死了’); }}之前讲了@ccclass是为了让编辑器识别这是一个组件类,可以挂在节点上,现在我们又看到了一个@property,这个是为了让一个组件的属性暴露在编辑器属性中,观察最上面的Game脚本,发现有三个成员变量,stage,scoreLabel和score,而只有前两个变量加上了@property,所以编辑器中只能看到stage和scoreLabel。@property括号里通常要填一个编辑器可以识别的类型,比如系统自带的cc.Label,cc.Node,cc.Sprite,cc.Integer,cc.Float等,也可以是用户脚本类名,比如上面的Stage和Player。回到编辑器,我们把几个脚本暴露在编辑器的变量通过拖拽的方式指向带有类型组件的节点。再把one,two两个按钮分别绑定在game里的onBtnOne,onBtnTwo两个函数上。这时我们已经有了一个简单的逻辑,点击1或2按钮,调用Game里的onBtnOne或onBtnTwo,传递给Stage调用playerJump,再传递给Player调用jump,player就会表现出跳一步还是跳两步的反应。点击预览按钮,进行测试:你可以按F12(windows)或cmd+opt+i(mac)打开chrome的开发者工具。人物跳跃动作现在我们来让Player跳起来,人物动作的实现大概可以借助以下几种方式实现:动画系统动作系统物理系统实时计算可以看到这个游戏人物动作比较简单,跳跃路径是固定的,所以我们选择用动作系统实现人物的跳跃动作。creator自带一套基于节点的动作系统,形式如node.runAction(action)。修改Player.ts,添加几个描述跳跃动作的参数,并且添加一个init函数由上层组件即Stage初始化时调用并传入所需参数。另外更改jump函数内容让Player执行jumpBy动作。Player.ts…private stepDistance: number; // 一步跳跃距离private jumpHeight: number; // 跳跃高度private jumpDuration: number; // 跳跃持续时间public canJump: boolean; // 此时是否能跳跃public init(stepDistance: number, jumpHeight: number, jumpDuration: number) { this.stepDistance = stepDistance; this.jumpHeight = jumpHeight; this.jumpDuration = jumpDuration; this.canJump = true;}public jump(step: number) { this.canJump = false; this.index += step; let jumpAction = cc.jumpBy(this.jumpDuration, cc.v2(step * this.stepDistance, 0), this.jumpHeight, 1); let finishAction = cc.callFunc(() => { this.canJump = true; }); this.node.runAction(cc.sequence(jumpAction, finishAction));}…Stage.ts…@property(cc.Integer)private stepDistance: number = 200;@property(cc.Integer)private jumpHeight: number = 100;@property(cc.Float)private jumpDuration: number = 0.3;@property(Player)private player: Player = null;private game: Game = null;public init(game: Game) { this.game = game; this.player.init(this.stepDistance, this.jumpHeight, this.jumpDuration);}public playerJump(step: number) { if (this.player.canJump) { this.player.jump(step); }}…这里要介绍一下 Cocos Creator 的动作系统,动作系统基于节点,你可以让一个节点执行一个瞬时动作或持续性的动作。比如让一个节点执行一个“3秒钟向右移动100”的动作,就可以这样写let moveAction = cc.moveBy(3, cc.v2(100, 0)); // cc.v2可以创建一个二位的点(向量),代表方向x=100,y=0this.node.runAction(moveAction);更多的动作使用可查询文档 http://docs.cocos.com/creator…回头看Player的jump方法,这里我们的意图是让Player执行一个跳跃动作,当跳跃动作完成时将this.canJump改为true,cc.CallFunc也是一个动作,这个动作可以执行你传入的一个函数。所以上面的finishAction执行的时候就可以将this.canJump改为true,cc.sequence用于将几个动作连接依次执行。可以看到jumpAction传入了很多参数,有些参数可以直接根据名字猜到,有一些可能不知道代表什么意思,这时你就要善于搜索api,另外要充分利用ts提示的功能,你可以直接按住ctrl/cmd+鼠标单击进入定义文件查看说明示例。再来看Stage,可以看到Player初始化的几个参数是由Stage传递的,并且暴露在了编辑器界面,我们可以直接在Stage的属性面板调整参数,来直观的编辑动作效果,这也是Creator编辑器的方便之处。上面的几个参数是我调整过后的,你也可以适当的修改,保存场景后预览效果。动态添加地面和移动场景显而易见,我们不可能提前设置好所有的地面(Block),而是要根据Player跳跃的时机和地点动态添加Block,这就涉及到一个新的知识点——如何用代码创建节点?每一个Block节点都是一样的,对于这样相同的节点可以抽象出一个模板,Creator里管这个模板叫做预制体(Prefab),想要一个新的节点时就可以通过复制Prefab得到。制作一个Prefab很简单,我们先在res目录下新建一个prefabs目录,然后将Block节点直接拖到目录里就可以形成一个Prefab了。你可以双击这个prefab进入其编辑模式,如果之前忘了将Block脚本挂在Block节点上,这里也可以挂在Block的Prefab上。有了Prefab后,我们就可以利用函数cc.instance来创建出一个节点。根据之前讲的组织代码原则,创建Block的职责应该交给他的上级,也就是Stage。之前编写Player代码时设置了一个index变量,用来记录Player跳到了“第几格”,根据游戏逻辑每当Player跳跃动作完成后就要有新的Block出现在前面。修改Stage如下:Stage.tsimport { Game } from ‘./Game’;import { Player } from ‘./Player’;import { Block } from ‘./Block’;const { ccclass, property } = cc._decorator;@ccclassexport class Stage extends cc.Component { @property(cc.Integer) private stepDistance: number = 200; @property(cc.Integer) private jumpHeight: number = 100; @property(cc.Float) private jumpDuration: number = 0.3; @property(Player) private player: Player = null; @property(cc.Prefab) private blockPrefab: cc.Prefab = null; // 编辑器属性引用 private lastBlock = true; // 记录上一次是否添加了Block private lastBlockX = 0; // 记录上一次添加Block的x坐标 private blockList: Array<Block>; // 记录添加的Block列表 private game: Game = null; public init(game: Game) { this.game = game; this.player.init(this.stepDistance, this.jumpHeight, this.jumpDuration); this.blockList = []; this.addBlock(cc.v2(0, 0)); for (let i = 0; i < 5; i++) { this.randomAddBlock(); } } public playerJump(step: number) { if (this.player.canJump) { this.player.jump(step); this.moveStage(step); let isDead = !this.hasBlock(this.player.index); if (isDead) { cc.log(‘die’); this.game.overGame(); } else { this.game.addScore(step === 1 ? 1 : 3); // 跳一步得一分,跳两步的三分 } } } private moveStage(step: number) { let moveAction = cc.moveBy(this.jumpDuration, cc.v2(-this.stepDistance * step, 0)); this.node.runAction(moveAction); for (let i = 0; i < step; i++) { this.randomAddBlock(); } } private randomAddBlock() { if (!this.lastBlock || Math.random() > 0.5) { this.addBlock(cc.v2(this.lastBlockX + this.stepDistance, 0)); } else { this.addBlank(); } this.lastBlockX = this.lastBlockX + this.stepDistance; } private addBlock(position: cc.Vec2) { let blockNode = cc.instantiate(this.blockPrefab); this.node.addChild(blockNode); blockNode.position = position; this.blockList.push(blockNode.getComponent(Block)); this.lastBlock = true; } private addBlank() { this.blockList.push(null); this.lastBlock = false; } private hasBlock(index: number): boolean { return this.blockList[index] !== null; }}首先我们在最上面添加了几个成员变量又来记录Block的相关信息。然后修改了playerJump方法,让player跳跃的同时执行moveStage,moveStage方法里调用了一个moveBy动作,这个动作就是把节点相对移动一段距离,这里要注意的是moveStage动作和player里的jump动作水平移动的距离绝对值和时间都是相等的,player向前跳,stage向后移动,这样两个相反的动作,就会让player始终处于屏幕中的固定位置而不会跳到屏幕外了。再看moveStage方法里会调用randomAddBlock,也就是随机添加block,随机算法要根据游戏规则推理一下:这个游戏的操作分支只有两个:1步或者是2步。所以每2个Block的间隔只能是0步或者1步。因此randomAddBlock里会判断最后一个Block是否为空,如果为空那新添加的一定不能为空。如果不为空则50%的概率随机添加或不添加Block。这样就能得到无限随机的地图了。为了激励玩家多按2步,所以设定跳1步的1分,跳2步得3分。另外Player跳几步randomAddBlock就要调用几次,这样才能保证地图与Player跳跃距离相匹配。再说一下addBlock方法,blockNode是由blockPrefab复制出来的,你必须通过addChild方法把它添加场景中的某个节点下才能让它显示出来,这里的this.node就是Stage节点。为了方便我们把lastBlockX初始值设为0,也就是水平第一个block的横坐标应该等于0,所以我们要回到编辑器调整一下stage,player,block三个节点的位置,让block和player的x都等于0,并且把Block的宽度设为180(一步的距离设为200,为了让两个相邻的Block有一点间距,要适当窄一些),最后不要忘记把BlockPrefab拖入对应的属性上。playerJump的的最后有一段判断游戏结束的逻辑,之前我们在player里设置了一个变量index,记录player当前跳到第几格,stage里也有一个数组变量blockList保存着所有格子的信息,当player跳完后判断一下落地点是否有格子就可以判断游戏是否结束。捋顺上面的逻辑后,你就可以预览一下这个看起来有点样子的游戏了地面下沉效果如果每一步都让玩家想很久,那这个游戏就没有尽头了。现在我们给它加点难度。设置的效果是:地面每隔一段时间就会下落,如果玩家没有及时跳到下一个格子就会跟着地面掉下去,为了实现这个人物和地面同时下坠的效果,我们要让Player和Block执行相同的动作,所以在Stage上新加两个变量fallDuration和fallHeight用来代表下落动作的时间和高度,然后传给Player和Block让它们执行。另外这种小游戏的难度一定是要随着时间增加而增大的,所以Block的下落时间要越来越快。下面我们来修改Block,Player,Stage三个脚本Block.tsconst { ccclass } = cc._decorator;@ccclassexport class Block extends cc.Component { public init(fallDuration: number, fallHeight: number, destroyTime: number, destroyCb: Function) { this.scheduleOnce(() => { let fallAction = cc.moveBy(fallDuration, cc.v2(0, -fallHeight)); // 下沉动作 this.node.runAction(fallAction); destroyCb(); }, destroyTime); }}这里补充了Block的init方法,传入了四个参数,分别是坠落动作的持续时间,坠落动作的高度,销毁时间,销毁的回调函数。scheduleOnce是一个一次性定时函数,存在于cc.Component里,所以你可以在脚本里直接通过this来调用这个函数,这里要实现的效果就是延迟destroyTime时间执行下落动作。Player.tsconst { ccclass } = cc._decorator;@ccclassexport class Player extends cc.Component { private stepDistance: number; // 一步跳跃距离 private jumpHeight: number; // 跳跃高度 private jumpDuration: number; // 跳跃持续时间 private fallDuration: number; // 坠落持续时间 private fallHeight: number; // 坠落高度 public canJump: boolean; // 此时是否能跳跃 public index: number; // 当前跳到第几格 public init(stepDistance: number, jumpHeight: number, jumpDuration: number, fallDuration: number, fallHeight: number) { this.stepDistance = stepDistance; this.jumpHeight = jumpHeight; this.jumpDuration = jumpDuration; this.fallDuration = fallDuration; this.fallHeight = fallHeight; this.canJump = true; this.index = 0; }… public die() { this.canJump = false; let dieAction = cc.moveBy(this.fallDuration, cc.v2(0, -this.fallHeight)); this.node.runAction(dieAction); }}首先将init里多传入两个变量fallDuration和fallHeight用来实现下落动作,然后补充die方法,这里的下落动作其实是个上面的Block里的下落动作是一样的。Stage.ts…@property(cc.Integer)private fallHeight: number = 500;@property(cc.Float)private fallDuration: number = 0.3;@property(cc.Float)private initStayDuration: number = 2; // 初始停留时间@property(cc.Float)private minStayDuration: number = 0.3; // 最小停留时间,不能再快了的那个点,不然玩家就反应不过来了@property(cc.Float)private speed: number = 0.1;private stayDuration: number; // 停留时间…public init(game: Game) { this.game = game; this.stayDuration = this.initStayDuration; this.player.init(this.stepDistance, this.jumpHeight, this.jumpDuration, this.fallDuration, this.fallHeight); this.blockList = []; this.addBlock(cc.v2(0, 0)); for (let i = 0; i < 5; i++) { this.randomAddBlock(); }}public addSpeed() { this.stayDuration -= this.speed; if (this.stayDuration <= this.minStayDuration) { this.stayDuration = this.minStayDuration; } cc.log(this.stayDuration);}public playerJump(step: number) { if (this.player.canJump) { this.player.jump(step); this.moveStage(step); let isDead = !this.hasBlock(this.player.index); if (isDead) { cc.log(‘die’); this.scheduleOnce(() => { // 这时还在空中,要等到落到地面在执行死亡动画 this.player.die(); this.game.overGame(); }, this.jumpDuration); } else { let blockIndex = this.player.index; this.blockList[blockIndex].init(this.fallDuration, this.fallHeight, this.stayDuration, () => { if (this.player.index === blockIndex) { // 如果Block下落时玩家还在上面游戏结束 this.player.die(); this.game.overGame(); } }); this.game.addScore(step === 1 ? 1 : 3); } if (this.player.index % 10 === 0) { this.addSpeed(); } }}…Player和Block下落动作都需要的fallDuration和fallHeight我们提取到Stage里,然后又添加了几个属性来计算Block存留时间。在playerJump方法里,补充了Player跳跃后的逻辑:如果Player跳空了,那么就执行死亡动画也就是下落动作,如果Player跳到Block上,那么这个Block就启动下落计时器,当Block下落时Player还没有跳走,那就和Player一起掉下去。最后增加下落速度的方式是每隔十个格子加速一次。回到编辑器,调整fallDuration,fallHeight,initStayDuration,minStayDuration,speed的值。预览游戏添加结算面板前面讲了这么多,相信你能自己拼出下面这个界面。上面挂载的OverPanel脚本如下:OverPanel.tsimport { Game } from “./Game”;const { ccclass, property } = cc._decorator;@ccclassexport class OverPanel extends cc.Component { @property(cc.Label) private scoreLabel: cc.Label = null; private game: Game; public init(game: Game) { this.game = game; } private onBtnRestart() { this.game.restartGame(); } private onBtnReturnMenu() { this.game.returnMenu(); } public show(score: number) { this.node.active = true; this.scoreLabel.string = score + ‘’; } public hide() { this.node.active = false; }}不要忘了将两个按钮绑定到对应的方法上。最后修改Game,让游戏结束时显示OverPanelGame.tsimport { Stage } from ‘./Stage’;import { OverPanel } from ‘./OverPanel’;const { ccclass, property } = cc._decorator;@ccclassexport class Game extends cc.Component { @property(Stage) private stage: Stage = null; @property(cc.Label) private scoreLabel: cc.Label = null; @property(OverPanel) private overPanel: OverPanel = null; private score: number = 0; protected start() { this.overPanel.init(this); this.overPanel.hide(); this.startGame(); } public addScore(n: number) { this.score += n; this.scoreLabel.string = this.score + ‘’; } public startGame() { this.score = 0; this.scoreLabel.string = ‘0’; this.stage.init(this); } public overGame() { this.overPanel.show(this.score); } public restartGame() { cc.director.loadScene(‘game’); } public returnMenu() { cc.director.loadScene(‘menu’); } private onBtnOne() { this.stage.playerJump(1); } private onBtnTwo() { this.stage.playerJump(2); }}将OverPanel的属性拖上去。为了不影响编辑器界面,你可以将OverPanel节点隐藏预览效果添加声音和键盘操作方式如果你玩过这个游戏,肯定知道声音才是其灵魂。既然是Player发出的声音,就挂在Player身上吧Player.tsconst { ccclass, property } = cc._decorator;@ccclassexport class Player extends cc.Component { @property({ type: cc.AudioClip }) private oneStepAudio: cc.AudioClip = null; @property({ type:cc.AudioClip }) private twoStepAudio: cc.AudioClip = null; @property({ type:cc.AudioClip }) private dieAudio: cc.AudioClip = null; … public jump(step: number) { … if (step === 1) { cc.audioEngine.play(this.oneStepAudio, false, 1); } else if (step === 2) { cc.audioEngine.play(this.twoStepAudio, false, 1); } } public die() { … cc.audioEngine.play(this.dieAudio, false, 1); }}这里你可能比较奇怪的为什么这样写@property({ type: cc.AudioClip})private oneStepAudio: cc.AudioClip = null;而不是这样写@property(cc.AudioClip)private oneStepAudio: cc.AudioClip = null;其实上面的写法才是完整写法,除了type还有displayName等参数可选,当只需要type这个参数时可以写成下面那种简写形式,但例外的是有些类型只能写完整形式,不然就会抱警告,cc.AudioClip就是其一。在电脑上点击两个按钮很难操作,所以我们添加键盘的操作方式。Game.tsimport { Stage } from ‘./Stage’;import { OverPanel } from ‘./OverPanel’;const { ccclass, property } = cc._decorator;@ccclassexport class Game extends cc.Component { … protected start() { … this.addListeners(); } … private addListeners() { cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, (event: cc.Event.EventKeyboard) => { if (event.keyCode === cc.macro.KEY.left) { this.onBtnOne(); } else if (event.keyCode === cc.macro.KEY.right) { this.onBtnTwo(); } }, this); }}在游戏初始化的时候通过cc.systemEvent注册键盘事件,按左方向键跳一步,按右方向键跳两步。至此我们的游戏就做完了。一步两步如果你有基础,这个游戏并不难,如果这是你的第一篇教程,你可能会很吃力,无论前者后者,遇到任何问题都可以在下方留言,我也会随时更新。另外不要忘了加QQ交流群哦 863758586 ...

January 7, 2019 · 6 min · jiezi

Cocos Creator 实战教程(0)——准备

Cocos Creator简介什么的,最没意思了。安装http://www.cocos.com/downloadWindows 安装过程中会询问是否安装 Visual Studio,其作用是编译 Windows 程序,我们暂时以 Web 平台开发为主,所以可以先跳过不安装,当然你非要安装我也不能拿你怎么样。注册账号如果你第一次使用 Cocos Creator,会提示你登录账号。你可以从下面的地址注册 Cocos 开发者账号。https://passport.cocos.com/au…Dashboard空白项目:自己做游戏选择这个。范例集合:官方的一些组件用法参考,有很多文档没有的内容,没事看一下。Hello World:自带一个场景,一个脚本,两张图片,可以用来做测试工程。Hello TypeScript:同上,这个为 TypeScript 脚本。Visual Studio Code如果你有偏爱的编辑器也可以继续使用,但是 VS Code 与Cocos Creator 结合的更好。安装https://code.visualstudio.com/Chrome浏览器通常是我们的调试场景,所以建议统一用Chrome。安装https://www.google.cn/chrome/吃惊地发现下载谷歌浏览器竟然不用翻墙了。。。TypeScript”我能不能用JavaScript啊?““不能。“学习TypeScript如果你没有接触过TS,也不用担心,你只要有一门语言的基础,入门别的语言其实很简单。你可以先看一下官方文档,然后跟着教程做一个游戏,遇到不会的地方搜索提问、搜索,如此循环即可。https://www.tslang.cn/docs/ho…快速预览混个脸熟。首先选择Hello TypeScript,新建一个工程。不出意外的话你就会看到这个界面序号名称功能备注1层级管理器显示场景中的节点层级关系-2场景编辑器预览场景效果-3控件库一些常用的可视化控件个人来讲基本不用,我会把这个面板隐藏掉4资源管理器存储游戏资源-5控制台输出系统和游戏信息-6属性检查器显示节点属性-当然你可以随意调整各个面板的位置,或者隐藏掉。关于资源管理器你可能还需要知道:Scene文件夹下的helloworld是一个场景文件,里面包含着一个游戏场景的相关信息,你可以双击打开它,进入对应的场景编辑界面。Script文件夹下Helloworld是一个脚本文件,里面包含着游戏逻辑,脚本通常会挂在节点上。Texture文件夹下存放着两张图片叫做贴图资源,你可以直接将其拖入场景编辑器或层级管理器使其变为场景中的一个带有Sprite组件的节点。简单介绍一下场景(Scene)、节点(Node)、组件(Component)的关系:学到后面你会发现游戏开发里的很多概念跟拍电影有些类似,游戏的场景可以简单的类比电影里的场景,场景里有角色有背景和一些“剧本”,还有对其拍摄的摄像机。节点可以简单的理解为游戏中的物体载体,这个载体有位置有大小等基本信息,可能是玩家控制的角色,可能是天空中飘着的一段云,也可能是可以点击的一个按钮。组件是游戏中最重要的一个概念,组件是赋予节点特殊能力的一个,额,一个东东。。。比如你可以在一个节点上添加Sprite组件使其显示一张图片,添加Label组件使其显示文字,添加Collider组件使其具有物理碰撞功能,还可以添加你自己写的用户脚本组件,使其具有特定的功能。下面双击helloworld场景将其打开,你就会看到一个编辑好的场景点击顶部的三角形播放按钮,即可在浏览器中看到游戏场景。你可以在1处调整预览的设备型号,在2处调整设备方向。现在再回过头来看一下场景的节点树结构。从上向下(你可以点击对应节点,在右边属性检查器查看节点属性)CanvasCanvas是每个场景的默认根节点,你不能删除,也不能移动,它在游戏运行时会根据你设定的屏幕分辨率和适配方式自动调整大小。可以看到Node下挂载的第一个组件就是Canvas组件,你可以在这里调整设计分辨率以及适配方式。Canvas下面还有一个Helloworld组件,这个其实是我们自己写的组件,对应着左边的Helloworld脚本,里面的脚步逻辑我们回头再看。Main CameraMain Camera也是每个场景都会有的,其作用是控制场景如何显示的。现阶段不用去修改它,后面我们会专门用一章来讲Camera。background先看background下面的Sprite组件,可以看到Sprite里有一个Sprite Frame属性,你可以点击它,会发现它指向的是左边资源管理器里一张白色图片。可以看出Sprite组件就是用来让节点显示图片的。再看上面的Widget组件,应该很明显可以看出它是用来对其四边的,上下左右都是0,那么就可以让这个节点铺满屏幕。你可能又发现了这个背景在场景中显示的不是白色,颜色其实是在Node属性下设置的。这里可以看出游戏中的一个物体其实是由节点和组件共同影响的。cocos跟background一样是一个可以显示图片的节点(场景中间的Cocos图标),没有Widget组件,就不会有对齐效果,你可以任意调整其位置。label这个也很明显就是一个可以显示文字的节点,你可以修改Label组件下的String属性里的值来改变其显示的文字。最后我们在回过头来看Canvas上的Helloworld组件,选中资源管理器的Helloworld脚本文件,可以在属性检查器里看到脚本内容。可以看到里面声明了两个属性:一个是label,其类型是cc.Label,label指向的就是场景中的label节点。另一个是text,其类型是string,并且默认值是‘hello’,你也可以在属性面板修改它的值。然后在start函数里将label的string改为text的值(start函数会在所有节点加载完成后自动执行)。现在我们尝试一下修改脚本里的内容,但是打开脚本之前还有几个前提操作。将下图几个选项一次点一遍。然后就可以双击脚本用 VS Code 打开了(Windows 系统默认会打开文件夹,但是 Mac 系统默认只会打开一个文件,暂时我还没找到解决办法,我通常会先打开 VS Code 然后选择工程文件夹再打开)。打开脚本后修改在start里的内容如下:start () { // init logic this.label.string = this.text; this.label.node.color = cc.Color.RED;}然后选中Canvas节点并且在右边的属性面板里更改text的值点击上方三角形运行按钮,即可看到下面效果最后补充几点常用操作操作步骤新建场景在资源管理器里右键选择新建->Scene新建节点在层级管理器右键创建节点,如果是带有图片的节点可以直接讲图片拖入场景或层级管理器中添加组件选中节点并在属性面板的最下方选择添加组件,或者直接讲用户脚本拖入属性面板脚本属性绑定将其对应类型的节点或带有组件的节点或资源拖入帮助在学习的这条道路上,一定 不孤单 是非常孤单的,首先你要学会自己寻找解决方法,途径通常有以下几种官方文档http://docs.cocos.com/creator…当你比较生疏的名词或想深入了解的概念,首先应该想到的是去文档里搜索查看一下。官方APIhttp://docs.cocos.com/creator…查找某个变量的含义,或某个函数的用法。官方论坛http://forum.cocos.com/当你自己真的解决不了的问题时,你可以去论坛发帖寻求帮助。因为你遇到的问题可能别人早就遇到过,所以发帖前一定要先搜索一下是否有类似的帖子,解决时间就是节约生命。另外,多逛论坛也是一种学习的方式。找个组织这是我建的一个QQ群,供新手学习交流863758586

January 7, 2019 · 1 min · jiezi

使用Laya引擎开发微信小游戏(下)

本文由云+社区发表6. 动画6.1 创建伞兵对象在src目录下创建一个新目录role,用来存放游戏中角色。 在role里创建一个伞兵Soldier.ts对象文件。module role{ export class Soldier extends Laya.Sprite{ constructor(){ super(); this.init(); } init():void{ var img:Laya.Sprite = new Laya.Sprite(); img.graphics.drawTexture(Laya.loader.getRes(“demo/soldier.png”),0,0,100,86); this.addChild(img); } }}修改GamePage.ts,把伞兵加入到游戏主画面中去,重点看renderSoldier()module view{ export class GamePage extends ui.GamePageUI{ private soldier:role.Soldier; constructor(){ super(); this.init(); } init():void{ this.renderSoldier(); } renderSoldier():void{ this.soldier= new role.Soldier(); this.addChild(this.soldier); } }}运行起来看下,发现游戏主画面上,已经多了一个伞兵(请忽略我的很烂的抠图,手动捂脸^~ )6.2 让伞兵掉下来做过前端的应该都明白,伞兵掉下来,就是要启动一个定时器,不断修改伞兵的Y坐标+1,移动伞兵图片的位置。原理都知道,但是如何实现呢? 一般定时器有两种:setInterval:基于用户指定时间requestAnimationFrame :基于浏览器帧能力相比起来,requestAnimationFrame 性能更高,更适合做动画。但是在游戏里会有很多地方都用到定时器,如何管理那么多定时器,是非常让人头疼的事情。所以Laya也提供了自己的定时器的相关实现:Laya.timer 来简化定时器的使用,这个定时器同样是基于帧率的,我们来看看这个怎么用。修改GamePage如下,重点看Laya.timer.frameLoopmodule view{ export class GamePage extends ui.GamePageUI{ private soldier:role.Soldier; constructor(){ super(); this.init(); } init():void{ this.renderSoldier(); //创建定时器 Laya.timer.frameLoop(1,this,this.onLoop); } renderSoldier():void{ this.soldier= new role.Soldier(); this.addChild(this.soldier); } onLoop():void{ //让伞兵45度下降 this.soldier.y=this.soldier.y+1; this.soldier.x=this.soldier.x+1; } }}来看下效果,看起来还不错7. 碰撞7.1 增加炮弹下一步,就改是大炮打伞兵了,当然首先得给大炮创建一个炮弹。 Ball.tsmodule role{ export class Ball extends Laya.Sprite{ constructor(){ super(); this.init(); } init():void{ var img:Laya.Sprite = new Laya.Sprite(); img.graphics.drawTexture(Laya.loader.getRes(“demo/ball.png”),0,0,45,54); this.addChild(img); } }}在GamePage上添加炮弹renderBall():void{ this.ball= new role.Ball(); this.ball.pos(162,540); this.addChild(this.ball); }嗯,炮弹添加成功,不过,貌似有点问题,怎么炮弹显示层级在大炮上面了?似乎有点难看?7.2 调整Sprite层级还记得前端世界里神奇的z-index吗? Laya也有,叫zOrder。调整zOrder的数值,可以调节Sprite的层次(脱了马甲,我一样认识你,^^) 把渲染炮弹部分改一下层级:renderBall():void{ this.ball= new role.Ball(); this.ball.pos(162,540); this.pao.zOrder=10; //调高原先大炮的显示层级 this.addChild(this.ball); }这次炮弹躲在大炮后面去了,一会儿再让他出来吧!7.3 点击大炮发射炮弹事件炮弹向上飞,就和伞兵向下掉一样,在帧循环里不断修改y值就可以。但是这次,我们要响应事件了,必须点击大炮,触发点击事件后,才发射炮弹。再次修改GamePage.ts,这次的重点是多了 this.pao.on(Laya.Event.MOUSE_DOWN,this,this.onMouseDown); 这个事件监听module view{ export class GamePage extends ui.GamePageUI{ private soldier:role.Soldier; private ball:role.Ball; private isSendBall:boolean=false; constructor(){ super(); this.init(); } init():void{ this.renderSoldier(); this.renderBall(); //给大炮增加事件监听 this.pao.on(Laya.Event.MOUSE_DOWN,this,this.onMouseDown); //创建定时器 Laya.timer.frameLoop(1,this,this.onLoop); } renderSoldier():void{ this.soldier= new role.Soldier(); this.addChild(this.soldier); } renderBall():void{ his.ball= new role.Ball(); this.ball.pos(162,540); this.pao.zOrder=10; this.addChild(this.ball); } onMouseDown():void{ this.isSendBall=true; } onLoop():void{ //让伞兵45度下降 this.soldier.y=this.soldier.y+1; this.soldier.x=this.soldier.x+1; //如果是发射炮弹状态,炮弹向上发射 if (this.isSendBall){ this.ball.y=this.ball.y-3; } } }}在运行一下看看: 到目前为止,还进行得不错,就差击落伞兵了,可怜的伞兵,你的死期就要到了,还差一个碰撞了。7.4 炮弹与伞兵的碰撞碰撞算法常见的有以下这些:矩形碰撞:矩形图片接触碰撞,计算性能最快,但是如果图像并不近似矩形的时候,准确度就不高了。圆形碰撞:和矩形类似,比如炮弹就是圆的,用圆形检测,更适合真实情况。多矩形碰撞:如果图像相对比较复杂,可以拆分为多个矩形,在准确性和性能方面取得平衡。像素检测碰撞:如果需要非常精确的碰撞,就要使用像素检测了,这个性能相对就比较低了。在Laya里,对于矩形碰撞检测,提供了Rectangle.intersection()方法,可以非常方便的进行矩形检测。继续修改GamePage.tsgameOver():void{ Laya.timer.clear(this,this.onLoop); //停止游戏帧定时器 this.renderBoom(); //显示爆炸图片 this.removeChild(this.soldier); //删除伞兵 this.removeChild(this.ball); //删除炮弹}onLoop():void{ //让伞兵45度下降 this.soldier.y=this.soldier.y+1; this.soldier.x=this.soldier.x+1; //如果是发射炮弹状态,这炮弹向上发射 if (this.isSendBall){ this.ball.y=this.ball.y-3; //使用矩形碰撞判断,如果炮弹和伞兵碰撞,则游戏结束 if (this.ball.getBounds().intersection(this.soldier.getBounds())){ this.gameOver(); } }}再来看下效果: Boom,伞兵成功被大炮打中,“绝地求死”完美收工!8. Laya的性能优化8.1 性能监测工具Laya已经内置了性能监测工具,只要初始化后执行Laya.Stat.show();就可以打开constructor() { //TS或JS版本初始化微信小游戏的适配 Laya.MiniAdpter.init(true,false); //初始化布局大小 Laya.init(375,667, WebGL); //布局方式设定 Laya.stage.scaleMode = Laya.Stage.SCALE_SHOWALL; Laya.stage.screenMode = Laya.Stage.SCREEN_VERTICAL; Laya.stage.alignV = Laya.Stage.ALIGN_CENTER; Laya.stage.alignH = Laya.Stage.ALIGN_CENTER; //打开性能监测面板 Laya.Stat.show(); }上面清楚的显示了目前的FPS、Sprite的数量、DrawCall 、内存消耗等,我们优化的目标就是把这些值降低下来。8.2 优化手段减少Sprite的数量不可见区域的Sprite及时移除静态内容使用cacheAs=bitmap降低DrawCall使用Laya.Pool管理对象,减少重复创建的性能消耗对象无用时,及时销毁定时器及时销毁。。。具体的优化手段有很多,大家可以在具体的业务开发中不断的总结提炼。9. 发布到微信小游戏讲了那么多的Laya,说好的微信小游戏呢? 不要急,这就来了,Laya生成的代码,可以非常方便的发布到微信小游戏。点击 进入发布界面,在发布平台选择“微信小游戏”,此时生成可以在微信开发者工具下运行的release/wxgame版本使用微信开发者工具打开,已经可以完美运行了。而且我们发现laya把我们刚才写的代码,和Laya的核心库一起,都被打包成一个code.js了。[ 微信开发者工具 ]10. 开发环境兼容可是,作为微信环境下的游戏,因为code.js是laya自动生成的,我们开发还是必须在laya的开发环境下,但是laya并不支持微信的接口调试,那我们可以在Laya里判断开发环境吗?当然可以,用Laya.Browser.onWeiXin 就可以判断了,比如: if (Laya.Browser.onWeiXin) { let wx=Laya.Browser.window.wx; //执行微信的API逻辑…..}只是调试起来就有点蛋疼了,得Laya里写好,发布到release/wxgame,再在微信开发者工具里调试。=总结=总体来说,Laya入门还是比较简单的,虽然官方也做了很多文档,也有做视频教程,但是感觉资料还是有点缺,这次自己研究Laya的历程分享出来,也算是为Laya社区做点贡献吧!因为本人接触Laya的时间并不长,也不是专业的游戏开发人员,如果有讲得不对的,也欢迎及时指出,欢迎大家一起交流。此文已由作者授权腾讯云+社区发布搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包! ...

December 11, 2018 · 2 min · jiezi

使用Laya引擎开发微信小游戏(上)

本文由云+社区发表使用一个简单的游戏开发示例,由浅入深,介绍了如何用Laya引擎开发微信小游戏。作者:马晓东,腾讯前端高级工程师。微信小游戏的推出也快一年时间了,在IEG的游戏运营活动中,也出现了越来越多的以小游戏作为载体运营的活动类型,比如游戏预约,抢先试完等等,都收到了非常良好的效果。在支持微信小游戏的游戏引擎中,Cocos,Egret,Laya都对小游戏的开发提供了很多强大的支持。前段时间正好抽空研究了一下这块的内容,现做一个总结,针对如何使用Laya引擎开发微信小游戏给大家做一下介绍。因为时间有限,研究并不深入, 如有高手路过,忘不吝赐教。做个啥游戏呢?“绝地求生”很火,我们做个“绝地求死”如何?策划也很简单,和绝地求生相反,主角不是跳伞的玩家,而是地面的炮手,大炮要把跳伞的伞兵用大炮一个个都消灭掉。牛逼的策划有了,咱们进入正题,看看怎么实现吧!1. 如果不用引擎会怎样?1.1 Canvas了解下微信小游戏提供了canvas这个游戏核心组件。利用Canvas可以在画布上画出文字、图形、图像等等。 不过讲微信小游戏之前,得先说说H5,在H5时代获取canvas对象非常简单,如下图:var canvas=document.getElementById(“myCanvas”);var ctx=canvas.getContext(“2d”);常用的一些API:ctx.drawImage(img,sx,sy,swidth,sheight,x,y,width,height); //绘制图片ctx.fillText(text,x,y,maxWidth); //绘制文字ctx.rect(x,y,width,height); //绘制矩形ctx.clearRect(x,y,width,height);//清除矩形内像素ctx.scale(scalewidth,scaleheight);//缩放ctx.rotate(angle);//旋转角度。。。。微信小游戏里,也提供了canvas对象,只不过获取接口变了:wx.createCanvas()其他H5环境下有的Canvas API,微信环境里也都有。1.2 动画的原理Canvas只是一个2D的画布,要做一个游戏,动画总不能少吧?要让图片能动起来,这又是怎么做到的呢?请看下图:好吧,动画其实就是不断画图片,然后擦除,再画图片,再擦除的循环过程,肉眼看起来,那就是动起来了。在古老的电影胶片时代,我们看到的电影,就是一张一张连续帧的胶片组成的,最后投射到大屏幕上,变成了我们看到的电影。1.3 动画性能优化但是,动画是讲究帧率的,一般如果能达到每秒60帧,那就和电影一样是很流畅的动画效果了。计算公式:1000ms/60fps=16.67ms,这就要求我们每次动画里的业务逻辑计算,都要16.6ms里完成,不能影响下一帧的显示,否则就是卡顿,也就被人说这个游戏好卡,性能好差了。知道原理了,性能优化具体怎么做呢?Canvas分层 有些游戏中,背景是不变的,为了提高性能,可以把游戏背景抽离出一个单独的canvas,这样,在画面发生变化的时候,不需要重绘整个背景,只需要绘制变化的那部分就可以。减少API调用 每次的ctx的api调用,都是有性能消耗的,所以,尽量减少每帧的api调用次数,具体怎么减少,就要看业务需求了。图片预裁剪 图片的裁剪过程,也是有性能消耗的,我们可以把裁剪的图片预先存起来,之后在绘制的时候,直接从内存里拿,而不需要每次都重新裁剪。离屏绘制 直接操作上屏的canvas,性能是很差的,尤其是有单帧绘制操作很多的时候,性能下降更明显。 这个时候,我们可以预先创建一个离屏的canvas,预先在这个canvas完成这一帧要绘制的所有动作,最后一次性的把这个离屏canvas绘制到上屏canvas中。避免阻塞 由于我们需要保证16.67ms就要完成一次帧的绘制,如果这一帧里,逻辑运算时间超过16ms怎么办?那就一定会卡帧了。 我们可以使用webworker之类的技术,把耗时的逻辑计算在另一个线程执行,或者把任务进行拆解,降低每帧的耗时。当然还有很多其他更多的技巧和手段来提升canvas的性能,在这样的情况下如果我们直接使用canvas去开发一个游戏,还会面临比如碰撞算法、物理系统之类的问题。 所以,如果只用canvas去开发游戏,就如同你在吃鸡游戏里,只拿了一把平底锅,你怎么和别人正面刚?所以,我们需要一把98K把自己武装起来,那就是使用游戏引擎开发。2. 为什么选择Laya?目前支持微信小游戏的引擎,有Cocos,Egret,Laya,我们先看下三者的功能比较: 从各种支持度上来讲,laya是目前支持度最好的,也据laya侧的宣传,他的性能也是最高的。(关于性能的问题,因外部水军比较多,在没有做实际详细测试前,暂时不发表评价。)在公司内部,都有三种引擎的游戏实现,下面是截止5月份的公开数据的引擎占比:其实三个引擎都提供了很好的支持度,一般来说,如果原先使用过Cocos实现过APP端游戏要移植到微信小游戏端来的,使用Cocos是最好的选择,如果是从头开发一款小游戏,那还是在Egret和Laya里选择一款吧!3. Laya 环境搭建前面讲了那么多,都还只是前戏,只是为了大家对游戏的开发有个初步的了解,从这一节开始我们就进入正题了。到 https://www.layabox.com/ 去下载最新的版本,并进行安装。目前有1.X版本和2.0版本。(本文使用1.7.20版本做示例)然后就可以创建一个新的游戏项目了,我们可以现在选择创建一个UI示例项目[ 创建新工程 ]3.1 代码模式当然就是给你写代码的地方,感觉这个编辑器,就是在VSCode的基础上改的。连最顶上的Code标识都还在。也因为这样,所以才能很好的支持TypeScript。[ 代码模式布局 ]为什么要使用TypeScript? 本文不详细展开比较,只需要了解TypeScript 是Javascript的超集,因为多了个“Type”表示他支持强类型,并且由于静态类型化,在写代码的时候编辑器就能提示你的错误,所以更适合开发游戏这种逻辑复杂的应用就好了。当然最终TypeScript还是会像ES6一样,被编译成普通的Javascript执行。但是在开发阶段管理代码来说,已经可以驾驭大型项目了。3.2 设计模式就是用来设计UI界面的地方,拖拖拽拽就可以把游戏页面整出来。Laya提供了好多组件,如果有需要的可以使用,当然也可以不用他的组件,自己搞自己的自定义组件。 [ 设计模式布局 ]4. Laya的HelloWorld都说作为一个程序员,买来文房四宝之后,写下的第一行字,一定是“Hello World”。(我拿着公司刚发的 20周年LAMY纪念钢笔,写的第一行字,居然也是“Hello World”,汗~~~)4.1 游戏初始化4.1.1.GameMain.ts首先删掉系统刚才默认的文件“LayaUISample.ts”,然后新建文件GameMain.tsimport WebGL = Laya.WebGL;class GameMain { constructor() { //TS或JS版本初始化微信小游戏的适配 Laya.MiniAdpter.init(true,false); //初始化布局大小 Laya.init(375,667, WebGL); //布局方式设定 Laya.stage.scaleMode = Laya.Stage.SCALE_SHOWALL; Laya.stage.screenMode = Laya.Stage.SCREEN_VERTICAL; Laya.stage.alignV = Laya.Stage.ALIGN_CENTER; Laya.stage.alignH = Laya.Stage.ALIGN_CENTER; }}new GameMain();Laya.MiniAdpter.init()是Laya提供的对小游戏提供的适配,因为在小程序&小游戏环境下,并没有Bom和DomAPI,比如,没有window,document, 所以需要这样一个适配器,对小游戏的开发方式,进行兼容。4.1.2. bin/index.html修改bin目录下的index.html ,删掉LayaUISample.ts的引用,改为下面的方式:<!–启动类添加到这里–><!–jsfile–Main–><script src=“js/GameMain.js”></script><!–jsfile–Main–>在index.html里,提供了很多Laya的类库,这些类库,最终会被打包成合并一个code.js. 因为微信小游戏的体积限制,我们不需要把所有的库都加载进来,只选择我们需要的库就好了,用不到的可以都删除。4.1.3. run接下来,点击运行,就会出现模拟器界面了。 [ 运行模拟器 ]先别管黑乎乎的一团,下面我们就要增加“Hello World”了。4.2 绘制文字4.2.1. Laya.Text再次修改GameMain的代码如下,重点是var txt:Laya.Text = new Laya.Text();import WebGL = Laya.WebGL;class GameMain { constructor() { //TS或JS版本初始化微信小游戏的适配 Laya.MiniAdpter.init(true,false); //初始化布局大小 Laya.init(375,667, WebGL); //布局方式设定 Laya.stage.scaleMode = Laya.Stage.SCALE_SHOWALL; Laya.stage.screenMode = Laya.Stage.SCREEN_VERTICAL; Laya.stage.alignV = Laya.Stage.ALIGN_CENTER; Laya.stage.alignH = Laya.Stage.ALIGN_CENTER; //创建Text对象 var txt:Laya.Text = new Laya.Text(); //给Text的属性赋值 txt.text = “Hello World”;//设定文字内容 txt.color = “#ffffff”; //设定颜色 txt.fontSize=20; //设定字体大小 txt.pos(100,200); //设定位置 //将Text对象添加到舞台 Laya.stage.addChild(txt); }}new GameMain();在上面的代码中,我们给Stage舞台上,添加了Text对象,然后点击运行啊哦,传说中的HelloWorld终于出现了4.3 绘制图片4.3.1 loadImageLaya的Sprite提供了一个非常简单的loadImage方法,可以即时加载图片并加载到舞台上。//设置舞台背景色 Laya.stage.bgColor="#1e83e8";//创建img Sprite精灵var img:Laya.Sprite = new Laya.Sprite();//加载显示图片,坐标位于100,50,并设置宽高 130*108img.loadImage(“demo/paratrooper.jpg”,100,50,130,108);//把图片添加到舞台Laya.stage.addChild(img);预览如下,是不是很简单?但是这个方法,其实并不实用,在真实项目中,一般会有很多图片,我们不会一张一张图片的去加载,而是预先加载好,再去显示图片。也就是我们常常在游戏主界面看到的进度条,其实就是在加载资源。4.3.2 资源预加载Laya提供一个资源加载器:Laya.loader ,来解决加载的问题。我们把上面的代码再修改下,实现先加载完图片,然后再绘制图片。private imgPath1:string=“demo/paratrooper.jpg”;private imgPath2:string=“demo/shell.jpg”;constructor() { //…..省略N行代码 this.renderImage(); //….省略N行代码}renderImage():void{ //定义图片路径集合 var resArray=[ {url:this.imgPath1,type:Laya.Loader.IMAGE}, {url:this.imgPath2,type:Laya.Loader.IMAGE} ]//使用加载器加载图片路径Laya.loader.load(resArray,Laya.Handler.create(this,this.onLoadComplete),Laya.Handler.create(this,this.onLoadProgress))}//加载完成后,把图片绘制到画布上onLoadComplete():void{ console.log(“加载完成”); var img1:Laya.Sprite = new Laya.Sprite(); img1.graphics.drawTexture(Laya.loader.getRes(this.imgPath1),100,50,100,100); Laya.stage.addChild(img1); var img2:Laya.Sprite = new Laya.Sprite(); img2.graphics.drawTexture(Laya.loader.getRes(this.imgPath2),100,300,100,100); Laya.stage.addChild(img2); }//这里可以获取到加载的进度,以后可以制作进度条onLoadProgress(percent:number):void{ console.log(“percent->"+percent);}4.3.3 图集只是预加载图片还不够,实际场景由于有很多小图片,所以我们可以把这些小图片拼合成图集,这就类似在前端在做性能优化的有时候所使用的css sprite精灵图,这样制作成图集,不但加载性能更高,而且也更便于制作帧动画。图集的加载类似这样:var resArray=[ {url:“res/atlas/demo.atlas”,type:Laya.Loader.ATLAS}, ] Laya.loader.load(resArray,Laya.Handler.create(this,this.onLoadComplete),Laya.Handler.create(this,this.onLoadProgress))和之前的图片加载时Laya.Loader.IMAGE不同的是,type变成了Laya.Loader.ATLAS。那图集怎么制作呢?还有,大量的游戏界面,真的就靠手动一张图片一张图片的显示吗? 当然不!因为我们接下来该了解下UI编辑器了。5. UI编辑器UI编辑器,当然是用来编辑UI的,大多数的客户端程序开发环境,都有类似的UI编辑器。点击左侧的图标,进入UI编辑器模式,如下图:具体UI编辑器的功能介绍,建议还是看官方文档,这里就不赘述了。 5.1创建UI 因为我们创建的是默认UI项目,所以UI编辑器里,有一个TestPage.ui,可以不用管他,我们创建一个自己的UI。 点击 文件->新建文件进入新建页面窗口,页面类型有View 和Dialog两种,因为这里我们做的是整个页面,所以选View。如果你有兴趣去看源码,其实Dialog也是基于View实现的,只不过多了Dialog的一些特性。如果对这个view后面还有逻辑代码要写,建议勾选“创建逻辑类”,这样就会自动在View目录下自动创建一个和UI对应的GamePage.ts[ 新建页面UI ]5.2 导入资源在assets目录下,新建一个demo资源目录,把需要的图片都扔进去,然后在UI编辑器的资源面板最下方找找到刷新按钮,新增资源图片后,一定要记得点下刷新,否则资源面板的内容不会自动刷新。只要是demo文件下的图片,都会被自动打包成图集,路径就是 res/atlas/demo.atlas。 不知道有没有同学发现,在上面的图片中,有部分资源显示“不打包”,这是什么原因的? 点击文件-》项目设置,我们会看到图集限制了能被打入图集的单图的最大宽高,和最终图集的最大宽高,默认标准可以自行修改。超过这个图集标准的图片,就不会打包到图集中去,就需要手动加载了。 [ 请在这里填写图片描述 ]5.3 编辑UI编辑页面功能,会用ppt的,应该都会用了,拖个图片谁不会?直接把资源管理器的图片,拖到右侧场景编辑器里。这次我们拖了一个蓝天白云的背景,并在最下方放了一个大炮,看起来还有点意思。 顶部有一排图标,是用来协助对齐图片用的,提供了顶部对齐,底部对齐,左对齐,右对齐,中线对齐等等,如果图片很多,用这个对齐就很方便了。 右侧的属性栏,就比较常用了。 var这里,你可以给你拖进来的图片组件,给个变量名,这个变量名,最后会在之前自动生成的逻辑类里用到。我们把大炮定个变量名“pao”,后面会用到;x,y,width,height这里,就是坐标和宽高,就不用多说了吧?5.4 导出UIUI做好以后,有个重要的工作,就是千万别忘记导出。很多初学者,经常会忘记这点。导出UI,才会重新生成图集和UI相关设置。导出以后,我们看laya/pages/GamePage.ui 文件,不用管里面的详细内容,里面就是刚才我们拖拽图片,自动生成的响应配置文件。5.5 使用UI下面我们要把刚才编辑的GamePage显示出来,那就回过头来,再次修改GameMain.tsclass GameMain { //定义静态变量 gamePageView public static gamePageView:view.GamePage; constructor() { //… this.renderImage(); //… } renderImage():void{ //资源加载 var resArray=[ {url:“res/atlas/demo.atlas”,type:Laya.Loader.ATLAS}, ] Laya.loader.load(resArray,Laya.Handler.create(this,this.onLoadComplete),Laya.Handler.create(this,this.onLoadProgress)) } onLoadComplete():void{ //初始化view GameMain.gamePageView = new view.GamePage(); //添加到舞台 Laya.stage.addChild(GameMain.gamePageView); }}new GameMain();运行一下,主界面游戏背景,和大炮都已经架设好了,好的开端,就是成功的一半了。 接下来,根据最初的牛逼策划,我们要像pubgm一样,让伞兵从天下掉下来,怎么实现?接着看动画部分吧!关注云+社区,及时获取下篇更新 ...

December 10, 2018 · 2 min · jiezi

腾讯云 Game-Tech 技术沙龙小游戏专场“空降”长沙

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~本文由腾讯游戏云发表于云+社区专栏小游戏作为今年快速成长的新生态,在开放进入市场之后持续成为行业热点,获得了游戏开发商的高度关注与参与。在阿拉丁统计平台最新公布的2018年8月小程序 Top100榜单中,有超过40%的小程序为小游戏,面对大量开发技术需求,腾讯游戏云针对小游戏开发者最为关注的技术问题和未来的发展趋势,将于2018年10月18日在长沙为“游戏湘军”带来Game-Tech 技术沙龙小游戏专场。本次长沙站小游戏专场,腾讯云Game-Tech技术沙龙不仅汇聚了腾讯云资深专家为开发者进行技术解读,来自知名的游戏引擎Layabox和专注于微信小程序生态服务的阿拉丁小程序统计平台的大咖们也将来到现场为从业者带来小游戏的开发技术分享。届时来自三方的资深技术专家将从小程序新技术&大商业、如何快速开发小游戏、用LayaAir 2.0高效开发微信小游戏、重度小游戏架构经验分享、H5游戏语音解决方案等方面进行深度探讨。另外,本次活动也得到了草花互动及七米文化的大力支持。小程序新技术&大商业根据阿拉丁报告显示,截至2018年1月至8月,微信小程序开发者数量从100万上升至150万,小程序用户平均每月打开小程序次数从4.01次上升至5.98次,无论是开发端还是用户端,今年小程序的增长都颇为显著。阿拉丁小程序统计平台创始人&CEO史文禄将围绕目前小程序行业发展状况、优秀小程序案例及阿拉丁指数榜单,展望小程序未来变化,为行业从业者带来深度观察。如何快速开发小游戏?——小程序·云开发解决方案微信小程序开发平台上月推出了全新的能力——小程序·云开发。腾讯云产品经理黄赞志本次将就此全新推出的能力,分享介绍云开发模式及其优势,以及如何在小游戏项目中使用云开发能力。“小程序·云开发”是由微信小程序团队及腾讯云云开发团队联合推出的功能,为开发者提供了完整的云端支持,开发者无需搭建服务器,通过小程序官方提供的 API ,即可进行核心业务开发,实现快速上线和迭代。用LayaAir 2.0高效开发微信小游戏Layabox合伙人李明将从小游戏开发入门介绍开始切入,结合LayaAir2.0的新特性,例如可视化物理系统、组件化、场景管理等功能,以及用前端的开发模式开发联网游戏等,再针对小游戏分包、物理缓存、开放域等开发中常见的问题,全面讲解用LayaAir 2.0引擎高效快速的开发微信小游戏产品。重度小游戏架构经验分享小游戏的出现吸引了无数的开发者加入,短短时间内成为了游戏行业的又一新的风口。腾讯云高级解决方案架构师陶为将从小游戏的特点讲起,向开发者全面讲解如何从容应对因社交传播导致小游戏瞬间爆发所带来的运维困境、以及腾讯云为小游戏开发者推出的扶持方案等内容。H5游戏语音解决方案随着小游戏市场规模不断扩大,自2018年以来用户群体日益递增,其社交需求也正逐渐提升,实现小游戏语音互通成为当下游戏开发商的迫切需求。为适应小游戏社交新形态,并增加客户黏性,语音能力支持将是一个不得不解决的问题。腾讯云GME高级工程师白兴师将从如何设计小游戏社交新形态,提升用户粘性;如何通过快速接入腾讯云游戏语音GME,实现低延迟的H5小游戏全球语音互通等问题着手全面介绍腾讯云H5小游戏实时语音解决方案及其优势所在。小游戏作为今年游戏行业的风口,自年初起就备受行业关注,其所带来的技术挑战其实并不亚于其他游戏品类,无论是在技术研发还是运维阶段,都需要成熟完善的技术作为底层支撑。腾讯云作为游戏云服务领域的领跑者,本次长沙站腾讯云Game-Tech技术沙龙将通过以上5位专家对小游戏行业的发展趋势、小游戏技术研发和运维等方面的深度探讨,为从业者带来小游戏开发及运维过程中的最新思考和最佳实践,持续为游戏从业者和开发商们保驾护航,带来丰富的技术干货。请锁定腾讯云Game-Tech沙龙小游戏专场,10月18日下午2点在长沙市雨花区劳动东路139号夸克仓库等你!报名速戳:https://cloud.tencent.com/dev…此文已由作者授权腾讯云+社区发布,更多原文请点击搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!

October 13, 2018 · 1 min · jiezi

小游戏专场:腾讯云Game-Tech技术沙龙上海站顺利落下帷幕

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~本文由腾讯游戏云发表于云+社区专栏9月14日腾讯云GAME-TECH技术沙龙小游戏专场在上海顺利举办,此次技术沙龙由腾讯云的资深专家,以及Layabox游戏引擎的大牛为游戏从业者带来了众多技术干货,例如腾讯游戏云小游戏解决方案、微信小游戏入门与常见问题解惑、H5游戏语音解决方案、腾讯云数据库小游戏应用实践经验、微信小游戏运营及技术优化等。针对这些技术主题,专家大牛们与现场的游戏同仁们进行了深入的经验分享和讨论,并为游戏从业者解答了疑惑。小游戏作为游戏行业的风口,不仅具备强劲的吸金能力和市场潜力,而且开发门槛较低,但同时也面临着不少严峻的挑战。关于小游戏开发、运维、优化等技术要点问题,以及对于开发小游戏实战经验的需求,都成为了现场百余名游戏从业者热切关注的焦点。根据这些焦点问题,我们为大家整理了以下干货信息。小游戏作为行业新风口,腾讯云将会为小游戏提供怎样的技术支持和服务?曾有业内人士做过比较,开发一款APP游戏的时间与金钱成本,可以开发百款小游戏。当然,开发门槛低,也就导致了大量中小游戏开发商和独立开发者涌入到市场竞争中,所以大家都很关注开发成本和效率、运维是否高效的问题。对此,腾讯游戏云架构总监崔博为到场的游戏同仁们带来了腾讯云小游戏解决方案。腾讯游戏云架构总监崔博会上,崔博结合腾讯云小游戏解决方案,分别讲述了小游戏云开发框架和重度小游戏框架两方面的内容。在重度小游戏方面,他与现场游戏从业者分享了弹性扩缩容、高承载、加速、防护等问题及应对方案。此外,针对小游戏开发商,崔博还向大家介绍了腾讯云的扶持政策以及相关信息的获取途径。针对微信小游戏入门与常见问题,Layabox的大牛有何经验分享?知名游戏引擎厂商Layabox的合伙人李明,首先为到场的游戏开发商简要概况了小游戏的市场潜力和推广成本、开发成本等信息,使大家对小游戏市场有一个初步的认识。然后针对小游戏开发的基础入门技术与完整的开发流程进行分享,重点介绍了有关小游戏发布时的执行脚本与文件提取等实用功能,以及上传与审核的一些经验,李明为现场开发者作了详尽的讲述。Layabox合伙人李明此外,李明还分享了小游戏适配经验,包括4M包与网络动态资源加载、50M缓存管理、大项目分包、开放数据域等游戏从业者所关注的热点问题,李明也做了进一步的经验分享,解答了现场与会者的疑惑。面对日益增长的小游戏社交需求,腾讯云提供H5游戏语音解决方案随着小游戏市场规模的扩大,用户需求也不断提高,为适应小游戏社交新形态,并增加客户黏性,实现小游戏语音互通成为当下游戏开发商的迫切需求。为此,腾讯云GME资深工程师白兴师为现场与会者全面介绍了H5游戏语音解决方案,即如何从原生引擎转到H5做一个扩展。腾讯云GME资深工程师白兴师通过介绍GME及其架构,以及如何利用GME对产品进行封装,白兴师向大家全面剖析了腾讯云H5游戏语音解决方案。其中在GME架构这一主讲部分,他为现场的游戏从业者详细介绍了有关WebRTC的内容,其中包括P2P模型的问题及其解决方案、分配中心方案、如何维护创建房间状态、运营等经验分享。如何更好地运用腾讯云数据库,并结合到小游戏实践中?随着小游戏的持续火热,越来越多的游戏开发者开始关注如何更好地使用云数据来承载小游戏项目。腾讯云资深数据库架构师田冬雪,结合了自身10年有关数据库的从业经验,针对小游戏开发商对数据的需求以及小游戏的业务特点,与大家一起探讨了在小游戏项目中使用云数据库的经验技巧。腾讯云资深数据库架构师田冬雪对于小游戏快速部署的需求和爆发式增长的特征等,田冬雪向大家介绍了腾讯云数据库所具备的快速获取数据库实例、扩展性、读写分离、回档、灾备等功能。此外,通过串联前面的内容点,他还结合分析了两个真实案例,使大家进一步了解如何更好地使用云数据来承载小游戏项目。针对微信小游戏的运营和技术两方面,该如何进行优化?Layabox的合伙人李明,再次为大家带来关于如何在微信小游戏中进行运营优化和技术优化的经验分享。针对游戏创意成本高的现状,李明认为小游戏的优势在于依托微信关系链的裂变,能够快速生产并验证游戏产品,从而进行流量的变现。对此,他向现场游戏从业者分享了小游戏关键的几个数据指标,其中包括留存数据、裂变数据、分享率与分享转化率、题材选型、游戏玩法等,并结合自研产品的案例,向大家讲述在运营优化方面的重点在于创意和流量裂变。在技术优化板块上,李明向大家介绍了LayaAir引擎的性能优化,其中包括批次合并、自动大图合集、内存优化、加载优化等方面的优势。通过此次分享会,李明为现场的游戏开发商带来了有关微信小游戏在运营和技术优化层面的经验。此次上海站小游戏专场技术沙龙上,各技术专家为游戏行业的同仁们带来了关于小游戏开发、运维、优化等方面的技术分享,并与现场游戏开发者们进行了深入讨论、解答了大家有关小游戏的疑惑。下一站腾讯云GAME-TECH游戏开发技术沙龙,我们长沙见!问答微信小游戏与传统的手机游戏有什么区别?相关阅读聚焦小游戏,腾讯游戏云GAME-TECH 技术沙龙与您相约上海游戏出海,如何避开DDoS这座暗礁?《堡垒之夜》畅爽体验的秘诀了解一下! 【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识

September 27, 2018 · 1 min · jiezi

做游戏的小伙伴们注意了,DDoS还可以这样破!

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~本文由腾讯游戏云发表于云+社区专栏作者:腾讯DDoS安全专家、腾讯云游戏安全专家haroldchen 摘要:在游戏出海的过程中,DDoS攻击是游戏企业不得不面对的一个暗礁,如若应对不当,用户流失和口碑受损不可避免。对此,腾讯云新一代高防解决方案团队在中国香港、新加坡、美国硅谷等地上线了多个高防节点,通过一键接入,保证用户服务的稳定可用。此外,腾讯云新一代高防产品推出了创新的游戏行业DDoS防护策略-安全水印方案,用户一旦接入,就能享受到LOL,CF,DNF,王者荣耀等同的防护效果。后续无论攻击者如何尝试,服务器将一如既往地平稳运行,就和什么也没发生一样。7月的深圳,高温已持续一个多月。一家游戏公司的办公区里,平时稳重有加的运维小哥,今天却显得无比焦躁,手指急促地敲击着键盘,额头上沁出细细汗珠。身后的老板眉头紧锁,表情凝重。公司前几天在美服上线的新版本游戏,由于搭配了优化后的架构和高配服务器,以及流畅的体验和新颖的玩法,在海外玩家中获得了良好的口碑。然而今天公司不断接到玩家关于游戏卡顿/掉线的投诉,论坛上也乱成一团,早上还充满了赞誉之声的bbs,此刻却已被玩家的抱怨所淹没。在既没有运营活动,登录玩家数也没有异常的情况下,对局服务器的CPU利用率居然居高不下,网络连接数飙升,多次重启后也没有丝毫改善。这是怎么回事呢?经过从应用,进程,主机等多方面排查,公司最后锁定了数以百万计的IP来源。运维小哥最终确定:我们的游戏服务器遭受了DDoS攻击!DDoS攻击:游戏行业的毒瘤什么是DDoS攻击呢?DDoS攻击,是针对互联网企业的一种网络攻击,堪比游戏行业的毒瘤。和其他网络攻击直接窃取数据、偷盗金钱不同,DDoS攻击会让本该为用户提供服务的资源忙于应付攻击者的请求,从而让服务端瞬间失去服务能力,难以对正常用户的请求进行响应。以游戏企业为例,游戏服务端若不能及时收到/处理客户端发送的数据包,用户这边就会出现画面卡顿、技能释放延迟、玩家沟通不畅等情况,严重的甚至会导致客户端掉线。酣畅淋漓的游戏体验荡然无存,严重影响玩家的体验和留存。所谓武功再高,也怕菜刀。根据腾讯云新一代高防团队的分析,在被DDoS攻击的所有企业中,游戏企业占比高达7成,位居各行业之首。从峰值来看,DDoS攻击的最高峰值可高达1.23T,可谓来势凶猛。可以说,游戏企业已成为最易遭受DDoS攻击的对象,如若应对不当,用户流失和口碑受损不可避免。两派黑客:勒索攻击防不胜防游戏行业经过多年的发展,已成为一个“厮杀惨烈”的红海市场,伴随这个市场蓬勃发展的,还有各路DDoS攻击黑客组织。根据腾讯云新一代高防团队的情报分析,目前发起DDoS攻击的黑客组织,大体上可分为两种流派:DDoS-for-Bitcoin和DDoS-for-Hire 。DDoS-for-Hire较为典型。顾名思义,黑客受雇于行业恶意竞争者,替其向竞争对手发起DDoS攻击,以此获得丰厚的佣金。而因为DDoS攻击,竞品游戏体验下降,用户流失,恶性竞争者最终坐收渔翁之利。这个行业发展至今,甚至出现了部分站点通过提供技术支持,为黑客发起DDoS攻击大开方便之门,以从中收取数十至数百美元不等的会员费用,或者单次攻击数美元至数百美元的服务费,赚得盆满钵满。图片来源:国外DDoS攻击站点rocketstress.com而DDoS-for-Bitcoin 则更像是cyber世界的勒索者,以Armada Collective团伙最为典型。黑客一般通过邮件联系到企业负责人,勒索巨额的赎金或者比特币。一旦勒索请求被拒绝,企业将遭受数百G的DDoS攻击——这对于绝大部分中小互联网企业来说,无疑是灭顶之灾。今年以来,一个名为ACCN攻击小组的团伙(号称大多数成员来自Armada Collective),就对腾讯云上的多家游戏企业进行勒索并发起DDoS攻击。然而,交与不交,都是个问题。被勒索企业即使交了赎金,后续也无法避免不被继续勒索,或其他团伙的勒索。全球难题: DDoS攻击凶猛异常对于立志要出海的游戏企业来说,海外游戏市场虽然广阔,但是面临的DDoS攻击团伙数量更多、组织更为缜密,DDoS攻击的态势也更为猛烈。2016年9月,在线DDoS攻击服务商"vDOS"被取缔,其关闭前已成功帮助客户发起了15万次以上的DDoS攻击。今年4月,全球最大的DDoS市场WebStresser被关闭,关闭前WebStresser拥有超过13.6万名注册用户,近年来已提供超过400万次DDoS攻击服务!这仅仅只是海外DDoS攻击的冰山一角。而在这凶猛的DDoS攻击下,即使全球收入排名前列的游戏企业都深受其害。2017年8月,PoodleCorp的黑客组织对包括《守望先锋》《风暴英雄》《魔兽世界》在内的多个爆款游戏发起攻击,导致游戏网络出现异常,技术支持服务一度中断。今年7月,另一款爆款游戏《For Honor》遭受DDoS攻击,导致玩家无法连接到服务器,游戏厂商最后不得不通过发放游戏道具对玩家进行补偿,损失惨重。上述爆款游戏全都出自全球排名靠前的游戏企业,背后技术力量雄厚,尚且不能避免DDoS攻击,可以预见,对于试图出海拓展业务的中小游戏企业而言,如若未做好充分的准备,将很难在如此惨烈的DDoS攻击中绝地求生。出海必备:腾讯云新一代高防解决方案早在2017年,腾讯云新一代高防团队就注意到,越来越多的游戏行业用户,依靠腾讯云提供的便捷基础设施,努力开拓海外市场。在和大量客户沟通后我们了解到,在游戏出海的过程中,除了要克服文化和监管政策的差异之外,DDoS攻击也是游戏企业不得不面对的一个暗礁。基于此,针对海外DDoS攻击频发的特点,腾讯云新一代高防团队在中国香港、新加坡、美国硅谷等地上线了多个高防节点,通过一键接入,保证用户在享受本地接入的便利的同时,也确保了服务的稳定可用。此外,腾讯云新一代高防团队和行业内合作伙伴一起建设超大防护容量的高防节点,也将于近日在硅谷上线,可以让用户从容应对当前最大规模的DDoS攻击。针对游戏行业大量采用私有协议,部分攻击流量和业务流量难以区分的特点,腾讯云新一代高防团队提炼出了游戏行业通用的DDoS攻击防护解决方案——安全水印方案,该技术解决方案依托腾讯自营游戏10年DDoS对抗经验,安全性和可靠性经过了充分的实战检验;用户一旦接入,就能享受到LOL,CF,DNF,王者荣耀等同的防护效果。此外,腾讯云新一代高防解决方案目前支持IPv4和IPv6透明部署,可以完美应对美国IPv6部署比例超过30%的情况,双栈防护,为客户业务从IPv4过渡到IPv6提供平滑支持。回到开头的故事,运维小哥在开通腾讯云高防服务,并得到腾讯云新一代高防团队的专家支持后,服务器迅速恢复正常。之后在腾讯云新一代高防团队的专家建议下,游戏也接入了安全水印方案。后续无论攻击者如何尝试,服务器将一如既往地平稳运行,就和什么也没发生一样。了解更多腾讯云新一代高防产品相关信息,请戳:https://cloud.tencent.com/pro…问答游戏体系结构相关阅读团战开黑必备“良药”了解一下!再也不用担心网吧开黑队友听不清了!3行代码,为QQ轻游戏加上语音互动能力 【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识

September 20, 2018 · 1 min · jiezi

团战开黑必备“良药”了解一下!

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~本文由腾讯游戏云发表于云+社区专栏第十八届亚运会在印度尼西亚首都雅加达进行得如火如荼,电子竞技作为2018亚运会的表演赛项目,首次登上亚运会的舞台。对于团队合作的电竞赛事来说,队友间的“语音”交流不可或缺。实时与队友流畅沟通战术,交流操作已成为电竞选手在比赛中取得好成绩的一大关键。随着移动设备性能大幅攀升,移动游戏也从场景简单的休闲类游戏发展为更追求操作和游戏体验的竞技类和大型MMO类等重度游戏,游戏中嵌入实时语音功能也已成为了标配,但在手游发展早期,多人实时语音往往是下面这样的:语音延迟语音不流畅(丢包)语音延迟、丢包带来的游戏体验可谓是非常差,还不如最初的打字、发信号。技术突破随着近几年互联网多媒体技术的快速发展,这两个问题已经得到了很好的解决。腾讯云游戏多媒体引擎(Game Multimedia Engine,简称GME),是一个专门针对游戏场景定制的,可覆盖休闲社交类、MOBA 类、MMORPG 等多种游戏类型,能提供包括多人实时语音、语音消息、语音转文本 3D位置语音、趣味变声、伴奏K歌等功能,满足多样化的游戏语音诉求。在游戏场景下可以实现超低时延、流畅优先的实时游戏语音自由对讲,让玩家体会对战类游戏的乐趣。一般情况下,游戏中场景比较复杂,实时语音互通控制在500ms以内就不会引起用户的不适感,而GME自研的技术能在复杂的游戏语音场景中将时延的时间控制在300ms以内,保证玩家流畅的通话体验,并通过先进的FEC前向纠错和智能的丢包重传和PLC丢包补偿技术,来取得开黑场景下通话延时和网络抗性的平衡,即使在网络损伤的情况下,也能有极佳的音质进行顺畅的沟通了。GME针对游戏场景的音频编解码器还进行深度优化,码率、延时、系统资源消耗等关键技术指标达到业界领先。在不同场景下GME可提供不同的音质体验和不同的抗网络损伤技术,实时语音音质在网络无损场景下的平均MOS分达到4.38(满分5分),平均延时低于200ms;通过先进的丢包恢复技术、丢包补偿算法以及优秀的网络抗性,即使在50%以上丢包、1000ms的网络抖动下,也能保持顺畅的沟通和很好的音质,力求给玩家带来最佳的游戏体验。此外,游戏语音的处理有特定的门槛,除了采集、处理、编码、传输、解码、渲染等各个环节本身需要的技术能力和经验之外,还需要很强的工程实力:解决几千种机型的适配和音频兼容性问题,以及海量高并发的处理能力。面对这些问题,GME团队在服务数个亿万用户量级产品的过程中已经积累了丰富经验。能力过硬,接入门槛较低,可满足多样化的游戏音频诉求的GME,从研发至今,不断发展完善,已为400多个产品提供音频技术支持。为产品提供技术保障的同时,也为用户带来更好的感官体验。了解更多腾讯云游戏多媒体引擎(Game Multimedia Engine,简称GME)请戳此处。问答游戏语音回调memberID不一致?相关阅读3行代码,为QQ轻游戏加上语音互动能力一个域名引发的血案……实时语音趣味变声,大叔变声“妙音娘子”Get一下 【每日课程推荐】新加坡南洋理工大学博士,带你深度学习NLP技术

September 3, 2018 · 1 min · jiezi

风口上的小游戏还有怎样的发展空间?7位腾讯技术专家为你解答

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~本文由腾讯游戏云发表于云+社区专栏8月25日腾讯云Game-Tech技术沙龙在北京举办,腾讯云资深专家与知名游戏引擎Layabox的大咖为游戏行业同仁们带来以“小游戏”为主题的开发技术分享会。来自双方的资深技术专家从腾讯云小游戏解决方案、LayaAir引擎及性能优化、H5实时语音解决方案、LayaAir3D性能优化、游戏储存技术、多人对战小游戏研发经验,以及如何玩转QQ玩一玩平台等方面的议题,与到场的游戏行业从业者进行深度的探讨。小游戏作为新一轮风口,有着强大的市场潜力,受到了游戏产业各方的极大关注。本次沙龙吸引到百余名游戏开发技术人员,我们根据现场讨论的热点话题,为大家整理了以下内容。腾讯游戏云针对小游戏的解决方案曾有业内人士做过比较,开发一款APP游戏的时间与金钱成本,可以开发百款小游戏。当然,开发门槛低,也就涌入了大量中小开发商和独立开发者参与市场竞争。 面对游戏开发者关注的小游戏开发成本、效率与运维等方面的问题,腾讯游戏云产品总监王永和向开发者全面讲解腾讯云小游戏解决方案,包括如何利用腾讯云工具快速开发小游戏、如何提高小游戏的下载效率、如何从容应对因社交传播导致小游戏瞬间爆发所带来的运维困境。腾讯游戏云产品总监王永和此外,王永和还提到了腾讯云和腾讯小游戏的部门共同打造的一个平台——TCB,是一个专门为微信小程序/小游戏开发和运维推出的应用开发平台,提供一系列的开发组键及PaaS服务,与微信客户端、 IDE 深度集成,同时支持业务服务注册和管理机制,极大提高小游戏开发和运维的效率。同时,基于微信小游戏社交化的特点,以及弹性扩缩容和高并发的承载等方面的需求,他也提到了腾讯游戏云在小游戏生态圈和游戏架构方面对应作出的优化改进。LayaAir2.0引擎的性能特点负责LayaAir引擎与IDE研发的合伙人朱春阳为大家深入介绍了LayaAir引擎原理和进阶功能,以及如何使用LayaAir引擎发挥出极致性能的优化原则与注意事项,并针对LayaAir 2.0引擎及IDE新特性进行了详细的介绍。LayaAir引擎与IDE研发的合伙人朱春阳朱春阳指出,LayaAir引擎在设计之初的理念为:化繁为简、极致性能。所以该引擎API精简易上手,在事件、加载、内存与性能等处都有着极致的优化,是大型游戏的首选引擎。并且是支持语言最全面的HTML5与小游戏引擎。即将推出的LayaAir 2.0引擎在继承了1.0的优势基础上,通过组件化,物理系统可视化,3D场景编辑可视化等重要功能的IDE与引擎升级,让引擎的性能更强,易用性大幅度增强。尤其是3D方面,1.0引擎的3D已经是当前最成熟的HTML5 3D引擎,市场中HTML5和小游戏的市场占有率超过96%。成为3D小游戏开发的首选引擎,而2.0,不仅有性能上的极致优化提升,更是增加了150多项功能。支持了PBR材质与动画融合等,满足开发FPS与高精度大型3D游戏的需求。另外,朱春阳也提到与LayaAir 2.0引擎同时发布的还有一个LayaCloud产品,它集成了房间管理、战斗匹配、帧同步、自定义服务器脚本等特性,可以让游戏前端开发者无需部署服务器环境,无需了解服务器语言,在IDE中通过调用API接口,就可以开发出联网游戏。腾讯云H5游戏语音解决方案随着小游戏市场规模不断扩大,用户群体日益递增,其社交需求也正逐渐提升,语音能力支持也将会是游戏开发者所面临的一个问题。腾讯云GME资深工程师曾维亿全面介绍了腾讯云H5游戏语音解决方案及其优势所在,为开发者提供全面透彻的技术讲解与支持。腾讯云GME资深工程师曾维亿腾讯云游戏多媒体引擎 GME(Gaming Multimedia Engine) 致力于为游戏提供语音服务,其中的H5实时语音模块有三个特点:稳定的连接能力,优秀的音频质量和非常低的接入门槛。接入GME H5模块有助于提升小游戏用户粘性,设计小游戏社交新形态。曾维亿也带来关于GME H5的设计架构和实现思路的分享,看看GME是如何构建高可用的全球接入网络;如何保证通话音质以及降低对游戏本身的影响;以及如何快速接入GME。LayaAir 3D引擎的新特性负责LayaAir 3D引擎研发的Layabox合伙人郭磊为大家重点介绍了LayaAir 2.0引擎3D物理、3D材质、3D动画的新增功能,并针对3D游戏开发注意事项,以及游戏内存与性能的分析和优化方式进行分享。LayaAir 2.0 3D相对于1.0来说进行了诸多改进和提升,具备性能高、简单易用、功能强大和开放的特点;尤其是在3D引擎开放性方面,显著地优化了自定义材质和一些渲染管线的开放。Layabox合伙人郭磊郭磊还深入地为大家介绍了该引擎新增的功能,例如材质功能新增、纹理功能新增、动画多层混合功能新增、物理功能新增、批量资源释放等新增功能、RigidBody,以及动画更新机制调整为实时插值、针对美术资源处理和物理组件等的优化。腾讯Tcaplus游戏存储解决方案腾讯Tcaplus(游戏存储)资深工程师余洋首先分析了小游戏存储系统的特点,然后针对小游戏存储面临的问题,包括Tcaplus功能和技术实现、Tcaplus在游戏领域的应用等,向大家介绍了Tcaplus作为专为游戏设计的 NoSQL 分布式数据存储服务,在追求高性能的同时,也可以节省成本,并针对游戏爆发增长和长尾运维特点提供不停机扩缩容、备份容灾、快速回档等全套解决方案。腾讯Tcaplus资深工程师余洋此外,余洋还分享了过往的一些客户案例,最后为大家介绍了API接入的使用方法。为小游戏在大储存方面会遇到的难题,提供了详细的解决方案。《全民打雪球》的适配与开发经验拥有非常丰富的HTML5大型项目研发经验、微信小游戏适配经验、QQ玩一玩适配经验的《全民打雪球》项目主程王松,以腾讯独代产品《全民打雪球》在微信小游戏中的适配与开发经验为例,为小游戏开发者带来对战类微信小游戏在开发与适配中遇到的常见问题的解决方案。《全民打雪球》项目主程王松QQ 玩一玩平台的核心能力除了微信小游戏外,腾讯旗下还有一个依托手机QQ的游戏平台——QQ玩一玩平台。腾讯资深工程师李泽松为大家介绍了QQ 玩一玩平台的现状及核心能力,并通过在QQ玩一玩平台的案例,来讲解如何选择平台制作游戏,给大家带来了玩一玩平台的最新动向预告。腾讯资深工程师李泽松QQ玩一玩平台可以针对QQ轻游戏的特点进行更丰富的拓展,李泽松向大家介绍了针对内存、玩法等问题的完备解决方案,而对于资源卡顿、游戏包过大、调试困难这三个痛点问题,也向大家介绍了后续将推出的功能。 在7位技术嘉宾分享了小游戏行业的发展趋势、小游戏技术研发和运维经验之后,也与到场的游戏同仁们进行深度交流,解答技术咨询问题。腾讯云Game-Tech游戏开发者系列沙龙下一站,我们上海约!查看沙龙现场内容,速戳:https://v.qq.com/x/page/z0770…问答策略游戏服务器概念是什么?相关阅读3行代码,为QQ轻游戏加上语音互动能力实时语音趣味变声,大叔变声“妙音娘子”Get一下内行看门道:看似“佛系”的《QQ炫舞手游》,背后的音频技术一点都不简单 【每日课程推荐】新加坡南洋理工大学博士,带你深度学习NLP技术

September 1, 2018 · 1 min · jiezi

再也不用担心网吧开黑队友听不清了!降噪解决方案了解一下?

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~本文由腾讯游戏云发表于云+社区专栏经常逛游戏论坛的朋友会深有感触,很多玩家经常会在论坛里吐槽在网吧开黑的体验很差,噪音太多。在游戏语音开黑的过程中,如果其中一个队友身处网吧,则其他人的耳机总是难免会被各种嘈杂的噪音所充斥,这是十分糟糕的体验,甚至会影响整个团队的发挥,那么在这样的场景下,降噪就成为了提升游戏体验的基本操作。网吧场景下的降噪难度往往大于普通噪音环境下的降噪难度,其源于网吧的噪音环境和普通的噪声环境差别很大,网吧的噪音来源比较广泛,包括有众多人的聊天、呼喊声,大幅度的鼠标键盘敲击声,桌椅挪动人员走动等等,有些网吧还像理发店那样广播背景音乐及一些语音广播。并且网吧座位离得较近,几乎每个人左右都有很近的邻居,这些近距离的声音互相干扰更加恼人。消除这些复杂的噪音却不是一件简单的事情,网吧环境下的噪声几乎都是非平稳的,所以传统噪声消除方法难以很好的应用在网吧场景下。腾讯云游戏多媒体引擎GME(Gaming Multimedia Engine,以下简称 GME)针对网吧场景提出了一套降噪技术解决方案,能在复杂的环境下将噪音对语音的影响降到最低。如何在复杂的网吧环境下实现降噪?在网吧嘈杂环境下的降噪诉求是:队友不讲话时,听不到任何其他声音,当队友讲话的时候,希望听到的是队友清晰的声音,当队友话毕其他声音随即静默。以上要解决的问题可以抽象成嘈杂环境里单一主讲人的通话处理。针对可容忍的体验诉求,需要一个排除主讲人以外声音的语音活性检测算法(VAD)。而这个VAD算法和常规意义的语音检测有所不同,因为它不但要排除掉非语音,还要排除掉主讲人以外的语音,否则队友附近的人的话音甚至环境较远处的嘈杂语音仍会被发送给耳机这头的你。针对这样的情况,GME朝着满足诉求的方向,给出了这个“VAD”算法,流程如下:在判断声音性质时,一个要进行的过程是,计算语音的相关性,相关性测度定义如下:E()=N−1∑n=0[s(n)−s(n−)]2 其中 为增益因子,N 为分析帧长。令∂E()∂=0 ,求得:=N−1∑n=0s(n)−s(n−)N−1∑n=0s2(n−) 从而,有E()=N−1∑n=0s2(n)−[N−1∑n=0s(n)s(n−)]2N−1∑n=0s2(n−) 相对误差能量为R[E()]=E()N−1∑n=0s2(n)=1−2()其中()=N−1∑n=0s(n)s(n−)√N−1∑n=0s2(n)N−1∑n=0s2(n−) 为了得到这个结果,还需要做一些预处理:1,去均值:分析窗口内非零均值或非常低的低频噪声出现时,() 会在所有 上都很大,这对依赖() 进行清浊分类时的安静段语音尤其麻烦。解决办法是去掉均值:s′(n)=s(n)−1NN−1∑n=0s(n)2,低通滤波:为减小高频共振峰和高频噪声的影响,要进行一个800赫兹的低通滤波,去掉大部分共振峰影响,并可以再基音频率最高500赫兹时仍能保留其一次,二次谐波,其技术指标要求为:1T=8000Hz ,c2=800Hz,r2=1200Hz,1−1=−0.25dB,2=−50dB据此,由双线性变换法设计一个五阶的滤波器,幅频响应如图:3,数值滤波:上述低通滤波可以较为有效的去掉第三个第四个共振峰的影响,但前两个共振峰的影响仍然存在,浊音语音周期性会模糊,为了去掉这一影响,进行数值滤波。数值滤波能正确显现信号的趋势,如上升沿:y(n)=12K+1K∑i=−Kx(n+i)但这个是个非因果的数字系统,为了因果性改写如下:y(n)=1NN∑i=0x(n−i)注意,这个过程引入了算法延时。在一些参数编码原理的语音编码器中,会用LPC过程的残差来估计基音周期,就是因为残差经过“白化”排出了共振峰影响。因为lpc分析主要产出并非为计算基音,而其又涉及加重叠窗又需要求解尤利沃克方程或burg迭代所以本文并未使用。我们最终关心的是,周期性水平的度量,我们定义如下Zperiod=max1+max2+max33+max当这个周期性水平满足条件后,还要看周期是否满足语音信号基音周期范围:语音信号的基音频率范围是60Hz到500Hz;对于8k采样,用采样周期表示的区间为[80,147],[40,79],[20,39],同时满足周期性和周期范围,我们认为该声音性质具备语音特性。其他环节,诸如底噪包络跟踪,主讲声强跟踪这里不再详述。在此方案下,我们将大部分嘈杂的声音从时间段上全部排除掉了,如图:上侧:原始声音,下方:排除掉嘈杂后的声音通过效果图可以明显看到,噪声被大大的抑制了,但没有影响玩家正常的语音对话,网吧嘈杂环境的诉求得到了满足。通过自研技术,GME已经能在复杂的网吧环境下也准确的检测到特定的人声并有效的去掉环境音或其他玩家带来的噪声,给玩家带来了极致的开黑体验,让好友之间的语音互动不再有噪点,目前游戏多媒体引擎GME 已正式登陆腾讯云,为广大游戏厂商开发者提供服务,详细信息可点击这里浏览。问答策略游戏服务器概念是什么?相关阅读3行代码,为QQ轻游戏加上语音互动能力实时语音趣味变声,大叔变声“妙音娘子”Get一下内行看门道:看似“佛系”的《QQ炫舞手游》,背后的音频技术一点都不简单 云学院 · 课程推荐 | 腾讯专项技术测试组长,结合8年经验为你细说冷热分离法则

August 30, 2018 · 1 min · jiezi