游戏商店系统

news/2024/11/29 4:41:42/

开头

根据原来项目的商店和需求整合了商城系统,记述下开发的思路

需求

普通的商店功能,但为了后续更有效的添加商店,做了优化处理

数据结构

数据库结构异常简单,其实在初始化的时候加载数据

功能开发

1.数据初始化管理

function StorePlug:Init()for k,v in pairs(StoreConfig.Config) do local store = Store.new(self.player)local storeId = v.typeif not self.cache[storeId] thenself.cache[storeId] = {}endstore:Init(storeId, self.cache[storeId])self.storeList[storeId] = storeend
end

self.cache 读取数据库store数据,StoreConfig配置好商店列表对应storeid

function Store:Init(storeId, InitData)--debuglua_app.log_debug("Store:Init", storeId)self.storeId = storeIdself.goodsRecords = InitData.goodsRecords or {}self.updatetime = InitData.updatetime or 0
end

storeplug为商店管理类,store商店实体类,goodsrecords储存购买物品id和数量。

2.物品购买

这是商城系统最重要的部分,但其实并不难。

1.购买传商店storeid,物品id和数量num,获取store实体类数据

--购买物品
function StorePlug:Buy(storeId, id, num)-- debuglua_app.log_debug("StorePlug:Buy", storeId, id, num)if not num or num == 0 thennum =1endlocal store = self.storeList[storeId]if not store thenreturn falseendif not self:CheckBuy(storeId, id, num) thenreturn falseend--通用商店newreturn store:Buy(id, num)
end

2.读取商店配置,验证判定并保存数据

function Store:Buy(id, num)--debuglua_app.log_debug("Store:Buy", id, num)local cfg = self:GoodsRecordsConfig(id)if not self.player.bag:PutNewItemIn(cfg.item.item, cfg.item.count * num) thenserver.sendErr(self.player, "can't put into bag")return falseendlocal pricecount = cfg.price.count--判断是否存在折扣if self.storeId == StoreConfig.StoreType.LuckyShop thenpricecount = getPrice(self.storeId,id,pricecount)elseif cfg.discount thenpricecount = pricecount * cfg.discountendself.player:PayReward(cfg.price.type,cfg.price.id,pricecount * num,BaseConfig.YuanbaoRecordType.Store,"商店购买")self:SetGoodsRecordsCount(id, num)local data = self:GetMsgData()self:_SendPlayerToClient(data)--debuglua_app.log_debug("Store:Buy", "success")return true
endStoreConfig.Config = {{type = 1,cfg = "LuckyShopConfig",storeType = "LuckyShop",limitType = 4}, {type = 2,cfg = "MallConfig",storeType = "MallStore",limitType = 2},
}

StoreConfig读取storeid对应的商店配置名称,购买验证判定其实放在Store类更好

function Store:GoodsRecordsConfig(id)local cfg = StoreConfig.Config[self.storeId].cfgreturn server.configCenter[cfg][id]
end--验证购买条件
function StorePlug:CheckBuy(storeId,id, count)local store = self.storeList[storeId]local cfg = store:GoodsRecordsConfig(id)if not cfg thenserver.sendErr(self.player, "error cfgid")return falseend-- 如果限购,检查数量 默认为1if cfg.limit thenlocal limitcount = 1if cfg.num thenlimitcount = tonumber(cfg.num)end	if store:GetGoodsRecordsCount(id) + count > limitcount thenserver.sendErr(self.player, "overflow limitcount")return falseendend-- 检查等级if cfg.level thenif self.player.cache.level < cfg.level thenserver.sendErr(self.player, "not enough level")return falseendend-- 检查时间if cfg.time thenif lua_app.now() < getTimeStamp(cfg.time[1]) or lua_app.now() > getTimeStamp(cfg.time[2]) thenserver.sendErr(self.player, "error time")return falseendend-- 检查钱if not self.player:CheckReward(cfg.price.type, cfg.price.id, cfg.price.value) thenserver.sendErr(self.player, "not enough money")return falseend-- 检查背包if self.player.bag:GetBagEmptyCount() <= 0 thenserver.sendErr(self.player, "bag full")return falseendreturn true
end

3.物品管理功能

根据条件分为每日每周和后续添加的12小时重置购买次数,重置类型依然配置的StoreConfig中

-- TODO:HJ player实现接口后调用这里
function StorePlug:onDayTimer()for _, store in pairs(self.storeList) dostore:onDayReset()end
endfunction Store:onDayReset()self:_ResetgoodsRecords(StoreConfig.LimitType.DayLimit)
endfunction Store:onHalfHour()if StoreConfig.Config[self.storeId].limitType == StoreConfig.LimitType.HalfDayLimit thenif lua_util.isfresh(self.updatetime) thenself:_ResetgoodsRecords(StoreConfig.LimitType.HalfDayLimit)endend
endfunction Store:onWeekReset()self:_ResetgoodsRecords(StoreConfig.LimitType.WeekLimit)
endfunction Store:_ResetgoodsRecords(limitType)--商店购买数据刷新for goodsid, data in pairs(self.goodsRecords) dolocal cfg = self:GoodsRecordsConfig(goodsid)if cfg.limit.type == limitType thendata.count = 0endendself.uptime = lua_app.now()local data = self:GetMsgData()self:_SendPlayerToClient(data)
end

4.推送数据给客户端

1.初始化推送全部商城数据

function StorePlug:onInitClient()--初始化商店信息for k,store in pairs(self.storeList) do store:onInitClient()end--初始化玩家购买信息local datas = {}for _, store in pairs(self.storeList) dolocal data = store:GetMsgData()table.insert(datas, data)endserver.sendReq(self.player,"sc_store_play_update",{storedatas = datas})
end

2.购买推送商店数据

function Store:_SendPlayerToClient(data)--玩家购买物品信息local datas = {}table.insert(datas, data)server.sendReq(self.player,"sc_store_play_update",{storedatas = datas})
end

3.协议数据结构

#store
.store_goods_data {id          0 : integerbuyCount    1 : integer 
}.store_buy_data {storeId     0 : integer		goods       1 : *store_goods_data  
}

5.特殊商店处理

这其实不算商城系统的功能,不过有些商店可能有各种奇怪的要求,下面这个辛运商店实例:

每12小时更新一次商品,玩家数据重置已经做了,不过商店是随机生成配置的部分物品和折扣价

--刷新商店
function LuckyShop:RefreshGoods()local cfg = StoreConfig.Config[self.storeId].cfglocal luckyShopConfig = server.configCenter[cfg]self.data = {}--获取随机id和折扣luckyShopConfig = lua_util.randArray(luckyShopConfig,6)for id, scfg in pairs(luckyShopConfig) doself.data[scfg.id] = {ratio = getRatio(scfg.discount)}	endself.updatetime = lua_app.now()server.settingCenter:SetData(SettingConfig.SettingType.LuckyShop,self.data)self:sendRecordToClient()return true
end

我选择的方式是创建一张全局配置表,每次刷新商店id和折扣率,初始和更新数据也发送给客户端

总体来说商店系统还是比较好做的,只要以后的商店统一配置管理,增加商店添加StoreConfig数据就行了


http://www.ppmy.cn/news/695758.html

相关文章

游戏的商店的设计

前言 商店在我们生活当中很常见的 维基百科 给商店定义: 泛指售卖商品或服务的地方&#xff0c;有零售、批发二类。商店包括有地铺、楼上铺和商场店子、百货公司、专门店等。它们可能是个体户或者连锁式经营。 生活中如果我们开店时需要以下商店的信息分为: 取名类型图片地…

Switch游戏机模型

一&#xff0c;Switch游戏机 1&#xff0c;大家好&#xff0c;我们老样子先放运行的照片放在下面。 2&#xff0c;看到上面的Switch游戏机有没有想快点想拿到源码的感觉&#xff0c;大家不要急&#xff0c;不妨先给我点个赞&#xff0c;如果给个关注那就更好了&#xff0c;谢谢…

redis-单节点安装

daemonize yes port 6379 bind 0.0.0.0 requirepass 123456 save 3600 1 300 100 60 10000dir /usr/local/redis dbfilename dump.rdb logfile redis.log pidfile redis.pid##save 3600 1 300 100 60 10000 ##3600秒(一小时),至少有一个值的话,会进行存盘 ##300秒(五分钟),至少…

C#的问号运算符

?. 运算符&#xff08;Null 条件运算符&#xff09;&#xff1a; 这个运算符用于访问对象的成员&#xff0c;但在对象为空&#xff08;null&#xff09;时不会引发异常。它的语法是 对象?.成员 例如&#xff1a; string name null; int length name?.Length; // 当name…

分布式锁特性

1、互斥性&#xff0c;这个是锁的最基本要求 2、可重入性&#xff0c;同一个线程可以重复多次获得锁 3、支持阻塞、非阻塞两种特性 4、支持锁超时&#xff0c;为了防止线程意外退出&#xff0c;没有正常释放锁&#xff0c;导致其他线程无法正常获取到锁。加锁时间超过一定时…

浪潮之巅(前言)

从今天开始我就在我的博客更新吴军老师浪潮之巅&#xff0c;我花了两个月看完这些对我触动还是很大的&#xff0c;看完吴军老师书可以让我们知道我们所在的历史环境&#xff0c;知道我们所在的位置&#xff0c;知道我们正处在一个伟大的时代&#xff0c;人类的文明飞速的发展&a…

《浪潮之巅》

《浪潮之巅》算是一本硅谷科技公司发展史科普书&#xff0c;大致介绍了每家公司的发展脉络&#xff0c;以及影响发展的重要事件&#xff0c;在数字时代&#xff0c;我们IT行业不可不读的作品。 《浪潮之巅》不只是一本历史书&#xff0c;除了讲述科技企业的发展规律&#xff0…

浅析国际专利和国内专利。

很多人会觉得国际专利和国内专利的概念很难理解。其实国际专利和国内专利并没有我们想象的那么复杂。通过下面的介绍&#xff0c;你可以了解什么是国际专利&#xff0c;什么是国内专利。 首先要先了解专利的“地域性”。所谓地域性&#xff0c;就是专利权的空间限制。是指一个…