美文网首页
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