blob: 040c5aa71a325e9483d9926caf5ceca6e16e3733 [file] [log] [blame] [edit]
#include "shmup.hpp"
#include "assets.hpp"
using namespace blit;
#define SCENERY_BIG_SKULL Rect(11, 3, 4, 3)
#define SCENERY_TUSK Rect(10, 3, 1, 3)
#define SCENERY_BIG_TUSK Rect(10, 6, 2, 3)
#define SCENERY_BIG_BONE Rect(12, 6, 3, 2)
#define SCENERY_CLAWS Rect(6, 5, 3, 2)
#define SCENERY_BIG_ROCK Rect(3, 5, 3, 3)
#define SHOT_BIG_RED Rect(6, 0, 2, 1)
#define SHOT_LONG_RED Rect(6, 0, 4, 1)
#define SHOT_BIG_PINK Rect(10, 0, 2, 1)
// These lookup tables include an offset in pixels
// as the first two uint8_t values.
// We offset in pixels rather than tiles to avoid having to
// multiply the values up when the sprite is drawn.
// The following values are bitmasks describing a sprite with
// a maximum of 8 tiles width, and unlimited height.
// Each bit, from left to right, indicates a tile starting from
// the offset that should be included in this sprite.
// This is much more space efficient than storing a point(x, y)
// for each tile we want in a sprite.
// Weird ship with a hole in it
const std::vector<uint8_t> BG_SHIP_1 = { \
12 * 8, 5 * 8, \
4, \
0b00100000, \
0b01110000, \
0b11110000 };
// Background ship with all the shuttle bays and little winglets on the bottom
const std::vector<uint8_t> BG_SHIP_2{ \
9 * 8, 4 * 8, \
5, \
0b11111000, \
0b11111000, \
0b01110000 };
// Hog ship!
const std::vector<uint8_t> HOG_SHIP{ \
10 * 8, 0, \
6, \
0b11111100, \
0b11111100, \
0b11111100, \
0b11111100 };
/*
Map
[] --> [] --> [] --> []
\
[] --> [] --> []
Player
x, y
vx, vy
life
Enemy
x, y
hit
life
Projectile
x, y
vx, vy
Background Scenery
x, y
*/
bool hit = false;
Pen hit_palette[2][5] = {
{},
{}
};
Size boar_ship_size(32, 32);
Surface* ships;
Surface* background;
Tween tween_bob;
Tween tween_dusk_dawn;
Tween tween_parallax;
void draw_tilebased_sprite(Surface* ss, Point origin, const std::vector<uint8_t> ship, bool hflip = false) {
// We can use uint8_t everywhere here, but this limits us
// to a spritesheet of 256*256. That's fine!
uint8_t o_x = ship[0];
uint8_t o_y = ship[1];
// We need to know the width of the ship within our bitmask
// so we can horizontally flip if needed without it going wonky
uint8_t w = ship[2];
for (auto i = 0; i < (uint8_t)ship.size() - 3; i++) {
uint8_t ship_mask = ship[i + 3]; // Bitmask for tiles in a horizontal row
uint8_t offset_y = (i * 8);
uint8_t src_y = o_y + offset_y;
for (auto j = 0; j < w; j++) {
uint8_t jj = j;
if (hflip) {
jj = w - 1 - jj;
}
if (ship_mask & (0b10000000 >> jj)) {
uint8_t offset_x = (jj * 8);
uint8_t src_x = o_x + offset_x;
screen.blit(ss, Rect(src_x, src_y, 8, 8), Point(origin.x + (j * 8), origin.y + offset_y), hflip);
}
}
}
}
void init() {
set_screen_mode(ScreenMode::hires);
ships = Surface::load(sprites_ships);
background = Surface::load(sprites_background);
tween_bob.init(tween_sine, 0.0f, 1.0f, 2500, -1);
tween_bob.start();
tween_dusk_dawn.init(tween_sine, 0.0f, 1.0f, 500, 1);
tween_dusk_dawn.start();
tween_parallax.init(tween_linear, 0.0f, 1.0f, 10000, -1);
tween_parallax.start();
screen.sprites = background;
for (int x = 0; x < 5; x++) {
Pen s_c = screen.sprites->palette[4 + x];
Pen c = Pen(
std::min(255, int(s_c.r * 1.8)),
std::min(255, int(s_c.g * 1.8)),
std::min(255, int(s_c.b * 1.8))
);
hit_palette[0][x] = s_c;
hit_palette[1][x] = c;
}
for (int x = 0; x < 32; x++) {
background->palette[x] = desert[x];
}
}
void render(uint32_t time) {
uint32_t ms_start = blit::now() - time;
screen.pen = background->palette[21];
screen.clear();
screen.sprites = background;
for (int x = 0; x < 40; x++) {
screen.sprite(Rect(15, 3, 1, 5), Point(x * 8, 0), 0);
screen.sprite(Rect(0, 1, 1, 8), Point(x * 8, screen.bounds.h - 64), 0);
}
Pen t = background->palette[29];
background->palette[29] = background->palette[20];
// Far mountains
screen.sprite(Rect(1, 2, 15, 1), Point((tween_parallax.value * 60), screen.bounds.h - 80), Point(0, 0), 2.0f, 0);
screen.sprite(Rect(5, 1, 2, 1), Point((tween_parallax.value * 60) + (8 * 4 * 2.0f), screen.bounds.h - 96), Point(0, 0), 2.0f, 0);
screen.sprite(Rect(12, 1, 3, 1), Point((tween_parallax.value * 60) + (8 * 11 * 2.0f), screen.bounds.h - 96), Point(0, 0), 2.0f, 0);
// Try and palette swap in a transparent colour and draw in some reflections?
background->palette[29] = Pen(background->palette[19].r, background->palette[19].g, background->palette[19].b, 100);
screen.sprite(Rect(1, 2, 15, 1), Point((tween_parallax.value * 60), screen.bounds.h - 64), Point(0, 0), 2.0f, 2);
screen.sprite(Rect(5, 1, 2, 1), Point((tween_parallax.value * 60) + (8 * 4 * 2.0f), screen.bounds.h - 48), Point(0, 0), 2.0f, 2);
screen.sprite(Rect(12, 1, 3, 1), Point((tween_parallax.value * 60) + (8 * 11 * 2.0f), screen.bounds.h - 48), Point(0, 0), 2.0f, 2);
background->palette[29] = t;
screen.sprite(Rect(2, 0, 2, 1), Point(0, screen.bounds.h - 72), 0);
screen.sprite(Rect(1, 2, 3, 1), Point(60, screen.bounds.h - 72), 0);
screen.sprite(Rect(2, 1, 2, 1), Point(120, screen.bounds.h - 72), 0);
background->palette[29] = background->palette[18];
screen.sprite(Rect(2, 0, 2, 1), Point(0, screen.bounds.h - 64), 2);
screen.sprite(Rect(1, 2, 3, 1), Point(60, screen.bounds.h - 64), 2);
screen.sprite(Rect(2, 1, 2, 1), Point(120, screen.bounds.h - 64), 2);
background->palette[29] = t;
screen.sprite(SCENERY_BIG_SKULL, Point(0, screen.bounds.h - 52), 0);
screen.sprite(SCENERY_CLAWS, Point(30, screen.bounds.h - 48), 0);
screen.sprite(SCENERY_BIG_TUSK, Point(70, screen.bounds.h - 32), 0);
screen.sprite(SCENERY_BIG_BONE, Point(120, screen.bounds.h - 64), 0);
screen.sprite(SCENERY_BIG_ROCK, Point(230, screen.bounds.h - 32), 0);
screen.sprite(SHOT_BIG_RED, Point(30, 60), 0);
// Draw a chessboard so we can count our sprite tiles
for (int x = 0; x < 128 / 8; x++) {
for (int y = 0; y < 128 / 8; y++) {
if ((y + x) & 1) {
screen.pen = Pen(0, 0, 0, 64);
}
else {
screen.pen = Pen(255, 255, 255, 64);
}
screen.rectangle(Rect(x * 8, y * 8, 8, 8));
}
}
// Draw the whole ship spritesheet
screen.blit(ships, Rect(0, 0, 128, 128), Point(0, 0));
draw_tilebased_sprite(ships, Point(170, 120 + 5.0f * tween_bob.value), BG_SHIP_1);
draw_tilebased_sprite(ships, Point(120, 120 + 10.0f * tween_bob.value), BG_SHIP_2);
draw_tilebased_sprite(ships, Point(200, 160 + 10.0f * tween_bob.value), HOG_SHIP);
draw_tilebased_sprite(ships, Point(60, 160 + 10.0f * tween_bob.value), HOG_SHIP, true);
screen.alpha = 200;
for (auto x = 0; x < 10; x++) {
for (auto y = 0; y < 10; y++) {
draw_tilebased_sprite(ships, Point(x * 32, y * 24 + 5.0f * tween_bob.value), BG_SHIP_1, (x + y) & 1);
}
}
screen.alpha = 255;
uint32_t ms_end = blit::now() - time;
screen.pen = Pen(255, 100, 100);
screen.text(std::to_string(ms_end - ms_start), minimal_font, Point(5, 230));
}
void update(uint32_t time) {
if (buttons & Button::A && tween_dusk_dawn.is_finished()) {
tween_dusk_dawn.start();
}
for (int x = 0; x < 32; x++) {
Pen original = Pen(
sprites_background[x * 4 + 20],
sprites_background[x * 4 + 21],
sprites_background[x * 4 + 22],
sprites_background[x * 4 + 23]
);
Pen d = desert[x];
float s = 1.0f - tween_dusk_dawn.value;
float c = tween_dusk_dawn.value;
background->palette[x] = Pen(
std::min(255, int((d.r * s) + (original.r * c))),
std::min(255, int((d.g * s) + (original.g * c))),
std::min(255, int((d.b * s) + (original.b * c))),
original.a
);
}
}