I tried removing the = NULL assigning, but it wont let me remove the static keyword ( I think merely creating a pointer to a surface is actually assigning it, assigning NULL to it initially just ensures it doesnt access a forbidden area of memory).
I tried moving the whole lot to the IO.cpp but then the classes outside IO dont know about the pointers to the surfaces.
I tried creating a SDL_Surface object called mMainScreen in the IO.h file , and then a pointer to SDL_Surface *mMainScreen in the IO.cpp but the compiler told me there was no suitable conversion from a mMainScreen to mMainScreen*.
I am posting the code to the IO and World classes if that will help.
This is my IO.h
#ifndef IO_H_
#define IO_H_
#include<iostream>
#include<fstream>
#include<sstream>
#include<ctime> // For time()
#include<cstdlib> // For srand() and rand()
#include<math.h> // for math function like square root and cosine.
#include<vector>
#include"SDL.h"
#include"SDL_ttf.h"
#include"SDL_image.h"
#include"timer.h"
#include"world.h"
/////////////////////////////////////////////////////////////////////////////////////////
//
//
// IO CLASS - provides via SDL access to the PC hardware, and provides some utility
// functions such as draw_text.
//
//
namespace IO
{
///////////////////////////////////////////////////////////////////////
// pointers to the surfaces
static SDL_Surface *mMainScreen = NULL;
static SDL_Surface *mGameWorld = NULL;
static SDL_Surface *mPlayer = NULL;
static SDL_Surface *mAli = NULL;
///////////////////////////////////////////////////////////////////////
// text colour
static SDL_Color textColor = { 0, 0, 255 };
///////////////////////////////////////////////////////////////////////
// pointer to the font
static TTF_Font *mFont = NULL;
///////////////////////////////////////////////////////////////////////
// counters and setter ints
static unsigned int msgBufferSize = 0;
static unsigned int msgStart = 0;
static unsigned int numberMsgToShow = 27;
///////////////////////////////////////////////////////////////////////
// IO Functions
int init();
void clean_up();
void draw_text( std::string msg, int x, int y );
SDL_Surface *load_image( std::string filename );
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip );
void draw( int x, int y, int subject, SDL_Rect* clip );
bool load_files();
void update_screen();
////////////////////////////////////////////////////////////////////////
// Console control functions
void report_screen( std::string msg );
void show_message();
void set_msgStart_increase();
void set_msgStart_decrease();
void set_tileCounter_inc();
void set_tileCounter_dec();
};
#endif
This is my IO.cpp
#include"io.h"
#include"global.h"
using std::vector;
/////////////////////////////////////////////////////////////////////////////////////////
//
//
// IO CLASS - provides via SDL access to the PC hardware, and provides some utility
// functions such as draw_text.
//
// global.h is a header file that defines constants and enums that are needed by all
// the classes.
//
//
////////////////////////////////////////////////////////////////////
// Local Data
static vector<std::string> msgBuffer;
static unsigned int lastTextX = 30; // provide the x value for the report function to pass to draw_text
static unsigned int lastTextY = 30; // proved the y value and is incremented to allow for a newline for each report
static unsigned int msgCount = 0; // counts the number of messages stored , used for limiting the number of messages displayed
static unsigned int tilesCounter = 0;
///////////////////////////////////////////////////////////////////
// IO Functions
int IO::init()
{
// Initialises the entire main SDL library,
// note it is possible to init portions individually
if ( SDL_Init(SDL_INIT_EVERYTHING) == -1 )
{
std::cerr << "Error init SDL_INIT_EVERYTHING" << std::endl;
return -1;
}
// Sets the main screen where all the surfaces will be blitted to,
// this sets the size and mode of the screen.
mMainScreen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
if ( mMainScreen == NULL )
{
std::cerr << "Error setting mainscreen surface" << std::endl;
return -1;
}
// Initialises the TTF sub library
if ( TTF_Init() == -1 )
{
std::cerr << "Error init TTF_Init" << std::endl;
return -1;
}
// Sets the title of the window
SDL_WM_SetCaption ( " Kickin' Sticks WIP --- Average Frames Per Second: ", NULL );
// open the font
mFont = TTF_OpenFont( "GFX/exprswy free.ttf", 16);
if ( mFont == NULL )
{
std::cerr << "Error loading exprswy free.ttf" << std::endl;
return -1;
}
// Now the program can report whats happening via the report_screen func
//////////////////////////////////////////////////////
//
// load the graphic sprite and tilesheet files
// Intend to expand this to a resource manager
// if the files become too much when using
// audio
//
report_screen( "This report was removed before posting to TIG" );
report_screen( "---------------------------------------------" );
report_screen( "SDL Init : OK" ); // SDL and TTF are assumed to have been init properly
report_screen( "TTF_Init : OK" ); // otherwise text display wouldnt be possible.
report_screen( "loading resources... " );
SDL_Delay( 800 ); // added for effect , not required at all.
if ( load_files() == false )
{
return -1;
}
report_screen( "Init and Load completed, starting game...." );
SDL_Delay( 800 ); // added for effect , not required at all.
// If everything initialises properly return true to the caller.
return 0;
}
void IO::clean_up()
{
report_screen( "Clean up function called..."); // Just to see the function IS getting called
SDL_Delay( 800 ); // gimme some time to see the report will ya :P
SDL_FreeSurface ( mGameWorld );
SDL_FreeSurface ( mPlayer );
SDL_FreeSurface ( mAli );
// Function frees up surfaces used, then shuts down the TTF and SDL libraries.
TTF_CloseFont( mFont );
TTF_Quit();
SDL_Quit();
}
void IO::draw_text( std::string msg, int x, int y )
{
SDL_Rect coordinates;
coordinates.x = (int)x;
coordinates.y = (int)y;
SDL_Surface *message = NULL;
message = TTF_RenderText_Solid( mFont, msg.c_str(), textColor );
SDL_BlitSurface( message, NULL, mMainScreen, &coordinates );
SDL_FreeSurface( message );
}
void IO::update_screen()
{
SDL_Flip( mMainScreen );
}
SDL_Surface *IO::load_image( std::string filename )
{
///////////////////////////////////////////////////////////////////////
// This function takes a graphics file to be loaded , it puts it on a
// temporary surface then uses SDL_DisplayFormat to optimise the
// image and then return the optimised image back to the caller.
//
SDL_Surface* loadedImage = NULL;
SDL_Surface* optimisedImage = NULL;
loadedImage = IMG_Load ( filename.c_str() );
if ( loadedImage != NULL )
{
optimisedImage = SDL_DisplayFormat( loadedImage );
SDL_FreeSurface( loadedImage );
if ( optimisedImage != NULL )
{
// Change the ->format RGB values to the colour that is the suppose to be transparent
// Currently its a purple colour.
SDL_SetColorKey( optimisedImage, SDL_SRCCOLORKEY,
SDL_MapRGB( optimisedImage->format, 0xA3, 0x4D, 0xFD ) );
}
}
///////////////////////////////////////////////
// Reports which file was loaded
// Could be improved with IO file checks
std::string buffer;
std::stringstream ss;
ss << "Loaded : " << filename ;
buffer = ss.str();
report_screen( buffer );
// End report block
///////////////////////////////////////////////
return optimisedImage;
}
void IO::apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL )
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
SDL_BlitSurface( source, clip, destination, &offset );
}
void IO::draw( int x, int y, int subject, SDL_Rect *clip )
{
SDL_Rect clips = *clip;
if ( subject == DRAW_TILE )
{ apply_surface( x, y, mGameWorld, mMainScreen, &clips ); }
}
bool IO::load_files()
{
mGameWorld = load_image( "GFX/tiles.png" );
if ( mGameWorld == NULL )
{
return false;
}
mPlayer = load_image( "GFX/stick.png" );
if ( mPlayer == NULL )
{
return false;
}
mAli = load_image( "GFX/kickassest.png" );
if ( mAli == NULL )
{
return false;
}
return true;
}
////////////////////////////////////////////////////////////////
// Console Control functions
void IO::report_screen( std::string msg )
{
std::string pushMsg = msg; // put the parameter string into a temp variable
msgBuffer.push_back( pushMsg ); // add the string in the temp variable to the vector
msgCount ++; // increment the msg counter ( temp check to count messages generated )
if ( msgCount > numberMsgToShow ) // this IF basically checks to see if the
{ // number of msgs is more than the number it should
msgStart ++; // show at one time, if it is it increments from where
} // the show_message start listing the vector of strings,
// IE messages ( limited to 27 msgs on screen at 1 time )
show_message();
}
void IO::show_message()
{
// SDL_FillRect( SDL_GetVideoSurface(), NULL, 0 ); // Clear the screen ( paint it black - warning: slow )
/////////////////////////////////////////////////////////////////////////
// Loop to go through the vector of messages and print them to screen
unsigned int tTxtLimit = numberMsgToShow + msgStart;
if ( tTxtLimit > msgBuffer.size() ) { tTxtLimit = msgBuffer.size(); }
for ( unsigned int i = 0 + msgStart; i < tTxtLimit; i++ ) // note msgStart here
{
std::string tMsg = msgBuffer[i];
draw_text( tMsg, lastTextX, lastTextY );
lastTextY += 20;
} // end of for loop
// End of loop
//
/////////////////////////////////////////////////////////////////////////
lastTextY = 30; // Resets the y value ready for the next call to report
////////////////////////////////////////////////////////////////////////
// Temp block to report the number of messages stored in the msgBuffer
std::string buffer;
std::stringstream ss;
ss << "Number of Messages [ " << msgCount << " ] " << " [ " << tilesCounter << " ] " ;
buffer = ss.str();
draw_text( buffer, SCREEN_WIDTH - 270, SCREEN_HEIGHT -25 );
// End block
////////////////////////////////////////////////////////////////////////
update_screen(); // Updates the screen so the messages get displayed
}
void IO::set_msgStart_increase()
{
if ( msgStart >= msgBuffer.size() ) { msgStart = msgBuffer.size(); } else msgStart ++;
show_message();
}
void IO::set_msgStart_decrease()
{
if ( msgStart <= 0 ) { msgStart = 0; } else msgStart -- ;
show_message();
}
void IO::set_tileCounter_inc()
{
tilesCounter++;
show_message();
}
void IO::set_tileCounter_dec()
{
tilesCounter--;
show_message();
}
//
// End of IO class
//
//////////////////////////////////////////////////////////////////////////////////////////////
This is my World.h
#ifndef WORLD_H_
#define WORLD_H_
#include"IO.h"
#include"global.h"
class Tile;
namespace K_WORLD
{
///////////////////////////////////////////////////////////////
// Pointer to tiles and a array of SDL_Rects holding clip data
static std::vector<Tile*> mTiles;
static SDL_Rect clips[ TILE_TYPES ];
///////////////////////////////////////////////////////////////
// K_World Functions
bool set_tiles();
void show_tiles();
void clean_tiles();
void clip_tiles();
};
#endif
This is my World.cpp
#include"world.h"
#include"tile.h"
/////////////////////////////////////////////////////////////////////////////
// K_WORLD Functions
bool K_WORLD::set_tiles()
{
int x = 0, y = 0;
std::ifstream map( "GFX/lazy.map" );
if ( map == NULL )
{
return false;
}
IO::report_screen( "Loading Tile Map ...." );
for ( int t = 0; t < TOTAL_TILES; t++ )
{
int tileType = -1;
map >> tileType;
if( map.fail() == true )
{
map.close();
return false;
}
if( ( tileType >=0 ) && ( tileType < TILE_TYPES ) )
{
mTiles.push_back( new Tile ( x , y , tileType ) );
IO::set_tileCounter_inc();
}
else
{
map.close();
return false;
}
x += TILE_WIDTH;
if( x >= LEVEL_WIDTH )
{
x = 0;
y += TILE_HEIGHT;
}
if( ( tileType >=4 ) && ( tileType < TILE_TYPES ) )
{
mTiles[ t ]->mTileState = TILE_COLLIDE ;
} else mTiles[ t ]->mTileState = TILE_AVAILABLE ;
/*
///////////////////////////////////////////////////////////////////////
// Temp block to report info on the tile as its being created
std::string buffer;
std::stringstream ss;
ss << "Tile [ " << t << " ] Type [ " << tileType << " ] X [ " << x << " ] Y [ " << y << " ] State [ " << mTiles[ t ]->get_state();
buffer = ss.str();
IO::report_screen( buffer );
// end tile report block
//////////////////////////////////////////////////////////////////////
*/
}
map.close();
return true;
}
void K_WORLD::show_tiles()
{
for( int t = 0; t < TOTAL_TILES; t++ )
{
IO::draw( mTiles[ t ]->mTileXpos, mTiles[ t ]->mTileYpos, DRAW_TILE ,&clips[ mTiles[ t ]->mTileType ] );
// IO::apply_surface( mTiles[ t ]->mTileXpos, mTiles[ t ]->mTileYpos, IO::mGameWorld, IO::mMainScreen ,&clips[ mTiles[ t ]->mTileType ] );
}
}
void K_WORLD::clean_tiles ()
{
int tmpCount = 0;
IO::report_screen( "Clean Tiles function called ..." );
for( std::vector<Tile*>::iterator i = mTiles.begin(); i != mTiles.end(); ++i )
{
delete *i ;
IO::set_tileCounter_dec();
}
IO::report_screen( "Clean Tiles function completed" );
SDL_Delay ( 400 );
}
void K_WORLD::clip_tiles()
{
IO::report_screen( "Clipping World Tiles... " );
// Clip the tile sprites for the level
clips[ TILE_RED ].x = 0;
clips[ TILE_RED ].y = TILE_HEIGHT * 3;
clips[ TILE_RED ].w = TILE_WIDTH;
clips[ TILE_RED ].h = TILE_HEIGHT;
clips[ TILE_GREEN ].x = TILE_WIDTH;
clips[ TILE_GREEN ].y = TILE_HEIGHT * 3;
clips[ TILE_GREEN ].w = TILE_WIDTH;
clips[ TILE_GREEN ].h = TILE_HEIGHT;
clips[ TILE_BLUE ].x = TILE_WIDTH * 2;
clips[ TILE_BLUE ].y = TILE_HEIGHT * 3;
clips[ TILE_BLUE ].w = TILE_WIDTH;
clips[ TILE_BLUE ].h = TILE_HEIGHT;
clips[ TILE_TOPLEFT ].x = 0;
clips[ TILE_TOPLEFT ].y = 0;
clips[ TILE_TOPLEFT ].w = TILE_WIDTH;
clips[ TILE_TOPLEFT ].h = TILE_HEIGHT;
clips[ TILE_LEFT ].x = 0;
clips[ TILE_LEFT ].y = TILE_HEIGHT;
clips[ TILE_LEFT ].w = TILE_WIDTH;
clips[ TILE_LEFT ].h = TILE_HEIGHT;
clips[ TILE_BOTTOMLEFT ].x = 0;
clips[ TILE_BOTTOMLEFT ].y = TILE_HEIGHT * 2;
clips[ TILE_BOTTOMLEFT ].w = TILE_WIDTH;
clips[ TILE_BOTTOMLEFT ].h = TILE_HEIGHT;
clips[ TILE_TOP ].x = TILE_WIDTH;
clips[ TILE_TOP ].y = 0;
clips[ TILE_TOP ].w = TILE_WIDTH;
clips[ TILE_TOP ].h = TILE_HEIGHT;
clips[ TILE_CENTER ].x = TILE_WIDTH;
clips[ TILE_CENTER ].y = TILE_HEIGHT;
clips[ TILE_CENTER ].w = TILE_WIDTH;
clips[ TILE_CENTER ].h = TILE_HEIGHT;
clips[ TILE_BOTTOM ].x = TILE_WIDTH;
clips[ TILE_BOTTOM ].y = TILE_HEIGHT * 2;
clips[ TILE_BOTTOM ].w = TILE_WIDTH;
clips[ TILE_BOTTOM ].h = TILE_HEIGHT;
clips[ TILE_TOPRIGHT ].x = TILE_WIDTH * 2;
clips[ TILE_TOPRIGHT ].y = 0;
clips[ TILE_TOPRIGHT ].w = TILE_WIDTH;
clips[ TILE_TOPRIGHT ].h = TILE_HEIGHT;
clips[ TILE_RIGHT ].x = TILE_WIDTH * 2;
clips[ TILE_RIGHT ].y = TILE_HEIGHT;
clips[ TILE_RIGHT ].w = TILE_WIDTH;
clips[ TILE_RIGHT ].h = TILE_HEIGHT;
clips[ TILE_BOTTOMRIGHT ].x = TILE_WIDTH * 2;
clips[ TILE_BOTTOMRIGHT ].y = TILE_HEIGHT * 2;
clips[ TILE_BOTTOMRIGHT ].w = TILE_WIDTH;
clips[ TILE_BOTTOMRIGHT ].h = TILE_HEIGHT;
// Temp clips for the hole and the explosion
clips[ TILE_HOLE ].x = TILE_WIDTH;
clips[ TILE_HOLE ].y = TILE_HEIGHT * 3;
clips[ TILE_HOLE ].w = TILE_WIDTH;
clips[ TILE_HOLE ].h = TILE_HEIGHT;
clips[ TILE_EXPLOSION ].x = TILE_WIDTH;
clips[ TILE_EXPLOSION ].y = TILE_HEIGHT * 4;
clips[ TILE_EXPLOSION ].w = TILE_WIDTH;
clips[ TILE_EXPLOSION ].h = TILE_HEIGHT;
}
The code works in the current form which comments out :
// IO::apply_surface( mTiles[ t ]->mTileXpos, mTiles[ t ]->mTileYpos, IO::mGameWorld, IO::mMainScreen ,&clips[ mTiles[ t ]->mTileType ] );
and uses the makeshift function :
IO::draw( mTiles[ t ]->mTileXpos, mTiles[ t ]->mTileYpos, DRAW_TILE ,&clips[ mTiles[ t ]->mTileType ] );
... so I am assuming the clipping and accessing the location and type, plus all the mapping worked as intended and only the pointers are the issue.