Hey, that's a pretty big step up from your
previous game - well done! Two-players with multiple choices of speed, or play against the computer… In particular the animation running behind the menu is nice. :)/>
The code could do with a few more "local" declarations (ideally none of your variables or functions should remain loaded in memory once the program ends, and making sure everything is "local" to your program ensures exactly that), but I suppose the best way to improve this would be to address the flickering issue.
For starters, don't load your background from disk over and over again. Load it into your "bg" variable once (at the very start of your program), then just keep accessing it from there until the program ends. Drive access is slow and this becomes very noticable when you're doing it once every frame update!
You could also help things a little by expanding your background image to cover the entire screen. This would remove all need to use "term.clear()", as redrawing the background would wipe off all previous content anyway. This would eliminate most of your flickering.
Ideally though, the program would redraw
parts of the background as it runs instead of the whole thing. You don't have to use paintutils to deal with the image - when you load it into "bg" that variable actually becomes a simple 2D table, and it's possible to pull colours directly from that table using "bg[y][x]" (where x/y are the co-ordinates in the image that you're interested in).
Let's say the ball is about to move, and so you want to redraw it. You can do something like this pseudo-code:
-- First, before the ball actually moves, get the colour of the background under it, and draw that:
term.setBackgroundColor( bg[self.ypos][self.xpos] )
term.setCursorPos(self.xpos,self.ypos)
term.write(" ")
-- Code to update the ball's position to its new location goes here.
-- Then we draw the ball at that new location:
term.setBackgroundColor(colors.white)
term.setCursorPos(self.xpos,self.ypos)
term.write(" ")
This updates the ball's position on the screen by drawing just two characters, which is dramatically faster then clearing the whole display off and drawing everything afresh. Of course, something similar can be done for the paddles - because they only move one row up/down the screen at a time, you still only need to draw two characters to update their position (redraw a bit of background at one end, then draw a bit more paddle at the other).