3
\$\begingroup\$

I would like to trigger an event each time my rigidbody2D is at a particular value.

The event should only be triggered once for each given value per complete object revolution.

Rotating Object - Yellow circle indicates current rotation

Initial attempts at achieving this have resulted in the following method which checks against an array of values, logging an event and incrementing an index when the value has been passed.

static readonly float[] angles = new float[] { 90f, 180f };  
int angleIndex = 0;

void CheckForTrigger()
{
    if (rigidbody2D.IsSleeping())
        return;

    var rotation = Mathf.Abs(rigidbody2D.rotation);

    if (rotation % 360f >= angles[angleIndex])        
    {        
        Debug.Log("Fire");

        angleIndex++;

        if (angleIndex== angles.Length)
            angleIndex= 0;
    }
}

This suffers from a couple of issues:

  • Floating point inaccuracy means that values close to 360f will often be missed (e.g. 359f)
  • Fire will be logged each frame between the last and first value (i.e. between 180f and 90f)

Does anyone have any advice for approaching this problem and improving the above method?

\$\endgroup\$
  • \$\begingroup\$ One fundamental flaw of this approach is that an object can pass through both angles without ever satisfying your check. There's no simple way to deal with that. Can you give more details on exactly are you trying to do? \$\endgroup\$ – Selali Adobor Aug 16 '14 at 5:13
1
\$\begingroup\$

This is somewhat long and might not work well if they are rotating faster than the deadzone value, but then you can just increase the deadzone. I've commented the below code: //declare new array of the dataclass we made below

static AngleData[] angleDatas = new AngleData[] { new AngleData(90f), new AngleData(180f) };
int angleIndex = 0;
//the deadzone is how close it has to be to the target angle to fire, and how far it needs to be to 'reset itself'
float deadzone = 15f;
void CheckForTrigger()
{
    if (rigidbody2D.IsSleeping())
        return;

    var rotation = Mathf.Abs(rigidbody2D.rotation) % 360f;
    //we get the current AngleData
    AngleData currentAngle = angleDatas[angleIndex];
    //find the absolute difference from the target to the current rotation
    float difference = Mathf.Abs(rotation - currentAngle.angle);
    //if we haven't 'used up' this angle for this revolution
    if (currentAngle.available)
    {
        //if it's within the deadzone
        if (difference < deadzone)
        {
            Debug.Log("Fire:" + currentAngle.angle);
            currentAngle.available = false;
        }
    }
    else
    {
        //if it's outside the deadzone
        if (difference > deadzone)
        {
            currentAngle.available = true;
            //move on to next angle in list
            angleIndex = (angleIndex + 1) % angleDatas.Length;
        }
    }
}
public class AngleData
{
    public float angle;
    public bool available = true;
    //could have an event declared here if you want specific event methods to be fired for every different angle
    public AngleData(float angle) { this.angle = angle; }
}

Let me know if you have any questions or if it doesn't work as intended.

\$\endgroup\$
  • \$\begingroup\$ Thank you for your response. It works but it is not accurate enough when increasing the angular velocity. This is still true when increasing the deadzone. I need to rethink my approach, perhaps a delta rotation approach will be more accurate? \$\endgroup\$ – user1423893 Aug 3 '14 at 11:00
  • \$\begingroup\$ Is this because of how fast the angular velocity is reaching? What would be some typical output when printing out the value of rotation every frame? Also, are you looking for your algorithm to be dynamic (to handle any set of angles you specify) or only for 90 and 180? \$\endgroup\$ – Ideae Aug 3 '14 at 14:21
  • \$\begingroup\$ The algorithm will need be dynamic. I am thinking that I can accumulate rotations from delta orientations each frame, which can be calculated from Atan2 or Quaternions. \$\endgroup\$ – user1423893 Aug 3 '14 at 15:31

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.