时间系统
时间系统的代码逻辑
思路
该部分主要通过两个重要的机制来完成,每秒的阈值和每个时间单位的进制来组合实现,每秒阈值通过使用Unity自带的Times.deltaTime
的累加实现,如果超过该阈值,则进一秒,因此当阈值越低,游戏内的时间流动越快。
而且游戏中时间流逝的进制在设置好以后通过每秒的递增来通过if语句体现
1
2
3
4
|
// 放入settings.cs中便于修改
/*时间控制*/
public const float GameTimeThreshold = 0.1f; // 每秒的时间长度,数值越小时间越快
public const int GameSecondHold = 59, GameMinuteHold = 59, GameHourHold = 23, GameDayHold = 10, GameMonthHold = 12, GameSeasonHold = 3; // 时间的进制
|
利用deltaTime
机制,当计时器超过游戏中每秒的刻度,就增加游戏秒一次,并调用计时函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// TimeManager.cs中的方法
private void Update()
{
if (!_gameClockPause)
{
tikTime += Time.deltaTime;
if (tikTime >= Settings.GameTimeThreshold)
{
tikTime -= Settings.GameTimeThreshold;
UpdateGameTime();
}
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
// TimeManager.cs中的方法
/*时间单位*/
private int _gameSeconds, _gameMinutes, _gameHours, _gameDays, _gameMonth, _gameYears;
/*时间的计数遍历*/
private Season _currentSeason = Season.Spring;
private int _monthInSeason = 3; // 每个季度的月份
private bool _gameClockPause;
private float tikTime; // 计时器
// 每次新开游戏的初始化
private void newGameTime()
{
tikTime = 0f;
_gameClockPause = false;
_gameSeconds = 0;
_gameMinutes = 0;
_gameHours = 0;
_gameDays = 1;
_gameMonth = 1;
_gameYears = 1;
_currentSeason = Season.Spring;
}
/// <summary>
/// 更新游戏时间, 游戏世界的每一秒都要调用一次的函数,
/// </summary>
private void UpdateGameTime()
{
_gameSeconds++;
// 如果累计时间超过了时间的进制单位,则进位
if (_gameSeconds > Settings.GameSecondHold)
{
_gameMinutes++;
_gameSeconds = 0;
if (_gameMinutes > Settings.GameMinuteHold)
{
_gameHours++;
_gameMinutes = 0;
if (_gameHours > Settings.GameHourHold)
{
_gameDays++;
_gameHours = 0;
if (_gameDays > Settings.GameDayHold)
{
_gameMonth++;
_gameDays = 1;
_monthInSeason--;
if (_gameMonth > Settings.GameMonthHold)
_gameMonth = 1;
if (_monthInSeason == 0)
{
_monthInSeason = 3;
int seasonNumber = (int)_currentSeason;
seasonNumber++;
if (seasonNumber > Settings.GameSecondHold)
{
seasonNumber = 0;
_gameYears++;
_gameYears %= 9999;
}
}
}
}
}
}
//
// Debug.Log("now Seconds is :" + _gameSeconds + ":: Minutes is " + _gameMinutes);
}
|
在该函数中,由于每秒刻度为0.1f,也就是说将现实一秒分为了10份,每一份是游戏中的一秒,那么现实世界每6秒相当于游戏内一分钟
构建时间UI
在UI的大Canvas
下构建一个基础的panel
用于构造时间框体,然后不断的在内部增加图片层次。
该方法是先设置一个主要显示内容的图片,然后将需要被显示的图像设置为该图像的子物体,然后对父物体使用Mask组件。而具体需要显示的内容则通过旋转得到
连接时间代码和UI
**思路:**在时间的UI代码中绑定一个UI变化函数,并在时间流逝代码中,每次分钟和小时变化的时候,调用这个事件,从而引起UI的变化;而图标等则通过代码进行变化。
步骤
-
构造UI代码,并建立对应的UI部件
-
定义UI变化的事件,并将事件与UI变化代码绑定
-
在时间变化函数中呼叫事件
-
构造UI代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 在TimeUI.cs中定义使用的所有组件,并绑定信息
public RectTransform dayNightImage;
public RectTransform timeBlockParent;
public Image seasonImg;
public TextMeshProUGUI dateText;
public TextMeshProUGUI timeText;
public Sprite[] seasonSprites;
private List<GameObject> _timeBlocks = new List<GameObject>();
private void Awake()
{
/* 为时间块绑定子物体 */
for (int i = 0; i < timeBlockParent.childCount; i++)
{
_timeBlocks.Add(timeBlockParent.GetChild(i).gameObject);
timeBlockParent.GetChild(i).gameObject.SetActive(false);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// EventHandler.cs
/* 每分钟更新的事件 */
public static event Action<int, int> GameMinuteEvent;
public static void CallGameMinuteEvent(int minute, int hour)
{
GameMinuteEvent?.Invoke(minute, hour);
}
/* 小时和日期更新的事件 */
public static event Action<int, int, int, int, Season> GameDateEvent;
public static void CallGameDateEvent(int hour, int day, int month, int year, Season season)
{
GameDateEvent?.Invoke(hour, day, month, year, season);
}
|
上述函数将在TimeManager.cs
的每分钟更新和每小时更新中进行使用,并且需要保证每次游戏一开始就需要更新,且由于事件是在OnEnable中绑定的,因此一开始的调用只能在Start中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
// 在TimeUI中定义UI变化的函数
private void OnGameDateEvent(int hour, int day, int month, int year, Season season)
{
dateText.text = year.ToString("0000") + "年" + month.ToString("00") + "月" +
day.ToString("00") + "日";
seasonImg.sprite = seasonSprites[(int)season];
SwitchHourBlockImage(hour);
DayNightImageRotate(hour);
}
private void OnGameMinuteEvent(int min ,int hour)
{
timeText.text = hour.ToString("00") + ":" + min.ToString("00");
}
/// <summary>
/// 对时间块进行处理,每四个小时亮一块
/// </summary>
/// <param name="hour"></param>
private void SwitchHourBlockImage(int hour)
{
var index = hour / 4;
for (int i = 0; i < _timeBlocks.Count; i++)
{
if (i < index + 1)
{
_timeBlocks[i].SetActive(true);
}
else
{
_timeBlocks[i].SetActive(false);
}
}
}
/// <summary>
/// 对时间图片进行旋转
/// </summary>
/// <param name="hour"></param>
private void DayNightImageRotate(int hour)
{
var targetRotate = hour * 15 - 90;
dayNightImage.DORotate(new Vector3(0, 0, targetRotate), 1f);
}
|
dayNightImage.DORotate
是DC.Tweening
的函数,用于对图片进行旋转,其第一个参数是旋转的目标位置