Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
594 lines (486 sloc) 12.7 KB
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <math.h>
#include <sys/param.h>
#if defined(SIMULATOR)
#include <X11/keysym.h>
#endif
#include "led.h"
#include "fifo.h"
typedef struct
{
int bright;
int r;
int g;
int b;
} pixel_t;
#define ORIENT_NORTH 0
#define ORIENT_EAST 1
#define ORIENT_SOUTH 2
#define ORIENT_WEST 3
#define X_ORIENT(o) ((o) == ORIENT_EAST ? 1 : (o) == ORIENT_WEST ? -1 : 0)
#define Y_ORIENT(o) ((o) == ORIENT_SOUTH ? 1 : (o) == ORIENT_NORTH ? -1 : 0)
typedef struct
{
double x;
double y;
int orientation;
double dx;
double dy;
int id;
int hits;
} dude_t;
typedef struct
{
double x;
double y;
double dx;
double dy;
int id;
} bullet_t;
typedef struct
{
int x;
int y;
int type;
int tick;
} explosion_t;
#define BLUE_DUDE 0
#define RED_DUDE 1
#define MAX_HITS 3
dude_t g_dudes[2];
int g_quit = 0;
#define MAX_BULLETS 10
#define BULLET_SPEED 0.2
#define MAX_SPEED 1.5
#define FRICTION .005
#define ACCELERATION .2
bullet_t g_bullets[MAX_BULLETS];
int g_bullet_count = 0;
#define MAX_EXPLOSIONS 10
#define EXPLOSION_RADIUS 1
#define EXPLOSION_LIFE_CYCLE 10
explosion_t g_explosions[MAX_EXPLOSIONS];
int g_explosion_count = 0;
int g_wide = 0;
int g_high = 0;
void reset_field(LED_HANDLE_T h)
{
int x, y;
g_bullet_count = g_explosion_count = 0;
memset(&g_dudes[BLUE_DUDE], 0, sizeof(g_dudes[BLUE_DUDE]));
memset(&g_dudes[RED_DUDE], 0, sizeof(g_dudes[RED_DUDE]));
memset(&g_bullets, 0, sizeof(g_bullets));
g_dudes[BLUE_DUDE].id = BLUE_DUDE;
g_dudes[BLUE_DUDE].orientation = ORIENT_EAST;
g_dudes[RED_DUDE].id = RED_DUDE;
g_dudes[RED_DUDE].orientation = ORIENT_WEST;
g_dudes[RED_DUDE].y = g_high - 1;
g_dudes[RED_DUDE].x = g_wide - 1;
for (y = 0; y < g_high; y++)
for (x = 0; x < g_wide; x++)
led_set_pixel(h, x, y, 0, 0, 0, 0);
}
double wrap_x(double x, double dx)
{
x += dx;
while (((int) x) >= g_wide)
x -= g_wide;
while ( x < 0.0)
x += g_wide;
return x;
}
double wrap_y(double y, double dy)
{
y += dy;
while (((int) y) >= g_high)
y -= g_high;
while (y < 0.0)
y += g_high;
return y;
}
pixel_t *get_dude_color(dude_t *dude)
{
static pixel_t colors[2][MAX_HITS] =
{
{
{ 0xc0, 0, 0, 0xf },
{ 0xc0, 5, 0, 0xf },
{ 0xc0, 15, 2, 0 }
},
{
{ 0xc0, 0xf, 0, 0 },
{ 0xc0, 15, 2, 0 },
{ 0xc0, 5, 0, 0xf }
}
};
return (&colors[dude->id][dude->hits]);
}
pixel_t *get_bullet_color(bullet_t *bullet)
{
static pixel_t colors[2] =
{
{ 0xc0, 0, 0, 0xf },
{ 0xc0, 0xf, 0, 0 }
};
return (&colors[bullet->id]);
}
void erase_dude(LED_HANDLE_T h, dude_t *dude)
{
led_set_pixel(h, (int) dude->x, (int) dude->y, 0, 0, 0, 0);
led_set_pixel(h, (int) wrap_x(((int) dude->x), X_ORIENT(dude->orientation)),
(int) wrap_y(((int) dude->y), Y_ORIENT(dude->orientation)),
0, 0, 0, 0);
}
void draw_dude(LED_HANDLE_T h, dude_t *dude)
{
pixel_t *pixel = get_dude_color(dude);
led_set_pixel(h, (int) dude->x, (int) dude->y,
pixel->bright, pixel->r,
pixel->g, pixel->b);
led_set_pixel(h, (int) wrap_x(((int) dude->x), X_ORIENT(dude->orientation)),
(int) wrap_y(((int) dude->y), Y_ORIENT(dude->orientation)),
0x30, pixel->r, pixel->g, pixel->b);
}
void draw_dudes(LED_HANDLE_T h)
{
int i;
for (i = 0; i < sizeof(g_dudes) / sizeof(g_dudes[0]); i++)
draw_dude(h, &g_dudes[i]);
}
void move_dude(LED_HANDLE_T h, dude_t *dude)
{
double newx, newy;
newx = wrap_x(dude->x, dude->dx);
newy = wrap_y(dude->y, dude->dy);
if ((int) newx != (int) dude->x ||
(int) newy != (int) dude->y)
{
erase_dude(h, dude);
dude->x = newx;
dude->y = newy;
draw_dude(h, dude);
}
else
{
dude->x = newx;
dude->y = newy;
}
}
void accelerate_dude(LED_HANDLE_T h, dude_t *dude)
{
if (dude->orientation == ORIENT_NORTH)
dude->dy -= ACCELERATION;
if (dude->orientation == ORIENT_SOUTH)
dude->dy += ACCELERATION;
if (dude->orientation == ORIENT_EAST)
dude->dx += ACCELERATION;
if (dude->orientation == ORIENT_WEST)
dude->dx -= ACCELERATION;
if (dude->dx > MAX_SPEED)
dude->dx = MAX_SPEED;
if (dude->dy > MAX_SPEED)
dude->dy = MAX_SPEED;
if (dude->dx < (-1 * MAX_SPEED))
dude->dx = (-1 * MAX_SPEED);
if (dude->dy < (-1 * MAX_SPEED))
dude->dy = (-1 * MAX_SPEED);
}
void friction_dude(dude_t *dude)
{
if (dude->dx < 0)
dude->dx += FRICTION;
if (dude->dy < 0)
dude->dy += FRICTION;
if (dude->dx > 0)
dude->dx -= FRICTION;
if (dude->dy > 0)
dude->dy -= FRICTION;
}
void erase_bullet(LED_HANDLE_T h, bullet_t *bullet)
{
led_set_pixel(h, (int) bullet->x, (int) bullet->y, 0, 0, 0, 0);
}
void draw_bullet(LED_HANDLE_T h, bullet_t *bullet)
{
pixel_t *pixel = get_bullet_color(bullet);
led_set_pixel(h, (int) bullet->x, (int) bullet->y,
pixel->bright, pixel->r,
pixel->g, pixel->b);
}
int move_bullet(LED_HANDLE_T h, bullet_t *bullet)
{
double newx, newy;
newx = bullet->x + bullet->dx;
newy = bullet->y + bullet->dy;
if (newx >= g_wide || newx < 0.0 ||
newy >= g_high || newy < 0.0)
{
erase_bullet(h, bullet);
return 1;
}
if ((int) newx != (int) bullet->x ||
(int) newy != (int) bullet->y)
{
erase_bullet(h, bullet);
bullet->x = newx;
bullet->y = newy;
draw_bullet(h, bullet);
draw_dudes(h);
}
else
{
bullet->x = newx;
bullet->y = newy;
}
return 0;
}
void position_bullet(dude_t *dude, bullet_t *bullet)
{
bullet->dx = dude->dx + BULLET_SPEED * X_ORIENT(dude->orientation);
bullet->dy = dude->dy + BULLET_SPEED * Y_ORIENT(dude->orientation);
bullet->x = round(wrap_x(dude->x, X_ORIENT(dude->orientation)));
bullet->y = round(wrap_y(dude->y, Y_ORIENT(dude->orientation)));
}
int limit_bullet(dude_t *dude)
{
int me;
int i;
for (i = 0, me = 0; i < g_bullet_count; i++)
if (g_bullets[i].id == dude->id)
{
me++;
if (me >= (MAX_BULLETS / 2))
return 1;
}
return 0;
}
void fire_bullet(LED_HANDLE_T h, dude_t *dude)
{
if (g_bullet_count == MAX_BULLETS)
return;
if (limit_bullet(dude))
return;
bullet_t *bullet = &g_bullets[g_bullet_count++];
bullet->id = dude->id;
position_bullet(dude, bullet);
}
void change_orientation(dude_t *dude, int o)
{
dude->orientation += o;
if (dude->orientation < 0)
dude->orientation = ORIENT_WEST;
if (dude->orientation > ORIENT_WEST)
dude->orientation = ORIENT_NORTH;
}
void left(LED_HANDLE_T h, dude_t *dude)
{
erase_dude(h, dude);
change_orientation(dude, -1);
}
void right(LED_HANDLE_T h, dude_t *dude)
{
erase_dude(h, dude);
change_orientation(dude, 1);
}
#if defined(SIMULATOR)
void my_callback(LED_HANDLE_T h, unsigned long key)
{
if (key == 'q')
g_quit++;
if (key == 'd')
right(h, &g_dudes[BLUE_DUDE]);
if (key == 'a')
left(h, &g_dudes[BLUE_DUDE]);
if (key == 'w')
accelerate_dude(h, &g_dudes[BLUE_DUDE]);
if (key == ' ' || key == 's')
fire_bullet(h, &g_dudes[BLUE_DUDE]);
if (key == XK_Right)
right(h, &g_dudes[RED_DUDE]);
if (key == XK_Left)
left(h, &g_dudes[RED_DUDE]);
if (key == XK_Up)
accelerate_dude(h, &g_dudes[RED_DUDE]);
if (key == XK_Down)
fire_bullet(h, &g_dudes[RED_DUDE]);
draw_dudes(h);
}
#endif
pixel_t * compute_explosion(explosion_t *exp, int x, int y)
{
static pixel_t color;
if (x == 0 && y == 0)
color.bright = 0xc0;
else
color.bright = 0x80;
color.r = (rand() % 4) + 12;
color.g = rand() % 4;
color.b = 0;
color.bright -= exp->tick * 8;
if (color.bright < 0)
color.bright = 0;
return &color;
}
int draw_explosion(LED_HANDLE_T h, explosion_t *exp)
{
int i, j;
for (i = -1 * EXPLOSION_RADIUS; i <= EXPLOSION_RADIUS; i++)
for (j = -1 * EXPLOSION_RADIUS; j <= EXPLOSION_RADIUS; j++)
{
pixel_t *pixel = compute_explosion(exp, i, j);
if (exp->tick == (EXPLOSION_LIFE_CYCLE - 1))
pixel->bright = pixel->r = pixel->g = pixel->b = 0;
if (exp->x + i >= 0 && exp->x + i < g_wide &&
exp->y + j >= 0 && exp->y + j < g_high)
led_set_pixel(h, exp->x + i, exp->y + j,
pixel->bright, pixel->r, pixel->g, pixel->b);
}
exp->tick++;
if (exp->tick >= EXPLOSION_LIFE_CYCLE)
return 1;
return 0;
}
void delete_bullet(int bullno)
{
if (g_bullet_count == 0)
return;
if (bullno < (g_bullet_count - 1))
memcpy(g_bullets + bullno, g_bullets + bullno + 1,
(g_bullet_count - bullno) * sizeof(g_bullets[0]));
g_bullet_count--;
}
int bullets_collide(bullet_t *a, bullet_t *b)
{
if (a->id != b->id && (int) a->x == (int) b->x &&
(int) a->y == (int) b->y)
return 1;
return 0;
}
int hit_dude(bullet_t *b, dude_t *d)
{
if (b->id != d->id &&
(int) b->x == (int) d->x &&
(int) b->y == (int) d->y)
{
d->hits++;
return 1;
}
return 0;
}
void show_loser(LED_HANDLE_T h, int dude)
{
int x, y;
for (y = 0; y < g_high; y++)
for (x = 0; x < g_wide; x++)
{
led_set_pixel(h, x, y, MAX_BRIGHT, dude == BLUE_DUDE ? 15 : 0, 0, dude == BLUE_DUDE ? 0 : 15);
usleep(20000);
}
reset_field(h);
}
void move_stuff(LED_HANDLE_T h)
{
int i, j;
for (i = 0; i < g_explosion_count; i++)
{
if (draw_explosion(h, &g_explosions[i]))
{
if (i < (g_explosion_count - 1))
g_explosions[i] = g_explosions[g_explosion_count - 1];
g_explosion_count--;
}
}
move_dude(h, &g_dudes[BLUE_DUDE]);
move_dude(h, &g_dudes[RED_DUDE]);
for (i = 0; i < g_bullet_count; i++)
{
if (move_bullet(h, &g_bullets[i]))
{
delete_bullet(i);
}
}
for (i = 0; i < g_bullet_count; i++)
{
for (j = 0; j < g_bullet_count; j++)
if (i == j)
break;
else
{
if (bullets_collide(&g_bullets[i], &g_bullets[j]))
{
if (g_explosion_count < MAX_EXPLOSIONS)
{
g_explosions[g_explosion_count].x = (int) g_bullets[i].x;
g_explosions[g_explosion_count].y = (int) g_bullets[i].y;
g_explosions[g_explosion_count].tick = 0;
g_explosion_count++;
}
delete_bullet(MAX(i, j));
delete_bullet(MIN(i, j));
}
}
}
for (i = 0; i < g_bullet_count; i++)
{
for (j = 0; j < sizeof(g_dudes) / sizeof(g_dudes[0]); j++)
if (hit_dude(&g_bullets[i], &g_dudes[j]))
{
delete_bullet(i);
if (g_dudes[j].hits >= MAX_HITS)
{
show_loser(h, j);
break;
}
}
}
friction_dude(&g_dudes[BLUE_DUDE]);
friction_dude(&g_dudes[RED_DUDE]);
}
void fifo_callback(void *parm, void *p)
{
LED_HANDLE_T h = (LED_HANDLE_T) parm;
int dude;
char buf[MAX_COMMAND_LEN];
sscanf(p, "%d-%s\n", &dude, buf);
if (strcasecmp(buf, "left") == 0)
left(h, &g_dudes[dude]);
if (strcasecmp(buf, "right") == 0)
right(h, &g_dudes[dude]);
if (strcasecmp(buf, "up") == 0)
accelerate_dude(h, &g_dudes[dude]);
if (strcasecmp(buf, "fire") == 0)
fire_bullet(h, &g_dudes[dude]);
draw_dudes(h);
}
int main (int argc, char *argv[])
{
LED_HANDLE_T p;
fifo_t f;
p = led_init();
#if defined(SIMULATOR)
ledsim_set_x_callback(p, my_callback);
#endif
led_get_size(p, &g_wide, &g_high);
umask(0);
if (fifo_init(FIFO_PATH, &fifo_callback, &f, p) != 0)
{
fprintf(stderr, "Error opening command fifo\n");
exit(1);
}
reset_field(p);
draw_dudes(p);
while (! g_quit)
{
usleep(100000);
move_stuff(p);
draw_dudes(p);
}
led_term(p);
fifo_term(&f);
return 0;
}