basic components

This commit is contained in:
Noel Berry
2021-01-02 16:20:01 -08:00
parent 8db43ce18e
commit 4e05170023
20 changed files with 636 additions and 9 deletions

View 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
View 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
View 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
View 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
View 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
View 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;
};
}

View File

14
src/components/player.h Normal file
View 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;
};
}