chore: extract physics as a mixins

Fixes #52
This commit is contained in:
Kazhnuz 2020-11-26 19:16:15 +01:00
parent 5393d16007
commit 79902a097f
4 changed files with 240 additions and 229 deletions

View file

@ -26,12 +26,14 @@ local BaseActor = require("birb.modules.world.actors.mixins.base")
local SpritedActor = require("birb.modules.world.actors.mixins.sprites") local SpritedActor = require("birb.modules.world.actors.mixins.sprites")
local TimedActor = require("birb.modules.world.actors.mixins.timers") local TimedActor = require("birb.modules.world.actors.mixins.timers")
local InputActor = require("birb.modules.world.actors.mixins.inputs") local InputActor = require("birb.modules.world.actors.mixins.inputs")
local PhysicalActor = require("birb.modules.world.actors.mixins.physics")
local Actor2D = Object:extend() local Actor2D = Object:extend()
Actor2D:implement(BaseActor) Actor2D:implement(BaseActor)
Actor2D:implement(SpritedActor) Actor2D:implement(SpritedActor)
Actor2D:implement(TimedActor) Actor2D:implement(TimedActor)
Actor2D:implement(InputActor) Actor2D:implement(InputActor)
Actor2D:implement(PhysicalActor)
local Hitbox = require("birb.modules.world.actors.utils.hitbox2D") 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 -- Initialise the actor and its base functions
function Actor2D:new(world, type, x, y, w, h, isSolid) 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:initHitboxes()
self:initTimers() self:initTimers()
self:initSprite() self:initSprite()

View file

@ -27,12 +27,14 @@ local BaseActor = require("birb.modules.world.actors.mixins.base")
local SpritedActor = require("birb.modules.world.actors.mixins.sprites") local SpritedActor = require("birb.modules.world.actors.mixins.sprites")
local TimedActor = require("birb.modules.world.actors.mixins.timers") local TimedActor = require("birb.modules.world.actors.mixins.timers")
local InputActor = require("birb.modules.world.actors.mixins.inputs") local InputActor = require("birb.modules.world.actors.mixins.inputs")
local PhysicalActor = require("birb.modules.world.actors.mixins.physics")
local Actor3D = Object:extend() local Actor3D = Object:extend()
Actor3D:implement(BaseActor) Actor3D:implement(BaseActor)
Actor3D:implement(SpritedActor) Actor3D:implement(SpritedActor)
Actor3D:implement(TimedActor) Actor3D:implement(TimedActor)
Actor3D:implement(InputActor) Actor3D:implement(InputActor)
Actor3D:implement(PhysicalActor)
local Hitbox = require(cwd .. "utils.hitbox3D") local Hitbox = require(cwd .. "utils.hitbox3D")
local Boxes = require(cwd .. "utils.boxes") local Boxes = require(cwd .. "utils.boxes")
@ -41,7 +43,8 @@ local Boxes = require(cwd .. "utils.boxes")
-- Initialise the actor and its base functions -- Initialise the actor and its base functions
function Actor3D:new(world, type, x, y, z, w, h, d, isSolid) 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:initHitboxes()
self:initTimers() self:initTimers()
self:initSprite() self:initSprite()

View file

@ -27,17 +27,17 @@ local BaseActor = Object:extend()
-- INIT FUNCTIONS -- INIT FUNCTIONS
-- Initialise the actor and its base functions -- Initialise the actor and its base functions
function BaseActor:init(world, type, x, y, z, w, h, d, isSolid) function BaseActor:init(world, type)
self.type = type or "" self.type = type or ""
self.isSolid = isSolid or false
self.depth = 0 self.depth = 0
self:setManagers(world) self:setManagers(world)
self:initKeys() self:initKeys()
self:initPhysics(x, y, z, w, h, d)
self:setDebugColor(1, 1, 1) self:setDebugColor(1, 1, 1)
self:register() self:register()
self.updateFunctions = {}
end end
function BaseActor:setManagers(world) function BaseActor:setManagers(world)
@ -64,128 +64,6 @@ function BaseActor:destroy()
self.isDestroyed = true self.isDestroyed = true
end 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()
self.updateFunctions = {}
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 -- UPDATE FUNCTIONS
-- Theses functions are activated every steps -- Theses functions are activated every steps
@ -195,7 +73,6 @@ end
function BaseActor:update(dt) function BaseActor:update(dt)
self:updateStart(dt) self:updateStart(dt)
self:autoMove(dt)
self:applyUpdateFunctions(dt) self:applyUpdateFunctions(dt)
self:updateEnd(dt) self:updateEnd(dt)
end end
@ -214,107 +91,6 @@ function BaseActor:updateEnd(dt)
end 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.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 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 FUNCTIONS
-- Draw the actors. -- Draw the actors.

View file

@ -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