没有协程旋转对象?

时间:2014-05-16 06:09:39

标签: unity3d

我目前正在制作一个时间系统,在那个系统中,我希望能够控制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?我不知道如何在我的系统中更改这个,所以如果有人有任何想法。请帮忙。

1 个答案:

答案 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。如果你这样做,你可以在开始时进行转换。

我希望这能回答你所有的问题,如果没有,请随时澄清没有回答的问题。