效果图:
游戏窗口有两个,一个类似于登录界面,点击屏幕跳转到另一个主窗口。
WASD控制上下左右,空格键攻击。只用单一的主窗口线程的话键盘不能同时响应移动和攻击事件,所以创建多线程来控制事件发生:
PaintThread pt = new PaintThread(); //画图线程
MyBulletThread bt = new MyBulletThread(); //控制我放飞机射击事件
EnemyThread et = new EnemyThread(); //控制敌方飞机生成和销毁
EnemyMoveThread ems = new EnemyMoveThread(); //控制敌方飞机的移动
EnemyShootThread est = new EnemyShootThread(); //控制敌方飞机射击
我方子弹、敌方飞机、敌方子弹对象利用ArrayList存储:
// 动态数组存储我方子弹、敌人、敌人子弹
List<Bullet> mybulletlist = new ArrayList<Bullet>();
List<Enemy> enemylist = new ArrayList<Enemy>();
List<Bullet> enemybulletlist = new ArrayList<Bullet>();
通过线程循环遍历集合来进行图形的碰撞检测,子弹出边界或触碰到飞机会自动销毁:
// 画我方子弹
for (int i = 0; i < mybulletlist.size(); i++) {
//子弹存活就画出来
if(mybulletlist.get(i).isLive()) {
mybulletlist.get(i).draw(gBuffer);
//我方子弹与敌人的碰撞检测
for(int j = 0;j<enemylist.size(); j++) {
//发生碰撞设置live为false,敌人hp-5
if (mybulletlist.get(i).getRect().intersects(enemylist.get(j).getRect())) {
mybulletlist.get(i).setLive(false);
enemylist.get(j).setHp(enemylist.get(j).getHp() - 5);
}
//子弹无碰撞则继续移动
else {
mybulletlist.get(i).setY(mybulletlist.get(i).getY() - sp);
}
}
}
}
画面闪烁通过引入双缓存解决:
if (iBuffer == null) {
iBuffer = createImage(this.getWidth(), this.getHeight());
}
gBuffer = iBuffer.getGraphics();
gBuffer.drawImage(bg, 0, 0, this.getWidth(), this.getHeight(), null);
// ...
g.drawImage(iBuffer, 0, 0, this.getWidth(), this.getHeight(), null);
通过设置暂停标识符控制线程暂停。在线程run()中加入while(pause),pause开始为false不执行内部循环,为true时线程进入死循环达到暂停效果。
public class PaintThread implements Runnable {
@Override
public void run() {
// TODO 自动生成的方法存根
while (true) {
while (pause) {
try {
Thread.sleep(60);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
repaint();
try {
Thread.sleep(60);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
窗口类部分代码:
package appwindow;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.Image;
import java.awt.event.*;
public class StartWindow extends JFrame{
/**
*
*/
private static final long serialVersionUID = 8073145223230620434L;
public StartWindow() {
}
public void init() {
this.setTitle("FunnyTopGun");
this.setSize(860,480);
this.setResizable(false);
this.setLocation(0,0);
this.setVisible(true);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void backimg() {
JLabel img_lab = new JLabel();
img_lab.setSize(860,480);
img_lab.setLocation(0, 0);
img_lab.setVisible(true);
add(img_lab);
ImageIcon icon = new ImageIcon("img//start.gif");
icon.setImage(icon.getImage().getScaledInstance(img_lab.getWidth(),img_lab.getHeight(),Image.SCALE_DEFAULT));
img_lab.setIcon(icon);
this.add(img_lab);
}
public static void main(String[] args) {
StartWindow app1 = new StartWindow();
app1.init();
app1.backimg();
app1.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
app1.dispose();
MainWindow app2 = new MainWindow();
}
});
}
}
游戏物体父类部分代码:
package flyobject;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
public class FlyObject {
int width;
int height;
Image img;
int x;
int y;
int speed;
boolean live;
int hp;
public FlyObject() {
}
public void draw(Graphics g) {
g.drawImage(img, x, y, width, height, null);
}
public Rectangle getRect() {
return new Rectangle((int)x,(int)y,width,height);
}
public Image getImg() {
return img;
}
public void setImg(Image img) {
this.img = img;
}
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;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public int getHp() {
return hp;
}
public void setHp(int hp) {
this.hp = hp;
}
public boolean isLive() {
return live;
}
public void setLive(boolean a) {
this.live = a;
}
}
目前还存在的BUG是游戏暂停后再开始时我方飞机移动会不受控制一小段时间。
源码:funnytopgun