Basic hit detection
This commit is contained in:
@ -9,4 +9,8 @@ using namespace Dawn;
|
||||
|
||||
BoxCollider::BoxCollider(SceneItem *i) : Collider2D(i) {
|
||||
|
||||
}
|
||||
|
||||
enum Collider2DType BoxCollider::getColliderType() {
|
||||
return COLLIDER2D_TYPE_BOX;
|
||||
}
|
@ -14,5 +14,6 @@ namespace Dawn {
|
||||
glm::vec2 max = glm::vec2( 0.5f, 0.5f);
|
||||
|
||||
BoxCollider(SceneItem *item);
|
||||
enum Collider2DType getColliderType() override;
|
||||
};
|
||||
}
|
@ -8,4 +8,5 @@ target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
BoxCollider.cpp
|
||||
Collider2D.cpp
|
||||
CharacterController2D.cpp
|
||||
)
|
@ -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);
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
||||
);
|
||||
};
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user