From e5553bb81c93cd76456d07d3a1d7e8bb1b249b6e Mon Sep 17 00:00:00 2001 From: sanine-a Date: Thu, 23 Mar 2023 13:35:37 -0500 Subject: implement skeleton of physics system --- main.lua | 139 ++++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 94 insertions(+), 45 deletions(-) (limited to 'main.lua') diff --git a/main.lua b/main.lua index 9f26eb3..2c92223 100644 --- a/main.lua +++ b/main.lua @@ -4,54 +4,20 @@ local glfw = honey.glfw local gl = honey.gl local Vec3 = honey.Vec3 local Mat4 = honey.Mat4 +local Quaternion = honey.Quaternion local ecs = honey.ecs local systems = honey.standardSystems local ode = honey.ode +local nvg = honey.nvg -- initialize honey local window = honey.init() --- setup physics -local world = ode.WorldCreate() -local space = ode.HashSpaceCreate(ode.Space0) -ode.WorldSetGravity(world, 0, -10, 0) -ode.WorldSetCFM(world, 1e-5) -ode.CreatePlane(space, 0, 1, 0, 0) -local contactgroup = ode.JointGroupCreate(16) -local body = ode.BodyCreate(world) -local geom = ode.CreateSphere(space, 0.5) -local mass = ode.MassCreate() -ode.MassSetSphere(mass, 1, 0.5) -ode.BodySetMass(body, mass) -ode.GeomSetBody(geom, body) -ode.BodySetPosition(body, 0, 3, 0) - -function physicsStep() - ode.SpaceCollide(space, function(o1, o2) - local b1 = ode.GeomGetBody(o1) - local b2 = ode.GeomGetBody(o2) - local contact = ode.CreateContact{ - surface = { - mode = ode.ContactBounce + ode.ContactSoftCFM, - mu = ode.Infinity, - bounce = 1.0, - bounce_vel = 0.1, - soft_cfm = 0.001, - }, - } - local collisions = ode.Collide(o1, o2, 1) - if #collisions > 0 then - print("collision detected!") - ode.ContactSetGeom(contact, collisions[1]) - local joint = ode.JointCreateContact(world, contactgroup, contact) - ode.JointAttach(joint, b1, b2) - end - end) - ode.WorldQuickStep(world, 0.01) - ode.JointGroupEmpty(contactgroup) -end - +-- setup vector graphics +local vg = nvg.CreateContext() +local november = nvg.CreateFont(vg, "November", "assets/november.regular.ttf") +local vw, vh = 640, 480 -- create camera matrices local camera = { @@ -65,6 +31,63 @@ level:addSystem(systems.transformCascade) level:addSystem(systems.renderCam(camera)) level:addSystem(systems.update) +-- physics system +local world = ode.WorldCreate() +local space = ode.HashSpaceCreate(ode.Space0) +level:addSystem{ + setup=function(self) + self.time = 0 + self.world=world + self.space=space + ode.WorldSetGravity(self.world, 0, -10, 0) + ode.WorldSetCFM(self.world, 1e-5) + self.contactgroup = ode.JointGroupCreate(32) + self.__gc = honey.util.gc_canary(function() + ode.WorldDestroy(self.world) + ode.SpaceDestroy(self.space) + end) + end, + filter = ecs.Filter.AND{"transform", "collisionShape", "physicsBody"}, + preUpdate = function(self) + self.dt = nil + if self.time > 0.01 then + self.time = self.time - 0.01 + ode.SpaceCollide(self.space, function(o1, o2) + local b1 = ode.GeomGetBody(o1) + local b2 = ode.GeomGetBody(o2) + local contact = ode.CreateContact{ + surface = { + mode = ode.ContactBounce + ode.ContactSoftCFM, + mu = ode.Infinity, + bounce = 0.99, + bounce_vel = 0.1, + soft_cfm = 0.001, + }, + } + local collisions = ode.Collide(o1, o2, 1) + if #collisions > 0 then + print("collision detected!") + ode.ContactSetGeom(contact, collisions[1]) + local joint = ode.JointCreateContact(self.world, self.contactgroup, contact) + ode.JointAttach(joint, b1, b2) + end + end) + ode.WorldQuickStep(self.world, 0.01) + ode.JointGroupEmpty(self.contactgroup) + end + end, + update = function(self, entity, dt) + if not self.dt then + self.dt = dt + self.time = self.time + dt + end + + local x, y, z = ode.BodyGetPosition(entity.physicsBody) + local a, b, c, d = ode.BodyGetQuaternion(entity.physicsBody) + entity.transform:identity():translate(Vec3{x, y, z}):mul(Quaternion{a, b, c, d}:toMat4()) + end, +} + -- create shader local shader = honey.Shader{ vertexFile = "vertex.glsl", @@ -127,13 +150,20 @@ local ball = { parent=false, mesh=icosa, shader=shader, - update=function(self, dt) - local x, y, z = ode.BodyGetPosition(body) - self.transform:identity():translate(Vec3{x, y, z}) - end, + collisionShape=ode.CreateSphere(space, 0.5), + physicsBody=ode.BodyCreate(world), } level:addEntity(ball) +local mass = ode.MassCreate() +ode.MassSetSphere(mass, 1, 0.5) +ode.BodySetMass(ball.physicsBody, mass) +ode.GeomSetBody(ball.collisionShape, ball.physicsBody) +ode.BodySetPosition(ball.physicsBody, 0, 3, 0) +ode.BodySetLinearVel(ball.physicsBody, 1, 0, 0) + +ode.CreatePlane(space, 0, 1, 0, -2) + -- close window on ESCAPE key window:setKeyCallback(function(_, key) if key == glfw.KEY_ESCAPE then @@ -145,14 +175,33 @@ end) window:setFramebufferSizeCallback(function(_, width, height) gl.Viewport(0, 0, width, height) camera.projection:perspectiveResize(width/height) + vw, vh = width, height end) +-- averager (for fps) +function averager(memory) + local buf = {} + local avg = 0 + for i=1,memory do table.insert(buf, 0) end + return function(value) + table.insert(buf, value) + local val = table.remove(buf, 1) + avg = avg + value - val + return avg / memory + end +end +local fpsAverage = averager(200) + -- main loop honey.loop(window, function(dt) gl.ClearColor(0.2, 0.4, 1.0, 1.0) gl.Clear(gl.COLOR_BUFFER_BIT + gl.DEPTH_BUFFER_BIT) level:update(dt) - physicsStep() + nvg.BeginFrame(vg, vw, vh, 1.0) + nvg.StrokeColor(vg, nvg.RGBf(1, 1, 1)) + nvg.FontFace(vg, "November") + nvg.Text(vg, 50, 50, "fps: "..tostring(math.floor(fpsAverage(1/dt)))) + nvg.EndFrame(vg) end) -- clean up -- cgit v1.2.1