I am working on a game that will feature an opening and closing gate for each player’s base.
I would like for this gate to have a cool “animation” where it will recede into the floor before it is not visible anymore, and then, when the player decides to close the gate, it retracts up to its original position, like seen here.
There would be a part in the model that would not move whatsoever; it would be an invisible, non-collidable part that would contain the ProximityPrompt that would be used for opening and closing this gate.
I have an idea of how I would do this, but I am not sure if TweenService or using an Animation Editor would be appropiate, especially since no parts of the gate are allowed to be unanchored - it is imperative all parts of this gate remain anchored.
1 Like
Unfortunately the CFrame of a Model can’t be set by using its CFrame property, you have to use PivotTo and TweenService only works on properties. Pretty annoying API for both Model and TweenService but oh well.
Here’s a workaround that lets you use TweenService to tween any function:
function tweenFunction(tweenInfo, callback, autoPlay: boolean) --Can't remember if it's bool or boolean xD
local stepped = RunService.IsServer and RunService.Stepped or RunService.RenderStepped
local progress = Instance.new("NumberValue")
progress.Value = 0
local tween = TweenService:Create(progress, tweenInfo, {Value = 1.0})
local steppedC = stepped:Connect(function()
callback(progress.Value)
end)
tween.Completed:Once(function(playbackState)
if playbackState == PlaybackState.Completed then
if numberValue.Value < 1.0 then
callback(1.0) --Probably not necessary but I don't know for sure.
end
steppedC:Disconnect()
elseif playbackState == PlaybackState.Cancelled then
steppedC:Disconnect()
end
end)
if play then tween:Play() end
return tween --So user can play, pause or cancel it
end
Then you can tween the model CFrame by using the progress value to lerp the CFrame:
function tweenModelCFrame(model, tweenInfo, targetCFrame, autoPlay: boolean)
local initialCFrame = model:GetPivot()
local function updateCFrame(progress: number)
model:PivotTo(initialCFrame:Lerp(targetCFrame, progress))
end
return tweenFunction(tweenInfo, updateCFrame, play)
end
The advantage is that you can still use all the convenient TweenInfo properties. I can’t test the code but the idea should work. Let me know if there are bugs, and I hope this helps!
2 Likes
What would “tweenInfo” be in your function? Also, what should “targetCFrame” be if I intend to move the gate down it’s y-axis by 13 studs? Move it up 13 studs etc.?
2 Likes
tweenInfo would be any TweenInfo object. If you’re not sure what that is, look into how to use TweenService there are decent tutorials on the wiki.
Here’s how I’d use the function to control gates:
--GateManager, server script.
local EasingStyle, EasingDirection = Enum.EasingStyle, Enum.EasingDirection
local GATE_HEIGHT = 13
local GATE_ANIM_TWEENINFO = TweenInfo.new(1.5, EasingStyle.Bounce, EasingDirection.Out)
local GateState = { --Custom Enum, to avoid using strings. Less prone to typos. Could be even better but this is nice and simple.
Open = {},
Closed = {},
Opening = {},
Closing = {},
}
local gateInfos = {}
function setupGate(gateModel)
local gateInfo = {
State = GateState.Closed,
InitialCFrame = gateModel:GetPivot(),
}
gateInfos[gateModel] = gateInfo
--Maybe if you need to set up ClickDetectors and stuff also do that here
end
function openGate(gateModel)
local gateInfo = gateInfos[gateModel]
local state = gateInfo.State
if state == GateState.Closed or state == GateState.Closing then
if state == GateState.Closing then
gateInfo.CurrentTween:Cancel()
end
gateInfo.State = GateState.Opening
local targetCFrame = gateInfo.InitialCFrame - (Vector3.yAxis * GATE_HEIGHT)
gateInfo.CurrentTween = tweenModelCFrame(gateModel, GATE_ANIM_TWEENINFO, targetCFrame, true)
elseif state == GateState.Open or state == GateState.Opening then
--Do nothing if already open or opening
else
error("Invalid GateState!")
end
end
function closeGate(gateModel)
local gateInfo = gateInfos[gateModel]
local state = gateInfo.State
if state == GateState.Open or state == GateState.Opening then
if state == GateState.Opening then
gateInfo.CurrentTween:Cancel()
end
gateInfo.State = GateState.Closing
local targetCFrame = gateInfo.InitialCFrame
gateInfo.CurrentTween = tweenModelCFrame(gateModel, GATE_ANIM_TWEENINFO, targetCFrame, true)
elseif state == GateState.Closed or state == GateState.Closing then
--Do nothing if already closed or closing
else
error("Invalid GateState!")
end
end
for _, tagged in ipairs(TagService:GetTagged("Gate")) do
setupGate(tagged)
end
I can’t test the code so let me know if it’s broken