reversipanel.java

来自「开源项目openfire的完整源程序」· Java 代码 · 共 312 行

JAVA
312
字号
/**
 * $Revision$
 * $Date$
 *
 * Copyright (C) 2006 Jive Software. All rights reserved.
 * This software is the proprietary information of Jive Software. Use is subject to license terms.
 */

package org.jivesoftware.game.reversi;

import javax.swing.*;
import java.util.*;
import java.util.List;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.filter.PacketExtensionFilter;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.DefaultPacketExtension;

/**
 * The game UI, which is created after both players have accepted a new game.
 *
 * @author Bill Lynch
 */
public class ReversiPanel extends JPanel {

    private static final int BOARD_SIZE = 320;
    private static final int INFO_PANEL_HEIGHT = 50;
    private static final int BORDER_SIZE = 5;
    public static final int TOTAL_WIDTH = BOARD_SIZE + (BORDER_SIZE*2);
    public static final int TOTAL_HEIGHT = TOTAL_WIDTH + INFO_PANEL_HEIGHT; // frame width + 50 for the info panel
    private static final int NUM_BLOCKS = 8;
    private static final int BLOCK_SIZE = BOARD_SIZE/NUM_BLOCKS;

    private static final int DISC_SIZE = (int)(BLOCK_SIZE*0.8); // 80% of block size

    private XMPPConnection connection;
    private int otherPlayer;
    private int gameID;
    private String opponentJID;
    private PacketListener gameMoveListener;

    private List blocks = new ArrayList();
    // Main game object
    private ReversiModel reversi;

    // All images used by the game.
    private Image imageBackground = new ImageIcon(getClass().getResource("images/reversi-board.png")).getImage();
    private Image imageScoreWhite = new ImageIcon(getClass().getResource("images/score-button-white.png")).getImage();
    private Image imageScoreBlack = new ImageIcon(getClass().getResource("images/score-button-black.png")).getImage();
    private Image imageTurnBlack = new ImageIcon(getClass().getResource("images/turn-label-black.png")).getImage();
    private Image imageTurnWhite = new ImageIcon(getClass().getResource("images/turn-label-white.png")).getImage();
    private Image imageButtonResign = new ImageIcon(getClass().getResource("images/button-resign.png")).getImage();
    private Image imageYou = new ImageIcon(getClass().getResource("images/you.png")).getImage();
    private Image imageThem = new ImageIcon(getClass().getResource("images/them.png")).getImage();

    /**
     * Creates a new Reversi panel.
     *
     * @param connection
     * @param gameID
     * @param startingPlayer
     * @param opponentJID
     */
    public ReversiPanel(XMPPConnection connection, final int gameID, boolean startingPlayer, String opponentJID) {
        this.connection = connection;
        this.gameID = gameID;
        this.opponentJID = opponentJID;
        otherPlayer = startingPlayer? ReversiModel.WHITE : ReversiModel.BLACK;

        // Load all images.

        // Start the game
        reversi = new ReversiModel();

        if (connection != null) {
            gameMoveListener = new PacketListener() {
                public void processPacket(Packet packet) {
                    GameMove move = (GameMove)packet.getExtension(GameMove.ELEMENT_NAME, GameMove.NAMESPACE);
                    // If this is a move for the current game.
                    if (move.getGameID() == gameID) {
                        int position = move.getPosition();
                        // Make sure that the other player is allowed to make the move right now.
                        if (reversi.getCurrentPlayer() == otherPlayer && reversi.isValidMove(position)) {
                            reversi.makeMove(position);
                            // Redraw board.
                            ReversiPanel.this.repaint();
                        }
                        else {
                            // TODO: other user automatically forfeits!
                        }
                        // Execute move.
                    }
                }
            };

            connection.addPacketListener(gameMoveListener, new PacketExtensionFilter(GameMove.ELEMENT_NAME,
                    GameMove.NAMESPACE));
            // TODO: at end of game, remove listener.
        }

        setOpaque(false);

        // Use absolute layout
        setLayout(null);
        // Set its size:
        setPreferredSize(new Dimension(TOTAL_WIDTH, TOTAL_HEIGHT));

        // Make a new panel which is the game board grid:
        JPanel reversiBoard = new JPanel(new GridLayout(NUM_BLOCKS,NUM_BLOCKS,0,0));
        reversiBoard.setOpaque(false);
        for (int i=0; i<NUM_BLOCKS*NUM_BLOCKS; i++) {
            ReversiBlock block = new ReversiBlock(this, i);
            blocks.add(block);
            reversiBoard.add(block);
        }
        // Add the reversi board to the main panel:
        add(reversiBoard);
        // Position it:
        reversiBoard.setBounds(BORDER_SIZE, BORDER_SIZE, BOARD_SIZE, BOARD_SIZE);


        // TODO: listen for click on resign button!!
    }

    /**
     * Sends a forfeit message to the other player.
     */
    public void sendForfeit() {
        DefaultPacketExtension forfeit = new DefaultPacketExtension(GameForfeit.ELEMENT_NAME, GameForfeit.NAMESPACE);
        forfeit.setValue("gameID", Integer.toString(gameID));
        Message message = new Message();
        message.setTo(opponentJID);
        message.addExtension(forfeit);
        connection.sendPacket(message);
        connection.removePacketListener(gameMoveListener);
    }

    public void paintComponent(Graphics g) {
        // Turn on anti-aliasing.
        Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON
        );

        // Background
        g.drawImage(imageBackground, 0, 0, null);

        // Draw info panel components.

        // Draw the score.
        g.drawImage(imageScoreWhite, 3, BOARD_SIZE + BORDER_SIZE*2 + 7, null);
        g.drawImage(imageScoreBlack, 3, BOARD_SIZE + BORDER_SIZE*2 + 27, null);
        g.setFont(new Font("SansSerif", Font.BOLD, 12));
        String whiteScore = String.valueOf(reversi.getWhiteScore());
        String blackScore = String.valueOf(reversi.getBlackScore());
        FontMetrics fm = g.getFontMetrics();
        int width = Math.max(fm.stringWidth(whiteScore), fm.stringWidth(blackScore));
        g.drawString(whiteScore, imageScoreBlack.getWidth(null) + 7 + width - fm.stringWidth(whiteScore),
                BOARD_SIZE + BORDER_SIZE*2 + 22);
        g.drawString(blackScore, imageScoreWhite.getWidth(null) + 7 + width - fm.stringWidth(blackScore),
                BOARD_SIZE + BORDER_SIZE*2 + 42);

        // Draw who's turn it is.
        if (reversi.getCurrentPlayer() == ReversiModel.BLACK) {
            g.drawImage(imageTurnBlack, 116, BOARD_SIZE + BORDER_SIZE*2 + 11, null);
        }
        else {
            g.drawImage(imageTurnWhite, 116, BOARD_SIZE + BORDER_SIZE*2 + 11, null);
        }
        if (reversi.getCurrentPlayer() == otherPlayer) {
            g.drawImage(imageThem, 163, BOARD_SIZE + BORDER_SIZE*2 + 31, null);
        }
        else {
            g.drawImage(imageYou, 163, BOARD_SIZE + BORDER_SIZE*2 + 31, null);
        }

        // The resign button.
        g.drawImage(imageButtonResign, 281, BOARD_SIZE + BORDER_SIZE*2 + 17, null);
    }

    /**
     * A Reversi block (one of the squares of the grid).
     */
    public class ReversiBlock extends JPanel {

        private ReversiPanel ui;
        private int index;

        public ReversiBlock(ReversiPanel ui, int index) {
            super();
            this.ui = ui;
            this.index = index;
            setPreferredSize(new Dimension(BLOCK_SIZE,BLOCK_SIZE));
            addMouseListener(new ReversiBlockMouseListener(this));
            setOpaque(false);
        }

        /**
         * Returns a handle on the game UI.
         */
        public ReversiPanel getReversiUI() {
            return ui;
        }

        /**
         * This block's index (0->63).
         */
        public int getIndex() {
            return index;
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            // Turn on anti-aliasing:
            ((Graphics2D)g).setRenderingHint(
                RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON
            );

            // Draw a disc in the block if the game says we should.
            int boardValue = reversi.getBoardValue(index);
            if (boardValue == org.jivesoftware.game.reversi.ReversiModel.BLACK) {
                drawDisc(g, Color.BLACK);
            }
            else if (reversi.getBoardValue(index) == org.jivesoftware.game.reversi.ReversiModel.WHITE) {
                drawDisc(g, Color.WHITE);
            }
        }

        /**
         * Draws the disc.
         */
        private void drawDisc(Graphics g, Color color) {
            int position = BLOCK_SIZE - ((BLOCK_SIZE+DISC_SIZE)/2);
            g.setColor(color);
            g.fillOval(position, position, DISC_SIZE, DISC_SIZE);
        }
    }

    /**
     * A mouse listener for a Reversi block.
     */
    public class ReversiBlockMouseListener extends MouseAdapter {

        private ReversiBlock block;

        public ReversiBlockMouseListener(ReversiBlock block) {
            this.block = block;
        }

        /**
         * Highlight the block if this block is a valid move.
         */
        public void mouseEntered(MouseEvent e) {
            super.mouseEntered(e);
            if (reversi.getCurrentPlayer() != otherPlayer && reversi.isValidMove(block.getIndex()))
            {
                block.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                block.setBorder(BorderFactory.createLineBorder(Color.WHITE));
            }
        }

        /**
         * Set the block color back to the default.
         */
        public void mouseExited(MouseEvent e) {
            super.mouseExited(e);
            block.setCursor(Cursor.getDefaultCursor());
            block.setBorder(null);
        }

        /**
         * If the click box is a valid move, register a move in this box.
         */
        public void mouseClicked(MouseEvent e) {
            super.mouseClicked(e);
            // Make sure that it's our turn and that it's a valid move.
            if (reversi.getCurrentPlayer() != otherPlayer && reversi.isValidMove(block.getIndex()))
            {
                // Update the game model.
                reversi.makeMove(block.getIndex());

                // Send the move to the other player.
                Message message = new Message(opponentJID);
                GameMove move = new GameMove();
                move.setGameID(gameID);
                move.setPosition(block.getIndex());
                message.addExtension(move);
                connection.sendPacket(message);

                // Repaint board.
                ReversiPanel.this.repaint();

                // Repaint all blocks.
//                for (Iterator it = block.getReversiUI().getBlocks().iterator(); it.hasNext();) {
//                    ReversiBlock component = (ReversiBlock)it.next();
//                    component.repaint();
//                }

            }
        }
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?