5
\$\begingroup\$

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);
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ Is there a reason you're polling ShouldDoEvent (presumably every frame) as opposed to getting the next interval and then Invoking your event after that interval using Unity's Invoke() method? \$\endgroup\$
    – Nick Udell
    Nov 17 '14 at 13:24
4
\$\begingroup\$

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));
}
\$\endgroup\$
1
  • \$\begingroup\$ Thanks! That makes a lot of sense. Within the context of PiecewiseLinear it is easy to understand what the algebra is for. \$\endgroup\$ Nov 13 '14 at 15:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.