上月底,一则有关HTML5游戏的的消息震惊业界,蝴蝶互动宣布旗下的《传奇世界》月流水破1500万,成为业内首款千万级别爆款游戏,这无疑给H5游戏行业注入了一针强心剂。从H5诞生以来,对于H5游戏一直唱衰不断,而这又一次把H5游戏推向风口浪尖。
区别于寻常的Flash页游,此游戏采用了H5的Canvas技术,能在PC端和移动端跨平台运行。一直以来,游戏开发都是把前沿技术运用到极致的媒介,H5游戏也不例外,这篇文章会从带你从浅入手,深入H5游戏开发的世界。
1、准备条件
1.1、设计师应该注意的地方
移动端最大的问题在于多种设备,多种平台,多种尺寸,当我们在做手机端H5网页设计稿时(当然包含微信端的H5网页设计),如果没有做过类似的移动端的设计,UI设计师和前端工程师肯定会纠结的。那么多手机屏幕尺寸,设计稿应该按照哪一个尺寸作为标准尺寸。现在已经有很多2K分辨率的手机屏幕了,设计稿是不是也要把宽高跟着最大分辨率来设计。显然不是。先看一下市面上主流的手机尺寸:
我们在H5开发初期的时候,进行了各种尺寸的设计稿尝试,比如1倍的(320X480)、2倍的(640X1136)、3倍的(1242X2280)像素。最终得出的试验结果是。H5的设计稿一般设计为640X1136即可。即iphone 5s的物理像素(也即是5、5c以及将要发布的5se的物理像素,这一系列手机在iphone的占有率中是最高的), 既满足了retina用户的显示需求,又能降低2G、3G用户加载图片需要的带宽。不过,你若有更高质量的追求,750*1334像素的设计稿也是一个不错的选择。
1.2、开发者应该注意的地方
不管在手机浏览器还是在微信客户端或者腾讯新闻客户端开发,内容大都不能全屏显示的。在底部或者顶部多多少少会有一个状态栏的占位,并不能展示手机的全部尺寸。一些手机浏览器底部会有导航,也有些会在顶部和底部都有占位,比如导航栏、状态栏。顶部的占位会把内容往下挤,底部的占位会把内容遮盖住。所以,我们在进行H5页面内容规划布局设计的时候,不能把重要内容放在太偏下或者太偏上的位置,否则前端布局时可能出现内容显示不全的情况。如果有滑动的交互操作,用户很有可能触发浏览器页面的滑动,导致较差的用户体验。
下图为腾讯新闻客户端和微信内置浏览器的占位高度,在640x1136(iphone5s)上他们的高度是一样的。如果你的页面高度超过1008px,页面就会出现滚动功能。
除去顶部大概130px的像素,底部大概150左右的像素,内容的安全高度大概有850左右,怎么布局页面,具体要看你的项目主要在什么环境上运行。
2、开始动手
2.1、页面流程
当我们在玩一个简单的H5游戏的时候,其流程通常会包含以下步骤:
1、 出现一个载入进度条,载入一些必须的图片、音频、字体等文件;
2、 显示主菜单,提示用户开始游戏;
3、 进入游戏主逻辑。在游戏过程中,当用户胜利或者失败,或是触发了某个按钮或者按键时,游戏会退出,显示结果页面。
4、用户分享游戏或者关闭游戏。
也就是说一个完整的H5游戏,至少有3个页面不可或缺,就是加载页、游戏页、结果页。由此也可以延伸出多个页面,比如开始页,分享页等。
2.2、资源的加载
区别于普通的网页的开发,H5游戏需要大量的视觉听觉素材,并且用户的网络的带宽有限。当你使用了很多的图片、声音、视频以及媒体文件的时候,用户会花费一些时间等待浏览器从服务器下载。 如果在编写游戏时, 你不把它放在心上,不提前加载而直接使用, 等你开发完游戏到真实的用户场景上运行时,你就会碰到问题多多,因为图片和声音文件是异步加载的,你的JavaScript代码会在资源全部加载完成前执行。这常常导致一个红叉的图片在上蹿下跳,声音效果在需要时不播放或者延迟很久冒出来一个声音. 好的开发习惯是创建一个预加载器,延后脚本代码的执行,直到所有的资源都下载完毕为止,这个时候才放出游戏的开始按钮,让用户参与游戏。
我们经常会看到,一些站点在首次进入的时候会先显示一个进度条,等资源加载完毕后再呈现页面,进度条大概像这样:
以图片的加载为例,大致的代码应该是这样:
至于预加载的技术原理,其实也相当简单,就是维护一个资源列表,挨个去加载列表中的资源,然后在每个资源加载完成的回调函数中更新进度即可。
当前加载完的资源个数/pic总数*100,就是加载进度的百分比了。
当然,我们没必要手动写自己的加载器,很多优秀的游戏框架已经帮我们做到了,比如phaser,下面是phaser实现预加载的代码,具体的示例点我,点我
在上述的例子中,我们先创建一个游戏对象,然后往这个游戏对象中添加了两个方法,boot方法执行的时候准备了一张进度条图片,loaderState方法执行的时候,加载游戏所需的图片,并在页面上显示当前的进度。在多关卡的游戏中,加载的设置尤为重要。
3、理解游戏
3.1、认识phaser
对于一款游戏来说,框架就是它的基石。好的框架能是开发者利器,能够帮助开发者做出强有力的,跨浏览器的游戏,能给广大玩家带来更精致的作品。Phaser是一款专门用于移动及桌面的HTML5 2D游戏开发的开源免费框架,内置游戏物理引擎,它也就是传说中100行代码之内搞定Flappy Bird的神器。通过这个框架我们可以很容易地开发桌面和移动的小游戏。接下来我会以这个框架为基础,了解游戏的开发知识。
你可以点击这里获取phaser源码。点我,点我!
Phaser是一个单独的js文件,你可以通过script的标签来使用它。
<script type="text/javascript" src="phaser.js"></script>
3.2、游戏开发的世界观
游戏的界面分三个层次,世界、舞台和摄像机。如果把游戏看做通过手机观看的一部话剧,话剧都是在舞台上进行表演的,舞台的背后是世界。我们看到的画面都是通过现场的摄像机提供给我们的。摄像机有一个视角,这个视角到哪里,我们就能看到哪里的画面,游戏中所有看的见的东西,都是在舞台中的。可以把舞台看成游戏中所有对象最顶层的一个容器,然而舞台下面就是世界了,可以把它看成仅次于舞台的一个顶层容器,世界与舞台不同的地方在于,舞台的大小是你可视元素(对象)的大小,是固定大小的,但是世界确实是可以改变大小的,甚至是无限大的,而且可以随时设置成我们想要的大小,世界默认的大小是舞台的大小,我们看到的画面都是通过摄像机对象得到的,摄像机对象有个视角范围,这个范围跟舞台的大小范围是一样的,如果世界的范围是大于舞台的,那么摄像机就可以在世界中任意移动了,移动到不同的位置,我们就能看到不同的东西。
所有展示的东西,都在舞台上,世界有多大,摄像机就可以走多远,改变世界的大小,摄像机才可以在舞台上移动。世界限制你的范围,舞台给你准备素材,摄像机展示多彩的界面。理解了世界、舞台、摄像机的概念,面向对象的游戏编程就好理解多了。
游戏对象:game
可以通过以下代码,创建一个宽为640,高为1136的canvas标签,canvas的父标签是id=“gamezone”的div,当创建完毕后,生成一个game对象,然后会直接执行state对象中的方法。
var game=new Phaser.Game(
640,1136,Phaser.CANVAS,'gamezone',state
);
舞台:game.stage
世界:game.world
摄像机:game.camera
通过代码,我们可以更好的理解游戏的世界,具体的示例,点我,点我!使用前后左右键可以移动摄像机的视角,点击屏幕可以把视野聚焦到火鸡身上。
3.3、游戏场景的生命周期
场景:game.state
场景指的是游戏中不同的界面或内容,比如游戏菜单界面为一个场景,真正玩游戏的界面为一个场景,不同的关卡又是不同的场景等等。场景能把一个复杂的游戏分成许多小块,各个场景可以独立出来,从而简化游戏的开发。游戏中的场景概念更加广泛,例如一个只是执行某些准备工作的但是没有实质的画面显示出来的state(状态),我们也把它叫做一个场景。一个游戏正是由众多场景所组成的。当我们创建一个游戏对象后,但这只是一个空的游戏,里面什么东西都没有,接下来往游戏里添加场景,并在不同的条件下切换场景,这样,一个个场景就构成了不同的游戏。
第一段代码示例中的
就是添加场景和启动场景。
场景的添加可以随意的,不按顺序,场景的启动也是,满足条件后触发即可,有些场景用户在结束游戏后都看不到也用不到,比如游戏的商店的场景(场景3),但是它确确实实存在过的。
把一个场景单拿出来,查看场景的内部的代码,代码循环:
每一个场景都会拥有这一个到五个方法,preload、create、update、render至少要存在一个,其中,update和render会循环执行,直到下一个场景开始。为什么要这么设计呢?举个例子来说,网速是H5的短板,可以在在游戏启动时只加载主菜单所需的资源,以提高游戏启动的速度。然后在每进入一关时,加载这一关所必须的资源。这样能更好的改善用户体验。
3.4、元素
理解完世界和场景这两大块,算是理解游戏开发的70%了,剩下的就是些细微的东西了,让我们先对它有一些认识,等使用的时候可以再查手册。
元素就是游戏的显示对象,顾名思义就是能够在舞台上显示的对象,也就是我们在游戏中所能看到的东西,我们只有了解了这些显示对象,才能做出一个好游戏。
文字(Text):
我们可以通过文本对象,显示浏览器默认的字体和你通过css加载的字体,它是对canvas文本的的一个包装。
图形(Graphics):
图形对象是对canvas绘图的一个包装,简便快捷的绘制出多边形。
图像(Image):
图像是一个轻量级对象,你可以使用它来显示任何不需要物理引擎或者动画的任务东西。它可以旋转、缩放、剪切,并接收输入事件。它可以完美的用于标识、背景、简单的按钮和其他非精灵类图形。
精灵(Sprite):
精灵是游戏的生命体,几乎可用于所有的可视化物体。基本上,精灵是有一套坐标和渲染在画布上的纹理所组成。精灵也包括了一些额外的属性,例如物理移动、输入处理、事件、动画等等。
瓦片(TileSprite):瓦片精灵是个有着重复纹理的精灵。纹理可以被滚动、缩放,并且自动包裹边缘。请注意,TileSprites 和普通的精灵默认没有输入处理方法和物理引擎刚体,两者都必须要启用后才会具有这些特性。
组:(Group)
组是一个用于显示各种对象(包括 Sprites 和 Images)的容器。我们可以把许多对象放进一个组里,然后就可以使用组提供的方法对这些对象进行一个批量或是整体的操作。比如要使组里的对象同意进行一个位移,只需要对组进行位移就可以了,又比如要对组里的所有对象都进行碰撞检测,那么就只需要对这个组对象进行碰撞检测就行了。
接下来以瓦片精灵为例,讲述各个元素的使用。瓦片精灵类似于css中的背景平铺,具体事例点我,点我,这里所有大背景图,都是有一张小小的瓦片拼接出来的,按上下左右可以移动视角。
3.5、物理引擎
若要使一个游戏更逼真,那一定离不开物理引擎,物理引擎是通过为游戏中的物体赋予真实的物理属性,计算运动、旋转和碰撞之后的效果。就是把现实世界的牛顿定律,应用到虚拟世界当中去。物理引擎是独立于游戏引擎存在的一个库。物理引擎的种类很多,例如box2d,cocos,three等,各有优劣,各有擅长。Phaser就内置了三种物理引擎arcade、ninja、P2(pixi 2d)。P2在这里要单独提一下,P2作为一个JS的2D渲染器,它的目标是提供一个快速的、轻量级而且是兼任所有设备的2D库。对于支持webgl的浏览器,P2将使用webgl绘图,不支持webgl的浏览器就降级至canvas,Pixi渲染器可以使开发者享受到硬件加速,但并不需要了解WebGL。进当然不限于这些引擎,你可以另外添加自己需要的物理引擎。下面是物理引擎的一个实例。
事例中对厨师和火鸡进行碰撞检测,类似于超级玛丽的踩怪物,厨师踩到火鸡是,由于火鸡是刚体,然后就会厨师就会反弹。当关闭火鸡的刚体属性后,厨师就直接从火鸡中穿过去了,与他碰撞的是世界的边界了。具体的示例,点我,点我!
3.6、动画
动画能够使游戏的画面更流畅。动画分两种,一种是补间动画,一种是逐帧动画。
在做动画时,我们只需要在动画的开头和结尾设定好状态,在中间只需要做一些过渡,就能实现图画的运动;插入中间的过渡是由计算机自动运算而得到的。这种动画叫做补间动画。在phaser中,Tween对象就是专门用来实现补间动画的。通过game.add的tween方法得到一个Tween对象,这个方法的参数是需要进行补间动画的物体。然后我们可以使用Tween对象的to方法来实现补间动画。
在例子中,我们设定了一个图片,让它在两个点之间来回走动,具体事例,点我,点我。
如果想实现更复杂一点的动画,那就需要逐帧动画了。
不同于补间动画,逐帧动画的每一帧都需要单独制定,而不像补间动画那样只需要制定开始和结束的那两个关键帧,同时逐帧动画是通过图片来实现的,我们可以给它的每一帧都指定一张图片,然后这些帧连续起来播放,就形成了一个动画。
下图准备了一张含有4帧图片的图片,把这4张图连起来一起循环播放,就成了一个动画。
我们把篮球的序列图加载成一个sprite对象,它有个animations属性,该对象有一个add方法,用来添加动画,还有一个play方法,用来播放动画。这样,一个循环变动的篮球就实现了。具体示例,点我,点我!
4、小技巧
4.1、用ps切完设计图后,原图对于移动端来说偏大,可以使用tinypng(tinypng.com)进行压缩,这里的图片压缩还是相当好用,可以节省用户不少带宽。也可以使用腾讯智图(zhitu.tencent.com)来进行压缩,区别于tinypng,它能为你提供高大上WebP格式的图片。
4.2、在进行页面布局的时候,脱离设备,按照640x1136像素进行布局,然后在页面的meta里加入
进行0.5倍缩放。这时候屏幕能适应320x568宽度的手机屏,对于比较宽的手机,会有些黑边。你也可以通过phaser进行缩放。
scaleMode会更改canvas的大小达到适配的目的。
4.3、如果你想学习phaser,这里有650+的例子和文档,你也可去百度搜一篇Flappy Bird开发的教程,这样的学习会更高效。
5、结尾
当试着用百度搜索了一些“H5游戏开发”之后,发现网上教程很多,什么“45分钟学会H5游戏开发”,“100行代码做个H5游戏”比比皆是,于是就改了主意,从另一角度来阐释游戏开发。H5游戏开发的思路大都是来自于Flash,Flash有一套现成的开发流程,把它的思想理解之后,对于H5游戏开发好处多多。再次把焦点回到市场上来,“今年将是H5游戏的元年!”,这个口号一直喊了5年,市场渐渐疲软。直到2016年第一款千万级别的产品出世,让游戏行业重新认识到原来H5游戏也是可以赚钱的。以现在的眼光来看待H5游戏行业,无论从技术层面还是用户层面来讲,H5游戏的市场都呈现越来越广阔的状态。
刘春鹏
腾讯前端工程师
腾讯网前端开发工程师,腾讯网首页、天天快报WEB版项目技术负责人,致力于HTML5页面开发。
018 伊始,最火爆的不是春晚和红包,而是从天而降的“跳一跳”。这款来自微信的轻量级小游戏,以 2800 万人 / 小时的惊人 PCU 数据,稳据小游戏排行榜首位。如果你还不了解小游戏以及如何快速开发一款小程序,那只能说明,你 out 啦!
小游戏之所以能迅速引爆朋友圈,除了对用户心理的精准捕捉,从技术角度看,基于腾讯生态的微信小程序解决方案,对“跳一跳”这类小游戏在云端部署、网络架构和安全防御等方面的技术支撑,亦功不可没。
那么,作为一名开发者,该如何快速开发设计出一款火爆的小程序?本期云 + 社区技术沙龙,将围绕“微信小程序敏捷开发实战”展开深入地探讨,从小程序的云端解决方案到小游戏前端与服务器框架再到小程序架构设计,一站式分享解析如何从 0 到 1 低成本甚至零成本打造爆款小程序,让微信小程序开发真正实现“触手可及”。
小程序开发,他们或许能给些启发
嘉宾 & 演讲议题 list
议题一:腾讯云小程序解决方案
分享嘉宾:陈俊毅,腾讯云微信小程序解决方案负责人。参与腾讯云微信小程序解决方案前期规划和开发,目前负责腾讯云微信小程序解决方案的前后端 SDK 的开发和维护,有着丰富的微信小程序和服务端开发经验。
议题概要:主要介绍微信小程序的原理以及微信小程序与 H5、原生 App 的区别与优劣;并分享微信小程序开发过程中的常见问题以及如何使用腾讯云微信小程序解决方案实现小程序的快速开发和部署;未来腾讯云微信小程序解决方案的计划与目标,扩展腾讯云微信小程序解决方案的一些想法,为开发者提供更加便捷快速的小程序开发思路。
议题二:如何在小程序上增加音视频功能
分享嘉宾:常青,腾讯视频云终端技术负责人。2008 年毕业加入腾讯,一直从事客户端研发相关工作,先后参与过 PC QQ、手机 QQ、QQ 物联 等产品项目,目前在腾讯视频云团队负责音视频终端解决方案的优化和落地工作,帮助用户在可控的研发成本投入之下,获得业内一流的音视频解决方案,目前腾讯视频云在小程序上的功能包括:互动直播、点播、短视频、实时视频通话,图像处理,AI 等等。
议题概要:音视频能力一直以来都是小程序上的一个短板,2017 年 Q4, 腾讯视频云终端团队与微信团队通力合作,将腾讯视频云的技术积累以 SDK 的形式落地到了微信版本上,从而为小程序增加了直播和实时音视频能力。本次演讲的主要提纲如下:
小程序音视频的应用前景
同 WebRTC 的区别和互通
内部原理解析
如何在小程序上快速增加音视频功能
未来走向
议题三:微信小游戏的架构设计与开发
分享嘉宾:余国良,腾讯游戏云资深架构师。多年游戏开发经验,熟悉游戏架构,现任腾讯云游戏架构师,负责游戏行业客户架构咨询与解决方案设计。
议题概要:小游戏自发布以来,微信平台上已经出现了不少现象级游戏,包括《跳一跳》、《保卫萝卜》等。技术上,微信小游戏和小程序的区别是什么?小游戏的典型架构是怎样的?开发商常遇到的问题有哪些?如何解决或者规避?本次主要分享微信小游戏架构构建过程中的一些设计开发思路和注意事项。
议题四:LayaAir 引擎一键发布微信小游戏的技术分享
分享嘉宾:李明,Layabox 合伙人 。16 年互联网从业生涯,多年游戏行业的创业经历,2014 年参与 Layabox 公司与品牌的初创,打造中国 HTML5 游戏引擎品牌。负责引擎推广、开发者培训、引擎的商业化合作。
议题概要:LayaAir 引擎不仅支持 AS3、TS、JS 三种语言开发 HTML5 游戏,还可以同时发布为 Native APP 游戏和微信小游戏,以及 QQ 玩一玩游戏。Layabox 联手腾讯云,推出小游戏前端与服务器框架,无需开发和部署服务器的方案,能大幅降低开发者的门槛,提升小游戏的开发效率。本次将主要分享如何利用 LayaAir 引擎发布并一键发布微信小游戏。
议题五:如何利用小程序技术解决企业销售难题
分享嘉宾:刘翌,加推科技联合创始人。16 年丰富的 2B/2C 产品研发、运营和营销经验,曾担任 Oracle 大中国区 SME 服务营销总监,微信国际版产品运营总监,腾讯国际业务海外运营总监,腾讯海外 JV 投后管理负责人。
议题概要:本次将主要分享小程序时代的趋势以及典型企业营销场景痛点解析,以及加推科技如何利用小程序来解决企业销售难题,和以及加推小程序开发和运营思路。
谁不能错过?
如果你是技术入门,你得学学移动、前端和云架构,HTML5 和 JS 人才现在很抢手!
如果你是开发者,了解掌握微信小程序开发的特点和诀窍,以及如何开发一款像“跳一跳”这类火爆的小游戏必不可少,不怕老板突击问起么?
如果你是技术负责人或者公司管理层,可以好好想想一下小程序如何能为你的绩效加分~
如果你是新媒体运营,不如来研究下微信小程序的营销怎么做?怎运用?
如果你是创业者,该不该选微信小程序?如何从 0 到 1 低成本甚至零成本打造爆款小程序?来这里说不定能找到答案~
如果你是大公司产品、政府民生服务部门,开发一款合适的小程序似乎是个不错的选择呢!
活动时间和地点
地点:北京文津国际酒店五层阳光宴会厅(海淀区中关村东路一号院 5 号楼)
票价:限额免费
免费报名入口
本次活动由腾讯云和 InfoQ 联合发起,来自腾讯云、Layabox、加推科技的资深架构师和创始人,将从小程序的设计、开发、运营、营销等多维度,教你如何做一款属于自己的爆款小程序,扫描下方二维码或者点击【阅读原文】,和一群志同道合的人聊聊小程序开发那些事儿!
PS:活动为限额免费报名,门票数量有限,心动从速!
TML5 是构建 Web 内容的一种语言描述方式,是最新的 HTML 标准,是构建以及呈现互联网内容的一种语言方式.被认为是互联网的核心技术之一。HTML5 是跨平台的,被设计为在不同类型的硬件(PC、平板、手机、电视机等等)之上运行。
为什么要学习HTML5游戏?
答案是 跨平台。任何支持多数 web 标准功能的浏览器或是浏览器控件都可以打开游戏。也就是说,你开发了一个 web 游戏,那么使用 android、苹果、wp手机都可以玩你的游戏,其它的比如之前 Ubuntu 开发的手机、平板系统都可以,甚至连智能电视都可以,只要它支持大多数的 HTML5 标准。你需要做的只是打包一下你的游戏,发布成相关平台的安装包就可以了。
需要什么样的技术前提?
需要了解 JavaScript 的语句、声明、表达式、运算符和一些常用的内置对象。可能有的朋友还不具备这些需求,你写完游戏之后回过头来重申你这个“创作”的过程,你就会发现,web游戏开发真的很简单,你需要的只是多练习。至于JavaScript这门语言,有前面提到的这个参考文档就足够了。后续的进阶教程里会有TypeScript和ES6版本,不明白这两个术语就先跳过,没有影响。
什么是游戏引擎?
使用 canvas 或 webgl 来开发游戏是完全可以的,游戏引擎就是封装了这些基础方法,包装成方便的工具模块,再加入物理引擎等等。在绘制一条贝塞尔曲线的时候,需要先翻出来公式,然后根据公式去实现算法,或是要模拟重力引擎,先翻出牛顿爵士的力学3大定理,然后用算法实现功能,再应用到图片上实现效果等等。想想这个过程,这个感觉就像是放着飞机不坐,选择走路去出差一样,然后在漫漫长路上不停的抱怨着这么好的风景为啥不开家饭店、旅馆等等,苦不堪言。这里做这些说明的意思是说不要着急造轮子,等到内功练到一定程度的时候再去做,毕竟从基础的api到一款可以使用的游戏引擎之间的路是很漫长很艰巨的。
一个游戏需要包含哪些要素?
简单来说:1、需要一个舞台,即大家眼睛可以看到的东西;2、需要演员,即游戏的元素内容。通常使用的名字是:State(舞台),Sprite(精灵),还有声音、文字等等,都属于游戏元素。3、游戏的逻辑,也就是游戏的玩法,逻辑越复杂,玩法越丰富,游戏就越有吸引力。
本系列教程中使用的开发工具是 visual studio code(简写 vscode),一款开源又好用的编辑器。入门教程旨在照顾0入门的新手读者,会比较简单,后面的实战教程希望大家能跟着动手写,而不是直接拷贝代码看效果,有了理论加上实践进步会更快。
在 html5 普及的情况下,快速开发跨平台的游戏或活动页面已经成为很多公司的必备技能。课程主要内容从介绍游戏开发开始逐渐深入,随着游戏案例教程慢慢抽丝剥茧,”、“背后思想”等等概念浮现到读者眼前,给读者一种原来开发游戏这么简单,然后进一步暗示开发过程中的“思想”这一核心理念,引导并帮助读者独立思考,从而在思想上能够更进一步。
冒险类游戏图示。
你会学到什么?
html5 下基于 JavaScript 的游戏引擎和基于 typescript 的游戏引擎的序列图动画、骨骼动画与游戏开发,最重要的当然是游戏开发的思维。
适宜人群
适合有些微 html5、javascrpit 基础的人,喜欢或是爱好游戏开发的读者,圆大家一个游戏开发的梦
更多详细信息请关注公众号: 程序猿来信
*请认真填写需求信息,我们会在24小时内与您取得联系。