From edf44fd252dc96a39b8f32e41bd24e3ac7ac3632 Mon Sep 17 00:00:00 2001 From: Kazhnuz Date: Thu, 6 May 2021 20:26:06 +0200 Subject: [PATCH] chore: extract physics as a mixins --- .../birb/modules/world/actors/actor2D.lua | 5 +- .../birb/modules/world/actors/actor3D.lua | 5 +- .../birb/modules/world/actors/mixins/base.lua | 224 ----------------- .../modules/world/actors/mixins/physics.lua | 229 ++++++++++++++++++ 4 files changed, 237 insertions(+), 226 deletions(-) create mode 100644 sonic-radiance.love/birb/modules/world/actors/mixins/physics.lua diff --git a/sonic-radiance.love/birb/modules/world/actors/actor2D.lua b/sonic-radiance.love/birb/modules/world/actors/actor2D.lua index 93f106d..549f204 100644 --- a/sonic-radiance.love/birb/modules/world/actors/actor2D.lua +++ b/sonic-radiance.love/birb/modules/world/actors/actor2D.lua @@ -26,12 +26,14 @@ local BaseActor = require "birb.modules.world.actors.mixins.base" local SpritedActor = require("birb.modules.world.actors.mixins.sprites") local TimedActor = require("birb.modules.world.actors.mixins.timers") local InputActor = require("birb.modules.world.actors.mixins.inputs") +local PhysicalActor = require("birb.modules.world.actors.mixins.physics") local Actor2D = Object:extend() Actor2D:implement(BaseActor) Actor2D:implement(SpritedActor) Actor2D:implement(TimedActor) Actor2D:implement(InputActor) +Actor2D:implement(PhysicalActor) local Hitbox = require "birb.modules.world.actors.utils.hitbox2D" @@ -39,7 +41,8 @@ local Hitbox = require "birb.modules.world.actors.utils.hitbox2D" -- Initialise the actor and its base functions function Actor2D:new(world, type, x, y, w, h, isSolid) - self:init(world, type, x, y, 0, w, h, 0, isSolid) + self:init(world, type) + self:initPhysics(x, y, 0, w, h, 0, isSolid) self:initHitboxes() self:initTimers() self:initSprite() diff --git a/sonic-radiance.love/birb/modules/world/actors/actor3D.lua b/sonic-radiance.love/birb/modules/world/actors/actor3D.lua index 3ee9b0f..46c8d87 100644 --- a/sonic-radiance.love/birb/modules/world/actors/actor3D.lua +++ b/sonic-radiance.love/birb/modules/world/actors/actor3D.lua @@ -29,18 +29,21 @@ local BaseActor = require("birb.modules.world.actors.mixins.base") local SpritedActor = require("birb.modules.world.actors.mixins.sprites") local TimedActor = require("birb.modules.world.actors.mixins.timers") local InputActor = require("birb.modules.world.actors.mixins.inputs") +local PhysicalActor = require("birb.modules.world.actors.mixins.physics") local Actor3D = Object:extend() Actor3D:implement(BaseActor) Actor3D:implement(SpritedActor) Actor3D:implement(TimedActor) Actor3D:implement(InputActor) +Actor3D:implement(PhysicalActor) -- INIT FUNCTIONS -- Initialise the actor and its base functions function Actor3D:new(world, type, x, y, z, w, h, d, isSolid) - self:init(world, type, x, y, z, w, h, d, isSolid) + self:init(world, type) + self:initPhysics(x, y, z, w, h, d, isSolid) self:initHitboxes() self:initTimers() self:initSprite() diff --git a/sonic-radiance.love/birb/modules/world/actors/mixins/base.lua b/sonic-radiance.love/birb/modules/world/actors/mixins/base.lua index 3262408..97e3a9a 100644 --- a/sonic-radiance.love/birb/modules/world/actors/mixins/base.lua +++ b/sonic-radiance.love/birb/modules/world/actors/mixins/base.lua @@ -35,8 +35,6 @@ function BaseActor:init(world, type, x, y, z, w, h, d, isSolid) self.updateFunctions = {} self:setManagers(world) - self:initKeys() - self:initPhysics(x, y, z, w, h, d) self:setDebugColor(1, 1, 1) self:register() @@ -81,126 +79,6 @@ function BaseActor:destroy() self.isDestroyed = true end --- PHYSICS FUNCTIONS --- Raw implementation of everything common in physics - -function BaseActor:initPhysics(x, y, z, w, h, d) - self:setCoordinate(x, y, z) - - self.w = w or 0 - self.h = h or 0 - self.d = d or 0 - - self.xsp = 0 - self.ysp = 0 - self.zsp = 0 - - self.xfrc = 0 - self.yfrc = 0 - self.zfrc = 0 - - self:initGravity() - - self:setBounceFactor() - self:setFilter() -end - -function BaseActor:setCoordinate(x, y, z, w, h, d) - self.x = x or self.x - self.y = y or self.y - self.z = z or self.z -end - -function BaseActor:setBounceFactor(newBounceFactor) - self.bounceFactor = newBounceFactor or 0 -end - -function BaseActor:setFilter() - -- Init the bump filter - self.filter = function(item, other) - if (other.owner == self) then - -- ignore every collision with our own hitboxes - return nil - elseif (other.isSolid) then - return "slide" - else - return "cross" - end - end -end - -function BaseActor:getFuturePosition(dt) - local dx, dy, dz - dx = self.x + self.xsp * dt - dy = self.y + self.ysp * dt - dz = self.z + self.zsp * dt - - return dx, dy, dz -end - -function BaseActor:applyFriction(dt) - self.xsp = utils.math.toZero(self.xsp, self.xfrc * dt) - self.ysp = utils.math.toZero(self.ysp, self.yfrc * dt) - self.zsp = utils.math.toZero(self.zsp, self.zfrc * dt) -end - -function BaseActor:solveAllCollisions(cols) - for i, col in ipairs(cols) do - self:collisionResponse(col) - if (col.type == "touch") or (col.type == "bounce") or (col.type == "slide") then - self:changeSpeedToCollisionNormal(col.normal) - end - end -end - -function BaseActor:collisionResponse(collision) - -- here come the response to the collision -end - -function BaseActor:changeSpeedToCollisionNormal(normal) - -- Empty function in baseactor -end - --- COORDINATE/MOVEMENT FUNCTIONS --- Handle coordinate - -function BaseActor:getCenter() - return (self.x + (self.w / 2)), (self.y + (self.h / 2)), (self.z + (self.d / 2)) -end - -function BaseActor:getViewCenter() - return self:getCenter() -end - --- GRAVITY SYSTEM FUNCTIONS --- All functions related to gravity - -function BaseActor:initGravity() - if (self.world.gravity.isDefault) then - self.grav = self.world.gravity.grav - else - self.grav = 0 - end - - self.onGround = false -end - -function BaseActor:setGravity(grav) - -- It's basically now a function with two roles at once : - -- - activate the gravity - -- - use the gravity value the dev want - - self.grav = grav or self.world.gravity.grav -end - -function BaseActor:applyGravity(dt) - -- Empty function in baseactor -end - -function BaseActor:checkGround() - -- Empty function in baseactor -end - -- UPDATE FUNCTIONS -- Theses functions are activated every steps @@ -210,7 +88,6 @@ end function BaseActor:update(dt) self:updateStart(dt) - self:autoMove(dt) self:applyUpdateFunctions(dt) self:updateEnd(dt) end @@ -219,107 +96,6 @@ function BaseActor:updateEnd(dt) end -function BaseActor:autoMove(dt) - -- The base actor don't have coordinate - -- so the autoMove is only usefull to its - -- 2D and 3D childrens -end - --- HITBOX FUNCTIONS --- All functions to handle hitboxes - -function BaseActor:initHitboxes() - self:initMainHitbox() - - self.hitboxes = {} - self.hitboxListFile = "" - self.hitboxList = nil -end - -function BaseActor:initMainHitbox() - -- Empty function : don't load ANY real hitbox function into baseactor -end - -function BaseActor:setHitboxFile(file) - self.hitboxList = require(file) - self.hitboxListFile = file -end - -function BaseActor:getAutomaticHitboxLoading() - return (self.hitboxList ~= nil) -end - -function BaseActor:getHitboxFile() - return self.hitboxListFile -end - -function BaseActor:getHitboxList(animation, frame) - if (animation == nil) or (self.hitboxList == nil) then - return self.hitboxList - else - local list = self.hitboxList[animation] - - if (frame == nil) or (list == nil) then - return list - else - return list[frame] - end - end -end - -function BaseActor:updateHitboxes() - if (self.hitboxList ~= nil) then - self:purgeHitbox() - local animation, frame - animation = self:getCurrentAnimation() - frame = self:getRelativeFrame() - local hitboxList = self:getHitboxList(animation, frame) - - if (hitboxList ~= nil) then - for i,v in ipairs(hitboxList) do - self:addHitboxFromFrameData(v, animation, frame, i) - end - end - end -end - -function BaseActor:checkHitboxesCollisions(filter) - for k,v in pairs(self.hitboxes) do - self:checkHitboxCollisions(k, filter) - end -end - -function BaseActor:hitboxResponse(name, type, collision) - -- just a blank placeholder function -end - -function BaseActor:removeHitbox(name) - if (self.hitboxes[name] ~= nil) then - self.hitboxes[name]:destroy() - self.hitboxes[name] = nil - end -end - -function BaseActor:purgeHitbox() - for k,v in pairs(self.hitboxes) do - v:destroy() - end - self.hitboxes = {} -end - -function BaseActor:drawHitboxes() - for k,v in pairs(self.hitboxes) do - v:draw() - end - self:drawMainHitbox() -end - -function BaseActor:drawMainHitbox() - if (self.mainHitbox ~= nil) then - self.mainHitbox:draw() - end -end - -- DRAW FUNCTIONS -- Draw the actors. diff --git a/sonic-radiance.love/birb/modules/world/actors/mixins/physics.lua b/sonic-radiance.love/birb/modules/world/actors/mixins/physics.lua new file mode 100644 index 0000000..86c21c6 --- /dev/null +++ b/sonic-radiance.love/birb/modules/world/actors/mixins/physics.lua @@ -0,0 +1,229 @@ +PhysicalActor = Object:extend() + +-- PHYSICS FUNCTIONS +-- Raw implementation of everything common in physics + +function PhysicalActor:initPhysics(x, y, z, w, h, d, isSolid) + self:setCoordinate(x, y, z) + + self.isSolid = isSolid or false + + self.w = w or 0 + self.h = h or 0 + self.d = d or 0 + + self.xsp = 0 + self.ysp = 0 + self.zsp = 0 + + self.xfrc = 0 + self.yfrc = 0 + self.zfrc = 0 + + self:initGravity() + + self:setBounceFactor() + self:setFilter() + + self:addUpdateFunction(self.autoMove) +end + +function PhysicalActor:setCoordinate(x, y, z, w, h, d) + self.x = x or self.x + self.y = y or self.y + self.z = z or self.z +end + +function PhysicalActor:setBounceFactor(newBounceFactor) + self.bounceFactor = newBounceFactor or 0 +end + +function PhysicalActor:setFilter() + -- Init the bump filter + self.filter = function(item, other) + if (other.owner == self) then + -- ignore every collision with our own hitboxes + return nil + elseif (other.isSolid) then + return "slide" + else + return "cross" + end + end +end + +function PhysicalActor:getFuturePosition(dt) + local dx, dy, dz + dx = self.x + self.xsp * dt + dy = self.y + self.ysp * dt + dz = self.z + self.zsp * dt + + return dx, dy, dz +end + +function PhysicalActor:applyFriction(dt) + self.xsp = utils.math.toZero(self.xsp, self.xfrc * dt) + self.ysp = utils.math.toZero(self.ysp, self.yfrc * dt) + self.zsp = utils.math.toZero(self.zsp, self.zfrc * dt) +end + +function PhysicalActor:solveAllCollisions(cols) + for i, col in ipairs(cols) do + self:collisionResponse(col) + if (col.type == "touch") or (col.type == "bounce") or (col.type == "slide") then + self:changeSpeedToCollisionNormal(col.normal) + end + end +end + +function PhysicalActor:collisionResponse(collision) + -- here come the response to the collision +end + +function PhysicalActor:changeSpeedToCollisionNormal(normal) + -- Empty function in PhysicalActor +end + +-- COORDINATE/MOVEMENT FUNCTIONS +-- Handle coordinate +-- Will be replaced by functions inside Actors or Rects/Point + +function PhysicalActor:getCenter() + return (self.x + (self.w / 2)), (self.y + (self.h / 2)), (self.z + (self.d / 2)) +end + +function PhysicalActor:getViewCenter() + return self:getCenter() +end + +-- GRAVITY SYSTEM FUNCTIONS +-- All functions related to gravity + +function PhysicalActor:initGravity() + if (self.world.gravity.isDefault) then + self.grav = self.world.gravity.grav + else + self.grav = 0 + end + + self.onGround = false +end + +function PhysicalActor:setGravity(grav) + -- It's basically now a function with two roles at once : + -- - activate the gravity + -- - use the gravity value the dev want + + self.grav = grav or self.world.gravity.grav +end + +function PhysicalActor:applyGravity(dt) + -- Empty function in PhysicalActor +end + +function PhysicalActor:checkGround() + -- Empty function in PhysicalActor +end + +function PhysicalActor:autoMove(dt) + -- The base actor don't have coordinate + -- so the autoMove is only usefull to its + -- 2D and 3D childrens +end + +-- HITBOX FUNCTIONS +-- All functions to handle hitboxes + +function PhysicalActor:initHitboxes() + self:initMainHitbox() + + self.hitboxes = {} + self.hitboxListFile = "" + self.hitboxList = nil +end + +function PhysicalActor:initMainHitbox() + -- Empty function : don't load ANY real hitbox function into PhysicalActor +end + +function PhysicalActor:setHitboxFile(file) + self.hitboxList = require(file) + self.hitboxListFile = file +end + +function PhysicalActor:getAutomaticHitboxLoading() + return (self.hitboxList ~= nil) +end + +function PhysicalActor:getHitboxFile() + return self.hitboxListFile +end + +function PhysicalActor:getHitboxList(animation, frame) + if (animation == nil) or (self.hitboxList == nil) then + return self.hitboxList + else + local list = self.hitboxList[animation] + + if (frame == nil) or (list == nil) then + return list + else + return list[frame] + end + end +end + +function PhysicalActor:updateHitboxes() + if (self.hitboxList ~= nil) then + self:purgeHitbox() + local animation, frame + animation = self.sprite:getCurrentAnimation() + frame = self.sprite:getRelativeFrame() + local hitboxList = self:getHitboxList(animation, frame) + + if (hitboxList ~= nil) then + for i, v in ipairs(hitboxList) do + self:addHitboxFromFrameData(v, animation, frame, i) + end + end + end +end + +function PhysicalActor:checkHitboxesCollisions(filter) + for k, v in pairs(self.hitboxes) do + self:checkHitboxCollisions(k, filter) + end +end + +function PhysicalActor:hitboxResponse(name, type, collision) + -- just a blank placeholder function +end + +function PhysicalActor:removeHitbox(name) + if (self.hitboxes[name] ~= nil) then + self.hitboxes[name]:destroy() + self.hitboxes[name] = nil + end +end + +function PhysicalActor:purgeHitbox() + for k, v in pairs(self.hitboxes) do + v:destroy() + end + self.hitboxes = {} +end + +function PhysicalActor:drawHitboxes() + for k, v in pairs(self.hitboxes) do + v:draw() + end + self:drawMainHitbox() +end + +function PhysicalActor:drawMainHitbox() + if (self.mainHitbox ~= nil) then + self.mainHitbox:draw() + end +end + +return PhysicalActor \ No newline at end of file