I’m trying to recreate this ability for an entirely different game concept, and I’m pretty confused on how the actions are tracked, and how the movement is executed, it looks like tweening but I’m unsure.
I’ve noticed that the Recall glove’s ability doesn’t instantly move you back to where you were, but instead moves you exactly from your previous actions, in terms of LUAU, how would someone go about making that work?
An example of what the glove does is shown in the clip below:
I don’t know for sure, but I bet there’s a table of your character’s last positions, that only keeps the last 5*60 actions (5 seconds at 60 fps)
Looking into the video a bit more, it seems that it only keeps the humanoid root part’s position, as your legs stop getting animated during that rewind.
You’d need someone smarter than me to show how to remove the first index of the position array, and then add to the table a new position lol
Also I bet there’s a cooldown to avoid going back too far in the array to where the values have been deleted.
Overall I think this is pretty simple, it should be possible for you
Edit: Here’s a creation by a discord member who I do don’t know the name of, but I’ll try to get his attention and credit himself :D
I mean, you could probably just make the glove periodically store the player’s position (and cap how many positions are stored at any given time by removing the first one) and once the ability is pressed, you can just tween the player to said positions
how it could work :
local tweenService = game:GetService("TweenService")
local glove:Tool = script.Parent -- script's parent is tool
local positions = {} -- your CFrames
local CHECK_INTERVAL = 0.5 -- how long it waits before doing a check
local MAX_POSITIONS = 10 -- how many positions can be stored at once at any given time
local PLAYER_TWEEN_DURATION = 0.25 -- how long it takes to tween the player to each position
---- GET PLAYER ----
-- EITHER: player is holding tool, so get player from character, since tool is a direct child of the character
-- OR: get player from it's backpack, since the glove will be located in player.Backpack["your glove name"]
-- OR return nil if both dont work
local player:Player = game.Players:GetPlayerFromCharacter(glove.Parent) or glove.Parent.Parent
print(player)
-- just to guarantee that the glove only runs when a player uses it
glove.Equipped:Connect(function()
if player ~= game.Players:GetPlayerFromCharacter(glove.Parent) then
player = game.Players:GetPlayerFromCharacter(glove.Parent)
end
end)
function update_positions()
local player_pos = player.Character:GetPivot()
if #positions == MAX_POSITIONS then
-- removes the first element of the table, which is the oldest
table.remove(positions, 1)
end
-- adds the position to the table
table.insert(positions, player_pos)
end
function tween_model(model:Model, goal_position:CFrame, duration:number)
-- Now, you CAN'T actually Tween a model, but there's a way around this...
-- using values such as CFrame values
local cframe_value = Instance.new("CFrameValue")
-- setting the cframe value to be the model cframe
cframe_value.Value = model:GetPivot()
local tween:Tween = tweenService:Create(cframe_value, TweenInfo(duration), {Value = goal_position})
tween:Play()
-- and checking when the value is changed
-- to update the player position
-- don't worry, lag isn't a constraint here :)
cframe_value.Changed:Connect(function(value:CFrame)
model:PivotTo(value)
end)
tween.Completed:Wait()
cframe_value:Destroy()
end
function rewind_player()
---------------------
-- here you can use a removeEvent to connect to a LocalScript
-- and do the effect that recall has that inverts the colors, since they must be applied client-side
---------------------
for i = 1, #positions do
-- tween the player for each position
tween_model(player.Character, positions[#positions - i + 1], PLAYER_TWEEN_DURATION)
end
end
---------------------
-- here you can setup a remote to a localscript that checks for player inputs
-- to activate the rewind_player() function
-- I'll let you do that yourself, but I can help if you need to.
---------------------
-- MAIN LOOP to check the positions
while task.wait(CHECK_INTERVAL) do
update_positions()
end
KEEP IN MIND I DIDNT TEST THE CODE, SO SOME THINGS COULD BE WRONG
It is actually fairly easy. You just need to store the HumanoidRootPart position in a table every 0.1 seconds, then use these stored positions to tween the character back to the position from 15 seconds ago. There is no need to use a faster loop, such as 60 times per second, since that can be performance-heavy and is unnecessary for tweening over such short distances.
If we run a loop every 0.1 seconds, we need to keep the last 150 positions in the table. Once you use the skill, you can clear the table and restart tracking.
local UserInputService = game:GetService("UserInputService")
local TweenService = game:GetService("TweenService")
local Character = script.Parent
local Root = Character:WaitForChild("HumanoidRootPart", 60)
local TweenInfos = TweenInfo.new(0.15, Enum.EasingStyle.Linear)
local LastPositions = {}
UserInputService.InputBegan:Connect(function(Input, Processed)
if not Processed and Input.KeyCode == Enum.KeyCode.E then
Root.Anchored = true
for _, NewPosition in LastPositions do
TweenService:Create(Root, TweenInfos, {CFrame = CFrame.new(NewPosition)}):Play()
task.wait(0.025)
end
Root.Anchored = false
table.clear(LastPositions)
end
end)
while task.wait(0.1) do
table.insert(LastPositions, 1, Root.Position)
if #LastPositions > 150 then
LastPositions[#LastPositions] = nil
end
end
You can also do it with CFrame in case you also want to rewind orientation.
local UserInputService = game:GetService("UserInputService")
local TweenService = game:GetService("TweenService")
local Character = script.Parent
local Root = Character:WaitForChild("HumanoidRootPart", 60)
local TweenInfos = TweenInfo.new(0.15, Enum.EasingStyle.Linear)
local LastCFrames = {}
UserInputService.InputBegan:Connect(function(Input, Processed)
if not Processed and Input.KeyCode == Enum.KeyCode.E then
Root.Anchored = true
for _, NewCFrame in LastCFrames do
TweenService:Create(Root, TweenInfos, {CFrame = NewCFrame}):Play()
task.wait(0.025)
end
Root.Anchored = false
table.clear(LastCFrames)
end
end)
while task.wait(0.1) do
table.insert(LastCFrames, 1, Root.CFrame)
if #LastCFrames > 150 then
LastCFrames[#LastCFrames] = nil
end
end
Here’s what he had to say:
“i made a tas system for roblox obbies that could be repurposed for thay
its very unoptimized though
but it has a better structure
when youre recording, you use a current frame variable
it initializes it self at 1
everytime the capture function is called
it goes on to the next frame
and the capture position gets stored in a table
this means you can overwrite frames
so you dont have to use too much memory
my explanation was awfully bad
you can edit those value individually and removing frames before or after a certain frame”
You need to adjust the length of the table depending on the loop speed and adjust the tween speed based on the distance between each position. For a 70/s loop, you need to keep about 1071 positions.
However, I do not recommend doing this at the frame rate, as it can be performance-intensive. The distance between two positions will be extremely small, making it difficult to adapt the tween smoothly. Additionally, since the frame rate is variable, it requires extra calculations to adjust the tween and the table’s maximum length in real time, which can further reduce performance.