add radial triggers

This commit is contained in:
MihailRis 2024-07-04 06:09:29 +03:00
parent e6c3775286
commit 736e5b95b6
9 changed files with 117 additions and 44 deletions

View File

@ -1,6 +1,7 @@
{ {
"hitbox": [0.2, 0.125, 0.2], "hitbox": [0.2, 0.125, 0.2],
"triggers": [ "triggers": [
["aabb", -0.2, -0.2, -0.2, 0.2, 0.2, 0.2] ["aabb", -0.2, -0.2, -0.2, 0.2, 0.2, 0.2],
["radius", 1.6]
] ]
} }

View File

@ -4,6 +4,7 @@ local rig = entity.modeltree
inair = true inair = true
ready = false ready = false
target = -1
local dropitem = ARGS.item local dropitem = ARGS.item
local scale = {1, 1, 1} local scale = {1, 1, 1}
@ -60,11 +61,20 @@ function on_fall()
end end
function on_trigger_enter(index, oid) function on_trigger_enter(index, oid)
if ready and oid == 0 then if ready and oid == 0 and index == 0 then
entity:despawn() entity:despawn()
inventory.add(player.get_inventory(oid), dropitem.id, dropitem.count) inventory.add(player.get_inventory(oid), dropitem.id, dropitem.count)
audio.play_sound_2d("events/pickup", 0.5, 0.8+math.random()*0.4, "regular") audio.play_sound_2d("events/pickup", 0.5, 0.8+math.random()*0.4, "regular")
end end
if index == 1 and ready and oid == 0 then
target = oid
end
end
function on_trigger_exit(index, oid)
if oid == target and index == 1 then
target = -1
end
end end
function on_update() function on_update()
@ -79,4 +89,10 @@ function on_update()
mat4.scale(matrix, scale, matrix) mat4.scale(matrix, scale, matrix)
rig:set_matrix(0, matrix) rig:set_matrix(0, matrix)
end end
if target ~= -1 then
local dir = vec3.sub({player.get_pos(target)}, tsf:get_pos())
vec3.normalize(dir, dir)
vec3.mul(dir, 10.0, dir)
body:set_vel(dir)
end
end end

View File

@ -14,7 +14,6 @@ function on_hud_open()
local pvel = {player.get_vel(pid)} local pvel = {player.get_vel(pid)}
local ppos = vec3.add({player.get_pos(pid)}, {0, 0.7, 0}) local ppos = vec3.add({player.get_pos(pid)}, {0, 0.7, 0})
local throw_force = vec3.mul(player.get_dir(pid), DROP_FORCE) local throw_force = vec3.mul(player.get_dir(pid), DROP_FORCE)
local drop = entities.spawn("base:drop", ppos, {item={ local drop = entities.spawn("base:drop", ppos, {item={
id=itemid, id=itemid,
count=1 count=1

View File

@ -320,10 +320,12 @@ void ContentLoader::loadEntity(EntityDef& def, const std::string& name, const fs
if (auto triggerarr = triggersarr->list(i)) { if (auto triggerarr = triggersarr->list(i)) {
auto triggerType = triggerarr->str(0); auto triggerType = triggerarr->str(0);
if (triggerType == "aabb") { if (triggerType == "aabb") {
def.boxTriggers.push_back({ def.boxTriggers.push_back({i, {
{triggerarr->num(1), triggerarr->num(2), triggerarr->num(3)}, {triggerarr->num(1), triggerarr->num(2), triggerarr->num(3)},
{triggerarr->num(4), triggerarr->num(5), triggerarr->num(6)} {triggerarr->num(4), triggerarr->num(5), triggerarr->num(6)}
}); }});
} else if (triggerType == "radius") {
def.radialTriggers.push_back({i, triggerarr->num(1)});
} else { } else {
logger.error() << name << ": trigger #" << i << " - unknown type " logger.error() << name << ": trigger #" << i << " - unknown type "
<< util::quote(triggerType); << util::quote(triggerType);

View File

@ -8,7 +8,7 @@ struct AABB {
glm::vec3 a {0.0f}; glm::vec3 a {0.0f};
glm::vec3 b {1.0f, 1.0f, 1.0f}; glm::vec3 b {1.0f, 1.0f, 1.0f};
AABB() {} AABB() = default;
AABB(glm::vec3 size) : a(0.0f), b(size) { AABB(glm::vec3 size) : a(0.0f), b(size) {
} }

View File

@ -42,6 +42,17 @@ void Entity::setRig(rigging::RigConfig* rigConfig) {
Entities::Entities(Level* level) : level(level) { Entities::Entities(Level* level) : level(level) {
} }
template<void(*callback)(const Entity&, size_t, entityid_t)>
static triggercallback create_trigger_callback(Entities* entities) {
return [=](auto entityid, auto index, auto otherid) {
if (auto entity = entities->get(entityid)) {
if (entity->isValid()) {
callback(*entity, index, otherid);
}
}
};
}
entityid_t Entities::spawn( entityid_t Entities::spawn(
Assets* assets, Assets* assets,
EntityDef& def, EntityDef& def,
@ -59,28 +70,25 @@ entityid_t Entities::spawn(
registry.emplace<Transform>(entity, pos, size, glm::mat3(1.0f)); registry.emplace<Transform>(entity, pos, size, glm::mat3(1.0f));
auto& body = registry.emplace<Rigidbody>( auto& body = registry.emplace<Rigidbody>(
entity, true, Hitbox {pos, def.hitbox}, std::vector<Trigger>{}); entity, true, Hitbox {pos, def.hitbox}, std::vector<Trigger>{});
for (auto& box : def.boxTriggers) {
body.triggers.emplace_back(Trigger{ body.triggers.resize(def.radialTriggers.size() + def.boxTriggers.size());
true, for (auto& [i, box] : def.boxTriggers) {
id, TriggerParams params {};
box, params.aabb = box;
AABB{}, body.triggers[i] = Trigger {
{}, true, TriggerType::AABB, i, id, params, params, {}, {},
{}, create_trigger_callback<scripting::on_trigger_enter>(this),
[=](auto entityid, auto index, auto otherid) { create_trigger_callback<scripting::on_trigger_exit>(this)
if (auto entity = get(entityid)) { };
if (entity->isValid()) { }
scripting::on_trigger_enter(*entity, index, otherid); for (auto& [i, radius] : def.radialTriggers) {
} TriggerParams params {};
} params.radial = glm::vec4(radius);
}, body.triggers[i] = Trigger {
[=](auto entityid, auto index, auto otherid) { true, TriggerType::RADIUS, i, id, params, params, {}, {},
if (auto entity = get(entityid)) { create_trigger_callback<scripting::on_trigger_enter>(this),
if (entity->isValid()) { create_trigger_callback<scripting::on_trigger_exit>(this)
scripting::on_trigger_exit(*entity, index, otherid); };
}
}
}});
} }
auto& scripting = registry.emplace<Scripting>( auto& scripting = registry.emplace<Scripting>(
entity, entity_funcs_set {}, nullptr); entity, entity_funcs_set {}, nullptr);
@ -135,8 +143,21 @@ void Entities::preparePhysics() {
} }
trigger.prevEntered = trigger.nextEntered; trigger.prevEntered = trigger.nextEntered;
trigger.nextEntered.clear(); trigger.nextEntered.clear();
trigger.calculated = trigger.aabb;
trigger.calculated.transform(transform.combined); switch (trigger.type) {
case TriggerType::AABB:
trigger.calculated.aabb = trigger.params.aabb;
trigger.calculated.aabb.transform(transform.combined);
break;
case TriggerType::RADIUS:
trigger.calculated.radial = glm::vec4(
rigidbody.hitbox.position.x,
rigidbody.hitbox.position.y,
rigidbody.hitbox.position.z,
trigger.params.radial.w*
trigger.params.radial.w);
break;
}
triggers.push_back(&trigger); triggers.push_back(&trigger);
} }
} }
@ -204,9 +225,11 @@ void Entities::renderDebug(LineBatch& batch, const Frustum& frustum) {
batch.box(hitbox.position, hitbox.halfsize * 2.0f, glm::vec4(1.0f)); batch.box(hitbox.position, hitbox.halfsize * 2.0f, glm::vec4(1.0f));
for (auto& trigger : rigidbody.triggers) { for (auto& trigger : rigidbody.triggers) {
if (trigger.type != TriggerType::AABB)
continue;
batch.box( batch.box(
trigger.calculated.center(), trigger.calculated.aabb.center(),
trigger.calculated.size(), trigger.calculated.aabb.size(),
glm::vec4(1.0f, 1.0f, 0.0f, 1.0f)); glm::vec4(1.0f, 1.0f, 0.0f, 1.0f));
} }
} }

View File

@ -18,7 +18,8 @@ struct EntityDef {
std::string scriptName = name.substr(name.find(':')+1); std::string scriptName = name.substr(name.find(':')+1);
glm::vec3 hitbox {0.5f}; glm::vec3 hitbox {0.5f};
std::vector<AABB> boxTriggers {}; std::vector<std::pair<size_t, AABB>> boxTriggers {};
std::vector<std::pair<size_t, float>> radialTriggers {};
std::string rigName = name.substr(name.find(":")+1); std::string rigName = name.substr(name.find(":")+1);
struct { struct {

View File

@ -8,15 +8,32 @@
#include <functional> #include <functional>
#include <glm/glm.hpp> #include <glm/glm.hpp>
enum class TriggerType {
AABB,
RADIUS,
};
union TriggerParams {
AABB aabb;
glm::vec4 radial; // x,y,z calculated entity coords + w - radius
constexpr TriggerParams() : aabb() {
}
};
using triggercallback = std::function<void(entityid_t, size_t, entityid_t)>;
struct Trigger { struct Trigger {
bool enabled = true; bool enabled = true;
TriggerType type;
size_t index;
entityid_t entity; entityid_t entity;
AABB aabb; TriggerParams params;
AABB calculated; TriggerParams calculated;
std::set<entityid_t> prevEntered; std::set<entityid_t> prevEntered;
std::set<entityid_t> nextEntered; std::set<entityid_t> nextEntered;
std::function<void(entityid_t, size_t, entityid_t)> enterCallback; triggercallback enterCallback;
std::function<void(entityid_t, size_t, entityid_t)> exitCallback; triggercallback exitCallback;
}; };
struct Hitbox { struct Hitbox {

View File

@ -7,13 +7,15 @@
#include "../voxels/voxel.hpp" #include "../voxels/voxel.hpp"
#include <iostream> #include <iostream>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/norm.hpp>
const float E = 0.03f; const float E = 0.03f;
const float MAX_FIX = 0.1f; const float MAX_FIX = 0.1f;
PhysicsSolver::PhysicsSolver(glm::vec3 gravity) : gravity(gravity) { PhysicsSolver::PhysicsSolver(glm::vec3 gravity) : gravity(gravity) {
} }
#include "../util/timeutil.hpp"
void PhysicsSolver::step( void PhysicsSolver::step(
Chunks* chunks, Chunks* chunks,
Hitbox* hitbox, Hitbox* hitbox,
@ -85,15 +87,27 @@ void PhysicsSolver::step(
aabb.a = hitbox->position - hitbox->halfsize; aabb.a = hitbox->position - hitbox->halfsize;
aabb.b = hitbox->position + hitbox->halfsize; aabb.b = hitbox->position + hitbox->halfsize;
for (size_t i = 0; i < triggers.size(); i++) { for (size_t i = 0; i < triggers.size(); i++) {
auto& trigger = triggers[i]; auto& trigger = *triggers[i];
if (trigger->entity == entity) { if (trigger.entity == entity) {
continue; continue;
} }
if (aabb.intersect(trigger->calculated)) {
if (trigger->prevEntered.find(entity) == trigger->prevEntered.end()) { bool triggered = false;
trigger->enterCallback(trigger->entity, i, entity); switch (trigger.type) {
case TriggerType::AABB:
triggered = aabb.intersect(trigger.calculated.aabb);
break;
case TriggerType::RADIUS:
triggered = glm::distance2(
hitbox->position, glm::vec3(trigger.calculated.radial))
< trigger.calculated.radial.w;
break;
}
if (triggered) {
if (trigger.prevEntered.find(entity) == trigger.prevEntered.end()) {
trigger.enterCallback(trigger.entity, trigger.index, entity);
} }
trigger->nextEntered.insert(entity); trigger.nextEntered.insert(entity);
} }
} }
} }