diff options
author | sanine <sanine.not@pm.me> | 2023-04-13 23:40:31 -0500 |
---|---|---|
committer | sanine <sanine.not@pm.me> | 2023-04-13 23:40:31 -0500 |
commit | 371e3a188e190a9c8b53dc6eef02d4eea72db826 (patch) | |
tree | 9d82a01b790682cc1c9889bb13494cfd8db9b545 | |
parent | 64be3e5d5788e5e866d7f5fb7b1c6f754735f2f4 (diff) |
move message dispatching into ecs-systems.lua
-rw-r--r-- | honey/ecs-systems.lua | 93 | ||||
-rw-r--r-- | honey/ecs.lua | 15 | ||||
-rw-r--r-- | main.lua | 87 |
3 files changed, 148 insertions, 47 deletions
diff --git a/honey/ecs-systems.lua b/honey/ecs-systems.lua index 5b9692b..ed51e5d 100644 --- a/honey/ecs-systems.lua +++ b/honey/ecs-systems.lua @@ -8,6 +8,28 @@ setmetatable(module, {__index=_G}) setfenv(1, module) +-- helper function for retrieving script functions +local function getFunction(script) + local f = require(script.script) + if script.func then + return f[script.func] + else + return f + end +end + + +--===== dispatch messages to handlers =====-- + +dispatch = function(entities, msg, data) + local query = entities:queryComponent(msg) + for id, handler in pairs(query) do + local f = getFunction(handler) + f(entities, id, data) + end +end + + --===== transform cascading =====-- @@ -111,9 +133,6 @@ end ---===== update functions =====-- - - --===== script system =====-- script = function(params) @@ -122,7 +141,7 @@ script = function(params) update=function(self, dt) local entities = self.db:queryComponent("script") for id, script in pairs(entities) do - local f = require(script.name) + local f = getFunction(script) f(self.db, id, dt) end end @@ -130,4 +149,70 @@ script = function(params) end +--===== physics =====-- + +physics = function(params) + local interval = params.interval or 0.01 + local groupSize = params.groupSize or 20 + return { + db=params.db, + space=params.space, + world=params.world, + contactGroup=ode.JointGroupCreate(groupSize), + time=interval, + update=function(self, dt) + local query = self.db:queryComponent("physics") + -- TODO: create physics bodies + + self.time = self.time + dt + -- only run the update every [interval] seconds + if self.time > interval then + self.time = self.time - interval + + -- check for near collisions between geoms + ode.SpaceCollide(self.space, function(a, b) + -- check for actual collisions + local collisions = ode.Collide(a, b, 1) + if #collisions > 0 then + -- set up the joint params + local contact = ode.CreateContact{ surface={ + mode = ode.ContactBounce + ode.ContactSoftCFM, + mu = ode.Infinity, + bounce = 0.90, + bounce_vel = 0.1, + soft_cfm = 0.001, + }} + ode.ContactSetGeom(contact, collisions[1]) + -- create the joint + local joint = ode.JointCreateContact( + self.world, + self.contactgroup, + contact + ) + -- attach the two bodies + local bodyA = ode.GeomGetData(a) + local bodyB = ode.GeomGetData(b) + ode.JointAttach(joint, bodyA, bodyB) + end + end) + -- update the world + ode.WorldQuickStep(self.world, interval) + -- remove all contact joints + ode.JointGroupEmpty(self.contactGroup) + + -- update entity transforms + for id, physics in pairs(query) do + local x,y,z = ode.BodyGetPosition(physics._body) + local d,a,b,c = ode.BodyGetQuaternion(physics._body) + entity.transform + :identity() + :translate(Vec3{x,y,z}) + :mul(Quaternion{a,b,c,d}:toMat4()) + end + end + end, + } +end + + return module diff --git a/honey/ecs.lua b/honey/ecs.lua index 69feb12..39f1c77 100644 --- a/honey/ecs.lua +++ b/honey/ecs.lua @@ -69,9 +69,22 @@ function EntityDb.addComponent(self, id, name, value) end +-- add multiple components at once, for convenience +function EntityDb.addComponents(self, id, components) + for name, value in pairs(components) do + self:addComponent(id, name, value) + end +end + + -- get all entities with a given component function EntityDb.queryComponent(self, name) - return self.components[name].data + local component = self.components[name] + if component then + return component.data + else + return {} + end end @@ -6,7 +6,7 @@ local Vec3 = honey.Vec3 local Mat4 = honey.Mat4 local Quaternion = honey.Quaternion local ecs = honey.ecs -local stdSystem = honey.standardSystems +local sys = honey.standardSystems local ode = honey.ode local nvg = honey.nvg @@ -21,63 +21,66 @@ local vw, vh = 640, 480 -- setup ecs -local db = ecs.Database() +local entities = ecs.EntityDb() +local systems = ecs.SystemDb(entities) -local camera = db:createEntity() -db:addComponent(camera, "camera", { - projection=Mat4():perspective(math.rad(45), 640/480, 0.1, 100), -}) -db:addComponent(camera, "transform", { - matrix=Mat4():identity():translate(Vec3{0, 0, -6}), -}) -db:addComponent(camera, "script", { - name = "cameraRotationScript", +local camera = entities:createEntity() +entities:addComponents(camera, { + camera={ + projection=Mat4():perspective(math.rad(45), 640/480, 0.1, 100), + }, + transform={ + matrix=Mat4():identity():translate(Vec3{0, 0, -6}), + }, + script={ + script="cameraRotationScript", + }, }) - - -db:addSystem(stdSystem.transform) -db:addSystem(stdSystem.renderCamera, {camera=camera}) -db:addSystem(stdSystem.script) -package.loaded['baseRotationScript'] = function(db, id, dt) - local transform = db:getComponent(id, "transform") +--entities:addComponent(camera, "camera", { +-- projection=Mat4():perspective(math.rad(45), 640/480, 0.1, 100), +--}) +--entities:addComponent(camera, "transform", { +-- matrix=Mat4():identity():translate(Vec3{0, 0, -6}), +--}) +--entities:addComponent(camera, "script", { +-- name = "cameraRotationScript", +--}) +-- + +systems:addSystem(sys.transform) +systems:addSystem(sys.renderCamera, {camera=camera}) +systems:addSystem(sys.script) +package.loaded['baseRotationScript'] = function(entities, id, dt) + local transform = entities:getComponent(id, "transform") transform.matrix:rotateZ(math.pi * dt) end -package.loaded['cameraRotationScript'] = function(db, id, dt) - local transform = db:getComponent(id, "transform") +package.loaded['cameraRotationScript'] = function(entities, id, dt) + local transform = entities:getComponent(id, "transform") transform.matrix:identity():translate(Vec3{0, 0, -6 + math.sin(math.pi * glfw.GetTime())}) end -function transmitMessage(msg, data) - local query = db:queryComponent(msg) - for id, handler in pairs(query) do - local f = require(handler.scriptName) - f(db, id, data) - end -end - - -local id = db:createEntity() -db:addComponent(id, "renderMesh", { +local id = entities:createEntity() +entities:addComponent(id, "renderMesh", { textures = { ourTexture={ filename="77155.png" }, }, shader = { vertex="vertex.glsl", fragment="fragment.glsl" }, mesh = { filename="assets/icosahedron.obj", index=1 }, }) -db:addComponent(id, "transform", { +entities:addComponent(id, "transform", { matrix = Mat4():identity():rotateZ(math.rad(45)), }) -db:addComponent(id, "script", { - name = "baseRotationScript", +entities:addComponent(id, "script", { + script = "baseRotationScript", }) -local id2 = db:createEntity() -db:addComponent(id2, "renderMesh", { +local id2 = entities:createEntity() +entities:addComponent(id2, "renderMesh", { shader = { vertex="vertex.glsl", fragment="fragment.glsl" }, mesh = { filename="assets/tetrahedron.obj", index=1 }, }) -db:addComponent(id2, "transform", { +entities:addComponent(id2, "transform", { parent=id, matrix=Mat4():identity():translate(Vec3{0, 2, 0}), }) @@ -97,14 +100,14 @@ end) window:setFramebufferSizeCallback(function(_, width, height) gl.Viewport(0, 0, width, height) vw, vh = width, height - transmitMessage("onWindowResize", { width=width, height=height }) + sys.dispatch(entities, "onWindowResize", { width=width, height=height }) end) -package.loaded["cameraHandleResize"] = function(db, id, data) - local camera = db:getComponent(id, "camera") +package.loaded["cameraHandleResize"] = function(entities, id, data) + local camera = entities:getComponent(id, "camera") camera.projection:perspectiveResize(data.width/data.height) end -db:addComponent(camera, "onWindowResize", { scriptName = "cameraHandleResize" }) +entities:addComponent(camera, "onWindowResize", { script = "cameraHandleResize" }) -- averager (for fps) function averager(memory) @@ -129,7 +132,7 @@ honey.loop(window, function(dt) gl.Enable(gl.DEPTH_TEST) gl.Disable(gl.CULL_FACE) - db:update(dt) + systems:update(dt) nvg.BeginFrame(vg, vw, vh, 1.0) nvg.StrokeColor(vg, nvg.RGBf(1, 1, 1)) nvg.FontFace(vg, "November") |