Implement initial test of entity physics, and entity vs terrain collision with high-density of colliders. (Decent performance w/o optimizations!)
This commit is contained in:
27
Client/src/Client/Entity.cpp
Normal file
27
Client/src/Client/Entity.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <Client/AssetService.hpp>
|
||||
#include <Core/Entity.hpp>
|
||||
#include <JGL/JGL.h>
|
||||
#include <rewindow/inputservice.hpp>
|
||||
|
||||
|
||||
void CaveGame::Core::Player::Draw() {
|
||||
auto myAsset = Client::AssetService::Get()->player_sprite;
|
||||
JGL::J2D::DrawPartialSprite(myAsset, position, {0,0}, {16, 24});
|
||||
JGL::J2D::OutlineRect(Colors::Red, position, bounding_box);
|
||||
}
|
||||
|
||||
void CaveGame::Core::Player::Update(float elapsed) {
|
||||
Humanoid::Update(elapsed);
|
||||
|
||||
if (InputService::IsKeyDown(Keys::A))
|
||||
WalkLeft();
|
||||
|
||||
if (InputService::IsKeyDown(Keys::D))
|
||||
WalkRight();
|
||||
|
||||
if (InputService::IsKeyDown(Keys::W))
|
||||
Jump();
|
||||
|
||||
if (InputService::IsKeyDown(Keys::S))
|
||||
Accelerate({0, -1});
|
||||
}
|
@@ -18,9 +18,12 @@
|
||||
#include <Core/Loggers.hpp>
|
||||
#include <rewindow/logger/logger.h>
|
||||
#include <Core/Tile.hpp>
|
||||
#include <JGL/logger/logger.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
JGL::Logger::Warning.EnableConsole(false);
|
||||
JGL::Logger::Debug.EnableConsole(false);
|
||||
ReWindow::Logger::Debug.EnableConsole(false);
|
||||
ReWindow::Logger::Debug.EnableFile(false);
|
||||
CaveGame::Logs::Info.IncludeLocation(false);
|
||||
@@ -32,12 +35,6 @@ int main(int argc, char** argv) {
|
||||
bool steam_success = SteamAPI_Init();
|
||||
#endif
|
||||
|
||||
//srand(0);
|
||||
|
||||
CaveGame::Core::DefineTiles();
|
||||
|
||||
//for (auto& tile : result)
|
||||
//std:: cout << tile << std::endl;
|
||||
|
||||
auto* window = new CaveGame::ClientApp::CaveGameWindow("Re-CaveGame", 800, 600);
|
||||
//window->SetResizable(true);
|
||||
@@ -52,4 +49,4 @@ int main(int argc, char** argv) {
|
||||
CaveGame::Logs::Info.Log("Exiting client program.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,9 @@
|
||||
#include <J3ML/LinearAlgebra.hpp>
|
||||
#include <vector>
|
||||
#include "Color4.hpp"
|
||||
#include "Interfaces.hpp"
|
||||
#include "Loggers.hpp"
|
||||
#include "SimpleAABBSolver.hpp"
|
||||
|
||||
namespace CaveGame::Core {
|
||||
class StatusEffect {
|
||||
@@ -13,14 +16,17 @@ namespace CaveGame::Core {
|
||||
|
||||
explicit Entity(const Vector2& spawnPoint);
|
||||
|
||||
int Health() const { return health; }
|
||||
int Health() const;
|
||||
|
||||
int MaxHealth() const { return max_health; }
|
||||
int MaxHealth() const;
|
||||
|
||||
virtual void Draw() = 0;
|
||||
|
||||
virtual void Update(float elapsed) = 0;
|
||||
|
||||
Vector2 Position() const { return position;}
|
||||
Vector2 Size() const { return bounding_box;}
|
||||
virtual void CollisionTest(ITileMap* map, float step) {}
|
||||
protected:
|
||||
int health;
|
||||
int max_health;
|
||||
@@ -37,19 +43,76 @@ namespace CaveGame::Core {
|
||||
class PhysicsEntity : public Entity {
|
||||
public:
|
||||
|
||||
explicit PhysicsEntity(const Vector2& spawnPoint) : Entity(spawnPoint) {}
|
||||
explicit PhysicsEntity(const Vector2& spawnPoint) : Entity(spawnPoint) {
|
||||
next_position = spawnPoint;
|
||||
}
|
||||
|
||||
[[nodiscard]] Vector2 Velocity() const { return velocity; }
|
||||
[[nodiscard]] Vector2 Velocity() const;
|
||||
|
||||
[[nodiscard]] Vector2 EstimatedNextPosition() const { return next_position; }
|
||||
[[nodiscard]] Vector2 EstimatedNextPosition() const;
|
||||
|
||||
void Accelerate(const Vector2& vector) {
|
||||
velocity += vector;
|
||||
}
|
||||
|
||||
virtual void PhysicsUpdate(float elapsed) {
|
||||
next_position += velocity * elapsed;
|
||||
|
||||
float friction = 2.45f;
|
||||
|
||||
velocity *= (1 - (elapsed*friction));
|
||||
|
||||
position = next_position;
|
||||
}
|
||||
|
||||
void CollisionTest(ITileMap* map, float elapsed) override
|
||||
{
|
||||
|
||||
for (int x = -1; x <= bounding_box.x; x++) {
|
||||
for (int y = -1; y <= bounding_box.y; y++) {
|
||||
Vector2 tileBoxPos = Vector2(Math::Floor(position.x), Math::Floor(position.y)) + Vector2(x,y);
|
||||
|
||||
TileID id = map->GetTile(tileBoxPos.x, tileBoxPos.y);
|
||||
|
||||
if (id == TileID::VOID || id == TileID::AIR)
|
||||
continue;
|
||||
|
||||
Vector2 entity_centroid = position + (bounding_box / 2.f);
|
||||
Vector2 entity_halfbox = bounding_box / 2.f;
|
||||
|
||||
Vector2 tile_centroid = tileBoxPos + Vector2{0.5f, 0.5f};
|
||||
Vector2 tile_halfbox = Vector2{0.5f, 0.5f};
|
||||
|
||||
|
||||
if (Solver::AABB2Dvs(entity_centroid, entity_halfbox, tile_centroid, tile_halfbox)) {
|
||||
Vector2 separation = Solver::SolveAABB(entity_centroid, entity_halfbox, tile_centroid, tile_halfbox);
|
||||
|
||||
Vector2 normal = Solver::GetNormalForAABB(separation, velocity);
|
||||
|
||||
next_position += separation;
|
||||
|
||||
//if (normal.y != 0)
|
||||
// velocity = {velocity.x, -velocity.y};
|
||||
|
||||
//if (normal.x != 0)
|
||||
// velocity = {-velocity.x, velocity.y};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Update(float elapsed) override {
|
||||
|
||||
// TODO: Sophisticated mechanism to maintain locked-timestep, multiple-iteration physics steps.
|
||||
PhysicsUpdate(elapsed);
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
Vector2 velocity;
|
||||
Vector2 next_position;
|
||||
float mass;
|
||||
private:
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -68,6 +131,14 @@ namespace CaveGame::Core {
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Update(float elapsed) override {
|
||||
PhysicsEntity::Update(elapsed);
|
||||
}
|
||||
void PhysicsUpdate(float elapsed) override {
|
||||
PhysicsEntity::PhysicsUpdate(elapsed);
|
||||
}
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
@@ -83,16 +154,24 @@ namespace CaveGame::Core {
|
||||
class Player : public Humanoid {
|
||||
public:
|
||||
|
||||
explicit Player(const Vector2& spawnPoint) : Humanoid(spawnPoint) { }
|
||||
explicit Player(const Vector2& spawnPoint);
|
||||
|
||||
|
||||
void Draw() override;
|
||||
void Update(float elapsed) override;
|
||||
void Jump();
|
||||
void PhysicsUpdate(float elapsed) override;
|
||||
void Jump() {
|
||||
Accelerate({0, 1});
|
||||
}
|
||||
void Climb();
|
||||
void Descend();
|
||||
void Crouch();
|
||||
void WalkLeft();
|
||||
void WalkRight();
|
||||
void WalkLeft() {
|
||||
Accelerate({-1, 0});
|
||||
}
|
||||
void WalkRight() {
|
||||
Accelerate({1, 0});
|
||||
}
|
||||
protected:
|
||||
};
|
||||
|
||||
@@ -108,4 +187,4 @@ namespace CaveGame::Core {
|
||||
class PhysicalParticle {};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -71,16 +71,14 @@ namespace CaveGame::Core
|
||||
|
||||
static LineSegTestResult LineSegment2Dvs(LineSegment2D s1, LineSegment2D s2);
|
||||
|
||||
|
||||
bool AABB2Dvs(const Vector2& posA, const Vector2& sizeA, const Vector2& posB, const Vector2& sizeB);
|
||||
|
||||
bool AABB2Dvs(const AABB2D& a, const AABB2D& b);
|
||||
|
||||
Vector2 SolveAABB(const Vector2& posA, const Vector2& sizeA, const Vector2& posB, const Vector2& sizeB);
|
||||
|
||||
static Vector2 SolveAABB(const Vector2& posA, const Vector2& sizeA, const Vector2& posB, const Vector2& sizeB);
|
||||
Vector2 GetNormalForAABB(const Vector2& separation, const Vector2& velocity);
|
||||
|
||||
static Vector2 GetNormalForAABB(const Vector2& separation, const Vector2& velocity);
|
||||
|
||||
static Vector2 SolveAABB(const AABB2D& a, const AABB2D& b);
|
||||
Vector2 SolveAABB(const AABB2D& a, const AABB2D& b);
|
||||
}
|
||||
}
|
@@ -366,8 +366,4 @@ namespace CaveGame::Core
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DefineTiles();
|
||||
|
||||
}
|
||||
|
@@ -1,16 +1,27 @@
|
||||
#include <Core/Entity.hpp>
|
||||
|
||||
|
||||
CaveGame::Core::Entity::Entity(const Vector2 &spawnPoint) {
|
||||
position = spawnPoint;
|
||||
}
|
||||
|
||||
void CaveGame::Core::Player::Draw() {
|
||||
#ifdef CAVE_CLIENT
|
||||
JGL::J2D::DrawPartialSprite();
|
||||
#endif
|
||||
|
||||
CaveGame::Core::Player::Player(const Vector2 &spawnPoint): Humanoid(spawnPoint) {
|
||||
bounding_box = {16, 24};
|
||||
}
|
||||
|
||||
int CaveGame::Core::Entity::Health() const { return health; }
|
||||
|
||||
int CaveGame::Core::Entity::MaxHealth() const { return max_health; }
|
||||
|
||||
Vector2 CaveGame::Core::PhysicsEntity::Velocity() const { return velocity; }
|
||||
|
||||
Vector2 CaveGame::Core::PhysicsEntity::EstimatedNextPosition() const { return next_position; }
|
||||
|
||||
|
||||
void CaveGame::Core::Player::Update(float elapsed) {
|
||||
|
||||
Humanoid::Update(elapsed);
|
||||
}
|
||||
|
||||
void CaveGame::Core::Player::PhysicsUpdate(float elapsed) {
|
||||
Humanoid::PhysicsUpdate(elapsed);
|
||||
}
|
||||
|
@@ -1,3 +1,4 @@
|
||||
#include <Core/Loggers.hpp>
|
||||
#include <Core/Tile.hpp>
|
||||
|
||||
namespace CaveGame::Core
|
||||
@@ -210,14 +211,7 @@ namespace CaveGame::Core
|
||||
}
|
||||
|
||||
|
||||
void DefineTiles() {
|
||||
/*RegisterTile(new Tile(TileID::AIR, "air", {0,0,0,0}));
|
||||
RegisterTile(new SoilTile(TileID::DIRT, "dirt", Colors::Green, TileID::DIRT));
|
||||
RegisterTile(new SoilTile(TileID::MUD, "mud", Colors::Green, TileID::MUD));
|
||||
RegisterTile(new Tile(TileID::STONE, "stone", Colors::Green));
|
||||
RegisterTile(new GrassyTile(TileID::GRASS, "grass", Colors::Green));*/
|
||||
|
||||
}
|
||||
|
||||
Tile *GetByName(const std::string &name) {
|
||||
// TODO: Optimize with additional mapping!!
|
||||
|
@@ -25,6 +25,14 @@ namespace CaveGame::Core
|
||||
}
|
||||
|
||||
DoRandomTileTicks();
|
||||
|
||||
for (auto* entity : entities) {
|
||||
entity->Update(elapsed);
|
||||
entity->CollisionTest(this, elapsed);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
TileID World::GetTile(int x, int y) const {
|
||||
|
Reference in New Issue
Block a user