From 601a45b056eea09680f86dae4aaeb79db80d7480 Mon Sep 17 00:00:00 2001 From: unittensor Date: Sat, 4 May 2024 18:06:08 -0400 Subject: [PATCH] working elevator doors, need to figure out a lerp formula for having the doors open while the elevator is moving --- src/server/main/Elevators/Otis1960/Doors.lua | 226 +++++++++++++------ src/server/main/Elevators/Otis1960/init.lua | 57 +++-- src/server/main/Lighting/init.lua | 2 +- src/server/main/Load/Tags/init.lua | 12 +- src/server/main/init.server.lua | 7 +- 5 files changed, 201 insertions(+), 103 deletions(-) diff --git a/src/server/main/Elevators/Otis1960/Doors.lua b/src/server/main/Elevators/Otis1960/Doors.lua index a7ee85a..c32555d 100644 --- a/src/server/main/Elevators/Otis1960/Doors.lua +++ b/src/server/main/Elevators/Otis1960/Doors.lua @@ -5,7 +5,11 @@ local RS: RunService = game:GetService("RunService") local Storage: ReplicatedStorage = game:GetService("ReplicatedStorage") +local Main = script.Parent.Parent.Parent +local Load = Main:WaitForChild("Load") + local Tween = require(Storage:WaitForChild("Tween")) +local Tags = require(Load:WaitForChild("Tags")) type DoorSensors = { [string]: BasePart @@ -17,11 +21,11 @@ type Impl_Constructor = { __index: Impl_Constructor, constructor: Constructor_Fun, --Class functions - DetectSensorHit: (self: ClassConstructor, DoorTween1: Tween, DoorTween2: Tween) -> RBXScriptConnection, - Opening: (self: ClassConstructor, opening: boolean?) -> () + __DetectSensorHit: (self: ClassConstructor, DoorTween1: Tween, DoorTween2: Tween) -> RBXScriptConnection, + ToggleElevatorDoors: (self: ClassConstructor, opening: boolean, floor: number) -> () } & Impl_Static_Props -type Constructor_Fun = (ElevatorBox: BasePart, ElevatorDoor1: BasePart, ElevatorDoor2: BasePart, ElevatorDoorSensor: Folder) -> ClassConstructor +type Constructor_Fun = (FloorDoorsTags: Tags.LandingTags, ElevatorBox: BasePart, ElevatorDoor1: BasePart, ElevatorDoor2: BasePart, ElevatorDoorSensor: Folder) -> ClassConstructor type Impl_Static_Props = { Closed: boolean, Sensors: boolean, @@ -32,6 +36,7 @@ type Impl_Static_Props = { __DontLeakMemory: RBXScriptConnection? } type Constructor_Return_Props = { + FloorDoorsTags: Tags.LandingTags, DoorTween1: CustomTween, DoorTween2: CustomTween, DoorSensor: DoorSensors, @@ -41,6 +46,11 @@ type Constructor_Return_Props = { DoorClosingClick: Sound } +type Floor = number +type FloorDoors = { + [Floor]: {Vector3}? +} + export type DoorConstructor = ClassConstructor local Doors = {} :: Impl_Constructor @@ -50,11 +60,11 @@ Doors.Closed = true Doors.Sensors = true Doors.Door1Stopped_X = Vector3.xAxis*2.9 Doors.Door2Stopped_X = Vector3.xAxis*5.8 -Doors.ElevatorDoorTime = 5 +Doors.ElevatorDoorTime = 3 Doors.ElevatorDoorStyle = Enum.EasingStyle.Quad Doors.__DontLeakMemory = nil -function Doors.constructor(ElevatorBox, ElevatorDoor1, ElevatorDoor2, ElevatorDoorSensor) +function Doors.constructor(FloorDoorsTags, ElevatorBox, ElevatorDoor1, ElevatorDoor2, ElevatorDoorSensor) local DoorTween1 = Tween.constructor(nil, ElevatorDoor1) local DoorTween2 = Tween.constructor(nil, ElevatorDoor2) local DoorSensor: DoorSensors = { @@ -68,6 +78,7 @@ function Doors.constructor(ElevatorBox, ElevatorDoor1, ElevatorDoor2, ElevatorDo DoorClosingClick.Parent = ElevatorDoor2 return setmetatable({ + FloorDoorsTags = FloorDoorsTags, DoorTween1 = DoorTween1, DoorTween2 = DoorTween2, DoorSensor = DoorSensor, @@ -79,86 +90,147 @@ function Doors.constructor(ElevatorBox, ElevatorDoor1, ElevatorDoor2, ElevatorDo end --speed -local init_opened_door1: Vector3?, - init_opened_door2: Vector3?, - init_closed_door1: Vector3?, - init_closed_door2: Vector3? +local init_floors_opened: FloorDoors = {} +local init_floors_closed: FloorDoors = {} + --Solve[5/x==3.5,x] --Solve was unable to solve the system with inexact coefficients. The answer was obtained by solving a corresponding exact system and numericizing the result. local opening_speed = Doors.ElevatorDoorTime/1.4285714285714286 local sensor_opening_speed = Doors.ElevatorDoorTime/2.5 -local function DoorsAnimationFloor(floor: number, opening: boolean?, activated_via_censor: boolean?, TweenTime: number): (Tween, Tween) - local DoorTween1 = Tween.constructor(TweenInfo.new( - TweenTime, - activated_via_censor and Enum.EasingStyle.Linear or Doors.ElevatorDoorStyle, - Enum.EasingDirection.Out - ), Floor10_Door1) - local DoorTween2 = Tween.constructor(TweenInfo.new( - TweenTime, - activated_via_censor and Enum.EasingStyle.Linear or Doors.ElevatorDoorStyle, - Enum.EasingDirection.Out - ), Floor10_Door2) - local Door1Tween_Floor: Tween = DoorTween1:Start(nil, { - Position = opening and init_closed_door1 or init_opened_door1 - }) - local Door2Tween_Floor: Tween = DoorTween2:Start(nil, { - Position = opening and init_closed_door1 or init_opened_door1 - }) +local function DoorsAnimationFloor(FloorDoors: {Instance?}, Floor: number, opening: boolean?, activated_via_censor: boolean?): (Tween?, Tween?) + local TweenTime = activated_via_censor and sensor_opening_speed or opening and opening_speed or Doors.ElevatorDoorTime + + local Door2Tween_Floor: Tween? + local Door1Tween_Floor: Tween? + local FloorDoor1 = FloorDoors[1] :: BasePart? + local FloorDoor2 = FloorDoors[2] :: BasePart? + + local FloorDoor1_P = FloorDoor1 and FloorDoor1.Position + local FloorDoor2_P = FloorDoor2 and FloorDoor2.Position + + if opening then + if not init_floors_closed[Floor] then + init_floors_closed[Floor] = {} + end + + if not (init_floors_closed[Floor] :: {})[1] and not (init_floors_closed[Floor] :: {})[2] then + if FloorDoor1_P then + (init_floors_closed[Floor] :: {})[1] = FloorDoor1_P+Doors.Door1Stopped_X + end + if FloorDoor2_P then + (init_floors_closed[Floor] :: {})[2] = FloorDoor2_P+Doors.Door2Stopped_X + end + end + else + if not init_floors_opened[Floor] then + init_floors_opened[Floor] = {} + end + + if not (init_floors_opened[Floor] :: {})[1] and not (init_floors_opened[Floor] :: {})[2] then + if FloorDoor1_P then + (init_floors_opened[Floor] :: {})[1] = FloorDoor1_P+Doors.Door1Stopped_X + end + if FloorDoor2_P then + (init_floors_opened[Floor] :: {})[2] = FloorDoor2_P+Doors.Door2Stopped_X + end + end + end + + if FloorDoor1 then + local DoorTween1 = Tween.constructor(TweenInfo.new( + TweenTime, + activated_via_censor and Enum.EasingStyle.Linear or Doors.ElevatorDoorStyle, + Enum.EasingDirection.Out + ), FloorDoor1) + + Door1Tween_Floor = DoorTween1:Start(nil, { + Position = opening and (init_floors_closed[Floor] :: {Vector3})[1] or (init_floors_opened[Floor] :: {Vector3})[1] + }) + end + + if FloorDoor2 then + local DoorTween2 = Tween.constructor(TweenInfo.new( + TweenTime, + activated_via_censor and Enum.EasingStyle.Linear or Doors.ElevatorDoorStyle, + Enum.EasingDirection.Out + ), FloorDoor2) + + Door2Tween_Floor = DoorTween2:Start(nil, { + Position = opening and (init_floors_closed[Floor] :: {Vector3})[2] or (init_floors_opened[Floor] :: {Vector3})[2] + }) + end return Door1Tween_Floor, Door2Tween_Floor end -local function DoorsAnimation(self: ClassConstructor, opening: boolean?, activated_via_censor: boolean?) - self.ElevatorBox.Anchored = true - +local function ElevatorDoorsAnimation(self: ClassConstructor, opening: boolean?, activated_via_censor: boolean?): Tween? + --Roblox physics will freak out + self.ElevatorDoor1.CanCollide = false + self.ElevatorDoor2.CanCollide = false + local ElevatorDoor1_P: Vector3 = self.ElevatorDoor1.Position local ElevatorDoor2_P: Vector3 = self.ElevatorDoor2.Position - - local TweenTime = activated_via_censor and sensor_opening_speed or opening and opening_speed or Doors.ElevatorDoorTime if opening then - if not init_closed_door1 and not init_closed_door2 then - init_closed_door1 = ElevatorDoor1_P+Doors.Door1Stopped_X - init_closed_door2 = ElevatorDoor2_P+Doors.Door2Stopped_X + --This is mega cringe but the doors can open while the elevator is moving + local Alpha = 0 + local P1 = (ElevatorDoor1_P+Doors.Door1Stopped_X).X + local P2 = (ElevatorDoor2_P+Doors.Door2Stopped_X).X + + while task.wait() do + Alpha+=.001 + + local Door1OpenVector = Vector3.new(P1, self.ElevatorDoor1.Position.Y, self.ElevatorDoor1.Position.Z) + local Door2OpenVector = Vector3.new(P2, self.ElevatorDoor2.Position.Y, self.ElevatorDoor2.Position.Z) + + self.ElevatorDoor1.Position = self.ElevatorDoor1.Position:Lerp(Door1OpenVector, Alpha) + self.ElevatorDoor2.Position = self.ElevatorDoor2.Position:Lerp(Door2OpenVector, Alpha) + + print(Alpha) + if Alpha>=1 then + break + end end else - if not init_opened_door1 and not init_opened_door2 then - init_opened_door1 = ElevatorDoor1_P-Doors.Door1Stopped_X - init_opened_door2 = ElevatorDoor2_P-Doors.Door2Stopped_X + + local TweenTime = activated_via_censor and sensor_opening_speed or opening and opening_speed or Doors.ElevatorDoorTime + + local Door1Tween = self.DoorTween1:Start(nil, { + Position = ElevatorDoor1_P-Doors.Door1Stopped_X + }, TweenInfo.new( + TweenTime, + activated_via_censor and Enum.EasingStyle.Linear or Doors.ElevatorDoorStyle, + Enum.EasingDirection.Out + )) + + local Door2Tween = self.DoorTween2:Start(nil, { + Position = ElevatorDoor2_P-Doors.Door2Stopped_X + }, TweenInfo.new( + TweenTime, + activated_via_censor and Enum.EasingStyle.Linear or Doors.ElevatorDoorStyle, + Enum.EasingDirection.Out + )) + + if Doors.__DontLeakMemory and Doors.__DontLeakMemory.Connected then + Doors.__DontLeakMemory:Disconnect() end + Doors.__DontLeakMemory = self:__DetectSensorHit(Door1Tween, Door2Tween) + + if not opening then + --Door clicking noise + task.delay(Doors.ElevatorDoorTime-.90, function() + --is the door close enough to closing? + if (ElevatorDoor2_P+Doors.Door2Stopped_X).X-self.ElevatorDoor2.Position.X>5 then + self.DoorClosingClick:Play() + end + end) + end + + return Door2Tween end - local Door1Tween = self.DoorTween1:Start(nil, { - Position = opening and init_closed_door1 or init_opened_door1 - }, TweenInfo.new( - TweenTime, - activated_via_censor and Enum.EasingStyle.Linear or Doors.ElevatorDoorStyle, - Enum.EasingDirection.Out - )) - local Door2Tween = self.DoorTween2:Start(nil, { - Position = opening and init_closed_door2 or init_opened_door2 - }, TweenInfo.new( - TweenTime, - activated_via_censor and Enum.EasingStyle.Linear or Doors.ElevatorDoorStyle, - Enum.EasingDirection.Out - )) - - if not opening then - --Door clicking noise - task.delay(Doors.ElevatorDoorTime-.90, function() - --is the door close enough to closing? - if (init_closed_door2 :: Vector3).X-self.ElevatorDoor2.Position.X>5 then - self.DoorClosingClick:Play() - end - end) - end - if Doors.__DontLeakMemory then - Doors.__DontLeakMemory:Disconnect() - end - Doors.__DontLeakMemory = self:DetectSensorHit(Door1Tween, Door2Tween) - - return Door1Tween, Door2Tween + return nil end local raycastParams = RaycastParams.new() @@ -174,8 +246,9 @@ for n: number = 1, #workspace_items do end end -function Doors:DetectSensorHit(DoorTween1, DoorTween2) +function Doors:__DetectSensorHit(DoorTween1, DoorTween2) local Step = nil + if Doors.Sensors and Doors.Closed then raycastParams.FilterDescendantsInstances = {self.ElevatorBox, table.unpack(RayIgnoring)} @@ -187,16 +260,15 @@ function Doors:DetectSensorHit(DoorTween1, DoorTween2) DoorTween1:Pause() DoorTween2:Pause() task.wait(1) --elevators irl have this delay - DoorsAnimation(self, true, true) - -- DoorTween1:Destroy() - -- DoorTween2:Destroy() + ElevatorDoorsAnimation(self, true, true) end end) end + return Step end -function Doors:Opening(opening) +function Doors:ToggleElevatorDoors(opening, floor) --short circuiting central if opening then if Doors.Closed then @@ -214,8 +286,14 @@ function Doors:Opening(opening) end end - local Door1Tween, Door2Tween = DoorsAnimation(self, opening) - Door2Tween.Completed:Wait() + local FloorDoors = DoorsAnimationFloor(self.FloorDoorsTags[floor], floor, opening) + local Door2Tween = ElevatorDoorsAnimation(self, opening) + + if Door2Tween then + Door2Tween.Completed:Wait() + end + self.ElevatorDoor1.CanCollide = true + self.ElevatorDoor2.CanCollide = true if Doors.__DontLeakMemory then Doors.__DontLeakMemory:Disconnect() diff --git a/src/server/main/Elevators/Otis1960/init.lua b/src/server/main/Elevators/Otis1960/init.lua index cdad693..9671ae8 100644 --- a/src/server/main/Elevators/Otis1960/init.lua +++ b/src/server/main/Elevators/Otis1960/init.lua @@ -46,12 +46,13 @@ type Impl_Static_Props = { LanternChimeDirection: rbxassetid, LanternChimeLanding: rbxassetid, FloorLevelingDistance: number, + DoorOpeningDistance: number, LeveledDistance: number, __Moving: boolean, __CurrentFloor: number } -type Constructor_Fun = (TagsConstructor: TagsConstructor, ButtonsTags: Tags.ElevatorButtons, LanternsTags: Tags.Lanterns) -> ClassConstructor +type Constructor_Fun = (TagsConstructor: TagsConstructor, ButtonsTags: Tags.ElevatorButtons, LanternsTags: Tags.Lanterns, LandingDoors: Tags.LandingTags) -> ClassConstructor type Constructor_Return_Props = { Tags: Tags, MOConstructor: MovingObjects.MovingObjectsConstructor, @@ -84,6 +85,7 @@ local Otis1960 = {} :: Impl_Constructor Otis1960.__index = Otis1960 Otis1960.FloorLevelingDistance = 2.5 +Otis1960.DoorOpeningDistance = Otis1960.FloorLevelingDistance/2.8 Otis1960.LeveledDistance = 0.5 Otis1960.Responsiveness = 50 Otis1960.MaxVelocity = 10 @@ -103,18 +105,17 @@ local ButtonFunctions: ButtonFunctions = { [Enums.ButtonTree.Car] = function(self, ButtonName, ButtonsConstructor, ButtonTree) local DecodedFloor = Tags.Decoders.CarTag(ButtonName) - if not DecodedFloor then + + if DecodedFloor then + local Prompt = PromptModule.constructor(ButtonTree.Prompt :: ProximityPrompt, ButtonTree.Inst :: Instance) + Prompt:AddHookTriggered(function(Player: Player) + if DecodedFloor then + local _ButtonThread = ButtonsConstructor:AestheticActivateButton(ButtonTree.Inst :: BasePart, false, Otis1960.ButtonActivatedColor) + self:GoToLevel(DecodedFloor) + end + end) end - - local Prompt = PromptModule.constructor(ButtonTree.Prompt, ButtonTree.Inst) - - Prompt:AddHookTriggered(function(Player: Player) - if DecodedFloor then - local _ButtonThread = ButtonsConstructor:AestheticActivateButton(ButtonTree.Inst :: BasePart, false, Otis1960.ButtonActivatedColor) - self:GoToLevel(DecodedFloor) - end - end) end, [Enums.ButtonTree.Special] = function(self, ButtonName, ButtonsConstructor, ButtonTree) @@ -141,7 +142,7 @@ local function HookButtons(self: ClassConstructor, ButtonsConstructor: ButtonTag end end -function Otis1960.constructor(TagsConstructor, ButtonsTags, LanternsTags) +function Otis1960.constructor(TagsConstructor, ButtonsTags, LanternsTags, LandingDoors) local self = {} :: Constructor_Return_Props self.ElevatorBox_1960 = TagsConstructor:Request("ElevatorMover_1960") :: UnionOperation self.ElevatorDoor1 = TagsConstructor:Request("ElevatorDoor_1960_1") :: BasePart @@ -173,7 +174,7 @@ function Otis1960.constructor(TagsConstructor, ButtonsTags, LanternsTags) self.BoxAlignPosition, self.BoxAlignOrientation = ElevatorMover(self.ElevatorBox_1960, self.ElevatorBox_1960.Position, Otis1960.Responsiveness, Otis1960.MaxVelocity) - self.ElevatorDoors = Doors.constructor(self.ElevatorBox_1960, self.ElevatorDoor1, self.ElevatorDoor2, self.ElevatorDoorSensor) + self.ElevatorDoors = Doors.constructor(LandingDoors, self.ElevatorBox_1960, self.ElevatorDoor1, self.ElevatorDoor2, self.ElevatorDoorSensor) self.TractionRopes = TractionRopes.constructor(self.Ropes, self.ElevatorBox_1960, Leveling) --Buttons @@ -183,6 +184,11 @@ function Otis1960.constructor(TagsConstructor, ButtonsTags, LanternsTags) local ClassConstructor = setmetatable(self, Otis1960) HookButtons(ClassConstructor, ButtonsConstructor, Enums.ButtonTree.Car) + --Open the elevator doors on server start + task.spawn(function() + self.ElevatorDoors:ToggleElevatorDoors(true, 1) + end) + print("🔝 Otis1960 initialized and ready") return ClassConstructor end @@ -203,7 +209,10 @@ local function FloorLeveled(self: ClassConstructor, RequestedLevel: number) end function Otis1960:__MoveFloors(GoalLevelVEC, RequestedLevel, GoingUp) - local RotationDelta = 0 + self.ElevatorDoors:ToggleElevatorDoors(false, Otis1960.__CurrentFloor) + + local Delta = 0 + local DoorsOpeningEvent = false local ElevatorBoxCurrentPos = self.ElevatorBox_1960.Position if self.__MovingConnection and self.__MovingConnection.Connected then @@ -220,30 +229,38 @@ function Otis1960:__MoveFloors(GoalLevelVEC, RequestedLevel, GoingUp) --Otis1960_ShaftGovernor self.__MovingConnection = RS.Heartbeat:Connect(function(_dt) --Not safe for parallel - RotationDelta+=1 + Delta+=1 Otis1960.__Moving = true local ElevatorPosition: Vector3 = self.ElevatorBox_1960.Position + local ElevatorPositionY: number = ElevatorPosition.Y + local BoxAlignY: number = self.BoxAlignPosition.Position.Y local ElevatorVelocityY: number = self.ElevatorBox_1960:GetVelocityAtPosition(ElevatorPosition).Y - self.MOConstructor:Frame_Pullies(RotationDelta, ElevatorVelocityY) + self.MOConstructor:Frame_Pullies(Delta, ElevatorVelocityY) self.TractionRopes:Move(26.3, ElevatorPosition) --Kill the connection if GoingUp then - if ElevatorPosition.Y>=self.BoxAlignPosition.Position.Y-Otis1960.FloorLevelingDistance then + if ElevatorPositionY>=BoxAlignY-Otis1960.FloorLevelingDistance then FloorLeveling(self, RequestedLevel) + + if ElevatorPositionY>=BoxAlignY-Otis1960.DoorOpeningDistance and not DoorsOpeningEvent then + print("fired") + DoorsOpeningEvent = true + self.ElevatorDoors:ToggleElevatorDoors(true, RequestedLevel) + end end - if ElevatorPosition.Y>=self.BoxAlignPosition.Position.Y-Otis1960.LeveledDistance then + if ElevatorPositionY>=BoxAlignY-Otis1960.LeveledDistance then FloorLeveled(self, RequestedLevel) end else - if ElevatorPosition.Y<=self.BoxAlignPosition.Position.Y+Otis1960.FloorLevelingDistance then + if ElevatorPositionY<=BoxAlignY+Otis1960.FloorLevelingDistance then FloorLeveling(self, RequestedLevel) end - if ElevatorPosition.Y<=self.BoxAlignPosition.Position.Y+Otis1960.LeveledDistance then + if ElevatorPositionY<=BoxAlignY+Otis1960.LeveledDistance then FloorLeveled(self, RequestedLevel) end end diff --git a/src/server/main/Lighting/init.lua b/src/server/main/Lighting/init.lua index d9adb09..518b124 100644 --- a/src/server/main/Lighting/init.lua +++ b/src/server/main/Lighting/init.lua @@ -60,7 +60,7 @@ return function(): Effects Lighting[Light_Prop] = Light_Value end) if not changed then - warn("Server Lighting:", err, debug.traceback()) + warn(err) end end diff --git a/src/server/main/Load/Tags/init.lua b/src/server/main/Load/Tags/init.lua index a9fedec..602511f 100644 --- a/src/server/main/Load/Tags/init.lua +++ b/src/server/main/Load/Tags/init.lua @@ -109,10 +109,12 @@ export type ExportedTags = { [string]: TagProduct } +export type LandingTags = { + [number]: {Instance} +} + export type DoorTags = { - [Enums.ElevatorValues]: { - [number]: {Instance} - } + [Enums.ElevatorValues]: LandingTags } export type TagProduct = Instance | {Instance} @@ -123,7 +125,7 @@ Tags.__index = Tags Tags.Decoders = { CarTag = function(FloorTag) - local Match = FloorTag:match('^%d+$') + local Match = FloorTag:match('%d+$') return Match and tonumber(Match) end } @@ -228,7 +230,7 @@ function Tags:__ElevatorButtons() if typeof(Inst) == "Instance" then Buttons[EnumValue :: Enums.ElevatorValues][TagName] = Inst else - warn(`TODO block hit. Inst={Inst},`, debug.traceback()) + warn(`Elevator buttons failed, tag has multiple instances. Inst={Inst} TagName={TagName},`, debug.traceback()) end end end diff --git a/src/server/main/init.server.lua b/src/server/main/init.server.lua index a66d173..7ef1e81 100644 --- a/src/server/main/init.server.lua +++ b/src/server/main/init.server.lua @@ -50,6 +50,7 @@ print("[DEBUG] Lanterns=", Lanterns) local LandingDoors = TagsConstructor:__ElevatorDoors() print("[DEBUG] Elevator Landing Doors=", LandingDoors) -local Otis1960Lanterns = Lanterns[Enums.Elevator.Otis1960] -local Otis1960Buttons = Buttons[Enums.Elevator.Otis1960] -local Otis1960 = Otis1960_Module.constructor(TagsConstructor, Otis1960Buttons, Otis1960Lanterns) \ No newline at end of file +local Otis1960Lanterns = Lanterns[Enums.Elevator.Otis1960] +local Otis1960Buttons = Buttons[Enums.Elevator.Otis1960] +local Otis1960LandingDoors = LandingDoors[Enums.Elevator.Otis1960] +local Otis1960 = Otis1960_Module.constructor(TagsConstructor, Otis1960Buttons, Otis1960Lanterns, Otis1960LandingDoors) \ No newline at end of file