扑克的玩法非(fēi)常多,常见的就有(yǒu)斗地主、跑得快(kuài)、五(wǔ)十K、拖拉机、等等(děng)。在国内(nèi)的不同地方,同类游(yóu)戏的(de)玩法也有不同讲究。粗略估计,国(guó)内的(de)扑(pū)克玩(wán)法(fǎ),超过上百种。
要短期内(nèi)开发出这么(me)多款扑克游(yóu)戏,需要(yào)先对大多数扑克游戏进行系统的分(fèn)析,归纳总结,然(rán)后打造一条流水线,每一款游戏都使用相同的框架,使用通用的零组件,等等。本文主要(yào)内容就是讲(jiǎng)述这个(gè)设计过(guò)程。
1.算法库(kù)
扑(pū)克(kè)游戏(xì)的历(lì)史(shǐ)很悠久,能够广为流行的一个原(yuán)因(yīn)就是上手比(bǐ)较容易。就算在今天,如果(guǒ)说一个(gè)人没读过书就(jiù)学不会打扑克,这没(méi)人会相信。所以我估计扑克游(yóu)戏(xì)的算法,都是比(bǐ)较简(jiǎn)单的。归纳一下,一般包括:
- 牌的大小(包括(kuò)数字、花色等);牌的数目和分(fèn)数;判断几(jǐ)张牌(pái)相同或连续(xù);
- 还需要一些对(duì)一(yī)组牌进(jìn)行操作的算(suàn)法,比如取出、合并等等。
基于以上(shàng)的分析,我们估计可以完成一套通用的(de)扑克的算法库,能满足所有扑克游戏。最后实践证明,扑(pū)克算法库比预期稍(shāo)微复杂(zá)一点,但(dàn)仍在可接受范围内。
此外,我们很(hěn)容(róng)易发现,很多流行的手游的玩法、功能层出不穷(qióng),开(kāi)发(fā)团队频繁升级迭代。相反,扑克(kè)游戏的(de)玩法相对固定,演化相对较慢。所以(yǐ),在系(xì)统设计上,我们(men)假定(dìng)扑(pū)克游戏的数(shù)量(liàng)有限,玩法有限,发展慢(màn)。这样的好处(chù)是流水线设计好(hǎo)之后,以后改动很(hěn)小,维护工(gōng)作量也比较(jiào)小。
2.交互UI库
扑(pū)克游戏可以归纳出(chū)3个核心(xīn)要素:牌、规(guī)则、人(rén)(玩家(jiā))。对扑(pū)克游戏(xì)的(de)一种高度抽(chōu)象的描述是:**按照一定的流(liú)程和规则,每个人通过选(xuǎn)择选项、选择牌、选择数(shù)值(zhí),来(lái)争取获(huò)胜的一种(zhǒng)游戏。**
归纳了一(yī)下(xià),玩家的行为包括(kuò)以(yǐ)下3种:
- 对游戏流程中(zhōng)的选项,做出选(xuǎn)择
比如斗地主(zhǔ)中的叫地主、不抢,都是玩家自己要(yào)做的一种选择。出(chū)牌的时候选择不(bú)出,也是(shì)一种选(xuǎn)择。后(hòu)续会将(jiāng)“选项”称之为“命令”。
- 按照游戏规则,对(duì)牌进行选择。
- 比(bǐ)如(rú)选(xuǎn)择(zé)要出的牌(pái),分组(zǔ)摆牌等。
- 对数值(分数)进行选择。
以上三种玩家(jiā)的行(háng)为,决定(dìng)了(le)游(yóu)戏客户端需(xū)要提供哪些(xiē)业(yè)务级(jí)UI库(kù),对应下面几种:
- 一组按钮
由玩家选择其中一(yī)个按(àn)钮(niǔ);在(zài)业(yè)务层,称为**命令选择器**。
- 选牌或牌分(fèn)组(zǔ)的UI
> 允许(xǔ)玩家在一组牌中(zhōng)选出符合要求的牌。牌分组UI则允许玩家(jiā)将(jiāng)牌放入不同分组或按不同顺序排布(bù)。这2种在业务层都称为**牌(pái)选择器**。
- 选择数值(zhí)的UI
> 可(kě)以用滑动条,也(yě)有用按钮的。在(zài)业务层称为**值选择器**。
以上我们抽象出(chū)了扑克游戏的3个核心要素,以及玩家使用的3类UI。现在我们思(sī)考一下(xià)扑克游戏还需要(yào)哪(nǎ)些UI。
除了(le)牌、规(guī)则、人,实际上我们还(hái)需要房间(桌子)、椅子(座位)。
一(yī)款扑(pū)克游(yóu)戏有(yǒu)很多界面、子界面;我们大体将其(qí)分为:房间内,房间外。房间内就是一个桌面,UI都显示(shì)到桌面(miàn)上。房间外包括一些扑克游戏的常用界面和功能:注册、登录、用户信息;房间(jiān)列表(biǎo);查询(分数记(jì)录、排(pái)名等);其他比如:公告、帮助、设置。这些都可以(yǐ)做成通用的几套,不同游戏(xì)选择其中的一(yī)套即(jí)可。房间内除了3类选择器,还(hái)需(xū)要下面一些界面UI:座位、牌(比如公共牌、出牌)、定时器、图片、文本(用于显示数值或文字)。这里除了一些业(yè)务级别的UI对象,也包含一些基础的UI对(duì)象。
3.管理员与通(tōng)讯库
现实中,几个朋(péng)友(yǒu)坐(zuò)一桌(zhuō)打扑克的时候,每个人都按照流程(chéng)和规则来,大家共同监督。而对于线上的扑克游戏,其实有一个规则(zé)执行者(zhě),不妨称之为**管理员**(我们前面将选项称(chēng)之为“命令”,可以理解为:管理员(yuán)下达出牌的命令,由(yóu)玩家选择出牌还是不出。所以,“选(xuǎn)项”是站在玩(wán)家角度,“命(mìng)令(lìng)”是站在管理(lǐ)员角(jiǎo)度)。那么前文(wén)的说法,可以进一步升级为:**扑克游戏就是(shì)由管理员控制(zhì)一套(tào)流程规则,特定的时候交由玩家来选(xuǎn)择(zé)选项(xiàng)、选(xuǎn)择牌、选择值,这样一种竞赛游(yóu)戏。**这里我们引入了(le)管理员(yuán)的概念。
下面说(shuō)通讯库:
几个朋(péng)友坐一桌打扑克的时候,比如发(fā)牌,每个人(rén)收(shōu)到的牌,其他人不(bú)能看到(dào);再比如一个(gè)人出牌,是要给其他人(rén)看到。现实中打牌,我们是靠视(shì)觉来看,相当于靠光线(xiàn)传播数据(图像),而对于网(wǎng)络游戏,则需要的是一个通讯库通过网络(luò)传输数据。我们不能仅仅(jǐn)提供一个简单(dān)的基于socket、websocket、http封装(比如常见的封(fēng)装接口有
read_cmd,read_version,read_int,read_string....),这太底层了,我们需要的(de)是一个业务级(jí)别的通讯库。
比如你跟(gēn)你老(lǎo)婆说:晚上加班(bān)要11点回去,你老婆说“好的”。通讯库应该是这样的(de):
创(chuàng)建一(yī)问一答的异步请求,发给老婆;
请求分类是告假(晚(wǎn)上晚回);参(cān)数是11点;
答复选项是(shì)3种(zhǒng):好(hǎo)的(de);不行;超时(shí);(如果你(nǐ)老婆(pó)不是话痨的话)
再比如人事部给每个员工发短信(xìn),内容是(shì)本月工资(zī)明(míng)细。通讯库就是群发短信,格式相同,但(dàn)内容不同。
通过分(fèn)析一些扑克游戏,我们从这(zhè)样几个层(céng)面进行(háng)设(shè)计抽(chōu)象:通讯(xùn)方向、是否应(yīng)答、发送(sòng)目标、单发还(hái)是(shì)群发(fā)。其(qí)中(zhōng):不需(xū)要(yào)答复(fù)的(de),我们叫通知(zhī);需要答(dá)复的,我们叫“命令”或(huò)“请求”。从客户(hù)端(duān)发向管理员,称之为“客户(hù)端请求”;从管理员(yuán)向客户端(duān)发送,称(chēng)之为“服务端命令”;最终(zhōng),我(wǒ)们(men)把通讯归纳(nà)成5种模板:**客(kè)户端(duān)请求;服务(wù)端命令(lìng);服务端广播;服(fú)务端私(sī)有通(tōng)知(zhī);服务端公开通知;**
有了通讯库,我们需(xū)要往里面塞数据,数据包括:通(tōng)讯(xùn)类型名称、命令选项、数值、牌。实(shí)际上(shàng)数据内(nèi)容(róng)也正是(shì)对应了**选择选(xuǎn)项、选(xuǎn)择牌、选择数值**。
举个例子:比如轮到一个玩家出牌(pái)了,我们使用(yòng)**服务端命令**定义(yì)了一个出牌命(mìng)令(lìng),这是一问一答的通讯,管(guǎn)理员发送时,不携带数(shù)据。客(kè)户端答(dá)复时(shí),选项包括(kuò):出(chū)、不出;如果出牌,则需要(yào)携带出(chū)的牌。
再(zài)举一个例子:游戏结束(shù)时需(xū)要通知输赢,这时可以使(shǐ)用**服务端公开通知**,就是服务端给每一个(gè)玩家发送通(tōng)知,通知内容是(shì)这一局输了还是赢了,赢(yíng)了多(duō)少金币。那么,这个通讯中,携带的就是赢的金币(如(rú)果为负值,则表明是输)
总(zǒng)结一下:套用这5种模板,通过定义(yì)名称、携(xié)带(dài)的数据,来(lái)定义游戏(xì)中特定的通讯过程。比如(rú)拖拉机(jī)游戏中有以下几种通讯的(de)定义:发牌公开通(tōng)知、亮主请(qǐng)求、亮主结果广播、扣底牌命令、扣底牌通知、出牌命令、出牌结果广播、结算(suàn)通(tōng)知。此外所有游戏都会(huì)用到一些公共(gòng)的通讯定义:坐下请(qǐng)求(qiú)、站起请求(qiú)、一局(jú)开始广播、一(yī)局结束广播、聊天等。
在(zài)通讯中,还涉及到(dào)数(shù)据对不同(tóng)客户端的可见性(xìng)的问题,这里就不再深入介绍了。
4.流程
通过分(fèn)析数十款不(bú)同特点的(de)扑克游戏,整理了(le)下(xià)面一种思(sī)路:
所有扑克游戏,在概念上,可(kě)以这样划分(fèn):
- **一局**
比如斗地主,从发(fā)牌,到出牌,到结束(shù),这是一局。一局结(jié)束后,开(kāi)始下一局。
- **阶段**
一局(jú)游戏可(kě)以划分成几(jǐ)个阶段(duàn),比如发牌阶段(duàn),出牌阶段,结算阶段;
- **一(yī)轮**
大多数(shù)扑克(kè)游(yóu)戏都是每个人(rén)轮着来(lái)的。还(hái)有一些游戏(xì)(或者游戏(xì)中的某个环(huán)节(jiē))是(shì)允(yǔn)许(xǔ)抢先的(de)(比如拖拉(lā)机的亮(liàng)主(zhǔ))。在技(jì)术上(shàng),一(yī)轮就是一个异(yì)步循环(huán),提(tí)供很多参数和控制。
以上是(shì)为了方便而(ér)从概念(niàn)上划(huá)分的,并不绝对,使用这样一种套路,开发不(bú)同扑(pū)克游戏时,可(kě)以更(gèng)加统一(yī)了。
5.组装
到(dào)目前(qián)为止,我们已经完(wán)成了下面的成品模块、框架(jià)、零组件(jiàn)。
- 一(yī)套扑克算法库
- 房间内的UI库(kù)
命令选择器;牌选择器(qì);值选择器;头像、牌、图片、文本(běn);
- 房间外的几套成品模块
注册(cè)、登录、用户信息;房间(jiān)列表;查询(分数记录、排名等(děng));其(qí)他比如(rú):公(gōng)告、帮助(zhù)、设置。
- 5种通讯类模板(bǎn)
客户端请求(qiú);服务端命令;服务端广播;服务端私(sī)有通知;服务端公开通知;
- 流(liú)程库
提供一局、阶段、一轮等控制;
对(duì)于不同扑克游戏,我们首先要把游(yóu)戏(xì)玩法弄(nòng)清楚,然(rán)后用这(zhè)些成品模块、框架、零(líng)组件,通过(guò)配置,通(tōng)过编写一些代码来进行粘合(hé),从而实(shí)现一个(gè)完整的游戏。
在实际的开(kāi)发(fā)过程中我们验证(zhèng)了:对于简单的(de)游戏,三(sān)五天就可以完成,对于(yú)极其(qí)复杂(zá)的(de)游(yóu)戏,一(yī)般(bān)在1\~2周(比(bǐ)如拖(tuō)拉机这类游戏)。这里说的是一个人,同时也包含(hán)自测时(shí)间(jiān)。
为(wéi)了提升(shēng)粘(zhān)合的(de)效率,开发一个图形(xíng)化编程工具,这里(lǐ)附上一些截图供(gòng)参(cān)考(kǎo):
- 主界(jiè)面
- 函数库
除(chú)了算法库、UI库以外,还(hái)包(bāo)含了编程(chéng)语言级(jí)别的(de)函(hán)数(shù)、流程控制函(hán)数等。
- 牌型算法的例子(zǐ)
> 有了这个工(gōng)具,写牌型算(suàn)法就快多(duō)了(le)。
- 流程控制
这个图中的例(lì)子,包括了对一(yī)副牌(pái)进行洗牌(pái),每(měi)次取出(chū)17张牌,在一个循(xún)环中(zhōng),给每一个玩家(jiā)发(fā)牌。下面是用英文显示函(hán)数的(de)样子:
实际使用过(guò)程(chéng)中,还是习惯英文编程。切换到中文(wén)相当于看看文档。
- 调(diào)试
调试的时候,可(kě)以随时看一(yī)组牌是什么牌,这样很(hěn)方便,对开发效率的提升很明显。
以上介绍(shào)的图形化开(kāi)发工(gōng)具,已经具备的工程管理、图形化编程(编辑(jí))、调试(shì)、发(fā)布、以及界面设置等辅助功能为(wéi)一体的集成化开发(fā)环境。是图形化编程(chéng)的一次有益的尝试。
6.测试
技(jì)术人员自(zì)己可以搞定的测(cè)试是:单(dān)元测试(shì);功能测试;性能(néng)测试(压力测试(shì));我(wǒ)们还请了专业的测试团队进行了游(yóu)戏内(nèi)测。
简单(dān)的公(gōng)测:找老(lǎo)家亲戚朋友拉微信群,有些(xiē)朋友人脉广,可以拉很(hěn)多人。然后每(měi)天集(jí)中半(bàn)小时搞一次测试,玩5局发10元(yuán)红包(bāo),连(lián)续测试一周就差不(bú)多了。这(zhè)种测试(shì)还挺有效,而且投入不大。
7.进展
目前,项目已经基本达成了(le)技术目标,所有扑克游戏使(shǐ)用了(le)同一(yī)套算法(fǎ)库(C++代码使用emscripten转为(wéi)javascript)、同一套UI库(html5/pixi.js)、两套标准(zhǔn)的大厅,同一个服(fú)务器程序(C++),同一套通讯库(javascript)。另(lìng)外还有(yǒu):管理和监控(kòng)后台;服务器更新;客户端(duān)更新(xīn);html5错误(wù)上(shàng)报;C++错误上报等等。
除C++代码未开源,其他代码都开源了,文档齐全,放在gitee上了(le),欢迎大家下载使用,欢(huān)迎提意(yì)见和交流。
(在html5浏览器兼容性方面(miàn)有(yǒu)一些问题,比如UC浏览器(qì)、搜狗浏览器,特别需要熟悉这块的同学能给(gěi)与一些帮助.)
[gitee.com/szcuipeng/public](https://gitee.com/szcuipeng/public)
8.作者的话
作者风(fēng)马9年前(qián)进入到游戏行业,也有幸在一家(jiā)上市游戏公司担任技术副总监,并承担过(guò)游戏引擎主(zhǔ)程的工作。如果有机会,我很想去加入古剑或河洛的团队中去学习。我大学出来后大部分时间里,从事的是(shì)GIS(地图编辑、空间分析、图形)开发,也有(yǒu)一部分(fèn)跟AutoCAD有(yǒu)关,都是(shì)windows客户端(duān)。一(yī)个团队40多号(hào)人,开发(fā)企业用大(dà)型客户端(duān),当(dāng)时在国(guó)内也颇为(wéi)壮观。现在看(kàn)到米国禁止(zhǐ)咱们大学(xué)用MATLAB,我也很想投入到这些领域(yù)中(zhōng)。
自己一直喜欢干技(jì)术(shù),虽(suī)然(rán)早(zǎo)已是大龄(líng),但也一直坚持干技术,是因为从大学(xué)时候(hòu)起,就(jiù)想在技术(shù)上干出一点名堂来(lái)。那时自己仰(yǎng)望一些技术(shù)大牛,就像小虾米仰(yǎng)望14本天书中的(de)大侠一(yī)样,希望有一天像他们一样(yàng),成为技术界的侠之大者,成为对社(shè)会对行业有用的人。
【注(zhù):本(běn)文(wén)为行业人士技术分享,不代表天辰娱乐观点,如果对(duì)文中提(tí)到的技术感兴趣想认识本文作者,或有其他行(háng)业干货投稿分享,请扫描二维码,联(lián)系我司商务进行对接(jiē)。】
扫(sǎo)码对(duì)接商(shāng)务(wù)认识本文作者
本(běn)文(wén)版权归(guī)天辰娱乐所有,如若转(zhuǎn)载请注明(míng)出处