Project
OS
Win
win_main.c // codice specifico per Windows
Game
g_main.c // codice di gioco
Libraries
l_module.c // librerie e funzioni astratte
GFX
l_openGL.c // implementazione funzioni grafica
SND
l_openAL.c // implementazione funzioni audio
// ---------------------------------------------
// - TEXTURE
// ---------------------------------------------
int tex_core_create(int width,int height,void*data,int mode);
// ---------------------------------------------
int tex_readTGA(const char*s,int mode);
void tex_delete(int*textID);
// ---------------------------------------------
// ---------------------------------------------
// - GRAPHIC
// ---------------------------------------------
int gfx_init();
int gfx_reset();
void gfx_enable2D(int enable);
void gfx_cleanSCREEN();
void gfx_drawBOX(float x,float y,float w,float h,float r,float g,float b,float alpha);
void gfx_drawSPRITE(float x,float y,float w,float h,int textID,float tx,float ty,float tw,float th,float alpha,float scale,int dir);
// ---------------------------------------------
// ---------------------------------------------
// - SOUND
// ---------------------------------------------
int wav_read(const char*s,int mode);
int wav_delete(int*waveID);
// ---------------------------------------------
int snd_init();
int snd_reset();
int snd_play(int waveID,int loop,int mode);
int snd_stop(int playwaveID);
int snd_pause(int playwaveID);
// ---------------------------------------------
if(game_init)
{
game_loop
game_reset
}
int GAME_init(WORLD*w,const char*res_basepath,float width,float height)
{
strcpy(os_szResPath,res_basepath);
os_video_w=width;
os_video_h=height;
gfx_init();
snd_init();
gfx_enable2D(1);
return 1;
}
int GAME_reset(WORLD*w)
{
gfx_enable2D(0);
snd_reset();
gfx_reset();
return 1;
}
void GAME_loop(WORLD*w)
{
// to do!
}
char orig_maze[11][20]= { "11111111111111111111",
"1.o..1........1..o.1",
"1.11.1.111111.1.11.1",
"1.1..............1.1",
"1.1.11.11 11.11.1.1",
"1......1ABCD1......1",
"1.1.11.111111.11.1.1",
"1.1.......*......1.1",
"1.11.1.111111.1.11.1",
"1.o..1........1..o.1",
"11111111111111111111"
};
Based on http://www-inst.eecs.berkeley.edu/~cs188/pacman/projects/multiagent/pacman_multi_agent.png
void drawMAZE(WORLD*w)
{
int msx=20,msy=11;
float x,y,sx=os_video_w/msx,float sy=os_video_h/msy;
for(y=0; y<sy; y++)
for(x=0; x<sx; x++)
{
float px=x*sx,py=y*sy;
switch(orig_maze[(int)y][(int)x])
{
case '1': gfx_drawBOX(px,py,sx,sy,0,0,0.5f,1); break;
case '.': gfx_drawBOX(px+sx/2-sx/10,py+sy/2-sx/10,sx/5,sx/5,1,1,1,1); break;
case 'o': gfx_drawBOX(px+sx/2-sx/4,py+sy/2-sx/4,sx/2,sx/2,1,1,0,1); break;
}
}
}
void GAME_loop(WORLD*w)
{
INGAME_handleUI(w);
INGAME_action(w);
INGAME_draw(w);
}
int INGAME_handleUI(WORLD*w)
{
return 1;
}
int INGAME_action(WORLD*w)
{
return 1;
}
int INGAME_draw(WORLD*w)
{
gfx_cleanSCREEN();
drawMAZE(w);
return 1;
}
int GAME_init(WORLD*w,const char*res_basepath,float width,float height)
{
strcpy(os_szResPath,res_basepath);
os_video_w=width;
os_video_h=height;
gfx_init();
snd_init();
gfx_enable2D(1);
GFXRES_init();
MATCH_init(w,1);
return 1;
}
// ---------------------------------------------
// - STRUCTURES
// ---------------------------------------------
typedef struct tagMAZE
{
char maze[11][20];
int sx,sy;
int home_x,home_y;
int coins;
} MAZE;
typedef struct tagWORLD{
MAZE M;
}WORLD;
http://www.javaonthebrain.com/java/msmidpman/spritecloseup.gif
typedef struct tagACTOR
{
float x,y;
int baseFrame,nFrames,curFrame,dir;
} ACTOR;
int g_nActors=5;
ACTOR g_actors[5],*g_player;
int g_textID;
int GFXRES_init()
{
g_textID=tex_readTGA("sprite.tga",0);
return (g_textID!=-1);
}
int GFXRES_reset()
{
tex_delete(&g_textID);
return 1;
}
int MATCH_init(WORLD*w,int way)
{
int x,y;
memset(&g_actors,0,sizeof(g_actors));
g_player=&g_actors[0];
if(way)
{
memset(&w->M,0,sizeof(w->M));
w->M.coins=0;
w->M.sx=20;
w->M.sy=11;
memcpy(w->M.maze,orig_maze,sizeof(orig_maze));
}
for(y=0; y<w->M.sy; y++)
for(x=0; x<w->M.sx; x++)
{
char ch=w->M.maze[y][x];
if((ch=='.')||(ch=='o'))
{
if(way)
w->M.coins++;
}
else if(ch=='*')
{
int wh=0;
ACTOR*a=&g_actors[wh];
a->x=x;
a->y=y;
a->baseFrame=0;
a->nFrames=3;
a->dir=dirLEFT;
}
else if((ch>='A')&&(ch<='D'))
{
int wh=1+(ch-'A');
ACTOR*a=&g_actors[wh];
if(ch=='B')
{
w->M.home_x=x;
w->M.home_y=y;
}
a->x=x;
a->y=y;
a->baseFrame=8+wh*8;
a->nFrames=2;
a->dir=wh;
}
}
return 1;
}
void drawACTORS(WORLD*w)
{
int i;
float sx=os_video_w/w->M.sx;
float sy=os_video_h/w->M.sy;
for(i=0; i<g_nActors; i++)
{
ACTOR*a=&g_actors[i];
float px=a->x*sx,py=a->y*sy;
int curframe=a->baseFrame+(a->dir-1)*a->nFrames+a->curFrame;
float fy=(curframe/8)*32.0f,fx=(curframe%8)*32.0f;
gfx_drawSPRITE(px,py,sx,sy,g_textID,fx,fy,32,32,1,1,0);
a->curFrame++;
if(a->curFrame>=a->nFrames)
a->curFrame=0;
}
}
int INGAME_draw(WORLD*w)
{
gfx_cleanSCREEN();
drawMAZE(w);
drawACTORS(w);
return 1;
}
#define dirUP 1
#define dirDOWN 2
#define dirLEFT 3
#define dirRIGHT 4
typedef struct tagWORLD{
int keys;
int score;
MAZE M;
}WORLD;
float l_dirX[5]= {0,0,0,-1,1};
float l_dirY[5]= {0,-1,1,0,0};
int INGAME_handleUI(WORLD*w)
{
w->keys=0;
#if defined(OS_WIN32)
if(GetKeyState(VK_UP) & 0x80 )
w->keys=dirUP;
else if(GetKeyState(VK_DOWN) & 0x80 )
w->keys=dirDOWN;
else if(GetKeyState(VK_LEFT) & 0x80 )
w->keys=dirLEFT;
else if(GetKeyState(VK_RIGHT) & 0x80 )
w->keys=dirRIGHT;
#endif
return 1;
}
int getavailableDIRS(MAZE*M,ACTOR*m,int*dir,int*mask,int check)
{
int x=(int)m->x,y=(int)m->y,ndirs=0;
if(mask) *mask=0;
if(x&&M->maze[y][x-1]!='1')
{
if((check==0)||(m->dir!=dirRIGHT))
{
if(dir) dir[ndirs++]=dirLEFT;
if(mask) *mask|=1;
}
}
if((x+1<M->sx)&&(M->maze[y][x+1]!='1'))
{
if((check==0)||(m->dir!=dirLEFT))
{
if(dir) dir[ndirs++]=dirRIGHT;
if(mask) *mask|=2;
}
}
if(y&&M->maze[y-1][x]!='1')
{
if((check==0)||(m->dir!=dirDOWN))
{
if(dir) dir[ndirs++]=dirUP;
if(mask) *mask|=4;
}
}
if((y+1<M->sy)&&(M->maze[y+1][x]!='1'))
{
if((check==0)||(m->dir!=dirUP))
{
if(dir) dir[ndirs++]=dirDOWN;
if(mask) *mask|=8;
}
}
return ndirs;
}
int chooseDIR(MAZE*M,ACTOR*m)
{
int dirs[4],ndirs=getavailableDIRS(M,m,dirs,NULL,1);
if(ndirs)
return dirs[rand()%ndirs];
else
return 0;
}
int INGAME_action(WORLD*w)
{
...
if(w->keys)
if(g_player->moving==0)
{
int i,dirs[4],ndirs=getavailableDIRS(&w->M,g_player,dirs,NULL,0);
for(i=0; i<ndirs; i++)
if(dirs[i]==w->keys)
{
g_player->dir_x=l_dirX[w->keys];
g_player->dir_y=l_dirY[w->keys];
g_player->dir=w->keys;
break;
}
}
...
}
...
if(g_actor->dir_x||g_actor->dir_y)
{
g_actor->x+=g_actor->dir_x*0.20f;
g_actor->y+=g_actor->dir_y*0.20f;
g_actor->moving++;
if(
(fabs(g_actor->x-g_actor->nx)<0.11f)&&
(fabs(g_actor->y-g_actor->ny)<0.11f)
)
{
g_actor->moving=0;
g_actor->x=g_actor->nx;
g_actor->y=g_actor->ny;
}
}
else
g_actor->moving=0;
...
if(g_actor->moving==0) { int x,y; x=(int)g_actor->x+g_actor->dir_x; y=(int)g_actor->y+g_actor->dir_y; if(w->M.maze[y][x]=='1') g_actor->dir_x=g_actor->dir_y=0; else { g_actor->nx=(int)g_actor->x+g_actor->dir_x; g_actor->ny=(int)g_actor->y+g_actor->dir_y;
} }
...
else
{
g_actor->nx=(int)g_actor->x+g_actor->dir_x;
g_actor->ny=(int)g_actor->y+g_actor->dir_y;
if(i==0) // solo il player può mangiare i coins
{
x=(int)g_actor->x;
y=(int)g_actor->y;
if(w->M.maze[y][x]=='.')
{
w->M.maze[y][x]=' ';
w->M.coins--;
w->score+=10;
}
}
}
int INGAME_postaction(WORLD*w)
{
...
if(w->M.coins==0)
{
MATCH_init(w,2); // WIN!
}
...
if(w->lifes>1)
{
w->lifes--;
MATCH_init(w,0);
}
else
{
... // GAME OVER
}
http://www.bigmessowires.com/atarifont.png
struct tagACTOR;
typedef int (*actionproc)(MAZE*M,struct tagACTOR*m);
typedef struct tagACTOR
{
float x,y;
float nx,ny;
float dir_x,dir_y;
int baseFrame,nFrames,curFrame;
int dir,moving,blink;
int movementmask;
int status;
actionproc act;
} ACTOR;
int PLAYER_act(MAZE*M,struct tagACTOR*m)
{
if(g_W.keys)
{
if(m->moving==0)
{
int i,dirs[4],ndirs=getavailableDIRS(M,m,dirs,NULL,0);
for(i=0; i<ndirs; i++)
if(dirs[i]==g_W.keys)
{
m->dir_x=l_dirX[g_W.keys];
m->dir_y=l_dirY[g_W.keys];
m->dir=g_W.keys;
return 1;
}
}
}
return 0;
}
int GHOST_act(MAZE*M,struct tagACTOR*m)
{
if(m->moving==0)
if(m->dir_x||m->dir_y)
{
int mask;
getavailableDIRS(M,m,NULL,&mask,1);
if(mask!=m->movementmask)
{
m->movementmask=mask;
if((rand()%10)>=5)
{
m->dir=chooseDIR(M,m);
m->dir_x=l_dirX[m->dir];
m->dir_y=l_dirY[m->dir];
}
}
}
else
{
m->dir=chooseDIR(M,m);
m->dir_x=l_dirX[m->dir];
m->dir_y=l_dirY[m->dir];
}
return 1;
}
int INGAME_postaction(WORLD*w)
{
{
int i;
for(i=1; i<g_nActors; i++)
{
ACTOR*g_actor=&g_actors[i];
if((fabs(g_actor->x-g_player->x)<0.5f)&&(fabs(g_actor->y-g_player->y)<0.5f))
if(g_actor->status&3)
{
g_actor->x=g_actor->nx=w->M.home_x;
g_actor->y=g_actor->ny=w->M.home_y;
g_actor->dir=dirUP;
g_actor->moving=0;
g_actor->movementmask=0;
g_actor->status=0;
w->score+=w->M.hunt_score;
w->M.hunt_score*=2;
}
else
{
if(w->lifes>1)
{
w->lifes--;
MATCH_init(w,0);
}
else
{
INGAME_set(w);
}
}
}
}
return 1;
}
...
else if(w->M.maze[y][x]=='o')
{
int j;
w->M.maze[y][x]=' ';
w->M.coins--;
w->score+=50;
w->M.hunt_timer=os_getMilliseconds()+5000;
w->M.hunt_score=200;
for(j=1; j<g_nActors; j++)
g_actor[j].status=1;
}
...
if(w->M.hunt_timer)
if(os_getMilliseconds()>w->M.hunt_timer)
{
int j;
w->M.hunt_timer=0;
for(j=1; j<g_nActors; j++)
g_actors[j].status=0;
}
else if(os_getMilliseconds()+2500>w->M.hunt_timer)
{
int j;
for(j=1; j<g_nActors; j++)
if(g_actors[j].status&1)
g_actors[j].status|=2;
}
typedef int (*gameloopproc)(WORLD*W);
typedef struct tagGAMELOOP{
gameloopproc handleUI;
gameloopproc action;
gameloopproc postaction;
gameloopproc draw;
}GAMELOOP;
void GAME_loop(WORLD*w)
{
if(g_G.handleUI)
g_G.handleUI(w);
if(g_G.action)
g_G.action(w);
if(g_G.postaction)
g_G.postaction(w);
if(g_G.draw)
g_G.draw(w);
}
typedef struct tagWORLD{
...
int event,event_timer;
...
}WORLD;
void EVENT_set(WORLD*w,int event)
{
w->event=event;
w->event_timer=os_getMilliseconds()+1000;
}
int g_wav_intro;
int g_wav_eat,g_wav_eatG;
int g_wav_chomp,g_wav_die;
int g_intoMUSIC,g_chomp;
int SNDRES_init()
{
snd_init();
g_wav_intro=wav_read("pacman_beginning.wav",0);
g_wav_eat=wav_read("pacman_eatfruit.wav",0);
g_wav_eatG=wav_read("pacman_eatghost",0);
g_wav_die=wav_read("pacman_death.wav",0);
g_wav_chomp=wav_read("pacman_chomp.wav",0);
return (g_wav_intro!=-1)&&(g_wav_eat!=-1)&&(g_wav_eatG!=-1)&&(g_wav_die!=-1)&&(g_wav_chomp!=-1);
}
int SNDRES_reset()
{
wav_deleteall();
snd_reset();
return 1;
}
void INGAME_set(WORLD*w)
{
if(g_intoMUSIC!=-1)
{
snd_stop(g_intoMUSIC);g_intoMUSIC=-1;
}
g_G.handleUI=INGAME_handleUI;
g_G.action=INGAME_action;
g_G.postaction=INGAME_postaction;
g_G.draw=INGAME_draw;
MATCH_init(w,1);
EVENT_set(w,event_GETREADY);
}
void HOME_set(WORLD*w)
{
g_intoMUSIC=snd_play(g_wav_intro,1,0);
g_G.handleUI=HOME_handleUI;
g_G.action=HOME_action;
g_G.postaction=NULL;
g_G.draw=HOME_draw;
MATCH_init(w,1);
}
int HOME_backaction(WORLD*w)
{
#if defined(OS_ANDROID)
jni_exit_app(0);
#endif
return 1;
}
if((g_G.backaction)&&(os_BACK_pressed))
{
g_G.backaction(w);
os_BACK_pressed = 0;
}
void GAME_pause(WORLD*w)
{
os_PAUSE=1;
}
void GAME_resume(WORLD*w)
{
os_PAUSE=0;
}
void GAME_loop(WORLD*w)
{
if(os_PAUSE)
;
else
{
if(g_G.handleUI)
g_G.handleUI(w);
if(g_G.action)
g_G.action(w);
if(g_G.postaction)
g_G.postaction(w);
if(g_G.draw)
g_G.draw(w);
}
}
int GAME_restore_textures(WORLD*w)
{
GFXRES_reset();
return GFXRES_init();
}