====== 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