more rooms and enemies!

This commit is contained in:
Noel Berry 2021-01-03 17:03:48 -08:00
parent fa949e1298
commit 36182673ef
21 changed files with 220 additions and 21 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 B

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 280 B

BIN
content/map/2x0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

BIN
content/map/3x0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

BIN
content/map/3x1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

BIN
content/map/4x1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

BIN
content/map/5x1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

BIN
content/sprites/bullet.ase Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
content/sprites/spitter.ase Normal file

Binary file not shown.

BIN
content/tilesets/back.ase Normal file

Binary file not shown.

View File

@ -1,17 +1,29 @@
#include "hurtable.h"
#include "animator.h"
using namespace TL;
void Hurtable::update()
{
if (collider && on_hurt && m_cooldown_timer <= 0)
if (collider && on_hurt && stun_timer <= 0)
{
if (collider->check(hurt_by))
{
m_cooldown_timer = cooldown;
stun_timer = 0.5f;
flicker_timer = 0.5f;
on_hurt(this);
}
}
m_cooldown_timer -= Time::delta;
stun_timer -= Time::delta;
if (flicker_timer > 0)
{
flicker_timer -= Time::delta;
if (Time::on_interval(0.05f))
entity()->visible = !entity()->visible;
if (flicker_timer <= 0)
entity()->visible = true;
}
}

View File

@ -10,13 +10,11 @@ namespace TL
{
class Hurtable : public Component
{
private:
float m_cooldown_timer = 0;
public:
float stun_timer = 0;
float flicker_timer = 0;
Collider* collider = nullptr;
uint32_t hurt_by = 0;
float cooldown = 1.0f;
std::function<void(Hurtable* self)> on_hurt;
void update() override;

View File

@ -13,7 +13,10 @@ bool Mover::move_x(int amount)
{
if (collider->check(Mask::solid, Point(sign, 0)))
{
stop_x();
if (on_hit_x)
on_hit_x(this);
else
stop_x();
return true;
}
@ -37,7 +40,10 @@ bool Mover::move_y(int amount)
{
if (collider->check(Mask::solid, Point(0, sign)))
{
stop_y();
if (on_hit_y)
on_hit_y(this);
else
stop_y();
return true;
}

View File

@ -2,6 +2,7 @@
#include "../world.h"
#include "collider.h"
#include <blah.h>
#include <functional>
using namespace Blah;
@ -16,6 +17,8 @@ namespace TL
Collider* collider = nullptr;
Vec2 speed;
float gravity = 0;
std::function<void(Mover*)> on_hit_x;
std::function<void(Mover*)> on_hit_y;
bool move_x(int amount);
bool move_y(int amount);

View File

@ -65,8 +65,16 @@ void Player::update()
anim->scale.x = Calc::abs(anim->scale.x) * m_facing;
}
// START
if (m_state == st_start)
{
anim->play("sword");
m_start_timer -= Time::delta;
if (m_start_timer <= 0)
m_state = st_normal;
}
// NORMAL STATE
if (m_state == st_normal)
else if (m_state == st_normal)
{
// Current Animation
if (m_on_ground)

View File

@ -13,6 +13,7 @@ namespace TL
static constexpr int st_normal = 0;
static constexpr int st_attack = 1;
static constexpr int st_hurt = 2;
static constexpr int st_start = 3;
int health = 3;
@ -24,12 +25,13 @@ namespace TL
void update() override;
private:
int m_state = st_normal;
int m_state = st_start;
int m_facing = 1;
float m_jump_timer = 0;
float m_attack_timer = 0;
float m_hurt_timer = 0;
float m_invincible_timer = 0;
float m_start_timer = 1;
Collider* m_attack_collider = nullptr;
bool m_on_ground;
};

View File

@ -59,9 +59,154 @@ Entity* Factory::pop(World* world, Point position)
anim->depth = -20;
auto timer = en->add(Timer(anim->animation()->duration(), [](Timer* self)
{
self->entity()->destroy();
}));
{
self->entity()->destroy();
}));
return en;
}
Entity* Factory::spitter(World* world, Point position)
{
auto en = world->add_entity(position);
auto anim = en->add(Animator("spitter"));
anim->play("idle");
anim->depth = -5;
auto hitbox = en->add(Collider::make_rect(RectI(-6, -12, 12, 12)));
hitbox->mask = Mask::enemy;
auto hurtable = en->add(Hurtable());
hurtable->hurt_by = Mask::player_attack;
hurtable->collider = hitbox;
hurtable->on_hurt = [](Hurtable* self) mutable
{
Time::pause_for(0.1f);
pop(self->world(), self->entity()->position + Point(0, -4));
self->entity()->destroy();
};
auto timer = en->add(Timer(1.0f, [](Timer* self)
{
bullet(self->world(), self->entity()->position + Point(-8, -8), -1);
self->get<Animator>()->play("shoot");
self->entity()->add(Timer(0.4f, [](Timer* self) { self->get<Animator>()->play("idle"); }));
self->start(3.0f);
}));
return en;
}
Entity* Factory::bullet(World* world, Point position, int direction)
{
auto en = world->add_entity(position);
auto anim = en->add(Animator("bullet"));
anim->play("idle");
anim->depth = -5;
auto hitbox = en->add(Collider::make_rect(RectI(-4, -4, 8, 8)));
hitbox->mask = Mask::enemy;
auto mover = en->add(Mover());
mover->collider = hitbox;
mover->speed = Vec2(direction * 40, 0);
mover->gravity = 130;
mover->on_hit_x = [](Mover* self) { self->entity()->destroy(); };
mover->on_hit_y = [](Mover* self) { self->speed.y = -60; };
auto hurtable = en->add(Hurtable());
hurtable->hurt_by = Mask::player_attack;
hurtable->collider = hitbox;
hurtable->on_hurt = [](Hurtable* self) mutable
{
Time::pause_for(0.1f);
pop(self->world(), self->entity()->position + Point(0, -4));
self->entity()->destroy();
};
en->add(Timer(2.5f, [](Timer* self)
{
self->get<Hurtable>()->flicker_timer = 100;
}));
en->add(Timer(3.0f, [](Timer* self)
{
self->entity()->destroy();
}));
return en;
}
namespace
{
class MosquitoBehavior : public Component
{
public:
int health = 2;
float timer = 0;
void update() override
{
auto mover = get<Mover>();
auto player = world()->first<Player>();
if (player)
{
auto diff = player->entity()->position.x - entity()->position.x;
auto dist = Calc::abs(diff);
if (dist < 100)
mover->speed.x += Calc::sign(diff) * 100 * Time::delta;
else
mover->speed.x = Calc::approach(mover->speed.x, 0, 100 * Time::delta);
if (Calc::abs(mover->speed.x) > 50)
mover->speed.x = Calc::approach(mover->speed.x, Calc::sign(mover->speed.x) * 50, 800 * Time::delta);
mover->speed.y = Calc::sin(timer) * 10;
}
timer += Time::delta * 4;
}
void hurt()
{
health--;
if (health <= 0)
{
Factory::pop(world(), entity()->position);
entity()->destroy();
}
else
{
auto mover = get<Mover>();
auto player = world()->first<Player>();
auto sign = Calc::sign(player->entity()->position.x - entity()->position.x);
mover->speed.x = -sign * 140;
}
}
};
}
Entity* Factory::mosquito(World* world, Point position)
{
auto en = world->add_entity(position);
auto mosquito = en->add(MosquitoBehavior());
auto anim = en->add(Animator("mosquito"));
anim->play("fly");
anim->depth = -5;
auto hitbox = en->add(Collider::make_rect(RectI(-4, -4, 8, 8)));
hitbox->mask = Mask::enemy;
auto mover = en->add(Mover());
auto hurtable = en->add(Hurtable());
hurtable->hurt_by = Mask::player_attack;
hurtable->collider = hitbox;
hurtable->on_hurt = [](Hurtable* self) { self->get<MosquitoBehavior>()->hurt(); };
return en;
}

View File

@ -11,5 +11,8 @@ namespace TL
Entity* player(World* world, Point position);
Entity* bramble(World* world, Point position);
Entity* pop(World* world, Point position);
Entity* spitter(World* world, Point position);
Entity* bullet(World* world, Point position, int direction);
Entity* mosquito(World* world, Point position);
}
}

View File

@ -24,12 +24,11 @@ void Game::startup()
// set batcher to use Nearest Filter
batch.default_sampler = TextureSampler(TextureFilter::Nearest);
m_draw_colliders = false;
// camera setup
camera = Vec2::zero;
// load first room
load_room(Point(0, 0));
camera = Vec2(room.x * width, room.y * height);
}
void Game::load_room(Point cell)
@ -45,6 +44,7 @@ void Game::load_room(Point cell)
auto castle = Content::find_tileset("castle");
auto grass = Content::find_tileset("grass");
auto plants = Content::find_tileset("plants");
auto backs = Content::find_tileset("back");
// make the floor
auto floor = world.add_entity(offset);
@ -56,7 +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);
Point world_position = offset + Point(x * tile_width, y * tile_height) + Point(tile_width / 2, tile_height);
Color col = grid->pixels[x + y * columns];
uint32_t rgb =
((uint32_t)col.r << 16) |
@ -86,15 +86,30 @@ void Game::load_room(Point cell)
tilemap->set_cell(x, y, &plants->random_tile());
break;
// back tiles
case 0x45283c:
tilemap->set_cell(x, y, &backs->random_tile());
break;
// player (only if it doesn't already exist)
case 0x6abe30:
if (!world.first<Player>())
Factory::player(&world, world_position + Point(tile_width / 2, tile_height));
Factory::player(&world, world_position);
break;
// brambles
case 0xd77bba:
Factory::bramble(&world, world_position + Point(tile_width / 2, tile_height));
Factory::bramble(&world, world_position);
break;
// spitter plant
case 0xac3232:
Factory::spitter(&world, world_position);
break;
// mosquito
case 0xfbf236:
Factory::mosquito(&world, world_position + Point(0, -8));
break;
}
}
@ -164,7 +179,14 @@ void Game::update()
{
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));
Calc::clamp_int(pos.y, bounds.y, bounds.y + bounds.h + 100));
// reload if they fell out the bottom
if (player->entity()->position.y > bounds.y + bounds.h + 64)
{
world.clear();
load_room(room);
}
}
}
}