I'm making baby steps in java programming and I just ended coding basic game: Snake. Could you share with me what is needed to improve in this code? What about OOP?

Ps. I want to create possibility to play multiplayer on two computers. Can you direct me what should i learn to do that?

**Code:**

**GameBoard.java**

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    import java.util.LinkedList;
    import java.util.concurrent.ScheduledThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    public class GameBoard extends JFrame {
        //setting board size
        public static int boardWidth = 1000;
        public static int boardHeight = 800;
    
        private JPanel scorePanel;
    
        public static void main(String[] args) {
            new GameBoard();
        }
    
        public GameBoard() {
            super("Snake Game");
            this.setSize(boardWidth, boardHeight);
            this.setResizable(false);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            addKeyListener(new KeyListener() {
                @Override
                public void keyTyped(KeyEvent e) {
    
                }
    
                @Override
                public void keyPressed(KeyEvent e) {
                    if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                        DrawingTheBoard.theSnake.changeDirection(Direction.LEFT);
                    } else if (e.getKeyCode() == KeyEvent.VK_UP) {
                        DrawingTheBoard.theSnake.changeDirection(Direction.UP);
                    } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
                        DrawingTheBoard.theSnake.changeDirection(Direction.RIGHT);
                    } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                        DrawingTheBoard.theSnake.changeDirection(Direction.DOWN);
                    }
                }
    
                @Override
                public void keyReleased(KeyEvent e) {
    
                }
            });
            DrawingTheBoard gamePanel = new DrawingTheBoard();
            this.add(gamePanel, BorderLayout.CENTER);
    
            scorePanel = new JPanel();
            scorePanel.add(gamePanel.scoreLabel, BorderLayout.CENTER);
            this.add(scorePanel, BorderLayout.PAGE_END);
    
            ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);
            executor.scheduleAtFixedRate(new RepaintTheBoard(this), 0, 1000, TimeUnit.MILLISECONDS); // updating board each 100MS
    
            this.setVisible(true);
        }
    }
    
    class RepaintTheBoard implements Runnable {
        private GameBoard theBoard;
    
        public RepaintTheBoard(GameBoard theBoard) {
            this.theBoard = theBoard;
        }
    
        public void run() {
            theBoard.repaint();
        }
    }
    
    class DrawingTheBoard extends JComponent {
        static Snake theSnake = new Snake(GameBoard.boardWidth, GameBoard.boardHeight);
        static SnakeState theState = new SnakeState();
        private LinkedList<Point> body;
        private Point apple;
    
        public JLabel scoreLabel;
        public int score = 0;
    
        public DrawingTheBoard() {
            apple = new Apple().getPointOfApple();
            scoreLabel = new JLabel("Score: " + Integer.toString(score));
            scoreLabel.setFont(new Font("Serif", Font.PLAIN, 40));
        }
    
        public void paint(Graphics g) {
            body = theSnake.getBody(); // making copy of List from Snake to draw it on screen
            Graphics2D g2D = (Graphics2D) g;
            g2D.setBackground(Color.BLACK);
            g2D.fillRect(0, 0, getWidth(), getHeight());
            g2D.setPaint(Color.WHITE);
    
            for (Point partOfBody : body) {
                g2D.fillRect(partOfBody.getX(), partOfBody.getY(), 10, 10); // painting body of rectangles 10x10
            }
    
            theSnake.update(apple);
    
            // checking if is gameOver
            if (theState.checkIfSnakeIsDead(body)) {
                theSnake.restartSnake();
                score = 0;
                setScoreLabel(score);
            }
    
            if (theSnake.hasEaten()) {
                apple = new Apple().getPointOfApple(); // if snake has eaten apple creating new one
                theSnake.setHasEatenApple(false);
                score += 10;
                setScoreLabel(score); // adding 10 to score
            }
            g2D.fillRect(apple.getX(), apple.getY(), 10, 10);
        }
    
        public void setScoreLabel(int newScore) {
            scoreLabel.setText("Score: " + Integer.toString(newScore));
        }
    }

**Apple.java**

    import java.util.Random;
    
        public class Apple {
            private int bWidth = GameBoard.boardWidth;
            private int bHeight = GameBoard.boardHeight;
            private int randomXPos;
            private int randomYPos;
            private Point pointOfApple;
        
            Random r = new Random();
            public Apple(){
                randomXPos = r.nextInt((bWidth-10)/10)*10;
                randomYPos = r.nextInt((bHeight-110)/10)*10;
                pointOfApple = new Point(randomXPos,randomYPos);
            }
            public Point getPointOfApple(){
                return pointOfApple;
            }
            public int getRandomXPos(){
                return randomXPos;
            }
            public int getRandomYPos(){
                return randomYPos;
            }
        }
      

  
**Snake.java**

    import java.awt.*;
    import java.util.LinkedList;
    
    public class Snake extends Rectangle {
        private LinkedList<Point> body; // list holding points(x,y) of snake body
        private Direction headDirection;
        private boolean hasEatenApple = false;
        private int bWidth;
        private int bHeight;
    
    
        public Snake(int bWidth, int bHeight) {
            this.bWidth = bWidth;
            this.bHeight = bHeight;
    
            body = new LinkedList<>();
            restartSnake();
    
        }
    
        public LinkedList<Point> getBody() {
            return (LinkedList<Point>) body.clone();
        }
    
        public void restartSnake() {
            body.clear();
    
            //creating 3-part starting snake
            body.addFirst(new Point(this.bWidth / 2, this.bHeight / 2));
            body.add(new Point((this.bWidth / 2) - 10, this.bHeight / 2));
            body.add(new Point((this.bWidth / 2) - 20, this.bHeight / 2));
            this.headDirection = Direction.RIGHT;
        }
    
        public void changeDirection(Direction theDirection) {
            if (theDirection != headDirection.opposite())
                this.headDirection = theDirection;
        }
    
        //updating localisation of snake
        public void update(Point applePoint) {
            if (headDirection == Direction.DOWN) {
                addPartOfBody(0, 10, applePoint);
            } else if (headDirection == Direction.UP) {
                addPartOfBody(0, -10, applePoint);
    
            } else if (headDirection == Direction.LEFT) {
                addPartOfBody(-10, 0, applePoint);
    
            } else if (headDirection == Direction.RIGHT) {
                addPartOfBody(10, 0, applePoint);
    
            }
        }
    
        public void addPartOfBody(int x, int y, Point applePoint) {
            body.addFirst(new Point(body.get(0).getX() + x, body.get(0).getY() + y));
    
            //if new point of head of snake is point of apple don't reduce last part of snake
            if (body.get(0).getX() != applePoint.getX() || body.get(0).getY() != applePoint.getY()) {
                body.removeLast();
            } else {
                hasEatenApple = true;
            }
        }
        public boolean hasEaten(){
            return hasEatenApple;
        }
        public void setHasEatenApple(boolean hasEatenApple){
            this.hasEatenApple = hasEatenApple;
        }
    
    
    }

**SnakeState.java**

    import java.util.LinkedList;
    
    public class SnakeState {
        private int bWidth = GameBoard.boardWidth;
        private int bHeight = GameBoard.boardHeight;
        private static boolean isDead = false;
    
        public boolean checkIfSnakeIsDead(LinkedList<Point> body) {
    
            //checking if head of snake is out of board
            if (body.get(0).getX() < 0 || body.get(0).getX() > bWidth-10
                    || body.get(0).getY() < 0 || body.get(0).getY() > bHeight-110) {
                return true;
            }
    
            //checking if head of the snake have collision with others parts of his body
            for (int i = 1; i < body.size(); i++) {
                if (body.get(i).getX() == body.get(0).getX() && body.get(i).getY() == body.get(0).getY())
                    return true;
            }
            return false;
        }
    
    }

**Point.java**

    public class Point {
        private int x;
        private int y;
    
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    
        public int getX() {
            return x;
        }
    
        public int getY() {
            return y;
        }
    }

**Direction.java**

    public enum Direction {
        LEFT {
            Direction opposite() {
                return RIGHT;
            }
        },
        RIGHT {
            Direction opposite() {
                return LEFT;
            }
        },
        UP {
            Direction opposite() {
                return DOWN;
            }
        },
        DOWN {
            Direction opposite() {
                return UP;
            }
        };
    
        abstract Direction opposite();
    }