通过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.什么是按钮控件?

按钮控件用于响应来自用户的事件,经常用于启动或者确认某项操作使用。

发布了35 篇原创文章 · 获赞 2 · 访问量 5840

猜你喜欢

转载自blog.csdn.net/weixin_41987154/article/details/100143227
今日推荐