You save the current state of the board and load back to a previous state. A new state would be saved every time a new action is done. This is easiest to implement.
Save the actions the user did, and an undo would be the inverse to those actions so you would still be saving the state of the board but only things that have changed. Still easy to implement, you would just have some inverse action that would take the new data and turn it into the old data. If you changed the color of a pixel then pressing undo would grab the top most action state, and hopefully you saved the information on what the action did, because you will then call your action but flip the parameters so that the new information becomes the old.
so you would when the player stops drawing, you put the drawed stuff in a folder,
and name it how many times the player has drawed, and store the value of the current times the player drawed, after that, when the undo button is clicked, delete the current drawed folder and -= 1 the stored value.
If the player directly draws without any extra processing first then you can just organise replicatedstorage in such a way that it acts like a cache of the last 15 or so actions depending on what you want, and just fill the cache as you go and empty the last entry, whenever you need something from in there just replace what you have in the workspace with the most recent entry in replicatedstorage and replace it with whatâs in the workspace, which allows you to kind of redo. Itâll need fleshing out to properly redo things.
I am trying this method because I like being able to bulk save easily, adding the folders is working great! But when adding a new removing the oldest not so well⌠I am trying to remove the oldest one but doesnât work (code below). I am aware the line that is âf v.Name == â1â thenâ wouldnât work
which is my issue, I am not sure how else to do it, thanks in advance.
function cacheDrawing(ui)
if totalAmountOfCache >= 20 then
local amountOver = math.abs(20 - tonumber(totalAmountOfCache))
for i, v in pairs(CacheFolder:GetChildren()) do
if v.Name == "1" then
v:Destroy()
totalAmountOfCache = totalAmountOfCache - 1
end
local newCache = Instance.new("Folder")
newCache.Name = tostring(totalAmountOfCache)
totalAmountOfCache += 1
local cache = ui:Clone()
cache.Parent = newCache
newCache.Parent = CacheFolder
end
else
local newCache = Instance.new("Folder")
newCache.Name = tostring(totalAmountOfCache)
totalAmountOfCache += 1
local cache = ui:Clone()
cache.Parent = newCache
newCache.Parent = CacheFolder
end
end
so you can set a value like â1â and then when it reached 20, remove the â1â folder and add up the value by += 1, BUT it will have too many undo histories because it will keep increasing, so also make it like +=10 instead
And you can use FindFirstChild instead of for i,v pairing to find the oldest cache.
I am not sure if there is a misunderstanding but it doesnât seem to be what I am looking for, when the user reaches the max undos âsavingâ which is 20, so they canât undo something over 20 actions back for example, when a new folder is created and it is over the max, it will remove the oldest and shift all the names down so then I only have to look for one name.
Hey, I the main thing is done, but I didnât feel like a new topic was necessary for this, I am trying to create the actual undo and redo to cycle through the cache.
I thought I could just subtract and add depending on if they undid, or redid but from the messy picture below trying to show I have an issue, which index do I save the one that was just there?
Blue line: the original frame
Red line: the frame found from the cache history replacing the original frame
The numbers: showing the indexes
Just make a table and add the frames inside the table after you could just cycle through with using the following; getframe = table[number] and when undoing just go back to that frame and delete the one that is latest one and when redoing do not delete them but just get the latest one that was undone with another table like so getundoneframe = undonetable[number]
I mean the system that @regexman told me is semi working, do you think your way will work better? I will be just getting the children of the frame for the table, with that way I can also check if there is the max cap and if so then, table.remove(table, 1) which is handy.
A system such as this in practice is not that complex. You can simply use an array and traverse the indexes based on keycodes. I would recommend using a custom enumerate system to keep track because strings generally take up more memory than numbers.
Yes there might be a max cap then you will need to remove the first one of the table and then add the new scribble/frame in using table.insert(table, item) but you can combine the two with what @samjay22 said.
Just for your own learning purposes (because everyone here seems to understand the principal of how this is accomplished with arrays), you could call it a stack. A stack is a LIFO data structure that uses push/pop (-> only the top of the stack can actually be altered at any time). You may not necessarily need all of the benefits that an actual stack structure can provide.
I was attempting to write using that method, however, lua has limitations that I am trying to bypass. I may have to write my own stack system and judging by the question OP wont understand the concepts used.
The obvious limitation as far as undo/redo is concerned is that you need to traverse the array in two directions. You could create two stacks, possibly wrote into a dictionary. Otherwise the ideal solution would be traversing a singular array where if you go too far in any one direction the final index on the opposing end gets removed.
You would know which index to get by just creating a variable and connecting it to something such as a key bind and just subtract once every time the key was pressed until the limit was hit which then you will need to wait until another item has been added or been redone. You do not need to put the frame anywhere before undoing but only until after undoing you will need to do something with that frame such as putting it into another table only for redoing and hiding that frame.