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

153 lines
No EOL
5.2 KiB
Lua

---@meta _
local squassets
local assetPath = "./SquAssets"
if pcall(require, assetPath) then squassets = require(assetPath) end
assert(squassets, "§4The hoverPoint module requires SquAssets, which was not found!§c")
---@class hoverPoint
local hoverPoint = {}
hoverPoint.all = {}
---*CONSTRUCTOR
---@param element ModelPart The element you are moving.
---@param elementOffset? Vector3 Defaults to `vec(0,0,0)`, the position of the hover point relative to you.
---@param springStrength? number Defaults to `0.2`, how strongly the object is pulled to it's original spot.
---@param mass? number Defaults to `5`, how heavy the object is (heavier accelerate/deccelerate slower).
---@param resistance? number Defaults to `1`, how much the elements speed decays (like air resistance).
---@param rotationSpeed? number Defaults to `0.05`, how fast the element should rotate to it's normal rotation.
---@param rotateWithPlayer? boolean Defaults to `true`, wheather or not the hoverPoint should rotate with you
---@param doCollisions? boolean Defaults to `false`, whether or not the element should collide with blocks (warning: the system is janky).
function hoverPoint:new(element, elementOffset, springStrength, mass, resistance, rotationSpeed, rotateWithPlayer, doCollisions)
---@class SquAPI.hoverPoint
local self = {}
self.element = element
assert(self.element,"§4The Hover point's model path is incorrect.§c")
self.element:setParentType("WORLD")
elementOffset = elementOffset or vec(0,0,0)
self.elementOffset = elementOffset*16
self.springStrength = springStrength or 0.2
self.mass = mass or 5
self.resistance = resistance or 1
self.rotationSpeed = rotationSpeed or 0.05
self.doCollisions = doCollisions
self.rotateWithPlayer = rotateWithPlayer
if self.rotateWithPlayer == nil then self.rotateWithPlayer = true end
self.pos = vec(0,0,0)
self.vel = vec(0,0,0)
self.init = true
self.delay = 0
self = setmetatable(self, {__index = hoverPoint})
table.insert(hoverPoint.all, self)
return self
end
--*CONTROL FUNCTIONS
---hoverPoint enable handling
function hoverPoint:disable() self.enabled = false return self end
function hoverPoint:enable() self.enabled = true return self end
function hoverPoint:toggle() self.enabled = not self.enabled return self end
---@param bool boolean
function hoverPoint:setEnabled(bool)
self.enabled = bool or false
return self
end
function hoverPoint:reset()
local yaw
if self.rotateWithPlayer then
yaw = math.rad(player:getBodyYaw() + 180)
else
yaw = 0
end
local sin, cos = math.sin(yaw), math.cos(yaw)
local offset = vec(
cos*self.elementOffset.x - sin*self.elementOffset.z,
self.elementOffset.y,
sin*self.elementOffset.x + cos*self.elementOffset.z
)
self.pos = player:getPos() + offset/16
self.element:setPos(self.pos*16)
self.element:setOffsetRot(0,-player:getBodyYaw()+180,0)
end
--*UPDATE FUNCTIONS
function hoverPoint:tick()
if self.enabled then
local yaw
if self.rotateWithPlayer then
yaw = math.rad(player:getBodyYaw() + 180)
else
yaw = 0
end
local sin, cos = math.sin(yaw), math.cos(yaw)
local offset = vec(
cos*self.elementOffset.x - sin*self.elementOffset.z,
self.elementOffset.y,
sin*self.elementOffset.x + cos*self.elementOffset.z
)
if self.init then
self.init = false
self.pos = player:getPos() + offset/16
self.element:setPos(self.pos*16)
self.element:setOffsetRot(0,-player:getBodyYaw()+180,0)
end
--adjusts the target based on the players rotation
local target = player:getPos() + offset/16
local pos = self.element:partToWorldMatrix():apply()
local dif = self.pos - target
local force = vec(0,0,0)
if self.delay == 0 then
--behold my very janky collision system
if self.doCollisions and world.getBlockState(pos):getCollisionShape()[1] then
local block, hitPos, side = raycast:block(pos-self.vel*2, pos)
self.pos = self.pos + (hitPos - pos)
if side == "east" or side == "west" then
self.vel.x = -self.vel.x*0.5
elseif side == "north" or side == "south" then
self.vel.z = -self.vel.z*0.5
else
self.vel.y = -self.vel.y*0.5
end
self.delay = 2
else
force = force - dif*self.springStrength --spring force
end
else
self.delay = self.delay - 1
end
force = force -self.vel*self.resistance --resistive force(based on air resistance)
self.vel = self.vel + force/self.mass
self.pos = self.pos + self.vel
end
end
---@param dt number Tick delta
function hoverPoint:render(dt, _)
self.element:setPos(
math.lerp(self.element:getPos(), self.pos * 16, dt / 2)
)
self.element:setOffsetRot(0,
math.lerp(self.element:getOffsetRot()[2], 180-player:getBodyYaw(), dt * self.rotationSpeed), 0)
end
return hoverPoint