C++ One enum name for more types

Started by
6 comments, last by BaneTrapper 10 years, 9 months ago

Hello.

The title is of, i am aware but i dont know how to describe the issue.

Intro:

I am making a 2d tiled map. Each tile has type that is a enum type.


class Tile{public: int type;}

The want to do:

I want to make a enum defined like this to be able to have state?

When i check collision, i want to check player V.S. the tile he is gonna move to, if the tile he wants to move to is "unwalkable" deny the movement, else relocate.


enum Tile_Type
{

grass = 1,
water = 2,
stone = 3

};
 
bool CollisionChecking()

{

if(VectorOfTiles[playerPositionInMap].TypeID] == my_enums::UNWALKABLE)

{ // Deny movement
}
else

{ // Relocate

}

}

The issue is that i want to set types for enum "Tile_Type" something like this


grass = WALKABLE;
water = UNWALKABLE;
stone = UNWALKABLE;

Any ideas how to achieve something similar to this?

Advertisement

Encode the information in an array and look it up from there.

enum {
    grass,
    tallGrass,
    water,
    stone
};
 
struct tile_information_t {
    bool walkable;    // is the tile walkable?
    bool swimable;    // is the tile swimable?
    int cost;    // if the tile is walk/swimable, how much movement does it cost to move
    // add as much information about the tiles you need here
} const tile_information[] = {
    {true, false, 1},  // grass is walkable and it costs one movement
    {true, false, 2},  // tall grass is walkable, but it costs two movement to wade through the tall grass
    {false, true, 1}, // water is swimable and it costs one movement
    {false, false, 0} // stone is not movable at all
};

Then look up the tile information based on the tile.

tile_information_t const *t = tile_information[tileID]
 
if(t->walkable) {
    // tile with id tileID is walkable, and it costs t->cost to move
}
 
if(hasSwimmingGear && t->swimable) {
    // tile with id tileID is swimable, and it costs t->cost to swim
}

While I made the tile information hard coded, you can easily parse it from a file so you can change it on the fly without recompiling.

Encode the information in an array and look it up from there.


enum {
    grass,
    tallGrass,
    water,
    stone
};
 
struct tile_information_t {
    bool walkable;    // is the tile walkable?
    bool swimable;    // is the tile swimable?
    int cost;    // if the tile is walk/swimable, how much movement does it cost to move
    // add as much information about the tiles you need here
} const tile_information[] = {
    {true, false, 1},  // grass is walkable and it costs one movement
    {true, false, 2},  // tall grass is walkable, but it costs two movement to wade through the tall grass
    {false, true, 1}, // water is swimable and it costs one movement
    {false, false, 0} // stone is not movable at all
};

Then look up the tile information based on the tile.


tile_information_t const *t = tile_information[tileID]
 
if(t->walkable) {
    // tile with id tileID is walkable, and it costs t->cost to move
}
 
if(hasSwimmingGear && t->swimable) {
    // tile with id tileID is swimable, and it costs t->cost to swim
}

While I made the tile information hard coded, you can easily parse it from a file so you can change it on the fly without recompiling.

What you just provided is flexible and so good thanks!

EDIT::
Aniway, this like is invalid

tile_information_t const *t = tile_information[tileID]

public struct TileInfo
{
	public bool walkable;
        public bool destructable;
	
	 public static TileInfo Grass()
        {
            return new TileInfo ()
            {
                walkable = true,
                destructable = false;
            }
         }

	 public static TileInfo Water()
        {
            return new TileInfo ()
            {
                walkable = false,
                destructable = false;
            }
         }
}

 

Then, where I want info for a tile, I have a TileInfo variable in a generic tile class, which I set like:

TileInfo tileInfo = TileInfo.Grass();

This makes it very easy and decouples tile meta data into nice segments which you could possibly parse from a file.

EDIT: To then do the actual check with player is trivial, since all instances of Tile will have a set TileInfo data, we can just use:

if(tileInfo.walkable)

{

//allow player movement

}

etc.


Aniway, this like is invalid
tile_information_t const *t = tile_information[tileID]

I think references would be nice here.

const tile_information_t& t = tile_information[tileID];

and then use t.swimable etc


Aniway, this like is invalid
tile_information_t const *t = tile_information[tileID]

I think references would be nice here.

const tile_information_t& t = tile_information[tileID];

and then use t.swimable etc

Not only would a reference be nice, but a pointer is plain wrong in that particular case: tile_information + tileID would be suitable for a pointer though :)

Joke aside, yes, my post was more for information and not a particular implementation with tested and verified code and I totally agree with using references instead.

You can also add some data to the tile object itself, if theres something you need to change a lot without changing the type. Some things you can implement using either separate types or data in the tile itself.

For example, you could have either of:

-Types OpenDoor and ClosedDoor

or

-Tile {TileType type; bool collides;}

Now, what if you not only had a "Door" type, but also a "Deth lazor" (active/inactive) type? you dont want to add separate bools because both only use one.

In this particular situation, you could use an union

union{

bool collides; //if door

bool activated; //if deth lazor

}; //i dont know if this is valid syntax for unions :P

So, eventually you will have something like:

union{

DoorData door; //contains bool for open/closed for example

DethLazorData lazor; //bool for activated, int for "energy left"

GrassData grass; //int for growth

BasicData basic; //for the most basic blocks like dirt, stone... i guess.

TeleportData tele; //x,y coordinates of destination

ChestData chest; //could contain an ID to point to an externally stored inventory object

}

The size of your tile type will be dictated by the biggest of the above. For this reason, when adding a new type of tile, you want to decide wether to store its data externally or within the tile. For example in the above, if the ChestData class contained a big array of objects inside it, every single tile would be that big and that wouldnt be nice. So you instead store it externally and just point to it.

The above seems like a nice solution. You store the tile type, followed by a section for type specific data (the union) which is big enough to work with all the types.

o3o

Incase someone googles this page i am posting results how ive done it:

// HEADER
class Tile
{
public:
    Tile();
    Tile(int id);
    sf::Uint8 ID;
};

enum TileType
{
    grassLT = 0,
    grassT = 1,
    grassRT = 2,
    grassLB = 40,
    grassB = 41,
    grassRB = 42,
    SandLT = 3
    
};

class TileInfo
{
public:
    TileInfo(int infoID);
    bool walkable;
    bool swimable;
};
// CPP
Tile::Tile()
{
    ID = 0;
}

Tile::Tile(int id)
{
    ID = id;
}


TileInfo::TileInfo(int infoID)
{
    switch(infoID)
    {
    case grassLT:
        walkable = true;
        swimable = false;
        break;
    case grassT:
        walkable = true;
        swimable = false;
        break;
    case grassRT:
        walkable = true;
        swimable = false;
        break;
    case grassLB:
        walkable = true;
        swimable = false;
        break;
    case grassB:
        walkable = true;
        swimable = false;
        break;
    case grassRB:
        walkable = true;
        swimable = false;
        break;
    case SandLT:
        walkable = true;
        swimable = false;
        break;

    default:
        walkable = false;
        swimable = false;
        break;
    }
}

This topic is closed to new replies.

Advertisement