From: Daniel Karbach Date: Wed, 9 Apr 2014 08:22:08 +0000 (+0200) Subject: simple controller X-Git-Url: http://git.localhorst.tv/?p=orbi.git;a=commitdiff_plain;h=dbc08d84d9de1a77cba0dd97e4701f4ac99d056e simple controller --- diff --git a/src/app/Application.cpp b/src/app/Application.cpp index 01568d9..cbfafd3 100644 --- a/src/app/Application.cpp +++ b/src/app/Application.cpp @@ -13,8 +13,10 @@ Application::Application(Canvas &c, World &w, Tileset &t) : canvas(c) , world(w) , tiles(t) -, focus(Vector(5, 5), 2) -, cam(c.Size(), focus.Pos()) +, ctrl() +, focus(5, 5) +, target(focus, 2) +, cam(c.Size(), focus) , last(SDL_GetTicks()) , running(false) , paused(false) { @@ -22,6 +24,15 @@ Application::Application(Canvas &c, World &w, Tileset &t) } +void Application::Control(Entity &e) { + ctrl.Control(e); +} + +void Application::Relinquish() { + ctrl.Relinquish(); +} + + void Application::Run() { running = true; while (running) { @@ -85,17 +96,22 @@ void Application::HandleEvents() { void Application::OnKeyDown(const SDL_KeyboardEvent &e) { switch (e.keysym.sym) { - case SDLK_UP: - focus.MoveUp(); + case SDLK_w: + target.MoveUp(); + break; + case SDLK_s: + target.MoveDown(); break; - case SDLK_DOWN: - focus.MoveDown(); + case SDLK_a: + ctrl.MoveLeft(); + target.MoveLeft(); break; - case SDLK_LEFT: - focus.MoveLeft(); + case SDLK_d: + ctrl.MoveRight(); + target.MoveRight(); break; - case SDLK_RIGHT: - focus.MoveRight(); + case SDLK_SPACE: + ctrl.StartJump(); break; case SDLK_p: paused = !paused; @@ -107,17 +123,22 @@ void Application::OnKeyDown(const SDL_KeyboardEvent &e) { void Application::OnKeyUp(const SDL_KeyboardEvent &e) { switch (e.keysym.sym) { - case SDLK_UP: - focus.StopUp(); + case SDLK_w: + target.StopUp(); break; - case SDLK_DOWN: - focus.StopDown(); + case SDLK_s: + target.StopDown(); break; - case SDLK_LEFT: - focus.StopLeft(); + case SDLK_a: + ctrl.StopLeft(); + target.StopLeft(); break; - case SDLK_RIGHT: - focus.StopRight(); + case SDLK_d: + ctrl.StopRight(); + target.StopRight(); + break; + case SDLK_SPACE: + ctrl.StopJump(); break; default: break; @@ -127,9 +148,15 @@ void Application::OnKeyUp(const SDL_KeyboardEvent &e) { void Application::Update(int dt) { const float delta = dt / 1e3; + ctrl.Update(delta); + target.Update(delta); + focus = ctrl.Controlling() + ? ctrl.Controlled().bounds.Center() + : target.Pos(); cam.Update(delta); - world.Update(dt); - focus.Update(delta); + for (int i = 0; i < dt; ++i) { + world.Update(1e-3); + } } @@ -163,21 +190,21 @@ void Application::RenderEntities() { canvas.SetColor(entityColor); for (const Entity &e : world.Entities()) { - const Vector pos(e.Bounds().Left(), e.Bounds().Top()); - const Vector size(e.Bounds().Size()); + const Vector pos(e.bounds.Left(), e.bounds.Top()); + const Vector size(e.bounds.Size()); canvas.OutlineRect(cam.ToScreen(pos), cam.ToScale(size)); } } void Application::RenderUI() { constexpr Color outlineColor(0x00, 0x00, 0xFA); - constexpr Color focusColor(0xFA, 0xFA, 0x00); + constexpr Color targetColor(0xFA, 0xFA, 0x00); canvas.SetColor(outlineColor); canvas.Grid(cam.ToScreen(Vector(0, 0)), cam.ToScale(world.Size()), cam.ToScale(Vector(1, 1))); - canvas.SetColor(focusColor); - canvas.Cross(cam.ToScreen(focus.Pos()), 15); + canvas.SetColor(targetColor); + canvas.Cross(cam.ToScreen(target.Pos()), 15); } } diff --git a/src/app/Application.h b/src/app/Application.h index 2b0b361..d714be6 100644 --- a/src/app/Application.h +++ b/src/app/Application.h @@ -1,6 +1,7 @@ #ifndef ORBI_APPLICATION_H_ #define ORBI_APPLICATION_H_ +#include "Controller.h" #include "../graphics/Camera.h" #include "../graphics/Moveable.h" #include "../graphics/Texture.h" @@ -20,6 +21,9 @@ class Application { public: Application(Canvas &, World &, Tileset &); + void Control(Entity &); + void Relinquish(); + public: void Run(); @@ -43,7 +47,9 @@ private: World &world; Tileset &tiles; - Moveable focus; + Controller ctrl; + Vector focus; + Moveable target; Camera cam; Uint32 last; diff --git a/src/app/Controller.cpp b/src/app/Controller.cpp new file mode 100644 index 0000000..88dd5eb --- /dev/null +++ b/src/app/Controller.cpp @@ -0,0 +1,65 @@ +#include "Controller.h" + +#include "../world/Entity.h" +#include "../graphics/const.h" + +#include + + +namespace orbi { + +Controller::Controller(Entity *ent) +: e(ent) +, moving(0) +, moveAcc(3.5) +, moveTerm(5) +, jumping(false) +, jumpVel(-5) { + +} + +void Controller::Update(float delta) { + if (!e) return; + + if (moving) { + if (std::abs(e->acc.x) < moveTerm) { + e->acc.x = sigma(moving) * moveAcc; + } else { + e->acc.x = 0; + } + } else { + e->acc.x = sigma(e->vel.x) * -moveAcc; + } + + if (jumping && e->onGround) { + e->vel.y += jumpVel; + jumping = false; + } +} + + +void Controller::MoveLeft() { + moving -= 1; +} + +void Controller::StopLeft() { + moving += 1; +} + +void Controller::MoveRight() { + moving += 1; +} + +void Controller::StopRight() { + moving -= 1; +} + +void Controller::StartJump() { + jumping = true; +} + +void Controller::StopJump() { + jumping = false; +} + +} diff --git a/src/app/Controller.h b/src/app/Controller.h new file mode 100644 index 0000000..356d78e --- /dev/null +++ b/src/app/Controller.h @@ -0,0 +1,44 @@ +#ifndef ORBI_CONTROLLER_H_ +#define ORBI_CONTROLLER_H_ + +namespace orbi { + +class Entity; + +class Controller { + +public: + explicit Controller(Entity * = nullptr); + + void Control(Entity &ent) { e = &ent; } + void Relinquish() { e = nullptr; } + + bool Controlling() const { return e; } + const Entity &Controlled() const { return *e; } + + void Update(float delta); + +public: + void MoveLeft(); + void StopLeft(); + void MoveRight(); + void StopRight(); + + void StartJump(); + void StopJump(); + +private: + Entity *e; + + int moving; + float moveAcc; + float moveTerm; + + bool jumping; + float jumpVel; + +}; + +} + +#endif diff --git a/src/orbi.cpp b/src/orbi.cpp index 42ee910..b052441 100644 --- a/src/orbi.cpp +++ b/src/orbi.cpp @@ -49,10 +49,11 @@ int main(int argc, const char *argv[]) { world.SetTile(Vector(9, 6), Tile(0)); Entity e; - e.Bounds() = AABB(Vector(5, 2), Vector(2, 3)); - world.AddEntity(e); + e.bounds = AABB(Vector(5, 0), Vector(2, 3)); + Entity &player = world.AddEntity(e); Application app(canv, world, tiles); + app.Control(player); app.Run(); return 0; diff --git a/src/world/Entity.h b/src/world/Entity.h index f9671ca..f8576c1 100644 --- a/src/world/Entity.h +++ b/src/world/Entity.h @@ -17,10 +17,6 @@ public: void Move(Vector delta) { bounds.Move(delta); } public: - AABB &Bounds() { return bounds; } - const AABB &Bounds() const { return bounds; } - -private: AABB bounds; Vector vel; Vector acc; @@ -28,6 +24,8 @@ private: float mass = 1.0f; float elast = 0.75f; + bool onGround = false; + }; } diff --git a/src/world/World.cpp b/src/world/World.cpp index e390914..f4d80f9 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -15,65 +15,78 @@ World::World(Vector size) } -void World::Update(int delta) { - for (int i = 0; i < delta; ++i) { - const float dt = 1e-3; - for (Entity &e : entities) { - e.Update(dt, gravity, terminal); - - const AABB &b = e.Bounds(); - - // world bounds collision - if (b.Top() < 0) e.Move(Vector(0, -b.Top())); - if (b.Right() > size.x) e.Move(Vector(size.x - b.Right(), 0)); - if (b.Bottom() > size.y) e.Move(Vector(0, size.y - b.Bottom())); - if (b.Left() < 0) e.Move(Vector(-b.Left(), 0)); - - const Vector cBegin(b.Left(), b.Top()); - const Vector cEnd(b.Right(), b.Bottom()); - - Vector topResponse; - for (Vector pos(cBegin); pos.x < cEnd.x; ++pos.x) { - if (TileAt(pos).IsSolid()) { - topResponse = Vector(0, pos.y + 1 - b.Top()); - break; - } - } - Vector bottomResponse; - for (Vector pos(cBegin.x, cEnd.y); pos.x < cEnd.x; ++pos.x) { - if (TileAt(pos).IsSolid()) { - bottomResponse = Vector(0, pos.y - b.Bottom()); - break; - } - } - if (!IsZero(topResponse)) { - if (IsZero(bottomResponse)) { - e.Move(topResponse); +void World::Update(float dt) { + for (Entity &e : entities) { + e.Update(dt, gravity, terminal); + e.onGround = false; + + const AABB &b = e.bounds; + + // world bounds collision + if (b.Top() < 0) { + e.Move(Vector(0, -b.Top())); + e.vel.y = 0; + } + if (b.Right() > size.x) { + e.Move(Vector(size.x - b.Right(), 0)); + e.vel.x = 0; + } + if (b.Bottom() > size.y) { + e.Move(Vector(0, size.y - b.Bottom())); + e.vel.y = 0; + e.onGround = true; + } + if (b.Left() < 0) { + e.Move(Vector(-b.Left(), 0)); + e.vel.x = 0; + } + + const Vector cBegin(b.Left(), b.Top()); + const Vector cEnd(b.Right() + 1, b.Bottom() + 1); + + Vector min; + Vector max; + + for (Vector pos(cBegin); pos.y < cEnd.y; ++pos.y) { + for (pos.x = cBegin.x; pos.x < cEnd.x; ++pos.x) { + if (!TileAt(pos).IsSolid()) continue; + const AABB tBounds(pos, Vector(1, 1)); + Vector pos; + Vector norm; + Vector depth; + if (!e.bounds.Intersects(tBounds, pos, norm, depth)) { + continue; } - } else if (!IsZero(bottomResponse)) { - e.Move(bottomResponse); + if (depth.x < min.x) min.x = depth.x; + if (depth.x > max.x) max.x = depth.x; + if (depth.y < min.y) min.y = depth.y; + if (depth.y > max.y) max.y = depth.y; } + } - Vector leftResponse; - for (Vector pos(cBegin); pos.y < cEnd.y; ++pos.y) { - if (TileAt(pos).IsSolid()) { - leftResponse = Vector(pos.x + 1 - b.Left(), 0); - break; - } + Vector resp; + if (min.x != 0) { + if (max.x == 0) { + resp.x = min.x; } - Vector rightResponse; - for (Vector pos(cEnd.x, cBegin.y); pos.y < cEnd.y; ++pos.y) { - if (TileAt(pos).IsSolid()) { - rightResponse = Vector(pos.x - b.Right(), 0); - break; - } + } else { + resp.x = max.x; + } + if (min.y != 0) { + if (max.y == 0) { + resp.y = min.y; } - if (!IsZero(leftResponse)) { - if (IsZero(rightResponse)) { - e.Move(leftResponse); - } - } else if (!IsZero(rightResponse)) { - e.Move(rightResponse); + } else { + resp.y = max.y; + } + e.Move(resp); + if (resp.x != 0) { + e.vel.x = 0; + } + if (resp.y != 0) { + e.vel.y = 0; + if (resp.y < 0) { + e.onGround = true; } } } diff --git a/src/world/World.h b/src/world/World.h index 3483f66..d77b15b 100644 --- a/src/world/World.h +++ b/src/world/World.h @@ -20,7 +20,7 @@ public: Vector Size() const { return size; } public: - void Update(int dt); + void Update(float dt); bool InBounds(Vector pos) const { return pos.x > 0 && pos.y > 0 && pos.x < size.x && pos.y < size.y; }