I have found a way to solve the ball-falling-into-hole simulation that I am quite happy with as it won’t let the ball sink into the solid parts of the floor and still looks convincing. As soon as the ball crosses a hole, I remember that hole and start the ball’s downward acceleration. While the ball is falling, I adjust its position towards the holes center as far as needed so it doesn’t intersect with the outline of the hole.
With the gameplay mechanics working well, I spent some more work implementing the actual logic. The gameplay controller now knows the game status and updates it accordingly when the time runs out, the ball falls into a wrong hole or into the exit hole.
Next component to implement was a simple game state management system. Originally I didn’t want to do this, but as I see it now, I would otherwise end up coding all the different states (main menu, level selector, ingame) into several big if or switch statements which would be a very awkward way to handle this.