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],
"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
ready = false
target = -1
local dropitem = ARGS.item
local scale = {1, 1, 1}
@ -60,11 +61,20 @@ function on_fall()
end
function on_trigger_enter(index, oid)
if ready and oid == 0 then
if ready and oid == 0 and index == 0 then
entity:despawn()
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")
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
function on_update()
@ -79,4 +89,10 @@ function on_update()
mat4.scale(matrix, scale, matrix)
rig:set_matrix(0, matrix)
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

View File

@ -14,7 +14,6 @@ function on_hud_open()
local pvel = {player.get_vel(pid)}
local ppos = vec3.add({player.get_pos(pid)}, {0, 0.7, 0})
local throw_force = vec3.mul(player.get_dir(pid), DROP_FORCE)
local drop = entities.spawn("base:drop", ppos, {item={
id=itemid,
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)) {
auto triggerType = triggerarr->str(0);
if (triggerType == "aabb") {
def.boxTriggers.push_back({
def.boxTriggers.push_back({i, {
{triggerarr->num(1), triggerarr->num(2), triggerarr->num(3)},
{triggerarr->num(4), triggerarr->num(5), triggerarr->num(6)}
});
}});
} else if (triggerType == "radius") {
def.radialTriggers.push_back({i, triggerarr->num(1)});
} else {
logger.error() << name << ": trigger #" << i << " - unknown type "
<< util::quote(triggerType);

View File

@ -8,7 +8,7 @@ struct AABB {
glm::vec3 a {0.0f};
glm::vec3 b {1.0f, 1.0f, 1.0f};
AABB() {}
AABB() = default;
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) {
}
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(
Assets* assets,
EntityDef& def,
@ -59,28 +70,25 @@ entityid_t Entities::spawn(
registry.emplace<Transform>(entity, pos, size, glm::mat3(1.0f));
auto& body = registry.emplace<Rigidbody>(
entity, true, Hitbox {pos, def.hitbox}, std::vector<Trigger>{});
for (auto& box : def.boxTriggers) {
body.triggers.emplace_back(Trigger{
true,
id,
box,
AABB{},
{},
{},
[=](auto entityid, auto index, auto otherid) {
if (auto entity = get(entityid)) {
if (entity->isValid()) {
scripting::on_trigger_enter(*entity, index, otherid);
}
}
},
[=](auto entityid, auto index, auto otherid) {
if (auto entity = get(entityid)) {
if (entity->isValid()) {
scripting::on_trigger_exit(*entity, index, otherid);
}
}
}});
body.triggers.resize(def.radialTriggers.size() + def.boxTriggers.size());
for (auto& [i, box] : def.boxTriggers) {
TriggerParams params {};
params.aabb = box;
body.triggers[i] = Trigger {
true, TriggerType::AABB, i, id, params, params, {}, {},
create_trigger_callback<scripting::on_trigger_enter>(this),
create_trigger_callback<scripting::on_trigger_exit>(this)
};
}
for (auto& [i, radius] : def.radialTriggers) {
TriggerParams params {};
params.radial = glm::vec4(radius);
body.triggers[i] = Trigger {
true, TriggerType::RADIUS, i, id, params, params, {}, {},
create_trigger_callback<scripting::on_trigger_enter>(this),
create_trigger_callback<scripting::on_trigger_exit>(this)
};
}
auto& scripting = registry.emplace<Scripting>(
entity, entity_funcs_set {}, nullptr);
@ -135,8 +143,21 @@ void Entities::preparePhysics() {
}
trigger.prevEntered = trigger.nextEntered;
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);
}
}
@ -204,9 +225,11 @@ void Entities::renderDebug(LineBatch& batch, const Frustum& frustum) {
batch.box(hitbox.position, hitbox.halfsize * 2.0f, glm::vec4(1.0f));
for (auto& trigger : rigidbody.triggers) {
if (trigger.type != TriggerType::AABB)
continue;
batch.box(
trigger.calculated.center(),
trigger.calculated.size(),
trigger.calculated.aabb.center(),
trigger.calculated.aabb.size(),
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);
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);
struct {

View File

@ -8,15 +8,32 @@
#include <functional>
#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 {
bool enabled = true;
TriggerType type;
size_t index;
entityid_t entity;
AABB aabb;
AABB calculated;
TriggerParams params;
TriggerParams calculated;
std::set<entityid_t> prevEntered;
std::set<entityid_t> nextEntered;
std::function<void(entityid_t, size_t, entityid_t)> enterCallback;
std::function<void(entityid_t, size_t, entityid_t)> exitCallback;
triggercallback enterCallback;
triggercallback exitCallback;
};
struct Hitbox {

View File

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