diff --git a/content/map/0x0.png b/content/map/0x0.png
index fa32c71..bfdb1ad 100644
Binary files a/content/map/0x0.png and b/content/map/0x0.png differ
diff --git a/content/map/1x0.png b/content/map/1x0.png
new file mode 100644
index 0000000..d71c89f
Binary files /dev/null and b/content/map/1x0.png differ
diff --git a/content/sprites/player.ase b/content/sprites/player.ase
index 2ebbb89..15baa48 100644
Binary files a/content/sprites/player.ase and b/content/sprites/player.ase differ
diff --git a/content/tilesets/castle.ase b/content/tilesets/castle.ase
index 767066b..6fcbbb8 100644
Binary files a/content/tilesets/castle.ase and b/content/tilesets/castle.ase differ
diff --git a/content/tilesets/grass.ase b/content/tilesets/grass.ase
new file mode 100644
index 0000000..9c5c998
Binary files /dev/null and b/content/tilesets/grass.ase differ
diff --git a/content/tilesets/plants.ase b/content/tilesets/plants.ase
new file mode 100644
index 0000000..53ac464
Binary files /dev/null and b/content/tilesets/plants.ase differ
diff --git a/src/assets/sprite.cpp b/src/assets/sprite.cpp
index e69de29..6f76a13 100644
--- a/src/assets/sprite.cpp
+++ b/src/assets/sprite.cpp
@@ -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;
+}
diff --git a/src/assets/sprite.h b/src/assets/sprite.h
index e9c4e75..6ebd967 100644
--- a/src/assets/sprite.h
+++ b/src/assets/sprite.h
@@ -17,10 +17,20 @@ namespace TL
{
String name;
Vector frames;
+
+ float duration() const
+ {
+ float d = 0;
+ for (auto& it : frames)
+ d += it.duration;
+ return d;
+ }
};
String name;
Vec2 origin;
Vector animations;
+
+ const Animation* get_animation(const String& name) const;
};
}
\ No newline at end of file
diff --git a/src/components/animator.cpp b/src/components/animator.cpp
index 92f198a..ba2386b 100644
--- a/src/components/animator.cpp
+++ b/src/components/animator.cpp
@@ -9,7 +9,12 @@ Animator::Animator(const String& sprite)
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!");
@@ -17,8 +22,13 @@ void Animator::play(const String& animation)
{
if (m_sprite->animations[i].name == animation)
{
- m_animation_index = i;
- m_frame_index = 0;
+ if (m_animation_index != i || restart)
+ {
+ m_animation_index = i;
+ m_frame_index = 0;
+ m_frame_counter = 0;
+ }
+
break;
}
}
diff --git a/src/components/animator.h b/src/components/animator.h
index c0515d3..007a34d 100644
--- a/src/components/animator.h
+++ b/src/components/animator.h
@@ -21,8 +21,8 @@ namespace TL
Animator() = default;
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 render(Batch& batch) override;
diff --git a/src/components/player.cpp b/src/components/player.cpp
index b460e12..2bfe552 100644
--- a/src/components/player.cpp
+++ b/src/components/player.cpp
@@ -27,12 +27,18 @@ Player::Player()
.press_buffer(0.15f)
.add_key(Key::X)
.add_button(0, Button::A);
+
+ input_attack = VirtualButton()
+ .press_buffer(0.15f)
+ .add_key(Key::C)
+ .add_button(0, Button::X);
}
void Player::update()
{
input_move.update();
input_jump.update();
+ input_attack.update();
auto mover = get();
auto anim = get();
@@ -44,37 +50,99 @@ void Player::update()
{
// land squish
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
- 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 m_facing
+ anim->scale.x = Calc::abs(anim->scale.x) * m_facing;
- // set facing
- anim->scale.x = Calc::abs(anim->scale.x) * facing;
}
- // Horizontal Movement
+ // NORMAL STATE
+ if (m_state == st_normal)
{
- // Acceleration
- mover->speed.x += input * (m_on_ground ? ground_accel : air_accel) * Time::delta;
-
- // Maxspeed
- auto maxspd = (m_on_ground ? max_ground_speed : max_air_speed);
- if (Calc::abs(mover->speed.x) > maxspd)
+ // Current Animation
+ if (m_on_ground)
{
- mover->speed.x = Calc::approach(
- mover->speed.x,
- Calc::sign(mover->speed.x) * maxspd,
- 2000 * Time::delta);
+ if (input != 0)
+ anim->play("run");
+ else
+ anim->play("idle");
+ }
+ else
+ {
+ anim->play("jump");
}
- // Friction
- if (input == 0 && m_on_ground)
- mover->speed.x = Calc::approach(mover->speed.x, 0, friction * Time::delta);
+ // Horizontal Movement
+ {
+ // Acceleration
+ mover->speed.x += input * (m_on_ground ? ground_accel : air_accel) * Time::delta;
- // Facing Direction
- if (input != 0 && m_on_ground)
- facing = input;
+ // Maxspeed
+ auto maxspd = (m_on_ground ? max_ground_speed : max_air_speed);
+ if (Calc::abs(mover->speed.x) > maxspd)
+ {
+ mover->speed.x = Calc::approach(
+ mover->speed.x,
+ Calc::sign(mover->speed.x) * maxspd,
+ 2000 * Time::delta);
+ }
+
+ // Friction
+ if (input == 0 && m_on_ground)
+ mover->speed.x = Calc::approach(mover->speed.x, 0, friction * Time::delta);
+
+ // Facing Direction
+ if (input != 0 && m_on_ground)
+ 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
@@ -86,22 +154,4 @@ void Player::update()
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;
- }
- }
}
diff --git a/src/components/player.h b/src/components/player.h
index c66bbd6..bcc3cc7 100644
--- a/src/components/player.h
+++ b/src/components/player.h
@@ -9,15 +9,21 @@ namespace TL
class Player : public Component
{
public:
+ static constexpr int st_normal = 0;
+ static constexpr int st_attack = 1;
+
VirtualStick input_move;
VirtualButton input_jump;
+ VirtualButton input_attack;
Player();
void update() override;
private:
- int facing = 1;
+ int m_state = st_normal;
+ int m_facing = 1;
float m_jump_timer = 0;
+ float m_attack_timer = 0;
bool m_on_ground;
};
}
\ No newline at end of file
diff --git a/src/components/tilemap.cpp b/src/components/tilemap.cpp
index 276ab62..289410c 100644
--- a/src/components/tilemap.cpp
+++ b/src/components/tilemap.cpp
@@ -52,10 +52,12 @@ void Tilemap::set_cells(int x, int y, int w, int h, const Subtexture* tex)
void Tilemap::render(Batch& batch)
{
+ batch.push_matrix(Mat3x2::create_translation(entity()->position));
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));
}
+ batch.pop_matrix();
}
diff --git a/src/game.cpp b/src/game.cpp
index 83a676c..71d35cb 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -4,10 +4,16 @@
#include "assets/tileset.h"
#include "components/collider.h"
#include "components/tilemap.h"
+#include "components/player.h"
#include "factory.h"
using namespace TL;
+namespace
+{
+ constexpr float transition_duration = 0.75f;
+}
+
void Game::startup()
{
// load our content
@@ -21,6 +27,8 @@ void Game::startup()
m_draw_colliders = false;
+ // camera setup
+ camera = Vec2::zero;
load_room(Point(0, 0));
}
@@ -30,14 +38,16 @@ void Game::load_room(Point cell)
BLAH_ASSERT(grid, "Room doesn't exist!");
room = cell;
- // destroy all the entities
- world.clear();
+ // get room offset
+ auto offset = Point(cell.x * width, cell.y * height);
// get the castle tileset for now
auto castle = Content::find_tileset("castle");
+ auto grass = Content::find_tileset("grass");
+ auto plants = Content::find_tileset("plants");
// make the floor
- auto floor = world.add_entity();
+ auto floor = world.add_entity(offset);
auto tilemap = floor->add(Tilemap(8, 8, columns, rows));
auto solids = floor->add(Collider::make_grid(8, 40, 23));
solids->mask = Mask::solid;
@@ -46,6 +56,7 @@ void Game::load_room(Point cell)
for (int x = 0; x < columns; x ++)
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];
uint32_t rgb =
((uint32_t)col.r << 16) |
@@ -58,15 +69,27 @@ void Game::load_room(Point cell)
case 0x000000:
break;
- // solids
+ // castle tiles
case 0xffffff:
tilemap->set_cell(x, y, &castle->random_tile());
solids->set_cell(x, y, true);
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:
- Factory::player(&world, Point(x * tile_width + tile_width / 2, (y + 1) * tile_height));
+ if (!world.first())
+ Factory::player(&world, world_position + Point(tile_width / 2, tile_height));
break;
}
}
@@ -79,12 +102,87 @@ void Game::shutdown()
void Game::update()
{
+ // Toggle Collider Render
if (Input::pressed(Key::F1))
m_draw_colliders = !m_draw_colliders;
- if (Input::pressed(Key::F2))
- load_room(room);
- world.update();
+ // Reload Current Room
+ if (Input::pressed(Key::F2))
+ {
+ m_transition = false;
+ world.clear();
+ load_room(room);
+ }
+
+ // Normal Update
+ if (!m_transition)
+ {
+ world.update();
+
+ auto player = world.first();
+ 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())
+ world.destroy_entity(it);
+ }
+
+ m_transition = false;
+ }
+ }
}
void Game::render()
@@ -93,6 +191,7 @@ void Game::render()
{
buffer->clear(0x150e22);
+ batch.push_matrix(Mat3x2::create_translation(-camera));
world.render(batch);
if (m_draw_colliders)
@@ -105,6 +204,7 @@ void Game::render()
}
}
+ batch.pop_matrix();
batch.render(buffer);
batch.clear();
}
diff --git a/src/game.h b/src/game.h
index af06765..6df38a2 100644
--- a/src/game.h
+++ b/src/game.h
@@ -20,6 +20,7 @@ namespace TL
FrameBufferRef buffer;
Batch batch;
Point room;
+ Vec2 camera;
void load_room(Point cell);
void startup();
@@ -29,5 +30,10 @@ namespace TL
private:
bool m_draw_colliders;
+ bool m_transition = false;
+ float m_next_ease;
+ Point m_next_room;
+ Point m_last_room;
+ Vector m_last_entities;
};
}
\ No newline at end of file