mirror of
https://github.com/NoelFB/tiny_link.git
synced 2024-11-25 18:18:56 +08:00
boss!!!
This commit is contained in:
parent
0d01334e0a
commit
f721b86bb9
|
@ -39,7 +39,7 @@ add_executable(game
|
||||||
src/components/timer.h
|
src/components/timer.h
|
||||||
src/components/timer.cpp
|
src/components/timer.cpp
|
||||||
src/components/enemy.h
|
src/components/enemy.h
|
||||||
)
|
"src/components/ghost_frog.h" "src/components/ghost_frog.cpp" "src/components/orb.h" "src/components/orb.cpp")
|
||||||
|
|
||||||
# Reference blah
|
# Reference blah
|
||||||
target_link_libraries(game blah)
|
target_link_libraries(game blah)
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 243 B After Width: | Height: | Size: 243 B |
BIN
content/sprites/ghostfrog.ase
Normal file
BIN
content/sprites/ghostfrog.ase
Normal file
Binary file not shown.
|
@ -72,7 +72,7 @@ void Animator::render(Batch& batch)
|
||||||
if (in_valid_state())
|
if (in_valid_state())
|
||||||
{
|
{
|
||||||
batch.push_matrix(
|
batch.push_matrix(
|
||||||
Mat3x2::create_transform(entity()->position, m_sprite->origin, scale, 0));
|
Mat3x2::create_transform(entity()->position + offset, m_sprite->origin, scale, 0));
|
||||||
|
|
||||||
auto& anim = m_sprite->animations[m_animation_index];
|
auto& anim = m_sprite->animations[m_animation_index];
|
||||||
auto& frame = anim.frames[m_frame_index];
|
auto& frame = anim.frames[m_frame_index];
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace TL
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Vec2 scale = Vec2::one;
|
Vec2 scale = Vec2::one;
|
||||||
|
Point offset = Point::zero;
|
||||||
|
|
||||||
Animator() = default;
|
Animator() = default;
|
||||||
Animator(const String& sprite);
|
Animator(const String& sprite);
|
||||||
|
|
|
@ -71,6 +71,11 @@ void Collider::set_cells(int x, int y, int w, int h, bool value)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Collider::check(uint32_t mask, Point offset) const
|
bool Collider::check(uint32_t mask, Point offset) const
|
||||||
|
{
|
||||||
|
return first(mask, offset) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Collider* Collider::first(uint32_t mask, Point offset)
|
||||||
{
|
{
|
||||||
if (world())
|
if (world())
|
||||||
{
|
{
|
||||||
|
@ -80,13 +85,32 @@ bool Collider::check(uint32_t mask, Point offset) const
|
||||||
if (other != this &&
|
if (other != this &&
|
||||||
(other->mask & mask) == mask &&
|
(other->mask & mask) == mask &&
|
||||||
overlaps(other, offset))
|
overlaps(other, offset))
|
||||||
return true;
|
return other;
|
||||||
|
|
||||||
other = (Collider*)other->next();
|
other = (Collider*)other->next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Collider* Collider::first(uint32_t mask, Point offset) const
|
||||||
|
{
|
||||||
|
if (world())
|
||||||
|
{
|
||||||
|
auto other = world()->first<Collider>();
|
||||||
|
while (other)
|
||||||
|
{
|
||||||
|
if (other != this &&
|
||||||
|
(other->mask & mask) == mask &&
|
||||||
|
overlaps(other, offset))
|
||||||
|
return other;
|
||||||
|
|
||||||
|
other = (Collider*)other->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Collider::overlaps(const Collider* other, Point offset) const
|
bool Collider::overlaps(const Collider* other, Point offset) const
|
||||||
|
|
|
@ -31,6 +31,8 @@ namespace TL
|
||||||
void set_cell(int x, int y, bool value);
|
void set_cell(int x, int y, bool value);
|
||||||
void set_cells(int x, int y, int w, int h, bool value);
|
void set_cells(int x, int y, int w, int h, bool value);
|
||||||
|
|
||||||
|
Collider* first(uint32_t mask, Point offset = Point::zero);
|
||||||
|
const Collider* first(uint32_t mask, Point offset = Point::zero) const;
|
||||||
bool check(uint32_t mask, Point offset = Point::zero) const;
|
bool check(uint32_t mask, Point offset = Point::zero) const;
|
||||||
bool overlaps(const Collider* other, Point offset = Point::zero) const;
|
bool overlaps(const Collider* other, Point offset = Point::zero) const;
|
||||||
|
|
||||||
|
|
268
src/components/ghost_frog.cpp
Normal file
268
src/components/ghost_frog.cpp
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
#include "ghost_frog.h"
|
||||||
|
#include "mover.h"
|
||||||
|
#include "hurtable.h"
|
||||||
|
#include "player.h"
|
||||||
|
#include "animator.h"
|
||||||
|
#include "orb.h"
|
||||||
|
#include "../masks.h"
|
||||||
|
#include "../factory.h"
|
||||||
|
|
||||||
|
using namespace TL;
|
||||||
|
|
||||||
|
GhostFrog::GhostFrog()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GhostFrog::awake()
|
||||||
|
{
|
||||||
|
m_home = entity()->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GhostFrog::update()
|
||||||
|
{
|
||||||
|
m_timer += Time::delta;
|
||||||
|
|
||||||
|
auto player = world()->first<Player>();
|
||||||
|
auto mover = get<Mover>();
|
||||||
|
auto anim = get<Animator>();
|
||||||
|
auto hitbox = get<Collider>();
|
||||||
|
|
||||||
|
// no player - turn off AI
|
||||||
|
if (!player)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto x = entity()->position.x;
|
||||||
|
auto y = entity()->position.y;
|
||||||
|
auto player_x = player->entity()->position.x;
|
||||||
|
|
||||||
|
// update sprite
|
||||||
|
if (mover->on_ground())
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// flip sprite
|
||||||
|
anim->scale = Vec2(m_facing, 1);
|
||||||
|
|
||||||
|
// NORMAL STATE
|
||||||
|
if (m_state == st_readying_attack)
|
||||||
|
{
|
||||||
|
m_facing = Calc::sign(player_x - x);
|
||||||
|
if (m_facing == 0)
|
||||||
|
m_facing = 1;
|
||||||
|
|
||||||
|
float target_x = player_x + 32 * -m_facing;
|
||||||
|
mover->speed.x = Calc::approach(mover->speed.x, Calc::sign(target_x - x) * 40, 400 * Time::delta);
|
||||||
|
mover->friction = 100;
|
||||||
|
anim->play("run");
|
||||||
|
|
||||||
|
if (m_timer > 3.0f ||
|
||||||
|
(m_timer > 1.0f && hitbox->check(Mask::solid, Point(-m_facing * 8, 0))))
|
||||||
|
{
|
||||||
|
mover->speed.x = 0;
|
||||||
|
set_state(st_perform_slash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// SLASH STATE
|
||||||
|
else if (m_state == st_perform_slash)
|
||||||
|
{
|
||||||
|
// start attack anim
|
||||||
|
anim->play("attack");
|
||||||
|
mover->friction = 500;
|
||||||
|
|
||||||
|
// after 0.8s, do the lunge
|
||||||
|
if (Time::on_time(m_timer, 0.8f))
|
||||||
|
{
|
||||||
|
mover->speed.x = m_facing * 250;
|
||||||
|
hitbox->set_rect(RectI(-4 + m_facing * 4, -12, 8, 12));
|
||||||
|
|
||||||
|
RectI rect(8, -8, 20, 8);
|
||||||
|
if (m_facing < 0)
|
||||||
|
rect.x = -(rect.x + rect.w);
|
||||||
|
|
||||||
|
if (m_attack_collider)
|
||||||
|
m_attack_collider->destroy();
|
||||||
|
m_attack_collider = entity()->add(Collider::make_rect(rect));
|
||||||
|
m_attack_collider->mask = Mask::enemy;
|
||||||
|
}
|
||||||
|
// turn off attack collider
|
||||||
|
else if (Time::on_time(m_timer, anim->animation()->duration() - 1.0f))
|
||||||
|
{
|
||||||
|
if (m_attack_collider)
|
||||||
|
m_attack_collider->destroy();
|
||||||
|
m_attack_collider = nullptr;
|
||||||
|
}
|
||||||
|
// end attack state
|
||||||
|
else if (m_timer >= anim->animation()->duration())
|
||||||
|
{
|
||||||
|
hitbox->set_rect(RectI(-4, -12, 8, 12));
|
||||||
|
|
||||||
|
if (health > 0)
|
||||||
|
{
|
||||||
|
set_state(st_readying_attack);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
phase = 1;
|
||||||
|
health = max_health_2;
|
||||||
|
m_side = Calc::rand_int(0, 2) == 0 ? -1 : 1;
|
||||||
|
set_state(st_floating);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FLOATING STATE
|
||||||
|
else if (m_state == st_floating)
|
||||||
|
{
|
||||||
|
anim->play("float");
|
||||||
|
|
||||||
|
mover->friction = 0;
|
||||||
|
mover->collider = nullptr;
|
||||||
|
|
||||||
|
float target_y = m_home.y - 50;
|
||||||
|
float target_x = m_home.x + m_side * 50;
|
||||||
|
|
||||||
|
if (Calc::sign(target_y - y) != Calc::sign(target_y - m_last_pos.y))
|
||||||
|
{
|
||||||
|
mover->speed.y = 0;
|
||||||
|
entity()->position.y = target_y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mover->speed.y = Calc::approach(mover->speed.y, Calc::sign(target_y - y) * 50, 800 * Time::delta);
|
||||||
|
|
||||||
|
if (Calc::abs(y - target_y) < 8)
|
||||||
|
mover->speed.x = Calc::approach(mover->speed.x, Calc::sign(target_x - x) * 80, 800 * Time::delta);
|
||||||
|
else
|
||||||
|
mover->speed.x = 0;
|
||||||
|
|
||||||
|
if (m_timer > 5.0f || (Calc::abs(target_x - x) < 8 && Calc::abs(target_y - y) < 8))
|
||||||
|
set_state(st_shoot);
|
||||||
|
}
|
||||||
|
// SHOOTING STATE
|
||||||
|
else if (m_state == st_shoot)
|
||||||
|
{
|
||||||
|
mover->speed = Calc::approach(mover->speed, Vec2::zero, 300 * Time::delta);
|
||||||
|
|
||||||
|
m_facing = Calc::sign(player_x - x);
|
||||||
|
if (m_facing == 0)
|
||||||
|
m_facing = 1;
|
||||||
|
|
||||||
|
if (Time::on_time(m_timer, 1.0f))
|
||||||
|
{
|
||||||
|
anim->play("reflect");
|
||||||
|
}
|
||||||
|
else if (Time::on_time(m_timer, 1.2f))
|
||||||
|
{
|
||||||
|
Factory::orb(world(), entity()->position + Point(m_facing * 12, -8));
|
||||||
|
m_reflect_count = 0;
|
||||||
|
}
|
||||||
|
else if (Time::on_time(m_timer, 1.4f))
|
||||||
|
{
|
||||||
|
anim->play("float");
|
||||||
|
set_state(st_reflect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// REFLECT STATE
|
||||||
|
else if (m_state == st_reflect)
|
||||||
|
{
|
||||||
|
if (Time::on_time(m_timer, 0.4f))
|
||||||
|
anim->play("float");
|
||||||
|
|
||||||
|
auto orb = world()->first<Orb>();
|
||||||
|
if (!orb)
|
||||||
|
{
|
||||||
|
if (m_timer > 1.0f)
|
||||||
|
{
|
||||||
|
m_side = -m_side;
|
||||||
|
set_state(st_floating);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!orb->towards_player)
|
||||||
|
{
|
||||||
|
if (m_reflect_count < 2)
|
||||||
|
{
|
||||||
|
if (Vec2(orb->entity()->position - orb->target()).length() < 16)
|
||||||
|
{
|
||||||
|
anim->play("reflect");
|
||||||
|
orb->on_hit();
|
||||||
|
m_reflect_count++;
|
||||||
|
m_timer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Vec2(orb->entity()->position - orb->target()).length() < 8)
|
||||||
|
{
|
||||||
|
Factory::pop(world(), entity()->position + Point(0, -8));
|
||||||
|
orb->entity()->destroy();
|
||||||
|
on_hurt(nullptr);
|
||||||
|
m_timer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// DEAD STATE
|
||||||
|
else if (m_state == st_dead_state)
|
||||||
|
{
|
||||||
|
anim->play("dead");
|
||||||
|
|
||||||
|
if (Time::on_interval(0.25f))
|
||||||
|
{
|
||||||
|
auto offset = Point(Calc::rand_int(-16, 16), Calc::rand_int(-16, 16));
|
||||||
|
Factory::pop(world(), entity()->position + Point(0, -8) + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Time::on_time(m_timer, 3.0f))
|
||||||
|
{
|
||||||
|
for (int x = -1; x < 2; x ++)
|
||||||
|
for (int y = -1; y < 2; y ++)
|
||||||
|
Factory::pop(world(), entity()->position + Point(x * 12, -8 + y * 12));
|
||||||
|
|
||||||
|
Time::pause_for(0.3f);
|
||||||
|
entity()->destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_state == st_floating || m_state == st_shoot || m_state == st_reflect)
|
||||||
|
{
|
||||||
|
anim->offset.y = Calc::sin(Time::elapsed * 2) * 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_last_pos = entity()->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GhostFrog::on_hurt(Hurtable* hurtable)
|
||||||
|
{
|
||||||
|
if (health > 0)
|
||||||
|
{
|
||||||
|
health--;
|
||||||
|
|
||||||
|
if (health <= 0 && phase > 0)
|
||||||
|
{
|
||||||
|
set_state(st_dead_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_state == st_waiting)
|
||||||
|
{
|
||||||
|
Factory::pop(world(), entity()->position + Point(0, -8));
|
||||||
|
Time::pause_for(0.25f);
|
||||||
|
set_state(st_readying_attack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GhostFrog::on_hit_x(Mover* mover)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GhostFrog::on_hit_y(Mover* mover)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GhostFrog::set_state(int state)
|
||||||
|
{
|
||||||
|
m_state = state;
|
||||||
|
m_timer = 0;
|
||||||
|
}
|
48
src/components/ghost_frog.h
Normal file
48
src/components/ghost_frog.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../world.h"
|
||||||
|
#include <blah.h>
|
||||||
|
|
||||||
|
using namespace Blah;
|
||||||
|
|
||||||
|
namespace TL
|
||||||
|
{
|
||||||
|
class Hurtable;
|
||||||
|
class Mover;
|
||||||
|
class Collider;
|
||||||
|
|
||||||
|
class GhostFrog : public Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr int st_waiting = 0;
|
||||||
|
static constexpr int st_readying_attack = 1;
|
||||||
|
static constexpr int st_perform_slash = 2;
|
||||||
|
static constexpr int st_floating = 3;
|
||||||
|
static constexpr int st_shoot = 4;
|
||||||
|
static constexpr int st_reflect = 5;
|
||||||
|
static constexpr int st_dead_state = 6;
|
||||||
|
|
||||||
|
static constexpr int max_health_1 = 10;
|
||||||
|
static constexpr int max_health_2 = 3;
|
||||||
|
int health = max_health_1;
|
||||||
|
int phase = 0;
|
||||||
|
|
||||||
|
GhostFrog();
|
||||||
|
|
||||||
|
void awake() override;
|
||||||
|
void update() override;
|
||||||
|
void on_hurt(Hurtable* hurtable);
|
||||||
|
void on_hit_x(Mover* mover);
|
||||||
|
void on_hit_y(Mover* mover);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void set_state(int state);
|
||||||
|
float m_timer = 0;
|
||||||
|
int m_state = st_waiting;
|
||||||
|
int m_facing = 1;
|
||||||
|
int m_side = 1;
|
||||||
|
int m_reflect_count = 0;
|
||||||
|
Point m_home;
|
||||||
|
Point m_last_pos;
|
||||||
|
Collider* m_attack_collider = nullptr;
|
||||||
|
};
|
||||||
|
}
|
42
src/components/orb.cpp
Normal file
42
src/components/orb.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include "orb.h"
|
||||||
|
#include "mover.h"
|
||||||
|
#include "hurtable.h"
|
||||||
|
#include "player.h"
|
||||||
|
#include "ghost_frog.h"
|
||||||
|
#include "../masks.h"
|
||||||
|
#include "../factory.h"
|
||||||
|
|
||||||
|
using namespace TL;
|
||||||
|
|
||||||
|
Point Orb::target() const
|
||||||
|
{
|
||||||
|
auto player = world()->first<Player>();
|
||||||
|
auto ghost = world()->first<GhostFrog>();
|
||||||
|
|
||||||
|
if (player && ghost)
|
||||||
|
return (towards_player ? player->entity()->position : ghost->entity()->position) + Point(0, -8);
|
||||||
|
|
||||||
|
return Point(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Orb::update()
|
||||||
|
{
|
||||||
|
auto mover = get<Mover>();
|
||||||
|
auto diff = Vec2(target() - entity()->position).normal();
|
||||||
|
mover->speed = diff * speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Orb::destroyed()
|
||||||
|
{
|
||||||
|
Factory::pop(world(), entity()->position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Orb::on_hit()
|
||||||
|
{
|
||||||
|
towards_player = !towards_player;
|
||||||
|
speed += 40;
|
||||||
|
|
||||||
|
auto hurt = get<Hurtable>();
|
||||||
|
if (towards_player)
|
||||||
|
hurt->stun_timer = 0;
|
||||||
|
}
|
20
src/components/orb.h
Normal file
20
src/components/orb.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../world.h"
|
||||||
|
#include <blah.h>
|
||||||
|
|
||||||
|
using namespace Blah;
|
||||||
|
|
||||||
|
namespace TL
|
||||||
|
{
|
||||||
|
class Orb : public Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float speed = 40;
|
||||||
|
bool towards_player = true;
|
||||||
|
|
||||||
|
Point target() const;
|
||||||
|
void update() override;
|
||||||
|
void destroyed() override;
|
||||||
|
void on_hit();
|
||||||
|
};
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
#include "mover.h"
|
#include "mover.h"
|
||||||
#include "animator.h"
|
#include "animator.h"
|
||||||
#include "collider.h"
|
#include "collider.h"
|
||||||
|
#include "orb.h"
|
||||||
#include "../masks.h"
|
#include "../masks.h"
|
||||||
|
|
||||||
using namespace TL;
|
using namespace TL;
|
||||||
|
@ -220,22 +221,31 @@ void Player::update()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hurt Check!
|
// Hurt Check!
|
||||||
if (m_invincible_timer <= 0 && hitbox->check(Mask::enemy))
|
if (m_invincible_timer <= 0)
|
||||||
{
|
{
|
||||||
Time::pause_for(0.1f);
|
auto hit = hitbox->first(Mask::enemy);
|
||||||
anim->play("hurt");
|
if (hit)
|
||||||
|
|
||||||
if (m_attack_collider)
|
|
||||||
{
|
{
|
||||||
m_attack_collider->destroy();
|
Time::pause_for(0.1f);
|
||||||
m_attack_collider = nullptr;
|
anim->play("hurt");
|
||||||
|
|
||||||
|
if (m_attack_collider)
|
||||||
|
{
|
||||||
|
m_attack_collider->destroy();
|
||||||
|
m_attack_collider = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
mover->speed = Vec2(-m_facing * 100, -80);
|
||||||
|
|
||||||
|
health--;
|
||||||
|
m_hurt_timer = hurt_duration;
|
||||||
|
m_invincible_timer = invincible_duration;
|
||||||
|
m_state = st_hurt;
|
||||||
|
|
||||||
|
// hack:
|
||||||
|
// destroy orb
|
||||||
|
if (hit->get<Orb>())
|
||||||
|
hit->entity()->destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
mover->speed = Vec2(-m_facing * 100, -80);
|
|
||||||
|
|
||||||
health--;
|
|
||||||
m_hurt_timer = hurt_duration;
|
|
||||||
m_invincible_timer = invincible_duration;
|
|
||||||
m_state = st_hurt;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace TL
|
||||||
static constexpr int st_attack = 1;
|
static constexpr int st_attack = 1;
|
||||||
static constexpr int st_hurt = 2;
|
static constexpr int st_hurt = 2;
|
||||||
static constexpr int st_start = 3;
|
static constexpr int st_start = 3;
|
||||||
static constexpr int max_health = 3;
|
static constexpr int max_health = 30;
|
||||||
|
|
||||||
int health = max_health;
|
int health = max_health;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include "components/hurtable.h"
|
#include "components/hurtable.h"
|
||||||
#include "components/timer.h"
|
#include "components/timer.h"
|
||||||
#include "components/enemy.h"
|
#include "components/enemy.h"
|
||||||
|
#include "components/ghost_frog.h"
|
||||||
|
#include "components/orb.h"
|
||||||
|
|
||||||
using namespace TL;
|
using namespace TL;
|
||||||
|
|
||||||
|
@ -19,6 +21,7 @@ Entity* Factory::player(World* world, Point position)
|
||||||
anim->depth = -10;
|
anim->depth = -10;
|
||||||
|
|
||||||
auto hitbox = en->add(Collider::make_rect(RectI(-4, -12, 8, 12)));
|
auto hitbox = en->add(Collider::make_rect(RectI(-4, -12, 8, 12)));
|
||||||
|
hitbox->mask = Mask::player;
|
||||||
|
|
||||||
auto mover = en->add(Mover());
|
auto mover = en->add(Mover());
|
||||||
mover->collider = hitbox;
|
mover->collider = hitbox;
|
||||||
|
@ -334,3 +337,55 @@ Entity* Factory::blob(World* world, Point position)
|
||||||
return en;
|
return en;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Entity* Factory::ghost_frog(World* world, Point position)
|
||||||
|
{
|
||||||
|
auto en = world->add_entity(position);
|
||||||
|
en->add(GhostFrog());
|
||||||
|
en->add(Enemy());
|
||||||
|
|
||||||
|
auto anim = en->add(Animator("ghostfrog"));
|
||||||
|
anim->play("sword");
|
||||||
|
anim->depth = -5;
|
||||||
|
|
||||||
|
auto hitbox = en->add(Collider::make_rect(RectI(-4, -12, 8, 12)));
|
||||||
|
hitbox->mask = Mask::enemy;
|
||||||
|
|
||||||
|
auto mover = en->add(Mover());
|
||||||
|
mover->collider = hitbox;
|
||||||
|
mover->gravity = 0;
|
||||||
|
mover->friction = 100;
|
||||||
|
mover->on_hit_x = [](Mover* self) { self->get<GhostFrog>()->on_hit_x(self); };
|
||||||
|
mover->on_hit_y = [](Mover* self) { self->get<GhostFrog>()->on_hit_y(self); };
|
||||||
|
|
||||||
|
auto hurtable = en->add(Hurtable());
|
||||||
|
hurtable->hurt_by = Mask::player_attack;
|
||||||
|
hurtable->collider = hitbox;
|
||||||
|
hurtable->on_hurt = [](Hurtable* self) { self->get<GhostFrog>()->on_hurt(self); };
|
||||||
|
|
||||||
|
return en;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity* Factory::orb(World* world, Point position)
|
||||||
|
{
|
||||||
|
auto en = world->add_entity(position);
|
||||||
|
en->add(Orb());
|
||||||
|
|
||||||
|
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->on_hit_x = [](Mover* self) { Factory::pop(self->world(), self->entity()->position); self->entity()->destroy(); };
|
||||||
|
mover->on_hit_y = [](Mover* self) { Factory::pop(self->world(), self->entity()->position); self->entity()->destroy(); };
|
||||||
|
|
||||||
|
auto hurtable = en->add(Hurtable());
|
||||||
|
hurtable->hurt_by = Mask::player_attack;
|
||||||
|
hurtable->collider = en->add(Collider::make_rect(RectI(-8, -8, 16, 16)));
|
||||||
|
hurtable->on_hurt = [](Hurtable* self) { self->get<Orb>()->on_hit(); };
|
||||||
|
|
||||||
|
return en;
|
||||||
|
}
|
||||||
|
|
|
@ -16,5 +16,7 @@ namespace TL
|
||||||
Entity* mosquito(World* world, Point position);
|
Entity* mosquito(World* world, Point position);
|
||||||
Entity* door(World* world, Point position, bool wait_for_player = false);
|
Entity* door(World* world, Point position, bool wait_for_player = false);
|
||||||
Entity* blob(World* world, Point position);
|
Entity* blob(World* world, Point position);
|
||||||
|
Entity* ghost_frog(World* world, Point position);
|
||||||
|
Entity* orb(World* world, Point position);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -29,7 +29,7 @@ void Game::startup()
|
||||||
m_draw_colliders = false;
|
m_draw_colliders = false;
|
||||||
|
|
||||||
// load first room
|
// load first room
|
||||||
load_room(Point(11, 0));
|
load_room(Point(12, 0));
|
||||||
camera = Vec2(room.x * width, room.y * height);
|
camera = Vec2(room.x * width, room.y * height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,13 +132,17 @@ void Game::load_room(Point cell, bool is_reload)
|
||||||
|
|
||||||
// closing door
|
// closing door
|
||||||
case 0x847e87:
|
case 0x847e87:
|
||||||
Factory::door(&world, world_position, true);
|
Factory::door(&world, world_position, !is_reload);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// blob
|
// blob
|
||||||
case 0x3f3f74:
|
case 0x3f3f74:
|
||||||
Factory::blob(&world, world_position);
|
Factory::blob(&world, world_position);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x76428a:
|
||||||
|
Factory::ghost_frog(&world, world_position + Point(-4, 0));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,5 +9,6 @@ namespace TL
|
||||||
static constexpr uint32_t jumpthru = 1 << 1;
|
static constexpr uint32_t jumpthru = 1 << 1;
|
||||||
static constexpr uint32_t player_attack = 1 << 2;
|
static constexpr uint32_t player_attack = 1 << 2;
|
||||||
static constexpr uint32_t enemy = 1 << 3;
|
static constexpr uint32_t enemy = 1 << 3;
|
||||||
|
static constexpr uint32_t player = 1 << 4;
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -245,6 +245,7 @@ namespace TL
|
||||||
entity->m_components.push_back(instance);
|
entity->m_components.push_back(instance);
|
||||||
|
|
||||||
// and we're done!
|
// and we're done!
|
||||||
|
instance->awake();
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user