通過Reworld中的時間戳寫一個計時器,讓計時更精準

運行環境

Win7,Win8,Win10 win64

Reworld版本 體驗版

 

針對零基礎讀者的補充

下載安裝 Reworld對應版本

Reworld官網鏈接:http://www.reworlder.com/

下載後安裝後註冊賬號打開空地圖

思路分析

    時間戳實現思路分爲三個部分:首先,獲取當前時間和要計時爲止的時間,然後轉化爲時間戳;其次,在當前時間與到達時間做差值,求得CD時間的時間戳差;最後,把求得的時間差轉換爲時間日期格式,在Update函數中進行計算與時間文本字符的賦值。其中有兩個難點:第一點,時間戳與日期的轉換,時間戳轉換爲具體某一天,某時的換算。第二點,要把時間戳的差值轉爲日期格式,明白os.time()與os.date()的用法。

功能效果展示

 

引入用例

    相信大家通過教學視頻和一些項目,都已經瞭解過Lua裏面的協程(coroutine),簡單的等待觸發是用wait()來控制一段時間後再繼續執行的。下面是用協程的例子:

function TestFun()

    print("我是重小啓")

end

 

Players.PlayerAdded:Connect(function(Uid)

    coroutine.start(function()

        print("角色生成了")

    wait(3)

    TestFun()

    end)

end)

 

   上面的Players裏面有一個PlayerAdded事件,是角色生成的時候調用執行,整體邏輯就是在角色生成後輸出“角色生成了”,3秒鐘以後,執行TestFun方法,輸出:我是重小啓。

但是當程序中出現多個攜程的時候,停止協程可能會導致程序錯誤。所以上面的計時器適用於時間較短週期短的倒計時。那麼我就引入了時間戳倒計時

 

一、時間戳介紹

時間戳是什麼呢?在寫製作步驟之前,先簡短介紹一下時間戳:百度給的定義是:“一個能表示一份數據在某個特定時間之前已經存在的、 完整的、 可驗證的數據,通常是一個字符序列,唯一地標識某一刻的時間。”

那麼時間戳是一個字符序列,下面我們一起探究時間戳!首先我打印一下時間戳:

Players.PlayerAdded:Connect(function(Uid)

    player = Players:GetPlayerByUserId(Uid)

    print(os.time())    --本地系統的時間戳

end)

下面是編輯器運行的結果:

沒接觸過時間戳的人會有疑問,(1560501534)這串數字是什麼?代表了什麼時間?其實我們可以通過百度搜索“時間戳在線轉換工具”進行轉換(打開轉換工具——>輸入時間戳——>得到具體時間日期)。

上面就是時間戳轉換爲具體時間的流程。1560501534 = 2019-06-14 16:38:54

如此一來,大家都明白了吧!但是每次都通過瀏覽器獲得時間,那也太麻煩了!我告訴大家通過代碼獲取時間戳裏面的日期:

Players.PlayerAdded:Connect(function(Uid)

    player = Players:GetPlayerByUserId(Uid)

    print("這是年: " .. os.date("%y",os.time()) .. 

    "這是月: " .. os.date("%m",os.time()).. 

    "這是日: " .. os.date("%d",os.time()))

    print("這是時: " .. os.date("%H",os.time()) .. 

    "這是分: " .. os.date("%M",os.time()).. 

    "這是秒: " .. os.date("%S",os.time())) 

end)

上面代碼裏,os.date()函數是時間戳轉換日期方法,下面是運行結果:

將詳細的日期打印了下來,那麼知道了現在的時間戳如何獲得明天的時間戳呢?想必大家已經知道了,就是通過將日期+1,得到的就是明天的時間戳。下面進行測試:

Players.PlayerAdded:Connect(function(Uid)

    player = Players:GetPlayerByUserId(Uid)

    print(os.date("%d",os.time()))

    local CurrentTimer = os.time({day=os.date("%d",os.time())+1,         --日期+1操作

    month=os.date("%m",os.time()), year=os.date("%Y",os.time()), 

    hour=os.date("%H",os.time()), min=os.date("%M",os.time()), 

    sec=os.date("%S",os.time())});

    print(os.date("%d",CurrentTimer))

end)

下面是運行結果

可以看到,兩個日期相差一天。所以終於給倒計時提供了一個思路:用時間戳的差值得到相差的時間戳,再轉換爲具體時間。

好了時間戳介紹完了,下面是時間戳倒計時的具體步驟:

二、創建服務器腳本並定義變量

首先在服務器邏輯裏面創建服務器腳本:

然後打開腳本,創建倒計時所需要的變量:

local workMin = 0            --分鐘

local workSec = 0            --秒鐘

local CurrentTimer = 0            --未來時間的倒計時

local TotalTime = 5            --CD總時間

local StartTimeCount = 0        --開始計時的時間戳

local Hero                    --角色

PlayerInfo = {}

PlayerInfo.PlayerID = 0            --角色Id

 

 

Players.PlayerAdded:Connect(function(Uid)

    PlayerInfo.PlayerID = Uid

    Hero = Players:GetPlayerByUserId(PlayerInfo.PlayerID)

 

三、編寫倒計時邏輯

倒計時是需要實時去執行的,所以寫在update裏面,下面是代碼:

GameRun.Update:Connect(function()

        --判斷時間戳是否已經賦值

    if StartTimeCount ~= 0 then

            --設置將來的時間

        CurrentTimer = os.time({day=os.date("%d",StartTimeCount), month=os.date("%m",StartTimeCount), year=os.date("%Y",StartTimeCount), hour=os.date("%H",StartTimeCount), min=os.date("%M",StartTimeCount), sec=os.date("%S",StartTimeCount)+TotalTime});     

        local PeriordTimer = CurrentTimer - StartTimeCount

        workMin = os.date("%M",CurrentTimer - os.time())

        workSec = os.date("%S",CurrentTimer - os.time())

        --做差值,得到要倒計時的時間與現在時間戳的差

        local alltime = PeriordTimer - ( os.time()-StartTimeCount)

        if alltime <= 0 then

            alltime = 0

            a= a+1

            if a == 1 then

                PlayerInfo.MatchState = false

                PlayerInfo.HideState = true

            end

            if a == 2 then

                PlayerInfo.HideState = false

                PlayerInfo.StartGame = true

            end

            if a == 3 then

                PlayerInfo.StartGame = false

            end

            if a == 4 then

                print("----end----")

            end

        end

        --將時間戳格式化爲時間格式

        local second = tonumber(workSec)

        local mint = tonumber(workMin)

        local hour = math.floor(alltime / 60 /60);

        if alltime <= 0 then            

            hour = 0;

            mint = 0;

        end

        if  mint < 10 then

            mint = '0'..mint

        end

        if hour < 10 then

            hour = '0'..hour

        end

        if second < 10 then

            second = '0'..second

        end

        --得到時間格式的倒計時(我們要顯示的倒計時文字)

        local temptime = tostring(hour).. ":" ..tostring(mint).. ":" ..tostring(second)

        if PlayerInfo.MatchState then

                --發送消息給客戶端進行顯示

            MessageEvent.FireClient(PlayerInfo.PlayerID,"Timer",temptime)

        end

    end

end)

 

--匹配設置開始時間

MessageEvent.ServerEventCallBack("StartMatch"):Connect(function()

    StartTimeCount = os.time()

    PlayerInfo.MatchState = true

end)

上面的時間戳倒計時中 temptime就是一串字符:00:00:05 ,可以直接賦值到Text文本中。當然如果想讓倒計時更加的精準,不受本地時間的影響就要獲取到服務器的時間戳,這樣就能保證客戶端與服務器的計時是一致的。

四、創建客戶端腳本,給UI賦值

我用到的UI是編輯器上給定的UI,下面是我的UI層級邏輯和客戶端腳本創建位置:

 

UI的“具體時間”文本框就是我們要顯示的倒計時文字,剛剛在服務器腳本已經得到倒計時的文字了,只要在客戶端腳本中接收然後給文本複製就可以了,下面是代碼:

local MoonPic = GameUI.時間顯示.時間.月亮

local SunPic = GameUI.時間顯示.時間.太陽

 

 

--匹配倒計時

MessageEvent.ClientEventCallBack("Timer"):Connect(function(time)

    GameUI.時間顯示.IsVisable = true

    if tonumber(os.date("%H",os.time())) >= 17 then

        MoonPic.IsVisable = true

        SunPic.IsVisable = false

    else

        MoonPic.IsVisable = false

        SunPic.IsVisable = true

    end

    GameUI.時間顯示.時間.時間文字.具體時間.Text = time

    GameUI.時間顯示.時間.時間文字.文本控件.Text = "匹配倒計時"

end)

所以,只要把temptime賦值給具體時間的文本控件即可。

五、設置開始倒計時的時間

我們是點擊匹配按鈕,開始倒計時,所以只要在點擊按鈕的時候,把StartTimeCount賦值爲當前時間的時間戳即可,下面是匹配按鈕UI層級和客戶端腳本的代碼:

local MatchBtn = GameUI.MatchingPanel.MatchBtn

 

 

--點擊匹配

MatchBtn.OnClick:Connect(function()

        --發送給服務器消息

    MessageEvent.FireServer("StartMatch")

    MatchBtn.IsVisable = false

    GameUI.跳躍.IsVisable = false

end)

大功告成,運行後顯示結果如下:

上面的月亮圖片是根據時間的小時來判斷的,如果當前時間的小時>17,也就是晚於晚上5點,我就判斷爲晚上,顯示月亮反之則顯示太陽。“00:00:04”就是我們要得到的倒計時,很精準。

如果想重置計時時間可以把StartTimeCount重新賦值爲os.time(),這樣就能重新去CD了。改動CD時間的話就改動TotalTime。

以上便是我的分享,希望時間戳倒計時可以幫到各位朋友,喜歡的童鞋記得關注哦~

六、補充說明

1.什麼是客戶端腳本?

只會在客戶端執行的腳本,執行的邏輯和表現也只會在本地客戶端展現;可在以下幾個文件目錄下自動執行,客戶端腳本在工作區下不會自動執行,需要放在以下對象裏面: 

1. 客戶端最先加載 。
2. 工作區中的角色模型玩家初始化中的角色初始化腳本,在運行後會自動移動到角色模型下。 
3. 玩家列表中的玩家玩家初始化中的玩家初始化腳本,在運行後會自動移動到玩家下 
4. 玩家玩家界面界面初始化的腳本,在運行後會自動移動到玩家界面下。 
5. 玩家的揹包,例如工具裏面的

2.爲什麼要使用客戶端腳本?

2D平面UI是隻在客戶端存在並加載的,在服務器是沒有2D平面UI的實體對象的,所以只能客戶端腳本來對2D平面UI的信息進行更新修改。其他這種只在客戶端存在的實體對象還有攝像機、鼠標、鍵盤等。

3.什麼是服務器邏輯?

服務對象。 

此服務下的腳本會在服務器上運行,用於放置服務器端遊戲邏輯 。

不可創建。

不能用RWObject.Create()函數創建此對象。

不可刪除。 

不能用Destroy()函數刪除此對象。

不可複製。 

不能用Clone()函數複製此對象。

4.什麼是服務器腳本?

   只會在服務器運行的Lua腳本代碼,用於編寫服務器邏輯。

5.爲什麼要使用服務器腳本?

   計時功能適用於單人和多人等不同環境,所以採用通用的服務器腳本。

  1. 服務器腳本與客戶端腳本不同,客戶端執行的操作只有本地客戶端,也就是玩家自己有效。而服務器執行的操作不僅針對單人有效,還針對與服務器相連的所有客戶端同步生效。
  2. 在多人遊戲中,如果這個對象的變化是針對一個人的,必須在客戶端腳本進行編寫;如果這個對象的變化是針對所有人的,那就必須在服務器腳本進行編寫。
  3. 對於只能在客戶端腳本修改的對象,如何讓服務器知曉變化結果是很重要的。這裏採用傳統遊戲的製作流程,也就是在客戶端進行修改,把修改後的結果通過與服務器通信的方式發送到服務器,再通過服務器進行邏輯運算,把執行結果再同步給所有客戶端。

6.什麼是文本控件?

圖像控件顯示非交互圖像,經常用於裝飾或者圖標使用。

7.什麼是按鈕控件?

按鈕控件用於響應來自用戶的事件,經常用於啓動或者確認某項操作使用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章