diff --git a/CMakeLists.txt b/CMakeLists.txt index 18d94bc..1a1b1b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,8 +17,13 @@ add_executable(game src/game.cpp src/content.h src/content.cpp + src/masks.h + src/factory.h + src/factory.cpp src/assets/sprite.h src/assets/sprite.cpp + src/assets/tileset.h + src/assets/tileset.cpp src/components/animator.h src/components/animator.cpp src/components/collider.h @@ -27,10 +32,14 @@ add_executable(game src/components/player.cpp src/components/mover.h src/components/mover.cpp - 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" "src/components/hurtable.h" "src/components/hurtable.cpp" "src/components/timer.h" "src/components/timer.cpp") + src/components/tilemap.h + src/components/tilemap.cpp + src/components/hurtable.h + src/components/hurtable.cpp + src/components/timer.h + src/components/timer.cpp + src/components/enemy.h +) # Reference blah target_link_libraries(game blah) diff --git a/content/map/10x0.png b/content/map/10x0.png new file mode 100644 index 0000000..66309ef Binary files /dev/null and b/content/map/10x0.png differ diff --git a/content/map/4x1.png b/content/map/4x1.png index e7fb624..a4bee13 100644 Binary files a/content/map/4x1.png and b/content/map/4x1.png differ diff --git a/content/map/5x1.png b/content/map/5x1.png index a625ce5..34fd711 100644 Binary files a/content/map/5x1.png and b/content/map/5x1.png differ diff --git a/content/map/6x1.png b/content/map/6x1.png new file mode 100644 index 0000000..3e36f98 Binary files /dev/null and b/content/map/6x1.png differ diff --git a/content/map/7x1.png b/content/map/7x1.png new file mode 100644 index 0000000..2442c17 Binary files /dev/null and b/content/map/7x1.png differ diff --git a/content/map/8x0.png b/content/map/8x0.png new file mode 100644 index 0000000..ec82f2f Binary files /dev/null and b/content/map/8x0.png differ diff --git a/content/map/8x1.png b/content/map/8x1.png new file mode 100644 index 0000000..03ddca3 Binary files /dev/null and b/content/map/8x1.png differ diff --git a/content/map/9x0.png b/content/map/9x0.png new file mode 100644 index 0000000..88c901e Binary files /dev/null and b/content/map/9x0.png differ diff --git a/content/sprites/blob.ase b/content/sprites/blob.ase new file mode 100644 index 0000000..a508084 Binary files /dev/null and b/content/sprites/blob.ase differ diff --git a/content/sprites/door.ase b/content/sprites/door.ase new file mode 100644 index 0000000..c5f9092 Binary files /dev/null and b/content/sprites/door.ase differ diff --git a/content/sprites/heart.ase b/content/sprites/heart.ase new file mode 100644 index 0000000..a47a7e5 Binary files /dev/null and b/content/sprites/heart.ase differ diff --git a/content/sprites/player.ase b/content/sprites/player.ase index 170ea83..0bf1e76 100644 Binary files a/content/sprites/player.ase and b/content/sprites/player.ase differ diff --git a/content/tilesets/grass.ase b/content/tilesets/grass.ase index 9c5c998..8f66da9 100644 Binary files a/content/tilesets/grass.ase and b/content/tilesets/grass.ase differ diff --git a/content/tilesets/plants.ase b/content/tilesets/plants.ase index 53ac464..e75056a 100644 Binary files a/content/tilesets/plants.ase and b/content/tilesets/plants.ase differ diff --git a/src/components/collider.cpp b/src/components/collider.cpp index fad9cbd..2d708b6 100644 --- a/src/components/collider.cpp +++ b/src/components/collider.cpp @@ -72,15 +72,18 @@ void Collider::set_cells(int x, int y, int w, int h, bool value) bool Collider::check(uint32_t mask, Point offset) const { - auto other = world()->first(); - while (other) + if (world()) { - if (other != this && - (other->mask & mask) == mask && - overlaps(other, offset)) - return true; + auto other = world()->first(); + while (other) + { + if (other != this && + (other->mask & mask) == mask && + overlaps(other, offset)) + return true; - other = (Collider*)other->next(); + other = (Collider*)other->next(); + } } return false; diff --git a/src/components/enemy.h b/src/components/enemy.h new file mode 100644 index 0000000..23c8ff1 --- /dev/null +++ b/src/components/enemy.h @@ -0,0 +1,10 @@ +#pragma once +#include "../world.h" + +namespace TL +{ + class Enemy : public Component + { + + }; +} \ No newline at end of file diff --git a/src/components/hurtable.cpp b/src/components/hurtable.cpp index 243f64c..7f2bcbe 100644 --- a/src/components/hurtable.cpp +++ b/src/components/hurtable.cpp @@ -9,6 +9,7 @@ void Hurtable::update() { if (collider->check(hurt_by)) { + Time::pause_for(0.1f); stun_timer = 0.5f; flicker_timer = 0.5f; on_hurt(this); diff --git a/src/components/mover.cpp b/src/components/mover.cpp index fad527d..6be1b42 100644 --- a/src/components/mover.cpp +++ b/src/components/mover.cpp @@ -87,6 +87,10 @@ bool Mover::on_ground(int dist) const void Mover::update() { + // apply friction maybe + if (friction > 0 && on_ground()) + speed.x = Calc::approach(speed.x, 0, friction * Time::delta); + // apply gravity if (gravity != 0 && (!collider || !collider->check(Mask::solid, Point(0, 1)))) speed.y += gravity * Time::delta; diff --git a/src/components/mover.h b/src/components/mover.h index e3b6735..110c321 100644 --- a/src/components/mover.h +++ b/src/components/mover.h @@ -17,6 +17,7 @@ namespace TL Collider* collider = nullptr; Vec2 speed; float gravity = 0; + float friction = 0; std::function on_hit_x; std::function on_hit_y; diff --git a/src/components/player.cpp b/src/components/player.cpp index 59e525e..65ba487 100644 --- a/src/components/player.cpp +++ b/src/components/player.cpp @@ -68,6 +68,9 @@ void Player::update() // START if (m_state == st_start) { + while (hitbox->check(Mask::solid)) + entity()->position.y++; + anim->play("sword"); m_start_timer -= Time::delta; if (m_start_timer <= 0) diff --git a/src/components/player.h b/src/components/player.h index 3b3e3ed..8141997 100644 --- a/src/components/player.h +++ b/src/components/player.h @@ -14,8 +14,9 @@ namespace TL static constexpr int st_attack = 1; static constexpr int st_hurt = 2; static constexpr int st_start = 3; + static constexpr int max_health = 3; - int health = 3; + int health = max_health; VirtualStick input_move; VirtualButton input_jump; diff --git a/src/factory.cpp b/src/factory.cpp index a4f833b..7bd2a0d 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -6,6 +6,7 @@ #include "components/player.h" #include "components/hurtable.h" #include "components/timer.h" +#include "components/enemy.h" using namespace TL; @@ -17,7 +18,7 @@ Entity* Factory::player(World* world, Point position) anim->play("idle"); anim->depth = -10; - auto hitbox = en->add(Collider::make_rect(RectI(-4, -8, 8, 8))); + auto hitbox = en->add(Collider::make_rect(RectI(-4, -12, 8, 12))); auto mover = en->add(Mover()); mover->collider = hitbox; @@ -42,7 +43,6 @@ Entity* Factory::bramble(World* world, Point position) hurtable->collider = hitbox; hurtable->on_hurt = [](Hurtable* self) { - Time::pause_for(0.1f); pop(self->world(), self->entity()->position + Point(0, -4)); self->entity()->destroy(); }; @@ -69,6 +69,7 @@ Entity* Factory::pop(World* world, Point position) Entity* Factory::spitter(World* world, Point position) { auto en = world->add_entity(position); + en->add(Enemy()); auto anim = en->add(Animator("spitter")); anim->play("idle"); @@ -193,6 +194,7 @@ Entity* Factory::mosquito(World* world, Point position) { auto en = world->add_entity(position); auto mosquito = en->add(MosquitoBehavior()); + en->add(Enemy()); auto anim = en->add(Animator("mosquito")); anim->play("fly"); @@ -211,3 +213,99 @@ Entity* Factory::mosquito(World* world, Point position) return en; } +Entity* Factory::door(World* world, Point position) +{ + auto en = world->add_entity(position); + + auto anim = en->add(Animator("door")); + anim->play("idle"); + anim->depth = -1; + + auto hitbox = en->add(Collider::make_rect(RectI(-6, -16, 12, 16))); + hitbox->mask = Mask::solid; + + // check if all enemies are dead + en->add(Timer(0.25f, [](Timer* self) + { + self->start(0.25f); + if (!self->world()->first()) + { + Factory::pop(self->world(), self->entity()->position + Point(0, -8)); + self->entity()->destroy(); + } + })); + + return en; +} + +Entity* Factory::blob(World* world, Point position) +{ + auto en = world->add_entity(position); + en->add(Enemy()); + + auto anim = en->add(Animator("blob")); + anim->play("idle"); + anim->depth = -5; + + auto hitbox = en->add(Collider::make_rect(RectI(-4, -8, 8, 8))); + hitbox->mask = Mask::enemy; + + auto mover = en->add(Mover()); + mover->collider = hitbox; + mover->gravity = 300; + mover->friction = 400; + mover->on_hit_y = [](Mover* self) + { + self->get()->play("idle"); + self->stop_y(); + }; + + en->add(Timer(2.0f, [](Timer* self) + { + auto mover = self->get(); + if (!mover->on_ground()) + { + self->start(0.05f); + } + else + { + self->get()->play("jump"); + self->start(2.0f); + mover->speed.y = -90; + + auto player = self->world()->first(); + if (player) + { + auto dir = Calc::sign(player->entity()->position.x - self->entity()->position.x); + if (dir == 0) dir = 1; + + self->get()->scale = Vec2(dir, 1); + mover->speed.x = dir * 40; + } + } + })); + + auto hurtable = en->add(Hurtable()); + hurtable->hurt_by = Mask::player_attack; + hurtable->collider = hitbox; + hurtable->on_hurt = [health = 3](Hurtable* self) mutable + { + auto player = self->world()->first(); + if (player) + { + auto mover = self->get(); + auto sign = Calc::sign(self->entity()->position.x - player->entity()->position.x); + mover->speed.x = sign * 120; + } + + health--; + if (health <= 0) + { + pop(self->world(), self->entity()->position + Point(0, -4)); + self->entity()->destroy(); + } + }; + + return en; +} + diff --git a/src/factory.h b/src/factory.h index 8e86303..c221c9a 100644 --- a/src/factory.h +++ b/src/factory.h @@ -14,5 +14,7 @@ namespace TL Entity* spitter(World* world, Point position); Entity* bullet(World* world, Point position, int direction); Entity* mosquito(World* world, Point position); + Entity* door(World* world, Point position); + Entity* blob(World* world, Point position); } } \ No newline at end of file diff --git a/src/game.cpp b/src/game.cpp index 2e7031d..a1e4559 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -5,6 +5,8 @@ #include "components/collider.h" #include "components/tilemap.h" #include "components/player.h" +#include "components/mover.h" +#include "assets/sprite.h" #include "factory.h" using namespace TL; @@ -27,11 +29,11 @@ void Game::startup() m_draw_colliders = false; // load first room - load_room(Point(0, 0)); + load_room(Point(10, 0)); camera = Vec2(room.x * width, room.y * height); } -void Game::load_room(Point cell) +void Game::load_room(Point cell, bool is_reload) { const Image* grid = Content::find_room(cell); BLAH_ASSERT(grid, "Room doesn't exist!"); @@ -94,7 +96,7 @@ void Game::load_room(Point cell) // player (only if it doesn't already exist) case 0x6abe30: if (!world.first()) - Factory::player(&world, world_position); + Factory::player(&world, world_position + (is_reload ? Point(0, -16) : Point::zero)); break; // brambles @@ -111,6 +113,16 @@ void Game::load_room(Point cell) case 0xfbf236: Factory::mosquito(&world, world_position + Point(0, -8)); break; + + // door + case 0x9badb7: + Factory::door(&world, world_position); + break; + + // blob + case 0x3f3f74: + Factory::blob(&world, world_position); + break; } } } @@ -152,7 +164,7 @@ void Game::update() if (pos.y < 0) next_room.y--; // see if room exists - if (Content::find_room(next_room)) + if (player->health > 0 && Content::find_room(next_room)) { Time::pause_for(0.1f); @@ -185,10 +197,24 @@ void Game::update() if (player->entity()->position.y > bounds.y + bounds.h + 64) { world.clear(); - load_room(room); + load_room(room, true); } } } + + // death ... delete everything except the player + // then when they fall out of the screen, we reset + if (player->health <= 0) + { + Entity* e = world.first_entity(); + while (e) + { + auto next = e->next(); + if (!e->get()) + world.destroy_entity(e); + e = next; + } + } } } // Room Transition routine @@ -207,6 +233,14 @@ void Game::update() // Finish Transition if (m_next_ease >= 1.0f) { + // boost player on vertical up rooms + if (m_next_room.y < m_last_room.y) + { + auto player = world.first(); + if (player) + player->get()->speed = Vec2(100, -200); + } + // delete old objects (except player!) for (auto& it : m_last_entities) { @@ -226,9 +260,13 @@ void Game::render() { buffer->clear(0x150e22); + // push camera offset batch.push_matrix(Mat3x2::create_translation(-camera)); + + // draw gameplay objects world.render(batch); + // draw debug colliders if (m_draw_colliders) { auto collider = world.first(); @@ -239,7 +277,31 @@ void Game::render() } } + // end camera offset batch.pop_matrix(); + + // draw the health + auto player = world.first(); + if (player) + { + auto hearts = Content::find_sprite("heart"); + auto full = hearts->get_animation("full"); + auto empty = hearts->get_animation("empty"); + + Point pos = Point(0, height - 16); + batch.rect(Rect(pos.x, pos.y + 7, 40, 4), Color::black); + + for (int i = 0; i < Player::max_health; i++) + { + if (player->health >= i + 1) + batch.tex(full->frames[0].image, pos); + else + batch.tex(empty->frames[0].image, pos); + pos.x += 12; + } + } + + // draw to the gameplay buffer batch.render(buffer); batch.clear(); } diff --git a/src/game.h b/src/game.h index 6df38a2..d6a4c1c 100644 --- a/src/game.h +++ b/src/game.h @@ -22,7 +22,7 @@ namespace TL Point room; Vec2 camera; - void load_room(Point cell); + void load_room(Point cell, bool is_reload = false); void startup(); void shutdown(); void update();