0

The declaration of the Rectangle object fails with an NullReferenceException, maybe it has to do with the for loops (yMax and xMax are in tiles unit) Thanks helping me catching why is this giving me an exception.

    TileData[][] tile = GameMain.Level.getCollisionTiles();
    int xMax = GameMain.Level.getMapHeight();
    int yMax = GameMain.Level.getMapWidth();

    for (int x = 0; x <= xMax; x++)
    {
        for (int y = 0; y <= yMax; y++)
        {
            Rectangle tileRectangle = tile[x][y].Target; //THIS LINE FAILS !!!!
            if (tileRectangle.Contains(m_hitbox)) //Si il y a collision
            {
                if ((m_hitbox.X + m_hitbox.Width) > tileRectangle.X) //si le joueur percute par la gauche
                {
                    m_hitbox.X--;
                }
                else if (m_hitbox.X < (tileRectangle.X + tileRectangle.Width)) //Droite
                {
                    m_hitbox.X++;
                }
                if ((m_hitbox.Y + m_hitbox.Height) > tileRectangle.Y) //si le joueur percute par le haut
                {
                    m_hitbox.Y--;
                }
                else if (m_hitbox.Y < (tileRectangle.Y + tileRectangle.Height)) //Bas
                {
                    m_hitbox.Y++;
                }
            }
        }
    }

Here is some code,

the accessor (GameMain.Level.) :

public TileData[][] getCollisionTiles()
    {
        return m_collisionTiles;
    }

the class "Level" attributes and constructor:

//Atributs
    Map m_map;
    List<TileLayer> m_layers;
    TileLayer m_collisionLayer;
    TileData[][] m_collisionTiles;
    int m_mapWidth;
    int m_mapHeight;
    int m_tileWidth;
    int m_tileHeight;
    //Constructeur
    public Level(ContentManager content, string levelName)
    {
        m_map = content.Load<Map>("Maps/"+levelName); //On charge la map

        //params
        m_mapWidth = m_map.Width;
        m_mapHeight = m_map.Height;
        m_tileWidth = m_map.TileWidth;
        m_tileHeight = m_map.TileHeight;

        //tiles / layers
        m_layers = new List<TileLayer>(m_map.TileLayers); //On charge les calques / couches
        m_collisionLayer = m_layers.Find( x => x.Name == "Collision"); //On charge le calque de collision
        m_collisionTiles = m_collisionLayer.Tiles;


    }
stalker2106
  • 118
  • 9
  • Show us your code of GameMain.Level.getCollisionTiles(); It seems as if you are doing something wrong when initialzing your array. – user1567896 Nov 18 '13 at 15:19
  • Well, what do you have in `tile[x][y]` when it fails? I know. It is null! You must fill every element in the `tile` array with a valid `TileData` object. The main failure is in your `GameMain.Level.getCollisionTiles()` method. – Mohammad Dehghan Nov 18 '13 at 15:21
  • 2
    [What is NullReferenceException](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it/4660186#4660186) – Sriram Sakthivel Nov 18 '13 at 15:22
  • 2
    "StackOverflow: faster than debugging your code since 2008!" – Paolo Falabella Nov 18 '13 at 15:24
  • Well I am really noobish with Visual Studio Debugger thing, so well i thought you could help... – stalker2106 Nov 18 '13 at 15:25
  • @stalker2106: You are almost certainly better off in the long run learning how to debug properly than asking questions on here. Hopefully you've read the link that Sriram posted and are about to start debugging it yourself though. Really though its as easy as starting it debugging and it should break on that exception. At that point you can inspect your variables to see what is null and then when you know that you can look at where is (or isn't) setting it to see why. – Chris Nov 18 '13 at 15:27
  • @stalker2106 At least try. Hovering a mouse cursor over a variable isn't really that hard. You might also want to read a bit about the "Watch window". – BartoszKP Nov 18 '13 at 15:27

3 Answers3

0

If this line throws a NullReferenceException:

Rectangle tileRectangle = tile[x][y].Target

then either tile, tile[x] or tile[x][y] is null. Run it in the debugger to find out which one.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
0

My guess would be that m_collisionLayer.Tiles constructs the two dimension array by looping through a list of the collision tiles and adding them to the array. If the array doesn't exist for a given x value it will create it and stick the appropriate tile in for the appropriate y value.

The problem with this approach would be that if no collision tile exists for a given x value then it will never create the array for that x value (that will be empty) and so tile[x] will stay null and so tile[x][y] will give a null reference exception.

The solution to this is to either fully initialise your array when you first declare it or to check if tile[x] is null before looping over y values and check tile[x][y] before calling .Target.

The null checks are probably the better approach since it will mean that you are passing round a compact array (ie no objects in the gaps rather than empty objects). And since you'd be wanting to do a null check probably before calling .Target then you might as well add in the previous null check too.

Also if there are no collision Tiles it may be that tile could be null in which case you'd want to check for that too.

for (int x = 0; x <= xMax; x++)
{
    if (tile[x]==null)
        continue;
    for (int y = 0; y <= yMax; y++)
    {
        if (tile[x][y]==null)
            continue;
        Rectangle tileRectangle = tile[x][y].Target; //THIS LINE FAILS !!!!
        //Snipped code here
    }
}

Initialising it would be done in the TileLayer object and would basically mean where you are creating your array you would do something akin to:

int[][] arr = new int[10][];
for (int i= 0; i<arr.Length; i++)
{
    arr[i] = new int[10];
}

One final point of note is that [][] is for a jagged array. If your tiles are always in a rectangle then you might actually be wanting to use TileData[,]. This is a single array with two indexes which is more probably what you want rather than an array of arrays (which is what you have now).

Chris
  • 27,210
  • 6
  • 71
  • 92
  • Thanks for answering ! I havent thought of that... Seems to be the solution, but how to initialize it in the constructor ? – stalker2106 Nov 18 '13 at 15:33
  • Well i found a workaround, I test if the tile[x][y] != null before creating rectangle, it now gives me a IndexOutOfRangeException on the testing line "if" – stalker2106 Nov 18 '13 at 15:44
  • I've updated my answer. The index out of range sounds like it is the `<` vs `<=` that others have mentioned. – Chris Nov 18 '13 at 15:46
  • when modifying these to simple <, it also trhows an exception. let me read your answer then i'll get back to the comments. – stalker2106 Nov 18 '13 at 15:48
  • Well index out of range exceptions will come from you using values of x or y that are bigger than the array is expecting (eg if it is 10 items long and you ask for item 15 then it will throw that exception. This means that you really need to look at the debugger and find out what the values of x and y are when it fails and what the size of your arrays are that you are checking against. – Chris Nov 18 '13 at 15:53
  • Well, when testing it, it crashes when it comes to the tile[x][y] one, so the [x] only works fine ( X = 0, Y = 20 and maxs are both 30). indeed, i wish i could use a TileData[,] but i cant, see yourself : https://bitbucket.org/vinull/xtiled/wiki/objects i use this already built framework in my XNA project :/ – stalker2106 Nov 18 '13 at 15:54
  • Its now working yay !!!!!!!!!!!!!!!!!!!! just had to replace the xMax and yMax by tile.GetLength(0) and tile[x].GetLength(0), so thanks anyway for helping me, it seems to work :) – stalker2106 Nov 18 '13 at 15:58
  • Looking at that page the first thing I notice is that a map has width and height in tiles but also tiles have a height and width in pixels. Are you sure that your `getMapHeight` is getting the height in tiles and not pixels? I can't actually see that method on their API... – Chris Nov 18 '13 at 15:58
  • Glad you've got it working. I really really strongly recommend you have a play with the debugger though to see what you can do with it. It will at least double your debugging productivity and more likely ten times or more better. The basics are really quite easy. – Chris Nov 18 '13 at 15:59
  • Yeah, thanks a lot ! collision still aint working though, but it'll be so much easier now ! do you have any Debugger reference under hand ? – stalker2106 Nov 18 '13 at 16:01
-1

Looks like you have got incorrect boundaries range in your loops.

for (int x = 0; x < xMax; x++)
{
    for (int y = 0; y < yMax; y++)

Not "less or equal" but just "less" comparison.

Dmytro Rudenko
  • 2,524
  • 2
  • 13
  • 22