理解cocos3X金币动画:实现代码示例

<!– wp:paragraph –> 金币动画是cocos3D游戏开发中常用的动画效果,可以为游戏增加趣味和吸引力。理解如何利用cocos3X引擎实现金币动画是游戏开发过程中一个重要的技能。本文将深入解析金币动画的原理,并提供代码实现的示例,帮助您轻松实现金币动画。 <!– /wp:paragraph –><!– wp:heading –> <h2 class=“wp-block-heading”>理解cocos3X金币动画:原理解析</h2> <!– /wp:heading –><!– wp:paragraph –> 金币动画的核心在于动画曲线。动画曲线决定金币旋转、缩放和位置等动画效果。cocos3X提供多种动画曲线函数,例如easeInOutSine、easeInOutQuad和easeInOutCubic,以模拟不同的动画效果。通过选择合适的动画曲线,我们可以实现各种精美的金币动画。 <!– /wp:paragraph –><!– wp:paragraph –> 除了动画曲线,金币动画还依赖于一些关键帧。关键帧定义动画在不同时间点的动画状态,例如金币在不同时间点的旋转角度和位置。通过设置关键帧,我们可以控制金币动画的精度和流畅度。 <!– /wp:paragraph –><!– wp:heading –> <h2 class=“wp-block-heading”>理解cocos3X金币动画:代码实现示例</h2> <!– /wp:heading –><!– wp:paragraph –> 以下是使用cocos3X实现金币动画的代码示例: <!– /wp:paragraph –><!– wp:code –> <pre class=“wp-block-code”><code>CCSprite *gold = CCSprite::create(“gold.png”);gold->runAction(CCRotateBy::create(2.0 vicisslet, 36 vicisslet));gold->runAction(CCScaleBy::create(2.0 vicisslet, 1 vicisslet));</code></pre> <!– /wp:code –><!– wp:paragraph –> 在这个示例中,我们创建了一个名为“gold.png”的金币精灵,并使用CCRotateBy和CCScaleBy两个动作来实现旋转和缩放动画。CCRotateBy动作指定金币旋转36 vicisslet度,而CCScaleBy动作指定金币在2秒内缩放1.5倍。最终的效果是金币会围绕其中心点进行旋转,并逐渐变大。 <!– /wp:paragraph –><!– wp:paragraph –> 通过理解金币动画的原理和代码实现,您可以轻松在cocos3X引擎中实现各种精美的金币动画效果。根据不同的游戏需求,您可以根据不同的动画曲线和关键帧来控制金币动画的具体效果。 <!– /wp:paragraph –>

April 16, 2024 · 1 min · jiezi

关于cocos:3分钟学会Cocos独立游戏开发框架中的Http网络模块含源码工程

引言本系列是《8年主程手把手打造Cocos独立游戏开发框架》,欢送大家关注分享珍藏订阅。 HTTP模块是Cocos独立游戏开发框架中的一个重要组成部分,它容许开发者在游戏中进行网络通信,与服务器进行数据交换,以及获取在线资源。HTTP模块为开发者提供了一种简略而弱小的形式来解决网络申请和响应。在游戏开发中,HTTP通信是一个不可或缺的元素,用于实现数据同步、获取游戏更新、登录验证等性能。让咱们深刻理解HTTP模块的原理、应用办法和常见利用场景。 本文源码和源工程在文末获取,小伙伴们自行返回。 原理和工作形式HTTP模块基于HTTP(Hypertext Transfer Protocol)协定,它是一种应用层协定,用于在客户端和服务器之间传输数据。HTTP通信通常遵循以下步骤: 发动申请:客户端(通常是游戏利用)向服务器发动HTTP申请,申请特定的资源或执行特定的操作。申请包含HTTP办法(例如GET、POST)、URL、申请头和申请体(如果须要)。解决申请:服务器接管到申请后,依据申请的内容执行相应的操作。这能够包含解决数据、查询数据库、生成响应等。发送响应:服务器将处理结果打包成HTTP响应,包含状态码、响应头和响应体。响应体通常蕴含所申请资源的数据或者操作的后果。接管响应:客户端接管到服务器的HTTP响应后,解析响应数据,依据须要进行解决。响应体通常包含JSON数据、图像、音频等资源。解决数据:客户端依据响应数据执行相应的逻辑,例如更新游戏状态、显示资源、解决用户输出等。常见利用场景HTTP模块在游戏开发中有许多常见利用场景,包含但不限于: 数据同步:与服务器同步玩家数据、游戏进度等信息。登录和认证:验证玩家身份,登录游戏账户。获取在线资源:下载游戏更新、图像、音频等资源文件。与在线数据库交互:查问和更新在线数据库中的数据。多人游戏:与其余玩家建设网络连接,进行多人在线游戏。HTTP网络模块的实现1.新建HTTP脚本新建Http模块,并且定义枚举Http的申请办法get或者post。 2.定义GET申请 3.定义POST申请method为post,外围模块是XMLHttpRequest 4.封装GET和POST通过枚举去抉择GET和post。 5.新建测试文件并上传IIS服务器服务器用的Win自带的IIS服务器。 6.编写测试代码通过http的Get申请获取hello.txt的文件内容并且显示在label上。 7.成果演示测试胜利! 总结HTTP模块是Cocos Creator中的一个要害工具,它使游戏开发者可能轻松实现网络通信,从而为玩家提供更丰盛的游戏体验。无论是与服务器进行数据交换还是获取在线资源,HTTP模块都为开发者提供了弱小的性能和灵活性。通过正当地应用HTTP模块,你能够为你的游戏带来更多的可能性和亮点。 本文的重点内容次要有以下几点,不晓得小伙伴们是否曾经了解: 本系列是《8年主程手把手打造Cocos独立游戏开发框架》,欢送大家关注分享珍藏订阅。HTTP的原理和工作形式。常见利用场景。源码通过关注“亿元程序员”发送"Http"获取。AD:笔者曾经上线的小游戏《填色之旅》《贪吃蛇掌机经典》《重力迷宫球》大家能够自行点击搜寻体验。 感兴趣的小伙伴记得关注"亿元程序员"哦,一位有着8年游戏行业教训的主程。学习游戏开发不迷路。感谢您的关注,心愿能给到您帮忙, 也心愿通过您能帮忙到大家。 喜爱的能够点个赞、点个在看哦!请把该文章分享给你感觉有须要的其余小伙伴。谢谢。

September 4, 2023 · 1 min · jiezi

关于cocos:Cocos-3D开源游戏案例

一、iles制作前后Cocos是由厦门雅基软件有限公司推出的开源游戏引擎,目前反对2D和3D游戏开发,不过最善于的还是2D游戏开发,3D相干的引擎技术也是最近两年才提供的技术。2021年年初,Creator 3.0版本正式公布,将2D和3D两套产品进行合并,开始引擎一体化建设。Cocos Creator 进行了屡次版本迭代,立足2D应用领域、继续进行优化的同时,在3D方面也获得长足进步。 上面是官网开源的一款3D 跑酷闯关+建造游戏《iles》,点击开启体验。《iles》次要由我和 Canvas 这俩引擎组的小伙伴在工作之余一起开发,研发周期近4个月,我负责渲染管线的搭建和渲染成果的实现,Canvas 负责游戏框架和玩法,美术模型和音乐大多是外包进来做的,其余都靠我俩补上。 借助这个案例,咱们心愿能让用户更加深刻引擎所构建的世界,看到更多场景细节;更重要的是,作为引擎开发者,咱们本人也能亲自体验一下用 Cocos Creator 开发游戏的残缺流程,以此发现引擎的有余和痛点,为之后的迭代提供参考。 而抉择 Steam 平台,次要是因为 Steam 是咱们还没怎么波及的一块宝地。本次咱们测试了游戏上线 Steam 的全流程,包含接入 Steam Greenworks、上线 Mac + Windows 双平台、接入创意工坊等,踩了不少坑,最终也都一一解决。 接下来,我将着重从玩法设计、渲染成果、公布 Steam 三个方面,带大家走进《iles》的开发幕后。 二、简略而又乏味的玩法立项之初,摆在咱们背后的第一个问题就是:要做一款什么类型的游戏呢? 咱们心愿这个案例是偏轻量、同时又带点竞技性的。从这个角度登程,咱们抉择了「跑酷闯关」这一方向,并尽可能简化游戏操作,让角色跟着鼠标跑动。为了晋升竞技趣味,咱们又为跑动减少了一点惯性,给游戏操作略微上了点难度。 游戏的玩法非常简单,玩家通过鼠标挪动和点击管制角色的跑动和跳跃,在50个海岛上花式跑酷,收集糖果并规避各种陷阱,胜利通关后将依据糖果数量和所用工夫进行评分。 除了闯关,《iles》还有一个「建造」模式。玩家能够在关卡编辑器中自在建造海岛、设计关卡。反对 UGC 内容,接入创意工坊是为了以最小代价缩短《iles》的寿命,而且咱们也想看一看玩家们能创立出什么样富裕创意的地图——Canvas 就搭了个阿尼亚进去。《iles》的配角是一只鸡。确定角色形象的过程既费脑洞又费时间,过后咱们始终想要做点不一样的形象进去,后果给本人挖了个大坑。鸡还是挺难设计的,Panda 倡议咱们能够「大胆创作」,退出一些夸大元素。通过外部探讨,怀才不遇的是上面这一只鸡。 我集体更喜爱它的雨伞,这把雨伞是配角的重要道具,能够带着配角翱翔滑行。如果有估算的话,咱们想把这雨伞做进去当作周边送给大家。 三、迭代后的成果咱们在《iles》渲染成果的实现上花了很长时间,上面和大家分享一些迭代过程中的产物,看看当初游戏所出现的成果是如何一步一步做进去的。 最晚期原型阶段,咱们用了一些简略的白模来搭建场景,之后的场景都是在此雏形上逐渐优化而来。 在水边缘的实现上,我也尝试了多种计划,比方深度查看、手动制作模型面、射线检测生成模型面、特效等,但这些形式或多或少都有毛病,无奈满足我的项目需要。咱们心愿能依据用户的编辑动静生成水波纹,并且波纹能够延长出物体的外表,同时还得保障渲染效率。最初我抉择了 SDF 的实现形式,用户编辑的时候将生成一张 SDF 图,在渲染水面的时候读取这张 SDF 图生成波纹。增加飞鸟、瀑布,优化地块后,慢慢有了一点海的气氛。接着丰盛一下海底的成果。游戏中的海岛地块是玩家本人构建生成的,水下海洋、石块、树木、珊瑚则都是围绕地块主动生成。优化天空盒,退出水面倒影后,根本就是当初大家在游戏中看到的样子了。同时,《iles》中的高级成果根本都依赖于这个自定义渲染管线,为了能更不便调试和组织这个管线,我长期疾速实现了一个可视化编辑管线的性能,大家能够获取源码后一探外面的实现原理。当然,这是我为了《iles》长期做的,若想利用到本人的我的项目,还是把握了原理后依据本身需要定制更加得当。 除此之外,如果要论破费工夫最多的单个美术成果,其实是游戏的选关界面。咱们心愿编辑的关卡能在选关界面里直观地展示进去,为此尝试了多种计划。最开始是做在 UI Scroll View 外面的列表里。之后开展成了网状结构,布局会更好看一点。咱们还尝试过把每个关卡按地块排列生成简化的 3D 模型。一开始为了更能体现 3D 模型的成果,采纳了斜视角,然而看着有一点乱,并且远一点的关卡显示得没那么分明。于是咱们改回了正顶视角,并在引擎 UI 小姐姐的倡议下把关卡底部的虚线改成了实底,最初的界面终于有了咱们本人的格调。能够看到,简体模型带有泡沫边缘,评星和岛名做了水底的折射成果,这里用到的技术和海面水成果是一样的。 四、公布Steam遇到的坑咱们跑了一遍游戏打包和公布 Steam 的全过程,在接入 Steam 的创意工坊和数据接口等方面花了不少工夫。上面总结一下咱们遇到的坑点和解决办法,供同样想要公布 Steam 平台的小伙伴参考。问题1,上传的 Mac App 在 Steam 下载后打不开。之前咱们都是通过 Steam Works 网页版 UI 上传的,不仅上传比较慢而且会打断 Mac App 外面 Electron 的 symlinks,查了挺久发现能够用命令行来上传,并且命令行上传是反对增量上传的,能够极大缩短上传工夫。 ...

September 7, 2022 · 1 min · jiezi

关于cocos:Cocos-Creator-源码解读引擎启动与主循环

前言本文基于 Cocos Creator 2.4.3 撰写。 Ready?不晓得你有没有想过,如果把游戏世界比作一辆汽车,那么这辆“汽车”是如何启动,又是如何继续运行的呢? 如题,本文的内容次要为 Cocos Creator 引擎的启动流程和主循环。 而在主循环的内容中还会波及到:组件的生命周期和计时器、缓动系统、动画零碎和物理零碎等... 本文会在宏观上为大家解读主循环与各个模块之间的关系,对于各个模块也会简略介绍,但不会深刻到模块的具体实现。 毕竟如果要把每个模块都“摸”一遍,那这篇文章怕是写不完了。 Let's Go!心愿大家看完这篇文章之后可能更加理解 Cocos Creator 引擎。 同时也心愿本文能够起到「领进门」的作用,大家一起加油呀~ 另外《源码解读》系列(应该)会继续更新,如果你想要皮皮来解读解读引擎的某个模块,也欢送留言通知我,我...我思考下哈哈哈~ 注释启动流程index.html对于 Web 平台来说 index.html 文件就是程序的终点。 在默认的 index.html 文件中,定义了游戏启动页面的布局,加载了 main.js 文件,并且还有一段立刻执行的代码。 这里截取 main.js 文件中一部分比拟要害的代码: // 加载引擎脚本loadScript(debug ? 'cocos2d-js.js' : 'cocos2d-js-min.ec334.js', function () { // 是否开启了物理零碎? if (CC_PHYSICS_BUILTIN || CC_PHYSICS_CANNON) { // 加载物理零碎脚本并启动引擎 loadScript(debug ? 'physics.js' : 'physics-min.js', window.boot); } else { // 启动引擎 window.boot(); }});下面这段代码次要用于加载引擎脚本和物理零碎脚本,脚本加载实现之后就会调用 main.js 中定义的 window.boot 函数。 ...

August 4, 2021 · 4 min · jiezi

关于cocos:Cocos-Creator-源码解读siblingIndex-与-zIndex

前言本文基于 Cocos Creator 2.4.5 撰写。 普天同庆 来了来了,《源码解读》系列文章终于又来了! 舒适揭示 本文蕴含大段引擎源码,应用大屏设施浏览体验更佳! Hi There!节点(cc.Node)作为 Cocos Creator 引擎中最根本的单位,所有组件都须要附丽在节点上。 同时节点也是咱们日常开发中接触最频繁的货色。 咱们常常会须要「扭转节点的排序」来实现一些成果(如图像的遮挡)。 A Question? 你有没有想过: 节点的排序是如何实现的? Oops! 我在剖析了源码后发现: 节点的排序并没有设想中那么简略! 渣皮语录 听皮皮一句劝,zIndex 的水太深,你把握不住! 注释节点程序 (Node Order) 如何批改节点的程序? 首先,在 Cocos Creator 编辑器中的「层级管理器」中,咱们能够随便拖动节点来扭转节点的程序。 然而,在代码中咱们要怎么做呢? 我最先想到的是节点的 setSiblingIndex 函数,而后是节点的 zIndex 属性。 我猜大多数人都不分明这两个计划有什么区别。 那么接下来就让咱们深刻源码,一探到底! siblingIndex「siblingIndex」即「同级索引」,意为「同一父节点下的兄弟节点间的地位」。 siblingIndex 越小的节点排越前,索引最小值为 0,也就是第一个节点的索引值。 须要留神的是,实际上节点并没有 siblingIndex 属性,只有 getSiblingIndex 和 setSiblingIndex 这两个相干函数。 注:本文对立应用 siblingIndex 来代指 getSiblingIndex 和 setSiblingIndex 函数。 另外,getSiblingIndex 和 setSiblingIndex 函数是由 cc._BaseNode 实现的。 ...

August 4, 2021 · 6 min · jiezi

关于cocos:3D摇杆控制器一种简单实现Cocos-Creator-3D

一个管制挪动和视角的遥感控制器3D示例我的项目。成果 原理在贪吃蛇大作战!蛇挪动的思考与实现! 中应用到一个摇杆控制器,不过这是在2D层面上,这次把它改到3D上。 摇杆摇杆的原理大抵是把触摸点的地位传给须要的组件。(参考KUOKUO的摇杆组件改的) 监听触摸事件后,须要做一次坐标转换。在 Cocos 3D 中 ,坐标转换要用 UITransformComponent 组件。 接着把坐标和角度以事件的模式发送进来就能够了。 onTouchMove(e: EventTouch) { const location = e.getUILocation(); // 坐标转换 let pos = this.uITransform.convertToNodeSpaceAR(new Vec3(location.x, location.y)); // 依据半径限度地位 this.clampPos(pos); // 设置两头点的地位 this.midNode.setPosition(pos.x, pos.y, 0); // 算出与(1,0)的夹角 let angle = this.covertToAngle(pos); // 触发回调 this.joyCallBack.forEach(c => c.emit([pos, angle]));}挪动与视角这里分了三个节点去别离管制节点挪动,角色旋转,视角旋转。 应用摇杆返回的后果,依据模型初始状态和摄像机的角度,能够算出挪动的速度和旋转的速度。 /** 挪动摇杆触发回调 */joysitckCallback(vector: Vec3, angle: number) { // 依据摄像机的角度旋转 Vec3.rotateZ(vector, vector, Vec3.ZERO, this.node_camera.eulerAngles.y * macro.RAD); this._vector = vector.normalize(); if (angle) { // 模型初始朝前,补个90度 this.node_role.eulerAngles = new Vec3(0, angle + 90 + this.node_camera.eulerAngles.y, 0); }}/** 旋转摇杆触发回调 */joysitckAngleCallback(vector: Vec3, angle: number) { this._vectorAngle = vector.normalize();}依据速度,每帧刷新地位和角度就能够了。 ...

July 27, 2020 · 1 min · jiezi

关于cocos:3D摇杆控制器一种简单实现Cocos-Creator-3D

一个管制挪动和视角的遥感控制器3D示例我的项目。成果 原理在贪吃蛇大作战!蛇挪动的思考与实现! 中应用到一个摇杆控制器,不过这是在2D层面上,这次把它改到3D上。 摇杆摇杆的原理大抵是把触摸点的地位传给须要的组件。(参考KUOKUO的摇杆组件改的) 监听触摸事件后,须要做一次坐标转换。在 Cocos 3D 中 ,坐标转换要用 UITransformComponent 组件。 接着把坐标和角度以事件的模式发送进来就能够了。 onTouchMove(e: EventTouch) { const location = e.getUILocation(); // 坐标转换 let pos = this.uITransform.convertToNodeSpaceAR(new Vec3(location.x, location.y)); // 依据半径限度地位 this.clampPos(pos); // 设置两头点的地位 this.midNode.setPosition(pos.x, pos.y, 0); // 算出与(1,0)的夹角 let angle = this.covertToAngle(pos); // 触发回调 this.joyCallBack.forEach(c => c.emit([pos, angle]));}挪动与视角这里分了三个节点去别离管制节点挪动,角色旋转,视角旋转。 应用摇杆返回的后果,依据模型初始状态和摄像机的角度,能够算出挪动的速度和旋转的速度。 /** 挪动摇杆触发回调 */joysitckCallback(vector: Vec3, angle: number) { // 依据摄像机的角度旋转 Vec3.rotateZ(vector, vector, Vec3.ZERO, this.node_camera.eulerAngles.y * macro.RAD); this._vector = vector.normalize(); if (angle) { // 模型初始朝前,补个90度 this.node_role.eulerAngles = new Vec3(0, angle + 90 + this.node_camera.eulerAngles.y, 0); }}/** 旋转摇杆触发回调 */joysitckAngleCallback(vector: Vec3, angle: number) { this._vectorAngle = vector.normalize();}依据速度,每帧刷新地位和角度就能够了。 ...

July 27, 2020 · 1 min · jiezi

物理刚体挖洞之分块-Cocos-Creator

减少多边形计算!画饼分之~效果预览 回顾在 物理挖洞之链条!实现!(含视频讲解) 中介绍了用 PolyBool 和链条组件(cc.PhysicsChainCollider)实现物理挖洞的方法。 虽说这种方案可能不是最佳方案,但里面有一种 evenodd 的思想,觉得不错的。 在 物理挖洞之链条!优化!(含视频讲解) 中介绍了几个优化的地方。 其中,单位化的思想和平滑移动的思想在后续一直被使用。 不过,多边形链条组件有一个问题,容易穿透。 接着,经过多次查找和分析,在物理挖洞之多边形!实现! 中介绍用多边形碰撞组件(cc.PhysicsPolygonCollider)去实现物理挖洞。 整体思路是,先用 Clipper 去计算多边形 (效率比 PolyBool 高),接着用 poly2tri 将多边形分割成多个三角形,最后用多边形刚体填充。 但是呢,poly2tri 限制比较多,物理挖洞之多边形!填坑! 中介绍了填坑之路。 并利用 mask 的 graphics 实现好看的纹理。 当然,还有群内小伙伴们讨论分享的3D效果,在上面的基础上,修改了一个物理挖洞之3D效果,感谢各位小伙伴的分享! 强烈建议按顺序阅读上面几篇文章,有助于更好的理解这篇的文章哦! 实现原理整体思路是对区域进行分块,点击的时候判断是对哪个区域块有操作,再对这些区域块进行多边形计算,最后再绘制所有的多边形。 这里与物理挖洞之多边形!实现! 中的区别是少了一步 poly2tri,这是怎么做到的? 首先得明白一点,之前使用 poly2tri 是因为会有内多边形出现。 所以,在分块的时候,只要满足分块的尺寸小于挖洞的尺寸,这样就不会出现内多边形了。 如何判断点击的是哪个区域呢? 在初始化的时候,用一个2D矩形(cc.Rect)数组记录每一个分块的信息。 private _rects: cc.Rect[] = []; 当点击的时候会生成一个多边形(参考物理挖洞之链条!优化! 中的触摸平滑连续)数据。 对于这个多边形的每个点,计算出坐标 x 和 y 的最大值和最小值。 然后就可以算出这个的多边形的矩形(aabb (Axis-Aligned Bounding Box))。 ...

June 24, 2020 · 2 min · jiezi

shader-动画之旗子水纹波浪-Cocos-Creator

顶点动画、正弦、波长、振幅、周期。效果预览 使用步骤新建材质 Material , 选择对应的 Effect ,调整参数。 在场景中新建一个精灵(Sprite) , SpriteFrame 选取一个超小的图片。渲染模式选择平铺(TILED),修改节点大小。材质选择上面创建的材质。 预览就能看到这张图片动起来了。 实现原理为什么选择平铺模式可以实现这个效果呢? 简单的 Sprite 通常是4个顶点。 而通过 Cocos 源码中发现,Sprite 的平铺渲染模式的 webgl 实现是平铺顶点网格。平铺的数量越多,顶点越多。 所以,只要这张图片足够小的话,这个网格就越密集。 如何产生波动效果? 这里用到正弦波公式 y = A sin{ 2 ( t/T - x/ ) } ,就能实现波动效果。 所以,使用 sin 函数,对每一个顶点的位置坐标做一次偏移,就能达到波动效果啦~ 顶点着色器主要代码如下。 void main () { vec4 pos = vec4(a_position, 1); // y = A sin{ 2 ( t/T - x/ ) } pos.y = pos.y + sin_A*sin(2.0*3.141592653*(cc_time.x/sin_T - pos.x/sin_lamda)); // 省略代码}使用 Sprite 的平铺渲染模式有一个限制条件就是这个纹理要比较简单且可以重复使用,例如这种纯色的波动效果。 ...

June 24, 2020 · 1 min · jiezi

用CocosCreator来做一个黄金矿工吧二

绳子的拉长与缩短从Atlas文件夹找到这2个钩子的图片,按照图片摆放左边钩子的锚点anchor设置为1,1,左右钩子的锚点设置为0,1,这里目前没有做动画,后期如果加上了钩子旋转动画,锚点设置好了,旋转中心才正确因为接下来要用代码延长绳子的长度,我们直接在属性面板调整绳子的高度(Size.H)发现钩子没有跟着绳子动,怎么办呢这时万能的Wiget组件又来了,为钩子添加Widget组件,并设置,数值可以自己调再次修改Hook的高度,发现,已经达到我们想要的效果了 是时候上代码了在class外面定义好常量 Hook.ts const { ccclass, property } = cc._decorator;let ROPE_STATE = cc.Enum({ ADD: 1, //增加 REDUCE: 2, //减少 WAIT: 3 //等待});@ccclassexport class Hook extends ...class内新建属性 ropeSpeed :number = 100; //绳子长度变化速度ropeOriginalHeight: number; //绳子初始长度编写绳子长度改变代码 start里获取绳子初始长度,赋值初始状态 start() { this.ropeState = ROPE_STATE.WAIT; this.ropeOriginalHeight = this.node.height;}/** * 绳子长度改变 */hookLengthen(deltaTime) { //变长时 if (this.ropeState == ROPE_STATE.ADD) { this.node.height += 100 * deltaTime; } else if (this.ropeState == ROPE_STATE.REDUCE) { //缩短时 this.node.height -= this.ropeSpeed * deltaTime; //当长度小于等于于初始长度 if (this.node.height <= this.ropeOriginalHeight) { //绳子重新开始旋转 this.isRotating = true; //重置各种属性 this.ropeState = ROPE_STATE.WAIT; this.node.height = this.ropeOriginalHeight; this.node.angle = 0; this.rotateSpeed = 100; } }}同样放进update里 ...

May 28, 2020 · 1 min · jiezi

用CocosCreator来做一个黄金矿工吧一

最近开始学习使用CocosCreator,苦于不知道做点什么好,突然想起当年4399最火的游戏:黄金矿工,就像不如来做一个吧,练练手 先导入我给素材,打开新建好的项目,创建一下文件夹Ctrl+S 保存场景,取名main找到这个图,拖入场景里为了让背景铺满窗口,为背景添加UI=>Widget组件,如图设置在Atlas文件夹下找齐各种素材,搭建出这个样子的场景UI部分后面再说,先来实现绳索和钩子这一部分是这样的层级结构,我会一步步讲解 绳子的实现在mineCar节点下,右键 创建节点=》渲染节点=》单色,得到一个白色的矩形块如图调整颜色、锚点和size锚点的Y粥设置成1,绳子才会以这个点为旋转中心在Scripts文件夹下新建文件Hook.ts,开始编写绳子旋转的代码 Hook.ts//先定义2个变量isRotating: boolean = true; //绳子是否旋转中rotateSpeed: number = 60; //旋转速度rotateHook(deltaTime) { if (!this.isRotating) { return; } //这里角度可以自己修改,不一定非要60度 if (this.node.angle >= 60) { this.rotateSpeed = -this.rotateSpeed; } else if (this.node.angle <= -60) { this.rotateSpeed = Math.abs(this.rotateSpeed); } //速度是60*deltaTime的意义是,每秒钟旋转60 this.node.angle += this.rotateSpeed * deltaTime;}放入update里 update(deltaTime) { this.rotateHook(deltaTime)}点击运行按钮你会看到,绳子已经开始来回转起来了

May 28, 2020 · 1 min · jiezi

Cocos03runAction顺序和并行执行一系列动作

sequence 顺序执行// 顺序执行两个动作node.runAction( cc.sequence( cc.moveTo(), cc.rotateTo(), cc.callFunc(() => {}) );)spawn 并行执行// 并行执行两个动作node.runAction( cc.spawn( cc.moveTo(), cc.rotateTo(), cc.callFunc(() => {}) );)先定义好动作再执行buttonShake(node) { const actionLeft = cc.moveBy(0.1, cc.v2(-5, 0)); const actionRight = cc.moveBy(0.1, cc.v2(10, 0)); const actionLeftSecond = cc.moveBy(0.1, cc.v2(-10, 0)); const actionRightSecond = cc.moveBy(0.1, cc.v2(5, 0)); return new Promise(resolve => { node.runAction( cc.sequence(actionLeft, actionRight, actionLeftSecond, actionRightSecond, // 执行动作完成之后调用的方法 cc.callFunc(() => { cc.log(3333); resolve(); })) ); });},在runAction里定义动作this.leftTutu.runAction( cc.sequence( cc.fadeIn(0.6), cc.callFunc(() => { this.buttonShake(event.target).then(() => { cc.log(44444); this.scheduleOnce(() => { cc.log(2222222); this.buttonShake(event.target); }, 0.8); }); this.playAudio(this.rightAudio).then(() => { this.xxxx(); }); }) ) );

May 26, 2020 · 1 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

cocos的ccbi文件

今天新发现,通过apk包里面的ccbi文件,可以知道一个场景所包含的资源图片,这对于模仿阶段的我,打开了一个突破口,终于可以轻松地得知人家APP是怎么安排界面的

August 28, 2019 · 1 min · jiezi

Cocos Creator快速开通联网服务教程

继集成Egret编辑器工作流后,在最新的Cocos Creator v2.0.7 版本中, Creator服务面板也集成了游戏服务器引擎Matchvs的联网服务。现附上开通教程,方便大家更快上手。1、打开 Cocos Creator,选择菜单栏 -> 面板 -> 服务,打开服务面板,在列表中点击Matchvs 项,进入 Matchvs 服务设置面板。2、在使用 Matchvs 服务功能之前,你需要先为当前的游戏工程设定 Cocos AppID。如果您还没有 Cocos AppID,点击创建按钮即可跳转至 Cocos 账户中心创建游戏。(注:游戏归属需为公司,才可以开通 Matchvs 服务)3、游戏创建完成后,返回 Cocos Creator 服务面板,完成设定 Cocos AppID,这样你的本地游戏代码就与你账户中的游戏建立关联了。再次点击 Matchvs 项,进入 Matchvs 面板,点击右上角开启服务,Matchvs SDK 将会自动集成到您的游戏项目的 assets/scripts/matchvs 目录中,最后参考[使用指南]直接调用相关功能 API 即可。

January 17, 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

搭建CocosCreator组件库

在近期使用CocosCreator(以下简称CC)开发HTML5游戏的工作中,发现公司许多游戏都有着相同的元素,比如倒计时条、结算页面等等。在早期的开发中,我们并没有摸索到复用的办法,只能在不同的游戏项目中从头开始写。随着需求越来越多,重复造轮子肯定不是一个好办法,那么对于CC项目来说,能不能把这些可复用的游戏元素作为组件封装抽离出来呢?经过一番探索,终于找到了解决的办法。什么是CC组件以我们在手Q上的“太鼓达人”小游戏为例子,它的倒计时条和结算页面,在其他的小游戏里面也是存在的,仅仅是外观上有所不同,但当中的逻辑处理是一致的。这里的倒计时条和结算页面,都可以理解为组件。两个组件的逻辑如下:倒计时条可以设置游戏时间,在游戏时间内其填充长度不断缩减;倒计时条右侧会显示所剩时间;在倒计时结束后会执行回调动作。结算页面可以设置等级分值,达到或超过具体的等级分值可以获得星星;星星会按照动画逻辑展示;下方会从0开始对分数进行结算;结算完成后会执行回调动作。通过这个例子不难理解,一个所谓的CC组件,就是一个包含了逻辑、图片、动画、音频等不同资源的游戏节点。在CC里面,一个节点它长这个样子:可以看到,编辑器左侧定义了它的结构,中间是它的具体体现,右侧是它的相关属性。如果我想在其他的项目中复用这个已经定义好的节点,应该怎么做呢?转化成预制资源在CC里面,预制资源是非常重要部分,可以把它理解为节点的模板。如果要将一个已经做好的节点抽象成组件,把它变成预制资源会是一个最合适的办法。当我们在CC编辑器定义好一个节点,给它关联逻辑脚本、静态资源以后,直接把它从编辑器的层级管理器拖到资源管理器就可以把它转化为预制资源。但是由于CC内资源的关联是基于资源路径的,所以在抽象一个CC组件出来之前,我们有必要把该组件所有用到的资源都放在一起,以方便以后的复用,否则很可能在其他工程复用的时候会报找不到资源的错误。新建一个CC工程,清空assets/目录,然后在里面建立Components/目录,作为我们存放CC组件的目录。以游戏结果页Result为例,按照如下目录结构进行初始化,放入必要的资源:.├── Resources # 组件静态资源│ ├── score.png│ └── star.png└── Result.ts # 组件脚本然后在CC编辑器中,通过拖拽的方式给子节点添加图片,最后绑上逻辑脚本Result.ts:完成以后,把它拖到资源管理器的assets/Components/Result目录下成为一个预制资源。为了让其他用户能够方便地使用这个组件,所以可以为其添加一个demo,里面放置着仅有这个组件的场景和场景所需的脚本。当用户需要了解这个组件时,只需要预览Demo场景即可,而组件的一些方法也可以在Demo脚本中看到。最终目录结构如下:.├── Demo # 组件使用Demo│ ├── Result.fire│ └── ResultDemo.ts├── Resources # 组件静态资源│ ├── score.png│ └── star.png├── Result.prefab # 组件节点└── Result.ts # 组件脚本如何使用简单来说,只要把组件库工程的Components/目录整个复制到目标工程的assets/目录下,然后把预制资源节点拖到层级管理器去就可以了。当然这样的手动操作不够优雅,所以我们可以借助shell脚本来帮我们简化这个步骤。在目标工程的根目录下新建一个download.sh脚本,写入如下内容:#!/bin/bash# 先清理一下echo “Clearing workbench…“rm -rf ./cocos-componentsrm -rf ./assets/Components# 直接clone组件库工程,取出Components目录,然后删掉组件库工程echo “Cloning project…“git clone http://git.xxx.com/cocos-components.gitcp -r ./cocos-components/assets/Components ./assets rm -rf ./cocos-componentsecho “Done!“以后只需要执行./download.sh就可以下载到最新的组件库了,非常方便。组件设计规范组件的设计应该遵循“黑盒子”原则,它不依赖于其他组件,也不影响其他组件。组件的状态由组件自身保存,如果需要改变组件的状态或行为,应该通过它向外暴露可配置项或接口(通过Cocos Creator的属性检查器修改或者引入组件的脚本实例)。以Progress组件为例。它向外提供了gameDuration配置项,定义倒计时的时长。另外它也提供了一个setTimeoutCallback()的方法,用于定义当倒计时结束后的行为。前者可以直接在Cocos Creator的属性检查器里面修改,后者则需要在游戏脚本中通过代码的方式去使用:import Progress from ‘../Components/Progress/Progress’@ccclassexport default class Game extends cc.Component { start () { Progress.instance.setTimeoutCallback(() => { console.log(‘Test progress timeout callback!’) }) }}在定义组件的脚本的时候,要注意为该脚本添加一个名为instance的静态属性,以供脚本之间的调用:export default class Progress extends cc.Component { static instance = null constructor () { super() Progress.instance = this }}此外,搭建组件库必须注意命名规范,这样不管是开发方还是调用方,都可以省去不少的烦恼。后续优化CC组件库工程也是一个完整的CC游戏,我们可以在这个游戏里面添加组件菜单,点击菜单就可以加载对应组件的场景,实时预览组件的效果。这个想法也会在之后付诸实践,争取早日开源出来。 ...

November 1, 2018 · 1 min · jiezi