Still Not Understanding the Whole "Fix" For Flickering Animation

I’ve now read at least 3 different tutorials on how to get rid of flickering animation, all using slightly different methods, and all making almost no sense to me. So alas, I am stuck with a broken game. So my question is, how do you guys personally get rid of flickering animation?


public class Game extends Canvas implements ActionListener, KeyListener {
	
	Level level;
	Timer timer;
	Player player;
	boolean started;
	
	public Game() {
		started = false;
		level = new Level();
		level.constructLevel();
		player = new Player(150, 425);
		addKeyListener(this);
		player.genCollisionPoints();
		timer = new Timer(50, this);
		timer.start();
	}
	
	public void paint(Graphics g) {
		g.setColor(Color.GRAY);
		g.fillRect(0, 475, 1200, 25);
		
		for(int x = 0; x < level.map.size(); x++) {
			if(level.map.get(x).x >= -100)
				level.map.get(x).drawBlock(g);	
			else 
				level.map.remove(x);	
		}
		
		if(level.map.size() == 0)
			timer.stop();
				
		player.drawPlayer(g);
		
		for(int x = 0; x < player.health; x++) {
			g.setColor(Color.RED);
			g.fillRect(x * 30 + 15, 25, 25, 50);
		}
		g.setFont(new Font("Custom", Font.BOLD, 18));
		g.setColor(Color.BLACK);
		g.drawString(Integer.toString((int)player.score), 700, 25);
	}
	
	public void actionPerformed(ActionEvent e) {
		for(int x = 0; x < level.map.size(); x++) {
			if(collision(level.map.get(x).genRect()) && level.map.get(x).isExist()) {
				player.health--;
				level.map.get(x).setExist(false);
			}
			if(player.health <= 0)
				timer.stop();
			}
		
		for(int x = 0; x < level.map.size(); x++)
			level.map.get(x).x = level.map.get(x).x - 15;
		
		if(player.isJumping  && player.y > player.maxHeight)
			player.y -= 30;
		
		if(player.isJumping && player.y <= player.maxHeight)
			player.isJumping = false;
		
		if(!player.isJumping && player.y != 425)
			player.y += 30;
		
		if(player.y > 425)
			player.y = 425;
		
		player.score += .1;
		
		repaint();
	}
	
	public boolean collision(Rectangle rec) {
		boolean collision = false;
		player.genCollisionPoints();		
		for(int x = 0; x < player.xValues.length; x++)
			for(int y = 0; y < player.yValues.length; y++) {
				collision = rec.contains(player.xValues[x], player.yValues[y]);
				if(collision)
					break;
			}
		return collision;
	}
	
	public void keyTyped(KeyEvent e) {
		char pressed = e.getKeyChar();
		player.canJump = (player.y == 425);
		if(player.canJump && pressed == ' ')
			player.isJumping = true;
	}
}

Basically, you need a back buffer on which you draw your current animation snapshot, afterwards draw the complete backbuffer on the graphics context of the component.
I never tried it, but there is a switch to enable the built in back buffering: JComponent#setDoubleBuffered()

Otherwise, just create your own buffered or volatile images to draw on.

You don’t draw directly to a Canvas. You draw on a BufferStrategy, which you get from a Canvas.