room transition + attack anim

This commit is contained in:
Noel Berry 2021-01-03 14:08:22 -08:00
parent a8b78214f9
commit fb9cebd8ff
15 changed files with 249 additions and 54 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

After

Width:  |  Height:  |  Size: 168 B

BIN
content/map/1x0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

Binary file not shown.

BIN
content/tilesets/grass.ase Normal file

Binary file not shown.

BIN
content/tilesets/plants.ase Normal file

Binary file not shown.

View File

@ -0,0 +1,11 @@
#include "sprite.h"
using namespace TL;
const Sprite::Animation* TL::Sprite::get_animation(const String& name) const
{
for (auto& it : animations)
if (it.name == name)
return ⁢
return nullptr;
}

View File

@ -17,10 +17,20 @@ namespace TL
{ {
String name; String name;
Vector<Frame> frames; Vector<Frame> frames;
float duration() const
{
float d = 0;
for (auto& it : frames)
d += it.duration;
return d;
}
}; };
String name; String name;
Vec2 origin; Vec2 origin;
Vector<Animation> animations; Vector<Animation> animations;
const Animation* get_animation(const String& name) const;
}; };
} }

View File

@ -9,16 +9,26 @@ Animator::Animator(const String& sprite)
m_animation_index = 0; m_animation_index = 0;
} }
void Animator::play(const String& animation) const Sprite* Animator::sprite() const
{
return m_sprite;
}
void Animator::play(const String& animation, bool restart)
{ {
BLAH_ASSERT(m_sprite, "No Sprite Assigned!"); BLAH_ASSERT(m_sprite, "No Sprite Assigned!");
for (int i = 0; i < m_sprite->animations.size(); i++) for (int i = 0; i < m_sprite->animations.size(); i++)
{ {
if (m_sprite->animations[i].name == animation) if (m_sprite->animations[i].name == animation)
{
if (m_animation_index != i || restart)
{ {
m_animation_index = i; m_animation_index = i;
m_frame_index = 0; m_frame_index = 0;
m_frame_counter = 0;
}
break; break;
} }
} }

View File

@ -21,8 +21,8 @@ namespace TL
Animator() = default; Animator() = default;
Animator(const String& sprite); Animator(const String& sprite);
void play(const String& animation); const Sprite* sprite() const;
void play(const String& animation, bool restart = false);
void update() override; void update() override;
void render(Batch& batch) override; void render(Batch& batch) override;

View File

@ -27,12 +27,18 @@ Player::Player()
.press_buffer(0.15f) .press_buffer(0.15f)
.add_key(Key::X) .add_key(Key::X)
.add_button(0, Button::A); .add_button(0, Button::A);
input_attack = VirtualButton()
.press_buffer(0.15f)
.add_key(Key::C)
.add_button(0, Button::X);
} }
void Player::update() void Player::update()
{ {
input_move.update(); input_move.update();
input_jump.update(); input_jump.update();
input_attack.update();
auto mover = get<Mover>(); auto mover = get<Mover>();
auto anim = get<Animator>(); auto anim = get<Animator>();
@ -44,13 +50,30 @@ void Player::update()
{ {
// land squish // land squish
if (!was_on_ground && m_on_ground) if (!was_on_ground && m_on_ground)
anim->scale = Vec2(facing * 1.5f, 0.7f); anim->scale = Vec2(m_facing * 1.5f, 0.7f);
// lerp scale back to one // lerp scale back to one
anim->scale = Calc::approach(anim->scale, Vec2(facing, 1.0f), Time::delta * 4); anim->scale = Calc::approach(anim->scale, Vec2(m_facing, 1.0f), Time::delta * 4);
// set facing // set m_facing
anim->scale.x = Calc::abs(anim->scale.x) * facing; anim->scale.x = Calc::abs(anim->scale.x) * m_facing;
}
// NORMAL STATE
if (m_state == st_normal)
{
// Current Animation
if (m_on_ground)
{
if (input != 0)
anim->play("run");
else
anim->play("idle");
}
else
{
anim->play("jump");
} }
// Horizontal Movement // Horizontal Movement
@ -74,7 +97,52 @@ void Player::update()
// Facing Direction // Facing Direction
if (input != 0 && m_on_ground) if (input != 0 && m_on_ground)
facing = input; m_facing = input;
}
// Invoke Jumping
{
if (input_jump.pressed() && mover->on_ground())
{
input_jump.clear_press_buffer();
anim->scale = Vec2(m_facing * 0.65f, 1.4f);
mover->speed.x = input * max_air_speed;
m_jump_timer = jump_time;
}
}
// Begin Attack
if (input_attack.pressed())
{
input_attack.clear_press_buffer();
m_state = st_attack;
m_attack_timer = anim->sprite()->get_animation("attack")->duration();
if (m_on_ground)
mover->speed.x = 0;
}
}
// ATTACK STATE
else if (m_state == st_attack)
{
anim->play("attack");
m_attack_timer -= Time::delta;
if (m_attack_timer <= 0)
{
anim->play("idle");
m_state = st_normal;
}
}
// Variable Jumping
if (m_jump_timer > 0)
{
mover->speed.y = -100;
m_jump_timer -= Time::delta;
if (!input_jump.down())
m_jump_timer = 0;
} }
// Gravity // Gravity
@ -86,22 +154,4 @@ void Player::update()
mover->speed.y += grav * Time::delta; mover->speed.y += grav * Time::delta;
} }
// Jumping
{
if (input_jump.pressed() && mover->on_ground())
{
anim->scale = Vec2(facing * 0.65f, 1.4f);
mover->speed.x = input * max_air_speed;
m_jump_timer = jump_time;
}
if (m_jump_timer > 0)
{
mover->speed.y = -100;
m_jump_timer -= Time::delta;
if (!input_jump.down())
m_jump_timer = 0;
}
}
} }

View File

@ -9,15 +9,21 @@ namespace TL
class Player : public Component class Player : public Component
{ {
public: public:
static constexpr int st_normal = 0;
static constexpr int st_attack = 1;
VirtualStick input_move; VirtualStick input_move;
VirtualButton input_jump; VirtualButton input_jump;
VirtualButton input_attack;
Player(); Player();
void update() override; void update() override;
private: private:
int facing = 1; int m_state = st_normal;
int m_facing = 1;
float m_jump_timer = 0; float m_jump_timer = 0;
float m_attack_timer = 0;
bool m_on_ground; bool m_on_ground;
}; };
} }

View File

@ -52,10 +52,12 @@ void Tilemap::set_cells(int x, int y, int w, int h, const Subtexture* tex)
void Tilemap::render(Batch& batch) void Tilemap::render(Batch& batch)
{ {
batch.push_matrix(Mat3x2::create_translation(entity()->position));
for (int x = 0; x < m_columns; x ++) for (int x = 0; x < m_columns; x ++)
for (int y = 0; y < m_rows; y ++) for (int y = 0; y < m_rows; y ++)
if (m_grid[x + y * m_columns].texture) 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)); batch.tex(m_grid[x + y * m_columns], Vec2(x * m_tile_width, y * m_tile_height));
} }
batch.pop_matrix();
} }

View File

@ -4,10 +4,16 @@
#include "assets/tileset.h" #include "assets/tileset.h"
#include "components/collider.h" #include "components/collider.h"
#include "components/tilemap.h" #include "components/tilemap.h"
#include "components/player.h"
#include "factory.h" #include "factory.h"
using namespace TL; using namespace TL;
namespace
{
constexpr float transition_duration = 0.75f;
}
void Game::startup() void Game::startup()
{ {
// load our content // load our content
@ -21,6 +27,8 @@ void Game::startup()
m_draw_colliders = false; m_draw_colliders = false;
// camera setup
camera = Vec2::zero;
load_room(Point(0, 0)); load_room(Point(0, 0));
} }
@ -30,14 +38,16 @@ void Game::load_room(Point cell)
BLAH_ASSERT(grid, "Room doesn't exist!"); BLAH_ASSERT(grid, "Room doesn't exist!");
room = cell; room = cell;
// destroy all the entities // get room offset
world.clear(); auto offset = Point(cell.x * width, cell.y * height);
// get the castle tileset for now // get the castle tileset for now
auto castle = Content::find_tileset("castle"); auto castle = Content::find_tileset("castle");
auto grass = Content::find_tileset("grass");
auto plants = Content::find_tileset("plants");
// make the floor // make the floor
auto floor = world.add_entity(); auto floor = world.add_entity(offset);
auto tilemap = floor->add(Tilemap(8, 8, columns, rows)); auto tilemap = floor->add(Tilemap(8, 8, columns, rows));
auto solids = floor->add(Collider::make_grid(8, 40, 23)); auto solids = floor->add(Collider::make_grid(8, 40, 23));
solids->mask = Mask::solid; solids->mask = Mask::solid;
@ -46,6 +56,7 @@ void Game::load_room(Point cell)
for (int x = 0; x < columns; x ++) for (int x = 0; x < columns; x ++)
for (int y = 0; y < rows; y++) for (int y = 0; y < rows; y++)
{ {
Point world_position = offset + Point(x * tile_width, y * tile_height);
Color col = grid->pixels[x + y * columns]; Color col = grid->pixels[x + y * columns];
uint32_t rgb = uint32_t rgb =
((uint32_t)col.r << 16) | ((uint32_t)col.r << 16) |
@ -58,15 +69,27 @@ void Game::load_room(Point cell)
case 0x000000: case 0x000000:
break; break;
// solids // castle tiles
case 0xffffff: case 0xffffff:
tilemap->set_cell(x, y, &castle->random_tile()); tilemap->set_cell(x, y, &castle->random_tile());
solids->set_cell(x, y, true); solids->set_cell(x, y, true);
break; break;
// player // grass tiles
case 0x8f974a:
tilemap->set_cell(x, y, &grass->random_tile());
solids->set_cell(x, y, true);
break;
// plants tiles
case 0x4b692f:
tilemap->set_cell(x, y, &plants->random_tile());
break;
// player (only if it doesn't already exist)
case 0x6abe30: case 0x6abe30:
Factory::player(&world, Point(x * tile_width + tile_width / 2, (y + 1) * tile_height)); if (!world.first<Player>())
Factory::player(&world, world_position + Point(tile_width / 2, tile_height));
break; break;
} }
} }
@ -79,12 +102,87 @@ void Game::shutdown()
void Game::update() void Game::update()
{ {
// Toggle Collider Render
if (Input::pressed(Key::F1)) if (Input::pressed(Key::F1))
m_draw_colliders = !m_draw_colliders; m_draw_colliders = !m_draw_colliders;
if (Input::pressed(Key::F2))
load_room(room);
// Reload Current Room
if (Input::pressed(Key::F2))
{
m_transition = false;
world.clear();
load_room(room);
}
// Normal Update
if (!m_transition)
{
world.update(); world.update();
auto player = world.first<Player>();
if (player)
{
auto pos = player->entity()->position;
auto bounds = RectI(room.x * width, room.y * height, width, height);
if (!bounds.contains(pos))
{
// target room
Point next_room = Point(pos.x / width, pos.y / height);
if (pos.x < 0) next_room.x--;
if (pos.y < 0) next_room.y--;
// see if room exists
if (Content::find_room(next_room))
{
// transiton to it!
m_transition = true;
m_next_ease = 0;
m_next_room = next_room;
m_last_room = room;
// store entities from the previous room
m_last_entities.clear();
Entity* e = world.first_entity();
while (e)
{
m_last_entities.push_back(e);
e = e->next();
}
// load contents of the next room
load_room(next_room);
}
// doesn't exist, clamp player
else
{
player->entity()->position = Point(
Calc::clamp_int(pos.x, bounds.x, bounds.x + bounds.w),
Calc::clamp_int(pos.y, bounds.y, bounds.y + bounds.h));
}
}
}
}
// Room Transition routine
else
{
auto last_cam = Vec2(m_last_room.x * width, m_last_room.y * height);
auto next_cam = Vec2(m_next_room.x * width, m_next_room.y * height);
m_next_ease = Calc::approach(m_next_ease, 1.0f, Time::delta / transition_duration);
camera = last_cam + (next_cam - last_cam) * Ease::cube_in_out(m_next_ease);
if (m_next_ease >= 1.0f)
{
// delete old objects (except player!)
for (auto& it : m_last_entities)
{
if (!it->get<Player>())
world.destroy_entity(it);
}
m_transition = false;
}
}
} }
void Game::render() void Game::render()
@ -93,6 +191,7 @@ void Game::render()
{ {
buffer->clear(0x150e22); buffer->clear(0x150e22);
batch.push_matrix(Mat3x2::create_translation(-camera));
world.render(batch); world.render(batch);
if (m_draw_colliders) if (m_draw_colliders)
@ -105,6 +204,7 @@ void Game::render()
} }
} }
batch.pop_matrix();
batch.render(buffer); batch.render(buffer);
batch.clear(); batch.clear();
} }

View File

@ -20,6 +20,7 @@ namespace TL
FrameBufferRef buffer; FrameBufferRef buffer;
Batch batch; Batch batch;
Point room; Point room;
Vec2 camera;
void load_room(Point cell); void load_room(Point cell);
void startup(); void startup();
@ -29,5 +30,10 @@ namespace TL
private: private:
bool m_draw_colliders; bool m_draw_colliders;
bool m_transition = false;
float m_next_ease;
Point m_next_room;
Point m_last_room;
Vector<Entity*> m_last_entities;
}; };
} }