Alright, so basically I have a script that draws ECG on a SurfaceGui with pixels (frames), and the thing is, the script runs very slowly, like twice or thrice slower than supposed to, like when I need script to draw a certain wave with length 80 ms, it draws it in 160 ms or more.
I figured out to use os.clock() to see what is going on, and found out that wait() and task.wait() become very inaccurate at very low wait times (e.g. 1/60 seconds).
I tried to use the same os.clock() to accurately measure time. It worked on paper fine, but on practice it made my PC lag and constantly cause Script exhausted execution time error. I was using this function:
local function AccurateWait(time)
local start = os.clock()
while os.clock() - start < time do
-- Nothing
end
end
Now I don't know what to do, here is full script, maybe it will help. I need to make script wait exactly 1 frame (at 60 FPS) or 0.017 seconds.
local leadFrame = script.Parent.blackBg.I_leadFrame
local leadFrameWidth = leadFrame.Size.X.Offset
local leadFrameUpdateTick = 1
local pixelSize = 2 -- def:
local pixels = {}
local step = 3 -- DO NOT CHANGE THIS VALUE, def: 4
local colGreen = Color3.fromRGB(25, 255, 25)
local heartBPM = 60 / 60 * 1000 -- Will need it later, for now let it remain as 60
local linePosX = 0
local linePosY = 0
local linePosY_Scale = 0.5
local lineAccuracy = 16 -- def: 16
local lineReachedFrameWidth = false
local lineLoops = true
local lineClearanceOffset = 20
local lineClearing = false
local section = 0
local sectionInMS = 0
local sectionMaxWidth = 0
local wholeBeatLength = 0
local function DrawLine()
if linePosX >= leadFrameWidth - pixelSize then
if lineLoops then
linePosX = 0
end
lineReachedFrameWidth = true
return
end
if linePosX >= leadFrameWidth - pixelSize - lineClearanceOffset or lineClearing then
lineClearing = true
pixels[1]:Destroy()
table.remove(pixels, 1)
end
if linePosY ~= linePosY then
linePosY = 0
end
local pixel = Instance.new("Frame", leadFrame)
pixel.Size = UDim2.new(0, pixelSize, 0, pixelSize)
pixel.Position = UDim2.new(0, linePosX, linePosY_Scale, linePosY)
pixel.BackgroundColor3 = colGreen
pixel.BackgroundTransparency = 0
pixel.BorderSizePixel = 0
pixel.Name = "pixel"
table.insert(pixels, pixel)
end
local function DrawP_Wave()
local durationP_Wave = 80 -- In ms, assume it is normal duration at 60 bpm
local durationPR_Segment = durationP_Wave + 40
local startTime = os.clock()
while sectionInMS < durationP_Wave do
-- At these parameters length of P wave is 90 ms
local A = 15 * step / 4 -- Scale of P wave, def: 15
local B = 2.4 -- Width of P wave, def: 2.2 (the higher - the shorter)
local C = 1.5 -- Can't describe, better not touch it, def: 1.5
local D = 0.4 -- Height of P wave, def:
local E = 1 -- Polarity of P wave, def: 1
for i = 1, lineAccuracy do
linePosY = -E * (A * D * math.sin(B * section / A))^C
DrawLine()
linePosX += step/lineAccuracy
section += step/lineAccuracy
sectionInMS = ((section/(60*step))*1000)
if sectionInMS > durationP_Wave then
break
end
end
wait(1/60)
end
print("P wave: "..((os.clock()-startTime)*1000).." ms")
while sectionInMS < durationPR_Segment do
for i = 1, lineAccuracy do
DrawLine()
linePosX += step/lineAccuracy
section += step/lineAccuracy
sectionInMS = ((section/(60*step))*1000)
if sectionInMS > durationPR_Segment then
break
end
end
wait(1/60)
wholeBeatLength += 1/60*1000
end
print("PQ segment: "..((os.clock()-startTime)*1000).." ms")
section = 0
sectionInMS = 0
end
local function DrawQRS_Complex()
local durationQRS_Complex = 90
local durationST_Segment = 100 + durationQRS_Complex
local startTime = os.clock()
while sectionInMS < durationQRS_Complex do
local A = 1.7 -- Width of QRS, def: 1.5 (the higher A - the shorter QRS)
local B = 1.7 -- Height of QRS, def: 1.7
local C = 3.6
local D = 3.5
local E = 5 -- def: 5
local F = 1.1 -- Proportions of Q to S (bigger num -> deeper peak Q), def: 1.1
local G = 15 * step / 4 -- Scale, def: 15
for i = 1, lineAccuracy do
linePosY = -G*((B*(math.sin(A/G * section))^E)^D-
(math.sin(A/G*F * section))^C)
DrawLine()
linePosX += step/lineAccuracy
section += step/lineAccuracy
sectionInMS = ((section/(60*step))*1000)
if sectionInMS > durationQRS_Complex then
break
end
end
wait(1/60)
wholeBeatLength += 1/60*1000
end
print("QRS complex: "..((os.clock()-startTime)*1000).." ms")
while sectionInMS < durationST_Segment do
for i = 1, lineAccuracy do
DrawLine()
linePosX += step/lineAccuracy
section += step/lineAccuracy
sectionInMS = ((section/(60*step))*1000)
if sectionInMS > durationST_Segment then
break
end
end
wait(1/60)
wholeBeatLength += 1/60*1000
end
print("ST segment: "..((os.clock()-startTime)*1000).." ms")
section = 0
sectionInMS = 0
end
local function DrawT_Wave()
local durationT_Wave = 160
local startTime = os.clock()
while sectionInMS < durationT_Wave do
local A = 1.1
local B = 1.6
local C = 3.6
local D = 0.9
local E = 5
local F = 1.1
local G = 15 * step / 4
local H = 2.1
for i = 1, lineAccuracy do
linePosY = -G*((B*(math.sin(A/G * section))^E)^D-
((math.sin(A/G*F * section))^H)^C)
DrawLine()
linePosX += step/lineAccuracy
section += step/lineAccuracy
sectionInMS = ((section/(60*step))*1000)
if sectionInMS > durationT_Wave then
break
end
end
wait(1/60)
wholeBeatLength += 1/60*1000
end
print("T wave: "..((os.clock()-startTime)*1000).." ms")
section = 0
sectionInMS = 0
end
local function BreakBetweenBeats()
local startTime = os.clock()
while wholeBeatLength < heartBPM do
for i = 1, lineAccuracy do
DrawLine()
linePosX += step/lineAccuracy
section += step/lineAccuracy
sectionInMS = ((section/(60*step))*1000)
end
wait(1/60)
wholeBeatLength += 1/60*1000
end
print("Pause: "..((os.clock()-startTime)*1000).." ms")
section = 0
sectionInMS = 0
wholeBeatLength = 0
end
while true do
DrawP_Wave()
DrawQRS_Complex()
DrawT_Wave()
BreakBetweenBeats()
end
print("ECG session has ended.")

just use task.wait() why do you even overthink it