figura-skin/scripts/libs/SquAPI_modules/squishy.lua
2025-11-23 01:10:42 -08:00

110 lines
No EOL
3.5 KiB
Lua

---@class squishy
local squishy = {}
squishy.all = {}
---*CONSTRUCTOR
---@param model ModelPart The model to squish
---@param dampening? number Defaults to `0.3`, how much the movement is dampened(like air resistance)
---@param spingStrength? number Defaults to `0.3`, how strongly the model will return to its original scale.
---@param crouchBounce? number Defaults to `-0.5`, when crouching/uncrouching, the model will bounce by this factor. Negative values squish down while positive up.
---@param lowerLimit? Vector3 Defaults to `vec(0.6, 0.5, 0.6)`, the minimum scale the model can be squished to.
---@param upperLimit? Vector3 Defaults to `vec(1.25, 1.5, 1.25)`, the maximum scale the model can be squished to.
function squishy:new(model, spingStrength, dampening, crouchBounce, lowerLimit, upperLimit)
---@class SquAPI.squishy
local self = {}
assert(model, "§4The squishy model path is incorrect.§c")
self.model = model
self.springStrength = spingStrength or 0.3
self.dampening = dampening or 0.3
self.crouchBounce = crouchBounce or -0.5
self.lowerLimit = lowerLimit or vec(0.6, 0.5, 0.6)
self.upperLimit = upperLimit or vec(1.25, 1.5, 1.25)
self.scale = vec(1,1,1)
self.oldScale = vec(1,1,1)
self.scaleVel = vec(0,0,0)
self = setmetatable(self, {__index = squishy})
table.insert(squishy.all, self)
return self
end
--*CONTROL FUNCTIONS
---squishy enable handling
function squishy:disable() self.enabled = false return self end
function squishy:enable() self.enabled = true return self end
function squishy:toggle() self.enabled = not self.enabled return self end
---@param bool boolean
function squishy:setEnabled(bool)
self.enabled = bool or false
return self
end
--*UPDATE FUNCTIONS
---@param force Vector3 The force vector to apply to the model
function squishy:applyForce(force)
self.scaleVel = vec(
self.scaleVel.x + force.x - force.y/2 - force.z/2,
self.scaleVel.y + force.y - force.x/2 - force.z/2,
self.scaleVel.z + force.z - force.x/2 - force.y/2
)
end
squishy.oldPose = "STANDING"
function squishy:tick()
self.oldScale = self.scale
local verticalVel = -player:getVelocity()[2]
local pose = player:getPose()
--avoid wonky when flying/swimming
if pose == "FALL_FLYING" or pose == "SWIMMING" or player:riptideSpinning() then
verticalVel = 0
end
--bounce when crouching/uncrouching
if pose == "CROUCHING" and self.oldPose ~= "CROUCHING" then
self:applyForce(vec(0, self.crouchBounce, 0))
elseif self.oldPose == "CROUCHING" and pose ~= "CROUCHING" then
self:applyForce(vec(0, -self.crouchBounce, 0))
end
self.oldPose = pose
--pulls back to original scale
local dif = vec(1,1,1) - self.scale
local springForce = dif*self.springStrength
--resistive force/dampening
local dampeningForce = self.scaleVel * self.dampening
local netForce = vec(0, verticalVel/4, 0) + springForce - dampeningForce
self:applyForce(netForce)
self.scale = self.scale + self.scaleVel
--safety net to make sure it doesn't get stuck at a non-original scale, which can happen if the forces cancel out
self.scale = self.scale + dif/5
--limiting scale
self.scale = vec(
math.clamp(self.scale.x, 0.6, 1.25),
math.clamp(self.scale.y, 0.5, 1.5),
math.clamp(self.scale.z, 0.6, 1.25)
)
end
---@param dt number Tick delta
function squishy:render(dt, _)
self.model:setScale(math.lerp(self.oldScale, self.scale, dt))
end
return squishy