Creating an undo system is relatively easy to do. One way to do this is to store multiple copies of the canvas as you draw your image (i.e, upon every mouse button click, save the current state of our image)
You can do this by using a table
local UndoFrames = {}
local MaxUndoFrames = 32
local function AddToUndoHistory()
-- Get all current pixels on the canvas
local Pixels = {}
for Y = 1, Resolution.Y do
for X = 1, Resolution.X do
table.insert(Pixels, Canvas:GetPixelXY(X, Y))
end
end
-- Avoid excessive memory consumption
if #UndoFrames >= MaxUndoFrames then
table.remove(UndoFrames, 1)
end
table.insert(UndoFrames, Pixels)
end
local function Undo()
-- Draw and remove the previous state of the canvas
local LastFrame = UndoFrames[#UndoFrames]
if LastFrame then
for X = 1, Resolution.X do
for Y = 1, Resolution.Y do
Canvas:SetPixel(X, Y, LastFrame[X + (Y - 1) * Resolution.X]) -- Formula for getting a 1D position from 2D coordinates
end
end
table.remove(UndoFrames, #UndoFrames)
end
end
In this example, I am saving to an array of a size of 32 images max every time I press the mouse button, and pressing Z to undo:
Full code
local Players = game:GetService("Players")
local LocalPlr = Players.LocalPlayer
local Gui = script.Parent
local Frame = Gui:WaitForChild("CanvasFrame")
local CanvasDraw = require(Gui:WaitForChild("CanvasDraw"))
local Mouse = LocalPlr:GetMouse()
local DrawColour = Color3.new(0, 0, 0)
local Radius = 1
-- Main
local MouseDown = false
local LastMousePoint
local Resolution = Vector2.new(158, 128)
local Canvas = CanvasDraw.new(Frame, Resolution)
local UndoFrames = {}
local MaxUndoFrames = 32
local function AddToUndoHistory()
-- Get all current pixels on the canvas
local Pixels = {}
for Y = 1, Resolution.Y do
for X = 1, Resolution.X do
table.insert(Pixels, Canvas:GetPixelXY(X, Y))
end
end
if #UndoFrames >= MaxUndoFrames then
table.remove(UndoFrames, 1)
end
table.insert(UndoFrames, Pixels)
end
local function Undo()
local LastFrame = UndoFrames[#UndoFrames]
if LastFrame then
for X = 1, Resolution.X do
for Y = 1, Resolution.Y do
Canvas:SetPixel(X, Y, LastFrame[X + (Y - 1) * Resolution.X])
end
end
table.remove(UndoFrames, #UndoFrames)
end
end
Mouse.Move:Connect(function()
local MousePoint = Canvas:GetMousePoint()
-- Check if we have a valid point on the canvas and the mouse button is being held down
if MousePoint and MouseDown then
--MousePoint += Vector2.new(25, 25)
-- Draw a line between the last mouse point and the current mouse point to avoid gaps from dragging the mouse too quickly
if LastMousePoint then
Canvas:DrawLine(LastMousePoint, MousePoint, DrawColour, Radius)
end
LastMousePoint = MousePoint
end
end)
Mouse.Button1Down:Connect(function()
MouseDown = true
AddToUndoHistory()
local MousePoint = Canvas:GetMousePoint()
-- For those who like dots
if MousePoint then
LastMousePoint = MousePoint
Canvas:DrawCircle(MousePoint, Radius, DrawColour)
end
end)
Mouse.Button2Down:Connect(function()
AddToUndoHistory()
local MousePoint = Canvas:GetMousePoint()
-- For those who like dots
if MousePoint then
Canvas:FloodFillXY(MousePoint.X, MousePoint.Y, DrawColour)
end
end)
Mouse.Button1Up:Connect(function()
LastMousePoint = nil
MouseDown = false
end)
-- Undo
game.UserInputService.InputBegan:Connect(function(Inp)
if Inp.KeyCode == Enum.KeyCode.Z then
Undo()
end
end)
AddToUndoHistory() -- Initalise