我有一条在时间't'评估的路径,并根据路径类型返回方向和位置。
时间值受路径类型影响:
switch (type)
{
case PathType.Closed:
time = ToolBox.Wrap(time, StartTime, EndTime);
break; // Wrap time around the path time to loop
case PathType.Open:
time = ToolBox.Min(time, EndTime);
break; // Clamp the time value to the max path time range
case PathType.Oscillating:
break;
}
缺失的环节正在振荡。
我的问题是,在两个值之间振荡的有效方法是什么?
例如(2,7)。如果时间达到7,则反转并向下递减至2,一旦达到2,则反转并向7增加。
算法应该知道是否根据原始值增加/减少值,所以如果值为9,则知道答案是7 - (Abs(7 - 9)。如果值为14,则值已经包围所以它会导致增加1.
较高的值也会增加或减少该值,具体取决于它包围原始范围的次数。
我希望这是有道理的,因为我发现很难解释。
编辑:
不会以浮点值振荡:
for (float i = 0; i < 100; i += 0.1f)
{
Console.WriteLine("{0} {1}", i, Oscillate(2.5f, 7.5f, i));
}
private float Oscillate(float min, float max, float value)
{
float range = max - min;
float multiple = value / range;
bool ascending = multiple % 2 == 0;
float modulus = value % range;
return ascending ? modulus + min : max - modulus;
}
答案 0 :(得分:7)
以下是我提出的建议:
public static int Oscillate(int input, int min, int max)
{
int range = max - min ;
return min + Math.Abs(((input + range) % (range * 2)) - range);
}
我假设input
将是一个从0开始的计数器。
答案 1 :(得分:4)
理想情况下,您应该将此功能抽象为某种类,而不关心实现在您使用它时的实际工作方式。这是对C ++中看起来像什么的初步看法(我的C#有点生疏)。我认为你可以毫不费力地将它用于C#。
class oscillator
{
private:
float min;
float max;
static float mod(float num, float div)
{
float ratio = num / div;
return div * (ratio - std::floor(ratio));
}
public:
oscillator(float a, float b)
: min(a < b ? a : b), max(a > b ? a : b) {}
float range() ( return max-min; }
float cycle_length() { return 2*range(); }
float normalize(float val)
{
float state = mod(val-min, cycle_length());
if (state > range())
state = cycle_length()-state;
return state + min;
}
};
答案 2 :(得分:3)
这将使您的数字在2&amp;之间振荡。 7,在这个例子中,time是一个int:
bool isIncreasing = time <= 7;
for (int i = 0; i < 20; i++) //some random loop
{
time = time + (isIncreasing ? 1 : -1);
if (time >= 7 || time <= 2) isIncreasing = !isIncreasing;
}
答案 3 :(得分:1)
浮动值的新答案:
// Note: Increase FACTOR depending on how many decimal places of accuracy you need.
private const float FACTOR = 10;
public void Test()
{
for (float i = 0; i < 1000; i += 0.1F)
{
Console.WriteLine("{0} {1}", i, Oscillate(2.5F, 7.5F, i));
}
}
private float Oscillate(float min, float max, float time)
{
return (float)(Oscillate_Aux(Upscale(min), Upscale(max), Upscale(time))) / FACTOR;
}
private int Upscale(float value)
{
return (int)(value * FACTOR);
}
private int Oscillate_Aux(int min, int max, int time)
{
int range = max - min;
int multiple = time / range;
bool ascending = multiple % 2 == 0;
int modulus = time % range;
return ascending ? modulus + min : max - modulus;
}
答案 4 :(得分:0)
您所描述的内容听起来很像两个值之间的周期性线性插值。考虑使用XNA的MathHelper.Lerp函数作为振荡的基础。
请注意,它使用百分比来控制振荡作为其第三个参数。您必须弄清楚如何将时间t值转换为百分位数,但您可以从ex开始。罪(t)看看事情是如何运作的。
如果您不愿意将XNA导入项目,那么核心等式非常简单:
value1 + (value2 - value1) * amount
编辑:如果您的问题的核心是“两个值之间振荡的有效方式是什么?”,那么Math.Sin(t)(或Cos)可以为您提供0到1之间的定期振荡。