2019-06-27 21:56:02 +02:00
|
|
|
-- BaseActor.lua :: the global implementation of an actor. Basically, it abstract
|
|
|
|
-- everything that isn't only 2D or 3D related to the actor system.
|
2019-05-05 20:30:25 +02:00
|
|
|
|
|
|
|
--[[
|
|
|
|
Copyright © 2019 Kazhnuz
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
|
|
this software and associated documentation files (the "Software"), to deal in
|
|
|
|
the Software without restriction, including without limitation the rights to
|
|
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
|
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
|
|
subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
|
|
copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
|
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
]]
|
|
|
|
|
2019-05-05 21:01:54 +02:00
|
|
|
local cwd = (...):gsub('%.baseactor$', '') .. "."
|
2019-05-05 20:30:25 +02:00
|
|
|
local BaseActor = Object:extend()
|
|
|
|
|
2019-05-05 21:01:54 +02:00
|
|
|
local Timer = require(cwd .. "utils.timer")
|
|
|
|
|
2019-05-05 20:49:28 +02:00
|
|
|
-- INIT FUNCTIONS
|
|
|
|
-- Initialise the actor and its base functions
|
|
|
|
|
2019-06-27 21:56:02 +02:00
|
|
|
function BaseActor:new(world, type, x, y, z, w, h, d, isSolid)
|
2019-05-05 21:27:02 +02:00
|
|
|
self.type = type or ""
|
|
|
|
self.isSolid = isSolid or false
|
2019-06-16 10:24:30 +02:00
|
|
|
self.depth = 0
|
2019-05-05 21:27:02 +02:00
|
|
|
|
2019-05-05 20:49:28 +02:00
|
|
|
self:setManagers(world)
|
2019-05-05 20:51:26 +02:00
|
|
|
self:initKeys()
|
2019-05-05 21:01:54 +02:00
|
|
|
self:initTimers()
|
|
|
|
self:setSprite()
|
2019-06-27 21:56:02 +02:00
|
|
|
self:initPhysics(x, y, z, w, h, d)
|
2019-05-05 20:49:28 +02:00
|
|
|
|
|
|
|
self:setDebugColor(1, 1, 1)
|
2019-05-05 21:56:55 +02:00
|
|
|
self:register()
|
2019-05-05 20:49:28 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:setManagers(world)
|
|
|
|
self.world = world
|
|
|
|
self.scene = world.scene
|
|
|
|
self.obj = world.obj
|
|
|
|
self.assets = self.scene.assets
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:setDebugColor(r,g,b)
|
|
|
|
self.debug = {}
|
|
|
|
self.debug.r = r
|
|
|
|
self.debug.g = g
|
|
|
|
self.debug.b = b
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:register()
|
|
|
|
self.world:registerActor(self)
|
|
|
|
self.isDestroyed = false
|
|
|
|
end
|
2019-05-05 20:30:25 +02:00
|
|
|
|
2019-05-05 20:49:28 +02:00
|
|
|
function BaseActor:destroy()
|
|
|
|
self.world:removeActor(self)
|
|
|
|
self.isDestroyed = true
|
2019-05-05 20:30:25 +02:00
|
|
|
end
|
|
|
|
|
2019-06-27 21:56:02 +02:00
|
|
|
-- 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
|
2019-05-05 21:44:12 +02:00
|
|
|
|
|
|
|
self:initGravity()
|
|
|
|
|
|
|
|
self:setBounceFactor()
|
|
|
|
self:setFilter()
|
|
|
|
end
|
|
|
|
|
2019-06-27 21:56:02 +02:00
|
|
|
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
|
|
|
|
|
2019-05-05 21:44:12 +02:00
|
|
|
function BaseActor:setBounceFactor(newBounceFactor)
|
|
|
|
self.bounceFactor = newBounceFactor or 0
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:setFilter()
|
|
|
|
-- Init the bump filter
|
|
|
|
self.filter = function(item, other)
|
2019-06-23 15:32:25 +02:00
|
|
|
if (other.owner == self) then
|
|
|
|
-- ignore every collision with our own hitboxes
|
|
|
|
return nil
|
|
|
|
elseif (other.isSolid) then
|
2019-05-05 21:44:12 +02:00
|
|
|
return "slide"
|
|
|
|
else
|
|
|
|
return "cross"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-06-27 22:14:12 +02:00
|
|
|
function BaseActor:getFuturePosition(dt)
|
|
|
|
local dx, dy
|
|
|
|
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
|
2019-05-05 21:44:12 +02:00
|
|
|
end
|
|
|
|
|
2019-06-27 21:56:02 +02:00
|
|
|
-- COORDINATE/MOVEMENT FUNCTIONS
|
|
|
|
-- Handle coordinate
|
|
|
|
|
|
|
|
function BaseActor:getCenter()
|
|
|
|
return (self.x + (self.w / 2)), (self.y + (self.h / 2)), (self.z + (self.d / 2))
|
2019-05-05 21:44:12 +02:00
|
|
|
end
|
|
|
|
|
2019-06-27 21:56:02 +02:00
|
|
|
function BaseActor:getViewCenter()
|
|
|
|
return self:getCenter()
|
|
|
|
end
|
2019-05-05 21:44:12 +02:00
|
|
|
|
2019-06-27 22:02:47 +02:00
|
|
|
-- 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
|
|
|
|
|
2019-05-05 21:04:00 +02:00
|
|
|
-- UPDATE FUNCTIONS
|
|
|
|
-- Theses functions are activated every steps
|
|
|
|
|
2019-06-13 18:39:09 +02:00
|
|
|
function BaseActor:updateStart(dt)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2019-05-05 21:04:00 +02:00
|
|
|
function BaseActor:update(dt)
|
2019-06-13 18:39:09 +02:00
|
|
|
self:updateStart(dt)
|
2019-05-05 21:04:00 +02:00
|
|
|
self:updateTimers(dt)
|
|
|
|
self:autoMove(dt)
|
|
|
|
self:updateSprite(dt)
|
2019-06-13 18:39:09 +02:00
|
|
|
self:updateEnd(dt)
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:updateEnd(dt)
|
|
|
|
|
2019-05-05 21:04:00 +02:00
|
|
|
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
|
|
|
|
|
2019-05-05 20:51:26 +02:00
|
|
|
-- INPUT FUNCTIONS
|
|
|
|
-- get input from the world object
|
|
|
|
|
|
|
|
function BaseActor:initKeys()
|
|
|
|
self.keys = core.input.fakekeys
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:getInput(keys)
|
|
|
|
self.keys = keys or core.input.fakekeys
|
|
|
|
end
|
|
|
|
|
2019-05-05 21:01:54 +02:00
|
|
|
-- TIMER FUNCTIONS
|
|
|
|
-- Control the integrated timers of the actor
|
|
|
|
|
|
|
|
function BaseActor:initTimers()
|
2019-09-08 12:57:13 +02:00
|
|
|
self.timers = core.modules.Timers(self)
|
2019-05-05 21:01:54 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:addTimer(name, t)
|
2019-09-08 12:57:13 +02:00
|
|
|
core.debug:warning("actor", "function actor:addTimer is deprecated, prefer actor.timers:newTimer")
|
|
|
|
self.timers:newTimer(t, name)
|
2019-05-05 21:01:54 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:updateTimers(dt)
|
2019-09-08 12:57:13 +02:00
|
|
|
self.timers:update(dt)
|
2019-05-05 21:01:54 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:timerResponse(name)
|
|
|
|
-- here come the timer responses
|
|
|
|
end
|
|
|
|
|
2019-06-28 08:43:01 +02:00
|
|
|
-- 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
|
|
|
|
|
2019-06-13 18:39:09 +02:00
|
|
|
-- DRAW FUNCTIONS
|
|
|
|
-- Draw the actors.
|
|
|
|
|
|
|
|
function BaseActor:drawStart()
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:draw()
|
|
|
|
self:drawStart()
|
|
|
|
self:drawEnd()
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:drawEnd()
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2019-06-13 22:23:23 +02:00
|
|
|
function BaseActor:drawHUD(id, height, width)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
2019-05-05 21:01:54 +02:00
|
|
|
-- SPRITES FUNCTIONS
|
|
|
|
-- Handle the sprite of the actor
|
|
|
|
|
|
|
|
function BaseActor:setSprite(spritename, ox, oy)
|
|
|
|
self.sprite = {}
|
|
|
|
self.sprite.name = spritename or nil
|
|
|
|
self.sprite.ox = ox or 0
|
|
|
|
self.sprite.oy = oy or 0
|
|
|
|
self.sprite.sx = 1
|
|
|
|
self.sprite.sy = 1
|
|
|
|
self.sprite.exist = (spritename ~= nil)
|
|
|
|
self.sprite.clone = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:cloneSprite()
|
|
|
|
if self.sprite.name ~= nil then
|
|
|
|
self.sprite.clone = self.assets.sprites[self.sprite.name]:clone()
|
2019-09-07 20:53:22 +02:00
|
|
|
self.sprite.clone:setCallbackTarget(self)
|
2019-05-05 21:01:54 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:changeAnimation(animation, restart)
|
|
|
|
if (self.sprite.clone == nil) then
|
|
|
|
self.assets.sprites[self.sprite.name]:changeAnimation(animation, restart)
|
|
|
|
else
|
|
|
|
self.sprite.clone:changeAnimation(animation, restart)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-09-07 20:53:22 +02:00
|
|
|
function BaseActor:animationEnded(animation)
|
|
|
|
-- Empty placeholder function
|
|
|
|
end
|
|
|
|
|
2019-05-05 21:01:54 +02:00
|
|
|
function BaseActor:setCustomSpeed(customSpeed)
|
|
|
|
if (self.sprite.clone == nil) then
|
|
|
|
self.assets.sprites[self.sprite.name]:setCustomSpeed(customSpeed)
|
|
|
|
else
|
|
|
|
self.sprite.clone:setCustomSpeed(customSpeed)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:updateSprite(dt)
|
|
|
|
if (self.sprite.clone ~= nil) then
|
|
|
|
self.sprite.clone:update(dt)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:setSpriteScallingX(sx)
|
|
|
|
local sx = sx or 1
|
|
|
|
|
|
|
|
self.sprite.sx = sx
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:setSpriteScallingY(sy)
|
|
|
|
local sy = sy or 1
|
|
|
|
|
|
|
|
self.sprite.sy = sy
|
|
|
|
end
|
|
|
|
|
2019-06-23 15:25:56 +02:00
|
|
|
function BaseActor:getCurrentAnimation()
|
|
|
|
if (self.sprite.clone == nil) then
|
2019-06-23 15:29:08 +02:00
|
|
|
return self.assets.sprites[self.sprite.name]:getCurrentAnimation()
|
2019-06-23 15:25:56 +02:00
|
|
|
else
|
2019-06-23 15:29:08 +02:00
|
|
|
return self.sprite.clone:getCurrentAnimation()
|
2019-06-23 15:25:56 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2019-06-23 10:19:01 +02:00
|
|
|
function BaseActor:getSpriteScalling()
|
|
|
|
return self.sprite.sx, self.sprite.sy
|
|
|
|
end
|
|
|
|
|
2019-06-23 14:27:07 +02:00
|
|
|
function BaseActor:getFrame()
|
|
|
|
if (self.sprite.name ~= nil) then
|
|
|
|
if (self.sprite.clone ~= nil) then
|
2019-06-23 15:29:08 +02:00
|
|
|
return self.sprite.clone:getFrame()
|
2019-06-23 14:27:07 +02:00
|
|
|
else
|
2019-06-23 15:29:08 +02:00
|
|
|
return self.assets.sprites[self.sprite.name]:getFrame()
|
2019-06-23 14:27:07 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:getRelativeFrame()
|
|
|
|
if (self.sprite.name ~= nil) then
|
|
|
|
if (self.sprite.clone ~= nil) then
|
2019-06-23 15:29:08 +02:00
|
|
|
return self.sprite.clone:getRelativeFrame()
|
2019-06-23 14:27:07 +02:00
|
|
|
else
|
2019-06-23 15:29:08 +02:00
|
|
|
return self.assets.sprites[self.sprite.name]:getRelativeFrame()
|
2019-06-23 14:27:07 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function BaseActor:getAnimationDuration()
|
|
|
|
if (self.sprite.name ~= nil) then
|
|
|
|
if (self.sprite.clone ~= nil) then
|
2019-06-23 15:29:08 +02:00
|
|
|
return self.sprite.clone:getAnimationDuration()
|
2019-06-23 14:27:07 +02:00
|
|
|
else
|
2019-06-23 15:29:08 +02:00
|
|
|
return self.assets.sprites[self.sprite.name]:getAnimationDuration()
|
2019-06-23 14:27:07 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-05-05 21:01:54 +02:00
|
|
|
function BaseActor:drawSprite(x, y, r, sx, sy, ox, oy, kx, ky)
|
|
|
|
if (self.sprite.name ~= nil) then
|
|
|
|
local x = x + self.sprite.ox
|
|
|
|
local y = y + self.sprite.oy
|
|
|
|
local sx = sx or self.sprite.sx
|
|
|
|
local sy = sy or self.sprite.sy
|
|
|
|
if (self.sprite.clone ~= nil) then
|
|
|
|
self.sprite.clone:draw(x, y, r, sx, sy, ox, oy, kx, ky)
|
|
|
|
else
|
|
|
|
self.assets.sprites[self.sprite.name]:drawAnimation(x, y, r, sx, sy, ox, oy, kx, ky)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-05-05 20:30:25 +02:00
|
|
|
return BaseActor
|