Skip to content

Commit

Permalink
SpriteHandler.h:
Browse files Browse the repository at this point in the history
* Sprite:
  * Privatizing some member variables in the Sprite class.
  * Creating a private function Sprite::fetch_frame().
  * Texture frames in Sprite now live in unique-ptrs to eliminate a lot of memory swapping overhead.
  * The Sprite class now has its own name.
  * Renaming Sprite::init_frame() to Sprite::create_frame() which is more accurate.
  * Added function Sprite::load_frame() that loads a texture from file.
  * Added function Sprite::save_frame().
  * Added function Sprite::get_curr_frame_texture() which also contains a sanity check.
* SpriteHandler_examples.h:
  * Fixing some syntax errors with begin_screen() / end_screen().
  * Fixing bug in star func_frame_to_texture std::function.
  * Now using load_frame() for background for sprite4.
  • Loading branch information
razterizer committed Oct 20, 2024
1 parent 3ec8b31 commit 5c2a346
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 42 deletions.
30 changes: 16 additions & 14 deletions Examples/SpriteHandler_examples.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace sprite_handler
auto* sprite0 = sprh.create_sprite("spaceship");
sprite0->layer_id = 4;
sprite0->init(4, 5);
sprite0->init_frame(0);
sprite0->create_frame(0);
sprite0->set_sprite_chars_from_strings(0,
" _ ",
" /#\\ ",
Expand All @@ -47,7 +47,7 @@ namespace sprite_handler
1, 7, 7, 7, 1,
-2, -2, 14, -2, -2
);
sprite0->init_frame(1);
sprite0->create_frame(1);
sprite0->set_sprite_chars_from_strings(1,
" _ ",
" /#\\ ",
Expand All @@ -66,7 +66,7 @@ namespace sprite_handler
1, 7, 7, 7, 1,
-2, -2, 4, -2, -2
);
sprite0->init_frame(2);
sprite0->create_frame(2);
sprite0->set_sprite_chars_from_strings(2,
" _ ",
" /#\\ ",
Expand Down Expand Up @@ -98,7 +98,7 @@ namespace sprite_handler
auto* sprite1 = sprh.create_sprite("alien");
sprite1->layer_id = 5;
sprite1->init(2, 3);
sprite1->init_frame(0);
sprite1->create_frame(0);
sprite1->set_sprite_chars(0,
' ', '^', ' ',
'%', 'U', '%'
Expand All @@ -111,7 +111,7 @@ namespace sprite_handler
Color::Transparent2, Color::Transparent2, Color::Transparent2,
Color::Transparent2, Color::DarkYellow, Color::Transparent2
);
sprite1->init_frame(1);
sprite1->create_frame(1);
sprite1->set_sprite_chars(1,
' ', '^', ' ',
'#', 'U', '#'
Expand Down Expand Up @@ -142,7 +142,7 @@ namespace sprite_handler
sprite2->pos.c = rnd::rand_int(0, sh.num_cols()-1);
sprite2->layer_id = rnd::rand_select<int>({ 1, 3 });
sprite2->init(1, 1);
sprite2->init_frame(0);
sprite2->create_frame(0);
sprite2->set_sprite_chars(0, '@');
sprite2->set_sprite_fg_colors(0, Color::DarkGray);
sprite2->set_sprite_bg_colors(0, Color::Transparent2);
Expand All @@ -162,36 +162,38 @@ namespace sprite_handler
sprite3->pos.c = rnd::rand_int(0, sh.num_cols()-1);
sprite3->layer_id = 0;
sprite3->init(1, 1);
sprite3->init_frame(0);
sprite3->create_frame(0);
char star_ch = rnd::rand_select<char>({ '.', '+' });
sprite3->set_sprite_chars(0, star_ch);
sprite3->set_sprite_fg_colors(0, rnd::rand_select<Color>({ Color::White, Color::White, Color::White, Color::White, Color::White, Color::Yellow, Color::Yellow, Color::Yellow, Color::Red, Color::Blue, Color::Blue, Color::Blue }));
sprite3->set_sprite_bg_colors(0, Color::Transparent2);
sprite3->init_frame(1);
sprite3->create_frame(1);
sprite3->set_sprite_chars(1, star_ch);
sprite3->set_sprite_fg_colors(1, Color::Black);
sprite3->set_sprite_bg_colors(1, Color::Transparent2);
const int max_twinkle = 100;
int twinkle_offs = rnd::rand_int(0, max_twinkle);
sprite3->func_frame_to_texture = [twinkle_offs](int anim_frame)
{
return 1 - (anim_frame + twinkle_offs) % max_twinkle;
if ((anim_frame + twinkle_offs) % max_twinkle == 0)
return 1;
return 0;
};
}

auto* sprite4 = sprh.create_sprite("background");
sprite4->layer_id = 2;
sprite4->init(sh.num_rows(), sh.num_cols());
sprite4->init_frame(0);
// sprite4->texture_frames[0].save("background.tex");
sprite4->texture_frames[0].load("background.tex");
sprite4->create_frame(0);
// sprite4->save_frame(0, "background.tex");
sprite4->load_frame(0, "background.tex");

// ///////////////////////////////////////////////////////////
// LET's GO ! //
// ///////////////////////////////////////////////////////////


begin_screen(sh, tt);
begin_screen();

float dt = 0.01f;
for (int i = -3; i < sh.num_rows(); ++i)
Expand Down Expand Up @@ -230,7 +232,7 @@ namespace sprite_handler
}

quit:
end_screen();
end_screen(sh, tt);
}

}
88 changes: 60 additions & 28 deletions SpriteHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,26 @@ class Sprite
throw std::invalid_argument("Number of arguments must match sprite size.");
target = {static_cast<T>(args)...}; // Unpack and assign to the target vector
}

RC size { 0, 0 };
int area = 0;
std::vector<std::unique_ptr<drawing::Texture>> texture_frames;
std::string name;

drawing::Texture* fetch_frame(int anim_frame)
{
while (texture_frames.size() <= anim_frame)
texture_frames.emplace_back(std::make_unique<drawing::Texture>());
return texture_frames[anim_frame].get();
}

public:
RC pos { 0, 0 };
RC size { 0, 0 };
int area = 0;

int layer_id = 0; // 0 is the bottom layer.
bool enabled = true;

std::vector<drawing::Texture> texture_frames;
Sprite(const std::string& a_name) : name(a_name) {}

// Initialize the sprite's dimensions (NR and NC)
void init(int NR, int NC)
Expand All @@ -42,16 +52,31 @@ class Sprite
area = NR * NC;
}

void init_frame(int anim_frame)
void create_frame(int anim_frame)
{
auto& texture = stlutils::at_growing(texture_frames, anim_frame);
texture.clear();
texture.area = area;
texture.size = size;
texture.characters.resize(area);
texture.fg_colors.resize(area);
texture.bg_colors.resize(area);
texture.materials.resize(area);
auto* texture = fetch_frame(anim_frame);
texture->clear();
texture->area = area;
texture->size = size;
texture->characters.resize(area);
texture->fg_colors.resize(area);
texture->bg_colors.resize(area);
texture->materials.resize(area);
}

void load_frame(int anim_frame, const std::string& file_path)
{
auto* texture = fetch_frame(anim_frame);
texture->clear();
texture->load(file_path);
if (texture->size != size)
throw std::invalid_argument("Loaded sprite frame doesn't have the same size as the sprite itself.");
}

void save_frame(int anim_frame, const std::string& file_path)
{
auto* texture = fetch_frame(anim_frame);
texture->save(file_path);
}

// #FIXME: Perhaps move these varyadic functions to Texture for more versatility.
Expand All @@ -60,58 +85,66 @@ class Sprite
template<typename... Chars>
void set_sprite_chars(int anim_frame, Chars... ch)
{
auto& texture = stlutils::at_growing(texture_frames, anim_frame);
set_sprite_data(texture.characters, ch...);
auto* texture = fetch_frame(anim_frame);
set_sprite_data(texture->characters, ch...);
}

// Set sprite characters from a string for each row
template<typename... Strings>
void set_sprite_chars_from_strings(int anim_frame, Strings... rows)
{
auto& texture = stlutils::at_growing(texture_frames, anim_frame);
auto* texture = fetch_frame(anim_frame);

std::array<std::string, sizeof...(rows)> row_array = { rows... };

// Check that the number of rows matches the texture's height
if (row_array.size() != texture.size.r)
if (row_array.size() != texture->size.r)
throw std::invalid_argument("Number of strings must match the number of rows.");

for (const auto& row : row_array)
if (row.size() != texture.size.c)
if (row.size() != texture->size.c)
throw std::invalid_argument("Each string must have exactly NC characters.");

// Unpack strings into the characters vector
int idx = 0;
for (const auto& row : row_array)
for (char ch : row)
texture.characters[idx++] = ch;
texture->characters[idx++] = ch;
}

// Set sprite foreground colors
template<typename... Colors>
void set_sprite_fg_colors(int anim_frame, Colors... fg_color)
{
auto& texture = stlutils::at_growing(texture_frames, anim_frame);
set_sprite_data(texture.fg_colors, fg_color...);
auto* texture = fetch_frame(anim_frame);
set_sprite_data(texture->fg_colors, fg_color...);
}

// Set sprite background colors
template<typename... Colors>
void set_sprite_bg_colors(int anim_frame, Colors... bg_color)
{
auto& texture = stlutils::at_growing(texture_frames, anim_frame);
set_sprite_data(texture.bg_colors, bg_color...);
auto* texture = fetch_frame(anim_frame);
set_sprite_data(texture->bg_colors, bg_color...);
}

// Set sprite materials
template<typename... Materials>
void set_sprite_materials(int anim_frame, Materials... mat)
{
auto& texture = stlutils::at_growing(texture_frames, anim_frame);
set_sprite_data(texture.materials, mat...);
auto* texture = fetch_frame(anim_frame);
set_sprite_data(texture->materials, mat...);
}

std::function<int(int)> func_frame_to_texture = [](int anim_frame) -> int { return 0; };

const drawing::Texture& get_curr_frame_texture(int anim_frame)
{
int tex_id = func_frame_to_texture(anim_frame);
if (tex_id >= texture_frames.size())
throw std::invalid_argument("ERROR: Incorrect frame id: " + std::to_string(tex_id) + " for sprite \"" + name + "\"! Sprite only has " + std::to_string(texture_frames.size()) + " frames.");
return *texture_frames[tex_id];
}
};

// /////////////////////////////////////
Expand All @@ -126,7 +159,7 @@ class SpriteHandler

Sprite* create_sprite(const std::string& sprite_name)
{
m_sprites[sprite_name] = std::make_unique<Sprite>();
m_sprites[sprite_name] = std::make_unique<Sprite>(sprite_name);
// We simply assume that it was successfully created.
return m_sprites[sprite_name].get();
}
Expand Down Expand Up @@ -154,9 +187,8 @@ class SpriteHandler
const auto& sprite = sprite_pair.second;
if (sprite->enabled && sprite->layer_id == layer_id)
{
int tex_id = sprite->func_frame_to_texture(anim_frame);
auto& texture = stlutils::at_growing(sprite->texture_frames, tex_id);

auto& texture = sprite->get_curr_frame_texture(anim_frame);

drawing::draw_box_textured(sh,
sprite->pos.r - 1, sprite->pos.c - 1,
texture.size.r + 2, texture.size.c + 2,
Expand Down

0 comments on commit 5c2a346

Please sign in to comment.