mirror of
https://github.com/NoelFB/tiny_link.git
synced 2025-07-01 19:45:27 +08:00
basic components
This commit is contained in:
76
src/components/animator.cpp
Normal file
76
src/components/animator.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
#include "animator.h"
|
||||
#include "../content.h"
|
||||
|
||||
using namespace TL;
|
||||
|
||||
Animator::Animator(const String& sprite)
|
||||
{
|
||||
m_sprite = Content::find_sprite(sprite);
|
||||
m_animation_index = 0;
|
||||
}
|
||||
|
||||
void Animator::play(const String& animation)
|
||||
{
|
||||
BLAH_ASSERT(m_sprite, "No Sprite Assigned!");
|
||||
|
||||
for (int i = 0; i < m_sprite->animations.size(); i++)
|
||||
{
|
||||
if (m_sprite->animations[i].name == animation)
|
||||
{
|
||||
m_animation_index = i;
|
||||
m_frame_index = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Animator::update()
|
||||
{
|
||||
// only update if we're in a valid state
|
||||
if (in_valid_state())
|
||||
{
|
||||
// quick references
|
||||
auto& anim = m_sprite->animations[m_animation_index];
|
||||
auto& frame = anim.frames[m_frame_index];
|
||||
|
||||
// increment frame counter
|
||||
m_frame_counter += Time::delta;
|
||||
|
||||
// move to next frame after duration
|
||||
while (m_frame_counter >= frame.duration)
|
||||
{
|
||||
// reset frame counter
|
||||
m_frame_counter -= frame.duration;
|
||||
|
||||
// increement frame, move back if we're at the end
|
||||
m_frame_index++;
|
||||
if (m_frame_index >= anim.frames.size())
|
||||
m_frame_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Animator::render(Batch& batch)
|
||||
{
|
||||
if (in_valid_state())
|
||||
{
|
||||
batch.push_matrix(
|
||||
Mat3x2::create_transform(entity()->position, m_sprite->origin, Vec2::one, 0));
|
||||
|
||||
auto& anim = m_sprite->animations[m_animation_index];
|
||||
auto& frame = anim.frames[m_frame_index];
|
||||
batch.tex(frame.image, Vec2::zero, Color::white);
|
||||
|
||||
batch.pop_matrix();
|
||||
}
|
||||
}
|
||||
|
||||
bool Animator::in_valid_state() const
|
||||
{
|
||||
return
|
||||
m_sprite &&
|
||||
m_animation_index >= 0 &&
|
||||
m_animation_index < m_sprite->animations.size() &&
|
||||
m_frame_index >= 0 &&
|
||||
m_frame_index < m_sprite->animations[m_animation_index].frames.size();
|
||||
}
|
31
src/components/animator.h
Normal file
31
src/components/animator.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include <blah.h>
|
||||
#include "../assets/sprite.h"
|
||||
#include "../world.h"
|
||||
|
||||
using namespace Blah;
|
||||
|
||||
namespace TL
|
||||
{
|
||||
class Animator : public Component
|
||||
{
|
||||
private:
|
||||
const Sprite* m_sprite = nullptr;
|
||||
int m_animation_index = 0;
|
||||
int m_frame_index = 0;
|
||||
float m_frame_counter = 0;
|
||||
|
||||
public:
|
||||
|
||||
Animator() = default;
|
||||
Animator(const String& sprite);
|
||||
|
||||
void play(const String& animation);
|
||||
|
||||
void update() override;
|
||||
void render(Batch& batch) override;
|
||||
|
||||
private:
|
||||
bool in_valid_state() const;
|
||||
};
|
||||
}
|
147
src/components/collider.cpp
Normal file
147
src/components/collider.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
#include "collider.h"
|
||||
|
||||
using namespace TL;
|
||||
|
||||
Collider::Collider()
|
||||
{
|
||||
visible = false;
|
||||
active = false;
|
||||
}
|
||||
|
||||
Collider Collider::make_rect(const RectI& rect)
|
||||
{
|
||||
Collider collider;
|
||||
collider.m_shape = Shape::Rect;
|
||||
collider.m_rect = rect;
|
||||
return collider;
|
||||
}
|
||||
|
||||
Collider Collider::make_grid(int tile_size, int columns, int rows)
|
||||
{
|
||||
Collider collider;
|
||||
collider.m_shape = Shape::Grid;
|
||||
collider.m_grid.tile_size = tile_size;
|
||||
collider.m_grid.columns = columns;
|
||||
collider.m_grid.rows = rows;
|
||||
collider.m_grid.cells = std::shared_ptr<bool[]>(new bool[columns * rows]);
|
||||
return collider;
|
||||
}
|
||||
|
||||
Collider::Shape Collider::shape() const
|
||||
{
|
||||
return m_shape;
|
||||
}
|
||||
|
||||
RectI Collider::get_rect() const
|
||||
{
|
||||
BLAH_ASSERT(m_shape == Shape::Rect, "Collider is not a Rectangle");
|
||||
return m_rect;
|
||||
}
|
||||
|
||||
void Collider::set_rect(const RectI& value)
|
||||
{
|
||||
BLAH_ASSERT(m_shape == Shape::Rect, "Collider is not a Rectangle");
|
||||
m_rect = value;
|
||||
}
|
||||
|
||||
bool Collider::get_cell(int x, int y) const
|
||||
{
|
||||
BLAH_ASSERT(m_shape == Shape::Grid, "Collider is not a Grid");
|
||||
BLAH_ASSERT(x >= 0 && y >= 0 && x < m_grid.columns && y < m_grid.rows, "Cell is out of bounds");
|
||||
|
||||
return m_grid.cells[x + y * m_grid.columns];
|
||||
}
|
||||
|
||||
void Collider::set_cell(int x, int y, bool value)
|
||||
{
|
||||
BLAH_ASSERT(m_shape == Shape::Grid, "Collider is not a Grid");
|
||||
BLAH_ASSERT(x >= 0 && y >= 0 && x < m_grid.columns&& y < m_grid.rows, "Cell is out of bounds");
|
||||
|
||||
m_grid.cells[x + y * m_grid.columns] = value;
|
||||
}
|
||||
|
||||
bool Collider::check(uint32_t mask, Point offset) const
|
||||
{
|
||||
auto other = world()->first<Collider>();
|
||||
while (other)
|
||||
{
|
||||
if (other != this &&
|
||||
(other->mask & mask) == mask &&
|
||||
overlaps(other, offset))
|
||||
return true;
|
||||
|
||||
other = (Collider*)other->next();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Collider::overlaps(const Collider* other, Point offset) const
|
||||
{
|
||||
if (m_shape == Shape::Rect)
|
||||
{
|
||||
if (other->m_shape == Shape::Rect)
|
||||
{
|
||||
return rect_to_rect(this, other, offset);
|
||||
}
|
||||
else if (other->m_shape == Shape::Grid)
|
||||
{
|
||||
return rect_to_grid(this, other, offset);
|
||||
}
|
||||
}
|
||||
else if (m_shape == Shape::Grid)
|
||||
{
|
||||
if (other->m_shape == Shape::Rect)
|
||||
{
|
||||
return rect_to_grid(other, this, -offset);
|
||||
}
|
||||
else if (other->m_shape == Shape::Grid)
|
||||
{
|
||||
BLAH_ASSERT(false, "Grid->Grid Overlap checks not supported!");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Collider::render(Batch& batch)
|
||||
{
|
||||
static const Color color = Color::red;
|
||||
|
||||
batch.push_matrix(Mat3x2::create_translation(entity()->position));
|
||||
|
||||
if (m_shape == Shape::Rect)
|
||||
{
|
||||
batch.rect_line(m_rect, 1, color);
|
||||
}
|
||||
else if (m_shape == Shape::Grid)
|
||||
{
|
||||
for (int x = 0; x < m_grid.columns; x++)
|
||||
{
|
||||
for (int y = 0; y < m_grid.rows; y++)
|
||||
{
|
||||
if (!m_grid.cells[x + y * m_grid.columns])
|
||||
continue;
|
||||
|
||||
batch.rect_line(
|
||||
Rect(x * m_grid.tile_size, y * m_grid.tile_size, m_grid.tile_size, m_grid.tile_size),
|
||||
1, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
batch.pop_matrix();
|
||||
}
|
||||
|
||||
bool TL::Collider::rect_to_rect(const Collider* a, const Collider* b, Point offset)
|
||||
{
|
||||
RectI ar = a->m_rect + a->entity()->position + offset;
|
||||
RectI br = b->m_rect + b->entity()->position;
|
||||
|
||||
return ar.overlaps(br);
|
||||
}
|
||||
|
||||
bool TL::Collider::rect_to_grid(const Collider* a, const Collider* b, Point offset)
|
||||
{
|
||||
return false;
|
||||
}
|
54
src/components/collider.h
Normal file
54
src/components/collider.h
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include <blah.h>
|
||||
#include <memory>
|
||||
#include "../world.h"
|
||||
|
||||
using namespace Blah;
|
||||
|
||||
namespace TL
|
||||
{
|
||||
class Collider : public Component
|
||||
{
|
||||
public:
|
||||
enum class Shape
|
||||
{
|
||||
None,
|
||||
Rect,
|
||||
Grid
|
||||
};
|
||||
|
||||
uint32_t mask;
|
||||
|
||||
Collider();
|
||||
|
||||
static Collider make_rect(const RectI& rect);
|
||||
static Collider make_grid(int tile_size, int columns, int rows);
|
||||
|
||||
Shape shape() const;
|
||||
RectI get_rect() const;
|
||||
void set_rect(const RectI& value);
|
||||
bool get_cell(int x, int y) const;
|
||||
void set_cell(int x, int y, bool value);
|
||||
|
||||
bool check(uint32_t mask, Point offset = Point::zero) const;
|
||||
bool overlaps(const Collider* other, Point offset = Point::zero) const;
|
||||
|
||||
void render(Batch& batch) override;
|
||||
|
||||
private:
|
||||
struct Grid
|
||||
{
|
||||
int columns;
|
||||
int rows;
|
||||
int tile_size;
|
||||
std::shared_ptr<bool[]> cells;
|
||||
};
|
||||
|
||||
Shape m_shape = Shape::None;
|
||||
RectI m_rect;
|
||||
Grid m_grid;
|
||||
|
||||
static bool rect_to_rect(const Collider* a, const Collider* b, Point offset);
|
||||
static bool rect_to_grid(const Collider* a, const Collider* b, Point offset);
|
||||
};
|
||||
}
|
89
src/components/mover.cpp
Normal file
89
src/components/mover.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
#include "mover.h"
|
||||
#include "../masks.h"
|
||||
|
||||
using namespace TL;
|
||||
|
||||
bool Mover::move_x(int amount)
|
||||
{
|
||||
if (collider)
|
||||
{
|
||||
int sign = Calc::sign(amount);
|
||||
|
||||
while (amount != 0)
|
||||
{
|
||||
if (collider->check(Mask::solid, Point(sign, 0)))
|
||||
{
|
||||
stop_x();
|
||||
return true;
|
||||
}
|
||||
|
||||
amount -= sign;
|
||||
entity()->position.x += sign;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
entity()->position.x += amount;
|
||||
}
|
||||
}
|
||||
|
||||
bool Mover::move_y(int amount)
|
||||
{
|
||||
if (collider)
|
||||
{
|
||||
int sign = Calc::sign(amount);
|
||||
|
||||
while (amount != 0)
|
||||
{
|
||||
if (collider->check(Mask::solid, Point(0, sign)))
|
||||
{
|
||||
stop_y();
|
||||
return true;
|
||||
}
|
||||
|
||||
amount -= sign;
|
||||
entity()->position.y += sign;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
entity()->position.y += amount;
|
||||
}
|
||||
}
|
||||
|
||||
void Mover::stop_x()
|
||||
{
|
||||
speed.x = 0;
|
||||
m_remainder.x = 0;
|
||||
}
|
||||
|
||||
void Mover::stop_y()
|
||||
{
|
||||
speed.y = 0;
|
||||
m_remainder.y = 0;
|
||||
}
|
||||
|
||||
void Mover::stop()
|
||||
{
|
||||
speed.x = 0;
|
||||
speed.y = 0;
|
||||
m_remainder.x = 0;
|
||||
m_remainder.y = 0;
|
||||
}
|
||||
|
||||
void Mover::update()
|
||||
{
|
||||
// get the amount we should move, including remainder from the previous frame
|
||||
Vec2 total = m_remainder + speed * Time::delta;
|
||||
|
||||
// round to integer values since we only move in pixels at a time
|
||||
Point to_move = Point((int)total.x, (int)total.y);
|
||||
|
||||
// store remainder floating values for next frame
|
||||
m_remainder.x = total.x - to_move.x;
|
||||
m_remainder.y = total.y - to_move.y;
|
||||
|
||||
// move by integer values
|
||||
move_x(to_move.x);
|
||||
move_y(to_move.y);
|
||||
}
|
28
src/components/mover.h
Normal file
28
src/components/mover.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "../world.h"
|
||||
#include "collider.h"
|
||||
#include <blah.h>
|
||||
|
||||
using namespace Blah;
|
||||
|
||||
namespace TL
|
||||
{
|
||||
class Mover : public Component
|
||||
{
|
||||
private:
|
||||
Vec2 m_remainder;
|
||||
|
||||
public:
|
||||
Collider* collider;
|
||||
Vec2 speed;
|
||||
|
||||
bool move_x(int amount);
|
||||
bool move_y(int amount);
|
||||
|
||||
void stop_x();
|
||||
void stop_y();
|
||||
void stop();
|
||||
|
||||
void update() override;
|
||||
};
|
||||
}
|
0
src/components/player.cpp
Normal file
0
src/components/player.cpp
Normal file
14
src/components/player.h
Normal file
14
src/components/player.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include "../world.h"
|
||||
#include <blah.h>
|
||||
|
||||
using namespace Blah;
|
||||
|
||||
namespace TL
|
||||
{
|
||||
class Player : public Component
|
||||
{
|
||||
public:
|
||||
void update() override;
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user