1

Sweet Snippet 之 PlayMode实现

 1 year ago
source link: https://blog.csdn.net/tkokof1/article/details/130275524
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Sweet Snippet 之 PlayMode实现

tkokof1 已于 2023-04-20 22:05:39 修改 259

本文简述了一种 PlayMode 的实现方式

PlayMode(播放模式)应该是编程开发中常见的概念,一般来讲有以下几种播放模式:

enum class EPlayMode : uint8
{
	Once, // 单次播放
	Loop, // 循环播放
	PingPong, // 往返播放
};

总结来讲, PlayMode 影响的是 时间因子(TimeFactor) 的计算,我们可以抽象出以下结构来进行实现说明:

class CPlayMode
{
public:
    CPlayMode(EPlayMode Mode_, float Duration_) :
        Mode(Mode_),
        Duration(Duration_),
        Elapsed(0)
    {
    }
    
    void Update(float DeltaTime);
	float GetFactor() const;
    
protected:    
	EPlayMode Mode;
    float Duration;
    float Elapsed;
};
newCodeMoreWhite.png

开始实现之前,我们先定义几个辅助函数:

float FloatDivide(float Dividend, float Divisor)
{
	if (Divisor != 0)
	{
		return Dividend / Divisor;
	}

	return 0;
}

float FloatModulo(float Dividend, float Divisor)
{
    if (Divisor != 0)
    {
        return Dividend - ((int)(Dividend / Divisor)) * Divisor;
    }
	
	return 0;
}
newCodeMoreWhite.png

作用就是处理浮点数的除法和取模(用以解决除零等问题).

之后便是正式的实现了:

void CPlayMode::Update(float DeltaTime)
{
	switch (Mode)
	{
		case EPlayMode::Once:
		{
			Elapsed += DeltaTime;
			if (Elapsed > Duration)
			{
				Elapsed = Duration;
			}
		}
		break;
		case EPlayMode::Loop:
		{
			Elapsed += DeltaTime;
			if (Elapsed > Duration)
			{
				Elapsed = FloatModulo(Elapsed, Duration);
			}
		}
		break;
		case EPlayMode::PingPong:
		{
			Elapsed += DeltaTime;

			float LoopDuration = 2.0f * Duration;
			if (Elapsed > LoopDuration)
			{
				Elapsed = FloatModulo(Elapsed, LoopDuration);
			}
		}
		break;
	}
}
newCodeMoreWhite.png

Update 函数主要用于更新 Elapsed:

  • 对于 Once 模式,直接使用 Duration 截断 Elapsed
  • 对于 Loop 模式,简单处理的话可以直接 Elapsed - Duration(当 Elapsed 超过 Duration 时),但是使用 FloatModulo 会更健壮一些(可以处理 DeltaTime 过大的情况)
  • 对于 PingPong 模式,处理上会取巧一些,直接将往返一次算作一次循环,这样处理上就和 Loop 模式类似了(原本的 Duration 需要加倍)

GetFactor 就是按照 Elapsed 获取当前的 TimeFactor :

float CPlayMode::GetFactor() const
{
	switch (Mode)
	{
	case EPlayMode::Once:
	case EPlayMode::Loop:
	{
		return FloatDivide(Elapsed, Duration);
	}
	case EPlayMode::PingPong:
	{
	    if (Elapsed <= Duration)
		{
		    return FloatDivide(Elapsed, Duration);
		}
		else
		{
			return 1.0f - FloatDivide(Elapsed - Duration, Duration);
		}
	}
	}

	return 0;
}
newCodeMoreWhite.png

其中 PingPong 模式的处理会有些特殊,但是了解了上面 Elapsed 的处理方式(PingPong 模式下)就容易理解了,有兴趣的朋友可以细看一下.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK