Mirai's Miscellaneous Misadventures
M3 / game.c
#include "game.h"
struct mirai_sprite_type
{
struct mirai_image *image;
int radius;
int height;
};
struct mirai_sprite
{
struct mirai_sprite_type *type;
int x, y;
int dx, dy;
int ax;
char airborne;
char moving_direction;
int attack_y;
int attack_width;
int attack_height;
int attack_time;
void (*behave)(struct mirai_game *game, struct mirai_sprite *sprite);
};
static int mirai_gravity = 4;
static struct mirai_image mirai_mirai_image = {20, 34};
static struct mirai_image mirai_ground_image = {16, 16};
static struct mirai_sprite_type mirai_mirai = {&mirai_mirai_image, 80, 544};
static char mirai_ground[][20] =
{
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};
struct mirai_game
{
struct mirai_engine engine;
struct mirai_sprite sprites[256];
unsigned char sprite_count;
unsigned int left_history:16;
unsigned int right_history:16;
struct mirai_sprite *camera_sprite;
int camera_x;
int camera_y;
};
static void mirai_stamp(struct mirai_game *game, int x, int y, struct mirai_image *image)
{
x -= game->camera_x;
x += mirai_width * 4;
y -= game->camera_y;
y += mirai_height * 4;
(*game->engine.stamp)(game->engine.data, x / 8, y / 8, image);
}
static void mirai_physics(struct mirai_sprite *sprite)
{
sprite->dx += sprite->ax;
sprite->x += sprite->dx;
sprite->y += sprite->dy;
int x0 = sprite->x;
int x1 = sprite->type->radius;
int y0 = sprite->y;
int y1 = sprite->type->height;
if (mirai_ground[(x0 + x1) / 128][(y0 - 127) / 128] != 0)
{
if (mirai_ground[(x0 + x1) / 128][(y0 - y1 / 2) / 128] == 0)
{
sprite->y = (y0 / 128 - 1) * 128;
}
else
{
sprite->dx = 0;
sprite->x = (x0 + x1) / 128 * 128 - x1;
}
}
if (mirai_ground[(x0 - x1) / 128][(y0 - 127) / 128] != 0)
{
if (mirai_ground[(x0 - x1) / 128][(y0 - y1 / 2) / 128] == 0)
{
sprite->y = (y0 / 128 - 1) * 128;
}
else
{
sprite->dx = 0;
sprite->x = ((x0 - x1) / 128 + 1) * 128 + x1;
}
}
x0 = sprite->x;
y0 = sprite->y;
if (mirai_ground[(x0 - x1) / 128][y0 / 128] != 0 || mirai_ground[(x0 + x1 - 1) / 128][y0 / 128] != 0)
{
sprite->y = y0 / 128 * 128;
sprite->dy = 0;
sprite->airborne = 0;
}
else if (!sprite->airborne)
{
if (mirai_ground[x0 / 128][y0 / 128 + 1] == 0)
sprite->airborne = 1;
else
sprite->y = (y0 / 128 + 1) * 128;
}
}
static void mirai_ground_physics(struct mirai_sprite *sprite)
{
sprite->dx *= 7;
sprite->dx /= 8;
sprite->dy = 0;
mirai_physics(sprite);
}
static void mirai_airborne_physics(struct mirai_sprite *sprite)
{
sprite->dx *= 15;
sprite->dx /= 16;
sprite->dy += mirai_gravity;
mirai_physics(sprite);
}
static void mirai_jump(struct mirai_sprite *sprite)
{
if (sprite->airborne) return;
sprite->airborne = 1;
sprite->dy = -64;
}
static void mirai_damage(struct mirai_game *game, struct mirai_sprite *sprite)
{
struct mirai_image area = {sprite->attack_width / 16, sprite->attack_height / 8};
int x = sprite->x + sprite->attack_width / 4;
int y = (sprite->y + sprite->attack_y);
if (sprite->moving_direction == 1) x -= sprite->attack_width / 2;
mirai_stamp(game, x, y, &area);
}
static void mirai_attack(struct mirai_game *game, struct mirai_sprite *sprite)
{
sprite->attack_y = -16;
sprite->attack_width = 512;
sprite->attack_height = 256;
mirai_damage(game, sprite);
}
static void mirai_rapid_attack(struct mirai_game *game, struct mirai_sprite *sprite)
{
sprite->attack_y = -128;
sprite->attack_width = sprite->attack_time * 16 + 64;
sprite->attack_height = 64;
if (sprite->attack_time != 0x7F) sprite->attack_time++;
mirai_damage(game, sprite);
}
static unsigned char mirai_count_oscillations(unsigned int history)
{
unsigned char count = 0;
unsigned char prev = history&1;
for (int i = 0 ; i < 16 ; i++)
{
if ((history&1) != prev) count++;
prev = history&1;
history >>= 1;
}
return count;
}
static void mirai_controls(struct mirai_game *game, struct mirai_sprite *sprite)
{
unsigned char left_oscillations = mirai_count_oscillations(game->left_history);
unsigned char right_oscillations = mirai_count_oscillations(game->right_history);
switch (sprite->moving_direction)
{
case 0:
if ((game->left_history&1) != 0)
sprite->moving_direction = 1;
if ((game->right_history&1) != 0)
sprite->moving_direction = 2;
break;
case 1:
if ((game->left_history&1) == 0)
sprite->moving_direction = 0;
else if (left_oscillations > 1)
mirai_jump(sprite);
if ((game->right_history&1) != 0)
if (right_oscillations == 0)
mirai_rapid_attack(game, sprite);
else
sprite->attack_time = 0;
if ((game->right_history&1) != 0 && (game->right_history&2) == 0)
mirai_attack(game, sprite);
break;
case 2:
if ((game->right_history&1) == 0)
sprite->moving_direction = 0;
else if (right_oscillations > 1)
mirai_jump(sprite);
if ((game->left_history&1) != 0)
if (left_oscillations == 0)
mirai_rapid_attack(game, sprite);
else
sprite->attack_time = 0;
if ((game->left_history&1) != 0 && (game->left_history&2) == 0)
mirai_attack(game, sprite);
break;
}
}
static void mirai_spawn(struct mirai_game *game, int x, int y, struct mirai_sprite_type *type, void (*behave)(struct mirai_game *game, struct mirai_sprite *sprite))
{
if (game->sprite_count == 0xFF) return;
struct mirai_sprite *sprite = game->sprites + game->sprite_count;
game->sprite_count++;
sprite->type = type;
sprite->x = x;
sprite->y = y;
sprite->dx = 0;
sprite->dy = 0;
sprite->ax = 0;
sprite->airborne = 1;
sprite->moving_direction = 0;
sprite->attack_time = 0;
sprite->behave = behave;
}
int mirai_game_size = sizeof (struct mirai_game);
int mirai_width = 512;
int mirai_height = 256;
void mirai_start(struct mirai_game *game, struct mirai_engine *engine)
{
game->engine = *engine;
game->left_history = 0;
game->right_history = 0;
game->sprite_count = 0;
mirai_spawn(game, 500, 1500, &mirai_mirai, &mirai_controls);
game->camera_x = 500;
game->camera_y = 1500;
game->camera_sprite = game->sprites;
}
void mirai_step(struct mirai_game *game, struct mirai_keys keys)
{
game->left_history <<= 1;
game->left_history |= keys.left;
game->right_history <<= 1;
game->right_history |= keys.right;
game->camera_x *= 3;
game->camera_y *= 3;
game->camera_x += game->camera_sprite->x;
game->camera_y += game->camera_sprite->y - 512;
game->camera_x /= 4;
game->camera_y /= 4;
for (int i = 0 ; i < sizeof mirai_ground / sizeof *mirai_ground ; i++)
for (int j = 0 ; j < sizeof *mirai_ground / sizeof **mirai_ground ; j++)
{
if (mirai_ground[i][j])
mirai_stamp(game, i * 128 + 64, j * 128 + 128, &mirai_ground_image);
}
for (int i = 0 ; i < game->sprite_count ; i++)
{
struct mirai_sprite *sprite = game->sprites + i;
if (game->sprites->airborne == 0)
mirai_ground_physics(sprite);
else
mirai_airborne_physics(sprite);
(*sprite->behave)(game, sprite);
game->sprites[i].ax = 0;
if (sprite->airborne)
{
if (sprite->moving_direction == 1)
sprite->ax = -3;
if (sprite->moving_direction == 2)
sprite->ax = 3;
}
else
{
if (sprite->moving_direction == 1)
sprite->ax = -4;
if (sprite->moving_direction == 2)
sprite->ax = 4;
}
mirai_stamp(game, sprite->x, sprite->y, sprite->type->image);
}
}