運行環境
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.爲什麼要使用服務器腳本?
計時功能適用於單人和多人等不同環境,所以採用通用的服務器腳本。
- 服務器腳本與客戶端腳本不同,客戶端執行的操作只有本地客戶端,也就是玩家自己有效。而服務器執行的操作不僅針對單人有效,還針對與服務器相連的所有客戶端同步生效。
- 在多人遊戲中,如果這個對象的變化是針對一個人的,必須在客戶端腳本進行編寫;如果這個對象的變化是針對所有人的,那就必須在服務器腳本進行編寫。
- 對於只能在客戶端腳本修改的對象,如何讓服務器知曉變化結果是很重要的。這裏採用傳統遊戲的製作流程,也就是在客戶端進行修改,把修改後的結果通過與服務器通信的方式發送到服務器,再通過服務器進行邏輯運算,把執行結果再同步給所有客戶端。
6.什麼是文本控件?
圖像控件顯示非交互圖像,經常用於裝飾或者圖標使用。
7.什麼是按鈕控件?
按鈕控件用於響應來自用戶的事件,經常用於啓動或者確認某項操作使用。