【游戏客户端】大话slg玩法架构(三)建筑控件
大家好,我是Lampard家杰~~ 今天我们继续给大家分享SLG玩法的实现架构,关于SLG玩法的介绍可以参考这篇上一篇文章:【游戏客户端】制作率土之滨Like玩法
PS:和之前一样,本文也只是分享实现思路,并不会贴具体的代码和资源哟
(一)架构总览
SLG玩法的实现思路可以划分为四个部分,分别是滚动容器基类的搭建,背景大地图的实现,建筑的生成与刷新,以及玩法优化预加载相关
上一篇文章我们分享了背景大地图的实现:【游戏客户端】大话slg玩法架构(二)背景地图,现在我们接着分享玩法的重中之重!!!建筑控件的实现逻辑
(二)建筑控件的实现
(1)控件的结构
建筑是玩法中的核心逻辑,玩法就呈现在每一个建筑的UI上。因此整理好一个建筑控件的展示结构与层级关系是很有必要的
比如帮派纷争设计的建筑层级就是:建筑状态底板(我方=蓝色,敌方=红色,中立=白色) < 建筑纹理 < 建筑UI(名字,坐标,头像等) < 交互按钮(如分享,战报) < 特效表现 (战斗中,免战状态等)
BUILD_PRIORITY = {BG = 1,TEXTURE = 2,UI_NODE = 3,BUTTON = 4EFFECT = 5,
}
其中建筑UI内容也有需要,它们也需要细分一个显示层级,因此可以先往建筑上挂一个UINode,然后把建筑UI挂在这个节点上再细分即可
(2)控件的生成逻辑
和大地图一样,首先第一步要知道这个控件生成出来之后要摆放到哪里。帮派纷争是一个77 * 77的小型slg玩法,那么我们将会有77 * 77个建筑位置。
每一个位置的建筑我们都可以通过接口计算出它在滚动容器上的坐标
function getPosById(Idx, Idy)-- BG_WIDTH = 大地图宽度-- BG_HEIGHT = 大地图高度-- BG_NUM = 每一行/列的地图块数量local PosX = (BG_WIDTH / 2) * (Idx + Idy - 1)local PosY = (Idy - Idx + BG_NUM) * (BG_HEIGHT / 2)return PosX, PosY
end
我们可以用一个Table去存生成的建筑对象,如果是1*1的数据(如下图)我们就可以直接赋值BuildMap[2][2] = 生成的建筑对象
如果是X * X的建筑,我们会把建筑对象记录左下角的坐标,如下图BuildMap[10][13] = 生成的建筑对象。那其余的位置怎么办呢?很简单,我们可以标识一个特殊的建筑类型--阻碍建筑,把其余八个位置标记为阻碍,玩家就不能迁城进攻到这些地方来了
(3)控件的数据获取
这是一个多人的实时同屏的玩法,因此建筑的所有数据(等级,占领状态等)都依赖服务端进行下发
把所有的数据一条协议下来那肯定是不科学的,我们用不上那么多数据,而且数据量太多协议肯定是顶不住。因此我们可以采取AOI的方式,根据目前所视的地图位置请求一定范围的建筑数据
比如目前所示的视野中心是(8,14),我们只需要请求以(8,14)为原点,半径为5的建筑数据(当然可以预留一些避免滑动时穿帮)。并且我们可以在滚动的时候设置监听事件,如果滑动距离超过一定阈值,那么我们就再次请求数据
PS:视野中心需要根据滚动容器InnerContainer当前所在位置进行换算,半径也需要根据不同机型的分辨率进行计算
此时有一个好奇的朋友就会问了,如果我生成建筑的时候,建筑数据还没回来怎么办呢?
这个很简单哈,只需要把返回的服务端数据缓存起来!!在数据回来的时候判断一下该位置的建筑生成了没有,如果没生成那么不用管它,它自然会从缓存中读取正确的数据。如果发现已经生成了,那也不要慌,同样先把数据缓存起来,然后执行一下那个建筑对象的update方法让其更新即可~~
(4)控件的刷新逻辑
和地图块一样我们不会生成所有的建筑。同样采取控件缓冲池的方式,在进游戏前先生成一堆建筑对象,然后根据目前所示的位置,更新建筑对象的信息以及位置摆放。从而使极限的建筑数量从77*77 转化为两三百个
-- 释放
for x = 1, 77 dofor y = 1, 77 dolocal IsInView = 判断一下这一块建筑需不需要显示if not IsInView and self.BuildMap[x][y] thenlocal Build = self.BuildMap[x][y]Build:setFree()self.BuildMap[x][y] = nilendend
end-- 生成
for x = 1, 77 dofor y = 1, 77 dolocal IsInView = 判断一下这一块建筑需不需要显示if IsInView thenif self.BuildMap[x][y] then-- 存在这个建筑就设置可视就行local Build = self.BuildMap[x][y]Build:setVisible(true)else-- 不存在则找一个空闲的建筑控件重设信息local Build = getFreeBuild()self.BuildMap[x][y] = Build Build:resetInfo(x, y)endendend
end
这里需要注意的是,getFreeBuild的时候,由于玩家可能会疯狂拖动导致建筑对象setFree不及时,那么就可能造成读取不到空闲的建筑对象,因此需要做一个保底处理,如果读不到的时候生成一个新的,然后塞进去缓冲池中即可
除了玩家的操作导致需要刷新建筑,还有可能其他人进行了操作,服务端需要同步最新的结果来更新显示。此时我们只需要和上文一样,在服务端下发新建筑数据时进行判定,有则更新,无则缓存即可
好啦~~建筑的生成介绍大概就到这里,下一篇文章会介绍这个玩法的预加载相关
感谢阅读,记得点赞和关注!!!