Java Puzzle Game Source Code

How To Create Image Puzzle Game in Java NetBeans

How To Create Image Puzzle Game in Java NetBeans


In this Java Tutorial we will see How to Create a picture puzzle game using Java Swing in Netbeans.
This java swing puzzle game is easy to use, player can upload his own images and Select the  difficulty level from multiple levels (4x4 to 8x8 grid).

The Game Features:
- Upload your own images.
Multiple difficulty levels (4x4 to 8x8 grid).
Move counter and timer.
Smooth piece-swapping animations.
- Winning detection and celebration.

How the Game Works:
When you start the game, you'll see a wimdow split into two parts:
- A sidebar with controls and game stats.
- The main puzzle grid area.

You can upload any image, and the game will automatically:
- Resize it to fit the game window.
- Split it into equal pieces based on your chosen difficulty.
- Shuffle the pieces for you to solve.

What We Are Gonna Use In This Project:

- Java Programming Language.
- NetBeans Editor.






Project Source Code:


    /**
     * Initializes the game timer that updates every second
     */
    private void initializeTimer() {
        timer = new Timer(1000, e -> {
            elapsedTime++;                    // Increment elapsed time
            int minutes = elapsedTime / 60;   // Calculate minutes
            int seconds = elapsedTime % 60;   // Calculate seconds
            timerLabel.setText(String.format("Time: %02d:%02d", minutes, seconds));  // Update timer display
        });
    }
    

    /**
     * Creates a panel to display game statistics (moves and time)
     */
    private JPanel createStatsPanel() {
        // Create panel with vertical box layout
        JPanel statsPanel = new JPanel();
        statsPanel.setLayout(new BoxLayout(statsPanel, BoxLayout.Y_AXIS));
        statsPanel.setOpaque(false);
        
        // Add semi-transparent border
        statsPanel.setBorder(BorderFactory.createCompoundBorder(
                new LineBorder(new Color(255, 255, 255, 50), 1, true), 
                new EmptyBorder(15, 15, 15, 15)));
        
        // Add statistics elements
        JLabel statsTitle = createLabel("Game Stats", 20, Font.BOLD);
        statsPanel.add(statsTitle);
        statsPanel.add(Box.createVerticalStrut(10));
        statsPanel.add(movesLabel);
        statsPanel.add(Box.createVerticalStrut(5));
        statsPanel.add(timerLabel);
        
        return statsPanel;
    }
    

    /**
     * Creates a styled label with specified text, font size, and style
     */
    private JLabel createLabel(String text, int fontSize, int fontStyle) {
        JLabel label = new JLabel(text);
        label.setFont(new Font("Arial", fontStyle, fontSize));  // Set font properties
        label.setForeground(Color.WHITE);                       // Set text color
        label.setAlignmentX(Component.CENTER_ALIGNMENT);        // Center align
        return label;
    }
    

    /**
     * Creates a styled button with specified text and background color
     */
    private JButton createButton(String text, Color color) {
        // Create button with custom painting for rounded corners
        JButton button = new JButton(text) {
            @Override
            protected void paintComponent(Graphics g) {
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setColor(getBackground());
                g2d.fill(new RoundRectangle2D.Float(0,0, getWidth(), getHeight(), 15, 15));
                g2d.dispose();
                super.paintComponent(g);
            }
        };
        
        // Style the button
        button.setAlignmentX(Component.CENTER_ALIGNMENT);
        button.setMaximumSize(new Dimension(240, 50));
        button.setFont(new Font("Arial", Font.BOLD, 16));
        button.setForeground(Color.WHITE);
        button.setBackground(color);
        button.setBorder(new EmptyBorder(10, 15, 10, 15));
        button.setFocusPainted(false);
        button.setContentAreaFilled(false);
        
        // Add hover effect
        button.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent evt) {
                button.setBackground(color.darker());    // Darken on hover
            }
            
            @Override
            public void mouseExited(MouseEvent evt) {
                button.setBackground(color);            // Restore original color
            }
        });
        
        return button;
    }
    

    /**
     * Applies custom styling to the difficulty combo box
     */
    private void styleCombobox(JComboBox<String> combobox) {
        combobox.setMaximumSize(new Dimension(240, 40));
        combobox.setFont(new Font("Arial", Font.PLAIN, 16));
        combobox.setBackground(new Color(236, 240, 241));
        combobox.setForeground(new Color(44, 62, 80));
        combobox.setBorder(BorderFactory.createCompoundBorder(
                new LineBorder(new Color(189, 195, 199), 1), 
                new EmptyBorder(5, 10, 5, 10)
        ));
        
        combobox.setAlignmentX(Component.CENTER_ALIGNMENT);
        
        // Center align items in dropdown
        combobox.setRenderer(new DefaultListCellRenderer() {
            @Override
            public Component getListCellRendererComponent(JList<?> list, Object value, 
                    int index, boolean isSelected, boolean cellHasFocus) {
                JLabel label = (JLabel)super.getListCellRendererComponent(
                        list, value, index, isSelected, cellHasFocus);
                label.setHorizontalAlignment(JLabel.CENTER);
                return label;
            }
        });
    }
    

    /**
     * Opens file chooser and loads selected image to start puzzle
     */
    private void loadAndStartPuzzle() {
        JFileChooser fileChooser = new JFileChooser();
        // Set filter to only show image files
        fileChooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter(
                "Image Files", ImageIO.getReaderFileSuffixes()));
        
        int returnValue = fileChooser.showOpenDialog(null);
        if(returnValue == JFileChooser.APPROVE_OPTION) {
            File selectedFile = fileChooser.getSelectedFile();
            
            try {
                originalImage = ImageIO.read(selectedFile);                    // Load image
                BufferedImage resizedImage = resizeImage(originalImage, IMAGE_SIZE, IMAGE_SIZE);  // Resize
                resetGame(resizedImage);                                      // Start new game
            } catch (IOException ex) {
                Logger.getLogger(Java_Puzzle_Game.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    

    /**
     * Resizes an image to specified dimensions while maintaining aspect ratio
     */
    private BufferedImage resizeImage(BufferedImage image, int targetWidth, int targetHeight) {
        // Create scaled instance of image
        Image reszedImage = image.getScaledInstance(targetWidth, targetHeight, Image.SCALE_SMOOTH);
        BufferedImage bufferedReszedImage = new BufferedImage(targetWidth, targetHeight, 
                BufferedImage.TYPE_INT_ARGB);
        
        // Draw scaled image
        Graphics2D g2d = (Graphics2D) bufferedReszedImage.createGraphics();
        g2d.drawImage(reszedImage, 0, 0, null);
        g2d.dispose();
        
        return bufferedReszedImage;
    }
    

    /**
     * Resets the game state and creates new puzzle pieces from the provided image
     */
    private void resetGame(BufferedImage image) {
        // Reset game statistics
        timer.stop();
        elapsedTime = 0;
        timerLabel.setText("Timer: 00:00");
        moves = 0;
        movesLabel.setText("Moves: 0");
        
        // Clear existing puzzle pieces
        gridPanel.removeAll();
        labelList.clear();
        correctOrder.clear();
        firstSelectedSlice = null;
        secondSelectedSlice = null;
        
        // Calculate dimensions for puzzle pieces
        int sliceWidth = image.getWidth() / GRID_SIZE;
        int sliceHeight = image.getHeight() / GRID_SIZE;
        List<ImageIcon> imageSlices = new ArrayList<>();
        
        // Create puzzle pieces
        for(int y = 0; y < GRID_SIZE; y++) {
            // Create puzzle pieces from subimages
            for(int x = 0; x < GRID_SIZE; x++) {
                // Extract piece from original image
                BufferedImage slice = image.getSubimage(
                    x * sliceWidth, 
                    y * sliceHeight, 
                    sliceWidth, 
                    sliceHeight
                );
                
                // Create icon from slice and add to lists
                ImageIcon imageIcon = new ImageIcon(
                    slice.getScaledInstance(sliceWidth, sliceHeight, Image.SCALE_SMOOTH)
                );
                imageSlices.add(imageIcon);
                correctOrder.add(imageIcon);
            }
        }
        
        // Randomly shuffle the puzzle pieces
        Collections.shuffle(imageSlices);
        
        // Create and add labels for each puzzle piece
        for(ImageIcon icon : imageSlices) {
            // Create label for puzzle piece
            JLabel sliceLabel = new JLabel(icon);
            sliceLabel.setBorder(BorderFactory.createLineBorder(new Color(189, 195, 199), 2));
            sliceLabel.setHorizontalAlignment(JLabel.CENTER);
            sliceLabel.setVerticalAlignment(JLabel.CENTER);
            
            // Add click listener to handle piece selection
            sliceLabel.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    handleSliceClick(sliceLabel);
                }
            });
            
            // Add to tracking lists and grid
            labelList.add(sliceLabel);
            gridPanel.add(sliceLabel);
        }
        
        // Refresh the display
        gridPanel.revalidate();
        gridPanel.repaint();
        
        // Start the game timer
        timer.start();
    }
    

    /**
     * Updates the grid size based on selected difficulty level
     */
    private void setGridSize(String difficulty) {
        // Set grid dimensions based on selection
        switch (difficulty) {
            case "4x4" -> GRID_SIZE = 4;
            case "5x5" -> GRID_SIZE = 5;
            case "6x6" -> GRID_SIZE = 6;
            case "7x7" -> GRID_SIZE = 7;
            case "8x8" -> GRID_SIZE = 9;
        }
        
        // Update grid layout
        gridPanel.setLayout(new GridLayout(GRID_SIZE, GRID_SIZE));
    }
    

    /**
     * Handles click events on puzzle pieces
     */
    private void handleSliceClick(JLabel clickedLabel) {
        if(firstSelectedSlice == null) {
            // First piece selection
            firstSelectedSlice = clickedLabel;
            firstSelectedSlice.setBorder(BorderFactory.createLineBorder(new Color(231,76,60), 2));
        }
        else if(secondSelectedSlice == null && clickedLabel != firstSelectedSlice) {
            // Second piece selection
            secondSelectedSlice = clickedLabel;
            secondSelectedSlice.setBorder(BorderFactory.createLineBorder(new Color(231,76,60), 2));
            
            // Start swap animation
            swapSlices();
        }
    }
    

    /**
     * Animates the swapping of two puzzle pieces
     */
    private void swapSlices() {
        Timer animationTimer = new Timer(10, null);
        final int animationDuration = 500;  // Animation duration in milliseconds
        final long startTime = System.currentTimeMillis();
        
        // Store initial positions
        Point firstLocation = firstSelectedSlice.getLocation();
        Point secondLocation = secondSelectedSlice.getLocation();
        
        // Animation update handler
        animationTimer.addActionListener((e) -> {
            // Calculate animation progress
            long elapsed = System.currentTimeMillis() - startTime;
            float progress = Math.min(1f, (float) elapsed / animationDuration);
            float easedProgress = easeInOut(progress);  // Apply easing for smooth movement
            
            // Calculate new positions
            int x1 = (int) (firstLocation.x + (secondLocation.x - firstLocation.x) * easedProgress);
            int y1 = (int) (firstLocation.y + (secondLocation.y - firstLocation.y) * easedProgress);
            int x2 = (int) (secondLocation.x + (firstLocation.x - secondLocation.x) * easedProgress);
            int y2 = (int) (secondLocation.y + (firstLocation.y - secondLocation.y) * easedProgress);
            
            // Update piece positions
            firstSelectedSlice.setLocation(x1, y1);
            secondSelectedSlice.setLocation(x2, y2);
            
            // Check if animation is complete
            if(progress >= 1f) {
                animationTimer.stop();
                finalizeSwap();
            }
        });
        
        // Start animation
        animationTimer.start();
    }
    

    /**
     * Easing function for smooth animation
     * Creates acceleration at start and deceleration at end
     */
    private float easeInOut(float t) {
        return t < 0.5f ? 2 * t * t : -1 + (4 - 2 * t) * t;
    }
    

    /**
     * Completes the swap operation after animation
     */
    private void finalizeSwap() {
        // Swap the icons between pieces
        Icon tempIcon = firstSelectedSlice.getIcon();
        firstSelectedSlice.setIcon(secondSelectedSlice.getIcon());
        secondSelectedSlice.setIcon(tempIcon);
        
        // Reset pieces to their grid positions
        firstSelectedSlice.setLocation(firstSelectedSlice.getParent().getComponent(
                labelList.indexOf(firstSelectedSlice)).getLocation()
        );
        secondSelectedSlice.setLocation(secondSelectedSlice.getParent().getComponent(
                labelList.indexOf(secondSelectedSlice)).getLocation()
        );
        
        // Reset borders to default
        firstSelectedSlice.setBorder(BorderFactory.createLineBorder(new Color(189, 195, 199), 2));
        secondSelectedSlice.setBorder(BorderFactory.createLineBorder(new Color(189, 195, 199), 2));
        
        // Clear selection
        firstSelectedSlice = null;
        secondSelectedSlice = null;
        
        // Update move counter
        moves++;
        movesLabel.setText("Moves: " + moves);
        
        // Check if puzzle is solved
        checkIfSolved();
    }
    

    /**
     * Checks if the puzzle has been solved
     */
    private void checkIfSolved() {
        // Compare current arrangement with correct order
        for(int i = 0; i < labelList.size(); i++) {
            if(labelList.get(i).getIcon() != correctOrder.get(i)) {
                return; // Puzzle not solved
            }
        }
        
        // Puzzle is solved
        timer.stop();
        showCongratulationDialog();
    }
    

    /**
     * Shows congratulation dialog when puzzle is solved
     */
    private void showCongratulationDialog() {
        // Create modal dialog
        JDialog dialog = new JDialog(this, "Congratulation!", true);
        dialog.setLayout(new BorderLayout());
        dialog.setSize(300, 200);
        dialog.setLocationRelativeTo(this);
        
        // Create panel with gradient background
        JPanel panel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                
                // Create gradient background
                int w = getWidth();
                int h = getHeight();
                Color color1 = new Color(41, 128, 185);
                Color color2 = new Color(44, 62, 80);
                GradientPaint gp = new GradientPaint(0, 0, color1, w, h, color2);
                g2d.setPaint(gp);
                g2d.fillRect(0, 0, w, h);
            }
        };
        
        // Configure panel layout
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        panel.setBorder(new EmptyBorder(20, 20, 20, 20));
        
        // Add congratulation message and stats
        JLabel congratsLabel = createLabel("Puzzle Solved!", 24, Font.BOLD);
        JLabel statsLabel = createLabel("Moves: " + moves + " | Time: " + formatTime(elapsedTime), 16, Font.PLAIN);
        
        // Add close button
        JButton closeButton = createButton("Close", new Color(231, 76, 60));
        closeButton.addActionListener((ActionEvent e) -> dialog.dispose());
        
        // Add components to panel
        panel.add(congratsLabel);
        panel.add(Box.createVerticalStrut(10));
        panel.add(statsLabel);
        panel.add(Box.createVerticalStrut(20));
        panel.add(closeButton);
        
        // Show dialog
        dialog.add(panel);
        dialog.setVisible(true);
    }
    

    /**
     * Formats time in minutes:seconds format
     */
    private String formatTime(int seconds) {
        int minutes = seconds / 60;
        int remainingSeconds = seconds % 60;
        return String.format("%02d:%02d", minutes, remainingSeconds);
    }
    

    /**
     * Shuffles the puzzle pieces on the grid
     */
    private void shuffleGrid() {
        // Reset game statistics
        timer.stop();
        elapsedTime = 0;
        timerLabel.setText("Timer: 00:00");
        moves = 0;
        movesLabel.setText("Moves: 0");
        
        // Create and shuffle new arrangement
        List<ImageIcon> shuffledIcons = new ArrayList<>(correctOrder);
        Collections.shuffle(shuffledIcons);
        
        // Apply new arrangement to grid
        for(int i = 0; i < labelList.size(); i++) {
            labelList.get(i).setIcon(shuffledIcons.get(i));
        }
        
        // Start timer if game is active
        if(originalImage != null) {
            timer.start();
        }
    }






The Final Result:

Image Puzzle Game in Java NetBeans

Puzzle Game in Java NetBeans

Java Puzzle Game

Java Puzzle Game Source Code

Java Image Puzzle Game Source Code

Java Swing Puzzle Game

Puzzle Game With Source Code In Java Netbeans







if you want the source code click on the download button below




disclaimer: you will get the source code with the database script and to make it work in your machine is your responsibility and to debug any error/exception is your responsibility this project is for the students who want to see an example and read the code not to get and run.





Share this

Related Posts

Latest
Previous
Next Post »