Как создать пульсирующее значение от 0..1..0..1..0 и т. д. в течение заданной продолжительности?
-
26-09-2019 - |
Вопрос
Я работаю над кодом, где у меня есть Time
объект с членом time
. Time.time
дает мне время с тех пор, как мое приложение началось в секундах (значение поплавки).Теперь я хочу создать пульсирующее значение от 0 до 1, а затем снова от 1 до 0, которое будет продолжать уменьшаться до тех пор, пока приложение не остановится.
Я думал использовать sin(), но не знал, что передать ему в качестве параметров для создания этого пульсирующего значения.
Как мне создать эту пульсирующую ценность?
Добрые пожелания, Pollux
Решение
Вы упоминаете, используя SIN (), поэтому, я думаю, вы хотите, чтобы он мог непрерывно импульс между 0 и 1.
Что-то вроде это сделает:
float pulse(float time) {
const float pi = 3.14;
const float frequency = 10; // Frequency in Hz
return 0.5*(1+sin(2 * pi * frequency * time));
}
1/frequency = 0.1 second
это период, который является временем между 1.
Другие советы
Как насчет x = 1 - x? Или если вы хотите, чтобы он был временным использованием таймера% 2
О, вы хотели, чтобы значения были также от 0 до 1. Как насчет Math.abs (100 - (таймер% 200)) / 100, где таймер является чем-то вроде dateTime.Now.timeOfday.totalmilliseconds
Редактировать:Мои тесты указывают, что это более чем в два раза быстрее, чем метод греха. Для 1 миллиона итераций метод греха занимает 0,48 секунды, когда метод ABS занимает около 0,023 секунды. Кроме того, вы получаете разные формы волны из двух, конечно. SIN производит синусоида, а абс производит треугольную волну.
static void Main(string[] args)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
const int count = 1000000;
float[] results = new float[count];
for (int i = 0; i < count; i++)
{
results[i] = AbsPulse(i/1000000F);
//results[i] = SinPulse(i / 1000000F);
}
sw.Stop();
Console.WriteLine("Time Elapsed: {0} seconds", sw.Elapsed.TotalSeconds);
char[,] graph = new char[80, 20];
for (int y = 0; y <= graph.GetUpperBound(1); y++)
for (int x = 0; x <= graph.GetUpperBound(0); x++)
graph[x, y] = ' ';
for (int x = 0; x < count; x++)
{
int col = x * 80 / count;
graph[col, (int)(results[x] * graph.GetUpperBound(1))] = 'o';
}
for (int y = 0; y <= graph.GetUpperBound(1); y++)
{
for (int x = 0; x < graph.GetUpperBound(0); x++)
Console.Write(graph[x, y]);
Console.WriteLine();
}
}
static float AbsPulse(float time)
{
const int frequency = 10; // Frequency in Hz
const int resolution = 1000; // How many steps are there between 0 and 1
return Math.Abs(resolution - ((int)(time * frequency * 2 * resolution) % (resolution * 2))) / (float)resolution;
}
static float SinPulse(float time)
{
const float pi = 3.14F;
const float frequency = 10; // Frequency in Hz
return 0.5F * (1 + (float)Math.Sin(2 * pi * frequency * time));
}
Я думаю, что функция синуса будет идеальной, но вам нужно отрегулировать период и масштаб.
Синусоидальная функция производит результаты от -1 до 1, но вы хотите пройти от 0 до 1., чтобы масштабироваться правильно, вы хотите (sin(x)+1)/2
.
Функция синуса начинается с нуля, идет к 1 на Pi / 2, снова ноль на Pi, -1 при 3 * Pi / 2 и обратно к нулю на 2 * Pi. Масштабирован, первый ноль произойдет при 3 * Pi / 2, а первый максимум после этого будет на 5/2 * Pi. Так x
В предыдущей формуле (2*time + 3) * pi/2
.
Положить все это вместе: (sin((2*time.time + 3) * pi/2) + 1) / 2
Как часто вы хотите, чтобы импульс?
Допустим, вы хотите пройти от 0 до 1 более 10 секунд.
float pulseValueForTime(int sec) {
int pulsePoint = sec % 10;
float pulsePercent = (float)pulsePoint / (float)10;
float pulseInTermsOfPI = (pulsePercent * 2 * PI) - PI;
float sinVal = MagicalSinFunction(pulseInTermsOfPI); // what framework you use to compute sin is up to you... I'm sure you can google that!
return (sinVal + 1) / 2; // sin is between 1 and -1, translate to between 0 and 1
}
Посмотрите на функции Ease.Они делают подобные вещи разными способами — линейными, полигональными, экспоненциальными, греховными и т. д.