luarobloxtweenluau

Part’s position is locked after playing a Tween


I am trying to use a Tween to smoothly move a Part. My current script creates a part, then moves it to a target over the course of a second. For some reason the part's position cannot be changed via script or the move tool after being moved.

Here's my LocalScript, which binds the creation and movement of a Part to a TextButton.

local tweenService = game:GetService("TweenService")
local runService = game:GetService("RunService")
local player = game.Players.LocalPlayer

local RunServiceEvent = nil
local tweenInfo = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut)

function SpawnPart()
    local part = Instance.new("Part")
    part.Anchored = true
    part.Parent = game.Workspace.Clutter.Coins

    local startPos = Vector3.new(0, 2, 0)
    part.Position = startPos

    local TargetPosition = Vector3.new(5, 2, 0)

    local Tween = tweenService:Create(part, tweenInfo, {Position = TargetPosition})
    Tween:Play()

    local StartTime = tick()
    RunServiceEvent = runService.RenderStepped:Connect(function()
        local Time = (tick() - StartTime) / tweenInfo.Time

        if part == nil then return end

        if Time > 1 then
            part.Position = TargetPosition
            return
        end
    end)

    task.spawn(function()
        Tween.Completed:Wait()
        task.wait()
        RunServiceEvent = nil
    end)
end

player:WaitForChild("PlayerGui"):WaitForChild("ScreenGui"):WaitForChild("TextButton").Activated:Connect(SpawnPart)

To reproduce, create the following structure, then play the game and click the GUI button.

├── StarterGui
│   ├── ScreenGui
│   │   ├── TextButton
├── StarterPlayer
│   ├── StarterPlayerScripts
│   │   ├── LocalScript

After the Tween finishes, the move tool (or trying to move via script) no longer has any affect on the new part.

You can also download this .rbxl file: TestPlace


Solution

  • The problem is in the work you're doing with RunServiceEvent. It seems like you're trying to make sure the part is at its target position once the Tween is over, then deleting the RenderStepped. Unfortunately, RunServiceEvent = nil won't delete it for you - it unbinds the object from that name, but it doesn't delete the object from memory.

    This means that after one second, your script will constantly move the part to your target position, effectively locking it in place.

    The good news is, you don't need that bit at all! Your Script works fine if you just remove that bit entirely:

    local tweenService = game:GetService("TweenService")
    local runService = game:GetService("RunService")
    local player = game.Players.LocalPlayer
    
    local RunServiceEvent = nil
    local tweenInfo = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut)
    
    function SpawnPart()
        local part = Instance.new("Part")
        part.Anchored = true
        part.Parent = game.Workspace.Clutter.Coins
    
        local startPos = Vector3.new(0, 2, 0)
        part.Position = startPos
    
        local TargetPosition = Vector3.new(5, 2, 0)
    
        local Tween = tweenService:Create(part, tweenInfo, {Position = TargetPosition})
        Tween:Play()
    end
    
    player:WaitForChild("PlayerGui"):WaitForChild("ScreenGui"):WaitForChild("TextButton").Activated:Connect(SpawnPart)
    

    If you really want to ensure that the part ends up in the right place, you can also just make your script wait until the Tween is done using task.delay:

    local tweenService = game:GetService("TweenService")
    local runService = game:GetService("RunService")
    local player = game.Players.LocalPlayer
    
    local RunServiceEvent = nil
    local tweenInfo = TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut)
    
    function SpawnPart()
        local part = Instance.new("Part")
        part.Anchored = true
        part.Parent = game.Workspace.Clutter.Coins
    
        local startPos = Vector3.new(0, 2, 0)
        part.Position = startPos
    
        local TargetPosition = Vector3.new(5, 2, 0)
    
        local Tween = tweenService:Create(part, tweenInfo, {Position = TargetPosition})
        Tween:Play()
    
        task.delay(tweenInfo.Time, function()
            part.Position = TargetPosition
        end)
    end
    
    player:WaitForChild("PlayerGui"):WaitForChild("ScreenGui"):WaitForChild("TextButton").Activated:Connect(SpawnPart)