2

I am currently developing a basic voxel (cuboid) game engine, and I have encountered a performance issue. Every frame the game:

Finds player's viewing direction → Checks every co-ordinate in the player's direct view path → Finds closest occupied space → Draws a wireframe around this block.

I am using OpenTK, a binding of OpenGL for .NET/Mono (specifically C#). My code OnRenderFrame contains this:

try
{
    for (int i = 0; i < 8; i++)
    {
        Vector3 block = InterfaceUtils.FindBlockLoc(Utilities.RoundToInt(cam.Position + (cam.lookat * i)));
        if (block != Vector3.Zero)
        {
            // Draw the wireframe
        }
    }
}
catch
{
}

The purpose of this code is to check up to eight blocks from the player until it finds a block. The only problem with this is that the try statement most often throws a (handled) exception: but the lag caused by this is massive. When I look into space, I only get 11FPS, but I get 50 if the code is successful.

If the code is successful (it can draw the wireframe), I get this:

The block-finding works by checking the objects list for a block in that location.

public static Vector3 FindBlockLoc(Vector3 location)
{
    Vector3 result = new Vector3(Vector3.Zero);

    result = Deltashot.Game.objects.Find(v => v.Position == location).Position;
    if (result != null)
    {
        return result;
    }
    else
    {
        return Vector3.Zero;
    }
}

However, this returns a NullReferenceException and I'm forced to use a TRY statement to get it to run. Which is back to square one again...

genpfault
  • 47,669
  • 9
  • 68
  • 119
Alex V-P
  • 49
  • 6
  • 3
    *Why* are you getting an exception? Instead of just catching and ignoring it, you should work out why you're getting an exception in the first place. What kind of exception is it, anyway? – Jon Skeet Feb 08 '15 at 19:50
  • my guess the nullref comes from assigning to result, instead store the result of `find` and test that for nullness – ratchet freak Feb 08 '15 at 19:53
  • 1
    What do you mean by "this returns a NullReferenceException? Where is the exception thrown, exactly? What have you done to diagnose it? A NullReferenceException is almost always something to be avoided, rather than caught. – Jon Skeet Feb 08 '15 at 20:10
  • Game engines avoid exception handling like the plague. Exception handling is slow, dead-slow. – LearnCocos2D Feb 11 '15 at 11:55

3 Answers3

2

Throwing and catching Exceptions is a costly operation in C#, and it seems you are using exceptions as flow control.

Your should avoid the NullReferenceException instead of catching it whenever it happens.

I would guess the exception happens here:

result = Deltashot.Game.objects.Find(v => v.Position == location).Position;

I'd suggest something like this:

public static Vector3 FindBlockLoc(Vector3 location)
{
    var result = Deltashot.Game.objects.Find(v => v.Position == location);

    if (result != null && result.Position != null)
    {
        return result.Position;
    }
    else
    {
        return Vector3.Zero;
    }
}
Community
  • 1
  • 1
Juliano
  • 2,095
  • 17
  • 21
0

If you change this line

result = Deltashot.Game.objects.Find(v => v.Position == location).Position;

to this:

result = Deltashot.Game.objects.Find(v => v.Position == location);
if (result != null)
{
    return result.Position;
}
...

You might be able to prevent the exception, if the Find method returns null, and you try to access any members from a null result, you get a null reference exception - You should rather than wrap something in a try/catch, spend a little time trying to figure out why you are getting the exception.

An Easy way to do this is to break up all code at dots with checks (until you figure out where the error is happening) As it is also possible that Deltashot.Game is null or Deltashot.Game.objects is null.

tophallen
  • 993
  • 6
  • 12
0

I fixed this issue by changing my function to:

public static Volume FindBlock(Vector3 location)
{
    return Deltashot.Game.objects.Find(v => v.Position == location);
}

So that I returned the whole Volume object (not just the position). I then changed the code that called it to this:

for (int i = 0; i < 8; i++)
{
    var block = InterfaceUtils.FindBlock(Utilities.RoundToInt(cam.Position + (cam.lookat * i)));
    if (block != null)
    {
        // Draw the wireframe
    }
}

So that block was initially typeless, and compared it to var's definition of null (which doesn't throw the exception!)

Thank you to Juliano for the (similar) solution and to tophallen for his diagnostic advice.

Alex V-P
  • 49
  • 6