首先进行界面设计,如图设计:
主要使用JFrame、JPanel和JButton组件,及添加一些监听器。
package 最_雷霆战机; /** * 游戏界面设计 * @author asus */ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; public class LeidianUI extends JFrame { public static void main(String[] arg) { new LeidianUI().initUI(); } public void initUI() { this.setTitle("雷电"); this.setSize(400, 600); this.setResizable(false); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLayout(new BorderLayout()); // 添加游戏界面 final GamePanel jp1 = new GamePanel(); jp1.setPreferredSize(new Dimension(380, 500)); jp1.setBackground(Color.BLACK); // 添加操作界面 JPanel jp2 = new JPanel(); jp2.setBackground(Color.WHITE); this.add(jp1, BorderLayout.NORTH); this.add(jp2, BorderLayout.CENTER); final JButton start = new JButton("start"); final JButton pause = new JButton("pause"); final JButton over = new JButton("over"); pause.setEnabled(false); over.setEnabled(false); jp2.add(start); jp2.add(pause); jp2.add(over); this.setVisible(true); ActionListener alis = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String s = e.getActionCommand(); if (s.equals("start")) { jp1.initGamePanel(15); // 禁用开始按钮,其他按钮启动 start.setEnabled(false); pause.setEnabled(true); over.setEnabled(true); } else if (s.equals("pause")) { pause.setText("continue"); GamePanel.pauseThread(); } else if (s.equals("continue")) { pause.setText("pause"); GamePanel.continueThread(); } else if (s.equals("over")) { pause.setText("pause"); start.setEnabled(true); pause.setEnabled(false); over.setEnabled(false); // 停止敌机 for (int i = 0; i < jp1.airList.size(); i++) { jp1.airList.get(i).stopThread(); } jp1.airList.clear(); // 停掉子弹线程 // 停止敌机 for (int i = 0; i < jp1.myAir.bulletList.size(); i++) { jp1.myAir.bulletList.get(i).stopThread(); } jp1.myAir.bulletList.clear(); // 自己的飞机 jp1.myAir.stopThread(); jp1.myAir = null; } } }; start.addActionListener(alis); pause.addActionListener(alis); over.addActionListener(alis); start.setFocusable(false); pause.setFocusable(false); over.setFocusable(false); //添加键盘监听器(GamePanel实现了KeyListener的接口,所以他就是一个监听器) this.addKeyListener(jp1); } }
将一个JPanel写成一个监听器,implements KeyListener。
package 最_雷霆战机; import java.awt.Color; import java.awt.Graphics; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.ArrayList; import javax.swing.JPanel; /*** * 重写paint方法绘制 * * @author asus * */ public class GamePanel extends JPanel implements KeyListener { public static boolean isRun = true; // 游戏是否终止 ArrayListairList = new ArrayList ();// 敌机对象个体存储的动态数组 MyAir myAir; private BackgroundThread bgThread; public void initGamePanel(int num) { myAir = new MyAir(this); myAir.start(); for (int i = 0; i < num; i++) { EAir air = new EAir(this); air.start(); airList.add(air); } } @Override public void paint(Graphics g) { super.paint(g); if (bgThread != null) { bgThread.draw(g); } // 绘制战机 if (myAir != null) { if (myAir.isLive) { myAir.draw(g); } for (int i = 0; i < myAir.bulletList.size(); i++) { BulletThread but = myAir.bulletList.get(i); // 如果活着就绘制,否则就删除掉 if (but.isLive) { but.draw(g); } else { myAir.bulletList.remove(i); } } } // 绘制敌机 for (int i = 0; i < airList.size(); i++) { EAir air = airList.get(i); if (air.isLive) { air.draw(g); } else { airList.remove(i); } } this.repaint(); } @Override public void keyTyped(KeyEvent e) { } public static void pauseThread() { isRun = false; } public static void continueThread() { isRun = true; } @Override public void keyPressed(KeyEvent e) { int code = e.getKeyCode(); switch (code) { case KeyEvent.VK_LEFT: MyAir.left = true; break; case KeyEvent.VK_RIGHT: MyAir.right = true; break; case KeyEvent.VK_UP: MyAir.up = true; break; case KeyEvent.VK_DOWN: MyAir.down = true; break; } } @Override public void keyReleased(KeyEvent e) { int code = e.getKeyCode(); switch (code) { case KeyEvent.VK_LEFT: MyAir.left = false; break; case KeyEvent.VK_RIGHT: MyAir.right = false; break; case KeyEvent.VK_UP: MyAir.up = false; break; case KeyEvent.VK_DOWN: MyAir.down = false; break; } } }
新建自己的战机的类MyAir,作为一个线程。
package 最_雷霆战机; /** * * 战机的类 * * @author asus */ import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; import java.net.URL; import java.util.ArrayList; import javax.swing.ImageIcon; public class MyAir extends Thread { // 飞机属性 int x = 10, y = 10; int width = 70; int height = 70; int xc = 2; int yc = 2; int blood = 20; Image img; private int panelWidth; private int panelHeight; private GamePanel panel; boolean isLive = true;// 线程是否活着 // 方向指令 public static boolean up, down, left, right; // 装子弹的队列 ArrayListbulletList = new ArrayList (); public MyAir(GamePanel gamePanel) { this.panel = gamePanel; Dimension dim = gamePanel.getPreferredSize(); panelWidth = dim.width; panelHeight = dim.height; // 获取战机图片 URL url = EAir.class.getResource("feiji.png"); img = new ImageIcon(url).getImage(); x = (panelWidth - width) / 2; y = panelHeight - height; } // 绘制战机 public void draw(Graphics g) { g.drawImage(img, x, y, width, height, null); } public void stopThread() { isLive = false; } public void fire() { BulletThread bullet = new BulletThread(panel, x + width / 2, y); bullet.start(); bulletList.add(bullet); } @Override public void run() { while (isLive) { if (GamePanel.isRun) { if (left) { xc = -2; } else if (right) { xc = 2; } else { xc = 0; } if (up) { yc = -2; } else if (down) { yc = 2; } else { yc = 0; } x += xc; y += yc; // 战机不出边界 if (x <= 0) { x = 0; } if (y <= 0) { y = 0; } if (x >= panelWidth - width) { x = panelWidth - width; } if (y >= panelHeight - height) { y = panelHeight - height; } } num++; if (num % 20 == 0) { this.fire(); } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } int num = 0; }
新建敌机类,extends Thread。存储到GamePanel中的动态数组里。
package 最_雷霆战机; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; import java.net.URL; import java.util.ArrayList; import java.util.Random; import javax.swing.ImageIcon; /** * 敌机的属性 * * @author asus * */ public class EAir extends Thread { // 敌机 int x = 10, y = 10; int width = 50, height = 50; int xc = 2, yc = 2; int blood = 5; Image img; Random rd = new Random(); int[] c = { 5, 4, 3, 2, 1 }; ArrayListairList; private int panelWidth; private int panelHeight; private GamePanel panel; boolean isLive = true; // 线程是否还存在 // static boolean isRun = true; // 线程是否还在执行逻辑处理-->进行数据的交换 public EAir(GamePanel gamePanel) { this.panel = gamePanel; this.airList = gamePanel.airList; Dimension dim = gamePanel.getPreferredSize(); panelWidth = dim.width; panelHeight = dim.height; URL url = EAir.class.getResource("diji.png"); img = new ImageIcon(url).getImage(); initDiji(); } // 敌机动作命令初始化 public void initDiji() { yc = c[rd.nextInt(c.length)]; x = rd.nextInt(panelWidth - width); y = -height; } // 绘制自身 public void draw(Graphics g) { g.drawImage(img, x, y, width, height, null); } @Override public void run() { while (isLive) { check(); if (GamePanel.isRun) { if (y >= panelHeight - height) { initDiji(); } y += yc; } try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } } } public void stopThread() { isLive = false; } // 检测两个小球是否相碰 public void check() { // 获得玩家飞机 MyAir myAir = panel.myAir; if (myAir != null) { // 检测玩家飞机和敌机是否碰撞 // 计算敌机的圆心 int xa = this.x + this.width / 2; int ya = this.y + this.width / 2; // 计算玩家的圆心 int xb = myAir.x + myAir.width / 2; int yb = myAir.y + myAir.width / 2; // 计算斜边 int c2 = Math.abs(xa - xb) * Math.abs(xa - xb) + Math.abs(ya - yb) * Math.abs(ya - yb); // 计算半径之和 int r = this.width / 2 + this.width / 2; // 碰撞到了 if (c2 <= r * r) { if (this.blood < myAir.blood) { myAir.blood -= this.blood; this.blood = 0; } else { myAir.stopThread(); } this.stopThread(); } for (int i = 0; i < myAir.bulletList.size(); i++) { // 取出一个子弹 BulletThread bullet = myAir.bulletList.get(i); int xc = bullet.x + bullet.width / 2; int yc = bullet.y + bullet.width / 2; // 计算斜边 int c3 = Math.abs(xa - xc) * Math.abs(xa - xc) + Math.abs(ya - yc) * Math.abs(ya - yc); // 计算半径之和 int r3 = this.width / 2 + this.width / 2; // 碰撞到了 if (c3 <= r3 * r3) { this.blood -= bullet.blood; bullet.blood = 0; if (this.blood <= 0) { // 敌机Over this.stopThread(); } // 子弹OVer bullet.stopThread(); } } } } }
设置子弹类,由战机发射子弹。
package 最_雷霆战机; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; public class BulletThread extends Thread{ int x, y; int width = 5, height = 5; int xc = 0, yc = -5; boolean isLive = true; int blood = 1; int screenWidth, screenHeight; public BulletThread(GamePanel gamePanel, int a, int b) { Dimension dim = gamePanel.getPreferredSize(); screenWidth = dim.width; screenHeight = dim.height; this.x = a - width / 2; this.y = b - height; } public void run() { while (isLive) { if (GamePanel.isRun) { if (y <= -height) { stopThread(); } // 子弹于飞出屏幕终止 x += xc; y += yc; } try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } public void stopThread() { isLive = false; } public void draw(Graphics g){ g.setColor(Color.green); g.fillOval(x, y, width, height); } }
注意isRun和isLive是否为静态,这里容易出错。并且over时各个线程要确定关闭。