mirror of
https://github.com/NoelFB/tiny_link.git
synced 2024-11-25 18:18:56 +08:00
tilemap rendering!
This commit is contained in:
parent
c38b1e1418
commit
dd1bbbc9de
|
@ -30,7 +30,7 @@ add_executable(game
|
|||
src/masks.h
|
||||
src/factory.h
|
||||
src/factory.cpp
|
||||
)
|
||||
"src/assets/tileset.h" "src/assets/tileset.cpp" "src/components/tilemap.h" "src/components/tilemap.cpp")
|
||||
|
||||
# Reference blah
|
||||
target_link_libraries(game blah)
|
||||
|
|
BIN
content/tilesets/castle.ase
Normal file
BIN
content/tilesets/castle.ase
Normal file
Binary file not shown.
0
src/assets/tileset.cpp
Normal file
0
src/assets/tileset.cpp
Normal file
18
src/assets/tileset.h
Normal file
18
src/assets/tileset.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
#include <blah.h>
|
||||
|
||||
using namespace Blah;
|
||||
|
||||
namespace TL
|
||||
{
|
||||
struct Tileset
|
||||
{
|
||||
static constexpr int max_columns = 16;
|
||||
static constexpr int max_rows = 16;
|
||||
|
||||
String name;
|
||||
int columns = 0;
|
||||
int rows = 0;
|
||||
Subtexture tiles[max_columns * max_rows];
|
||||
};
|
||||
}
|
|
@ -24,6 +24,9 @@ Collider Collider::make_grid(int tile_size, int columns, int rows)
|
|||
collider.m_grid.columns = columns;
|
||||
collider.m_grid.rows = rows;
|
||||
collider.m_grid.cells = std::shared_ptr<bool[]>(new bool[columns * rows]);
|
||||
|
||||
memset(collider.m_grid.cells.get(), 0, sizeof(bool) * columns * rows);
|
||||
|
||||
return collider;
|
||||
}
|
||||
|
||||
|
@ -60,6 +63,13 @@ void Collider::set_cell(int x, int y, bool value)
|
|||
m_grid.cells[x + y * m_grid.columns] = value;
|
||||
}
|
||||
|
||||
void Collider::set_cells(int x, int y, int w, int h, bool value)
|
||||
{
|
||||
for (int tx = x; tx < x + w; tx++)
|
||||
for (int ty = y; ty < y + h; ty++)
|
||||
m_grid.cells[tx + ty * m_grid.columns] = value;
|
||||
}
|
||||
|
||||
bool Collider::check(uint32_t mask, Point offset) const
|
||||
{
|
||||
auto other = world()->first<Collider>();
|
||||
|
@ -143,5 +153,21 @@ bool TL::Collider::rect_to_rect(const Collider* a, const Collider* b, Point offs
|
|||
|
||||
bool TL::Collider::rect_to_grid(const Collider* a, const Collider* b, Point offset)
|
||||
{
|
||||
// get a relative rectangle to the grid
|
||||
RectI rect = a->m_rect + a->entity()->position + offset - b->entity()->position;
|
||||
|
||||
// get the cells the rectangle overlaps
|
||||
int left = Calc::clamp_int(Calc::floor(rect.x / (float)b->m_grid.tile_size), 0, b->m_grid.columns);
|
||||
int right = Calc::clamp_int(Calc::ceiling(rect.right() / (float)b->m_grid.tile_size), 0, b->m_grid.columns);
|
||||
int top = Calc::clamp_int(Calc::floor(rect.y / (float)b->m_grid.tile_size), 0, b->m_grid.rows);
|
||||
int bottom = Calc::clamp_int(Calc::ceiling(rect.bottom() / (float)b->m_grid.tile_size), 0, b->m_grid.rows);
|
||||
|
||||
// check each cell
|
||||
for (int x = left; x < right; x++)
|
||||
for (int y = top; y < bottom; y++)
|
||||
if (b->m_grid.cells[x + y * b->m_grid.columns])
|
||||
return true;
|
||||
|
||||
// all cells were empty
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace TL
|
|||
void set_rect(const RectI& value);
|
||||
bool get_cell(int x, int y) const;
|
||||
void set_cell(int x, int y, bool value);
|
||||
void set_cells(int x, int y, int w, int h, bool value);
|
||||
|
||||
bool check(uint32_t mask, Point offset = Point::zero) const;
|
||||
bool overlaps(const Collider* other, Point offset = Point::zero) const;
|
||||
|
|
61
src/components/tilemap.cpp
Normal file
61
src/components/tilemap.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
#include "tilemap.h"
|
||||
|
||||
using namespace TL;
|
||||
|
||||
Tilemap::Tilemap()
|
||||
{
|
||||
}
|
||||
|
||||
Tilemap::Tilemap(int tile_width, int tile_height, int columns, int rows)
|
||||
{
|
||||
m_tile_width = tile_width;
|
||||
m_tile_height = tile_height;
|
||||
m_columns = columns;
|
||||
m_rows = rows;
|
||||
m_grid = std::shared_ptr<Subtexture[]>(new Subtexture[columns * rows]);
|
||||
}
|
||||
|
||||
int Tilemap::tile_width() const
|
||||
{
|
||||
return m_tile_width;
|
||||
}
|
||||
|
||||
int Tilemap::tile_height() const
|
||||
{
|
||||
return m_tile_height;
|
||||
}
|
||||
|
||||
int Tilemap::columns() const
|
||||
{
|
||||
return m_columns;
|
||||
}
|
||||
|
||||
int Tilemap::rows() const
|
||||
{
|
||||
return m_rows;
|
||||
}
|
||||
|
||||
void Tilemap::set_cell(int x, int y, const Subtexture* tex)
|
||||
{
|
||||
if (tex)
|
||||
m_grid[x + y * m_columns] = *tex;
|
||||
else
|
||||
m_grid[x + y * m_columns].texture.reset();
|
||||
}
|
||||
|
||||
void Tilemap::set_cells(int x, int y, int w, int h, const Subtexture* tex)
|
||||
{
|
||||
for (int tx = x; tx < x + w; tx++)
|
||||
for (int ty = y; ty < y + h; ty++)
|
||||
set_cell(tx, ty, tex);
|
||||
}
|
||||
|
||||
void Tilemap::render(Batch& batch)
|
||||
{
|
||||
for (int x = 0; x < m_columns; x ++)
|
||||
for (int y = 0; y < m_rows; y ++)
|
||||
if (m_grid[x + y * m_columns].texture)
|
||||
{
|
||||
batch.tex(m_grid[x + y * m_columns], Vec2(x * m_tile_width, y * m_tile_height));
|
||||
}
|
||||
}
|
32
src/components/tilemap.h
Normal file
32
src/components/tilemap.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
#include "../world.h"
|
||||
#include <blah.h>
|
||||
#include <memory>
|
||||
|
||||
using namespace Blah;
|
||||
|
||||
namespace TL
|
||||
{
|
||||
class Tilemap : public Component
|
||||
{
|
||||
public:
|
||||
Tilemap();
|
||||
Tilemap(int tile_width, int tile_height, int columns, int rows);
|
||||
|
||||
int tile_width() const;
|
||||
int tile_height() const;
|
||||
int columns() const;
|
||||
int rows() const;
|
||||
|
||||
void set_cell(int x, int y, const Subtexture* tex);
|
||||
void set_cells(int x, int y, int w, int h, const Subtexture* tex);
|
||||
void render(Batch& batch) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Subtexture[]> m_grid;
|
||||
int m_tile_width = 0;
|
||||
int m_tile_height = 0;
|
||||
int m_columns = 0;
|
||||
int m_rows = 0;
|
||||
};
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
#include "content.h"
|
||||
#include "game.h"
|
||||
#include "assets/sprite.h"
|
||||
#include "assets/tileset.h"
|
||||
|
||||
using namespace TL;
|
||||
|
||||
|
@ -7,6 +9,7 @@ namespace
|
|||
{
|
||||
FilePath root;
|
||||
Vector<Sprite> sprites;
|
||||
Vector<Tileset> tilesets;
|
||||
Vector<Subtexture> subtextures;
|
||||
TextureRef sprite_atlas;
|
||||
|
||||
|
@ -62,13 +65,8 @@ void Content::load()
|
|||
SpriteInfo* info = sprite_info.expand();
|
||||
info->aseprite = Aseprite(it.cstr());
|
||||
info->name = String(it.cstr() + sprite_path.length(), it.end() - 4);
|
||||
}
|
||||
|
||||
// add to the atlas
|
||||
for (auto& info : sprite_info)
|
||||
{
|
||||
info.pack_index = pack_index;
|
||||
for (auto& frame : info.aseprite.frames)
|
||||
info->pack_index = pack_index;
|
||||
for (auto& frame : info->aseprite.frames)
|
||||
{
|
||||
packer.add(pack_index, frame.image);
|
||||
pack_index++;
|
||||
|
@ -76,6 +74,36 @@ void Content::load()
|
|||
}
|
||||
}
|
||||
|
||||
// load tileset
|
||||
Vector<SpriteInfo> tileset_info;
|
||||
{
|
||||
// get all the tilesets
|
||||
FilePath sprite_path = path() + "tilesets/";
|
||||
for (auto& it : Directory::enumerate(sprite_path, true))
|
||||
{
|
||||
if (!it.ends_with(".ase"))
|
||||
continue;
|
||||
|
||||
SpriteInfo* info = tileset_info.expand();
|
||||
info->aseprite = Aseprite(it.cstr());
|
||||
info->name = String(it.cstr() + sprite_path.length(), it.end() - 4);
|
||||
info->pack_index = pack_index;
|
||||
|
||||
auto& frame = info->aseprite.frames[0];
|
||||
auto columns = frame.image.width / Game::tile_width;
|
||||
auto rows = frame.image.height / Game::tile_height;
|
||||
|
||||
for (int x = 0; x < columns; x++)
|
||||
for (int y = 0; y < rows; y++)
|
||||
{
|
||||
auto subrect = RectI(x * Game::tile_width, y * Game::tile_height, Game::tile_width, Game::tile_height);
|
||||
auto subimage = frame.image.get_sub_image(subrect);
|
||||
packer.add(pack_index, subimage);
|
||||
pack_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// build the atlas
|
||||
{
|
||||
packer.pack();
|
||||
|
@ -113,6 +141,24 @@ void Content::load()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add tilesets
|
||||
for (auto& info : tileset_info)
|
||||
{
|
||||
auto& frame = info.aseprite.frames[0];
|
||||
|
||||
Tileset* tileset = tilesets.expand();
|
||||
tileset->name = info.name;
|
||||
tileset->columns = frame.image.width / Game::tile_width;
|
||||
tileset->rows = frame.image.height / Game::tile_height;
|
||||
|
||||
for (int x = 0, i = info.pack_index; x < tileset->columns; x++)
|
||||
for (int y = 0; y < tileset->rows; y++)
|
||||
{
|
||||
tileset->tiles[x + y * tileset->columns] = subtextures[i];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Content::unload()
|
||||
|
@ -133,3 +179,12 @@ const Sprite* Content::find_sprite(const char* name)
|
|||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Tileset* Content::find_tileset(const char* name)
|
||||
{
|
||||
for (auto& it : tilesets)
|
||||
if (it.name == name)
|
||||
return ⁢
|
||||
|
||||
return nullptr;
|
||||
}
|
|
@ -6,6 +6,7 @@ using namespace Blah;
|
|||
namespace TL
|
||||
{
|
||||
struct Sprite;
|
||||
struct Tileset;
|
||||
|
||||
class Content
|
||||
{
|
||||
|
@ -18,5 +19,6 @@ namespace TL
|
|||
static TextureRef atlas();
|
||||
|
||||
static const Sprite* find_sprite(const char* name);
|
||||
static const Tileset* find_tileset(const char* name);
|
||||
};
|
||||
}
|
|
@ -10,8 +10,9 @@ Entity* Factory::player(World* world, Point position)
|
|||
{
|
||||
auto en = world->add_entity(position);
|
||||
|
||||
auto an = en->add(Animator("player"));
|
||||
an->play("idle");
|
||||
auto anim = en->add(Animator("player"));
|
||||
anim->play("idle");
|
||||
anim->depth = -10;
|
||||
|
||||
auto hitbox = en->add(Collider::make_rect(RectI(-4, -8, 8, 8)));
|
||||
|
||||
|
|
21
src/game.cpp
21
src/game.cpp
|
@ -1,7 +1,9 @@
|
|||
#include "game.h"
|
||||
#include "content.h"
|
||||
#include "masks.h"
|
||||
#include "assets/tileset.h"
|
||||
#include "components/collider.h"
|
||||
#include "components/tilemap.h"
|
||||
#include "factory.h"
|
||||
|
||||
using namespace TL;
|
||||
|
@ -12,7 +14,7 @@ void Game::startup()
|
|||
Content::load();
|
||||
|
||||
// framebuffer for the game
|
||||
buffer = FrameBuffer::create(320, 180);
|
||||
buffer = FrameBuffer::create(width, height);
|
||||
|
||||
// set batcher to use Nearest Filter
|
||||
batch.default_sampler = TextureSampler(TextureFilter::Nearest);
|
||||
|
@ -27,10 +29,20 @@ void Game::load_map()
|
|||
world.clear();
|
||||
|
||||
// add a test player
|
||||
Factory::player(&world, Point(50, 50));
|
||||
Factory::player(&world, Point(width / 2, height - 32));
|
||||
|
||||
auto floor = world.add_entity(Point(0, 100));
|
||||
auto c2 = floor->add(Collider::make_rect(RectI(0, 0, 320, 16)));
|
||||
// get the castle tileset for now
|
||||
auto castle = Content::find_tileset("castle");
|
||||
|
||||
// make the floor
|
||||
auto floor = world.add_entity();
|
||||
auto tm = floor->add(Tilemap(8, 8, 40, 23));
|
||||
tm->set_cells(0, 20, 40, 3, &castle->tiles[0]);
|
||||
tm->set_cells(0, 18, 10, 2, &castle->tiles[0]);
|
||||
|
||||
auto c2 = floor->add(Collider::make_grid(8, 40, 23));
|
||||
c2->set_cells(0, 20, 40, 3, true);
|
||||
c2->set_cells(0, 18, 10, 2, true);
|
||||
c2->mask = Mask::solid;
|
||||
}
|
||||
|
||||
|
@ -67,6 +79,7 @@ void Game::render()
|
|||
}
|
||||
}
|
||||
|
||||
batch.tex(Content::atlas());
|
||||
batch.render(buffer);
|
||||
batch.clear();
|
||||
}
|
||||
|
|
|
@ -9,6 +9,11 @@ namespace TL
|
|||
class Game
|
||||
{
|
||||
public:
|
||||
static constexpr int width = 320;
|
||||
static constexpr int height = 180;
|
||||
static constexpr int tile_width = 8;
|
||||
static constexpr int tile_height = 8;
|
||||
|
||||
World world;
|
||||
FrameBufferRef buffer;
|
||||
Batch batch;
|
||||
|
|
Loading…
Reference in New Issue
Block a user