我目前正在制作一个时间系统,在那个系统中,我希望能够控制SUNRISE在哪个时间开始,DAY开始,SUNSET开始和NIGHT开始。目前在系统中这是可能的,当“时钟”到达下一个开始时间时,我开始一个Coroutine开始旋转太阳和月亮。
我的协程看起来像这样:
IEnumerator RotateSun(Vector3 fDegrees, float SecondsDuringTimeSet)
{
Quaternion quaFromPosition = _lSunLight.transform.rotation;
Quaternion quaToPostion = Quaternion.Euler(fDegrees);
for (float t = 0.0f; t < 1; t += Time.deltaTime / SecondsDuringTimeSet)
{
_lSunLight.transform.rotation = Quaternion.Lerp(quaFromPosition, quaToPostion, t);
yield return null;
}
}
正如你所看到的那样,每次运行它都会将值传递给它。这是这样做的:
if (_fCurrGameHour == _fTimeStartSunrise && _bMoveSunAndMoonOnlyOnce == true)
{
// Which TIMESET should it be:
_en_CurrTimeSet = TimeSet.SUNRISE;
// How long should the SUN move and how many which degree should it reach before that time ends
vec3MoveSun = new Vector3(10.0f, 0, 0);
StartCoroutine(RotateSun(vec3MoveSun, _fConvertSunriseToGTSeconds));
// How long should the MOON move and how many which degree should it reach before that time ends
vec3MoveMoon = new Vector3(180.0f, 0, 0);
StartCoroutine(RotateMoon(vec3MoveMoon, _fConvertSunriseToGTSeconds));
// Tell bool that we don't need to move the sun and moon more then once
_bMoveSunAndMoonOnlyOnce = false;
}
正如我写的那样,这个系统目前正在运作。然而,它是一种静态系统。所以目前我需要确保游戏的开始时间是日出时间。否则我的协程会破坏,因为它不会在白天开始时间之前旋转到正确的位置。我绝对不会在接近日落的情况下开始游戏,然后太阳以完全错误的方式旋转,因为它接近旋转错误的方式然后(我假设)。
所以我的第一个问题是:我能以某种方式使系统更具活力吗?我希望能够在不同的季节中确定SUNRISE,DAY,SUNSET和NIGHT应该在哪个时间开始,例如我可以在我的日子里有不同的长度。我希望能够在游戏中改变这些时间,然后如果SUNSET稍后会被设置,太阳会开始旋转一点点,因为它应该花更长的时间才能到达它的SUNSET位置。
在我的第二个问题上:是否也可以重写我的协程,这样我就可以在任何我需要的时间开始游戏,太阳仍然会以正确的旋转度开始?
太阳将始终设置为相同的旋转(170度)并以相同的旋转(350度)上升。我只想控制它到达那些旋转所需的时间。也许我可以以某种方式将其移至我的更新阶段而不是使用Coroutine?我不知道如何在我的系统中更改这个,所以如果有人有任何想法。请帮忙。
答案 0 :(得分:1)
您可以使用State设计模式远离协程。
public int SunRise = 8;
public int SunSet = 15;
public Quaternion RiseRotation;
public Quaternion SetRotation;
public int StartHour = 8;
float time; // our time on a 24 hr system
bool wasSun; // what was our previous state?
void Start()
{
GoToHour(StartHour);
ToggleState(IsSun());
}
void Update()
{
bool isSun = IsSun();
if (isSun != wasSun)
ToggleState(isSun);
time = (time + Time.deltaTime) % 24; // wrap at 24 hrs back to 0
if (isSun)
UpdateSun();
else
UpdateMoon();
}
bool IsSun()
{
return time >= SunRise && time < SunSet
}
void UpdateSun()
{
float t = (time - SunRise) / (SunSet - SunRise);
UpdateRotation(_lSunLight.transform, RiseRotation, SetRotation, t);
}
void UpdateMoon()
{
float t;
if (time >= SunRise)
t = time - SunRise;
else
t = time + (24 - SunSet);
t = t / ((24 - SunSet) + SunRise));
UpdateRotation(_lMoonLight.transform, RiseRotation, SetRotation, t);
}
void GoToHour(int hour)
{
t = hour / 24;
}
void ToggleState(bool isSun)
{
if (isSun)
{
// Custom logic here, turn on sun, turn off moon?
}
else
{
// Custom logic here, turn on moon, turn off sun?
}
wasSun = isSun;
}
static void SetRotation(Transform target, Quaternion start, Quaternion end, float t)
{
target.rotation = Quaternion.Lerp(start, end, t);
}
完全未经测试的代码,但这是如何使用类更新太阳或月亮的基本想法。这是一个二进制实现,所以太阳正在显示,或月亮。如果你想要重叠,你当然可以自定义它。你会想要月亮升起和月亮设置的不同时间,然后如果/月亮和太阳更新则不会。
代码也是非常基本的并且做了很多假设(日出从不与24小时标记重叠。)所有这些都可以清理。您还可以创建变量来存储每帧完成的计算(关于日出/设置的持续时间),由您自行决定。如果你想这样做,只需在GoToHour方法中设置它。
SetRotation不是超级必要的,但它可以保持代码清洁。如果您以后决定要使用Quaternion.Slerp,则只需在一个地方更改它。
我在检查器中暴露了Quaternions,你可能只使用浮点数或Euler Vecter3。如果你这样做,你可以在开始时进行转换。
我希望这能回答你所有的问题,如果没有,请随时澄清没有回答的问题。