Being given a point and a miss for same tile

local function giveMiss(tile)
	Note.TextColor3 = Color3.fromRGB(255, 80, 80)
	Note.Text = 'MISS'
		
	Combo = 0
	ComboLabel.Text = ''
	
	spawn(function()
		if tile then
			tile.ImageColor3 = Color3.fromRGB(255, 80, 80)
			wait(0.25)
			tile.ImageColor3 = Color3.fromRGB(255, 255, 255)
		end
	end)
	
	if Score >= 3 then
		Score = Score - 3
	end
	
	wait(0.25)
	
	Note.Text = ''
end

-- create the tile and move it down. Destroy when at bottom
-- I try using Scrolling:FindFirstChild(Tile.Name) to check if it still exists, and for a split second it does
-- even if I have removed it already (from pressing the key)
    spawn(function()
		Tile:TweenPosition(UDim2.new(TilePosition.Position.X.Scale, 0, 1, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Linear, timer, true)
		wait(timer)
		if Scrolling:FindFirstChild(Tile.Name) then
			giveMiss()
			Tile:Destroy()
		end		
	end)

robloxapp-20191210-0939091
Can see, the second one I got Perfect and then a Miss as well. As well as the last one, I got Great but then a miss as well.

This is what checks the position when I press the keys

local function checkPosition()
	if Debounce then return end
	
	Debounce = true
	
	local BottomTile = Bottom:FindFirstChild(CurrentTile.Name)		
	if CurrentTile.Position.Y.Scale < 0.7 and CurrentTile.Position.Y.Scale > 0.3 then
		local ScorePoints = 0
		if CurrentTile.Position.Y.Scale < 0.55 and CurrentTile.Position.Y.Scale > 0.45 then
			Note.TextColor3 = Color3.fromRGB(29, 252, 255)
			Note.Text = 'PERFECT'
			
			ScorePoints = 5
			BottomTile.ImageColor3 = Color3.fromRGB(29, 252, 255)
		elseif CurrentTile.Position.Y.Scale < 0.6 and CurrentTile.Position.Y.Scale > 0.4 then
			Note.TextColor3 = Color3.fromRGB(79, 255, 114)
			Note.Text = 'GREAT'	
			
			ScorePoints = 3
			BottomTile.ImageColor3 = Color3.fromRGB(79, 255, 114)
		else
			Note.TextColor3 = Color3.fromRGB(252, 199, 255)
			Note.Text = 'OK'
			
			ScorePoints = 1
			BottomTile.ImageColor3 = Color3.fromRGB(252, 199, 255)
		end
		
		Combo = Combo + 1
		
		if Combo >= 5 then
			ComboLabel.Text = 'COMBO ' .. Combo
			
			ScorePoints = ScorePoints + Combo
		end
		
		Score = Score + ScorePoints
		
		spawn(function()
			createScoreLabel(ScorePoints, BottomTile)
		end)
		
		BottomTile:TweenSize(UDim2.new(0.25, 0, 1, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0.05, true)
		
		CurrentTile:Destroy()
	else
		giveMiss(BottomTile)
	end
	
	wait(0.05)
	
	if BottomTile then
		BottomTile:TweenSize(UDim2.new(0.2, 0, 1, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0.05, true)
	end
	
	BottomTile.ImageColor3 = Color3.fromRGB(255, 255, 255)
	
	Note.Text = ''
	
	wait(0.5)
	
	Debounce = false
end

One idea might be to create another variable and call it something like “Assigned_Text.” And when ever you assign the text of the note to one of the three (perfect, great, ok) you could set that variable to true. Then, in your else statement you could change that to something like…

elseif not Assigned_Text then
    giveMiss(BottomTile)
end

I assume something among those lines could work. Hope this helps :slight_smile:

I feel like the problem is here

spawn(function()
		Tile:TweenPosition(UDim2.new(TilePosition.Position.X.Scale, 0, 1, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Linear, timer, true)
		wait(timer)
		
		if not GameRunning then
			DanceMinigame:StopGame()
			Scrolling:ClearAllChildren()
			
			return
		end

		if Scrolling:FindFirstChild(Tile.Name) then
			giveMiss()
			Tile:Destroy()
		end		
	end)

As it’s giving the player a score, but then the wait(timer) has also gone off at the exact same time, and the tile is still there for a split second.

1 Like

wait() can sometimes be unpredictable and can vary slightly on its exact time. I suggest using the callback function TweenPosition provides to run a function upon completion of the Tween to get the most accurate time.

Or you could switch over to TweenService and use the Completed() event if that makes it easier.

You could still use wait, but maybe give it a slightly longer time then the Tween is expected to take.

Having the correct timing is crucial to a rhythm system, so I highly suggest the first two options.

Wait isn’t sometimes unpredictable. Wait will wait for n amount of seconds (or the minimum of ~1/30 if n isn’t specified) as well as until there is an open slot in the task scheduler. This is what causes the time variation. You can see the exact time wait spent yielding by printing out the first value it returns.

Isn’t is tied to frames? It does wait 1/30th of a second, but depending on when it was called there is a chance that it will be done by the next frame. In some instances it will have to wait two frames instead of one because it was called late in the frame or due to lag.

Oh ok I get what you’re saying. wait() itself is always correct but it varies due to external factors such as frames and no open task scheduler slots.

No, it is not tied to frames, it is tied to the task scheduler. Lua is single-threaded and needs to schedule tasks to be ran. When the task scheduler is occupied with running other tasks, the yielded thread cannot resume which is where the extra time on wait comes from - looking for an open slot to resume at.

Lag doesn’t necessarily have anything to do with it either, or rather not directly. In the cases where you have lag, the thread scheduler will often be hogged or occupied by a certain task so the yielding thread can’t find a good time to set in. That’s why some developers in the past have complained about wait taking significantly longer than the time value they passed to wait.