开头
根据原来项目的商店和需求整合了商城系统,记述下开发的思路
需求
普通的商店功能,但为了后续更有效的添加商店,做了优化处理
数据结构
数据库结构异常简单,其实在初始化的时候加载数据
功能开发
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数据就行了