summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--honey/ecs-systems.lua93
-rw-r--r--honey/ecs.lua15
-rw-r--r--main.lua87
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
diff --git a/main.lua b/main.lua
index 5ef09dd..a686daa 100644
--- a/main.lua
+++ b/main.lua
@@ -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")