Wednesday, August 22, 2018

c# - IndexOutOfRangeException on World.Step after enabling/disabling a Farseer physics body?


Earlier, I posted a question asking how to swap fixtures on the fly in a 2D side-scroller using Farseer Physics Engine. The ultimate goal being that the player's physical body changes when the player is in different states (I.e. standing, walking, jumping, etc). After reading this answer, I changed my approach to the following:



  1. Create a physical body for each state when the player is loaded

  2. Save those bodies and their corresponding states in parallel lists


  3. Swap those physical bodies out when the player state changes (which causes an exception, see below)


The following is my function to change states and swap physical bodies:


new protected void SetState(object nState)
{
//If mBody == null, the player is being loaded for the first time
if (mBody == null)
{
mBody = mBodies[mStates.IndexOf(nState)];
mBody.Enabled = true;

}
else
{
//Get the body for the given state
Body nBody = mBodies[mStates.IndexOf(nState)];

//Enable the new body
nBody.Enabled = true;

//Disable the current body

mBody.Enabled = false;

//Copy the current body's attributes to the new one
nBody.SetTransform(mBody.Position, mBody.Rotation);
nBody.LinearVelocity = mBody.LinearVelocity;
nBody.AngularVelocity = mBody.AngularVelocity;

mBody = nBody;
}


base.SetState(nState);
}

Using the above method causes an IndexOutOfRangeException when calling World.Step:


mWorld.Step(Math.Min((float)nGameTime.ElapsedGameTime.TotalSeconds, (1f / 30f)));

I found that the problem is related to changing the .Enabled setting on a body. I tried the above function without setting .Enabled, and there was no error thrown. Turning on the debug views, I saw that the bodies were updating positions/rotations/etc properly when the state was changes, but since they were all enabled, they were just colliding wildly with each other.


Does Enabling/Disabling a body remove it from the world's body list, which then causes the error because the list is shorter than expected?


Update:


For such a straightforward issue, I feel this question has not received enough attention. Has anyone else experienced this? Would anyone try a quick test case? I know this issue can be sidestepped - I.e. by not disabling a body during the simulation - but it seems strange that this issue would exist in the first place, especially when I see no mention of it in the documentation for farseer or box2d. I can't find any cases of the issue online where things are more or less kosher, like in my case. Any leads on this would be helpful.




Answer



Does the erroneous line in your World.step() method have square brackets in it anywhere? Or a get() method of some sort with an index in it.


This error suggests that you're asking for an object in an array or list by providing an index outside of the array bounds. Array bounds start at 0, and end at array.Length - 1.


So a lot of the time this error is caused by looping through objects in an array up to and including array.Length or list.Count


EDIT:


The issue appears to be here (like you suggested):


//Enable the new body
nBody.Enabled = true;

//Disable the current body

mBody.Enabled = false;

//Copy the current body's attributes to the new one
nBody.SetTransform(mBody.Position, mBody.Rotation);
nBody.LinearVelocity = mBody.LinearVelocity;
nBody.AngularVelocity = mBody.AngularVelocity;

I was looking at the code for the .Enabled setter in body.cs in Farseer -- I haven't used Farseer personally so I don't know the exact details of the implementation, but it does a lot of disposing and destroying things when you set enabled to false. I would recommend just rearranging your code like this and giving it a go:


//Enable the new body
nBody.Enabled = true;


//Copy the current body's attributes to the new one
nBody.SetTransform(mBody.Position, mBody.Rotation);
nBody.LinearVelocity = mBody.LinearVelocity;
nBody.AngularVelocity = mBody.AngularVelocity;

//Disable the current body
mBody.Enabled = false;

mBody = nBody;

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...