• Create Account

## Returning an element from an array

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

24 replies to this topic

### #1Toshio  Members

Posted 12 July 2012 - 04:20 PM

Hi there. I hope someone could help me solve this problem.

I suspect this is not the way to do it, but here's the code:

int tile[210][210];

int Map::getTile(int a, int b)
{
return tile[a][b];
}


When I want to return the element in a different class, it returns 0.

Also, I can't make my tilemap (tile[a][b]) bigger than 212 * 212. The game crashes just after it launches.

### #2ApochPiQ  Moderators

Posted 12 July 2012 - 04:52 PM

If you want the tile to be connected to an instance of the Map class, you need to place the definition of tile inside the class { } body where you define Map. Just sticking it out in no-man's-land makes it a global variable, so every copy of Map will access the same variable.
Wielder of the Sacred Wands

### #3Servant of the Lord  Members

Posted 13 July 2012 - 12:57 AM

In addition to what ApochPiQ mentioned, you should use an std::vector if you're going to have a large amount of data, because you're putting too much data on the stack which is why it crashes. This is called a Stack Overflow, apparently (I never knew what it was called until just now ).

Using a std::vector puts the data on the heap instead, which won't crash your program with the amount of data you are using.
(Note: Just because std::vectors are resizable, doesn't mean you have to use that. They are good as for constant sized arrays also. Infact, the new C++ standard even introduced a new type of container: A non-resizable vector. )

This code should give you a good boost-start:
#include <vector>

class Map
{
public:
Map(int width, int height) : width(width), height(height)
{
//Resize the vector to be the size we want (width * height).
this->tiles.resize((width * height), 0); //Initialize each tile to 0.
}

int Map::GetTile(int x, int y)
{
int index = _GetIndex(x,y);

//Make sure this is a valid index.
if(_IsValid(index))
{
return this->tiles[index];
}

return 0;
}

void Map::SetTile(int x, int y, int tileID)
{
int index = _GetIndex(x,y);

//Make sure this is a valid index.
if(_IsValid(index))
{
this->tiles[index] = tileID;
}
}

private:
int width, height;
std::vector<int> tiles;

//Converts from a two-dimensional x,y to a one-dimensional index into our vector.
int _GetIndex(int x, int y)
{
return (y * this->width) + x;
}

//Makes sure that we aren't going out of bounds, which will crash the program.
bool _IsValid(int index)
{
if(index < this->tiles.size())
return true;

return false;
}
};

int main()
{
const int NOTHING = 0;
const int GRASS = 1;
const int DIRT = 2;
const int DIFFERENT_DIRT = 3;
//...
const int WATER = 211;
const int LAVA = 300;

Map map(20, 20); //I want a map that's 20 by 20 tiles.

Map largeMap(2000, 5000); //I also want a map that's 2000 by 5000 tiles.

largeMap.SetTile(50, 100, DIRT) //Access tile X:50, Y:100, and set it to DIRT.

if(largeMap.GetTile(playerTileX, playerTileY) == LAVA)
{
//...damage the player.
}
}


If you have any questions about how it works, don't hesitate to ask.

Edited by Servant of the Lord, 13 July 2012 - 01:00 AM.

It's perfectly fine to abbreviate my username to 'Servant' or 'SotL' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames -

### #4Toshio  Members

Posted 13 July 2012 - 03:08 AM

Wow, thanks, I can make the map any size I want.

But, I create the map and do all of this inside my Map class. And when again I want to get the tile in the Player class, it returns 0.

### #5brx  Members

Posted 13 July 2012 - 03:32 AM

Could you please post the code how the Map instance is passed to the Player? I have the suspicion you are creating a new (uninitialized) Map instance in your Player class.

### #6Toshio  Members

Posted 13 July 2012 - 03:40 AM

class Player
{
Map m;
public:
Player();
void Init();
//...
}


I set the width and the height inside the Map class.

### #7rnlf  Members

Posted 13 July 2012 - 03:55 AM

Are you sure you want every player to have her own map? Because that's what you are doing right now. What you want to do, is pass a reference to your map to the player, like this:

class Player
{
Map& m;
public:
Player(Map& map)
: m(map) { ... old constructor code ... }
};
in main:
set up the map as you did before, then when creating the player:
Player player(map); // or largeMap


This way you only have one map for all players, all referencing the same data. If you do it the way you did, you create an empty map for every player, and one in your main, which you never use.

### #8Servant of the Lord  Members

Posted 13 July 2012 - 10:47 AM

But, I create the map and do all of this inside my Map class. And when again I want to get the tile in the Player class, it returns 0.

Could you show a complete example of code? We need to see what your entire Map class looks like, and your entire Player class, if we're to figure out why your Player class is not interacting with the Map class properly. Also show where your Map or Player is created.

Edited by Servant of the Lord, 13 July 2012 - 10:48 AM.

It's perfectly fine to abbreviate my username to 'Servant' or 'SotL' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames -

### #9arkane7  Members

Posted 13 July 2012 - 01:52 PM

I think SOAL and rnlf are correct, you need every player to have a reference not create its own (though personally I would use a pointer but its all the same)

Make the player class have a reference to a M

Are you sure you want every player to have her own map? Because that's what you are doing right now. What you want to do, is pass a reference to your map to the player, like this:

class Player
{
Map& m;
public:
Player(Map& map)
: m(map) { ... old constructor code ... }
};
in main:
set up the map as you did before, then when creating the player:
Player player(map); // or largeMap


This way you only have one map for all players, all referencing the same data. If you do it the way you did, you create an empty map for every player, and one in your main, which you never use.

this is pefect, should easily solve the issue

also SOAL you forgot to include a check inside the isValid function if it is less than 0. I don't know if std::vector does that check or not.
Always improve, never quit.

### #10Servant of the Lord  Members

Posted 13 July 2012 - 02:47 PM

also SOAL you forgot to include a check inside the isValid function if it is less than 0. I don't know if std::vector does that check or not.

Oops, you're right.

The function should be:
bool _IsValid(int index)
{
if(index < this->tiles.size() && index > 0)
return true;

return false;
}

If it was my own code, I'd just make 'index' be unsigned or a size_t.
It's perfectly fine to abbreviate my username to 'Servant' or 'SotL' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames -

### #11fastcall22  Moderators

Posted 13 July 2012 - 03:12 PM

Oof; not quite, Servant. 0 is also a valid element.

I try to write it as close to the mathematical notation, [0 size) or 0 <= x < size, as possible:
bool _IsValid( int index ) const {
return 0 <= index && index < tiles.size();
}

I find it's easier to "read" the domain of the condition at a glance.

Edited by fastcall22, 13 July 2012 - 03:14 PM.

zlib: eJzVVLsSAiEQ6/1qCwoK i7PxA/2S2zMOZljYB1TO ZG7OhUtiduH9egZQCJH9 KcJyo4Wq9t0/RXkKmjx+ cgU4FIMWHhKCU+o/Nx2R LEPgQWLtnfcErbiEl0u4 0UrMghhZewgYcptoEF42 YMj+Z1kg+bVvqxhyo17h nUf+h4b2W4bR4XO01TJ7 qFNzA7jjbxyL71Avh6Tv odnFk4hnxxAf4w6496Kd OgH7/RxC

### #12Servant of the Lord  Members

Posted 13 July 2012 - 04:32 PM

Oof; not quite, Servant. 0 is also a valid element.

/facepalm

I must be having one of those days. It's a good thing my build environment broke, or I'd probably be wreaking havoc on my code base right now.
Or maybe that's how my build environment broke.

Edited by Servant of the Lord, 13 July 2012 - 04:49 PM.

It's perfectly fine to abbreviate my username to 'Servant' or 'SotL' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames -

### #13Toshio  Members

Posted 17 July 2012 - 03:26 PM

Are you sure you want every player to have her own map? Because that's what you are doing right now. What you want to do, is pass a reference to your map to the player, like this:

class Player
{
Map& m;
public:
Player(Map& map)
: m(map) { ... old constructor code ... }
};
in main:
set up the map as you did before, then when creating the player:
Player player(map); // or largeMap


This way you only have one map for all players, all referencing the same data. If you do it the way you did, you create an empty map for every player, and one in your main, which you never use.

I've been struggling with this for a few days now. I do all it says here, but it always returns some kind of an error. The error it returns when I write as it says is: "error: 'map' is not a type" pointing to this line "Player p(map);".

### #14Servant of the Lord  Members

Posted 17 July 2012 - 03:35 PM

You have to actually create the map somewhere before you can pass it into Player p(map);

Either globally, or preferably, whatever function or class creates and owns "Player p" should also own "Map map".

Example:
Map myMap;
Player myPlayer(myMap);

'myMap' is an instance of the 'Map' class type.
'myPlayer' is an instance of the 'Player' class type, and we're passing the 'myMap' instance into the Player constructor to create 'myPlayer'.
Because the Player class takes a reference (the & character) to a Map, it doesn't actually copy the map, but it shares the same map - Changing one changes the other, because Player's 'm' Map is a reference to 'myMap' Map (a different variable but pointing to the same location in memory).

You just have to be sure that "Map myMap" lasts as long or longer than "Player myPlayer"'s 'm' Map reference.

Edited by Servant of the Lord, 17 July 2012 - 03:36 PM.

It's perfectly fine to abbreviate my username to 'Servant' or 'SotL' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames -

### #15ApochPiQ  Moderators

Posted 17 July 2012 - 03:36 PM

Can you post the code you are trying to compile?

 Ninja'd with actual advice :-)

Edited by ApochPiQ, 17 July 2012 - 03:36 PM.

Wielder of the Sacred Wands

### #16Toshio  Members

Posted 17 July 2012 - 03:48 PM

I actually do have the "Map m;" line above the "Player p;" one, just didn't write it in the post. But yeah, it doesn't work.
Here's the code I'm trying to compile:

class Game
{
Map map;
Player p(map);
public:
Game();
//...
};


... and here is the Player class header file code:

class Player
{
Map& m;
public:
Player(Map& map) : m(map) {}
//...
};


### #17ApochPiQ  Moderators

Posted 17 July 2012 - 03:53 PM

class Game
{
Map map;
Player p(map);
public:
Game();
//...
};


This is the source of your problem. The compiler thinks you are trying to create a function called p which takes a parameter of type map with no name, and returns a Player.

Basically, this is because you're trying to create a variable instance inside a class declaration. This is not legal. You need to create variables inside a code block such as a function body:

class Map { /* ... */ };
class Player {
public:
Player(Map& map) :
MyMap(map)
{ }

private:
Map& MyMap;
};

int main () {
Map someMap;
Player somePlayer(someMap);

// Do stuff!

return 0;
}

Wielder of the Sacred Wands

### #18Toshio  Members

Posted 17 July 2012 - 04:17 PM

Ah, thank you so much. That part works now But how does the Player constructor look like in the Player code (.cpp) file?

### #19ApochPiQ  Moderators

Posted 17 July 2012 - 04:46 PM

Moving the constructor to a separate .cpp file is pretty simple:

// Map.h
class Map { /* ... */ };

// Player.h
class Player {
public:
Player(Map& map);

private:
Map& MyMap;
};

// Player.cpp
Player::Player (Map& map)
: MyMap(map)
{
}

// Main.cpp
int main () {
Map someMap;
Player somePlayer(someMap);

// Do stuff!

return 0;
}

Wielder of the Sacred Wands

### #20Toshio  Members

Posted 17 July 2012 - 05:19 PM

Hmm.. It compiles now, but the initialization, loop and rendering of the Player all got messed up. None works properly.. Anyone knows why that might have happened?

Edited by Toshio, 17 July 2012 - 05:21 PM.

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.