飞机大战游戏1

前言:利用前面总结的继承,接口的知识,以及UI设计,设计一个线程游戏,会涉及多线程知识,类似于网页上的飞机大战,2d小游戏

1.设计UI界面,利用之前学习的UI设计知识,先设计基础界面,即窗体,标题,窗体大小等

java 复制代码
 JFrame jf=new JFrame("射击游戏");
        jf.setSize(1000,1000);
        jf.setDefaultCloseOperation(3);
        jf.setLocationRelativeTo(null);

        JPanel gamepanel=new JPanel();
        gamepanel.setBackground(Color.WHITE);
        jf.add(gamepanel,BorderLayout.CENTER);

        jf.setVisible(true);

1.我们这里选择使用JPanel组件来专门承载整个游戏载体,是因为JFrame无法让监听器正常被接收,而键盘监听器需要JPanel组件去接受

2.设置可见

2.我们需要各个组件有反应,让飞机可以在组件上动,释放技能,我们需要利用键盘监听器,我们可以弄一个键盘监听器接口

1.由于要讲东西画上面板,则我们需要画笔对象,再利用构造函数实现画笔在类与类之间的传递

java 复制代码
Graphics g= gamepanel.getGraphics();
        GameListener listener=new GameListener(g);
        gamepanel.addMouseListener(listener);

        gamepanel.addKeyListener(listener);
        gamepanel.requestFocus();
java 复制代码
        public GameListener(Graphics g){
        this.g=g;
    }

其中requestFocus是为了让键盘能够正确输出

2.要让各个功能都独立执行,我们需要使用多线程,即利用一个Thread类去继承自带的Thread类,从而实现我们想要的功能效果

1.整个游戏,由玩家对象,敌机对象,子弹对象构成,我们需要创建各自对应的类,去分别实现

2.关于玩家类,我们可以单独实现玩家对应的属性和方法

java 复制代码
 public int x,y,size;
    public int speedX,speedY;
    public Image image;
java 复制代码
 public MPlayer(int x,int y){
        this.x=x;
        this.y=y;
        size=100;

        image=new ImageIcon("image\\img.png").getImage();
    }

    public void drawPlayer(Graphics g){

        // 左右边界限制
        if (x < 0) x = 0;
        if (x > 1000 - size) x = 1000 - size;

        g.drawImage(image,x,y,size,size,null);
        move();

    }
    public void move(){
        x+=speedX;
        y+=speedY;
    }

注意:该图片路径是相对路径,这样做可以避免图片被删除后,程序就崩溃了,在左上角的项目那里新建文件夹即可

3.设计子弹类,和前面的玩家类的实现一个逻辑

但是还没有加图片素材,我们用矩形代替,子弹本身的创建依旧是用画笔去画,也就是给对应函数传画笔参数,实现子弹的绘制,为了避免出现连续矩形,我们可以先画白色,再画子弹颜色,但是这样做的缺点是无法更换背景以及会出现闪烁,我们后面再修改

java 复制代码
public class Bullet {
    public int x;
    public int y;
    public int width=10;
    public int height=8;
    public int speedY=-8;

    public Bullet(){}

    public Bullet(int startX,int startY){
        this.x=startX;
        this.y=startY;
    }

    public void move(){
        y+=speedY;
    }

    public void drawBullet(Graphics g){
        g.setColor(Color.WHITE);
        g.fillOval(x,y,width,height);

        g.setColor(Color.blue);
        g.fillOval(x,y,width,height);
    }


}

4.接下来是敌机,逻辑和之前的一样

java 复制代码
public class Enemy {
    public int x,y;
    public int width=60;
    public int height=60;

    public int speedY=3;
    public Random random=new Random();

    public Enemy(){
        this.x=random.nextInt(940);
        this.y=-height;
    }

    public void move(){
        y+=speedY;
    }

    public void drawEnemy(Graphics g){
        g.setColor(Color.RED);
        g.fillRect(x,y,width,height);
    }
}    

这个random表示的是随机的创建,因为敌机一般是随机出现嘛

3.设计几个键来控制游戏开始,以及飞机本体,在线程类中创建即可,这样就是多线程,单线程的话就无法执行其他操作,会卡顿

1.先创建两个可扩容数组来存放敌机和子弹,因为需要一直有嘛,肯定要自动扩容

java 复制代码
public Graphics g;
    public MPlayer mp;
    public Enemy enemy;
    public ArrayList<Bullet> arrayList=new ArrayList<>();
    public ArrayList<Enemy> enemyList=new ArrayList<>();

2.设计几个变量控制游戏的开始,暂停

java 复制代码
public boolean isrunning=false;//R键表示启动
 public boolean gameThreadStarted=false;//游戏渲染线程
 public boolean bulletThreadStarted=false;//自动发射子弹线程是否启动
 public boolean enemyThreadStarted=false; 

3.写一个敌人生成的专线程

java 复制代码
class EnemySpawnThread implements Runnable{
        private GameListener listener;
        public EnemySpawnThread(GameListener listener){
            this.listener=listener;
        }
        @Override
        public void run() {
            while(true){
                try {
                    Thread.sleep(800);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(listener.isrunning){
                    listener.enemyList.add(new Enemy());
                }
            }
        }
    }

4.空格键表示游戏开始,游戏开始时启动,在里面创建线程对象,start()表示线程开始

java 复制代码
case KeyEvent.VK_SPACE :
                if(!gameThreadStarted) {
                    mp = new MPlayer(350, 600);
                    GameThread gt = new GameThread(g, mp, arrayList,enemyList,this);
                    gt.start();
                    gameThreadStarted=true;
                    isrunning=true;

5.A表示向左移动,D表示向右移动

java 复制代码
 case KeyEvent.VK_A:
                mp.speedX=-5;
                break;

            case KeyEvent.VK_D:
                mp.speedX=5;
                break;

6.按J创建子弹对象,并存进数组,然后传递到线程类,再利用循环画出子弹

java 复制代码
case KeyEvent.VK_J:
                if(mp !=null && isrunning) {
                    Bullet bullet = new Bullet(mp.x, mp.y);
                    arrayList.add(bullet);

                }
                break;      
java 复制代码
for (int i=0;i<arrayList.size();i++){
                      Bullet bullet=arrayList.get(i);
                      bullet.move();
                      bullet.drawBullet(g);
                      if(bullet.y<0){
                          arrayList.remove(i);
                      }
                 }       

7.创建一个时间类线程,控制子弹的定时发动

java 复制代码
public class TimeThread implements Runnable{
    public long time=200;
    public MPlayer mp;
    public ArrayList<Bullet> arrayList;
    public GameListener gameListener;

    public TimeThread(MPlayer mp, ArrayList<Bullet> arrayList,GameListener gameListener){
        this.mp=mp;
        this.arrayList=arrayList;
        this.gameListener=gameListener;
    }
    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            // 暂停状态不生成子弹
            if (!gameListener.isrunning || mp == null) {
                continue;
            }
            Bullet bullet=new Bullet(mp.x, mp.y);
            arrayList.add(bullet);
        }

    }
}                            

8.按Q则是启动这个时间类线程

java 复制代码
case KeyEvent.VK_Q:
                if(!bulletThreadStarted && mp !=null) {
                    TimeThread timeThread = new TimeThread(mp, arrayList,this);
                    new Thread(timeThread).start();
                    bulletThreadStarted=true;

                }
                break;       

易错总结:1.如果不使用线程类,则就是单线程,这样会使得程序卡顿

2.再传递画笔的时候,要注意空指针异常

3.后面我们将使用缓冲区去绘制画面,就不会出现闪烁等问题

以下是完整代码:

java 复制代码
public class GameUI {
    public void initUI(){
        JFrame jf=new JFrame("射击游戏");
        jf.setSize(1000,1000);
        jf.setDefaultCloseOperation(3);
        jf.setLocationRelativeTo(null);

        JPanel gamepanel=new JPanel();
        gamepanel.setBackground(Color.WHITE);
        jf.add(gamepanel,BorderLayout.CENTER);

        jf.setVisible(true);

        Graphics g= gamepanel.getGraphics();
        GameListener listener=new GameListener(g);
        gamepanel.addMouseListener(listener);

        gamepanel.addKeyListener(listener);
        gamepanel.requestFocus();
    }

    public static void main(String[] args) {
        GameUI ui=new GameUI();
        ui.initUI();
    }
}      
public class GameListener extends MouseAdapter implements KeyListener{
    public Graphics g;
    public MPlayer mp;
    public Enemy enemy;
    public ArrayList<Bullet> arrayList=new ArrayList<>();
    public ArrayList<Enemy> enemyList=new ArrayList<>();
    public GameListener listener;

    //游戏标识================
    public boolean isrunning=false;//R键表示启动
    public boolean gameThreadStarted=false;//游戏渲染线程
    public boolean bulletThreadStarted=false;//自动发射子弹线程是否启动
    public boolean enemyThreadStarted=false;

    class EnemySpawnThread implements Runnable{
        private GameListener listener;
        public EnemySpawnThread(GameListener listener){
            this.listener=listener;
        }
        @Override
        public void run() {
            while(true){
                try {
                    Thread.sleep(800);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(listener.isrunning){
                    listener.enemyList.add(new Enemy());
                }
            }
        }
    }



    public GameListener(Graphics g){
        this.g=g;
    }
    public void mouseClicked(MouseEvent e) {
        System.out.println("点击!");
        int x = e.getX();
        int y = e.getY();


    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        int key=e.getKeyCode();
        System.out.println("key"+key);

        switch (key){
            case KeyEvent.VK_SPACE :
                if(!gameThreadStarted) {
                    mp = new MPlayer(350, 600);
                    GameThread gt = new GameThread(g, mp, arrayList,enemyList,this);
                    gt.start();
                    gameThreadStarted=true;
                    isrunning=true;

                }
                // 启动敌机生成线程
                if(!enemyThreadStarted){
                    new Thread(new EnemySpawnThread(this)).start();
                    enemyThreadStarted=true;
                }
                break;
            case KeyEvent.VK_A:
                mp.speedX=-5;
                break;

            case KeyEvent.VK_D:
                mp.speedX=5;
                break;
            case KeyEvent.VK_J:
                if(mp !=null && isrunning) {
                    Bullet bullet = new Bullet(mp.x, mp.y);
                    arrayList.add(bullet);

                }
                break;
            case KeyEvent.VK_Q:
                if(!bulletThreadStarted && mp !=null) {
                    TimeThread timeThread = new TimeThread(mp, arrayList,this);
                    new Thread(timeThread).start();
                    bulletThreadStarted=true;

                }
                break;
            case KeyEvent.VK_R:
                isrunning=!isrunning;
                if(isrunning){
                    JOptionPane.showMessageDialog(null,"游戏继续");

                }else {
                    JOptionPane.showMessageDialog(null,"游戏暂停");
                }
                break;

        }

    }

    @Override
    public void keyReleased(KeyEvent e) {
             int key=e.getKeyCode();
             if(key==KeyEvent.VK_A || key==KeyEvent.VK_D){
                 if(mp !=null)
                     mp.speedX=0;
             }
    }

}
public class Enemy {
    public int x,y;
    public int width=60;
    public int height=60;

    public int speedY=3;
    public Random random=new Random();

    public Enemy(){
        this.x=random.nextInt(940);
        this.y=-height;
    }

    public void move(){
        y+=speedY;
    }

    public void drawEnemy(Graphics g){
        g.setColor(Color.RED);
        g.fillRect(x,y,width,height);
    }
}
public class MPlayer {
    public int x,y,size;
    public int speedX,speedY;
    public Image image;

    public MPlayer(int x,int y){
        this.x=x;
        this.y=y;
        size=100;

        image=new ImageIcon("image\\img.png").getImage();
    }

    public void drawPlayer(Graphics g){

        // 左右边界限制
        if (x < 0) x = 0;
        if (x > 1000 - size) x = 1000 - size;

        g.drawImage(image,x,y,size,size,null);
        move();

    }
    public void move(){
        x+=speedX;
        y+=speedY;
    }
}
public class TimeThread implements Runnable{
    public long time=200;
    public MPlayer mp;
    public ArrayList<Bullet> arrayList;
    public GameListener gameListener;

    public TimeThread(MPlayer mp, ArrayList<Bullet> arrayList,GameListener gameListener){
        this.mp=mp;
        this.arrayList=arrayList;
        this.gameListener=gameListener;
    }
    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            // 暂停状态不生成子弹
            if (!gameListener.isrunning || mp == null) {
                continue;
            }
            Bullet bullet=new Bullet(mp.x, mp.y);
            arrayList.add(bullet);
        }

    }
}
public class GameThread extends Thread{
         public Graphics g;
         public MPlayer mp;

         public GameListener listener;
         public int x;
         public ArrayList<Bullet> arrayList;
         public ArrayList<Enemy> enemyList;
         public GameThread(Graphics g, MPlayer mp, ArrayList<Bullet> arrayList,ArrayList<Enemy> enemyList,GameListener listener){
             this.g=g;
             this.mp=mp;
             this.arrayList=arrayList;
             this.enemyList=enemyList;
             this.listener=listener;
         }
         public void run(){
             System.out.println(Thread.currentThread().getName()+"线程启动");
             while (true){
                 try {
                     Thread.sleep(50);
                 } catch (InterruptedException e) {
                     throw new RuntimeException(e);
                 }
                 if(!listener.isrunning){
                     continue;
                 }
                 mp.drawPlayer(g);

                 for (int i=0;i<arrayList.size();i++){
                      Bullet bullet=arrayList.get(i);
                      bullet.move();
                      bullet.drawBullet(g);
                      if(bullet.y<0){
                          arrayList.remove(i);
                      }
                 }

                 for (int i = enemyList.size() - 1; i >= 0; i--) {
                     Enemy enemy = enemyList.get(i);
                     enemy.move();
                     enemy.drawEnemy(g);
                     if (enemy.y > 1000) {
                         enemyList.remove(i);
                     }
                 }
             }
         }
}
public class Bullet {
    public int x;
    public int y;
    public int width=10;
    public int height=8;
    public int speedY=-8;

    public Bullet(){}

    public Bullet(int startX,int startY){
        this.x=startX;
        this.y=startY;
    }

    public void move(){
        y+=speedY;
    }

    public void drawBullet(Graphics g){
        g.setColor(Color.WHITE);
        g.fillOval(x,y,width,height);

        g.setColor(Color.blue);
        g.fillOval(x,y,width,height);
    }


}
相关推荐
山东布谷网络科技5 小时前
靠“社交+游戏”突围:中东语聊APP前景预测与低成本运营案例
人工智能·游戏
郝学胜-神的一滴10 小时前
[简化版 GAMES 104] 现代游戏引擎 04:从0到1构建你的游戏世界
c++·游戏·unity·游戏引擎·软件工程·unreal engine
爱勇宝14 小时前
《完蛋!我被男同学包围了》为什么会火?不只是因为“高中生玩票”
游戏·游戏开发
中国搜索直付通16 小时前
游戏车机端支付通道,会是下一个被低估的合规战场吗?
java·大数据·开发语言·人工智能·游戏
humors2211 天前
支付宝游戏频道《灵画师》体验
游戏·介绍·体验·攻略·灵画师·试玩
HMS Core1 天前
基于人体骨骼点识别与跟踪,实现低时延体感游戏
游戏·华为·harmonyos
AI分享猿2 天前
游戏原画与建筑灵感:AI图像生成如何服务前期设计
人工智能·游戏
饺子大魔王的男人2 天前
NAS还能挂机修仙?极空间部署XiuXianGame网页游戏教程
游戏
Tisfy3 天前
LeetCode 1406.石子游戏 III:递归(DFS+记忆化) / 递推(DP+原地滚动)
leetcode·游戏·深度优先·dfs·题解·博弈