Advertisement

need a review of my tilemap code

Started by September 25, 2015 06:47 PM
3 comments, last by Alberth 9 years, 3 months ago

Greeting first of all !!

I 'd like to share some part of the code im writting , im totally beginner i wrote a pong but I decide to make other thing bigger than this and im trying to make a platform Im follow some tutorial from here , but im really don't know how to make it jump correctly , but first let me show the code is what i learnt in this travel of game development.





#include<SDL2/SDL.h>
#include<iostream>
#include<vector>
#include<map>
#include<fstream>
#include<sstream>

using namespace std;


#define GLOBAL_ERROR_FLAG  -1
#define UNABLE_LOAD_IMG    "The image could not be load"
#define LOADED			   "Image load well"
#define UNABLE_TO_LOAD_MAP "Unnable to load that map"




#define DEBUG 1
#ifdef DEBUG
#define debug() cout <<__FUNCTION__<<"  " <<__LINE__<<"  "<<__DATE__<<endl;
#define Debug(X) cout <<"Function Name : "<<__FUNCTION__<<" , Line no.  " <<__LINE__<<" , "<<__DATE__ <<" , "<<__TIME__<<"  ,  VALUE : "<< X <<endl;
#else
#define debug()
#define Debug(X)
#endif

template<class T,class E>
string BuildString(T uno, E dos)
{
  stringstream st;
  st << uno << "  " << dos <<endl;
  return st.str();
}

const char *gTitulo                = "TITLE APP ";
const int   TAMANO_PANTALLA_ANCHO  = 640;
const int   TAMANO_PANTALLA_ALTO   = 480;
const int   TAMANO_MAPA_ANCHO      = 2100;
const int   TAMANO_MAPA_ALTO       = 500;
const int   FPS 				   = 60;
const int   PL_VEL                 = 48;


SDL_Window   *window;
SDL_Renderer *render;
SDL_Event    event;
bool         run;
int          gReturn;

unsigned int start;
unsigned int delay;

struct Camara
{
	SDL_Rect _camara;
}cam;


struct Entidad
{
   SDL_Rect    crop;
   SDL_Rect    offset;
   SDL_Texture *img;
   unsigned int hp;
   unsigned int mp;
   bool EstaSaltando;
   bool EstaCallendo;
};

struct Tile
{
   SDL_Rect crop;
   SDL_Rect offset;
   int type;
};
struct TileSet
{
	SDL_Texture *res;

}TestTileset;




Entidad player;
vector<Entidad> enemigos;
vector<Entidad> objetos;
vector<Tile >   tile;



void Init();                       ///done
void HandleEvent();

void Render();
int  Destroy();
void StartFrame();
void RegulateFrame();

void FixBounds();



void LoadTile(vector<Tile> *ref,const char *fname);
void DrawMap();
SDL_Texture *CargarImagen(const char *fname, unsigned int r, unsigned int g, unsigned int b);
bool CheckCollison(Entidad *e1, Entidad e2);
void CargarRecursos();
bool IsTouchingTheWall();


//void ArgManager(int argc, char **argv);
///void Update();
//


int main(int argc, char *argv[])
{

	Init();
	CargarRecursos();
    while(run)
    {
    	StartFrame();
    	HandleEvent();
    	Render();
        RegulateFrame();
    }

    return Destroy();
}



void Init()
{

	Debug("Init")

	 if(SDL_Init(SDL_INIT_EVERYTHING) < 0)
	 {
		 gReturn  = GLOBAL_ERROR_FLAG;
		 debug()
	 }

	 if(gReturn != GLOBAL_ERROR_FLAG)
	 {

		 window = SDL_CreateWindow(gTitulo,100,100,TAMANO_PANTALLA_ANCHO,TAMANO_PANTALLA_ALTO, SDL_WINDOW_SHOWN );
		 render = SDL_CreateRenderer(window , -1 , SDL_RENDERER_ACCELERATED);
		 if(window == NULL|| render == NULL)
		 {
			 gReturn = GLOBAL_ERROR_FLAG;
		     cout    << "error Creado la ventana \n";
		 }
		 else
		 {
		     run = true;
		 }
	 }

}



void HandleEvent()
{
	//Debug("HandleEvent")
    while(SDL_PollEvent(&event))
    {

    	if(event.type == SDL_KEYDOWN)
    	{

    		switch(event.key.keysym.sym)
    		{

    			case SDLK_q:
    				run =false;
                    break;
    			case SDLK_UP:
    				 player.offset.y -= PL_VEL;
    				 break;
    			case SDLK_DOWN:
    				 player.offset.y += PL_VEL;
    				   break;
    			case SDLK_LEFT:
    				 player.offset.x -= PL_VEL;
    				   break;
    			case SDLK_RIGHT:
    				 player.offset.x += PL_VEL;
    				    				 break;
    			default:
    				break;
    		}
    	}

    	 FixBounds();

    }
}

void Render()
{
//	Debug("Render")

   SDL_RenderClear(render);
   SDL_SetRenderDrawColor(render, 0,23,34,56);
   DrawMap();
   SDL_RenderCopy(render, player.img,&player.crop,&player.offset);
#if 0
   for(unsigned int Ei = 0; Ei < enemigos.size(); Ei++)
   {
	   SDL_RenderCopy(render, enemigos.at(Ei).img,&enemigos.at(Ei).crop,&enemigos.at(Ei).offset);
   }
   for(unsigned int Ei = 0; Ei < objetos.size(); Ei++)
   {
  	   SDL_RenderCopy(render, objetos.at(Ei).img,&objetos.at(Ei).crop,&objetos.at(Ei).offset);
   }
#endif

   SDL_RenderPresent(render);
}




void StartFrame()
{

   start  = SDL_GetTicks();
}

void RegulateFrame()
{


   if(1000/FPS <  start - SDL_GetTicks())
   {
	   delay = 1000/FPS <  start - SDL_GetTicks();
	   SDL_Delay(delay);
	 //  Debug(delay)
   }

}


bool CheckCollison(Entidad *e1, Entidad *e2)
{
  int l1,r1,t1,b1;
  int l2,r2,t2,b2;

  l1 = e1->offset.x;
  r1 = e1->offset.x + e1->offset.w;
  t1 = e1->offset.y;
  b1 = e1->offset.y + e1->offset.h;

  l2 = e2->offset.x;
  r2 = e2->offset.x + e2->offset.w;
  t2 = e2->offset.y;
  b2 = e2->offset.y + e2->offset.h;

	if(l1 <= r2)
	  return true;












   return true;
}

SDL_Texture *CargarImagen(const char *fname, unsigned int r, unsigned int g, unsigned int b)
{
   SDL_Texture *SRet = NULL;
   SDL_Surface *temp  = SDL_LoadBMP(fname);
   if(temp == NULL)
   {
	   Debug("Unable to load")
   }
   else
   {
	   SDL_SetColorKey(temp, SDL_TRUE, SDL_MapRGB(temp->format, r,b,g));
       SRet = SDL_CreateTextureFromSurface(render, temp);
       SDL_FreeSurface(temp);
       if(SRet == NULL)
       {
    	   Debug( UNABLE_LOAD_IMG )
       }

   }
   return SRet;
}


void CargarRecursos()
{

	player.img = CargarImagen("player.bmp", 0, 0, 0);
    if(player.img == NULL)
    	Debug( UNABLE_LOAD_IMG )
     else
    	Debug(LOADED)


    player.crop.w = 48;
    player.crop.h = 48;
    player.crop.x = 0;
    player.crop.y = 0;

    player.offset.w = 48;
    player.offset.h = 48;
    player.offset.x = 10;
    player.offset.y = 400;

    player.EstaCallendo = true;
    player.EstaSaltando = false;

/* map */

    LoadTile(&tile,"testmap.map");

    TestTileset.res = CargarImagen("tileset.bmp", 0, 0, 0);
    if(TestTileset.res == NULL)
    {
    	Debug("the tileset Could not be loaded")
    }


/*enemigos area*/

}


void FixBounds()
{
  if(player.offset.x <= 0 )
     player.offset.x =   TAMANO_PANTALLA_ANCHO + 32;

  if(player.offset.x >= TAMANO_PANTALLA_ANCHO)
     player.offset.x -=  32;

  if(player.offset.y <= 0)
     player.offset.y = TAMANO_PANTALLA_ALTO    + 32;

  if(player.offset.y >= TAMANO_PANTALLA_ALTO)
     player.offset.y  -= 32;
}


void LoadTile(vector<Tile> *ref,const char *fname)
{
    ifstream file_(fname);
    vector<string>mapa;
    string linea;
    Tile t;
    unsigned int x  = 0;
    unsigned int y  = 0;
    int type  = 0;
    const int TILESIZE =48;

    if(!file_.is_open())
    {
    	Debug("the map file could not be open!")

    }
    else
    {
    	while(getline(file_, linea))
    	{
    	   mapa.push_back(linea);
    	   Debug(linea);
    	}
    	file_.close();
    	Debug("file close")
        for(unsigned int outer = 0; outer < mapa.size(); outer++ )
        {
           for(unsigned int inner = 0 ; inner < mapa[outer].size(); inner++)
           {


        	   if(mapa[outer].at(inner) == '1')
        	   {
        		   Debug(BuildString("Cargando Terreno 1",mapa[outer].at(inner) ))
        	       type = 0;
        	   }
        	   if(mapa[outer].at(inner) == '4')
        	   {
        	       Debug(BuildString("Cargando Terreno 4",mapa[outer].at(inner) ))
        	       type = 48;
        	   }

        	  t.crop.x = type;
        	  t.crop.y = 0;
        	  t.crop.w = TILESIZE;
        	  t.crop.h = TILESIZE;

        	  t.offset.x = x;
        	  t.offset.y = y;
        	  t.offset.w = TILESIZE;
        	  t.offset.h = TILESIZE;

        	  x += 48;
        	  if(x >= TAMANO_PANTALLA_ANCHO )
        	  {
        		  x = 0;
        		  y += TILESIZE;
        	  }
             Debug(BuildString("value of X ", x))
             Debug(BuildString("value of Y", y ))
             ref->push_back(t);
           }
        }
    }

}

void DrawMap()
{
	   Debug("Drawing map")
   for(unsigned int i= 0; i < tile.size(); i++)
   {
	   Debug(BuildString("OFFSET X ", tile[i].offset.x))
	   Debug(BuildString("OFFSET Y ", tile[i].offset.y))
	   SDL_RenderCopy(render, TestTileset.res, &tile[i].crop, &tile[i].offset);
   }
}
bool IsTouchingTheWall()
{
   for(unsigned int in= 0; in < tile.size(); in++)
   {
     ///no implemented yet 
  }
}


int Destroy()
{
	debug()
   SDL_DestroyWindow(window);
   SDL_DestroyRenderer(render);
   SDL_Quit();
   return gReturn;
}

this code only load a " sprite " and draw a map , im really not sure how to implement scroll and if this touching the wall and gravity , i wrotte another code where i can jump the sprite but the gravity is like is in the space , I would any advice from you thank you .

and apologize my english im learning too...

I am just going to dump what I see here, so it might not be well organized

[background=#fafbfc]__DATE__ and __TIME__ mark the time the program was compiled, not when the code is run. What that the intended use?[/background]

[background=#fafbfc][size=13]Your structs contain data but don't have any methods. You would benefit from putting methods on your structs and making their data private. That way your data is much better encapsulated and follows oop principles.[/background]

[background=#fafbfc][size=13]You change the players position based on a velocity but don't take into account the amount of time between frames. This means the players movement will depend on the frame rate. You are better off using velocity as units/second and multiplying that value by seconds since the last frame.[/background]

Use pointers only if NULL is an acceptable value

void LoadTile(vector<Tile> *ref,const char *fname)
Pass by reference if you want to modify the passed value

void LoadTile(vector<Tile> &ref,const char *fname)
I would add a list of sprites to your TileSet and have your map type value refer to what tile in the tileset to use


if(mapa[outer].at(inner) == '1')
{
    Debug(BuildString("Cargando Terreno 1",mapa[outer].at(inner) ))
    type = 0;
}
if(mapa[outer].at(inner) == '4')
{
    Debug(BuildString("Cargando Terreno 4",mapa[outer].at(inner) ))
    type = 48;
}
t.crop.x = type;
t.crop.y = 0;
t.crop.w = TILESIZE;
t.crop.h = TILESIZE;
You could have something like this


struct Sprite
{
    SDL_Texture* texture;
    SDL_Rect crop;
};

struct TileSet
{
    vector<Sprite> tiles;
};

t.sprite = TestTileset.tiles.at(atoi(mapa[outer].at(inner)));
My current game project Platform RPG
Advertisement

thank you for answer I Did put the __TIME__ and other stuff because im debugging but it could be fixed.

im understand a lilte bit the other stuff but do you think the other part is ok ?

I know I need to fix the FrameRate Control function and also would recommend something to check when it collide to a " wall " ?

A vector of tiles seems a bit wasteful. instead of using X amount of bytes and copying data around. You can store your tile definitions in an Array. But for your actual map draws, you refer to them by the ID located in the array. This, of course, assumes that you will have a fixed tile definition.

Vector<TILES> TileData // Only stores information about a reusable tile.
Vector<Vector<MAP>> MapLayout // Stores ints that points to information from the

What this does for you, is reduce your memory usage. Slightly decouples your Tile Map structure from your local array.

From the looks of it, you are also storing offset information. Unless the Tiles are varied in size, this is a bit unnecessary as well. You can set it to a fixed amount with a #define, or ENUM.

The ENUM would be better as you can use it during run time to add some varying sizes. Better yet. just Static Constant variables

Example

static constant unsigned int16 FLAG_TILE_SIZE_8
FLAG_TILE_SIZE_16
FLAG_TILE_SIZE_32

FLAG_TILE_SIZE_64 = 16448 //BitCompression. Two 8bit unsigned ints in one. 64 = 01000000. The last 8bits = 64. use some Bitwise functions to extract this data. With this in mind. You can compress two different sizes into one int.

Obviously that is a bit complicated, and probably ridiculously stupid. I just did that when I worked with tiles to make it hard to screw up. Had little to do with saving space. More so with a common name for formats.

#define DEBUG 1
#ifdef DEBUG

You need "#if DEBUG" here, "#ifdef DEBUG" tests whether 'DEBUG' exists (without caring about its value). "#define DEBUG 0" still defines the DEBUG variable.

how to implement scroll and if this touching the wall and gravity , i wrotte another code where i can jump the sprite but the gravity is like is in the space , I would any advice from you thank you .

You did not include DrawMap(), but I think you just draw tile (0, 0) at position (0, 0), ie top-left or so.
Scrolling can be done by keeping track of the tile to draw at the top-left corner. If you draw tile (1, 0) at (0, 0), everything shifts a single tile to the left.

Not walking through a wall can be done by checking if the player does not enter a wall tile after a move. If he does, move him back (or move him to just before 'entering' the wall).
Gravity is done by having a vertical speed. (I assume negative is up, and positive is down. If you have it the other way around, change the signs).
Add a vertical speed to the player. Add that to the y position (y is vertical for me) every frame (which like the horizontal update, should be compensated fro frame delay as HappyCoder explained).
On jump, set it to a negative value. Now the player moves up every frame.
In addition, add a small value to the speed each frame (again, compensate for time between frames).
This means the player moves up less, every frame, and eventually starts going downward.
When he hits the ground, set the speed to 0 (and do not add a small value to it as long as he is standing on solid ground).

This topic is closed to new replies.

Advertisement