bunch of stuff
|
@ -17,8 +17,13 @@ add_executable(game
|
||||||
src/game.cpp
|
src/game.cpp
|
||||||
src/content.h
|
src/content.h
|
||||||
src/content.cpp
|
src/content.cpp
|
||||||
|
src/masks.h
|
||||||
|
src/factory.h
|
||||||
|
src/factory.cpp
|
||||||
src/assets/sprite.h
|
src/assets/sprite.h
|
||||||
src/assets/sprite.cpp
|
src/assets/sprite.cpp
|
||||||
|
src/assets/tileset.h
|
||||||
|
src/assets/tileset.cpp
|
||||||
src/components/animator.h
|
src/components/animator.h
|
||||||
src/components/animator.cpp
|
src/components/animator.cpp
|
||||||
src/components/collider.h
|
src/components/collider.h
|
||||||
|
@ -27,10 +32,14 @@ add_executable(game
|
||||||
src/components/player.cpp
|
src/components/player.cpp
|
||||||
src/components/mover.h
|
src/components/mover.h
|
||||||
src/components/mover.cpp
|
src/components/mover.cpp
|
||||||
src/masks.h
|
src/components/tilemap.h
|
||||||
src/factory.h
|
src/components/tilemap.cpp
|
||||||
src/factory.cpp
|
src/components/hurtable.h
|
||||||
"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/hurtable.cpp
|
||||||
|
src/components/timer.h
|
||||||
|
src/components/timer.cpp
|
||||||
|
src/components/enemy.h
|
||||||
|
)
|
||||||
|
|
||||||
# Reference blah
|
# Reference blah
|
||||||
target_link_libraries(game blah)
|
target_link_libraries(game blah)
|
||||||
|
|
BIN
content/map/10x0.png
Normal file
After Width: | Height: | Size: 265 B |
Before Width: | Height: | Size: 323 B After Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 325 B After Width: | Height: | Size: 334 B |
BIN
content/map/6x1.png
Normal file
After Width: | Height: | Size: 285 B |
BIN
content/map/7x1.png
Normal file
After Width: | Height: | Size: 270 B |
BIN
content/map/8x0.png
Normal file
After Width: | Height: | Size: 254 B |
BIN
content/map/8x1.png
Normal file
After Width: | Height: | Size: 195 B |
BIN
content/map/9x0.png
Normal file
After Width: | Height: | Size: 284 B |
BIN
content/sprites/blob.ase
Normal file
BIN
content/sprites/door.ase
Normal file
BIN
content/sprites/heart.ase
Normal file
|
@ -72,6 +72,8 @@ 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
|
||||||
{
|
{
|
||||||
|
if (world())
|
||||||
|
{
|
||||||
auto other = world()->first<Collider>();
|
auto other = world()->first<Collider>();
|
||||||
while (other)
|
while (other)
|
||||||
{
|
{
|
||||||
|
@ -82,6 +84,7 @@ bool Collider::check(uint32_t mask, Point offset) const
|
||||||
|
|
||||||
other = (Collider*)other->next();
|
other = (Collider*)other->next();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
10
src/components/enemy.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../world.h"
|
||||||
|
|
||||||
|
namespace TL
|
||||||
|
{
|
||||||
|
class Enemy : public Component
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ void Hurtable::update()
|
||||||
{
|
{
|
||||||
if (collider->check(hurt_by))
|
if (collider->check(hurt_by))
|
||||||
{
|
{
|
||||||
|
Time::pause_for(0.1f);
|
||||||
stun_timer = 0.5f;
|
stun_timer = 0.5f;
|
||||||
flicker_timer = 0.5f;
|
flicker_timer = 0.5f;
|
||||||
on_hurt(this);
|
on_hurt(this);
|
||||||
|
|
|
@ -87,6 +87,10 @@ bool Mover::on_ground(int dist) const
|
||||||
|
|
||||||
void Mover::update()
|
void Mover::update()
|
||||||
{
|
{
|
||||||
|
// apply friction maybe
|
||||||
|
if (friction > 0 && on_ground())
|
||||||
|
speed.x = Calc::approach(speed.x, 0, friction * Time::delta);
|
||||||
|
|
||||||
// apply gravity
|
// apply gravity
|
||||||
if (gravity != 0 && (!collider || !collider->check(Mask::solid, Point(0, 1))))
|
if (gravity != 0 && (!collider || !collider->check(Mask::solid, Point(0, 1))))
|
||||||
speed.y += gravity * Time::delta;
|
speed.y += gravity * Time::delta;
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace TL
|
||||||
Collider* collider = nullptr;
|
Collider* collider = nullptr;
|
||||||
Vec2 speed;
|
Vec2 speed;
|
||||||
float gravity = 0;
|
float gravity = 0;
|
||||||
|
float friction = 0;
|
||||||
std::function<void(Mover*)> on_hit_x;
|
std::function<void(Mover*)> on_hit_x;
|
||||||
std::function<void(Mover*)> on_hit_y;
|
std::function<void(Mover*)> on_hit_y;
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,9 @@ void Player::update()
|
||||||
// START
|
// START
|
||||||
if (m_state == st_start)
|
if (m_state == st_start)
|
||||||
{
|
{
|
||||||
|
while (hitbox->check(Mask::solid))
|
||||||
|
entity()->position.y++;
|
||||||
|
|
||||||
anim->play("sword");
|
anim->play("sword");
|
||||||
m_start_timer -= Time::delta;
|
m_start_timer -= Time::delta;
|
||||||
if (m_start_timer <= 0)
|
if (m_start_timer <= 0)
|
||||||
|
|
|
@ -14,8 +14,9 @@ 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;
|
||||||
|
|
||||||
int health = 3;
|
int health = max_health;
|
||||||
|
|
||||||
VirtualStick input_move;
|
VirtualStick input_move;
|
||||||
VirtualButton input_jump;
|
VirtualButton input_jump;
|
||||||
|
|
102
src/factory.cpp
|
@ -6,6 +6,7 @@
|
||||||
#include "components/player.h"
|
#include "components/player.h"
|
||||||
#include "components/hurtable.h"
|
#include "components/hurtable.h"
|
||||||
#include "components/timer.h"
|
#include "components/timer.h"
|
||||||
|
#include "components/enemy.h"
|
||||||
|
|
||||||
using namespace TL;
|
using namespace TL;
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ Entity* Factory::player(World* world, Point position)
|
||||||
anim->play("idle");
|
anim->play("idle");
|
||||||
anim->depth = -10;
|
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());
|
auto mover = en->add(Mover());
|
||||||
mover->collider = hitbox;
|
mover->collider = hitbox;
|
||||||
|
@ -42,7 +43,6 @@ Entity* Factory::bramble(World* world, Point position)
|
||||||
hurtable->collider = hitbox;
|
hurtable->collider = hitbox;
|
||||||
hurtable->on_hurt = [](Hurtable* self)
|
hurtable->on_hurt = [](Hurtable* self)
|
||||||
{
|
{
|
||||||
Time::pause_for(0.1f);
|
|
||||||
pop(self->world(), self->entity()->position + Point(0, -4));
|
pop(self->world(), self->entity()->position + Point(0, -4));
|
||||||
self->entity()->destroy();
|
self->entity()->destroy();
|
||||||
};
|
};
|
||||||
|
@ -69,6 +69,7 @@ Entity* Factory::pop(World* world, Point position)
|
||||||
Entity* Factory::spitter(World* world, Point position)
|
Entity* Factory::spitter(World* world, Point position)
|
||||||
{
|
{
|
||||||
auto en = world->add_entity(position);
|
auto en = world->add_entity(position);
|
||||||
|
en->add(Enemy());
|
||||||
|
|
||||||
auto anim = en->add(Animator("spitter"));
|
auto anim = en->add(Animator("spitter"));
|
||||||
anim->play("idle");
|
anim->play("idle");
|
||||||
|
@ -193,6 +194,7 @@ Entity* Factory::mosquito(World* world, Point position)
|
||||||
{
|
{
|
||||||
auto en = world->add_entity(position);
|
auto en = world->add_entity(position);
|
||||||
auto mosquito = en->add(MosquitoBehavior());
|
auto mosquito = en->add(MosquitoBehavior());
|
||||||
|
en->add(Enemy());
|
||||||
|
|
||||||
auto anim = en->add(Animator("mosquito"));
|
auto anim = en->add(Animator("mosquito"));
|
||||||
anim->play("fly");
|
anim->play("fly");
|
||||||
|
@ -211,3 +213,99 @@ Entity* Factory::mosquito(World* world, Point position)
|
||||||
return en;
|
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<Enemy>())
|
||||||
|
{
|
||||||
|
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<Animator>()->play("idle");
|
||||||
|
self->stop_y();
|
||||||
|
};
|
||||||
|
|
||||||
|
en->add(Timer(2.0f, [](Timer* self)
|
||||||
|
{
|
||||||
|
auto mover = self->get<Mover>();
|
||||||
|
if (!mover->on_ground())
|
||||||
|
{
|
||||||
|
self->start(0.05f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self->get<Animator>()->play("jump");
|
||||||
|
self->start(2.0f);
|
||||||
|
mover->speed.y = -90;
|
||||||
|
|
||||||
|
auto player = self->world()->first<Player>();
|
||||||
|
if (player)
|
||||||
|
{
|
||||||
|
auto dir = Calc::sign(player->entity()->position.x - self->entity()->position.x);
|
||||||
|
if (dir == 0) dir = 1;
|
||||||
|
|
||||||
|
self->get<Animator>()->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<Player>();
|
||||||
|
if (player)
|
||||||
|
{
|
||||||
|
auto mover = self->get<Mover>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,5 +14,7 @@ namespace TL
|
||||||
Entity* spitter(World* world, Point position);
|
Entity* spitter(World* world, Point position);
|
||||||
Entity* bullet(World* world, Point position, int direction);
|
Entity* bullet(World* world, Point position, int direction);
|
||||||
Entity* mosquito(World* world, Point position);
|
Entity* mosquito(World* world, Point position);
|
||||||
|
Entity* door(World* world, Point position);
|
||||||
|
Entity* blob(World* world, Point position);
|
||||||
}
|
}
|
||||||
}
|
}
|
72
src/game.cpp
|
@ -5,6 +5,8 @@
|
||||||
#include "components/collider.h"
|
#include "components/collider.h"
|
||||||
#include "components/tilemap.h"
|
#include "components/tilemap.h"
|
||||||
#include "components/player.h"
|
#include "components/player.h"
|
||||||
|
#include "components/mover.h"
|
||||||
|
#include "assets/sprite.h"
|
||||||
#include "factory.h"
|
#include "factory.h"
|
||||||
|
|
||||||
using namespace TL;
|
using namespace TL;
|
||||||
|
@ -27,11 +29,11 @@ void Game::startup()
|
||||||
m_draw_colliders = false;
|
m_draw_colliders = false;
|
||||||
|
|
||||||
// load first room
|
// load first room
|
||||||
load_room(Point(0, 0));
|
load_room(Point(10, 0));
|
||||||
camera = Vec2(room.x * width, room.y * height);
|
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);
|
const Image* grid = Content::find_room(cell);
|
||||||
BLAH_ASSERT(grid, "Room doesn't exist!");
|
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)
|
// player (only if it doesn't already exist)
|
||||||
case 0x6abe30:
|
case 0x6abe30:
|
||||||
if (!world.first<Player>())
|
if (!world.first<Player>())
|
||||||
Factory::player(&world, world_position);
|
Factory::player(&world, world_position + (is_reload ? Point(0, -16) : Point::zero));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// brambles
|
// brambles
|
||||||
|
@ -111,6 +113,16 @@ void Game::load_room(Point cell)
|
||||||
case 0xfbf236:
|
case 0xfbf236:
|
||||||
Factory::mosquito(&world, world_position + Point(0, -8));
|
Factory::mosquito(&world, world_position + Point(0, -8));
|
||||||
break;
|
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--;
|
if (pos.y < 0) next_room.y--;
|
||||||
|
|
||||||
// see if room exists
|
// see if room exists
|
||||||
if (Content::find_room(next_room))
|
if (player->health > 0 && Content::find_room(next_room))
|
||||||
{
|
{
|
||||||
Time::pause_for(0.1f);
|
Time::pause_for(0.1f);
|
||||||
|
|
||||||
|
@ -185,10 +197,24 @@ void Game::update()
|
||||||
if (player->entity()->position.y > bounds.y + bounds.h + 64)
|
if (player->entity()->position.y > bounds.y + bounds.h + 64)
|
||||||
{
|
{
|
||||||
world.clear();
|
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<Player>())
|
||||||
|
world.destroy_entity(e);
|
||||||
|
e = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Room Transition routine
|
// Room Transition routine
|
||||||
|
@ -207,6 +233,14 @@ void Game::update()
|
||||||
// Finish Transition
|
// Finish Transition
|
||||||
if (m_next_ease >= 1.0f)
|
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<Player>();
|
||||||
|
if (player)
|
||||||
|
player->get<Mover>()->speed = Vec2(100, -200);
|
||||||
|
}
|
||||||
|
|
||||||
// delete old objects (except player!)
|
// delete old objects (except player!)
|
||||||
for (auto& it : m_last_entities)
|
for (auto& it : m_last_entities)
|
||||||
{
|
{
|
||||||
|
@ -226,9 +260,13 @@ void Game::render()
|
||||||
{
|
{
|
||||||
buffer->clear(0x150e22);
|
buffer->clear(0x150e22);
|
||||||
|
|
||||||
|
// push camera offset
|
||||||
batch.push_matrix(Mat3x2::create_translation(-camera));
|
batch.push_matrix(Mat3x2::create_translation(-camera));
|
||||||
|
|
||||||
|
// draw gameplay objects
|
||||||
world.render(batch);
|
world.render(batch);
|
||||||
|
|
||||||
|
// draw debug colliders
|
||||||
if (m_draw_colliders)
|
if (m_draw_colliders)
|
||||||
{
|
{
|
||||||
auto collider = world.first<Collider>();
|
auto collider = world.first<Collider>();
|
||||||
|
@ -239,7 +277,31 @@ void Game::render()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// end camera offset
|
||||||
batch.pop_matrix();
|
batch.pop_matrix();
|
||||||
|
|
||||||
|
// draw the health
|
||||||
|
auto player = world.first<Player>();
|
||||||
|
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.render(buffer);
|
||||||
batch.clear();
|
batch.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace TL
|
||||||
Point room;
|
Point room;
|
||||||
Vec2 camera;
|
Vec2 camera;
|
||||||
|
|
||||||
void load_room(Point cell);
|
void load_room(Point cell, bool is_reload = false);
|
||||||
void startup();
|
void startup();
|
||||||
void shutdown();
|
void shutdown();
|
||||||
void update();
|
void update();
|
||||||
|
|