Hi,
I know C pretty well, but now am learning C++.
I am writing a maze program that wants to have a Windows (SDL) timer call back to a
member function in the Maze class.
The compiler is complaining, and I can't quite figure it out. It has to do with the SDL_AddTimer() function which needs a function pointer to Maze::Maze_timer_update() (see red in maze.cpp below).
Code:
C:\Prj\codeblocks\Amazing\maze.cpp||In constructor `Maze::Maze(unsigned int, unsigned int, unsigned int)':|
C:\Prj\codeblocks\Amazing\maze.cpp|24|error: cannot convert `Uint32 (Maze::*)(Uint32, void*)' to `Uint32 (*)(Uint32, void*)' for argument `2' to `_SDL_TimerID* SDL_AddTimer(Uint32, Uint32 (*)(Uint32, void*), void*)'|
C:\Prj\codeblocks\Amazing\maze.cpp|20|warning: unused variable 'Maze_array'|
C:\Prj\codeblocks\Amazing\maze.cpp|24|warning: unused variable 'Maze_timer'|
||=== Build finished: 1 errors, 2 warnings ===|
Also, I'm not clear on how the member declaration should work to allow access to
Maze::Maze_timer_update(). It shouldn't be public, but private doesn't seem right
either. It should probably be a friend, but I don't see how to give just SDL access to it.
Any help is appreciated.
Maze.h:
Code:
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#ifdef __APPLE__
#include <SDL/SDL.h>
#else
#include <SDL.h>
#endif
#ifndef maze_h
#define maze_h
#include <stack>
#include <time.h>
typedef struct int_vector_s {
int x;
int y;
} int_vector_t;
typedef enum MazeDirs_e {
up=0,
dn,
lf,
rt,
dirs_last
} MazeDirs_t;
class Maze {
private:
bool *WallLocations;
SDL_Surface *screen;
MazeDirs_t MazeOptsMoves[dirs_last];
int MazeOptsMovesAvail;
bool MazeDirsOK[dirs_last];
std::stack <int_vector_t> MazeTravelStack;
uint16_t MazeTravelDist;
MazeDirs_t MazeTravelDir;
uint16_t MazeTravelXpos;
uint16_t MazeTravelYpos;
bool *Maze_array;
SDL_Surface *Maze_screen;
SDL_TimerID Maze_timer;
public:
Uint8 WallThickness; // Thickness of wall in pizxels
Uint16 Width; // Width of maze in wall thicknesses (must be odd)
Uint16 Height; // Height of maze in wall thicknesses (must be odd)
Uint32 Maze_timer_update(Uint32 interval, void *UserData);
Maze::Maze( unsigned int Width, unsigned int Height, unsigned int Wallthickness );
Maze::~Maze();
void Maze_iterate(class Maze* const);
void Maze::Maze_draw(class Maze* const);
};
#endif
maze.cpp:
Code:
#ifdef __cplusplus
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#ifdef __APPLE__
#include <SDL/SDL.h>
#else
#include <SDL.h>
#endif
#include "maze.h"
#define MAZE_WALL_ELEMENT(MAZE,X,Y) (*((MAZE)->WallLocations+(MAZE)->Width*(Y)+(X)))
Maze::Maze( unsigned int Width, unsigned int Height, unsigned int Wallthickness ) {
MazeTravelStack.push( (int_vector_t){1,1} );
bool Maze_array = malloc( Width * Height * sizeof(bool) );
Maze_screen = SDL_SetVideoMode(Width*Wallthickness, Height*Wallthickness, 8, SDL_HWSURFACE|SDL_DOUBLEBUF);
SDL_TimerID Maze_timer = SDL_AddTimer(2000, &Maze::Maze_timer_update, this);
srand ( time(NULL) );
// clear screen
SDL_FillRect(this->screen, 0, SDL_MapRGB(this->screen->format, 0xff, 0xff, 0xff));
{
this->MazeTravelXpos = 1;
this->MazeTravelYpos = 1;
int x;
int y;
for (x=0; x<this->Width; x++) {
for (y=0; y<this->Height; y++) {
MAZE_WALL_ELEMENT(this,x,y) = x&1 && y&1 ? false : true;
}
}
}
}
Maze::~Maze() {
free (Maze::Maze_array);
}
Uint32 Maze::Maze_timer_update(Uint32 interval, void *UserData) {
Maze_iterate(this);
Maze_draw(this);
return interval;
}
void Maze::Maze_iterate(class Maze* const) {
if ( this->MazeTravelStack.size() || this->MazeOptsMovesAvail ) {
this->MazeOptsMovesAvail = 0;
if (
MazeTravelYpos>2
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos ,MazeTravelYpos-1)
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos ,MazeTravelYpos-3)
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos-1,MazeTravelYpos-2)
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos+1,MazeTravelYpos-2)
) {
MazeDirsOK[up]=true;
this->MazeOptsMoves[this->MazeOptsMovesAvail++] = up;
}
else {
MazeDirsOK[up]=false;
}
if (
MazeTravelYpos<this->Height-3
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos ,MazeTravelYpos+1)
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos ,MazeTravelYpos+3)
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos-1,MazeTravelYpos+2)
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos+1,MazeTravelYpos+2)
) {
MazeDirsOK[dn]=true;
this->MazeOptsMoves[this->MazeOptsMovesAvail++] = dn;
}
else {
MazeDirsOK[dn]=false;
}
if (
MazeTravelXpos>2
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos-1,MazeTravelYpos )
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos-3,MazeTravelYpos )
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos-2,MazeTravelYpos-1)
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos-2,MazeTravelYpos+1)
) {
MazeDirsOK[lf]=true;
this->MazeOptsMoves[this->MazeOptsMovesAvail++] = lf;
}
else {
MazeDirsOK[lf]=false;
}
if (
MazeTravelXpos<this->Width-3
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos+1,MazeTravelYpos )
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos+3,MazeTravelYpos )
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos+2,MazeTravelYpos-1)
&& MAZE_WALL_ELEMENT(this,MazeTravelXpos+2,MazeTravelYpos+1)
) {
MazeDirsOK[rt]=true;
this->MazeOptsMoves[this->MazeOptsMovesAvail++] = rt;
}
else {
MazeDirsOK[rt]=false;
}
// We know which directions are OK, so now check:
// if we run out of travel distance or the next step in the
// current direction is not valid, we must pick a new acceptable direction.
if ( this->MazeOptsMovesAvail ) {
if ( !MazeTravelDist || !MazeDirsOK[MazeTravelDir] ) {
MazeTravelDist = rand()%6+1;
MazeTravelDir = this->MazeOptsMoves[rand()%this->MazeOptsMovesAvail];
MazeTravelStack.top().x = MazeTravelXpos;
MazeTravelStack.top().y = MazeTravelYpos;
}
else {
MazeTravelDist--;
}
// Ok, now we punch through a wall.
switch ( MazeTravelDir ) {
case up:
MAZE_WALL_ELEMENT(this,MazeTravelXpos ,MazeTravelYpos-1) = false;
MazeTravelYpos-=2;
break;
case dn:
MAZE_WALL_ELEMENT(this,MazeTravelXpos ,MazeTravelYpos+1) = false;
MazeTravelYpos+=2;
break;
case lf:
MAZE_WALL_ELEMENT(this,MazeTravelXpos-1,MazeTravelYpos ) = false;
MazeTravelXpos-=2;
break;
case rt:
MAZE_WALL_ELEMENT(this,MazeTravelXpos+1,MazeTravelYpos ) = false;
MazeTravelXpos+=2;
break;
case dirs_last:
break;
}
}
else {
// Can't turn anywhere, so we must pop back on the stack.
if ( MazeTravelStack.size()>1 ) {
MazeTravelXpos = MazeTravelStack.top().x;
MazeTravelYpos = MazeTravelStack.top().y;
}
}
}
}
void Maze::Maze_draw(class Maze* const) {
// Draw the maze on the screen
int x;
int y;
Uint8 *p;
Uint8 MazeWallBlockX; // This is for filling in blocks in the wall when the block is more than 1 pizel across.
Uint8 MazeWallBlockY; // This is for filling in blocks in the wall when the block is more than 1 pizel across.
for (x=0; x<this->Width; x++) {
for (y=0; y<this->Height; y++) {
if ( MAZE_WALL_ELEMENT(this,x,y) ) {
for (MazeWallBlockX=0; MazeWallBlockX<this->WallThickness; MazeWallBlockX++) {
for (MazeWallBlockY=0; MazeWallBlockY<this->WallThickness; MazeWallBlockY++) {
p = (Uint8 *)(this->screen->pixels) + (y*this->WallThickness+MazeWallBlockY) * this->screen->pitch + (x*this->WallThickness+MazeWallBlockX) * this->screen->format->BytesPerPixel;
*p = 0;
}
}
}
}
}
SDL_Flip(this->screen);
}