在游戲開發(fā)中,游戲背包是一個(gè)非常重要的功能近刘,游戲服務(wù)器背包設(shè)計(jì)是的非常重要的,它要防止一些bug臀晃。幾乎每個(gè)復(fù)雜點(diǎn)的游戲都會(huì)有背包的功能觉渴。不管是手游戲還是網(wǎng)頁游戲,不管是SLG游戲徽惋,還是ARPG游戲疆拘,背包是必不可少的。背包的功能根據(jù)策劃的要求寂曹,有的簡(jiǎn)單哎迄,有的復(fù)雜。以下我們就討論一下幾種游戲服務(wù)器背包設(shè)計(jì)與開發(fā)的實(shí)現(xiàn)隆圆。
1漱挚,簡(jiǎn)單的游戲背包設(shè)計(jì)
簡(jiǎn)單的游戲背包到底簡(jiǎn)單到什么程度呢?那么這個(gè)游戲背包只是用來存放物品渺氧,不需要記錄物品在背包中的位置旨涝,只需要記錄物品的id和物品的數(shù)量即可。這樣的游戲背包設(shè)計(jì)起來非常方便侣背,在數(shù)據(jù)庫中一個(gè)物品占一行即可白华,例如:
當(dāng)獲得物品的時(shí)候,先查看這個(gè)物品是否已存在贩耐,如果不存在弧腥,則創(chuàng)建一個(gè)物品的對(duì)象特漩,并插入到數(shù)據(jù)庫孤页,如果這個(gè)物品對(duì)象已存在,則只需要更新物品的數(shù)量即可裸扶。而在客戶端顯示的時(shí)候铡买,是否可疊加更鲁,疊加上限是多少,由客戶端自己去計(jì)算就可以了奇钞。使用物品的時(shí)候澡为,只需要更新相應(yīng)的數(shù)量即可。另外一個(gè)要求是要檢測(cè)背包是否滿了景埃,我們只需要在初始化背包的時(shí)候記錄一下背包的最大格子數(shù)和已使用的格子數(shù)就可以了媒至。如果獲得的物品在背包中不存在或疊加數(shù)已滿顶别,且沒有剩余的格子則返回背包已滿的提示。
再復(fù)雜一些的背包是筋夏,有一些特殊的物品蒂胞,比如裝備图呢,裝備一般都是可以鑲嵌寶石的,這樣的話每個(gè)裝備的id是不能相同的骗随,即使是同一件名字一樣的裝備蛤织,它也要有一個(gè)唯一標(biāo)識(shí)的id。這樣就需要我們?cè)诜湃胛锲返臅r(shí)候給物品生成一個(gè)唯一的id標(biāo)識(shí)鸿染。生成唯一id的算法之前也介紹過指蚜,可以參考:http://www.youxijishu.com/h-nd-147-0_35.html(游戲服務(wù)器生成全局唯一ID的幾種方法)但是這些方法感覺用在生成背包物品唯一id上有點(diǎn)大材小用了。我們?cè)偬峁┮粋€(gè)方法涨椒,以供參考:
唯一id用一個(gè)long類型存儲(chǔ)摊鸡,long類型有64位,我們使用它的低32位存儲(chǔ)策劃配置的物品表中的物品id蚕冬,高32用來記錄每獲得一個(gè)物品就自增加1的序列order免猾,即
Int itemBaseId = 10001;//配置表中的物品id
Int order = 1;//每獲得一個(gè)物品這個(gè)序列自增加一,每個(gè)游戲背包都有自己的order囤热,這樣可以減少并發(fā)對(duì)order的增加猎提。
Long itemUid =(((long)order)<< 32)+ (long)itemBaseId;
那么這個(gè)order怎么記錄呢旁蔼?這個(gè)order不用記錄锨苏,那么當(dāng)玩家退出后再進(jìn)入游戲怎么得到這個(gè)order呢?我們?cè)谕婕业顷憰r(shí)第一次初始化游戲背包時(shí)棺聊,只需要從每個(gè)itemUid中拿出來每個(gè)物品的order伞租,然后比較一個(gè),得到最大的order做為起始o(jì)rder即可限佩。這樣可以從一個(gè)itemBaseId中獲得一個(gè)order:
Int order = itemUid >>> 32;
而那些可以疊加肯夏,不需要唯一id的物品,只需要把它們的配置id轉(zhuǎn)化為long存儲(chǔ)即可犀暑。
這樣在內(nèi)存中驯击,我們可以把所有的物品放入一個(gè)Hashmap中,獲得新物品和使用物品也不用遍歷查找耐亏,速度很快徊都。
更為復(fù)雜的背包广辰,就是需要記錄物品在背包中的位置索引暇矫。一般這樣的游戲背包都會(huì)帶物品的位置交換和整理功能主之。這種背包麻煩的是那些可以疊加的物品,因?yàn)橥粋€(gè)物品可能會(huì)占多個(gè)格子李根,而且還不連續(xù)槽奕。
我們還利用上面第二種背包的唯一id方式,不過這里會(huì)多增加一個(gè)物品在背包中的位置索引房轿,唯一id還是long類型粤攒,而long是由:orderId +位置索引+物品配置id組成。
比如:高25位為order囱持,中間10位為位置索引(一個(gè)背包有一千多個(gè)物品也差不多了)夯接,剩余的29位存儲(chǔ)物品的配置id,這些位數(shù)可以根據(jù)實(shí)際需要自己調(diào)整纷妆。
在內(nèi)存中盔几,我們用一個(gè)數(shù)組來存儲(chǔ)所有的物品,每個(gè)物品占一個(gè)格子掩幢,數(shù)組索引即物品的位置索引逊拍。當(dāng)獲取一個(gè)新物品的時(shí)候,如果這個(gè)物品是不可疊加的际邻,直接遍歷數(shù)組芯丧,找一個(gè)空位置,利用這個(gè)索引和order枯怖,物品的配置id組成一個(gè)唯一的id放入即可注整。如果這個(gè)物品是可疊加的,需要用數(shù)組的0索引到最大索引和物品配置id一一組成唯一id查找對(duì)應(yīng)的物品對(duì)象度硝,找到之后判斷是否疊加已達(dá)最大數(shù)肿轨,如果已達(dá)到,直接找個(gè)空格子放入蕊程,如果沒有達(dá)到椒袍,直接更新數(shù)量,更新完數(shù)理再判斷是否達(dá)到最大疊加數(shù)藻茂,如果達(dá)到了驹暑,需要把多余的再占一個(gè)格子。
在使用物品的時(shí)候辨赐,客戶端傳過來這個(gè)物品的唯一id优俘,我們就能拿到它的數(shù)組索引,直接操作即可掀序。這里還有個(gè)問題帆焕,就是在使用前可能需要判斷是否足夠,如果只用一個(gè)數(shù)組的話不恭,需要遍歷數(shù)組叶雹,計(jì)算這個(gè)物品的總數(shù)量财饥。如果不想遍歷的話,可以另外再加一個(gè)Hashmap折晦,存儲(chǔ)一個(gè)可疊加物品的總數(shù)量钥星,即key物品配置id,value為當(dāng)前這個(gè)物品的總數(shù)量满着。這樣判斷是否足夠的時(shí)候就可以直接判斷了谦炒。
目前最常見的就是這三種類型的游戲背包了,我在網(wǎng)上還看到有的設(shè)計(jì)是一個(gè)物品要占多個(gè)格子漓滔,這樣的背包做的時(shí)候再考慮怎么設(shè)計(jì)吧编饺。
在游戲背包中乖篷,還可能遇到一種情況响驴,就是有些特殊物品,比如某個(gè)寶石撕蔼,當(dāng)把這個(gè)寶石鑲嵌到裝備上豁鲤,會(huì)額外增加這個(gè)裝備的屬性加成。但是具體增加多少鲸沮,是在獲取寶石的時(shí)候琳骡,根據(jù)一定算法隨機(jī)出來的,而且影響幾個(gè)屬性也是隨機(jī)的讼溺。一般來說一旦隨機(jī)之后楣号,這些屬性加成就不會(huì)再變化了,也就是說不會(huì)再更新了怒坯。那么在背包中我們就可以增加一個(gè)字段炫狱,存儲(chǔ)這些數(shù)據(jù),這些數(shù)據(jù)可以是一個(gè)單獨(dú)的對(duì)象剔猿,然后序列化為byte[]存儲(chǔ)到數(shù)據(jù)庫的blob中视译,可是把這個(gè)對(duì)象轉(zhuǎn)為json直接到text中。
這樣就可以任意添加多個(gè)屬性數(shù)據(jù)归敬,而不用修改數(shù)據(jù)庫各代碼了酷含。物品背包就可以統(tǒng)一管理了。