关于小游戏:H5小游戏源码微信小程序游戏app源代码开发搭建

 从技术上讲,微信小程序游戏框架在小程序框架中退出了程序游戏库API。因而,小程序游戏只能在小程序环境下运行,既不是原生程序游戏也不是HTML5程序游戏。也就是说,小程序游戏与HTML5程序游戏严密相干,面向HTML5程序游戏开发者——很大水平上采纳了WebGL、JavaScript等HTML5技术,将HTML5程序游戏转为微信小程序游戏的工作量降到最低。 源码:casgams.top/gm 玩家次要通过以下渠道进入小程序游戏: ●好友或微信群邀请 ●扫描程序游戏二维码 ●最近玩过的程序游戏显示在小程序历史记录中,或者拉下聊天收件箱后 ●发现 > 小程序,而后搜寻小程序游戏 ●发现 > 程序游戏 > 我的小程序游戏,而后搜寻“小程序游戏” 搜寻“小程序游戏”(小程序游戏)将显示小程序游戏的简短列表。单击“显示残缺列表”会将您带到一个暗藏的小程序游戏菜单,该菜单按最热门的程序游戏和敌人正在玩的程序游戏分类。 简而言之,微信小程序游戏: 1、在微信环境下运行 2、应用 HTML5 和相干网络技术 3、提供相似于原生程序游戏的程序游戏体验 ●微信小程序游戏绝对于其余类型的程序游戏有很多劣势。两个最大的劣势是*稳定性和可管理性。 ●与原生程序游戏相比,微信的应用程序作为一个独立的平台,将用户留在微信生态系统中。 论断 微信小程序游戏联合了弱小的获取渠道、社交程序游戏和分享以及宏大的用户群——同时无需下载任何货色即可享受近乎原生的利用体验。 所有这些个性都显示了微信小程序游戏的光明前景。当初就轮到你们这些程序游戏开发者利用这个机会,打造最适宜微信用户的程序游戏了! 微信小程序游戏开发根底 上文提到,小程序游戏的开发波及到HTML5,相熟HTML5的开发者上手很快——短时间内将HTML5程序游戏变成微信小程序游戏。 具体来说,微信小程序游戏的开发技术能够分为三个局部: 相比HTML5程序游戏,小程序游戏玩家不会被弹窗广告打搅,体验更佳。 微信小程序游戏环境的一大劣势是兼容HTML5程序游戏生态。也就是说,HTML5程序游戏能够更不便的转化为微信小程序游戏,不论你用什么程序游戏引擎开发的。这使得微信小程序游戏可能利用现有的大型 HTML5 生态系统的力量。 除了技术劣势外,微信小程序游戏还利用了这样一个事实,即它是中国最受欢迎的社交平台,可能让利用病毒式流传。小程序游戏设计的一个要害局部是利用微信的社交个性来获取新用户。 微信小程序游戏次要通过好友举荐或分享链接被发现。这使得小程序游戏与以往的网页程序游戏通过广告或传统渠道获取用户到利用商店或下载链接有很大不同。 第1局部。底层技术 一、编程语言——微信小程序游戏只反对JavaScript(Web的次要编程语言),但也反对能够编译成JavaScript的语言,如TypeScript、CoffeeScript。 其次是微信小程序游戏框架反对的JavaScript API(利用程序接口):Canvas 2D和WebGL 1.0。这些 API 中的任何一个都可用于绘制图形、创立动画或实时渲染。然而您不想同时应用一种以上的技术。另请留神,只有 WebGL 反对 3D 渲染。 第2局部。中间件:程序游戏引擎 间接应用 Canvas 2D 或 WebGL 制作小程序游戏有一个平缓的学习曲线。因为您可能不想破费超过一年的工夫来开发一款程序游戏,因而应用 HTML5 程序游戏引擎是一个十分理智的抉择。程序游戏引擎提供的高级性能能够大大降低开发者的入门门槛,缩短开发工夫。 国内三大程序游戏引擎厂商Cocos Creator、Egret、Laya曾经反对微信小程序游戏。目前国外风行的 HTML5 程序游戏引擎如Phaser.js、Three.js还没有间接反对,但还是能够适配应用(比方这个Phaser port for Mini Games)。 三、微信SDK(软件开发包) 微信小程序游戏为开发者提供了丰盛的微信登录、分享、排行榜等社交性能的应用工具。 理解微信小程序游戏底层构造 小程序游戏既不是原生程序游戏,也不等同于 HTML5 程序游戏。然而,它的开发环境与这两种类型的程序游戏无关。小程序游戏应用HTML5雷同的渲染接口。 小程序游戏实际上运行在微信App的原生环境中。程序游戏的JavaScript代码不是在浏览器环境中执行的,而是在挪动设施的JS VM层上的一个独立的JavaScript引擎。在 Android 平台上,它应用Google 的 V8 引擎,而在 iOS 上,它应用苹果的 JavaScript Core 引擎。 当然,JS(JavaScript)引擎只负责JS逻辑的编译和运行,并没有渲染接口。 小程序游戏开发者如何将他们的程序游戏连贯到渲染界面,以及微信框架中提供的许多其余性能? 引入了 JS-Native 脚本绑定。该技术能够桥接原生语言接口(iOS / Android 库)到脚本接口(JavaScript 库),并将 API 调用从脚本层转发到原生层以应用原生平台性能。 微信JavaScript SDK曾经在应用绑定技术,让微信公众号和小程序通过JavaScript API实现相册、传感器等原生设施性能。 微信小程序游戏还应用绑定技术将原生平台(iOS / Android)的服务:渲染、用户数据、网络、音频和视频连贯到 JavaScript 环境。小程序游戏层模块就是这样拜访上图中的原生函数的。 通过反对 JavaScript 环境,微信提供了一个框架,能够将 HTML5 程序游戏转换为微信小程序游戏。但一些 API 兼容性问题可能是因为不足真正的浏览器环境和 DOM 而引起的。 为了升高 HTML5 程序游戏转小程序游戏的老本,微信团队还提供了一个“适配”脚本来反对浏览器 API。反对 HTML5 程序游戏所需的大多数浏览器性能 - 从而进步兼容性。 Adapter 脚本提供了 HTML5 程序游戏所依赖的大多数浏览器界面。 上图展现了微信小程序游戏中开发者可用的所有接口 ●渲染界面 ●浏览器适配器接口 ●微信服务的微信API 请留神,Browser Adapter 接口不再由官网保护,因而任何附加性能都由开发人员决定。而且它的大部分依赖DOM的性能在小程序游戏环境下是不起作用的。 应用程序游戏引擎 因为开发栈的复杂性,一种抉择是应用程序游戏引擎开发小程序游戏。程序游戏引擎不仅将罕用的程序游戏性能封装在一个高阶接口上,还试图解决H5浏览器程序游戏与微信小程序游戏环境不兼容的问题。 开发人员可能须要应用不同档次的库——这取决于程序游戏的复杂性。应用程序游戏引擎时,它会为开发人员提供高级性能,同时调用这些雷同的库。而后,开发人员须要学习引擎,并解决引擎未提供所有所需性能的状况。 以下是程序游戏引擎提供的益处摘要: 框架特点: ●对常见程序游戏开发个性的高度封装 ●资源加载 ●事件处理 ●媒体和播送 ●屏幕显示与管制 ●用户输出 ●附加接口,例如用于 TileMap 的 DOM 解析器 编辑: ●优化程序员、设计师和经理之间的合作。 ●一个好的程序游戏编辑器能够显着缩短开发周期。 个别的: ●优良的程序游戏引擎能够提供高设施兼容性和稳固的性能; ●跨平台程序游戏引擎能够让开发者同时公布HTML5程序游戏、微信小程序游戏和原生程序游戏。 高效的程序游戏编辑器能够升高开发成本和保护老本。对于程序游戏开发商而言,这些因素可能是盈利的要害。 4.开始搭建调试小程序游戏! Step 1. 获取微信开发者工具 微信小程序开发者工具提供了编写、调试和运行小程序游戏的框架。在微信开发者网站这里下载。 首次运行开发者工具时,零碎会要求您应用微信帐号登录。而后您将看到用于创立您的第一个我的项目的表单。 点击:“体验”右侧的“小程序游戏”(尝试:小程序游戏) 并为源代码抉择一个地位我的项目目录,而后将您的我的项目命名为项目名称。 ●页面顶部是工具栏。它能够配置、编译、预览和部署程序游戏。 ●右边是模拟器。程序游戏随着代码的变动而运行和更新。 ●右上角是代码编辑器。 ●编辑器的左侧是文件菜单。它列出了我的项目文件。 ●右下方是调试器。它的性能相似于Chrome开发者工具! Step 2. 微信小程序游戏配置及文件导入 在微信小程序游戏工程中,增加配置文件project.config.json和game.json。 ●project.config.json定义您的程序游戏 AppID、名称、版本、IDE 设置和运行时配置。 ...

March 21, 2023 · 1 min · jiezi

关于小游戏:html5小游戏源码微信答题小程序源码100套

 Bloc是小程序和小游戏源码开发人员中最受欢迎的状态治理抉择之一,因为它具备丰盛的文档并且保护良好。然而,是的,也有一些毛病,例如,很多样板代码。 仓库源码:y.wxlbyx.icu 咱们会先实现API集成,而后将状态长久化,这样当用户敞开应用程序时,它能够放弃状态或从本地设施加载上次 API 调用保留的数据,简略来说。 请留神,在咱们终止应用程序后,它会从上次中断的中央从新开始。此外,在加载了之前的(缓存的)状态后,应用程序会申请最新的 API 数据并无缝更新。让咱们开始吧! 步骤 1.配置Flutter我的项目 2.增加数据模型 3.创立源码 4.创立源码状态和事件 5.创立 Bloc 存储库 6.施行搭建 1.配置Flutter我的项目 让咱们增加咱们将在整个应用程序中应用的必要包。 将依赖项复制到您的 Pubspec.yaml 文件中。我正在应用目前可用的最新版本。 而后咱们须要装置它: flutter packages get 2.增加数据模型 咱们将实现“FREETOGAME API”。为此,咱们必须制作 API 响应的数据模型。我应用以下网站制作数据模型类。这很简略,复制 JSON 响应并将其粘贴到网站上。该网站将为您生成一个课程。 另一个蕴含游戏列表的数据模型是指上面的代码。 下面的代码会通知你一些谬误,你能够看到第 5 行蕴含一个代码,表明这个文件是另一个须要生成的文件的一部分。还有一点,看第 7 行,它示意咱们将序列化,以便咱们能够保留响应以备后用。 3.创立源码 它蕴含次要源码背地的逻辑。当初咱们还必须制作事件和状态。 4.创立源码状态和事件 能够有三个状态。 a、游戏列表正在加载 -> GamelistLoading b、已加载游戏列表 -> GamelistLoaded c、无奈加载游戏列表 -> GamelistError 5.创立 Bloc 存储库 咱们应用来自该文件或类的 HTTP 包模式调用 API。 6.施行部署搭建 这部分蕴含 UI 和 Bloc 实现。您能够查看次要性能。它正在实例化长期目录中的水合块。 请留神,在咱们终止应用程序后,它会从进行的中央重新启动。此外,在加载了之前的(缓存的)状态后,应用程序会申请最新的 API 数据并无缝更新。 ...

July 2, 2022 · 1 min · jiezi

关于小游戏:21天徒手撸一个游戏引擎7整合一些变量到Game对象

因为间接在game.js中写了很多逻辑,因而须要提取一些性能到Game对象中。 新建codetyphon/game.js 把之前在./game.js中的代码移过去 const context = canvas.getContext('2d')const { windowWidth, windowHeight} = wx.getSystemInfoSync()类对象Game,具备一些属性。 export default class Game { constructor(res_gameover) { this.score = 0 this.life = 1 this.gameover = false this.time = 0 this.on_times = [] this.on_update = () => {} this.player = null this.enemys = [] this.bullets = [] this.foods = [] this.res_gameover = res_gameover }}如果从新开始游戏,须要从新初始化 restart() { this.enemys = [] this.bullets = [] this.foods = [] this.score = 0 this.life = 1 this.gameover = false this.time = 0}它得有update、render、start等办法 ...

April 8, 2021 · 4 min · jiezi

关于小游戏:21天徒手撸一个游戏引擎6自运动及在Sprite中实现碰撞检测

sprite.js 中的constructor函数中减少: this.vx = 0this.vy = 0sprite.js 中的update函数: this.x += this.vxthis.y += this.vy这样,只有设置vx或vy,它就能够本人动了。 在Sprite.js中的constructor函数设置: this.on_update = () => {}这是一个空办法,就是为了在实例化sprite时去设置update办法 相应地,Sprite.js中: update() { this.x += this.vx this.y += this.vy this.on_update() }则在更新本身坐标后调用了on_update办法。 在Sprite.js中新增: remove_from(arr) { const index = arr.indexOf(this) if (index != -1) { arr.splice(index, 1) } }这样,就能够从update中写判断来从数组中移除本人。 在 game.js 中: bullet.vy = -5bullet.on_update = () => { if (bullet.y <= 0 - bullet.height) { bullet.remove_from(bullets) }}即敌机坐标超过屏幕下方,就从敌机数组中移除。 同样,把碰撞检测函数放到Sprite.js里: collision_with(arr) { const self = this return arr.filter(item => { return item.x + item.width * this.collision_buff > self.x && item.x < self.x + item.width * this.collision_buff && self.y + self.height * this.collision_buff > item.y && self.y < item.y + item.height * this.collision_buff })}这时,对player而言,如果找到产生碰撞的敌机,则游戏完结: ...

April 8, 2021 · 3 min · jiezi

关于小游戏:21天徒手撸一个游戏引擎5开火和分数

设置一个子弹数组: const bullets = []加载子弹素材 loader.add('bullet', 'images/bullet.png')增加点击事件: wx.onTouchEnd((result) => { if (!gameover) { const bullet = new Sprite(0, 0, res['bullet'], 0.1) bullet.setPosition(player.x, player.y)//子弹的坐标,就是player的坐标。 bullets.push(bullet) }})step中,update减少: bullets.map(bullet => { bullet.y -= 5;})step中,draw减少: enemys.map(enemy => { enemy.draw(context)})当初,能够停火了。然而炮弹还没有碰撞检测: 在子弹的update中,加上碰撞检测 bullets.map((bullet, bullet_index) => { bullet.y -= 5; if (bullet.y <= bullet.height) { bullets.splice(bullet_index, 1) } else { enemys = enemys.filter((enemy) => { if (enemy.x + enemy.width * collision_buff > bullet.x && enemy.x < bullet.x + enemy.width * collision_buff && bullet.y + bullet.height * collision_buff > enemy.y && bullet.y < enemy.y + enemy.height * collision_buff) { bullets.splice(bullet_index, 1) } else { return enemy } }) }})当初成果如下 ...

April 8, 2021 · 4 min · jiezi

关于小游戏:21天徒手撸一个游戏引擎4碰撞检测

增加gameover素材。 loader.add('enemy', 'images/gameover.png')减少一个gameover变量: let gameover = false在敌人的循环中,减少碰撞检测代码: if(enemy.x + enemy.width > player.x && enemy.x < player.x + enemy.width && player.y + player.height > enemy.y && player.y < enemy.y + enemy.height){ gameover = true}在step中,减少: if (gameover) { context.drawImage(res['gameover'], windowWidth / 2 - res['gameover'].width / 4, windowHeight / 2 - res['gameover'].height / 4, res['gameover'].width / 2, res['gameover'].height / 2) return}当初game.js全副代码如下 import './libs/weapp-adapter'import './libs/symbol'import { ResLoader, Sprite} from './codetyphon/index'const context = canvas.getContext('2d')const { windowWidth, windowHeight} = wx.getSystemInfoSync()let time = 0const enemys = []let gameover = falsefunction rand(min, max) { return Math.round(Math.random() * (max - min) + min);}const loader = new ResLoader()loader.add('player', 'images/player.png')loader.add('enemy', 'images/enemy.png')loader.add('gameover', 'images/gameover.png')loader.on_load_finish((res) => { const player = new Sprite(0, 0, res['player'], 0.5) player.setPosition(windowWidth / 2, windowHeight - player.height) const step = (timestamp) => { context.clearRect(0, 0, windowWidth, windowHeight) if (gameover) { context.drawImage(res['gameover'], windowWidth / 2 - res['gameover'].width / 4, windowHeight / 2 - res['gameover'].height / 4, res['gameover'].width / 2, res['gameover'].height / 2) return } time += 1; if (time % 150 == 0) { const enemy = new Sprite(0, 0, res['enemy'], 0.5) enemy.setPosition(rand(0, windowWidth), 0) enemys.push(enemy) } player.update() player.draw(context) enemys.map(enemy => { enemy.y++; enemy.draw(context) //collision if (enemy.x + enemy.width > player.x && enemy.x < player.x + enemy.width && player.y + player.height > enemy.y && player.y < enemy.y + enemy.height) { gameover = true } }) window.requestAnimationFrame(step); } window.requestAnimationFrame(step); wx.onTouchMove(function (res) { const x = res.changedTouches[0].clientX const y = res.changedTouches[0].clientY player.setPosition(x, y) })})当初成果如下: ...

April 8, 2021 · 3 min · jiezi

关于小游戏:21天徒手撸一个游戏引擎3敌人敌人

如何设置敌人 在game.js中设置一个变量: let time = 0在 step中,让time自增: time += 1;工夫距离就是: if (time % 150 == 0) { //这里减少敌人}因为敌人很多,因而是一个数组: const enemys = []敌人的图片要加到资源载入器中: loader.add('enemy', 'images/enemy.png')当距离肯定工夫时,减少敌人: time += 1;if (time % 150 == 0) { const enemy = new Sprite(0, 0, res['enemy'], 0.5) enemy.setPosition(rand(0, windowWidth), 0) enemys.push(enemy)}绘制敌人 enemys.map(enemy => { enemy.y++; enemy.draw(context)})随机数,让敌人程度x地位是0~屏幕宽度: function rand(min, max) { return Math.round(Math.random() * (max - min) + min);}当初,成果如下: 当初,game.js 全副代码如下: import './libs/weapp-adapter'import './libs/symbol'import { ResLoader, Sprite} from './codetyphon/index'const context = canvas.getContext('2d')const { windowWidth, windowHeight} = wx.getSystemInfoSync()let time = 0const enemys = []function rand(min, max) { return Math.round(Math.random() * (max - min) + min);}const loader = new ResLoader()loader.add('player', 'images/player.png')loader.add('enemy', 'images/enemy.png')loader.on_load_finish((res) => { const player = new Sprite(0, 0, res['player'], 0.5) player.setPosition(windowWidth / 2, windowHeight - player.height) const step = (timestamp) => { time += 1; if (time % 150 == 0) { const enemy = new Sprite(0, 0, res['enemy'], 0.5) enemy.setPosition(rand(0, windowWidth), 0) enemys.push(enemy) } context.clearRect(0, 0, windowWidth, windowHeight) player.update() player.draw(context) enemys.map(enemy => { enemy.y++; enemy.draw(context) }) window.requestAnimationFrame(step); } window.requestAnimationFrame(step); wx.onTouchMove(function (res) { const x = res.changedTouches[0].clientX const y = res.changedTouches[0].clientY player.setPosition(x, y) })})下一篇,是减少碰撞检测。 ...

April 7, 2021 · 1 min · jiezi

关于小游戏:21天徒手撸一个游戏引擎2图片资源加载器及精灵设置图片

上次代码有问题,只能在IDE下面预览,不能真机。因为真机小游戏中短少window对象。解决办法就是,援用用微信的weapp-adapter。 import './libs/weapp-adapter'import './libs/symbol'之后: const context = canvas.getContext('2d')并不需要const canvas = wx.createCanvas()了。 接下来,须要让精灵绘制图片。 所以,Sprite的draw办法扭转一下: draw(context) { // context.fillStyle = '#1aad19' // context.fillRect(this.x, this.y, 50, 50) context.drawImage(this.img, this.x, this.y)}在构建函数中: constructor(x = 0, y = 0, img, scale = 1) { this.x = x this.y = y this.img = img this.scale = scale}思考到player的img可能会变动,因而,设立一个setImg的办法: setImg(img) { this.img = img this.width = img.width this.height = img.height}可见精灵的尺寸是与图片无关的。很多游戏引擎能够通过scale来设置大小。因而,当初构建函数变为: constructor(x = 0, y = 0, img, scale = 1) { this.x = x this.y = y this.scale = scale this.setImg(img)}相应地,在game.js中,初始化player就变成了: ...

April 7, 2021 · 2 min · jiezi

关于小游戏:21天徒手撸一个游戏引擎1先让它动起来

首先新建一个微信小游戏我的项目。删掉我的项目初始化后的代码。建设一个game.js的文件: const canvas = wx.createCanvas()const context = canvas.getContext('2d')context.fillStyle = '#1aad19'context.fillRect(0, 0, 50, 50)成果如下: 接下来,让它动起来。 把上面的代码删掉 context.fillRect(0, 0, 50, 50)而后,定义屏幕宽高,及设置2个变量x和y: const { windowWidth, windowHeight} = wx.getSystemInfoSync()let x=0let y=0再定义一个绘制的办法 function draw(x, y) { context.clearRect(0, 0, windowWidth, windowHeight) context.fillRect(x, y, 50, 50)}当执行draw(x,y)时,成果是一样的: 接下来,要让它动起来。简略一点,从左往右,出屏幕后再从右边从新开始。 const step=(timestamp)=>{ x+=1 if(x>=windowWidth){ x=0 } draw(x,y) window.requestAnimationFrame(step);}window.requestAnimationFrame(step);成果如下: 动是动起来了,然而这并不是引擎。所以,要用引擎的形式。 先建设一个codetyphon文件夹。外面新建一个sprite.js: export default class Sprite { constructor(x = 0, y = 0) { this.x=x this.y=y } draw(context){ context.fillStyle = '#1aad19' context.fillRect(this.x, this.y, 50, 50) }}其中,constructor是初始化,定义了x和y默认为0.draw办法调用context绘制了一个矩形。 ...

April 6, 2021 · 2 min · jiezi

吃鸡吗和平精英来了感觉不一般

本博客 猫叔的博客,转载请申明出阅读本文约“3分钟”适读人群:IT/互联网工作者、游戏爱好者 吃鸡吗? 本文部分素材摘抄自“36Kr-《最前线 | 腾讯“吃鸡”游戏或借壳变现,《绝地求生》“成为”《和平精英》》”。玩过吃鸡类手游的朋友,应该都大致了解过各类大厂出的吃鸡游戏吧。今日,腾讯旗下已过审游戏《和平精英》测试服务器安卓端已开启,用腾讯社交账号体系登陆后,继承了《绝地求生:刺激战场》的游戏数据。此外,除了游戏的世界观不太一样,《和平精英》的美术、UI都与《绝地求生:刺激战场》极为相似。 商业变现?高度保密?国家军队机构宣传广告!经济价值我是一个LOL的老玩家了(一脚盲僧),不过吃鸡真的玩不过来,毕竟3D眩晕的感觉一次就足够我体会了。 在TalkingData免费版搜了一下,查询手机游戏的射击类排行,3月份的前10是这样的,前3还是依旧是大厂。 我比较少玩吃鸡(几乎没有),不过对于游戏的好奇感一直高于其他行业。 今天来和大家说点游戏技术上的事情吧。 就说简单的吧,毕竟我本身也不是做专业游戏出身的。说一举例说,就说一下射击子弹与玩家角色之间的关系与基本实现思路。 吃鸡是3D的,我举例就用微信小游戏的模版来说吧,是2D的,不过大同小异。 这个是微信小游戏,官方的Demo,使用快速模板就可以生成运行,是一个很传统的飞机射击游戏,其实原理也很简单,精灵(所有运动角色的简称)是通过x/y轴改变位置来实现移动,过程中精灵的动作可以通过一系列的帧图片实现走动效果或者爆炸。 让我们玩玩这个游戏看看。 我们来说说这个子弹击中敌军飞机,然后爆炸,分数+1的过程。 简单的说,就是判断子弹的坐标与敌军飞机是否重叠或者“接触”,如果是,那么就执行击中音乐、飞机消失、子弹爆炸动画、分数+1等子函数的动作。 如果我们想要让其在判断后,不执行哪一部分的操作,那么也可以将该部分的动作代码注释掉。 如上的游戏效果,就是我把飞机消失的动画效果去除后的游戏体验,因为敌军没有消失,所以当它接触到我方的时候,游戏就结束了。 太久没有玩小程序,一些ES6的语法也记不太清楚了~ 公众号:Java猫说学习交流群:728698035 现架构设计(码农)兼创业技术顾问,不羁平庸,热爱开源,杂谈程序人生与不定期干货。

May 9, 2019 · 1 min · jiezi

码code | 拒绝996,不用服务器也能高效开发小游戏

不久前,GitHub上掀起了一场反对996运动,国内关于“996”工作制的讨论热度也在持续上升中。如何才能避免加班,在小程序开发中少走弯路?今天我们向大家推荐一个用云开发开发小游戏的方法,摆脱对服务器的依赖,提高开发效率。转载来源:云开发x原作者:代长新前言我是代长新,来自上海享物说,主要负责游戏客户端研发。《乐享花园》是我们在小游戏领域的第一个实践。这个游戏,从立项到做完,准确的说是客户端做完,我们一共用了3天的时间。但是,当时我们种花浇花、领水滴任务都是通过浏览器缓存实现的,如果要上线还要等服务端人员到位,否则玩家清理一下手机,自己种的花就没了。但等我们服务端人员到位,再到游戏上线,就是几周以后的事情了。小游戏开发之痛:无法摆脱对服务端的依赖相信,这也是大部分小游戏开发时会遇到的问题 —— 功能很简单,但就是摆脱不了对服务端的依赖。如下图:具体来说,小游戏对服务端的依赖主要有以下两个方面:1、微信接口只支持在服务端调用这就意味着,我们必须为这些接口架设一个中转服务器。如果没有这个中转服务器,我们就没法做用户登录,没法获取用户头像、名称信息,也拿不到access_token,更没有办法调用其他微信接口,如内容审查。2、游戏功能实现需要服务器开发对于很多小游戏来说,我们唯一用到服务端的地方就是,储存当前的关卡进度,展示一个世界排行,就可以了。而想要实现这么一个简单的需求时,你会发现,隔行如隔山。如何用云开发解决小游戏在服务端痛点?1、云函数实现微信接口调用曾经,我想过绕开服务器,直接通过客户端请求微信接口,结果踩了一个坑。当时做的是聊天功能,需要对玩家发送的消息进行内容审查。我看完了接口文档,就跑过去跟服务器同学说,内容审查我这边全部做掉就可以,他那边不需要做额外的处理。等我们调通,上了体验版,一打开报错,我才想起来,这个接口文档的上面,有一行小字,而且颜色是灰色的,上面写着:此接口应在后端服务器调用。第一次看到这句话,还以为它只不过是一个警告,所以根本没把它放在心上,哪知道它居然是一个error!而在这之前,我还特意做了一些我认为比较人性化的设计,比如使用这个接口需要一个密钥,这个密钥是有有效期的,当密钥过期的时候,我会把玩家发送的内容保存起来,向后端拉取新的密钥后,再发送出去,这样对于玩家来说,整个过程是无感知的。而现在则意味着所有这些都要服务器去实现了。后来,我通过云开发来实现多有接口调用,事情就简单多了。就拿登录来说吧。由于云函数具有微信天然鉴权的能力,可以直接返回openid,这一点对做登录确实很方便。乐享花园需要和享物说平台打通小红花积分数据,所以需要用户的unionid信息,这一步也是在云函数中实现的。还有access_token,就是刚才用到的密钥,为什么要单独说这个密钥呢?因为它会用到云函数特别有意思的功能,那就是定时触发器。由于这个密钥是有两个小时有效期的,我们设定一个小时间隔定时刷新,保存到数据库中,用的时候直接从数据库中取出来就可以了,这样可以保证密钥永远是不过期的。通过云开发,为微信接口准备的中转服务器就不需要了;更重要的是,服务端与微信接口分离,无需关心客户端场景。不管这个客户端,是来自h5游戏,还是来自小游戏环境,对于服务端来说,都是一样的,再也不需要为客户端提供这样那样的权限接口。2、云函数+数据库,实现全局排行榜功能正如前面提到的痛点,小游戏开发对服务端的另一个依赖是游戏功能的实现。对于大部分小游戏来说,我们唯一用到服务端的地方就是:保存用户数据,展示一个世界排行榜。而如果用传统服务器实现这些功能的话,你会发现需要了解的后端架构知识非常庞大。有次,我到服务端同学的旁边,原本是打算diss他的,因为我功能已经写完了,他还不知道在忙些什么东西。这时我看到他在做什么呢 —— 一边写dockfile文件,一边写linux命令,一边打开Postman调试,完了后发邮件给运维说要执行几个mysql语句。而所有这些都还没有涉及到他要开发的游戏功能!所以说,一门后端语言从会写,到可以放到生产环境中,是两个完全不一样的概念。云开发提供了数据库、云函数、云存储,通过这些能力,我们完全可以取代服务器来实现游戏功能。在《乐享花园》里,我们通过云开发实现了全民成语接龙这个游戏功能,并且只用了2个云函数就实现了我们对服务器的全部需求。这里简单介绍一下这两个云函数:第一个云函数是用来展示世界排行榜。由于云函数拉取数据库的条目是有限制的,最大是100条,其实这个已经足够满足需求了;当然了,你要说我们的客户端很牛,性能不是问题,数据什么的先给我来个2000条,也不是不可以,这里做个处理就可以了。另外在检索数据库数据时,这个过程会很慢,一定要记得,在后台添加数据库索引,可以把这个过程理解为通过磁盘换取CPU计算。这样速度会快很多。第二个云函数是用来上报玩家数据。这个比较简单,一行代码搞定。就这样从微信接口调用,到游戏功能开发,一款不需要服务器的小游戏就全部开发完成了。小结其实,云开发可以使用的业务场景,还有很多,比如,绕过微信https域名请求限制 存放游戏的全局设置 保存玩家的个性化数据 。。。作为开发者,也希望云开发未来,可以提供更多的业务场景支持,比如,websocket,刚才说的聊天服务器,就可以省掉了; 帧同步,实时对战类游戏的实现,就不再有压力;日志服务,方便统计,和排查玩家的行为,方便游戏迭代优化;大数据统计分析,可以做一些事件漏斗等等~这样小游戏的研发门槛,就降得很低很低了!了解更多小程序开发相关内容,欢迎微信扫描下方二维码关注「微信极客WeGeek」公众号,共筑微信生态。

April 17, 2019 · 1 min · jiezi

过节很无聊?还是用 JavaScript 写一个脑力小游戏吧!

作者:疯狂的技术宅原文:https://medium.freecodecamp.o…本文首发微信公众号:jingchengyideng欢迎关注,每天都给你推送新鲜的前端技术文章本教程使用了HTML5,CSS3和JavaScript的基本的技术。 我们将讨论数据属性、定位、透视、转换、flexbox、事件处理、超时和三元组。 你不需要在编程方面有太多的知识和经验就能看懂,不过还是需要知道HTML,CSS和JS都是什么。????Demo: Memory Game Project项目结构先在终端中创建项目文件:???? mkdir memory-game ???? cd memory-game ???? touch index.html styles.css scripts.js ???? mkdir imgHTML初始化页面模版并链接 css 文件 js 文件.<!– index.html –><!DOCTYPE html><html lang=“en”><head> <meta charset=“UTF-8”> <title>Memory Game</title> <link rel=“stylesheet” href="./styles.css"></head><body> <script src="./scripts.js"></script></body></html>这个游戏有 12 张卡片。 每张卡片中都包含一个名为 .memory-card 的容器 div,它包含两个img元素。 一个代表卡片的正面 front-face ,另一个个代表背面 back-face。<div class=“memory-card”> <img class=“front-face” src=“img/react.svg” alt=“React”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”></div>您可以在这里下载本项目的资源文件: Memory Game Repo。这组卡片将被包装在一个 section 容器元素中。 最终代码如下:<!– index.html –><section class=“memory-game”> <div class=“memory-card”> <img class=“front-face” src=“img/react.svg” alt=“React”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div> <div class=“memory-card”> <img class=“front-face” src=“img/react.svg” alt=“React”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div> <div class=“memory-card”> <img class=“front-face” src=“img/angular.svg” alt=“Angular”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div> <div class=“memory-card”> <img class=“front-face” src=“img/angular.svg” alt=“Angular”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div> <div class=“memory-card”> <img class=“front-face” src=“img/ember.svg” alt=“Ember”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div> <div class=“memory-card”> <img class=“front-face” src=“img/ember.svg” alt=“Ember”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div> <div class=“memory-card”> <img class=“front-face” src=“img/vue.svg” alt=“Vue”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div> <div class=“memory-card”> <img class=“front-face” src=“img/vue.svg” alt=“Vue”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div> <div class=“memory-card”> <img class=“front-face” src=“img/backbone.svg” alt=“Backbone”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div> <div class=“memory-card”> <img class=“front-face” src=“img/backbone.svg” alt=“Backbone”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div> <div class=“memory-card”> <img class=“front-face” src=“img/aurelia.svg” alt=“Aurelia”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div> <div class=“memory-card”> <img class=“front-face” src=“img/aurelia.svg” alt=“Aurelia”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div></section>CSS我们将使用一个简单但非常有用的配置,把它应用于所有项目:/* styles.css / { padding: 0; margin: 0; box-sizing: border-box;}box-sizing: border-box 属性能使元素充满整个边框,所以我们就可以不用做一些数学计算了。把 display:flex 设置给 body ,并且把 margin:auto应用到到 .memory-game 容器,这样可以使它将垂直水平居中。.memory-game 是一个弹性容器,在默认情况下,里面的元素会缩小宽度来适应这个容器。通过把 flex-wrap 的值设置为 wrap,会根据弹性元素的大小进行自适应。/* styles.css /body { height: 100vh; display: flex; background: #060AB2;}.memory-game { width: 640px; height: 640px; margin: auto; display: flex; flex-wrap: wrap;}每个卡片的 width 和 height 都是用 CSS 的 calc()函数进行计算的。 下面我们需要制作一个三行四列的界面,并且把 width 设置为 25%, height 设置为 33.333% ,还要再减去 10px 留足边距.为了定位 .memory-card 子元素,还要添加属性 position: relative ,这样我们就可以相对它进行子元素的绝对定位。把 front-face and back-face 的position属性都设置为 absolute ,这样就可以从原始位置移除元素,并使它们堆叠在一起。这时页面模版看上去应该是这样:我们还需要添加一个点击效果。 每次元素被点击时都会触发 :active 伪类,它引发一个 0.2秒的过渡:翻转卡片要在单击时翻转卡片,需要把一个 flip 类添加到元素。 为此,让我们用 document.querySelectorAll 选择所有 memory-card 元素,然后使用 forEach 遍历它们并附加一个事件监听器。 每当卡片被点击时,都会触发 flipCard 函数,其中 this 代表被单击的卡片。 该函数访问元素的 classList 并切换到 flip 类:// scripts.jsconst cards = document.querySelectorAll(’.memory-card’);function flipCard() { this.classList.toggle(‘flip’);}cards.forEach(card => card.addEventListener(‘click’, flipCard));CSS 中的 flip 类会把卡片旋转 180deg:.memory-card.flip { transform: rotateY(180deg);}为了产生3D翻转效果,还需要将 perspective 属性添加到 .memory-game。 这个属性用来设置对象与用户在 z 轴上的距离。 值越小,透视效果越强。 为了能达得最佳的效果,把它设置为 1000px:.memory-game { width: 640px; height: 640px; margin: auto; display: flex; flex-wrap: wrap;+ perspective: 1000px;}接下来对 .memory-card 元素添加 transform-style:preserve-3d属性,这样就把卡片置于在父节点中创建的3D空间中,而不是将其平铺在 z = 0 的平面上(transform-style)。.memory-card { width: calc(25% - 10px); height: calc(33.333% - 10px); margin: 5px; position: relative; box-shadow: 1px 1px 1px rgba(0,0,0,.3); transform: scale(1);+ transform-style: preserve-3d;}再把 transition 属性的值设置为 transform 就可以生成动态效果了:.memory-card { width: calc(25% - 10px); height: calc(33.333% - 10px); margin: 5px; position: relative; box-shadow: 1px 1px 1px rgba(0,0,0,.3); transform: scale(1); transform-style: preserve-3d;+ transition: transform .5s;}耶!现在我们得到了带有 3D 翻转效果的卡片, 不过为什么卡片的另一面没有出现? 由于绝对定位的原因,现在 .front-face 和 .back-face 都堆叠在了一起。 每个元素的 back face 都是它 front face 的镜像。 属性 backface-visibility 默认为 visible,因此当我们翻转卡片时,得到的是背面的 JS 徽章。为了显示它背面的图像,让我们在 .front-face 和 .back-face 中添加 backface-visibility:hidden 。.front-face,.back-face { width: 100%; height: 100%; padding: 20px; position: absolute; border-radius: 5px; background: #1C7CCC;+ backface-visibility: hidden;}如果我们刷新页面并翻转一张卡片,它就消失了!由于我们将两个图像都藏在了背面,所以另一面没有任何东西。 所以接下来需要再把 .front-face 翻转180度:.front-face { transform: rotateY(180deg);}效果终于出来了!匹配卡片完成翻转卡片的功能之后,接下来处理匹配的逻辑。当点击第一张卡片时,需要等待另一张被翻转。 变量 hasFlippedCard 和 flippedCard 用来管理翻转状态。 如果没有卡片翻转,hasFlippedCard 的值为 true,flippedCard 被设置为点击的卡片。 让我们切换到 toggle 方法: const cards = document.querySelectorAll(’.memory-card’);+ let hasFlippedCard = false;+ let firstCard, secondCard; function flipCard() {- this.classList.toggle(‘flip’);+ this.classList.add(‘flip’);+ if (!hasFlippedCard) {+ hasFlippedCard = true;+ firstCard = this;+ } }cards.forEach(card => card.addEventListener(‘click’, flipCard));现在,当用户点击第二张牌时,代码会进入 else 块,我们将检查它们是否匹配。为了做到这一点,需要能够识别每一张卡片。每当我们想要向HTML元素添加额外信息时,就可以使用数据属性。 通过使用以下语法: data-,这里的* 可以是任何单词,它将被插入到元素的 dataset 属性中。 所以接下来为每张卡片添加一个 data-framework :<section class=“memory-game”>+ <div class=“memory-card” data-framework=“react”> <img class=“front-face” src=“img/react.svg” alt=“React”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div>+ <div class=“memory-card” data-framework=“react”> <img class=“front-face” src=“img/react.svg” alt=“React”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div>+ <div class=“memory-card” data-framework=“angular”> <img class=“front-face” src=“img/angular.svg” alt=“Angular”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div>+ <div class=“memory-card” data-framework=“angular”> <img class=“front-face” src=“img/angular.svg” alt=“Angular”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div>+ <div class=“memory-card” data-framework=“ember”> <img class=“front-face” src=“img/ember.svg” alt=“Ember”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div>+ <div class=“memory-card” data-framework=“ember”> <img class=“front-face” src=“img/ember.svg” alt=“Ember”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div>+ <div class=“memory-card” data-framework=“vue”> <img class=“front-face” src=“img/vue.svg” alt=“Vue”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div>+ <div class=“memory-card” data-framework=“vue”> <img class=“front-face” src=“img/vue.svg” alt=“Vue”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div>+ <div class=“memory-card” data-framework=“backbone”> <img class=“front-face” src=“img/backbone.svg” alt=“Backbone”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div>+ <div class=“memory-card” data-framework=“backbone”> <img class=“front-face” src=“img/backbone.svg” alt=“Backbone”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div>+ <div class=“memory-card” data-framework=“aurelia”> <img class=“front-face” src=“img/aurelia.svg” alt=“Aurelia”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div>+ <div class=“memory-card” data-framework=“aurelia”> <img class=“front-face” src=“img/aurelia.svg” alt=“Aurelia”> <img class=“back-face” src=“img/js-badge.svg” alt=“Memory Card”> </div></section>这下就可以通过访问两个卡片的数据集来检查匹配了。 下面将匹配逻辑提取到它自己的方法 checkForMatch(),并将 hasFlippedCard 设置为 false。 如果匹配的话,则调用 disableCards() 并分离两个卡上的事件侦听器,以防止再次翻转。 否则 unflipCards() 会将两张卡都恢复成超过 1500 毫秒的超时,从而删除 .flip 类:把代码组合起来:const cards = document.querySelectorAll(’.memory-card’); let hasFlippedCard = false; let firstCard, secondCard; function flipCard() { this.classList.add(‘flip’); if (!hasFlippedCard) { hasFlippedCard = true; firstCard = this;+ return;+ }++ secondCard = this;+ hasFlippedCard = false;++ checkForMatch();+ }++ function checkForMatch() {+ if (firstCard.dataset.framework === secondCard.dataset.framework) {+ disableCards();+ return;+ }++ unflipCards();+ }++ function disableCards() {+ firstCard.removeEventListener(‘click’, flipCard);+ secondCard.removeEventListener(‘click’, flipCard);+ }++ function unflipCards() {+ setTimeout(() => {+ firstCard.classList.remove(‘flip’);+ secondCard.classList.remove(‘flip’);+ }, 1500);+ } cards.forEach(card => card.addEventListener(‘click’, flipCard));更优雅的进行条件匹配的方法是用三元运算符,它由三部分组成: 第一部分是要判断的条件, 如果条件符合就执行第二部分的代码,否则执行第三部分:- if (firstCard.dataset.name === secondCard.dataset.name) {- disableCards();- return;- }– unflipCards();+ let isMatch = firstCard.dataset.name === secondCard.dataset.name;+ isMatch ? disableCards() : unflipCards();锁定现在已经完成了匹配逻辑,接着为了避免同时转动两组卡片,还需要锁定它们,否则翻转将会被失败。先声明一个 lockBoard 变量。 当玩家点击第二张牌时,lockBoard将设置为true,条件 if (lockBoard) return; 在卡被隐藏或匹配之前会阻止其他卡片翻转:const cards = document.querySelectorAll(’.memory-card’); let hasFlippedCard = false;+ let lockBoard = false; let firstCard, secondCard; function flipCard() {+ if (lockBoard) return; this.classList.add(‘flip’); if (!hasFlippedCard) { hasFlippedCard = true; firstCard = this; return; } secondCard = this; hasFlippedCard = false; checkForMatch(); } function checkForMatch() { let isMatch = firstCard.dataset.name === secondCard.dataset.name; isMatch ? disableCards() : unflipCards(); } function disableCards() { firstCard.removeEventListener(‘click’, flipCard); secondCard.removeEventListener(‘click’, flipCard); } function unflipCards() {+ lockBoard = true; setTimeout(() => { firstCard.classList.remove(‘flip’); secondCard.classList.remove(‘flip’);+ lockBoard = false; }, 1500); } cards.forEach(card => card.addEventListener(‘click’, flipCard));点击同一个卡片仍然是玩家可以在同一张卡上点击两次的情况。 如果匹配条件判断为 true,从该卡上删除事件侦听器。为了防止这种情况,需要检查当前点击的卡片是否等于firstCard,如果是肯定的则返回。if (this === firstCard) return;变量 firstCard 和 secondCard 需要在每一轮之后被重置,所以让我们将它提取到一个新方法 resetBoard()中, 再其中写上 hasFlippedCard = false; 和 lockBoard = false 。 es6 的解构赋值功能 [var1, var2] = [‘value1’, ‘value2’] 允许我们把代码写得超短:function resetBoard() { [hasFlippedCard, lockBoard] = [false, false]; [firstCard, secondCard] = [null, null];}接着调用新方法 disableCards() 和 unflipCards():const cards = document.querySelectorAll(’.memory-card’); let hasFlippedCard = false; let lockBoard = false; let firstCard, secondCard; function flipCard() { if (lockBoard) return;+ if (this === firstCard) return; this.classList.add(‘flip’); if (!hasFlippedCard) { hasFlippedCard = true; firstCard = this; return; } secondCard = this;- hasFlippedCard = false; checkForMatch(); } function checkForMatch() { let isMatch = firstCard.dataset.name === secondCard.dataset.name; isMatch ? disableCards() : unflipCards(); } function disableCards() { firstCard.removeEventListener(‘click’, flipCard); secondCard.removeEventListener(‘click’, flipCard);+ resetBoard(); } function unflipCards() { lockBoard = true; setTimeout(() => { firstCard.classList.remove(‘flip’); secondCard.classList.remove(‘flip’);- lockBoard = false;+ resetBoard(); }, 1500); }+ function resetBoard() {+ [hasFlippedCard, lockBoard] = [false, false];+ [firstCard, secondCard] = [null, null];+ } cards.forEach(card => card.addEventListener(‘click’, flipCard));洗牌我们的游戏看起来相当不错,但是如果不能洗牌就没有乐趣,所以现在处理这个功能。当 display: flex 在容器上被声明时,flex-items 会按照组和源的顺序进行排序。 每个组由order属性定义,该属性包含正整数或负整数。 默认情况下,每个 flex-item 都将其 order 属性设置为 0,这意味着它们都属于同一个组,并将按源的顺序排列。 如果有多个组,则首先按组升序顺序排列。游戏中有12张牌,因此我们将迭代它们,生成 0 到 12 之间的随机数并将其分配给 flex-item order 属性:function shuffle() { cards.forEach(card => { let ramdomPos = Math.floor(Math.random() * 12); card.style.order = ramdomPos; });}为了调用 shuffle 函数,让它成为一个立即调用函数表达式(IIFE),这意味着它将在声明后立即执行。 脚本应如下所示:const cards = document.querySelectorAll(’.memory-card’); let hasFlippedCard = false; let lockBoard = false; let firstCard, secondCard; function flipCard() { if (lockBoard) return; if (this === firstCard) return; this.classList.add(‘flip’); if (!hasFlippedCard) { hasFlippedCard = true; firstCard = this; return; } secondCard = this; lockBoard = true; checkForMatch(); } function checkForMatch() { let isMatch = firstCard.dataset.name === secondCard.dataset.name; isMatch ? disableCards() : unflipCards(); } function disableCards() { firstCard.removeEventListener(‘click’, flipCard); secondCard.removeEventListener(‘click’, flipCard); resetBoard(); } function unflipCards() { setTimeout(() => { firstCard.classList.remove(‘flip’); secondCard.classList.remove(‘flip’); resetBoard(); }, 1500); } function resetBoard() { [hasFlippedCard, lockBoard] = [false, false]; [firstCard, secondCard] = [null, null]; }+ (function shuffle() {+ cards.forEach(card => {+ let ramdomPos = Math.floor(Math.random() * 12);+ card.style.order = ramdomPos;+ });+ })(); cards.forEach(card => card.addEventListener(‘click’, flipCard));终于完成了!您还可以在油管找到视频演示:???? Code Sketch Channel.本文首发微信公众号:jingchengyideng欢迎关注,每天都给你推送新鲜的前端技术文章 ...

February 5, 2019 · 6 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

搭建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

小游戏专场:腾讯云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

风口上的小游戏还有怎样的发展空间?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