mirror of
https://github.com/unixtensor/Roblox-Elevator-Game.git
synced 2025-12-14 06:41:55 +00:00
105 lines
3.3 KiB
Lua
105 lines
3.3 KiB
Lua
--!optimize 2
|
|
--!native
|
|
--!strict
|
|
|
|
type Head = BasePart
|
|
type UpperTorso = BasePart
|
|
type Neck = Motor6D
|
|
type Waist = Motor6D
|
|
type NeckC0 = CFrame
|
|
type WaistC0 = CFrame
|
|
type UDP = UnreliableRemoteEvent
|
|
type CharacterShared = Folder
|
|
|
|
type struct_SpineMovement = {
|
|
Neck: CFrame,
|
|
Waist: CFrame
|
|
}
|
|
|
|
type ClassConstructor = typeof(setmetatable({} :: Constructor_Return_Props, {} :: Impl_Constructor))
|
|
type Impl_Constructor = {
|
|
__index: Impl_Constructor,
|
|
constructor: Constructor_Fun,
|
|
--Class functions
|
|
Move: (self: ClassConstructor, CameraCFrame: CFrame, IsFirstPerson: boolean) -> ()
|
|
} & Impl_Static_Props
|
|
|
|
type Constructor_Fun = (CharacterShared: CharacterShared, Head: Head, UpperTorso: UpperTorso) -> ClassConstructor
|
|
type Impl_Static_Props = {
|
|
Enabled: boolean,
|
|
Multiplier: number
|
|
}
|
|
type Constructor_Return_Props = {
|
|
Remote: UDP,
|
|
Head: Head,
|
|
UpperTorso: UpperTorso,
|
|
Neck: Neck,
|
|
Waist: Waist,
|
|
NeckC0: NeckC0,
|
|
WaistC0: WaistC0
|
|
}
|
|
|
|
export type SpineKinematicsConstructor = ClassConstructor
|
|
|
|
local Spine = {} :: Impl_Constructor
|
|
Spine.__index = Spine
|
|
|
|
Spine.Enabled = true
|
|
Spine.Multiplier = .5
|
|
|
|
function Spine.constructor(CharacterShared, Head, UpperTorso)
|
|
local self = {}
|
|
self.Remote = Instance.new("UnreliableRemoteEvent") :: UDP
|
|
self.Remote.Name = "SpineStream"
|
|
self.Remote.Parent = CharacterShared
|
|
|
|
self.Head = Head
|
|
self.UpperTorso = UpperTorso
|
|
self.Neck = Head:WaitForChild("Neck") :: Motor6D
|
|
self.Waist = UpperTorso:WaitForChild("Waist") :: Motor6D
|
|
self.NeckC0 = (self.Neck :: Motor6D).C0
|
|
self.WaistC0 = (self.Neck :: Motor6D).C0
|
|
|
|
return setmetatable(self, Spine)
|
|
end
|
|
|
|
local function SpineMovement(self: ClassConstructor, CameraCFrame: CFrame, IsFirstPerson: boolean): struct_SpineMovement
|
|
local HeadCFrame: CFrame = self.Head.CFrame
|
|
local TorsoPosition: Vector3 = self.UpperTorso.Position
|
|
local TorsoLookVector: Vector3 = self.UpperTorso.CFrame.LookVector
|
|
local HeadPosition: Vector3 = HeadCFrame.Position
|
|
local CameraPosition: Vector3 = CameraCFrame.Position
|
|
|
|
local HeadDelta: Vector3 = HeadPosition-CameraPosition
|
|
local TorsoDeltaNormal: Vector3 = (TorsoPosition-CameraPosition).Unit
|
|
local HeadDeltaNormal: Vector3 = HeadDelta.Unit
|
|
local HeadDeltaMagnitude: number = HeadDelta.Magnitude
|
|
|
|
local arc = Spine.Multiplier*math.asin(HeadDelta.Y/HeadDeltaMagnitude)
|
|
local Neck = CFrame.Angles(arc, 0, 0)
|
|
local Waist = CFrame.Angles(arc, 0, 0)
|
|
|
|
if not IsFirstPerson then
|
|
--Make this less cringe at some point, combine the dot product into the equation
|
|
local LookingAtSelf = CameraCFrame.LookVector:Dot(HeadCFrame.LookVector)<0 --Make our head face the camera if we are looking at ourself
|
|
local HeadCrossDelta = Spine.Multiplier*HeadDeltaNormal:Cross(TorsoLookVector).Y
|
|
local TorsoCrossDelta = Spine.Multiplier*TorsoDeltaNormal:Cross(TorsoLookVector).Y
|
|
|
|
Neck*=CFrame.Angles(0, HeadCrossDelta, 0)
|
|
Waist*=CFrame.Angles(0, LookingAtSelf and TorsoCrossDelta or -TorsoCrossDelta, 0)
|
|
end
|
|
|
|
return {
|
|
Neck = Neck,
|
|
Waist = Waist
|
|
}
|
|
end
|
|
|
|
function Spine:Move(CameraCFrame, IsFirstPerson)
|
|
local SpineIK = SpineMovement(self, CameraCFrame, IsFirstPerson)
|
|
|
|
self.Neck.C0 = self.Neck.C0:Lerp(self.NeckC0*SpineIK.Neck, .9)
|
|
self.Waist.C0 = self.Waist.C0:Lerp(self.WaistC0*SpineIK.Waist, .9)
|
|
end
|
|
|
|
return Spine |