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