从0制作一个多线程游戏实录

本文记录了使用IntelliJ IDEA制作一款多线程游戏的过程,目前实现了飞机的键盘控制、子弹发射、背景移动和敌机自动落下。接下来将实现宝箱随机生成、碰撞检测及强化效果等功能,并分享代码更新和解决问题的思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目前学习的示例代码是做一个飞机大战。参照其实现方法希望可以实现一个泡泡龙的游戏。

当前进度实现了

1.飞机的键盘监听(即用键盘控制我放飞机的移动)

2.子弹的自动发射

3.背景移动

4.定时器线程生成敌方飞机,自动落下)

待实现功能:

1.随机生成宝箱对子弹进行强化

2.子弹和飞机的碰撞,

3.我机和奖励宝箱的碰撞

4.子弹对象会因为宝箱产生攻击力和载入图片效果的变化

5.给定我方飞机,地方飞机的生命值

会在这里持续更新代码和遇到的问题,以及如何解决的思路。

当前实现效果图

 代码如下

/**
 * 飞机类,用于发射子弹的小球

 */
public class Aircraft extends MoveBall {
    //游戏界面的大小

    //初始化飞机的位置
    public Aircraft(){
        setX(370);
        setY(700);
        setSize(60);
    }

}

/**
 * 子弹类
 */
public class Bullet extends MoveBall {
    //重载构造方法
    public Bullet(int x,int y){
        setX(x - 13);
        setY(y);
        setSize(25);
        setVy(-5);
    }
    //子弹的碰撞效果

}
//敌机类
public class Enemy extends MoveBall {
    public Enemy(int x,int y){
        setX(x - 13);
        setY(y);

        setVy(5);
    }
}
import javax.swing.*;
import java.awt.*;

/**
界面

 本次板本希望解决如下问题
 1、闪烁问题
 1)问题原因
 当我们利用普通画笔的时候是实时进行画图,
 当我们利用一个画笔同时在画飞机子弹类和背景类的时候,
 就会出现延迟,即当我在用画笔画背景的时候,
 此时没有画笔在画飞机,这个时候飞机就会消失,
 因为时间间隔很短,所以也就是所谓的闪屏,会出现图片的闪动。
 2)问题解决
 而利用缓存画笔则巧妙的解决了这个问题,
 这个相当于一次性让画笔画完一整张图,
 然后再一次性呈现出来,这样就解决了闪屏。
 2.碰撞问题
 */
public class GameBallUI {
    public void showGameBall(){
        JFrame jf = new JFrame();
        jf.setTitle("飞机大战v2.0");
        jf.setSize(800, 800);
        jf.setLocationRelativeTo(null);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //不能直接调用jf.setBackground()因为JFrame中用许多面板,这样才有效
        jf.getContentPane().setBackground(Color.white);
        jf.setLayout(new FlowLayout());
//        JButton add = new JButton("add");
//        jf.add(add);
//        JButton start = new JButton("start");
//        jf.add(start);

        jf.setVisible(true);

        //给窗体添加键盘监听器方法
        GameListener gl = new GameListener(jf);
        jf.addKeyListener(gl);//给窗体添加键盘监听器方法

        jf.requestFocus();//让窗体获取焦点,没有焦点java无法获取键盘

    }

    public static void main(String[] args) {
        new GameBallUI().showGameBall();
    }
}


import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;

/**
监听器
 */
public class GameListener implements KeyListener {
//    private JFrame jf;
    private Aircraft aircraft;//利用键盘控制小球对象,该类为飞机类
    private Graphics g;
//    private Ball ball;//发射器
    public List<MoveBall> moveBallList = new ArrayList<>();//保存到列表中
    public List<Enemy> enemyList = new ArrayList<>();//保存到列表中
    private GameThread gmThread;//子弹
    public JFrame jf;

    public GameListener(JFrame jf) {
        this.jf=jf;
        g = jf.getGraphics();
    }


    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        // 获取当前的按键
        int key = e.getKeyCode();
        //System.out.println("按下 : " + key);
        switch (key) {
            case KeyEvent.VK_W:
//                ball.setVy(-5);
                aircraft.setVy(-5);
                break;
            case KeyEvent.VK_A:
//                ball.setVx(-5);
                aircraft.setVx(-5);
                break;
            case KeyEvent.VK_S:
//                ball.setVy(5);
                aircraft.setVy(5);
                break;
            case KeyEvent.VK_D:
//                ball.setVx(5);
                aircraft.setVx(5);
                break;

            // 发射子弹的按键
            case KeyEvent.VK_J:
                //启动游戏,创建子弹对象
//                MoveBall ba = new MoveBall(g,ball.getX()+10,ball.getY());
                Bullet bullet = new Bullet(aircraft.getX(), aircraft.getY());
                //保存到moveBallList
                moveBallList.add(bullet);

//                //启动线程画子弹
                if(gmThread == null){
//                    gmThread = new GameThread(ba);
//                    new Thread(gmThread).start();
                }
                break;
            case KeyEvent.VK_SPACE:
                System.out.println("启动游戏");
                //绘制游戏动画的线程
                if(gmThread == null){
                    //启动游戏,创建小球对象
                    aircraft = new Aircraft();
                    //启动线程
                    gmThread = new GameThread(moveBallList,g,aircraft,enemyList,jf);
                    new Thread(gmThread).start();
                    //启动定时任务线程
                    TimeThread time = new TimeThread(aircraft,moveBallList,enemyList);
                    new Thread(time).start();
                }

                break;

        }

    }

    @Override
    public void keyReleased(KeyEvent e) {
        //要将WASD四个键全部置为0,这样方向键不会斜着走
        int key = e.getKeyCode();
        switch (key) {
            case KeyEvent.VK_W:
                aircraft.setVy(0);
                break;
            case KeyEvent.VK_A:
                aircraft.setVx(0);
                break;
            case KeyEvent.VK_S:
                aircraft.setVy(0);
                break;
            case KeyEvent.VK_D:
                aircraft.setVx(0);
                break;
        }
    }
}


import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.List;

/*
游戏线程类
 */

public class GameThread implements Runnable{
    public List<MoveBall> moveBallList; // 子弹对象的list
    public List<Enemy> enemyList;
    public Graphics g;
    private Aircraft aircraft;//键盘控制的对象
    private ImageIcon bgimage;//背景图片
    private ImageIcon apimage;//飞机图片
    private ImageIcon blimage;//子弹图片
    private ImageIcon enimage;//敌机图片
    public int imageX,imageY;//背景图的起始点坐标(图片左上角的位置坐标)
//    private MoveBall ba; //子弹对象
    public JFrame jf;
   // public BufferedImage bf;

    //初始化属性
    public GameThread(List<MoveBall> moveBallList, Graphics g, Aircraft aircraft, List<Enemy>enemyList,JFrame jf) {
        this.moveBallList = moveBallList;
        this.g = g;
        this.aircraft = aircraft;
        this.enemyList=enemyList;
        this.jf=jf;
    }

    //重写run方法
    @Override
    public void run() {
        //初始化背景图片
        bgimage = new ImageIcon("C:\\Users\\Sky\\IdeaProjects\\new pr\\imgs\\背景.png");
        apimage = new ImageIcon("C:\\Users\\Sky\\IdeaProjects\\new pr\\imgs\\Aplane.png");
        blimage = new ImageIcon("C:\\Users\\Sky\\IdeaProjects\\new pr\\imgs\\红豆.png");
        enimage = new ImageIcon("C:\\Users\\Sky\\IdeaProjects\\new pr\\imgs\\我机.png");
        //建立缓存图片
        System.out.println("jf="+jf);
        BufferedImage bf = new BufferedImage(jf.getWidth(),jf.getHeight(),BufferedImage.TYPE_INT_RGB);
        //获取缓存图片上的画笔
        Graphics ng =bf.getGraphics();

        while (true){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //绘制背景效果
            //绘制两张图进行连接,第二张图的起始点的纵坐标比窗口界面高一个图片的高度,故为:imageY-image.getIconHeight()
//            g.drawImage(image.getImage(),0,0,800,800,null);
            ng.drawImage(bgimage.getImage(),imageX,imageY,null);
            ng.drawImage(bgimage.getImage(),imageX,imageY-bgimage.getIconHeight(),null);
            imageY++;

            //让两张图片循环使用:当第二张图片的左上角位置几乎快靠近窗体的左上角位置时,将第一张图片的起始位置设为0            if(imageY-image.getIconHeight() >= 0){
            if(imageY- bgimage.getIconHeight() >= 0){
                imageY = 0;
            }

                //遍历moveBallList
                for (int i = 0; i < moveBallList.size(); i++) {
                    MoveBall bullet = moveBallList.get(i);
                    //g.setColor(Color.DARK_GRAY);
                    //bullet.drawBall(g);
                    //用子弹图片代替子弹小球
                    bullet.drawPlane(ng, blimage);
                    bullet.move();

                }
                for (int i = 0; i < enemyList.size(); i++) {
                    MoveBall enemy = enemyList.get(i);
                    //g.setColor(Color.DARK_GRAY);
                    //bullet.drawBall(g);
                    //用子弹图片代替子弹小球
                    enemy.drawPlane(ng, enimage);
                    enemy.move();

                }
                //控制角色
                //g.setColor(Color.black);
                //aircraft.drawBall(g);
                //用图片代替小球
                aircraft.drawPlane(ng, apimage);
                aircraft.move();
                g.drawImage(bf,0,0,null);

            }


        }

}


import javax.swing.*;
import java.awt.*;

/**
 * 是个移动对象,作为各类飞行物体的父类

 */
public class MoveBall {
    private int x, y;//小球的起始位置
    private int vx, vy;//小球的运动速度,运动方向
    private int size;//小球直径
//    private Graphics g;
//    Random random = new Random();


    //创建子弹的构造方法
    //根据移动的对象初始化子弹位置
    public MoveBall(){
        x = 370;
        y = 700;
        size = 60;
    }

//    int a = random.nextInt(255);//给小球设置随机颜色
//    int b = random.nextInt(255);
//    int c = random.nextInt(255);



    //小球的绘制
    public void drawBall(Graphics g) {
//        //绘制小球
//        g.setColor(Color.WHITE);
//        g.fillOval(x, y, size, size);
//        //小球移动
//        x += vx;
//        y += vy;
//        g.setColor(new Color(a,b,c));
        g.fillOval(x, y, size, size);

//        //小球边界问题
//        if(x >= 800-size || y >= 800-size || x<= 0 || y <= 65){
//            vx = -vx;
//            vy = -vy;
//        }

        //小球碰撞问题
    }
    public void drawPlane(Graphics g, ImageIcon imageIcon){
        g.drawImage(imageIcon.getImage(),x,y,null);
        x+=vx;
        y+=vy;


    }

    public void drawEnemy(Graphics g, ImageIcon imageIcon){
        g.drawImage(imageIcon.getImage(),x,y,null);
        x+=vx;
        y+=vy;


    }
    //移动的方法
    public void move(){
        x += vx;
        y += vy;
    }
    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    //提供速度的get、set方法
    public int getVx() {
        return vx;
    }

    public void setVy(int vy) {
        this.vy = vy;
    }

    public int getVy() {
        return vy;
    }

    public void setVx(int vx) {
        this.vx = vx;
    }

    public int getX() {
        return x;
    }

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

    public int getY() {
        return y;
    }

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

import java.util.List;
import java.util.Random;

/**
 * 定时任务线程:每隔一段时间就创建一个新的子弹对象
 * 定时任务线程:每隔一段时间就创建一个新的敌机对象

 */
public class TimeThread implements Runnable {
    public long time = 400;//任务的间隔时间
    public Aircraft aircraft ;//飞机对象
    public List<MoveBall> moveBallList;
    public List<Enemy> enemyList;

    Random random = new Random();



    //初始化飞机对象/保存子弹list
    public TimeThread(Aircraft aircraft, List<MoveBall> moveBallList, List<Enemy>enemyList){
        this.aircraft = aircraft;
        this.moveBallList = moveBallList;
        this.enemyList = enemyList;
    }

    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //创建子弹对象,根据我方飞机位置实时创建子弹对象
            int x = aircraft.getX() + aircraft.getSize()/2+6;
            int y = aircraft.getY() + aircraft.getSize()/-100;

            int a = random.nextInt(800);

            Enemy enemy = new Enemy(a,40);
            enemyList.add(enemy);

            Bullet bullet = new Bullet(x,y);
            moveBallList.add(bullet);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值