add birds to runner game

This commit is contained in:
Crispy 2024-04-07 19:35:35 +02:00
parent 42eda85fd0
commit e2190c8dc8
3 changed files with 152 additions and 32 deletions

View file

@ -1,6 +1,18 @@
#define OBSTACLE_TYPES 5
const unsigned char soweli_a[8] = {
const u16 digit_font[] = {
0b111101101101111, // 0
0b010110010010111, // 1
0b111001111100111, // 2
0b111001111001111, // 3
0b101101111001001, // 4
0b111100111001111, // 5
0b111100111101111, // 6
0b111001001001001, // 7
0b111101111101111, // 8
0b111101111001111, // 9
};
const u8 soweli_a[8] = {
0b01111111,
0b10000000,
0b10101000,
@ -11,7 +23,7 @@ const unsigned char soweli_a[8] = {
0b01010000,
};
const unsigned char soweli_b[8] = {
const u8 soweli_b[8] = {
0b01111111,
0b10000000,
0b10101000,
@ -22,7 +34,14 @@ const unsigned char soweli_b[8] = {
0b00000101,
};
const unsigned char obstacle_sprites[OBSTACLE_TYPES][8] = {
#define GROUND_OBSTACLE_TYPES 5
#define OBSTACLE_TYPES (GROUND_OBSTACLE_TYPES + 1)
const u8 obstacle_heights[OBSTACLE_TYPES] = {6, 4, 4, 8, 5, 8};
const u8 obstacle_widths[OBSTACLE_TYPES] = {8, 8, 8, 7, 5, 7}; // (width + 8 )/2
const u8 obstacle_y_offset[OBSTACLE_TYPES] = {0, 0, 0, 0, 0, 18};
const u8 obstacle_sprites[OBSTACLE_TYPES][8] = {
{
0b00000000,
0b00000000,
@ -38,7 +57,6 @@ const unsigned char obstacle_sprites[OBSTACLE_TYPES][8] = {
0b00000000,
0b00000000,
0b00000000,
0b00111100,
0b01100110,
0b11000011,
@ -74,7 +92,14 @@ const unsigned char obstacle_sprites[OBSTACLE_TYPES][8] = {
0b00011000,
0b00111100,
},
{
0b00100000,
0b00010000,
0b00001000,
0b01010100,
0b00000010,
0b00011110,
0b00010000,
0b00010000,
},
};
const unsigned char obstacle_heights[OBSTACLE_TYPES] = {6, 4, 4, 8, 5};
const unsigned char obstacle_widths[OBSTACLE_TYPES] = {8, 8, 8, 7, 5};

View file

@ -109,14 +109,19 @@ void remove_obstacle()
obstacle_count--;
}
void spawn_obstacle(u8 pos)
void spawn_ground_obstacle(u8 pos)
{
if (obstacle_count >= MAX_OBSTACLES)
return;
obstacle_positions[obstacle_count] = pos;
obstacle_types[obstacle_count] = rand8() % OBSTACLE_TYPES;
obstacle_types[obstacle_count] = rand8() % GROUND_OBSTACLE_TYPES;
obstacle_count++;
}
void spawn_air_obstacle(u8 pos)
{
spawn_ground_obstacle(pos);
obstacle_types[obstacle_count - 1] = 5;
}
void update()
{
@ -136,7 +141,9 @@ void update()
obstacle_positions[i] -= SCROLL_SPEED;
u8 type = obstacle_types[i];
u8 dist_x = gfx_abs((s16)obstacle_positions[i] - (s16)PLAYER_X);
if (dist_x < obstacle_widths[type] && (player_y >> Y_PRECISION) < obstacle_heights[type])
u8 dist_y = gfx_abs((s16)obstacle_y_offset[type] - (s16)(player_y >> Y_PRECISION));
if (dist_x < obstacle_widths[type] && dist_y < obstacle_heights[type])
{
is_running = 0;
}
@ -145,34 +152,25 @@ void update()
{
remove_obstacle();
}
if (time_to_obstacle < 5)
if (time_to_obstacle == 0)
{
u8 count = 1 + (rand8() & rand8() & 1) + (rand8() & rand8() & rand8() & rand8() & 1);
for (u8 i = 0; i < count; i++)
if (rand8() & rand8() & 1)
spawn_air_obstacle(128);
else
{
spawn_obstacle(128 + i * 8);
spawn_ground_obstacle(128);
if (rand8() & rand8() & 1 && obstacle_types[obstacle_count - 1] != 5)
spawn_ground_obstacle(136);
}
time_to_obstacle = (rand8() & 31) + 50;
time_to_obstacle = (rand8() & 31) + 45;
}
time_to_obstacle -= 1;
}
void render_digit(u8 digit, u8 x, u8 y)
{
const u16 digit_font[] = {
0b111101101101111, // 0
0b010110010010111, // 1
0b111001111100111, // 2
0b111001111001111, // 3
0b101101111001001, // 4
0b111100111001111, // 5
0b111100111101111, // 6
0b111001001001001, // 7
0b111101111101111, // 8
0b111101111001111, // 9
};
u16 pixels = digit_font[digit];
ssd1306_drawPixel(x + 0, y + 0, (pixels >> 14) & 1);
ssd1306_drawPixel(x + 1, y + 0, (pixels >> 13) & 1);
ssd1306_drawPixel(x + 2, y + 0, (pixels >> 12) & 1);
@ -218,13 +216,13 @@ void render()
for (u8 i = 0; i < obstacle_count; i++)
{
u8 type = obstacle_types[i];
ssd1306_drawImage(obstacle_positions[i], 31 - 8, obstacle_sprites[type], 8, 8, 0);
ssd1306_drawImage(obstacle_positions[i], 31 - 8 - obstacle_y_offset[type], obstacle_sprites[type], 8, 8, 0);
}
if (time & RUN_ANIM_SPEED && is_running)
ssd1306_drawImage(PLAYER_X, 31 - (player_y >> Y_PRECISION) - 8, soweli_a, 8, 8, 0);
ssd1306_drawImage(PLAYER_X, 31 - 8 - (player_y >> Y_PRECISION), soweli_a, 8, 8, 0);
else
ssd1306_drawImage(PLAYER_X, 31 - (player_y >> Y_PRECISION) - 8, soweli_b, 8, 8, 0);
ssd1306_drawImage(PLAYER_X, 31 - 8 - (player_y >> Y_PRECISION), soweli_b, 8, 8, 0);
}
/* White Noise Generator State */

View file

@ -232,6 +232,103 @@ void ssd1306_drawPixel(uint8_t x, uint8_t y, uint8_t color)
ssd1306_buffer[addr] &= ~(1 << (y & 7));
}
/*
* plot a pixel in the buffer
*/
void ssd1306_xorPixel(uint8_t x, uint8_t y)
{
uint16_t addr;
/* clip */
if (x >= SSD1306_W)
return;
if (y >= SSD1306_H)
return;
/* compute buffer address */
addr = x + SSD1306_W * (y / 8);
ssd1306_buffer[addr] ^= (1 << (y & 7));
}
/*
* draw a an image from an array, directly into to the display buffer
* the color modes allow for overwriting and even layering (sprites!)
*/
void ssd1306_drawImage(uint8_t x, uint8_t y, const unsigned char *input, uint8_t width, uint8_t height, uint8_t color_mode)
{
uint8_t x_absolute;
uint8_t y_absolute;
uint8_t pixel;
uint8_t bytes_to_draw = width / 8;
uint16_t buffer_addr;
for (uint8_t line = 0; line < height; line++)
{
y_absolute = y + line;
if (y_absolute >= SSD1306_H)
{
break;
}
// SSD1306 is in vertical mode, yet we want to draw horizontally, which necessitates assembling the output bytes from the input data
// bitmask for current pixel in vertical (output) byte
uint8_t v_mask = 1 << (y_absolute & 7);
for (uint8_t byte = 0; byte < bytes_to_draw; byte++)
{
uint8_t input_byte = input[byte + line * bytes_to_draw];
for (pixel = 0; pixel < 8; pixel++)
{
x_absolute = x + 8 * (bytes_to_draw - byte) + pixel;
if (x_absolute >= SSD1306_W)
{
break;
}
// looking at the horizontal display, we're drawing bytes bottom to top, not left to right, hence y / 8
buffer_addr = x_absolute + SSD1306_W * (y_absolute / 8);
// state of current pixel
uint8_t input_pixel = input_byte & (1 << pixel);
switch (color_mode)
{
case 0:
// write pixels as they are
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (input_pixel ? v_mask : 0);
break;
case 1:
// write pixels after inversion
ssd1306_buffer[buffer_addr] = (ssd1306_buffer[buffer_addr] & ~v_mask) | (!input_pixel ? v_mask : 0);
break;
case 2:
// 0 clears pixel
ssd1306_buffer[buffer_addr] &= input_pixel ? 0xFF : ~v_mask;
break;
case 3:
// 1 sets pixel
ssd1306_buffer[buffer_addr] |= input_pixel ? v_mask : 0;
break;
case 4:
// 0 sets pixel
ssd1306_buffer[buffer_addr] |= !input_pixel ? v_mask : 0;
break;
case 5:
// 1 clears pixel
ssd1306_buffer[buffer_addr] &= input_pixel ? ~v_mask : 0xFF;
break;
}
}
#if SSD1306_LOG_IMAGE == 1
printf("%02x ", input_byte);
#endif
}
#if SSD1306_LOG_IMAGE == 1
printf("\n\r");
#endif
}
}
/*
* fast vert line
*/