OK, this isn’t a bug per se but the inherent fact that one can move the mouse faster than the screen can update. i.e. what is happening here is that you have relatively small stimuli and a screen that I guess is updating at the typical rate of 60 Hz. So you can detect a click in a stimulus and then move the stimulus to the current mouse position. But on the next screen refresh, the new mouse position can easily have moved beyond the boundaries of the stimulus, so the .isPressedIn()
check fails. Crude solutions to (partially) address this are simply to use larger stimuli (not practical here) or to use a screen that updates faster (e.g. on a 60 Hz screen, the mouse position has 16.7 ms of motion between checks, whereas on a 144 Hz screen, just 6.9 ms, so it is less likely to move outside the bounds of the stimulus).
However, a more robust solution would be to amend your algorithm. I’d suggest doing an initial check of whether the mouse is pressed in any stimulus, and if so, flag that a drag has started. Thereafter, keep updating the selected stimulus position to match the mouse position, contingent only on the mouse button still being pressed (i.e. no longer also check if it is within a stimulus). That way, the mouse can “lead” the stimulus, not having to stay within its bounds, and the stimulus then catches up with it on every screen refresh. If you find that the mouse button is no longer pressed, then flag that the drag is no longer in operation and hence the stimulus position no longer gets actively updated.
e.g. the following code seems to work rock-solidly for me, in that the stimulus stays glued to the mouse, although the stimulus can move quite markedly between screen refreshes when the mouse is moving rapidly, so although it is keeping up with the mouse exactly, it can look like it is jumping across the screen rather than moving smoothly:
Begin routine code:
drag_in_process = False
Each frame code:
if not drag_in_process: # check if one should be
for stimulus in stimuli:
if mouse.isPressedIn(stimulus):
clicked_stimulus = stimulus
drag_in_process = True
break
if True in mouse.getPressed():
if drag_in_process:
# I guess this is also where you might put code to
# 'snap' the stimulus to the grid if required.
clicked_stimulus.pos = mouse.getPos()
else:
drag_in_process = False
This code might seem to have a strange flow, but I found that a more “elegant” logic could lead to a one-frame lag in response at times.