Basic hit detection

This commit is contained in:
2023-03-21 14:42:54 -07:00
parent 3a790e57c9
commit 978c420046
20 changed files with 343 additions and 41 deletions

View File

@ -9,4 +9,8 @@ using namespace Dawn;
BoxCollider::BoxCollider(SceneItem *i) : Collider2D(i) {
}
enum Collider2DType BoxCollider::getColliderType() {
return COLLIDER2D_TYPE_BOX;
}

View File

@ -14,5 +14,6 @@ namespace Dawn {
glm::vec2 max = glm::vec2( 0.5f, 0.5f);
BoxCollider(SceneItem *item);
enum Collider2DType getColliderType() override;
};
}

View File

@ -8,4 +8,5 @@ target_sources(${DAWN_TARGET_NAME}
PRIVATE
BoxCollider.cpp
Collider2D.cpp
CharacterController2D.cpp
)

View File

@ -0,0 +1,71 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "CharacterController2D.hpp"
using namespace Dawn;
CharacterController2D::CharacterController2D(SceneItem *i) :
SceneItemComponent(i)
{
}
void CharacterController2D::onStart() {
useEvent([&](float_t delta){
// Friction
velocity -= velocity * friction * delta;
auto myCollider = item->getComponent<Collider2D>();
glm::vec2 currentPosition(
this->transform->getLocalPosition().x,
this->transform->getLocalPosition().z
);
// Perform movement and check for collisions.
glm::vec2 moveAmount;
if(myCollider == nullptr) {
moveAmount = velocity;
} else {
// Perform sweep
auto allColliders = getScene()->findComponents<Collider2D>();
auto itColliders = allColliders.begin();
glm::vec2 normal;
float_t entryTime;
float_t exitTime;
glm::vec2 entryPoint;
glm::vec2 exitPoint;
bool_t result;
// Check for collisions, definitely not working 100% yet
while(itColliders != allColliders.end()) {
auto c = *itColliders;
++itColliders;
if(c == myCollider) continue;
result = myCollider->getCollidingResult(
velocity, c, normal, entryTime, exitTime, entryPoint, exitPoint
);
if(result) break;
}
if(result && entryTime <= delta) {
// Slide Resolution https://www.gamedev.net/articles/programming/general-and-gameplay-programming/swept-aabb-collision-detection-and-response-r3084/
float dotprod = (velocity.x * normal.y) + (velocity.y * normal.x) * (1.0f - entryTime);
moveAmount = velocity * entryTime;
// Respond to changes
velocity.x = dotprod * normal.y;
velocity.y = dotprod * normal.x;
} else {
moveAmount = velocity;
}
}
transform->setLocalPosition(
transform->getLocalPosition() + (glm::vec3(moveAmount.x, 0, moveAmount.y) * delta)
);
}, getScene()->eventSceneUpdate);
}

View File

@ -0,0 +1,21 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "Collider2D.hpp"
namespace Dawn {
class CharacterController2D : public SceneItemComponent {
private:
void move(glm::vec2 distance);
public:
glm::vec2 velocity;
float_t friction = 12.0f;
CharacterController2D(SceneItem *i);
void onStart() override;
};
}

View File

@ -4,9 +4,64 @@
// https://opensource.org/licenses/MIT
#include "Collider2D.hpp"
#include "BoxCollider.hpp"
using namespace Dawn;
Collider2D::Collider2D(SceneItem *i) : SceneItemComponent(i) {
}
bool_t Collider2D::getCollidingResult(
glm::vec2 movement,
Collider2D *other,
glm::vec2 &normal,
float_t &entryTime,
float_t &exitTime,
glm::vec2 &entryPoint,
glm::vec2 &exitPoint
) {
assertNotNull(other);
assertTrue(movement.x != 0 || movement.y != 0);
auto localPos = this->transform->getLocalPosition();
glm::vec2 myPos(localPos.x, localPos.z);
// Check what THIS is
switch(this->getColliderType()) {
case COLLIDER2D_TYPE_BOX: {
auto box1 = dynamic_cast<BoxCollider*>(this);
assertNotNull(box1);
// Box VS ?
switch(other->getColliderType()) {
case COLLIDER2D_TYPE_BOX: {
auto box2 = dynamic_cast<BoxCollider*>(other);
assertNotNull(box2);
auto localPos2 = box2->transform->getLocalPosition();
glm::vec2 otherPos(localPos2.x, localPos2.z);
return boxCheckCollision(
myPos, box1->min, box1->max,
otherPos, box2->min, box2->max,
movement,
normal, entryTime, exitTime, entryPoint, exitPoint
);
}
default: {
assertUnreachable();
}
}
break;
}
default: {
assertUnreachable();
}
}
assertUnreachable();
return false;
}

View File

@ -5,10 +5,54 @@
#pragma once
#include "scene/SceneItemComponent.hpp"
#include "physics/2d/Box.hpp"
namespace Dawn {
enum Collider2DType {
COLLIDER2D_TYPE_BOX
};
struct Collider2DAxisAlignedCollidingResult {
glm::vec2 normal;
float_t entryTime;
float_t exitTime;
glm::vec2 entryPoint;
glm::vec2 exitPoint;
};
class Collider2D : public SceneItemComponent {
public:
Collider2D(SceneItem *item);
/**
* Returns which type of collider this is.
*
* @return The collider type that this is.
*/
virtual enum Collider2DType getColliderType() = 0;
/**
* Gets the result of checking if two collider bodies are intersecting.
* This is performed WITH movement to return entry and exit times.
*
* @param result Where to store the results of the calculation.
* @param movement Movement operation that THIS object is performing.
* @param other Other Collider that is being compared.
* @param normal Output normal of the intersection.
* @param entryTime Output entry time when the two objects will intersect.
* @param exitTime Output exit time when the object will pass through.
* @param entryPoint Output point in 2D space where object will enter.
* @param exitPoint Output point where object will have passed through.
* @return True if the two objects will intersect at move otherwise false.
*/
bool_t getCollidingResult(
glm::vec2 movement,
Collider2D *other,
glm::vec2 &normal,
float_t &entryTime,
float_t &exitTime,
glm::vec2 &entryPoint,
glm::vec2 &exitPoint
);
};
}

View File

@ -9,6 +9,8 @@
#include "scene/Scene.hpp"
#include "scene/components/physics/3d/Collider3D.hpp"
#include "scene/components/physics/3d/CubeCollider.hpp"
#include "scene/components/physics/2d/Collider2D.hpp"
#include "scene/components/physics/2d/BoxCollider.hpp"
using namespace Dawn;
@ -162,4 +164,40 @@ void Scene::debugHitboxes() {
}
++itColliders;
}
auto colliders2d = this->findComponents<Collider2D>();
auto itColliders2 = colliders2d.begin();
while(itColliders2 != colliders2d.end()) {
auto c = *itColliders2;
switch(c->getColliderType()) {
case COLLIDER2D_TYPE_BOX:
auto asBox = dynamic_cast<BoxCollider*>(c);
this->debugLine({
.v0 = glm::vec3(asBox->min.x, 0, asBox->min.y),
.v1 = glm::vec3(asBox->max.x, 0, asBox->min.y),
.color = COLOR_BLUE,
.transform = c->transform->getWorldTransform()
});
this->debugLine({
.v0 = glm::vec3(asBox->max.x, 0, asBox->min.y),
.v1 = glm::vec3(asBox->max.x, 0, asBox->max.y),
.color = COLOR_BLUE,
.transform = c->transform->getWorldTransform()
});
this->debugLine({
.v0 = glm::vec3(asBox->max.x, 0, asBox->max.y),
.v1 = glm::vec3(asBox->min.x, 0, asBox->max.y),
.color = COLOR_BLUE,
.transform = c->transform->getWorldTransform()
});
this->debugLine({
.v0 = glm::vec3(asBox->min.x, 0, asBox->max.y),
.v1 = glm::vec3(asBox->min.x, 0, asBox->min.y),
.color = COLOR_BLUE,
.transform = c->transform->getWorldTransform()
});
break;
}
++itColliders2;
}
}