====== Das Pong-Beispielspiel ====== Das soll ein Proove-of-Concept-Spiel sein. Der Code ist weder ein gutes Beispiel für guten Programmierstil, noch für ein sauberes GBA-Programm. Man sollte sich unbedingt etwas anderes überlegen, wie man verhindern kann, dass der Ball oder die Schläger eine Spur hinter sich herziehen. ===== ball.h ===== #ifndef GBA_PONG_BALL #define GBA_PONG_BALL #define BALL_X 115 #define BALL_Y 85 #define BALL_SPEED_X 0.2 #define BALL_SPEED_Y 0.1 #define BALL_DIMENSIONS_X 10 #define BALL_DIMENSIONS_Y 10 #include "score.h" #include "paddle.h" struct paddle; struct ball { struct { float x, y; } speed; struct { char width, height; } dimensions; float x, y; }; void update ( struct ball* bl, struct score* score ); void ball_reset ( struct ball* bl ); void collision ( struct ball* bl, struct paddle* player, struct paddle* cpu); float _abs ( float val ); #endif ===== ball.c ===== #include #include "ball.h" #include "screen.h" #include "score.h" float _abs ( float val ) { if (val<0) return (val*-1); return val; } void update ( struct ball* bl, struct score* score ) { bl->x+=bl->speed.x; bl->y+=bl->speed.y; bl->speed.x*=_abs((3/bl->speed.x) - 1/bl->speed.x); bl->speed.y*=_abs((3/bl->speed.y) - 1/bl->speed.y); if (bl->y<0 || bl->y+bl->dimensions.height > HEIGHT) { bl->speed.y*=-1; } // one of them scored if (bl->x+bl->dimensions.width > WIDTH) { ball_reset(bl); bl->speed.x*=-1; int dice = rand() % 2; if (dice==1) bl->speed.y*=-1; clrScr(); score->player++; } if (bl->x<0) { ball_reset(bl); int dice = rand()*10 % 2; if (dice==1) bl->speed.y*=-1; clrScr(); score->cpu++; } } void collision (struct ball* bl, struct paddle* player, struct paddle* cpu) { if (bl->y+bl->dimensions.height>=player->y && bl->xx+player->dimensions.width && bl->y<=player->y+player->dimensions.height) { bl->speed.x*=-1; } if (bl->y+bl->dimensions.height>=cpu->y && bl->x+bl->dimensions.width>=cpu->x+cpu->dimensions.width && bl->y<=cpu->y+cpu->dimensions.height) { bl->speed.x*=-1; } } void ball_reset ( struct ball* bl ) { bl->speed.y=BALL_SPEED_Y; bl->speed.x=BALL_SPEED_X; bl->x=BALL_X; bl->y=BALL_Y; } ===== score.h ===== #ifndef GBA_PONG_SCORE #define GBA_PONG_SCORE struct score { char player; char cpu; }; #endif ===== paddle.h ===== #ifndef GBA_PONG_PADDLE #define GBA_PONG_PADDLE #define PADDLE_SPEED 2 #define REG_INPUT 0x04000130 #define KEY_A 1 #define KEY_B 2 #define KEY_SELECT 4 #define KEY_START 8 #define KEY_RIGHT 16 #define KEY_LEFT 32 #define KEY_UP 64 #define KEY_DOWN 128 #define KEY_R 256 #define KEY_L 512 #include "ball.h" struct ball; struct paddle { struct { char width, height; } dimensions; char x, y; }; void intelligence( struct ball* bl, struct paddle* cpu ); void input ( struct paddle* player ); #endif ===== paddle.c ===== #include "paddle.h" #include "screen.h" #include "ball.h" void intelligence( struct ball* bl, struct paddle* cpu ) { if (bl->y>cpu->y+cpu->dimensions.height-10 && (HEIGHT-(cpu->y+cpu->dimensions.height))>=PADDLE_SPEED) { cpu->y+=PADDLE_SPEED; } if (bl->yy+10 && cpu->y>=PADDLE_SPEED) { cpu->y-=PADDLE_SPEED; } } void input (struct paddle* player) { int* KEYS = (int*)REG_INPUT; if (!(*KEYS & KEY_UP) && player->y>=PADDLE_SPEED) { player->y-=PADDLE_SPEED; } if (!(*KEYS & KEY_DOWN) && (HEIGHT-(player->y+player->dimensions.height))>=PADDLE_SPEED) { player->y+=PADDLE_SPEED; } } ===== screen.h ===== #ifndef GBA_SCREEN #define GBA_SCREEN #define _REG_FRAMEBUFFER 0x6000000 #define RGB16(r,g,b) ((r)+(g<<5)+(b<<10)) #define _BACKGROUND RGB16(0,0,0) #define HEIGHT 160 #define WIDTH 240 //unsigned short* REG_FRAME = (unsigned short*) _REG_FRAMEBUFFER; void clrScr(); void drawDot(char x, char y, unsigned short color); void paddle (int height, int width, int beginx, int beginy, unsigned short color); void drawNumber(char x, char y, char num, unsigned short color); void draw0(char x, char y, unsigned short color); void draw1(char x, char y, unsigned short color); void draw2(char x, char y, unsigned short color); void draw3(char x, char y, unsigned short color); void draw4(char x, char y, unsigned short color); void draw5(char x, char y, unsigned short color); void draw6(char x, char y, unsigned short color); void draw7(char x, char y, unsigned short color); void draw8(char x, char y, unsigned short color); void draw9(char x, char y, unsigned short color); #endif ===== screen.c ===== #include "screen.h" unsigned short* REG_FRAME = (unsigned short*) _REG_FRAMEBUFFER; void clrScr() { for (char x=0; x<240;x++) { for(char y=0; y<160; y++) { REG_FRAME[x+y*240]=_BACKGROUND; } } } void drawDot(char x, char y, unsigned short color) { REG_FRAME[x+y*240]=color; } void paddle (int height, int width, int beginx, int beginy, unsigned short color) { for (char x=beginx-5; xbeginy && ybeginx && x6) ex=1; REG_FRAME[x+ex+((y+ey)*240)]=color; REG_FRAME[x+ex-1+((y+ey)*240)]=color; } } void draw3(char x, char y, unsigned short color) { for (char ey=0; ey<14; ey++) { REG_FRAME[x+10+((y+ey)*240)]=color; REG_FRAME[x+9+((y+ey)*240)]=color; } for (char ex=0; ex<10; ex++) { REG_FRAME[x+ex+(y*240)]=color; REG_FRAME[x+ex+((y+1)*240)]=color; REG_FRAME[x+ex+((y+13)*240)]=color; REG_FRAME[x+ex+((y+14)*240)]=color; if (ex>=2) { REG_FRAME[x+ex+((y+6)*240)]=color; REG_FRAME[x+ex+((y+7)*240)]=color; } } } void draw4(char x, char y, unsigned short color) { for (char ex=0; ex<10; ex++) { REG_FRAME[x+ex+((y+6)*240)]=color; REG_FRAME[x+ex+((y+7)*240)]=color; } for (char ey=0; ey<14; ey++) { char ex=1; if (ey>6) ex=5; REG_FRAME[x+ex+((y+ey)*240)]=color; REG_FRAME[x+ex-1+((y+ey)*240)]=color; } REG_FRAME[x+4+((y+5)*240)]=color; REG_FRAME[x+4+((y+4)*240)]=color; REG_FRAME[x+5+((y+5)*240)]=color; REG_FRAME[x+5+((y+4)*240)]=color; } void draw5(char x, char y, unsigned short color) { for (char ex=0; ex<10; ex++) { REG_FRAME[x+ex+(y*240)]=color; REG_FRAME[x+ex+((y+1)*240)]=color; REG_FRAME[x+ex+((y+7)*240)]=color; REG_FRAME[x+ex+((y+6)*240)]=color; REG_FRAME[x+ex+((y+14)*240)]=color; REG_FRAME[x+ex+((y+13)*240)]=color; } for (char ey=0; ey<14; ey++) { char ex=1; if (ey>6) ex=10; REG_FRAME[x+ex+((y+ey)*240)]=color; REG_FRAME[x+ex-1+((y+ey)*240)]=color; } } void draw6(char x, char y, unsigned short color) { for (char ex=0; ex<10; ex++) { REG_FRAME[x+ex+(y*240)]=color; REG_FRAME[x+ex+((y+1)*240)]=color; REG_FRAME[x+ex+((y+7)*240)]=color; REG_FRAME[x+ex+((y+6)*240)]=color; REG_FRAME[x+ex+((y+13)*240)]=color; REG_FRAME[x+ex+((y+14)*240)]=color; } for (char ey=0; ey<14; ey++) { REG_FRAME[x+((y+ey)*240)]=color; REG_FRAME[x+1+((y+ey)*240)]=color; if (ey>6) { REG_FRAME[x+10+((y+ey)*240)]=color; REG_FRAME[x+9+((y+ey)*240)]=color; } } } void draw7(char x, char y, unsigned short color) { for (char ex=0; ex<10; ex++) { REG_FRAME[x+ex+(y*240)]=color; REG_FRAME[x+ex+((y+1)*240)]=color; } char i=0; for (char ey=0; ey<14; ey++) { REG_FRAME[x+10-i+((y+ey)*240)]=color; REG_FRAME[x+9-i+((y+ey)*240)]=color; if (ey==5 || ey==10) i++; } } void draw8(char x, char y, unsigned short color) { for (char ey=0; ey<14; ey++) { REG_FRAME[x+10+((y+ey)*240)]=color; REG_FRAME[x+9+((y+ey)*240)]=color; REG_FRAME[x+((y+ey)*240)]=color; REG_FRAME[x+1+((y+ey)*240)]=color; } for (char ex=0; ex<10; ex++) { REG_FRAME[x+ex+(y*240)]=color; REG_FRAME[x+ex+((y+1)*240)]=color; REG_FRAME[x+ex+((y+13)*240)]=color; REG_FRAME[x+ex+((y+14)*240)]=color; REG_FRAME[x+ex+((y+7)*240)]=color; REG_FRAME[x+ex+((y+6)*240)]=color; } } void draw9(char x, char y, unsigned short color) { for (char ex=0; ex<10; ex++) { REG_FRAME[x+ex+(y*240)]=color; REG_FRAME[x+ex+((y+1)*240)]=color; REG_FRAME[x+ex+((y+7)*240)]=color; REG_FRAME[x+ex+((y+6)*240)]=color; REG_FRAME[x+ex+((y+13)*240)]=color; REG_FRAME[x+ex+((y+14)*240)]=color; } for (char ey=0; ey<14; ey++) { if (ey<6) { REG_FRAME[x+((y+ey)*240)]=color; REG_FRAME[x+1+((y+ey)*240)]=color; } REG_FRAME[x+10+((y+ey)*240)]=color; REG_FRAME[x+9+((y+ey)*240)]=color; } } ===== Main.c ===== #define RGB16(r,g,b) ((r)+(g<<5)+(b<<10)) #include "screen.h" #include "ball.h" #include "score.h" #include "paddle.h" #include int main() { *(unsigned long*)0x4000000 = 0x403; srand( 0 ); struct ball bl; bl.x=BALL_X; bl.y=BALL_Y; bl.speed.x=BALL_SPEED_X; bl.speed.y=BALL_SPEED_Y; bl.dimensions.width=BALL_DIMENSIONS_X; bl.dimensions.height=BALL_DIMENSIONS_Y; struct score score; score.player=0; score.cpu=0; struct paddle cpu_paddle; cpu_paddle.x=225; cpu_paddle.y=20; cpu_paddle.dimensions.height=30; cpu_paddle.dimensions.width=5; struct paddle player_paddle; player_paddle.x=10; player_paddle.y=20; player_paddle.dimensions.height=30; player_paddle.dimensions.width=5; while(1) { paddle (player_paddle.dimensions.height, player_paddle.dimensions.width, player_paddle.x, player_paddle.y, RGB16(31, 0,0)); paddle (cpu_paddle.dimensions.height, cpu_paddle.dimensions.width, cpu_paddle.x, cpu_paddle.y, RGB16(31, 0,0)); update(&bl, &score); collision(&bl, &player_paddle, &cpu_paddle); intelligence(&bl, &cpu_paddle); input (&player_paddle); drawNumber(40, 5, score.player, RGB16(31,31,31)); drawNumber(190, 5, score.cpu, RGB16(31,31,31)); // Ball paddle (bl.dimensions.width, bl.dimensions.height, (char) bl.x, (char) bl.y, RGB16( 0,31,0)); } } ===== Make.sh ===== Ein Bash-Skript zum Bauen des Spiels. Der Compiler liegt in /devkitadv/bin ; der Programmcode liegt in adv/ . Ich benutze hier nicht den Linux-Port des Compilers, sondern den Windows-Port und führe den unter Linux mit Wine aus. Das geht besser als einen uralten GCC auf dem System zu haben. cd ../devkitadv/bin wine gcc.exe -o ../../adv/hello.elf ../../adv/main.c ../../adv/screen.c \ ../../adv/ball.c ../../adv/paddle.c -std=c99 -Wall -pedantic wine objcopy.exe -O binary ../../adv/hello.elf ../../adv/hello.gba