Unity实战之类爬塔功能

Posted 爱上游戏开发

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity实战之类爬塔功能相关的知识,希望对你有一定的参考价值。

推荐阅读:

前言

首先,小编在这里给大家道个歉。由于最近被生活折磨得不成人形,在文章输出方面明显能感觉到水的成分,虽然也在持续输出,但是大部分都是转载。
“盼来盼去盼不尽 天涯何处是归鸿”,终于有时间写文章了,来之不易的空闲时间,打算来介绍一下最近做的功能,先来看看成品吧!

功能简介

元朝圣殿,说白了就是一个类爬塔功能。根据星期开启对应类型的爬塔,爬塔按照一层一层的通关要求进行挑战。不可挑战已挑战的,不可跨层挑战。
首先看看主界面:包含帮助按钮,排行榜按钮和中间的5个圣殿。

创建对象,拼接界面如下:

可以发现,main下面的5个对象颜色与其他对象颜色不同,这就是传说中的预制体。

什么是预制体?

简单来说,预制体就是一个模板,你可以使用这个模板来快速生成一个相同的游戏对象,包括游戏对象的所有组件以及其下的所有子游戏对象。像上图中主界面场景那样,
这个预置体包括背景,名字,倒计时。他们长相一样却又有差异,就像双胞胎一样,名字不同,衣服(背景)不同,喜好(倒计时)不同一样。那么,怎么修改他们之间的区别呢?这时候我们
有两种解决办法:
1.直接在功能中替换名字背景
2.代码动态修改
由于策划的需求变幻莫测,推荐大家代码可以控制的表现,都用代码实现,手动在工程中修改真的很辛苦~
那么,接下来介绍一下如何代码动态修改。
首先创建一个table来存储这5个对象的信息:名字,背景,倒计时等

ui.relicsAdven = 
ui.relicsAdven.Item = --RelicsAdvenItem
ui.relicsAdven.ItemTxt = --名字
ui.relicsAdven.ItemBg = --背景
ui.relicsAdven.openTm = --倒计时
ui.isOpen = --标识该神殿是否开启
for i = 1 , 6 do
    ui.relicsAdven.Item[i] = base:findobj("Main/RelicsAdvenItem"..i)
    ui.relicsAdven.ItemTxt[i] = utils.findtext(ui.relicsAdven.Item[i],"relicsName/Text")
    ui.relicsAdven.ItemBg[i] = utils.findimage(ui.relicsAdven.Item[i],"bg")
    ui.relicsAdven.openTm[i] = utils.findtext(ui.relicsAdven.Item[i],"openTm")
    utils.addclickevent(ui.relicsAdven.Item[i],base.ClickPoint,i)
    ui.isOpen[i] = false
end

接下来便是数据填充阶段了

local testData = 
    [1] = name = "光之圣殿",bgImg = "1",openTime = 1,,
    [2] = name = "暗之圣殿",bgImg = "2",openTime = 2,,
    [3] = name = "水之圣殿",bgImg = "3",openTime = 3,,
    [4] = name = "火之圣殿",bgImg = "4",openTime = 4,,
    [5] = name = "风之圣殿",bgImg = "5",openTime = 5,,

local function InitData()
    local tm = os.time()
    GetWeek(tm)
    for i,v in ipairs(testData) do
        ui.relicsAdven.ItemTxt[i].text = v.name
        ui.relicsAdven.ItemBg[i].sprite = utils.loadsprite("relicsadven","relicsadven_00"..v.icon)
        local temp = ""
        for a,b in ipairs(v.openTime) do
            if wday ~= b then
                --未开启
                if temp == "" then
                    temp = b
                else
                    temp = string.format("%s,%s",temp,b)
                end
            end
        end
        if temp == "" then
            --已经开启,倒计时
            isOpen[i] = true
            ui.relicsAdven.ItemBg[i].material = nil
            local tm = GetReaminSecondsTo24()
            if this.coroutine == nil then
                settime(tm,i)
            end
        else
            isOpen[i] = false
            ui.endTm[i] = nil
            ui.relicsAdven.ItemBg[i].material = Asset:LoadAsset(asseturi.getshaderpath("UIGray_Material"))
            ui.relicsAdven.openTm[i].text = string.format("<color=#FF0000>周%s开启</color>",temp)
        end
    end
end

上述代码中有些功能,接下来做简单介绍:

获取当前星期几

1.通过时间戳获取当前是星期几的方法:

local function GetWeek(tm)
    local temp = os.date("*t", tm)
    local wday = temp.wday - 1
end

该方法返回的数据与星期的对应关系如下,因此需要减一:
1:星期天
2:星期一
3:星期二
4:星期三
5:星期四
6:星期五
7:星期六
接下来就是未开启的显示文本处理:
因为测试数据中openTime字段是一个table表,里面可能配有多个星期,需要处理一下数据:
首先创建一个temp变量,用来存储周几开启,如果temp值变了,代表未开启;没变,代表当前已开启
已开启需要显示关闭倒计时:显示倒计时,需要知道剩余时间,剩余时间=结束时间-当前时间。当前时间使用os.time()获取,结束时间为当天晚上13:59:59,那么如何获取当钱距离当天结束的剩余呢?请看下面代码:

距离当前结束倒计时

--获取到当日凌晨的剩余时间 返回秒数
function GetReaminSecondsTo24()
    local toYear=os.date("*t").year
    local toMonth=os.date("*t").month
    local toDay=os.date("*t").day
    local toTime = os.time(year =toYear, month = toMonth, day =toDay, hour =23, min =59, sec = 59)
    local time=os.time()
    return toTime-time  
end

-- 获取到了剩余时时间戳,接下来就是倒计时计时器了,使用协程等待1秒的方式来实现:
local function settime(tm,index) --设置剩余时间
   this.coroutine = coroutine.start(function ()
        while true do
            if this.gameObject == nil then
                return
            end
             if tm < 1 then
                --结束
                ui.openTm[index].text = ui.openTxt[k]
                coroutine.stop(this.coroutine)
                this.coroutine = nil
            else
                tm = tm - 1
                local timedata = FormatTime(tm)
                ui.openTm[index].text = string.format("<color=#00FF00>%s 后关闭</color>",(timedata))
            end
            coroutine.wait(1)
        end 
    end)
end 

说明:当剩余时间<=0时,结束倒计时,协程停止并刷新界面;否则继续倒计时,显示剩余时间。
FormatTime函数:将时间戳转换为xx填xx小时XX分钟XX秒,具体实现如下:

local function second2DHMS(second)
    if second <= 0 then
        return 0,0,0,0
    end
    local d = math.floor(second / 86400)
    second = second - d * 86400

    local h = math.floor(second / 3600)
    second = second - h * 3600

    local m = math.floor(second / 60)
    second = second - m * 60

    local s = second

    return d, h, m, s
end

local function FormatTime(_ls)
    local _d, _h, _m, _s = second2DHMS(_ls)
    local timedata = ""
    if _h < 10 then
        _h = "0".._h
    end
    if _m < 10 then
        _m = "0".._m
    end
    if _s < 10 then
        _s = "0".._s
    end
    if _d > 0 then
        timedata = _d.."天".._h..":".._m..":".._s
    else
        timedata = _h..":".._m..":".._s
    end
    return timedata
end

至此,终于把主界面的显示搞定了,讲得有点详细,具体到了每个小功能的实现。
界面显示完成了,不容易啊。接下来就是界面的点击时间,点击神殿跳转到挑战界面。

选择圣殿

function view.ClickPoint(go,index)
    if not isOpen[index] then
        --未开启
        print(“未开启)
        return
    end
    local data = 
    data.type = index
    --当前已经通过的层数,测试数据
    local currLayer = 0
    data.layerNum = currLayer + 1
    --传数据给挑战界面并打开挑战界面
    relicschallenge:setdata(data)
    relicschallenge:open(nil,true)
end

说明:这两行代码是传数据并打开挑战界面。具体实现方法是由项目框架决定了,读者可以根据自己的实际项目调用自己的方法哦~

挑战界面

relicschallenge:setdata(data)
relicschallenge:open(nil,true)
挑战界面示意图如下:

功能第一版:使用循环列表来实现滑动列表,首先拼UI如下:

该界面为一个活动界面,显示每层的奖励信息及对应可操作按钮
(1)使用循环列表,需在content添加循环列表的计算脚本。如下图:如需使用循环列表脚本,可加群下载,csdn积分下载或者联系小编下载。
使用步骤如下:
1.创建Scroll View组件,在content上添加对应脚本。上下滑动:添加UILayoutVertical脚本;左右滑动:添加UILayoutHorizontal脚本

2.代码控制

    ui.list = base:findcom("bot/Viewport/Content", "UILayout")
    ui.list.onCreate = base.createrender
    ui.list.onUpdate = base.updaterender
    ui.list.ItemRenderer = Asset:LoadAsset(asseturi.getassetpath(base.module, "Item"))

    ui.list.DataCount = #data--item总个数
    ui.list:InvalidateData()

    --创建item
local itemRender =
function base.createrender(go)
    local render = 
    render.num = utils.findtext(go,"num")--层
    itemRender[go] = render
end

--刷新item
function base.updaterender(go, index)
    local config = data[index] --data中放着每个item的数据
    local render = itemRender[go]
    render.num.text = index
end

功能第二版:使用滑动列表
1、创建Scroll View组件,在content上添加对应脚本组件。上下滑动:添加VerticalLayoutGroup脚本;左右滑动:添加HorizontalLayoutGroup脚本
2.代码控制:

ui.content = base:findobj("list/Viewport/Content")
ui.ItemRenderer = Asset:LoadAsset(asseturi.getassetpath(base.module, "Item"))

--生成之前先全部清空再生成
Util.DestroyAllChild(ui.content)
for i=1,#data do
    local go = utils.addchild(ui.content, ui.ItemRenderer)
    local dataInfo = data[i] 
    utils.findtext(go,"num").text = i
end


到此为止,列表滑动已经实现,接下来就是事件的点击了

local function ClickChalleng()
    -- TODO
    --打开布阵界面
end
utils.addclickevent(go,ClickChalleng,i)

后面的功能流程就是:点击挑战,打开布阵界面,布阵完毕,挑战结算等。

排行榜

最后来介绍一下主界面的排行榜功能:
首先拼接ui层级如下:两个按钮对应两个界面。第一个界面为排行榜,第二个界面是对应排名的奖励预览。

最终呈现给用户的效果如下:


界面搭建完了,就开始我们的功能开发吧。
由于排行榜数据瞬息万变,我们不能一上游戏或者是进入该系统时获取排行榜数据,而是在需要显示的时候拿去,这样才能保证以最少的获取次数取到最新的数据。
因此,我们在该系统主界面点击排行榜时,向服务器请求数据,拿到数据我们再显示排行榜界面。

network.request("rankData")

if 返回成功 then
    打开排行榜界面
end

打开排行榜时,除了需要传入排行榜数据,还需要传入一个下标index,标志着打开哪一个标签,传1则代表打开排行榜界面,传2代表打开奖励预览界面。

for k,v in ipairs(ui.tabs)do
    SetActive(ui.pages[k],index == k)
    SetActive(ui.pages[k],index == k)
end

接下来便是显示对应打开页签的数据了。注意,这里的列表,我是用的是前面介绍的循环列表,用法不再累叙

if index == 1 then
    ui.rankRoot.DataCount = #base.data.rankList
    ui.rankRoot:InvalidateData()
elseif index == 2 then
    ui.rewardRoot.DataCount = utils.tablelen(base.data.rewardList)
    ui.rewardRoot:InvalidateData()
end

以上是关于Unity实战之类爬塔功能的主要内容,如果未能解决你的问题,请参考以下文章

unity实战之lua计算某一时间段开始和结束时间戳

Unity3D协同函数与异步加载功能实战 学习

Unity3D手机斗地主游戏开发实战(02)_叫地主功能实现(不定期更新中~~~)

unity工具类篇 unity 计时器

unity工具类篇 unity 计时器

Unity小功能开发实战教程在UI画布上画网格线