美文网首页
Java Swing 打砖块游戏(2)

Java Swing 打砖块游戏(2)

作者: 天不错啊 | 来源:发表于2018-04-27 15:01 被阅读0次

    萧大佬JS游戏视频:https://www.bilibili.com/video/av12168808

    这一次代码大变样,绕的我脑子都晕了,许多地方真的是写的太垃圾。
    添加功能如下:
    1.手动关卡编辑
    2.把定时器新建了一个类
    3.新增加了砖块和砖块的HP
    4.加了双缓冲(不知道有没有用)
    5.P键暂停(挡板移动的BUG还没有搞)

    准备添加新功能:
    1.不同生命值的方块颜色不同。
    2.添加积分功能。
    3.打完所有砖块,进入下一关。
    4.可能会把draw的方块换成图片。


    可以看到方块是有生命值的,但是还有个BUG没演示。
    球会卡在挡板里,就这样了。装作什么都没发生

    项目截图如下:


    1.Ball类

    新添加了rebound反弹函数
    网上抄了一个矩形相交的代码

    public class Ball {
        /**
         * @param BALL_WIDTH 球宽度
         * @param BALL_HEIGHT 球高度
         */
        private static final int BALL_WIDTH = 25;
        private static final int BALL_HEIGHT = 25;
    
        private int x = 175;
        private int y = 200;
        private int speedX = 5;
        private int speedY = 5;
        private boolean fired = false;
    
        public void draw(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            //抗锯齿
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2.drawOval(x, y, BALL_WIDTH, BALL_HEIGHT);
        }
    
        public void fire() {
            fired = true;
        }
    
        public void move() {
            if (fired) {
                // 边界判定
                if (x <= 0 || x + BALL_WIDTH >= 400)
                    speedX *= -1;
                if (y <= 0 || y + BALL_HEIGHT >= 400)
                    speedY *= -1;
                x += speedX;
                y += speedY;
            }
        }
        public void rebound(){
            speedY *= -1;
        }
    
        public boolean collide(int x, int y, int width, int height) {
            boolean code = false;
            // 矩形相交
            if (this.x + BALL_WIDTH > x && x + width > this.x && this.y + BALL_HEIGHT > y && y + height > this.y) {
                code = true;
            }
            return code;
        }
    
    }
    

    2.Block类

    最为主要的就是存活状态和生命值

    public class Block {
        /**
         * @param BALL_WIDTH 球宽度
         * @param BALL_HEIGHT 球高度
         */
        public static final int BLOCK_WIDTH = 75;
        public static final int BLOCK_HEIGHT = 25;
    
        /**
         * @param alive 存活状态
         * @param hp 生命 默认1
         */
        private int x = 100;
        private int y = 100;
        private int hp = 2;
        private boolean alive = true;
    
        public void draw(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            g2.drawRect(x, y, BLOCK_WIDTH, BLOCK_HEIGHT);
        }
    
        public void kill() {
            if (hp > 0) {
                hp--;
                if (hp == 0)
                    alive = false;
            }
        }
    
        public int getHp() {
            return hp;
        }
    
        public void setHp(int hp) {
            this.hp = hp;
        }
    
        public int getX() {
            return x;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    
        public int getY() {
            return y;
        }
    
        public boolean getBlockAlive() {
            return alive;
        }
    }
    

    3.Paddle类

    这个挡板类好像没怎么动过。

    package com.draw;
    
    import java.awt.*;
    
    /**
     * Created by Administrator on 2018/4/25 0025.
     */
    public class Paddle {
        /**
         * @param PADDLE_WIDTH 挡板宽度
         * @param PADDLE_HEIGHT 挡板高度
         */
        public static final int PADDLE_WIDTH = 125;
        public static final int PADDLE_HEIGHT = 25;
    
        private int x = 150;
        private int y = 300;
        private int speed = 15;
    
        //绘图
        public void draw(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            g2.drawRect(x, y, PADDLE_WIDTH, PADDLE_HEIGHT);
        }
    
    
        public  void moveLeft(){
            if(x > 0)
                x -= speed;
        }
    
        public void moveRight(){
            if(x < 400-PADDLE_WIDTH)
                x += speed;
        }
    
        public int getX() {
            return x;
        }
    
        public int getY() {
            return y;
        }
    }
    
    

    4.StringUtil类
    新添加的类,用于读取levels.properties文件返回 ArrayList<int[]>类型

    public class StringUtil {
    
        public ArrayList<int[]> readToList(String key,String fileName) {
            Properties properties = new Properties();
            ArrayList<int[]> arrayList = new ArrayList<>();
            try {
                InputStream in = new BufferedInputStream(new FileInputStream(fileName));
                properties.load(in);
                String value = properties.getProperty(key);
    
                for (String s : value.split("\\|")) {
                    String[] s1 = s.split(",");
                    int[] array = new int[s1.length];
                    for (int i = 0; i < s1.length; i++) {
                        array[i] = Integer.valueOf(s1[i]);
                    }
                    arrayList.add(array);
                }
    
            } catch (IOException e) {
                e.printStackTrace();
    
            }
            return arrayList;
        }
    }
    

    5.levels.properties文件

    用于存储关卡信息。如0,0,1。s = [0,0,1].
    s[0] = X位置
    s[1] = Y位置
    s[2] = 方块生命值

    1=0,0,1
    2=0,0,1|30,30,2
    3=0,0,1|30,30,2|60,60,3
    4=0,0,1|30,30,3|60,60,3|90,90,4
    

    6.RepaintTask类

    这个类写的不好,太乱了。用于移动和碰撞的刷新。

    public class RepaintTask extends TimerTask {
        private Paddle paddle = new Paddle();
        private Ball ball = new Ball();
        private ArrayList<Block> blocks = new ArrayList<>();
        private MyComponent component = null;
        private boolean isTrue = true;
    
        public RepaintTask(Ball ball, Paddle paddle, ArrayList<Block> blocks, MyComponent component) {
            this.ball = ball;
            this.paddle = paddle;
            this.blocks = blocks;
            this.component = component;
        }
    
        @Override
        public void run() {
            if (isTrue) {
                // 重绘
                component.repaint();
                // 球移动
                ball.move();
                // 板子与球相撞
                if (ball.collide(paddle.getX(), paddle.getY(), paddle.PADDLE_WIDTH, paddle.PADDLE_HEIGHT)) {
                    ball.rebound();
                }
    
                for (Block block : blocks) {
                    //是否存活
                    if (block.getBlockAlive()) {
                        // 球与方块相撞
                        if (ball.collide(block.getX(), block.getY(), block.BLOCK_WIDTH, block.BLOCK_HEIGHT)) {
                            block.kill();
                            ball.rebound();
                        }
                    }
                    //如果全部挂掉,就开始下一关
                    //nextLevel();
                }
    
            }
        }
    
        public boolean getIsTrue() {
            return isTrue;
        }
    
        public void setTrue(boolean aTrue) {
            isTrue = aTrue;
    
        }
    
    }
    
    

    7.MyComponent类

    主要功能双缓冲和调用Draw方法的绘图。

    class MyComponent extends JComponent {
        //初始化
        private Ball ball = null;
        private Paddle paddle = null;
        private ArrayList<Block> blocks;
        private Image ImageBuffer = null;
        private Graphics GraImage = null;
    
        // 获取对象
        public MyComponent(Ball ball, Paddle paddle, ArrayList<Block> blocks) {
            this.ball = ball;
            this.paddle = paddle;
            this.blocks = blocks;
    
        }
    
        @Override
        public void update(Graphics g) {
            super.update(g);
            //创建图形缓冲区
            ImageBuffer = createImage(this.getWidth(), this.getHeight());
            //获取图形缓冲区的图形上下文
            GraImage = ImageBuffer.getGraphics();
            //用paint方法中编写的绘图过程对图形缓冲区绘图
            paint(GraImage);
            //释放图形上下文资源
            GraImage.dispose();
            g.drawImage(ImageBuffer, 0, 0, this);
        }
    
        @Override
        public void paint(Graphics g) {
            super.paint(g);
            ball.draw(g);
            paddle.draw(g);
            for (Block block : blocks) {
                if (block.getBlockAlive())
                    block.draw(g);
            }
        }
    }
    

    8.ListenerFrame类

    主要功能:调用各种方法和键盘监听,载入配置。读取关卡信息。

    class ListenerFrame extends JFrame implements KeyListener {
        /**
         * @param DEFAULT_WIDTH 组件宽
         * @param DEFAULT_HEIGHT 组件高度
         */
        private static final int DEFAULT_WIDTH = 400;
        private static final int DEFAULT_HEIGHT = 400;
    
        private Paddle paddle = new Paddle();
        private Ball ball = new Ball();
        private String level = "4";
    
        private ArrayList<Block> blocks = loadLevel(level);
        private MyComponent component = new MyComponent(ball, paddle, blocks);
        private RepaintTask task = new RepaintTask(ball, paddle, blocks, component);
    
        public ListenerFrame() {
    
            //定时器 定时重绘组件
            Timer t = new Timer();
            t.schedule(task, 0, 1000/100);
    
            //配置
            setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
            add(component);
    
        }
    
    
        public ArrayList<Block> loadLevel(String level) {
            ArrayList<Block> blocks = new ArrayList<>();
            StringUtil stringUtil = new StringUtil();
            ArrayList<int[]> arrayList = stringUtil.readToList(level, "src/com/levels.properties");
            for (int[] k : arrayList) {
                Block block = new Block();
                block.setX(k[0]);
                block.setY(k[1]);
                block.setHp(k[2]);
                blocks.add(block);
            }
    
            return blocks;
        }
    
    
        //键盘监听
        @Override
        public void keyPressed(KeyEvent e) {
            switch (e.getKeyCode()) {
                case KeyEvent.VK_LEFT:
                    paddle.moveLeft();
                    break;
                case KeyEvent.VK_RIGHT:
                    paddle.moveRight();
                    break;
    
                case KeyEvent.VK_A:
                    paddle.moveLeft();
                    break;
                case KeyEvent.VK_D:
                    paddle.moveRight();
                    break;
                case KeyEvent.VK_F:
                    ball.fire();
                    break;
                case KeyEvent.VK_P:
                    if(task.getIsTrue())
                        task.setTrue(false);
                    else
                        task.setTrue(true);
                    break;
            }
        }
    
        @Override
        public void keyReleased(KeyEvent e) {
    
        }
    
        @Override
        public void keyTyped(KeyEvent e) {
    
        }
    }
    

    9.Main

    没有动作,还是配置各类东西。

    public class Main {
        public static void main(String[] args) {
            // 事件分配线程写法来自Java Core 1(408页)
            // 没有记错的话这个是Java 8里的lambda表达式
            EventQueue.invokeLater(() -> {
                //创建对象
                ListenerFrame frame = new ListenerFrame();
                //添加关闭按钮
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                //添加Title
                frame.setTitle("打砖块");
                //添加键盘监听事件
                frame.addKeyListener(frame);
                //设置可见
                frame.setVisible(true);
            });
        }
    }
    
    ``

    相关文章

      网友评论

          本文标题:Java Swing 打砖块游戏(2)

          本文链接:https://www.haomeiwen.com/subject/qcwblftx.html