Made the hurt hazard work better.
This commit is contained in:
@ -175,6 +175,15 @@ Transform * Transform::getParent() {
|
||||
return this->parent;
|
||||
}
|
||||
|
||||
bool_t Transform::isChildOf(Transform *parent) {
|
||||
Transform *current = this->getParent();
|
||||
while(current != nullptr) {
|
||||
if(current == parent) return true;
|
||||
current = current->getParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Transform::~Transform() {
|
||||
this->setParent(nullptr);
|
||||
|
||||
|
@ -162,6 +162,15 @@ namespace Dawn {
|
||||
*/
|
||||
Transform * getParent();
|
||||
|
||||
/**
|
||||
* Returns true if this transform is a child of the given transform, this
|
||||
* climbs up the heirarchy until it finds a match.
|
||||
*
|
||||
* @param p Transform to check if this transform is a child of.
|
||||
* @return True if this transform is a child of the given transform.
|
||||
*/
|
||||
bool_t isChildOf(Transform *p);
|
||||
|
||||
/**
|
||||
* Dispose and clenaup this transform, also removes self from parent.
|
||||
*/
|
||||
|
@ -85,15 +85,13 @@ bool_t Dawn::boxIsBoxColliding(
|
||||
glm::vec2 posB, glm::vec2 minB, glm::vec2 maxB
|
||||
) {
|
||||
// Check for no overlap in X axis
|
||||
if (posA.x + maxA.x < posB.x + minB.x || posA.x + minA.x > posB.x + maxB.x) {
|
||||
if (posA.x + maxA.x < posB.x + minB.x || posB.x + maxB.x < posA.x + minA.x) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for no overlap in Y axis
|
||||
if (posA.y + maxA.y < posB.y + minB.y || posA.y + minA.y > posB.y + maxB.y) {
|
||||
if (posA.y + maxA.y < posB.y + minB.y || posB.y + maxB.y < posA.y + minA.y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// There is overlap in both X and Y axis, so the boxes are colliding
|
||||
return true;
|
||||
}
|
13
src/dawn/physics/2d/Physics2D.hpp
Normal file
13
src/dawn/physics/2d/Physics2D.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
static inline glm::vec2 physics3Dto2D(glm::vec3 v) {
|
||||
return glm::vec2(v.x, v.z);
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
#pragma once
|
||||
#include "Collider2D.hpp"
|
||||
#include "physics/2d/Box.hpp"
|
||||
#include "physics/2d/Physics2D.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class BoxCollider : public Collider2D {
|
||||
|
@ -16,10 +16,6 @@ void CharacterController2D::onStart() {
|
||||
useEvent([&](float_t delta){
|
||||
// Common variables
|
||||
auto myCollider = item->getComponent<Collider2D>();
|
||||
glm::vec2 currentPosition(
|
||||
this->transform->getLocalPosition().x,
|
||||
this->transform->getLocalPosition().z
|
||||
);
|
||||
|
||||
// Friction
|
||||
velocity -= velocity * friction * delta;
|
||||
@ -40,7 +36,7 @@ void CharacterController2D::onStart() {
|
||||
while(itColliders != allColliders.end()) {
|
||||
auto c = *itColliders;
|
||||
++itColliders;
|
||||
if(c->item == this->item) continue;
|
||||
if(c->item == this->item || c->transform->isChildOf(this->transform)) continue;
|
||||
result = c->getCollidingResult(
|
||||
velocity,
|
||||
myCollider,
|
||||
@ -66,10 +62,10 @@ void CharacterController2D::onStart() {
|
||||
}
|
||||
}
|
||||
|
||||
if(
|
||||
mathAbs<float_t>(moveAmount.x) <= 0.001f &&
|
||||
mathAbs<float_t>(moveAmount.y) <= 0.001f
|
||||
) return;
|
||||
// if(
|
||||
// mathAbs<float_t>(moveAmount.x) <= 0.001f &&
|
||||
// mathAbs<float_t>(moveAmount.y) <= 0.001f
|
||||
// ) return;
|
||||
|
||||
transform->setLocalPosition(
|
||||
transform->getLocalPosition() + (glm::vec3(moveAmount.x, 0, moveAmount.y) * delta)
|
||||
@ -81,7 +77,7 @@ void CharacterController2D::onStart() {
|
||||
while(itTriggers != allTriggers.end()) {
|
||||
auto c = *itTriggers;
|
||||
++itTriggers;
|
||||
if(c->item == this->item) continue;
|
||||
if(c->item == this->item || c->transform->isChildOf(this->transform)) continue;
|
||||
if(c->getCollidingResult(myCollider)) {
|
||||
c->eventTriggerEnter.invoke(this);
|
||||
}
|
||||
|
@ -29,8 +29,7 @@ bool_t SolidController2D::getCollidingResult(
|
||||
assertNotNull(movingObject);
|
||||
if(movement.x == 0 && movement.y == 0) return false;
|
||||
|
||||
auto localPos = movingObject->transform->getWorldPosition();
|
||||
glm::vec2 myPos(localPos.x, localPos.z);
|
||||
auto myPos = physics3Dto2D(movingObject->transform->getWorldPosition());
|
||||
|
||||
// Check what the moving object is
|
||||
switch(movingObject->getColliderType()) {
|
||||
@ -43,8 +42,7 @@ bool_t SolidController2D::getCollidingResult(
|
||||
case COLLIDER2D_TYPE_BOX: {
|
||||
auto box2 = dynamic_cast<BoxCollider*>(this->collider);
|
||||
assertNotNull(box2);
|
||||
auto localPos2 = box2->transform->getWorldPosition();
|
||||
glm::vec2 otherPos(localPos2.x, localPos2.z);
|
||||
auto otherPos = physics3Dto2D(box2->transform->getWorldPosition());
|
||||
|
||||
return boxCheckCollision(
|
||||
myPos, box1->min, box1->max,
|
||||
|
@ -32,8 +32,8 @@ bool_t TriggerController2D::getCollidingResult(Collider2D* movingObject) {
|
||||
auto box2 = dynamic_cast<BoxCollider*>(collider);
|
||||
assertNotNull(box2);
|
||||
return boxIsBoxColliding(
|
||||
box1->transform->getWorldPosition(), box1->min, box1->max,
|
||||
box2->transform->getWorldPosition(), box2->min, box2->max
|
||||
physics3Dto2D(box1->transform->getWorldPosition()), box1->min, box1->max,
|
||||
physics3Dto2D(box2->transform->getWorldPosition()), box2->min, box2->max
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@ namespace Dawn {
|
||||
class TriggerController2D : public SceneItemComponent {
|
||||
public:
|
||||
Collider2D *collider = nullptr;
|
||||
|
||||
StateEvent<CharacterController2D*> eventTriggerEnter;
|
||||
|
||||
TriggerController2D(SceneItem *i);
|
||||
|
@ -7,5 +7,41 @@
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
HurtHazard::HurtHazard(SceneItem* item) : SceneItemComponent(item) {}
|
||||
HurtHazard::HurtHazard(SceneItem* item) :
|
||||
trigger(nullptr),
|
||||
SceneItemComponent(item)
|
||||
{
|
||||
}
|
||||
|
||||
void HurtHazard::onStart() {
|
||||
this->evtTriggerEnter = [&]{};
|
||||
|
||||
useEffect([&]{
|
||||
this->evtTriggerEnter();
|
||||
if(this->trigger == nullptr) return;
|
||||
|
||||
this->evtTriggerEnter = useEvent([&](CharacterController2D *controller) {
|
||||
// Check faction(s)
|
||||
auto otherFaction = controller->item->getComponent<EntityFaction>();
|
||||
if(otherFaction != nullptr && faction == otherFaction->faction) return;
|
||||
|
||||
// Check health
|
||||
auto otherHealth = controller->item->getComponent<EntityHealth>();
|
||||
if(otherHealth == nullptr) return;
|
||||
|
||||
// Damage
|
||||
if(otherHealth->isInvincible()) return;
|
||||
|
||||
glm::vec2 back = (
|
||||
physics3Dto2D(this->transform->getWorldPosition()) -
|
||||
physics3Dto2D(controller->transform->getWorldPosition())
|
||||
);
|
||||
controller->velocity = back * -hitKnockback;
|
||||
otherHealth->damage({
|
||||
.amount = damage
|
||||
});
|
||||
|
||||
std::cout << "Trigger" << std::endl;
|
||||
}, this->trigger->eventTriggerEnter);
|
||||
}, this->trigger)();
|
||||
}
|
@ -6,13 +6,26 @@
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
#include "scene/components/entity/EntityFaction.hpp"
|
||||
#include "scene/components/physics/2d/TriggerController2D.hpp"
|
||||
#include "scene/components/entity/EntityHealth.hpp"
|
||||
#include "scene/components/entity/EntityFaction.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class HurtHazard : public SceneItemComponent {
|
||||
private:
|
||||
std::function<void()> evtTriggerEnter;
|
||||
|
||||
public:
|
||||
// @optional
|
||||
float_t hitKnockback = 20.0f;
|
||||
// @optional
|
||||
int32_t damage = 1;
|
||||
enum Faction faction = FACTION_NONE;
|
||||
// @optional
|
||||
StateProperty<TriggerController2D*> trigger;
|
||||
|
||||
HurtHazard(SceneItem* item);
|
||||
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -11,13 +11,6 @@ EntityHealth::EntityHealth(SceneItem* item) : SceneItemComponent(item) {
|
||||
|
||||
}
|
||||
|
||||
std::vector<SceneItemComponent*> EntityHealth::getDependencies() {
|
||||
return {
|
||||
this->characterController = this->item->getComponent<CharacterController2D>(),
|
||||
this->entityFaction = this->item->getComponent<EntityFaction>()
|
||||
};
|
||||
}
|
||||
|
||||
void EntityHealth::onStart() {
|
||||
// Update
|
||||
useEvent([&](float_t delta){
|
||||
@ -32,29 +25,31 @@ void EntityHealth::onStart() {
|
||||
|
||||
|
||||
// Hurt Hazard Processing
|
||||
useEvent([&](struct CharacterController2DCollisionEventInfo info) {
|
||||
if(this->isInvincible()) return;
|
||||
// if(this->characterController != nullptr) {
|
||||
// useEvent([&](struct CharacterController2DCollisionEventInfo info) {
|
||||
// if(this->isInvincible()) return;
|
||||
|
||||
auto hurtHazard = info.collider->item->getComponent<HurtHazard>();
|
||||
if(hurtHazard == nullptr) return;
|
||||
if(
|
||||
entityFaction != nullptr &&
|
||||
hurtHazard->faction == this->entityFaction->faction
|
||||
) return;
|
||||
// auto hurtHazard = info.collider->item->getComponent<HurtHazard>();
|
||||
// if(hurtHazard == nullptr) return;
|
||||
// if(
|
||||
// entityFaction != nullptr &&
|
||||
// hurtHazard->faction == this->entityFaction->faction
|
||||
// ) return;
|
||||
|
||||
glm::vec2 back = glm::vec2(
|
||||
info.collider->transform->getLocalPosition().x,
|
||||
info.collider->transform->getLocalPosition().z
|
||||
) - glm::vec2(
|
||||
this->transform->getLocalPosition().x,
|
||||
this->transform->getLocalPosition().z
|
||||
);
|
||||
// glm::vec2 back = glm::vec2(
|
||||
// info.collider->transform->getLocalPosition().x,
|
||||
// info.collider->transform->getLocalPosition().z
|
||||
// ) - glm::vec2(
|
||||
// this->transform->getLocalPosition().x,
|
||||
// this->transform->getLocalPosition().z
|
||||
// );
|
||||
|
||||
this->characterController->velocity = back * -hitKnockback;
|
||||
this->damage({
|
||||
.amount = hurtHazard->damage
|
||||
});
|
||||
}, this->characterController->eventCollision);
|
||||
// this->characterController->velocity = back * -hitKnockback;
|
||||
// this->damage({
|
||||
// .amount = hurtHazard->damage
|
||||
// });
|
||||
// }, this->characterController->eventCollision);
|
||||
// }
|
||||
}
|
||||
|
||||
bool_t EntityHealth::isInvincible() {
|
||||
|
@ -5,9 +5,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
#include "scene/components/entity/EntityFaction.hpp"
|
||||
#include "scene/components/physics/2d/CharacterController2D.hpp"
|
||||
#include "scene/components/HurtHazard.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
struct DamageInformation {
|
||||
@ -17,10 +15,6 @@ namespace Dawn {
|
||||
};
|
||||
|
||||
class EntityHealth : public SceneItemComponent {
|
||||
protected:
|
||||
EntityFaction *entityFaction = nullptr;
|
||||
CharacterController2D *characterController = nullptr;
|
||||
|
||||
public:
|
||||
// @optional
|
||||
int32_t health = 10;
|
||||
@ -30,11 +24,8 @@ namespace Dawn {
|
||||
float_t invincibleTime = 0.0f;
|
||||
// @optional
|
||||
float_t stunTime = 0.0f;
|
||||
// @optional
|
||||
float_t hitKnockback = 20.0f;
|
||||
|
||||
EntityHealth(SceneItem* item);
|
||||
std::vector<SceneItemComponent*> getDependencies() override;
|
||||
void onStart() override;
|
||||
|
||||
/**
|
||||
|
@ -24,10 +24,8 @@ namespace Dawn {
|
||||
|
||||
auto player = Player::create(this);
|
||||
|
||||
auto wall = Wall::create(this);
|
||||
|
||||
// auto urchin = Urchin::create(this);
|
||||
// urchin->transform.setLocalPosition(glm::vec3(0, 0, -5));
|
||||
auto urchin = Urchin::create(this);
|
||||
urchin->transform.setLocalPosition(glm::vec3(0, 0, -5));
|
||||
|
||||
// auto crab = Crab::create(this);
|
||||
// crab->transform.setLocalPosition(glm::vec3(3, 0, 0));
|
||||
|
@ -64,7 +64,15 @@ struct PrefabComponentParserRuleset PrefabRegistry::getRuleset(std::string type)
|
||||
|
||||
// Find each instance of "@optional" when it's used within a comment
|
||||
// e.g. // @optional or /* @optional */ in the string data.
|
||||
std::regex regex("^\\s*(?:\\/\\/|\\/\\*){1}\\s*\\@optional\\s*(?:\\*\\/)?\\s*$", std::regex_constants::ECMAScript | std::regex_constants::multiline);
|
||||
|
||||
std::regex_constants::syntax_option_type regexFlags;
|
||||
#if defined(__GNUC__)
|
||||
regexFlags = std::regex_constants::ECMAScript | std::regex_constants::multiline;
|
||||
#else
|
||||
regexFlags = std::regex_constants::ECMAScript;
|
||||
#endif
|
||||
|
||||
std::regex regex("^\\s*(?:\\/\\/|\\/\\*){1}\\s*\\@optional\\s*(?:\\*\\/)?\\s*$", regexFlags);
|
||||
std::sregex_iterator it(data.begin(), data.end(), regex);
|
||||
std::sregex_iterator end;
|
||||
while(it != end) {
|
||||
@ -92,7 +100,7 @@ struct PrefabComponentParserRuleset PrefabRegistry::getRuleset(std::string type)
|
||||
auto variableString = data.substr(varStart, varLength);
|
||||
|
||||
// Now (should) be able to extract the type;
|
||||
std::regex regex2("^\\s*(?:[\\S]+<)?([\\w*:_\\s]+)(?:[\\S]+)? (\\**[\\w]+)\\s*$", std::regex_constants::ECMAScript | std::regex_constants::multiline);
|
||||
std::regex regex2("^\\s*(?:[\\S]+<)?([\\w*:_\\s]+)(?:[\\S]+)? (\\**[\\w]+)\\s*$", regexFlags);
|
||||
std::smatch match;
|
||||
if(!std::regex_search(variableString, match, regex2)) {
|
||||
std::cout << "Failed to extract type and name from variable string! " << variableString << std::endl;
|
||||
|
Reference in New Issue
Block a user