Heads up: This post will contain math.
So I'm trying to build an accuracy calculator for my rhythm project, but the equation to calculate the accuracy requires division by 0. In words, the equasion goes like this:
Find the average of the time between the keypress and the time they key was supposed to be pressed for every keypresses since the song began
Subtract the average by the true value
Divide that by the true value
Multiply by 100
This is all well and good, but in my case, the true value is 0, because a second difference of 0 seconds means the key was hit at the perfect time. But of course, you can't divide by 0, and doing so seems to result in math.huge
.
How would I go about resolving this?
If you need my code, here you go:
local sounds = game.SoundService local CAS = game.ContextActionService local rep = game.ReplicatedStorage local getLevel = require(rep.GetLevel) local beat = 0 local multiplier = 1000 local active = {} local secDifs = {} local testLvl = getLevel.GetLevel('TestingLevel') local selectedLvl = testLvl local beatDur = 60 / selectedLvl['BPM'] local TPU = 1 / selectedLvl['Speed'] -- Short for Time per unit local function ProcessKeyPress(color) print(color..' has been pressed!') local correctNote for i, v in ipairs(active) do if v[1] == color then correctNote = v end end if correctNote ~= nil then -- This is the part to focus on! -- This is the part to focus on! -- This is the part to focus on! print('Nice!') local secDif = math.ceil((math.abs(beat - correctNote[2]) * beatDur) * multiplier) table.insert(secDifs, secDif) local all = 0 for i, v in ipairs(secDifs) do all += v end local average = all / #secDifs local accuracy = ((average - 0) / 0) * 100 print(accuracy) rep.AddPoints:Fire(secDif) print(beat, correctNote[2], beat - correctNote[2], math.abs(beat - correctNote[2]), (math.abs(beat - correctNote[2]) * beatDur), ((math.abs(beat - correctNote[2]) * beatDur) * multiplier)) print('beat: '..tostring(beat), 'correctNote[2]: '..tostring(correctNote[2]), 'secDif before math.ceil: '..tostring((math.abs(beat - correctNote[2]) * beatDur) * multiplier), 'secDif: ', tostring(secDif)) else print('Miss!') end local closest = workspace.Notes:GetChildren()[1] if closest ~= nil then for i, v in ipairs(workspace.Notes:GetChildren()) do if math.floor(math.abs(v.Position.X)) < math.floor(closest.Position.X) and v.Name == color then --closest.Color = Color3.new(1, 0, 0) closest = v end end if math.ceil(math.abs(closest.Position.X) - workspace.Strumline[color].Position.X) <= 3 then coroutine.resume(coroutine.create(function() closest.Color = Color3.new(1, 1, 0) --wait(0.3) closest:Destroy() end)) end end end rep.TempStart.Event:Wait() print('eyey') local keybinds = { Red = nil, Blue = nil, Green = nil, White = nil } for i, keybind in ipairs(rep.Keybinds:GetChildren()) do for i, enum in ipairs(Enum.KeyCode:GetEnumItems()) do if string.sub(tostring(enum), 14, string.len(tostring(enum))) == keybind.Value then keybinds[keybind.Name] = enum end end end selectedLvl['Song']:Play() CAS:BindAction('Press red', function(nagareteku, instate, toki, no, naka, de, demo) if instate ~= Enum.UserInputState.Begin then return end ProcessKeyPress('Red') end, false, keybinds['Red']) CAS:BindAction('Press blue', function(nagareteku, instate, toki, no, naka, de, demo) if instate ~= Enum.UserInputState.Begin then return end ProcessKeyPress('Blue') end, false, keybinds['Blue']) CAS:BindAction('Press Green', function(nagareteku, instate, toki, no, naka, de, demo) if instate ~= Enum.UserInputState.Begin then return end ProcessKeyPress('Green') end, false, keybinds['Green']) CAS:BindAction('Press white', function(nagareteku, instate, toki, no, naka, de, demo) if instate ~= Enum.UserInputState.Begin then return end ProcessKeyPress('White') end, false, keybinds['White']) local stTick = tick() local permT = tick() game:GetService('RunService').Heartbeat:Connect(function() beat += math.floor(((tick() - stTick) / beatDur) * 1000) / 1000 -- Reduce time to 3 decimals stTick = tick() end) for i, v in ipairs(selectedLvl['Chart']) do local activateKeyPress = coroutine.create(function() print(v[1]..' wait duration: '..tostring((v[2] * beatDur) - TPU * 3), 'unactivate wait duration: '..tostring(((v[2] * beatDur) - TPU * 3) + (TPU * 6))) wait((v[2] * beatDur) - TPU * 3) table.insert(active, v) print(v[1]..' active') wait(TPU * 6) print(v[1]..' not active') for I, V in ipairs(active) do if v == V then rep.AddPoints:Fire(-25) table.remove(active, I) end end end) local createKeys = coroutine.create(function() wait((v[2] * beatDur) - (TPU * 20)) local keyClone = workspace.Strumline[v[1]]:Clone() keyClone.Parent = workspace.Notes keyClone.Transparency = 0 print(workspace.Strumline[v[1]]) keyClone.Position = workspace.Strumline[v[1]].Position - Vector3.new(20, 0, 0) local tween = game.TweenService:Create(keyClone, TweenInfo.new( TPU * 40, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut ), {Position = workspace.Strumline[v[1]].Position + Vector3.new(20, 0, 0)}) tween:Play() end) coroutine.resume(activateKeyPress) coroutine.resume(createKeys) end
If you need the module script code and the bindable event code, here you also go:
local levels = { TestingLevel = { Song = game.SoundService.Tem, Speed = 32, -- 32 units per second, or 32u/s BPM = 120, Chart = { -- Every table in the Chart represents a note. Properties: string button, num beat, num beatToReleaseAt {'Red', 10}, {'Green', 11}, {'Blue', 12}, {'White', 13}, {'Blue', 14}, {'Green', 15}, {'Red', 16, 21}, {'Green', 17}, {'Blue', 18}, {'White', 19}, {'Blue', 20}, {'Green', 21}, {'Red', 22, 27}, {'Green', 24}, {'Blue', 25}, {'White', 26}, {'Blue', 27}, {'Green', 28}, {'Red', 29, 34}, {'Green', 30}, {'Blue', 31}, {'White', 32}, {'Blue', 33}, {'Green', 34}, {'Red', 35, 45} } } } local module = {} module.GetLevel = function(name) return levels[name] end return module
e
local rep = game.ReplicatedStorage local frame = script.Parent local points = 0 rep.AddPoints.Event:Connect(function(pointsToAdd) points += pointsToAdd frame.Score.Text = 'Points: '..tostring(points) print(points) end) rep.ChangeAccuracy.Event:Connect(function(accuracy) -- Currently unused frame.Accuracy = tostring(accuracy)..'%' end) rep.TempStart.Event:Connect(function() script.Parent.Visible = true end)
Anything is appreciated!