Implemented ground framework for collectables simulation
This commit is contained in:
parent
949412df8a
commit
a5ceecd2a4
15 changed files with 353 additions and 47 deletions
|
@ -121,7 +121,12 @@ set(SOURCES
|
|||
src/game/physics/holes/layouts/hole_layout.cpp
|
||||
src/game/physics/holes/layouts/hole_layout.hpp
|
||||
src/game/physics/holes/layouts/depth_hole_layout.hpp
|
||||
src/game/physics/holes/layouts/depth_hole_description.hpp src/game/physics/holes/collectable_sim_ground_segment.hpp src/game/physics/holes/collectable_sim_ground_segment.cpp)
|
||||
src/game/physics/holes/layouts/depth_hole_description.hpp
|
||||
src/game/physics/holes/ground/collectable_sim_ground_segment.hpp
|
||||
src/game/physics/holes/ground/collectable_sim_ground.cpp
|
||||
src/game/physics/holes/ground/collectable_sim_ground.hpp
|
||||
src/game/physics/body_adapter.cpp
|
||||
src/game/physics/body_adapter.hpp)
|
||||
|
||||
set(PHYSICS_00_SOURCES
|
||||
src/prototypes/physics_00.cpp)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define DEFAULT_PLAYER_POINTS 0
|
||||
#define PLAYER_MIN_RADIUS 0.5f // World units
|
||||
#define PLAYER_RADIUS_PER_LEVEL 0.25f
|
||||
#define DEFAULT_MAX_PLAYER_NUMBER 4
|
||||
|
||||
// World
|
||||
#define WORLD_GRAVITY b2Vec2(0.f, -9.8f)
|
||||
|
|
82
src/game/physics/body_adapter.cpp
Normal file
82
src/game/physics/body_adapter.cpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
#include "body_adapter.hpp"
|
||||
|
||||
#include "../../config.h"
|
||||
|
||||
BodyAdapter::BodyAdapter(std::shared_ptr<b2World> world)
|
||||
: world(std::move(world)), bodyObject(nullptr)
|
||||
{}
|
||||
|
||||
BodyAdapter::~BodyAdapter()
|
||||
{
|
||||
destroyBody();
|
||||
}
|
||||
|
||||
void BodyAdapter::destroyBody()
|
||||
{
|
||||
if (bodyObject != nullptr)
|
||||
{
|
||||
world->DestroyBody(bodyObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BodyAdapter::createSquare(b2BodyType type, sf::Vector2f center, sf::Vector2f size)
|
||||
{
|
||||
destroyBody();
|
||||
|
||||
b2BodyDef bodyDef;
|
||||
bodyDef.type = type;
|
||||
bodyDef.angularDamping = COLLECTABLES_SIM_ANGULAR_DAMPING;
|
||||
bodyDef.linearDamping = COLLECTABLES_SIM_LINEAR_DAMPING;
|
||||
bodyDef.position.Set(center.x, center.y);
|
||||
bodyObject = world->CreateBody(&bodyDef);
|
||||
|
||||
setBoxSize(size);
|
||||
}
|
||||
|
||||
b2Body *BodyAdapter::body() const
|
||||
{
|
||||
return bodyObject;
|
||||
}
|
||||
|
||||
sf::Vector2f BodyAdapter::getCenter() const
|
||||
{
|
||||
auto position = bodyObject->GetPosition();
|
||||
auto velocity = bodyObject->GetLinearVelocity();
|
||||
return sf::Vector2f(position.x, position.y) + sf::Vector2f(velocity.x, velocity.y);
|
||||
}
|
||||
|
||||
sf::Vector2f BodyAdapter::getSize() const
|
||||
{
|
||||
return boundingBox;
|
||||
}
|
||||
|
||||
void BodyAdapter::setCenter(sf::Vector2f center)
|
||||
{
|
||||
// Set via velocity
|
||||
auto velocity = bodyObject->GetLinearVelocity();
|
||||
velocity += b2Vec2(center.x, center.y) - bodyObject->GetPosition();
|
||||
bodyObject->SetLinearVelocity(velocity);
|
||||
}
|
||||
|
||||
void BodyAdapter::setBoxSize(sf::Vector2f size)
|
||||
{
|
||||
// Remove old fixture
|
||||
if (bodyObject->GetFixtureList() != nullptr)
|
||||
{
|
||||
bodyObject->DestroyFixture(bodyObject->GetFixtureList());
|
||||
}
|
||||
|
||||
// Recreates a square fixture
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(size.x / 2.f, size.y / 2.f);
|
||||
boundingBox = size;
|
||||
|
||||
b2FixtureDef fixtureDef;
|
||||
fixtureDef.shape = &shape;
|
||||
fixtureDef.friction = COLLECTABLES_SIM_FRICTION;
|
||||
fixtureDef.restitution = COLLECTABLES_SIM_RESTITUTION;
|
||||
fixtureDef.density = COLLECTABLES_SIM_DENSITY;
|
||||
|
||||
bodyObject->CreateFixture(&fixtureDef);
|
||||
}
|
37
src/game/physics/body_adapter.hpp
Normal file
37
src/game/physics/body_adapter.hpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef HOLESOME_BODY_ADAPTER_HPP
|
||||
#define HOLESOME_BODY_ADAPTER_HPP
|
||||
|
||||
|
||||
#include <box2d/box2d.h>
|
||||
#include <memory>
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
|
||||
class BodyAdapter
|
||||
{
|
||||
public:
|
||||
explicit BodyAdapter(std::shared_ptr<b2World> world);
|
||||
~BodyAdapter();
|
||||
|
||||
[[nodiscard]] b2Body *body() const;
|
||||
|
||||
void createSquare(b2BodyType type, sf::Vector2f center, sf::Vector2f size);
|
||||
|
||||
[[nodiscard]] sf::Vector2f getCenter() const;
|
||||
|
||||
void setCenter(sf::Vector2f center);
|
||||
|
||||
[[nodiscard]] sf::Vector2f getSize() const;
|
||||
|
||||
void setBoxSize(sf::Vector2f size);
|
||||
|
||||
private:
|
||||
std::shared_ptr<b2World> world;
|
||||
b2Body *bodyObject;
|
||||
|
||||
sf::Vector2f boundingBox;
|
||||
|
||||
void destroyBody();
|
||||
};
|
||||
|
||||
|
||||
#endif //HOLESOME_BODY_ADAPTER_HPP
|
|
@ -1 +0,0 @@
|
|||
#include "collectable_sim_ground_segment.hpp"
|
|
@ -1,14 +0,0 @@
|
|||
#ifndef HOLESOME_COLLECTABLE_SIM_GROUND_SEGMENT_HPP
|
||||
#define HOLESOME_COLLECTABLE_SIM_GROUND_SEGMENT_HPP
|
||||
|
||||
#include <box2d/box2d.h>
|
||||
|
||||
class CollectableSimGroundSegment
|
||||
{
|
||||
public:
|
||||
int leftHoleId;
|
||||
int rightHoleId;
|
||||
b2Body *body;
|
||||
};
|
||||
|
||||
#endif //HOLESOME_COLLECTABLE_SIM_GROUND_SEGMENT_HPP
|
|
@ -11,9 +11,14 @@ CollectableSimulation::CollectableSimulation(const std::shared_ptr<Collectable>
|
|||
world = std::make_shared<b2World>(WORLD_GRAVITY);
|
||||
world->SetAllowSleeping(COLLECTABLES_SIM_SLEEPING);
|
||||
|
||||
// Create ground
|
||||
simGround = std::make_shared<CollectableSimGround>(world);
|
||||
// Todo: Set proper ground width
|
||||
|
||||
// Create body
|
||||
collectableBody = std::make_shared<BodyAdapter>(world);
|
||||
auto coordinates = collectable->coordinates->diagonalWorld();
|
||||
body = addSquareBody(b2_dynamicBody, {coordinates.horizontal, coordinates.vertical}, sf::Vector2f(1, 1));
|
||||
collectableBody->createSquare(b2_dynamicBody, {coordinates.horizontal, coordinates.vertical}, sf::Vector2f(1, 1));
|
||||
}
|
||||
|
||||
void CollectableSimulation::physicsUpdate()
|
||||
|
@ -25,28 +30,6 @@ void CollectableSimulation::physicsUpdate()
|
|||
updateCollectable();
|
||||
}
|
||||
|
||||
b2Body *CollectableSimulation::addSquareBody(b2BodyType type, sf::Vector2f center, sf::Vector2f size)
|
||||
{
|
||||
b2BodyDef bodyDef;
|
||||
bodyDef.type = type;
|
||||
bodyDef.angularDamping = COLLECTABLES_SIM_ANGULAR_DAMPING;
|
||||
bodyDef.linearDamping = COLLECTABLES_SIM_LINEAR_DAMPING;
|
||||
bodyDef.position.Set(center.x, center.y);
|
||||
b2Body *body = world->CreateBody(&bodyDef);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(size.x / 2.f, size.y / 2.f);
|
||||
|
||||
b2FixtureDef fixtureDef;
|
||||
fixtureDef.shape = &shape;
|
||||
fixtureDef.friction = COLLECTABLES_SIM_FRICTION;
|
||||
fixtureDef.restitution = COLLECTABLES_SIM_RESTITUTION;
|
||||
fixtureDef.density = COLLECTABLES_SIM_DENSITY;
|
||||
|
||||
body->CreateFixture(&fixtureDef);
|
||||
return body;
|
||||
}
|
||||
|
||||
std::shared_ptr<Collectable> CollectableSimulation::getCollectable() const
|
||||
{
|
||||
return collectable;
|
||||
|
@ -56,15 +39,25 @@ void CollectableSimulation::updateGroundHole()
|
|||
{
|
||||
auto holeLayout = HoleLayout::getInstance()->atDepth(collectable->getDepth());
|
||||
|
||||
if (holeLayout.holes.empty())
|
||||
{
|
||||
simGround->closeAllHoles();
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Remove assumption
|
||||
// Assume only one hole
|
||||
auto hole = holeLayout.holes[0];
|
||||
|
||||
// todo: Update ground hole
|
||||
}
|
||||
|
||||
void CollectableSimulation::updateCollectable()
|
||||
{
|
||||
auto bodyPosition = body->GetPosition();
|
||||
auto bodyPosition = collectableBody->body()->GetPosition();
|
||||
collectable->coordinates->setDiagonal({bodyPosition.x, bodyPosition.y, collectable->getDepth()});
|
||||
|
||||
// Convert radians to degrees
|
||||
float angle = body->GetAngle() * 180 / M_PI;
|
||||
float angle = collectableBody->body()->GetAngle() * 180 / M_PI;
|
||||
collectable->setRotation(angle);
|
||||
}
|
||||
|
|
|
@ -3,8 +3,12 @@
|
|||
|
||||
|
||||
#include <box2d/box2d.h>
|
||||
#include <map>
|
||||
#include "../../game_object.h"
|
||||
#include "../../collectables/collectable.hpp"
|
||||
#include "ground/collectable_sim_ground_segment.hpp"
|
||||
#include "ground/collectable_sim_ground.hpp"
|
||||
#include "../body_adapter.hpp"
|
||||
|
||||
class CollectableSimulation : public GameObject
|
||||
{
|
||||
|
@ -17,15 +21,15 @@ public:
|
|||
|
||||
private:
|
||||
std::shared_ptr<b2World> world;
|
||||
b2Body* body;
|
||||
std::shared_ptr<BodyAdapter> collectableBody;
|
||||
|
||||
std::shared_ptr<Collectable> collectable;
|
||||
|
||||
std::shared_ptr<CollectableSimGround> simGround;
|
||||
|
||||
void updateGroundHole();
|
||||
|
||||
void updateCollectable();
|
||||
|
||||
b2Body *addSquareBody(b2BodyType type, sf::Vector2f center, sf::Vector2f size);
|
||||
};
|
||||
|
||||
|
||||
|
|
102
src/game/physics/holes/ground/collectable_sim_ground.cpp
Normal file
102
src/game/physics/holes/ground/collectable_sim_ground.cpp
Normal file
|
@ -0,0 +1,102 @@
|
|||
#include "collectable_sim_ground.hpp"
|
||||
|
||||
#include <utility>
|
||||
#include "../../../../config.h"
|
||||
|
||||
void CollectableSimGround::closeAllHoles()
|
||||
{
|
||||
segments.clear();
|
||||
|
||||
// Create one segment for the ground
|
||||
auto groundSegment = std::make_shared<CollectableSimGroundSegment>(world);
|
||||
groundSegment->body->createSquare(b2_kinematicBody,
|
||||
{0, -COLLECTABLES_SIM_GROUND_THICKNESS / 2.f},
|
||||
{groundWidth, COLLECTABLES_SIM_GROUND_THICKNESS});
|
||||
|
||||
segments.push_back(groundSegment);
|
||||
}
|
||||
|
||||
CollectableSimGround::CollectableSimGround(std::shared_ptr<b2World> world, float groundWidth)
|
||||
: world(std::move(world))
|
||||
{
|
||||
setGroundWidth(groundWidth);
|
||||
closeAllHoles();
|
||||
}
|
||||
|
||||
void CollectableSimGround::setGroundWidth(float width)
|
||||
{
|
||||
if (width <= 0)
|
||||
{
|
||||
throw std::runtime_error("Ground width must be greater than 0");
|
||||
}
|
||||
|
||||
if (width == groundWidth)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
groundWidth = width;
|
||||
updateOuterSegmentsToWidth();
|
||||
}
|
||||
|
||||
void CollectableSimGround::updateOuterSegmentsToWidth()
|
||||
{
|
||||
auto outerSegments = getOuterSegments();
|
||||
auto borderPoints = groundWidth / 2.f;
|
||||
|
||||
// Left segment
|
||||
if (outerSegments.left != nullptr)
|
||||
{
|
||||
auto leftSegment = outerSegments.left->body;
|
||||
auto leftCenter = leftSegment->getCenter();
|
||||
auto leftSize = leftSegment->getSize();
|
||||
auto deltaToBorder = borderPoints - abs(leftCenter.x - leftSize.x / 2.f);
|
||||
|
||||
// Increase width if positive, decrease if negative
|
||||
leftSize.x += deltaToBorder;
|
||||
leftCenter.x -= deltaToBorder / 2.f;
|
||||
|
||||
leftSegment->setBoxSize(leftSize);
|
||||
leftSegment->setCenter(leftCenter);
|
||||
}
|
||||
|
||||
// Right segment
|
||||
if (outerSegments.right != nullptr)
|
||||
{
|
||||
auto rightSegment = outerSegments.right->body;
|
||||
auto rightCenter = rightSegment->getCenter();
|
||||
auto rightSize = rightSegment->getSize();
|
||||
auto deltaToBorder = borderPoints - abs(rightCenter.x + rightSize.x / 2.f);
|
||||
|
||||
// Increase width if positive, decrease if negative
|
||||
rightSize.x += deltaToBorder;
|
||||
rightCenter.x += deltaToBorder / 2.f;
|
||||
|
||||
rightSegment->setBoxSize(rightSize);
|
||||
rightSegment->setCenter(rightCenter);
|
||||
}
|
||||
}
|
||||
|
||||
CollectableSimGround::SideSegments CollectableSimGround::getOuterSegments(int holeId)
|
||||
{
|
||||
SideSegments sideSegments;
|
||||
|
||||
for (const auto &segment: segments)
|
||||
{
|
||||
// If valid holeId, match left hole id
|
||||
// If invalid holeId, get outer segment
|
||||
if ((segment->leftHoleId == holeId && holeId >= 0)
|
||||
|| (segment->rightHoleId < 0 && holeId < 0))
|
||||
{
|
||||
sideSegments.right = segment;
|
||||
}
|
||||
|
||||
if ((segment->rightHoleId == holeId && holeId >= 0)
|
||||
|| (segment->leftHoleId < 0 && holeId < 0))
|
||||
{
|
||||
sideSegments.left = segment;
|
||||
}
|
||||
}
|
||||
|
||||
return sideSegments;
|
||||
}
|
34
src/game/physics/holes/ground/collectable_sim_ground.hpp
Normal file
34
src/game/physics/holes/ground/collectable_sim_ground.hpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef HOLESOME_COLLECTABLE_SIM_GROUND_HPP
|
||||
#define HOLESOME_COLLECTABLE_SIM_GROUND_HPP
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "collectable_sim_ground_segment.hpp"
|
||||
|
||||
class CollectableSimGround
|
||||
{
|
||||
public:
|
||||
CollectableSimGround(std::shared_ptr<b2World> world, float groundWidth = 1000);
|
||||
|
||||
void closeAllHoles();
|
||||
|
||||
void setGroundWidth(float width);
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<CollectableSimGroundSegment>> segments;
|
||||
std::shared_ptr<b2World> world;
|
||||
float groundWidth;
|
||||
|
||||
struct SideSegments {
|
||||
std::shared_ptr<CollectableSimGroundSegment> left;
|
||||
std::shared_ptr<CollectableSimGroundSegment> right;
|
||||
};
|
||||
|
||||
SideSegments getOuterSegments(int holeId = -1);
|
||||
|
||||
void updateOuterSegmentsToWidth();
|
||||
};
|
||||
|
||||
|
||||
#endif //HOLESOME_COLLECTABLE_SIM_GROUND_HPP
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef HOLESOME_COLLECTABLE_SIM_GROUND_SEGMENT_HPP
|
||||
#define HOLESOME_COLLECTABLE_SIM_GROUND_SEGMENT_HPP
|
||||
|
||||
#include <box2d/box2d.h>
|
||||
#include <memory>
|
||||
#include "../layouts/depth_hole_description.hpp"
|
||||
#include "../../body_adapter.hpp"
|
||||
|
||||
class CollectableSimGroundSegment
|
||||
{
|
||||
public:
|
||||
explicit CollectableSimGroundSegment(const std::shared_ptr<b2World>& world)
|
||||
{
|
||||
body = std::make_shared<BodyAdapter>(world);
|
||||
}
|
||||
|
||||
int leftHoleId = -1;
|
||||
int rightHoleId = -1;
|
||||
std::shared_ptr<BodyAdapter> body;
|
||||
};
|
||||
|
||||
#endif //HOLESOME_COLLECTABLE_SIM_GROUND_SEGMENT_HPP
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <vector>
|
||||
#include "depth_hole_description.hpp"
|
||||
#include "../../../../logging/easylogging++.h"
|
||||
|
||||
struct DepthHoleLayout
|
||||
{
|
||||
|
@ -12,6 +13,26 @@ struct DepthHoleLayout
|
|||
DepthHoleLayout(float depth, std::vector<DepthHoleDescription> holes)
|
||||
: depth(depth), holes(std::move(holes))
|
||||
{}
|
||||
|
||||
[[nodiscard]] DepthHoleDescription getHole(int playerId) const
|
||||
{
|
||||
for (const auto &hole: holes)
|
||||
{
|
||||
if (hole.playerId == playerId)
|
||||
{
|
||||
return hole;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error(
|
||||
"No hole for player " + std::to_string(playerId) + " at depth " + std::to_string(depth) +
|
||||
" in layout.");
|
||||
}
|
||||
|
||||
[[nodiscard]] bool hasHole(int playerId) const
|
||||
{
|
||||
return std::ranges::any_of(holes, [playerId](const auto &hole) { return hole.playerId == playerId; });
|
||||
}
|
||||
};
|
||||
|
||||
#endif //HOLESOME_DEPTH_HOLE_LAYOUT_HPP
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
#include "../input/input_mapper.h"
|
||||
#include "../../texture_config.h"
|
||||
|
||||
PlayerCollection::PlayerCollection()
|
||||
PlayerCollection::PlayerCollection(int maxPlayerCount)
|
||||
: maxPlayerCount(maxPlayerCount)
|
||||
{
|
||||
// Set default spawn point
|
||||
setSpawnPoints({{0, 0}});
|
||||
|
@ -29,6 +30,7 @@ void PlayerCollection::addPlayer(const std::shared_ptr<Player> &player)
|
|||
{
|
||||
newPlayerBuffer.push_back(player);
|
||||
addDetachedChild(player);
|
||||
updateInputIdentityAllowance();
|
||||
}
|
||||
|
||||
void PlayerCollection::clear()
|
||||
|
@ -47,6 +49,7 @@ void PlayerCollection::clear()
|
|||
}
|
||||
|
||||
clearChildren();
|
||||
updateInputIdentityAllowance();
|
||||
}
|
||||
|
||||
void PlayerCollection::lateUpdate()
|
||||
|
@ -77,6 +80,7 @@ void PlayerCollection::removePlayer(const std::shared_ptr<Player> &player)
|
|||
{
|
||||
removedPlayerBuffer.push_back(player);
|
||||
removeChild(player);
|
||||
updateInputIdentityAllowance();
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Player>> PlayerCollection::getNewPlayers() const
|
||||
|
@ -130,3 +134,13 @@ std::shared_ptr<Player> PlayerCollection::getPlayerById(int playerId) const
|
|||
}
|
||||
throw std::runtime_error("Player with id " + std::to_string(playerId) + " not found");
|
||||
}
|
||||
|
||||
int PlayerCollection::getMaxPlayerCount() const
|
||||
{
|
||||
return maxPlayerCount;
|
||||
}
|
||||
|
||||
void PlayerCollection::updateInputIdentityAllowance() const
|
||||
{
|
||||
InputMapper::getInstance()->allowNewInputIdentities = getPlayers().size() < maxPlayerCount;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
class PlayerCollection : public GameObject
|
||||
{
|
||||
public:
|
||||
PlayerCollection();
|
||||
explicit PlayerCollection(int maxPlayerCount = DEFAULT_MAX_PLAYER_NUMBER);
|
||||
|
||||
static std::shared_ptr<PlayerCollection> getInstance();
|
||||
|
||||
|
@ -26,6 +26,8 @@ public:
|
|||
|
||||
[[nodiscard]] std::vector<std::shared_ptr<Player>> getRemovedPlayers() const;
|
||||
|
||||
[[nodiscard]] int getMaxPlayerCount() const;
|
||||
|
||||
void lateUpdate() override;
|
||||
|
||||
void clear();
|
||||
|
@ -40,6 +42,10 @@ private:
|
|||
int nextSpawnPointIndex = 0;
|
||||
|
||||
void spawnPlayer(const std::shared_ptr<InputIdentity> &inputIdentity);
|
||||
|
||||
int maxPlayerCount;
|
||||
|
||||
void updateInputIdentityAllowance() const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ std::map<std::string, LevelConfig> const all_levels = {
|
|||
{18, 18},
|
||||
{0, 18},
|
||||
{18, 0}}, {
|
||||
CollectableInLevel("box", {0, 0})
|
||||
CollectableInLevel("box", {3, 5})
|
||||
},
|
||||
{
|
||||
// Blues
|
||||
|
|
Loading…
Reference in a new issue