add triggers

This commit is contained in:
MihailRis 2024-06-30 16:25:08 +03:00
parent 50c714692a
commit 5769be8ec8
15 changed files with 239 additions and 64 deletions

View File

@ -0,0 +1,28 @@
local tsf = entity.transform
local body = entity.rigidbody
inair = true
ready = false
function on_grounded(force)
tsf:set_rot(mat4.rotate({0, 1, 0}, math.random()*360))
inair = false
ready = true
end
function on_fall()
inair = true
end
function on_trigger_enter(index, oid)
if ready then
entity:despawn()
end
end
function on_update()
if inair then
tsf:set_rot(mat4.rotate(tsf:get_rot(), {0, 1, 0}, math.random()*12))
tsf:set_rot(mat4.rotate(tsf:get_rot(), {0, 0, 1}, math.random()*12))
end
end

View File

@ -1,23 +0,0 @@
inair = true
function on_grounded(force)
entity.transform:set_rot(mat4.rotate({0, 1, 0}, math.random()*360))
inair = false
end
function on_fall()
inair = true
end
function on_update()
local tsf = entity.transform
local body = entity.rigidbody
if inair then
tsf:set_rot(mat4.rotate(tsf:get_rot(), {0, 1, 0}, math.random()*12))
tsf:set_rot(mat4.rotate(tsf:get_rot(), {0, 0, 1}, math.random()*12))
end
local dir = vec3.sub({player.get_pos(hud.get_player())}, tsf:get_pos())
vec3.normalize(dir, dir)
vec3.mul(dir, time.delta()*50.0, dir)
--body:set_vel(vec3.add(rigidbody:get_vel(), dir))
end

View File

@ -3,15 +3,15 @@ local DROP_INIT_VEL = {0, 3, 0}
function on_hud_open()
input.add_callback("player.drop", function ()
for i=1,5 do
for i=1,80 do
local pid = hud.get_player()
local pvel = {player.get_vel(pid)}
local ppos = vec3.add({player.get_pos(pid)}, {0, 0.7, 0})
local throw_force = vec3.mul(vec3.add(player.get_dir(pid),
{
math.random() - 0.5,
math.random() - 0.5,
math.random() - 0.5
(math.random() - 0.5) * 5,
(math.random() - 0.5) * 5,
(math.random() - 0.5) * 5
}), DROP_FORCE)
local drop = entity.spawn("base:drop", ppos)

View File

@ -322,9 +322,9 @@ void ContentLoader::loadEntity(EntityDef& def, const std::string& full, const st
auto configFile = folder/fs::path("entities/"+name+".json");
if (fs::exists(configFile)) loadEntity(def, full, configFile);
auto scriptfile = folder/fs::path("scripts/"+def.scriptName+".lua");
auto scriptfile = folder/fs::path("scripts/components/"+def.scriptName+".lua");
if (fs::is_regular_file(scriptfile)) {
scripting::load_entity_script(env, def, scriptfile);
scripting::load_entity_component(env, def, scriptfile);
}
}

View File

@ -233,7 +233,7 @@ void WorldRenderer::renderLines(Camera* camera, Shader* linesShader) {
renderBlockSelection();
}
if (player->debug) {
level->entities->renderDebug(*lineBatch);
level->entities->renderDebug(*lineBatch, *frustumCulling);
}
lineBatch->render();
}

View File

@ -30,15 +30,6 @@ void LevelController::update(float delta, bool input, bool pause) {
settings.chunks.loadDistance.get() +
settings.chunks.padding.get() * 2);
chunks->update(settings.chunks.loadSpeed.get());
player->update(delta, input, pause);
// erease null pointers
level->objects.erase(
std::remove_if(
level->objects.begin(), level->objects.end(),
[](auto obj) { return obj == nullptr; }),
level->objects.end()
);
level->entities->clean();
if (!pause) {
@ -52,6 +43,15 @@ void LevelController::update(float delta, bool input, bool pause) {
level->entities->updatePhysics(delta);
level->entities->update();
}
player->update(delta, input, pause);
// erease null pointers
level->objects.erase(
std::remove_if(
level->objects.begin(), level->objects.end(),
[](auto obj) { return obj == nullptr; }),
level->objects.end()
);
}
void LevelController::saveWorld() {

View File

@ -273,6 +273,8 @@ scriptenv scripting::on_entity_spawn(const EntityDef& def, entityid_t eid, entit
funcsset.on_grounded = lua::hasfield(L, "on_grounded");
funcsset.on_fall = lua::hasfield(L, "on_fall");
funcsset.on_despawn = lua::hasfield(L, "on_despawn");
funcsset.on_trigger_enter = lua::hasfield(L, "on_trigger_enter");
funcsset.on_trigger_exit = lua::hasfield(L, "on_trigger_exit");
lua::pop(L, 2);
return entityenv;
}
@ -325,6 +327,29 @@ bool scripting::on_entity_fall(const Entity& entity) {
return true;
}
void scripting::on_trigger_enter(const Entity& entity, size_t index, entityid_t oid) {
const auto& script = entity.getScripting();
if (script.funcsset.on_trigger_enter) {
process_entity_callback(script.env, "on_trigger_enter", [index, oid](auto L) {
lua::pushinteger(L, index);
lua::pushinteger(L, oid);
return 2;
});
}
}
void scripting::on_trigger_exit(const Entity& entity, size_t index, entityid_t oid) {
const auto& script = entity.getScripting();
if (script.funcsset.on_trigger_exit) {
process_entity_callback(script.env, "on_trigger_exit", [index, oid](auto L) {
lua::pushinteger(L, index);
lua::pushinteger(L, oid);
return 2;
});
}
}
void scripting::on_entities_update() {
auto L = lua::get_main_thread();
lua::get_from(L, STDCOMP, "update", true);
@ -415,10 +440,10 @@ void scripting::load_item_script(const scriptenv& senv, const std::string& prefi
funcsset.on_block_break_by = register_event(env, "on_block_break_by", prefix+".blockbreakby");
}
void scripting::load_entity_script(const scriptenv& penv, const EntityDef& def, const fs::path& file) {
void scripting::load_entity_component(const scriptenv& penv, const EntityDef& def, const fs::path& file) {
auto L = lua::get_main_thread();
std::string src = files::read_string(file);
logger.info() << "script (entity) " << file.u8string();
logger.info() << "script (component) " << file.u8string();
lua::loadbuffer(L, 0, src, file.u8string());
lua::store_in(L, lua::CHUNKS_TABLE, def.scriptName);
}

View File

@ -81,6 +81,8 @@ namespace scripting {
bool on_entity_grounded(const Entity& entity, float force);
bool on_entity_fall(const Entity& entity);
void on_entities_update();
void on_trigger_enter(const Entity& entity, size_t index, entityid_t oid);
void on_trigger_exit(const Entity& entity, size_t index, entityid_t oid);
/// @brief Called on UI view show
void on_ui_open(
@ -115,7 +117,7 @@ namespace scripting {
const fs::path& file,
item_funcs_set& funcsset);
void load_entity_script(
void load_entity_component(
const scriptenv& env,
const EntityDef& def,
const fs::path& file);

View File

@ -6,13 +6,16 @@
/// @brief Axis Aligned Bounding Box
struct AABB {
glm::vec3 a {0.0f};
glm::vec3 b {1.0f};
glm::vec3 b {1.0f, 1.0f, 1.0f};
AABB() {}
AABB(glm::vec3 size) : a(0.0f), b(size) {
}
AABB(glm::vec3 pos, glm::vec3 size) : a(pos), b(size) {
}
/// @brief Get AABB point with minimal x,y,z
inline glm::vec3 min() const {
return glm::min(a, b);
@ -59,6 +62,44 @@ struct AABB {
return !(pos.x < p.x || pos.y < p.y || pos.z < p.z ||
pos.x >= p.x+s.x || pos.y >= p.y+s.y || pos.z >= p.z+s.z);
}
void fix() {
auto beg = min();
auto end = max();
a = beg;
b = end;
}
inline void addPoint(glm::vec3 p) {
a = glm::min(a, p);
b = glm::max(b, p);
}
/// TODO: optimize
void transform(const glm::mat4& matrix) {
auto pa = a;
auto pb = b;
a = matrix * glm::vec4(a, 1.0f);
b = matrix * glm::vec4(b, 1.0f);
fix();
addPoint(matrix * glm::vec4(pb.x, pa.y, pa.z, 1.0f));
addPoint(matrix * glm::vec4(pb.x, pb.y, pa.z, 1.0f));
addPoint(matrix * glm::vec4(pb.x, pb.y, pb.z, 1.0f));
addPoint(matrix * glm::vec4(pa.x, pb.y, pa.z, 1.0f));
addPoint(matrix * glm::vec4(pa.x, pa.y, pb.z, 1.0f));
addPoint(matrix * glm::vec4(pb.x, pa.y, pb.z, 1.0f));
}
inline bool intersect(const AABB& aabb) {
return (
a.x <= aabb.b.x &&
b.x >= aabb.a.x &&
a.y <= aabb.b.y &&
b.y >= aabb.a.y &&
a.z <= aabb.b.z &&
b.z >= aabb.a.z
);
}
};
#endif // MATHS_AABB_HPP_

View File

@ -35,7 +35,22 @@ entityid_t Entities::spawn(EntityDef& def, glm::vec3 pos) {
auto id = nextID++;
registry.emplace<EntityId>(entity, static_cast<entityid_t>(id), def);
registry.emplace<Transform>(entity, pos, size/4.0f, glm::mat3(1.0f));
registry.emplace<Rigidbody>(entity, true, Hitbox {pos, def.hitbox});
registry.emplace<Rigidbody>(entity, true, Hitbox {pos, def.hitbox}, std::vector<Trigger>{
{true, id, AABB {glm::vec3{-1.0f, -1.0f, -1.0f}, glm::vec3{1.0f, 1.0f, 1.0f}}, {}, {}, {},
[=](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);
}
}
}}
});
auto& scripting = registry.emplace<Scripting>(entity, entity_funcs_set {}, nullptr);
entities[id] = entity;
scripting.env = scripting::on_entity_spawn(def, id, scripting.funcsset);
@ -44,24 +59,50 @@ entityid_t Entities::spawn(EntityDef& def, glm::vec3 pos) {
void Entities::despawn(entityid_t id) {
if (auto entity = get(id)) {
scripting::on_entity_despawn(entity->getDef(), *entity);
registry.destroy(get(id)->getHandler());
auto& eid = entity->getID();
if (!eid.destroyFlag) {
eid.destroyFlag = true;
scripting::on_entity_despawn(entity->getDef(), *entity);
}
}
}
void Entities::clean() {
for (auto it = entities.begin(); it != entities.end();) {
if (registry.valid(it->second)) {
if (!registry.get<EntityId>(it->second).destroyFlag) {
++it;
} else {
registry.destroy(it->second);
it = entities.erase(it);
}
}
}
#include "../util/timeutil.hpp"
void Entities::updatePhysics(float delta){
auto view = registry.view<EntityId, Transform, Rigidbody>();
auto physics = level->physics.get();
{
std::vector<Trigger*> triggers;
for (auto [entity, eid, transform, rigidbody] : view.each()) {
if (!rigidbody.enabled) {
continue;
}
for (size_t i = 0; i < rigidbody.triggers.size(); i++) {
auto& trigger = rigidbody.triggers[i];
for (auto oid : trigger.prevEntered) {
if (trigger.nextEntered.find(oid) == trigger.nextEntered.end()) {
trigger.exitCallback(trigger.entity, i, oid);
}
}
trigger.prevEntered = trigger.nextEntered;
trigger.nextEntered.clear();
trigger.calculated = trigger.aabb;
trigger.calculated.transform(transform.combined);
triggers.push_back(&trigger);
}
}
physics->setTriggers(std::move(triggers));
}
for (auto [entity, eid, transform, rigidbody] : view.each()) {
if (!rigidbody.enabled) {
continue;
@ -76,11 +117,11 @@ void Entities::updatePhysics(float delta){
10,
false,
1.0f,
true
true,
eid.uid
);
hitbox.linearDamping = hitbox.grounded * 24;
transform.pos = hitbox.position;
//transform.rot = glm::rotate(glm::mat4(transform.rot), delta, glm::vec3(0, 1, 0));
if (hitbox.grounded && !grounded) {
scripting::on_entity_grounded(*get(eid.uid), glm::length(prevVel-hitbox.velocity));
}
@ -92,14 +133,27 @@ void Entities::updatePhysics(float delta){
void Entities::update() {
scripting::on_entities_update();
auto view = registry.view<Transform>();
for (auto [entity, transform] : view.each()) {
transform.refresh();
}
}
void Entities::renderDebug(LineBatch& batch) {
void Entities::renderDebug(LineBatch& batch, Frustum& frustum) {
batch.lineWidth(1.0f);
auto view = registry.view<Transform, Rigidbody>();
for (auto [entity, transform, rigidbody] : view.each()) {
const auto& hitbox = rigidbody.hitbox;
const auto& pos = transform.pos;
const auto& size = transform.size;
if (!frustum.isBoxVisible(pos-size, pos+size)) {
continue;
}
batch.box(hitbox.position, hitbox.halfsize * 2.0f, glm::vec4(1.0f));
for (auto& trigger : rigidbody.triggers) {
batch.box(trigger.calculated.center(), trigger.calculated.size(), glm::vec4(1.0f, 1.0f, 0.0f, 1.0f));
}
}
}
@ -110,7 +164,6 @@ void Entities::render(Assets* assets, ModelBatch& batch, Frustum& frustum) {
const auto& pos = transform.pos;
const auto& size = transform.size;
if (frustum.isBoxVisible(pos-size, pos+size)) {
transform.refresh();
batch.pushMatrix(transform.combined);
batch.draw(model);
batch.popMatrix();

View File

@ -4,6 +4,7 @@
#include "../typedefs.hpp"
#include "../physics/Hitbox.hpp"
#include <vector>
#include <optional>
#include <glm/glm.hpp>
#include <unordered_map>
@ -14,6 +15,8 @@ struct entity_funcs_set {
bool on_despawn : 1;
bool on_grounded : 1;
bool on_fall : 1;
bool on_trigger_enter : 1;
bool on_trigger_exit : 1;
};
struct EntityDef;
@ -21,6 +24,7 @@ struct EntityDef;
struct EntityId {
entityid_t uid;
const EntityDef& def;
bool destroyFlag = false;
};
struct Transform {
@ -35,6 +39,7 @@ struct Transform {
struct Rigidbody {
bool enabled = true;
Hitbox hitbox;
std::vector<Trigger> triggers;
};
struct Scripting {
@ -59,8 +64,8 @@ public:
Entity(Entities& entities, entityid_t id, entt::registry& registry, const entt::entity entity)
: entities(entities), id(id), registry(registry), entity(entity) {}
entityid_t getID() const {
return id;
EntityId& getID() const {
return registry.get<EntityId>(entity);
}
bool isValid() const {
@ -106,7 +111,7 @@ public:
void updatePhysics(float delta);
void update();
void renderDebug(LineBatch& batch);
void renderDebug(LineBatch& batch, Frustum& frustum);
void render(Assets* assets, ModelBatch& batch, Frustum& frustum);
entityid_t spawn(EntityDef& def, glm::vec3 pos);

View File

@ -88,7 +88,8 @@ void Player::updateInput(
substeps,
crouch,
flight ? 0.0f : 1.0f,
!noclip
!noclip,
0
);
if (flight && hitbox->grounded) {

View File

@ -1,8 +1,24 @@
#ifndef PHYSICS_HITBOX_HPP_
#define PHYSICS_HITBOX_HPP_
#include "../maths/aabb.hpp"
#include "../typedefs.hpp"
#include <set>
#include <functional>
#include <glm/glm.hpp>
struct Trigger {
bool enabled = true;
entityid_t entity;
AABB aabb;
AABB 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;
};
struct Hitbox {
glm::vec3 position;
glm::vec3 halfsize;

View File

@ -6,12 +6,14 @@
#include "../voxels/Chunks.hpp"
#include "../voxels/voxel.hpp"
#include <iostream>
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,
@ -19,7 +21,8 @@ void PhysicsSolver::step(
uint substeps,
bool shifting,
float gravityScale,
bool collisions
bool collisions,
entityid_t entity
) {
float dt = delta / static_cast<float>(substeps);
float linearDamping = hitbox->linearDamping;
@ -78,6 +81,21 @@ void PhysicsSolver::step(
hitbox->grounded = true;
}
}
AABB aabb;
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) {
continue;
}
if (aabb.intersect(trigger->calculated)) {
if (trigger->prevEntered.find(entity) == trigger->prevEntered.end()) {
trigger->enterCallback(trigger->entity, i, entity);
}
trigger->nextEntered.insert(entity);
}
}
}
void PhysicsSolver::colisionCalc(

View File

@ -1,17 +1,21 @@
#ifndef PHYSICS_PHYSICSSOLVER_HPP_
#define PHYSICS_PHYSICSSOLVER_HPP_
#include "Hitbox.hpp"
#include "../typedefs.hpp"
#include "../voxels/voxel.hpp"
#include <vector>
#include <glm/glm.hpp>
class Block;
class Chunks;
struct Hitbox;
struct Trigger;
class PhysicsSolver {
glm::vec3 gravity;
std::vector<Trigger*> triggers;
public:
PhysicsSolver(glm::vec3 gravity);
void step(
@ -21,18 +25,23 @@ public:
uint substeps,
bool shifting,
float gravityScale,
bool collisions
bool collisions,
entityid_t entity
);
void colisionCalc(
Chunks* chunks,
Hitbox* hitbox,
glm::vec3& vel,
glm::vec3& pos,
Chunks* chunks,
Hitbox* hitbox,
glm::vec3& vel,
glm::vec3& pos,
const glm::vec3 half,
float stepHeight
);
bool isBlockInside(int x, int y, int z, Hitbox* hitbox);
bool isBlockInside(int x, int y, int z, Block* def, blockstate state, Hitbox* hitbox);
void setTriggers(std::vector<Trigger*> triggers) {
this->triggers = std::move(triggers);
}
};
#endif // PHYSICS_PHYSICSSOLVER_HPP_