I have been working on a few games which all have a need to create "events" randomly over time. The intervals need to get shorter as time goes on if the event is negative or they need to get longer as time goes on if the event is positive in order to make the game harder the longer you play.
enter image description here
In my head, this picture describes how the intervals should change over time. At first, the minimum and maximum possible time change linearly, but there is a limit for both of them which can not be exceeded once it is met.
Below is my implementation. It is intended to be used by another object which will actually create the event. The parent object should repeatedly call ShouldDoEvent
with the amount of time that has passed since the last time it was called.
My concern is that the getNextInterval
method only makes sense if you have the picture in your head and have worked out the algebra. How can I make that method clearer?
using UnityEngine;
using System.Collections;
public class RandomIntervals
{
private Vector2 _startMax;
private Vector2 _startMin;
private Vector2 _endMax;
private Vector2 _endMin;
private float _elapsedTime = 0;
private float _nextEvent = -1f;
private System.Random _random = new System.Random();
public RandomIntervals(Vector2 startMax, Vector2 startMin, Vector2 endMax, Vector2 endMin)
{
_startMax = startMax;
_startMin = startMin;
_endMax = endMax;
_endMin = endMin;
}
public bool ShouldDoEvent(float deltaTime)
{
_elapsedTime += deltaTime;
if (_elapsedTime < _nextEvent) return false;
_nextEvent = _elapsedTime + getNextInterval();
return true;
}
private float getNextInterval()
{
float max, min;
if (_elapsedTime < _endMax.x)
{
float percentBetween = _elapsedTime / _endMax.x;
var maxPoint = _startMax + percentBetween * (_endMax - _startMax);
max = maxPoint.y;
}
else
{
max = _endMax.y;
}
if (_elapsedTime < _endMin.y)
{
float percentBetween = _elapsedTime / _endMin.x;
var minPoint = _startMin + percentBetween * (_endMin - _startMin);
min = minPoint.y;
}
else
{
min = _endMin.y;
}
return min + ((float)_random.NextDouble()) * (max - min);
}
}
1 Answer 1
It might be worth introducing an abstraction for the type of piecewise linear functions that bound your intervals. For example (warning, there might be errors)
class PiecewiseLinear
{
private readonly Vector2 start;
private readonly Vector2 end;
public PiecewiseLinear(Vector2 start, Vector2 end)
{
this.start = start;
this.end = end;
}
public double ValueAt(double x)
{
if (x >= end.x)
{
return end.y;
}
return (start + (x / (end.x - start.x)) * (end - start)).y;
}
}
The class name is not ideal, as the class only deals with a very specialised case, but I can't think of a more specific name.
Anyway, you can now use it like this
var max = new PiecewiseLinear(new Vector2(0, 5), new Vector2(3, 2));
var min = new PiecewiseLinear(new Vector2(0, 4), new Vector2(2, 1));
for (double x = 0; x <= 4; x += 0.25)
{
Console.WriteLine("({0}, {1})", x, max.ValueAt(x) - min.ValueAt(x));
}
-
\$\begingroup\$ Thanks! That makes a lot of sense. Within the context of PiecewiseLinear it is easy to understand what the algebra is for. \$\endgroup\$PatrickSharbaugh– PatrickSharbaugh2014年11月13日 15:33:01 +00:00Commented Nov 13, 2014 at 15:33
ShouldDoEvent
(presumably every frame) as opposed to getting the next interval and then Invoking your event after that interval using Unity'sInvoke()
method? \$\endgroup\$