开心消消乐

消消乐游戏需求

  1. 所参与的角色:熊、鸟、狐狸、青蛙
  2. 功能:
    1. 由系统随机长成元素并显示在窗口中(8行6列),保证不能有可消元素
    2. 选中两个元素,若相邻则交换,而后判断:
      1. 若不可消(不连3),则换回去
      2. 若可消(连3及以上),则:
        1. 爆破后删除元素
        2. 重新生成新的元素,若还是可消则重复2.2步骤,直到没有可消元素为止

游戏展示

初始界面

在这里插入图片描述

爆炸展示

在这里插入图片描述

代码实现

熊类

public class Bear extends Element{


    public Bear(int x, int y) {
        super(x, y);
    }

    @Override
    public ImageIcon getImage() {
        return Images.bear;
    }
}

鸟类

public class Bird extends Element{
    public Bird(int x, int y) {
        super(x, y);
    }

    @Override
    public ImageIcon getImage() {
        return Images.bird;
    }
}

狐狸类

public class Fox extends Element {
    public Fox(int x, int y) {
        super(x, y);
    }

    @Override
    public ImageIcon getImage() {
        return Images.fox;
    }
}

青蛙类

public class Frog extends Element {
    public Frog(int x, int y) {
        super(x, y);
    }

    @Override
    public ImageIcon getImage() {
        return  Images.frog;
    }
}

元素类

public abstract class Element {
    private int x, y;   //x, y 坐标
    private boolean selected; //是否选中
    private boolean eliminated; //是否可消除
    private int eliminatedIndex; //爆炸动画图片起始下标

    public Element(int x, int y) {
        this.x = x;
        this.y = y;
        this.selected = false;
        this.eliminated = false;
        this.eliminatedIndex = 0;
    }

    /**
     * 获取图片
     *
     * @return
     */
    public abstract ImageIcon getImage();


    public void paintElement(Graphics g) {
        if (isSelected()) {
            g.setColor(Color.GREEN);
            g.fillRect(x, y, World.ELEMENT_SIZE, World.ELEMENT_SIZE);
            this.getImage().paintIcon(null, g, this.x, this.y);

        } else if (isEliminated()) {
            //若没到最后一张爆炸图
            if (eliminatedIndex < Images.bombs.length) {
                Images.bombs[eliminatedIndex++].paintIcon(null, g, x, y);
            }

        } else {
            this.getImage().paintIcon(null, g, this.x, this.y);
        }
    }


    /**
     * 是否选中
     *
     * @return
     */
    boolean isSelected() {
        return selected;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
    }

    /**
     * 是否消除
     *
     * @return
     */
    boolean isEliminated() {
        return eliminated;
    }

    public void setEliminated(boolean eliminated) {
        this.eliminated = eliminated;
    }


    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }
}

图片类

public class Images {

    public static ImageIcon background; //背景图
    public static ImageIcon bird;
    public static ImageIcon bear;
    public static ImageIcon fox;
    public static ImageIcon frog;
    public static ImageIcon[] bombs;

    static {
        background = new ImageIcon("HappyEliminate/src/com/liner/img/background.png");
        bird = new ImageIcon("HappyEliminate/src/com/liner/img/bird.png");
        bear = new ImageIcon("HappyEliminate/src/com/liner/img/bear.png");
        fox = new ImageIcon("HappyEliminate/src/com/liner/img/fox.png");
        frog = new ImageIcon("HappyEliminate/src/com/liner/img/frog.png");
        bombs = new ImageIcon[4];
        for (int i = 0; i < bombs.length; i++) {
            bombs[i] = new ImageIcon("HappyEliminate/src/com/liner/img/bom" + (i + 1) + ".png");
        }
    }

    public static void main(String[] args) {
        System.out.println(background.getImageLoadStatus());    //返回8表示成功
        System.out.println(bird.getImageLoadStatus());    //返回8表示成功
        System.out.println(frog.getImageLoadStatus());    //返回8表示成功
        System.out.println(fox.getImageLoadStatus());    //返回8表示成功
        System.out.println(bear.getImageLoadStatus());    //返回8表示成功
        for (int i = 0; i < bombs.length ; i++) {
            System.out.println(bombs[i].getImageLoadStatus());
        }

    }
}

游戏窗口

public class World extends JPanel {
    public static final int WIDTH = 429;    //窗口的宽
    public static final int HEIGHT = 570;   //窗口的高
    public static final int ROWS = 8;   //8行
    public static final int COLS = 6;   //6列
    public static final int ELEMENT_SIZE = 60;   //元素大小
    public static final int OFFSET = 30;   //偏移量(第一个元素距离窗口左、上边的距离)

    private Element[][] elements = new Element[ROWS][COLS]; //元素数组 8行6列
    private boolean canInteractive = true;  //可交互状态(默认可交互)
    private int selectedNumber = 0; //已经选中的元素个数
    private int firstRow = 0; //第一个选中的元素的ROW
    private int firstCol = 0; //第一个选中的元素的COL
    private int secondRow = 0; //第二个选中的元素的ROW
    private int secondCol = 0; //第二个选中的元素的COL


    public static void main(String[] args) {
        JFrame jFrame = new JFrame();
        World world = new World();
        world.setFocusable(true);
        jFrame.add(world);
        jFrame.setTitle("开心消消乐");
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.setSize(WIDTH, HEIGHT + 17);
        jFrame.setVisible(true);


        world.start();

    }


    /**
     * 程序启动
     */
    private void start() {
        //游戏启动填充所有元素
        fillAllElement();

        //鼠标监听
        MouseAdapter mouseAdapter = new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                //重写鼠标点击事件
                if (!canInteractive) {   //不可交互时,不响应鼠标事件
                    return;
                }
                canInteractive = false; //只要选中元素,就先将状态修改为不可交互
                int row = (e.getY() - OFFSET) / ELEMENT_SIZE;   //获取选中元素的ROW
                int col = (e.getX() - OFFSET) / ELEMENT_SIZE;   //获取选中元素的COL

                selectedNumber++;   //选中的元素增1
                if (selectedNumber == 1) {
                    //第一次选中
                    firstRow = row;
                    firstCol = col;
                    elements[firstRow][firstCol].setSelected(true); //设置选中状态

                    canInteractive = true;  //可交互
                } else if (selectedNumber == 2) {
                    //第二次选中
                    secondRow = row;
                    secondCol = col;
                    elements[secondRow][secondCol].setSelected(true); //设置选中状态
                    //判断两次选中是否相邻
                    if (isAdjacent()) {
                        //若相邻则  移动、交换、消除
                        new Thread(() -> {
                            elements[firstRow][firstCol].setSelected(false); //取消选中状态
                            elements[secondRow][secondCol].setSelected(false); //取消选中状态
                            //移动、交换、消除
                            moveElement();      //移动两个元素
                            exchangeElement();  //交换两个元素
                            if (eliminateElement()) { //若有可消元素,并消除
                                //下落元素
                                do {
                                    dropElement();
                                    try {
                                        Thread.sleep(10);
                                    } catch (InterruptedException ex) {
                                        ex.printStackTrace();
                                    }
                                }while (eliminateElement());    //持续扫描

                            } else {
                                //交换回去
                                moveElement();      //移动两个元素
                                exchangeElement();  //交换两个元素
                            }

                            canInteractive = true;  //可交互


                        }).start();

                    } else {
                        elements[firstRow][firstCol].setSelected(false); //取消选中状态
                        elements[secondRow][secondCol].setSelected(false); //取消选中状态
                        canInteractive = true;//可交互

                    }

                    canInteractive = true;//在某种条件下可交互
                    selectedNumber = 0; //选中个数归零
                }

                repaint();  //重画

            }
        };

        this.addMouseListener(mouseAdapter);    //添加鼠标监听器

    }


    /**
     * 下落元素
     */
    private void dropElement() {
        for (int row = ROWS - 1; row >= 0; row--) {
            //只要有null 元素就将它上面的元素落下
            while (true) {
                int[] nullCols = {};    //当前行为null的列号

                for (int col = COLS - 1; col >= 0; col--) {
                    Element element = elements[row][col];
                    if (element == null) {
                        nullCols = Arrays.copyOf(nullCols, nullCols.length + 1);
                        nullCols[nullCols.length - 1] = col;
                    }
                }

                //查找null 列
                if (nullCols.length > 0) {
                    //移动下落元素
                    for (int count = 0; count < 15; count++) {
                        // 向下落一下
                        for (int i = 0; i < nullCols.length; i++) {
                            int nullCol = nullCols[i];
                            for (int dr = row - 1; dr >= 0; dr--) {
                                Element element = elements[dr][nullCol];
                                if (element != null) {
                                    element.setY(element.getY() + 4);
                                }
                            }
                        }


                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        repaint();
                    }

                    //真正让数组上面的元素向下移动
                    for (int i = 0; i < nullCols.length; i++) {
                        int nullCol = nullCols[i];
                        for (int nr = row; nr > 0; nr--) {
                            elements[nr][nullCol] = elements[nr - 1][nullCol];
                        }
                        //生成新元素
                        elements[0][nullCol] = createElement(0,nullCol);
                    }

                } else {
                    break;
                }
            }
        }

    }

    /**
     * 扫描并删除元素
     */
    private boolean eliminateElement() {
        boolean haveEliminated = false;

        for (int row = ROWS - 1; row >= 0; row--) {
            for (int col = COLS - 1; col >= 0; col--) {
                Element element = elements[row][col];
                if (element == null) {   //若元素为null 则跳过
                    continue;
                }

                //查找一行内当前元素前面的连续个数, 查找一列内当前元素前面的连续个数
                int colRepeat = 0; //行不变,列相邻,与当前元素相邻的行元素连续重复个数
                for (int pc = col - 1; pc >= 0; pc--) {
                    if (elements[row][pc] == null) {
                        //若当前元素为null 则break 直接退出
                        break;
                    }
                    //若遍历元素与当前元素类型相同,重复个数增1,否则 break
                    if (elements[row][pc].getClass() == element.getClass()) {
                        colRepeat++;
                    } else {
                        break;  //只要右一个不同,后续不需比较
                    }

                }
                int rowRepeat = 0; //列不变,行相邻,与当前元素相邻的列元素连续重复个数
                for (int pr = row - 1; pr >= 0; pr--) {
                    if (elements[pr][col] == null) {
                        //若当前元素为null 则break 直接退出
                        break;
                    }
                    //若遍历元素与当前元素类型相同,重复个数增1,否则 break
                    if (elements[pr][col].getClass() == element.getClass()) {
                        rowRepeat++;
                    } else {
                        break;  //只要右一个不同,后续不需比较
                    }

                }

                //将可消除元素设计为可消除状态
                if (colRepeat >= 2) {
                    //行不变,列相邻
                    elements[row][col].setEliminated(true); //设置当前元素可消除
                    for (int i = 1; i <= colRepeat; i++) {
                        //遍历连续个数次
                        elements[row][col - i].setEliminated(true);   //行不变,列前元素设置为可消
                    }

                }

                if (rowRepeat >= 2) {
                    //列不变,行相邻
                    elements[row][col].setEliminated(true); //设置当前元素可消除
                    for (int i = 1; i <= rowRepeat; i++) {
                        //遍历连续个数次
                        elements[row - i][col].setEliminated(true);   //列不变,行前元素设置为可消
                    }
                }

                //将可消除状态元素绘制成爆炸动画
                if (colRepeat >= 2 || rowRepeat >= 2) {
                    for (int i = 0; i < Images.bombs.length; i++) {
                        repaint();
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }


                //将可消除状态元素设置为null 等待其他元素下落
                if (colRepeat >= 2) {
                    elements[row][col] = null; //设置当前元素null
                    for (int i = 1; i <= colRepeat; i++) {
                        //遍历连续个数次
                        elements[row][col - i] = null;   //行不变,列前元素设置为null
                    }
                    haveEliminated = true;  //有可消元素被消除
                }

                if (rowRepeat >= 2) {
                    elements[row][col] = null; //设置当前元素null
                    for (int i = 1; i <= rowRepeat; i++) {
                        //遍历连续个数次
                        elements[row - i][col] = null;   //列不变,行前元素设置为null
                    }
                    haveEliminated = true;  //有可消元素被消除
                }

            }
        }


        return haveEliminated;


    }

    /**
     * 交换两个元素
     */
    private void exchangeElement() {
        Element element1 = elements[firstRow][firstCol];
        Element element2 = elements[secondRow][secondCol];
        elements[firstRow][firstCol] = element2;
        elements[secondRow][secondCol] = element1;


    }

    /**
     * 移动两个元素
     */
    private void moveElement() {
        if (firstRow == secondRow) {
            //若行号相同,表示左右移动
            int firstX = OFFSET + firstCol * ELEMENT_SIZE;
            int secondX = OFFSET + secondCol * ELEMENT_SIZE;
            int step = firstX < secondX ? 4 : -4;  //设置步长
            for (int i = 0; i < 15; i++) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                firstX += step;
                secondX -= step;
                //修改元素坐标
                elements[firstRow][firstCol].setX(firstX);
                elements[secondRow][secondCol].setX(secondX);

                repaint();
            }

        }
        if (firstCol == secondCol) {
            //若列号相同,表示上下移动
            int firstY = OFFSET + firstRow * ELEMENT_SIZE;
            int secondY = OFFSET + secondRow * ELEMENT_SIZE;
            int step = firstY < secondY ? 4 : -4;  //设置步长
            for (int i = 0; i < 15; i++) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                firstY += step;
                secondY -= step;
                //修改元素坐标
                elements[firstRow][firstCol].setY(firstY);
                elements[secondRow][secondCol].setY(secondY);

                repaint();
            }
        }
    }

    public static final int ELEMENT_TYPE_BEAR = 0;  //熊
    public static final int ELEMENT_TYPE_BIRD = 1;  //鸟
    public static final int ELEMENT_TYPE_FOX = 2;  //狐狸
    public static final int ELEMENT_TYPE_FROG = 3;  //青蛙

    public static final int ELIMINATE_NONE = 0; //元素不可消
    public static final int ELIMINATE_ROW = 1; //元素行可消
    public static final int ELIMINATE_COL = 2; //元素列可消

    /**
     * 检测元素是否可消
     */
    public int canEliminate(int row, int col) {
        Element element = elements[row][col];   //获取当前元素
        //判断纵向
        if (row >= 2) {
            Element element1 = elements[row - 1][col];  //获取当前元素上面第1个元素
            Element element2 = elements[row - 2][col];  //获取当前元素上面第2个元素
            if (element1 != null && element2 != null && element != null) {
                //若元素都不为null
                if (element.getClass().equals(element1.getClass()) && element.getClass().equals(element2.getClass())) {
                    return ELIMINATE_COL; //表示列可消除
                }
            }
        }

        //判断横向
        if (col >= 2) {
            Element element1 = elements[row][col - 1];  //获取当前元素前面第1个元素
            Element element2 = elements[row][col - 2];  //获取当前元素前面第2个元素
            if (element1 != null && element2 != null && element != null) {
                //若元素都不为null
                if (element.getClass().equals(element1.getClass()) && element.getClass().equals(element2.getClass())) {
                    return ELIMINATE_ROW; //表示行可消除
                }
            }
        }

        return ELIMINATE_NONE;  //表示不能消除
    }

    /**
     * 判断两元素是否能交换
     */
    public boolean isAdjacent() {
        //若行相邻且列相等  或 列相邻且行相等
        if ((Math.abs(firstRow - secondRow) == 1 && firstCol == secondCol) || (Math.abs(firstCol - secondCol) == 1 && firstRow == secondRow)) {
            return true;    //相邻
        } else {
            return false;    //不相邻
        }
    }


    /**
     * 返回元素
     */
    public Element createElement(int row, int col) {
        int x = OFFSET + col * ELEMENT_SIZE;    //列col的值控制x坐标
        int y = OFFSET + row * ELEMENT_SIZE;    //行row的值控制y坐标
        Random random = new Random();
        int type = random.nextInt(4);
        switch (type) {
            case ELEMENT_TYPE_BEAR:
                return new Bear(x, y);
            case ELEMENT_TYPE_BIRD:
                return new Bird(x, y);
            case ELEMENT_TYPE_FOX:
                return new Fox(x, y);
            default:
                return new Frog(x, y);
        }

    }

    /**
     * 填充所有元素
     */
    public void fillAllElement() {
        for (int row = 0; row < ROWS; row++) {
            for (int col = 0; col < COLS; col++) {
                //判断行消列消
                do {
                    Element element = createElement(row, col);
                    elements[row][col] = element;   //将元素填充到 elements数组中
                } while (canEliminate(row, col) != ELIMINATE_NONE);  //若可消则重新生成元素

            }
        }

    }


    @Override
    public void paint(Graphics g) {
        Images.background.paintIcon(null, g, 0, 0);
        for (int row = 0; row < ROWS; row++) {
            for (int col = 0; col < COLS; col++) {
                Element element = elements[row][col];
                if (element != null) {
                    element.paintElement(g);
                }

            }
        }
    }
}
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐