diff --git a/MSTests/MSTests.cpp b/MSTests/MSTests.cpp index dc3aeea..01bd8a1 100644 --- a/MSTests/MSTests.cpp +++ b/MSTests/MSTests.cpp @@ -309,6 +309,80 @@ namespace MSTests } } + /// + /// Spawns two balls and platforms, each on different layers. One of the balls cannot interact with one of the platforms. + /// + TEST_METHOD(LayerInteractionTest) + { + RenderWindow window(VideoMode(800, 600), "Set velocity test"); + World world(Vector2f(0, 1)); + PhysicsCircle circle1; + circle1.setCenter(Vector2f(300, 100)); + circle1.setSize(Vector2f(50, 50)); + circle1.setLayer(0); + circle1.setFillColor(sf::Color::Red); + world.AddPhysicsBody(circle1); + + PhysicsCircle circle2; + circle2.setCenter(Vector2f(500, 100)); + circle2.setSize(Vector2f(100, 100)); + circle2.setLayer(1); + circle2.setFillColor(sf::Color::Green); + world.AddPhysicsBody(circle2); + + + PhysicsRectangle floor1; + floor1.setSize(Vector2f(800, 20)); + floor1.setCenter(Vector2f(400, 590)); + floor1.setStatic(true); + floor1.setLayer(0); + world.AddPhysicsBody(floor1); + + PhysicsRectangle floor2; + floor2.setSize(Vector2f(800, 20)); + floor2.setCenter(Vector2f(400, 400)); + floor2.setStatic(true); + floor2.setLayer(2); + floor2.setFillColor(sf::Color::Green); + world.AddPhysicsBody(floor2); + + world.ExcludeCollision(1, 2); + + system_clock::time_point last = system_clock::now(); + + Clock clock; + Time lastTime(clock.getElapsedTime()); + Time runTime = clock.getElapsedTime() + sf::seconds(10); + while (clock.getElapsedTime() < runTime) { + + // calculate MS since last frame + Time currentTime(clock.getElapsedTime()); + Time deltaTime(currentTime - lastTime); + int deltaTimeMS(deltaTime.asMilliseconds()); + if (deltaTimeMS > 0) { + world.UpdatePhysics(deltaTimeMS, 1); + lastTime = currentTime; + } + window.clear(Color(0, 0, 0)); + + window.draw(circle1); + window.draw(circle2); + window.draw(floor1); + window.draw(floor2); + world.VisualizeAllBounds(window); + window.display(); + + Event ev; + if (window.pollEvent(ev)) + { + if (ev.key.code == Keyboard::Space) + { + break; + } + } + } + } + TEST_METHOD(SFMLBinding) { World world(Vector2f(0, 1)); diff --git a/SFPhysics/CircleBounds.cpp b/SFPhysics/CircleBounds.cpp index fa3cbb6..9035f71 100644 --- a/SFPhysics/CircleBounds.cpp +++ b/SFPhysics/CircleBounds.cpp @@ -107,7 +107,7 @@ float sfp::CircleBounds::getRadius() void sfp::CircleBounds::setSize(Vector2f extents) { - setRadius(max(extents.x, extents.y)/2); + setRadius(max(extents.x, extents.y)); } Vector2f sfp::CircleBounds::getSize() diff --git a/SFPhysics/PhysicsBody.cpp b/SFPhysics/PhysicsBody.cpp index 5c6d76b..d960d4e 100644 --- a/SFPhysics/PhysicsBody.cpp +++ b/SFPhysics/PhysicsBody.cpp @@ -10,7 +10,7 @@ using namespace sfp; sfp::PhysicsBody::PhysicsBody(): restitution(1.0),mass(1.0),isStatic(false), - velocity(Vector2f(0,0)) + velocity(Vector2f(0,0)), layer(0) { } @@ -124,6 +124,16 @@ bool sfp::PhysicsBody::hasMoved() return moved; } +void sfp::PhysicsBody::setLayer(unsigned int layer) +{ + this->layer = layer; +} + +unsigned int sfp::PhysicsBody::getLayer() +{ + return layer; +} + diff --git a/SFPhysics/PhysicsLayer.cpp b/SFPhysics/PhysicsLayer.cpp new file mode 100644 index 0000000..fbc7338 --- /dev/null +++ b/SFPhysics/PhysicsLayer.cpp @@ -0,0 +1,2 @@ +#include "pch.h" +#include "PhysicsLayer.h" diff --git a/SFPhysics/SFPhysics.vcxproj b/SFPhysics/SFPhysics.vcxproj index f49824e..912382a 100644 --- a/SFPhysics/SFPhysics.vcxproj +++ b/SFPhysics/SFPhysics.vcxproj @@ -181,6 +181,7 @@ + @@ -209,6 +210,7 @@ + diff --git a/SFPhysics/SFPhysics.vcxproj.filters b/SFPhysics/SFPhysics.vcxproj.filters index e80d770..ea6928a 100644 --- a/SFPhysics/SFPhysics.vcxproj.filters +++ b/SFPhysics/SFPhysics.vcxproj.filters @@ -90,6 +90,9 @@ Header Files + + Header Files + @@ -152,6 +155,9 @@ Source Files + + Source Files + diff --git a/SFPhysics/World.cpp b/SFPhysics/World.cpp index 05b2a69..d76e564 100644 --- a/SFPhysics/World.cpp +++ b/SFPhysics/World.cpp @@ -81,7 +81,7 @@ void sfp::World::UpdatePhysics(unsigned long deltaMilliseconds,unsigned long msP // do collision, very stupid right now. long run should not check // objecst that havent moved for (auto obj2 : objects) { - if ((obj != obj2) && (ignoreMovement || obj->hasMoved() || obj2->hasMoved())) { + if ((obj != obj2) && (ignoreMovement || obj->hasMoved() || obj2->hasMoved()) && HasCollision(obj->getLayer(), obj2->getLayer())) { PhysicsBodyCollisionResult collision = obj->collideWith(*obj2); if (collision.hasCollided) { @@ -111,3 +111,54 @@ void sfp::World::setIgnoreMovement(bool ignore) { ignoreMovement = ignore; } + +void sfp::World::ExcludeCollision(unsigned int layer1, unsigned int layer2) +{ + // Use the lower layer number. This is to prevent overlap. + int primaryLayer = layer1 < layer2 ? layer1 : layer2; + int otherLayer = layer1 < layer2 ? layer2 : layer1; + + for (auto layer : layers) + { + if (layer.Layer == primaryLayer) + { + layer.AddExcludedLayer(otherLayer); + return; + } + } + + PhysicsLayer layer; + layer.Layer = layer1; + layer.AddExcludedLayer(layer2); + layers.push_back(layer); +} + +void sfp::World::IncludeCollision(unsigned int layer1, unsigned int layer2) +{ + // Use the lower layer number. This is to prevent overlap. + int primaryLayer = layer1 < layer2 ? layer1 : layer2; + int otherLayer = layer1 < layer2 ? layer2 : layer1; + + for (auto layer : layers) + { + if (layer.Layer == primaryLayer) + { + layer.RemoveExcludedLayer(otherLayer); + return; + } + } +} + +bool sfp::World::HasCollision(unsigned int layer1, unsigned int layer2) +{ + // Use the lower layer number. This is to prevent overlap. + int primaryLayer = layer1 < layer2 ? layer1 : layer2; + int otherLayer = layer1 < layer2 ? layer2 : layer1; + + for (auto layer : layers) + { + if (layer.Layer == primaryLayer) + return !layer.ExcludesLayer(otherLayer); + } + return true; +} diff --git a/SFPhysics/include/SFPhysics/PhysicsBody.h b/SFPhysics/include/SFPhysics/PhysicsBody.h index fd3e0a1..ca3b23e 100644 --- a/SFPhysics/include/SFPhysics/PhysicsBody.h +++ b/SFPhysics/include/SFPhysics/PhysicsBody.h @@ -16,11 +16,11 @@ namespace sfp { bool isStatic; Vector2f velocity; bool moved; - + unsigned int layer; public: PhysicsBody(); PhysicsBody(Bounds& bounds, bool isStatic = false, - float restitution=1.0f,float mass=1.0f); + float restitution=1.0f,float mass=1.0f, int layer = 0); void applyImpulse(Vector2f impulse); void update(unsigned int deltaMillisconds); void setPosition(Vector2f center); @@ -39,6 +39,16 @@ namespace sfp { PhysicsBodyCollisionResult collideWith(PhysicsBody& other); void setMoved(bool moved = false); bool hasMoved(); + /// + /// Sets the collision layer to be set to this object. Default is 0. + /// + /// The layer to use. + void setLayer(unsigned int layer); + /// + /// Gets the current layer associated with this object. Default is 0. + /// + /// The layer this object is associated with. + unsigned int getLayer(); bool operator == (const PhysicsBody& other) { return this == &other; diff --git a/SFPhysics/include/SFPhysics/PhysicsLayer.h b/SFPhysics/include/SFPhysics/PhysicsLayer.h new file mode 100644 index 0000000..8ed5fc0 --- /dev/null +++ b/SFPhysics/include/SFPhysics/PhysicsLayer.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +/// +/// Struct that stores a Layer and a list of Exclusion layers. +/// This struct is intended for internal use. +/// +/// Notes: This isn't intended to be a very complex Physics Layer system. Instead, it tries to prioritize ease-of-use without concerning too much on bit flags. +/// +struct PhysicsLayer +{ +public: + unsigned Layer; + std::list ExclusionLayers; + + bool ExcludesLayer(unsigned layer) + { + for (unsigned excludedLayer : ExclusionLayers) + { + if (excludedLayer == layer) + return true; + } + return false; + } + + void AddExcludedLayer(unsigned layer) + { + for (unsigned excludedLayer : ExclusionLayers) + { + if (excludedLayer == layer) + return; + } + + ExclusionLayers.push_back(layer); + } + + void RemoveExcludedLayer(unsigned layer) + { + ExclusionLayers.remove(layer); + } +}; + diff --git a/SFPhysics/include/SFPhysics/World.h b/SFPhysics/include/SFPhysics/World.h index faab82d..cd31561 100644 --- a/SFPhysics/include/SFPhysics/World.h +++ b/SFPhysics/include/SFPhysics/World.h @@ -2,6 +2,7 @@ #include #include #include "PhysicsBody.h" +#include "PhysicsLayer.h" using namespace sf; using namespace std; @@ -15,6 +16,7 @@ namespace sfp { bool ignoreMovement; list removalList; long unsigned deltaAccumulator = 0; + list layers; public: World(Vector2f gravity); @@ -23,6 +25,25 @@ namespace sfp { void UpdatePhysics(unsigned long deltaMilliseconds, unsigned long msPerTick = 0); void VisualizeAllBounds(RenderWindow& window); void setIgnoreMovement(bool ignore = true); + /// + /// Prevents a layer from interacting with another layer. + /// + /// The first layer to compare + /// The second layer to compare + void ExcludeCollision(unsigned int layer1, unsigned int layer2); + /// + /// Allows a layer to interact with another layer. Note that layers can interact with other layers by default. + /// + /// The first layer to compare + /// The second layer to compare + void IncludeCollision(unsigned int layer1, unsigned int layer2); + /// + /// Check if a layer is allowed to collide with another layer. + /// + /// The first layer to compare + /// The second layer to compare + /// + bool HasCollision(unsigned int layer1, unsigned int layer2); }; }