working elevator doors, need to figure out a lerp formula for having the doors open while the elevator is moving

This commit is contained in:
2024-05-04 18:06:08 -04:00
parent 78bf856c7e
commit 601a45b056
5 changed files with 201 additions and 103 deletions

View File

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

View File

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

View File

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

View File

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

View File

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