local ParentObject = require "scenes.battlesystem.actors.parent" local Movable = ParentObject:extend() local MOVEMENT_NONE = "none" local MOVEMENT_MOTION = "motion" local MOVEMENT_TARGET = "target" local ZGRAVITY = 12 local MIDDLE_ARENA = 6 function Movable:new(world, x, y, z) Movable.super.new(self, world, x, y, z) self.direction = utils.math.sign(MIDDLE_ARENA - x) self.start = {} self.start.x = x self.start.y = y self.start.z = z self.start.direction = self.direction self:resetMovement() end -- MOVE FUNCTIONS -- All functions handling the moving function Movable:resetMovement() self:resetMotion() self:resetJump() self:resetDirection() self:resetTarget() end function Movable:resetMovementType() self.movementType = MOVEMENT_NONE end function Movable:stopMoving() self:resetMotion() self:finishAction("goTo") end function Movable:update(dt) Movable.super.update(self, dt) self:updateMotion(dt) self:updateDirection() self:updatePreviousPosition() end function Movable:updatePreviousPosition() self.xprevious = self.x self.yprevious = self.y self.zprevious = self.z end -- GoTo movement functions function Movable:goTo(dx, dy, duration) self:resetMotion() self:setTarget(dx, dy) local speed = utils.math.pointDistance(self.x, self.y, dx, dy) / duration self:setMotionToPoint(speed, dx, dy) self.movementType = MOVEMENT_TARGET end function Movable:goTo3D(dx, dy, dz, duration) self:resetMotion() self:resetJump() self:setTarget(dx, dy, dz) local speed = utils.math.pointDistance3D(self.x, self.y, self.z, dx, dy, dz) / duration self:setMotionToPoint(speed, dx, dy, dz) self.movementType = MOVEMENT_TARGET end -- MOTION HANDLING function Movable:resetMotion() self.speed, self.angle = 0, 0 self.xspeed, self.yspeed = 0,0 self:updatePreviousPosition() self:resetMovementType() end function Movable:setMotion(speed, angle, vertAngle) self.speed = speed self.angle = angle self.motion3D = (vertAngle ~= nil) if (self.motion3D) then self.vertAngle = vertAngle end self.movementType = MOVEMENT_MOTION end function Movable:setMotionToPoint(speed, dx, dy, dz) local angle = utils.math.pointDirection(self.x, self.y, dx, dy) local vertAngle = nil if (dz ~= nil) then local distance2D = utils.math.pointDistance(self.x, self.y, dx, dy) vertAngle = utils.math.pointDirection(0, self.z, distance2D, dz) end self:setMotion(speed, angle, vertAngle) end function Movable:updateMotion(dt) self:checkTarget(dt) self.xspeed, self.yspeed, self.zspeed = self:getMotionCoord() self.x = self.x + (self.xspeed) * dt self.y = self.y + (self.yspeed) * dt self.z = self.z + (self.zspeed) * dt self:checkGround() end function Movable:getMotionCoord() local gspeed, xspeed, yspeed, zspeed if (self.motion3D) then gspeed, zspeed = utils.math.lengthdir(self.speed, self.vertAngle) xspeed, yspeed = utils.math.lengthdir(gspeed, self.angle) else xspeed, yspeed = utils.math.lengthdir(self.speed, self.angle) zspeed = self:getJumpMotion() end return xspeed, yspeed, zspeed end -- Target handling function Movable:setTarget(x, y, z) self.target = {} self.target.x = x self.target.y = y self.target.z = z end function Movable:isTargetActive() return (self.target ~= nil) end function Movable:resetTarget() self.target = nil end function Movable:isNearTarget(distance) if (not self:isTargetActive()) then return false end if (self.target.z == nil) then return (utils.math.pointDistance(self.x, self.y, self.target.x, self.target.y) <= distance) else return (utils.math.pointDistance3D(self.x, self.y, self.z, self.target.x, self.target.y, self.target.z) <= distance) end end function Movable:checkTarget(dt) if (self:isTargetActive()) then local isNearTarget = self:isNearTarget(self.speed * dt) if (isNearTarget) then self:finishTarget() end end end function Movable:finishTarget() -- TODO: add a one-time signal to target handling if (self.movementType == MOVEMENT_TARGET) then self.x = self.target.x self.y = self.target.y if (self.target.z ~= nil) then self.z = self.target.z end self:stopMoving() end self:resetTarget() end -- Direction handling function Movable:resetDirection() self.direction = self.start.direction self.directionPrevious = self.start.direction self.directionLocked = false end function Movable:updateDirection() -- Handle direction if math.abs(self.xspeed) >= 0.01 then if not (self.directionLocked or self.jump.lockDir) then self.direction = utils.math.sign(self.xspeed) end end end -- Jump system function Movable:resetJump() self.jump = {} self.jump.useDefaultAnimation = true self.jump.isJumping = false self.jump.bounceNumber = 0 self.jump.stopWhenLanding = false self.jump.lockDir = false self.zspeed = 0 self.motion3D = false self.vertAngle = 0 end function Movable:stopJumping() self.z = 0 self.tweens:newTimer(0.01, "jump") if (self.jump.stopWhenLanding) then self:resetMotion() end self:resetJump() self:land() end function Movable:land() -- Empty function end function Movable:setJump(power, bounceNumber, useDefaultAnimation) self.zspeed = (power * 60) self.jump.useDefaultAnimation = useDefaultAnimation self.jump.bounceNumber = bounceNumber self.jump.isJumping = true end function Movable:jumpTo(dx, dy, height, speed, useDefaultAnimation) height = height or 4 self:setMotionToPoint(speed, dx, dy) self:setJump(height, 0, useDefaultAnimation) self.jump.stopWhenLanding = true end function Movable:jumpBack(height, speed) self:jumpTo(self.start.x, self.start.y, height, speed, true) self.jump.lockDir = true end function Movable:getJumpMotion() if (self.jump.isJumping) then return self.zspeed - ZGRAVITY else return 0 end end function Movable:checkGround() if (self.z <= 0 and self.jump.isJumping) then if (self.jump.bounceNumber > 0) then self.zspeed = self.zspeed * -0.5 self.jump.bounceNumber = self.jump.bounceNumber - 1 else self:stopJumping() end end end return Movable