复习facade外观模式:
https://blog.csdn.net/phs999/article/details/107298881
使用facade外观模式简化TankFrame类,将炮弹类、坦克类、爆炸类之间的逻辑关系、碰撞检测等进行封装,封装为GameModelFacade类。
修改前的版本看这里:
其中,修改优化前的TankFrame类如下,我们要做的是把逻辑调用、碰撞检测等从该类剥离,使得该类只负责展示方面的工作,减少与其他类如Tank、Bullet等的耦合。
package phs999.tank;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
public class TankFrame extends Frame {
Tank myTank = new Tank(200, 400, Dir.UP,Group.GOOD,this);
List<Bullet> bullets =new ArrayList<>();
List<Tank> enemyTanks=new ArrayList<>();
List<Explode> explodes=new ArrayList<>();
static final int GAME_WIDTH=800,GAME_HEIGHT=600;
public TankFrame() {
setSize(GAME_WIDTH, GAME_HEIGHT);// 像素px
setResizable(false);// 禁止改变大小
setTitle("tank war");
setVisible(true);// 设置可见性
addKeyListener(new MykeyListener());
// 设置关闭
addWindowListener(new WindowAdapter() {
/**
* Invoked when a window is in the process of being closed. The close operation
* can be overridden at this point.
*
* @param e
*/
@Override
public void windowClosing(WindowEvent e) {
// super.windowClosing(e);
System.exit(0);
}
});
}
Image offScreenImage = null;
@Override
public void update(Graphics g) {
if (offScreenImage == null) {
offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);
}
Graphics gOffScreen = offScreenImage.getGraphics();
Color c = gOffScreen.getColor();
gOffScreen.setColor(Color.BLACK);
gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
gOffScreen.setColor(c);
paint(gOffScreen);
g.drawImage(offScreenImage, 0, 0, null);
}
@Override
public void paint(Graphics g) {
Color color=g.getColor();
g.setColor(Color.WHITE);
g.drawString("子弹数量:"+bullets.size(), 10, 60);
g.drawString("敌人数量:"+enemyTanks.size(), 10, 80);
g.drawString("爆炸数量:"+explodes.size(), 10, 100);
g.setColor(color);
myTank.paint(g);
for (int i = 0; i < bullets.size(); i++) {
bullets.get(i).paint(g);
}
for (int i = 0; i < enemyTanks.size();i++) {
enemyTanks.get(i).paint(g);
}
for (int i = 0; i <bullets.size(); i++) {
for (int j = 0; j < enemyTanks.size(); j++) {
bullets.get(i).collideWith(enemyTanks.get(j));
}
}
for (int i = 0; i < explodes.size(); i++) {
explodes.get(i).paint(g);
}
/*
* for (Bullet bullet : bullets) { bullet.paint(g); }
*/
}
class MykeyListener extends KeyAdapter {
boolean bL=false;
boolean bR=false;
boolean bU=false;
boolean bD=false;
@Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_LEFT:
bL=true;
break;
case KeyEvent.VK_RIGHT:
bR=true;
break;
case KeyEvent.VK_UP:
bU=true;
break;
case KeyEvent.VK_DOWN:
bD=true;
break;
case KeyEvent.VK_CONTROL:
myTank.fire(FourDirFireStrategy.getFireStrategy());
default:
break;
}
// x+=200;
// y+=10;
// repaint();
setMainTankDir();
new Thread(()->new Audio("audio/tank_move.wav").play()).start();
/*
* if (bL) { x-=10; } if (bR) { x+=10; } if (bU) { y-=10; } if (bD) { y+=10; }
*/
}
private void setMainTankDir() {
if (!bL && !bR && !bU && !bD) {
myTank.setMoving(false);
}else {
myTank.setMoving(true);
if (bL) {
myTank.setDir(Dir.LEFT);
}
if (bR) {
myTank.setDir(Dir.RIGHT);
}
if (bU) {
myTank.setDir(Dir.UP);
}
if (bD) {
myTank.setDir(Dir.DOWN);
}
}
}
@Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_LEFT:
bL=false;
break;
case KeyEvent.VK_RIGHT:
bR=false;
break;
case KeyEvent.VK_UP:
bU=false;
break;
case KeyEvent.VK_DOWN:
bD=false;
break;
default:
break;
}
setMainTankDir();
}
}
}
修改后的代码如下:
package phs999.tank;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
public class TankFrame extends Frame {
GameModelFacade gm=new GameModelFacade();
static final int GAME_WIDTH=800,GAME_HEIGHT=600;
public TankFrame() {
setSize(GAME_WIDTH, GAME_HEIGHT);// 像素px
setResizable(false);// 禁止改变大小
setTitle("tank war");
setVisible(true);// 设置可见性
addKeyListener(new MykeyListener());
// 设置关闭
addWindowListener(new WindowAdapter() {
/**
* Invoked when a window is in the process of being closed. The close operation
* can be overridden at this point.
*
* @param e
*/
@Override
public void windowClosing(WindowEvent e) {
// super.windowClosing(e);
System.exit(0);
}
});
}
Image offScreenImage = null;
@Override
public void update(Graphics g) {
if (offScreenImage == null) {
offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);
}
Graphics gOffScreen = offScreenImage.getGraphics();
Color c = gOffScreen.getColor();
gOffScreen.setColor(Color.BLACK);
gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
gOffScreen.setColor(c);
paint(gOffScreen);
g.drawImage(offScreenImage, 0, 0, null);
}
@Override
public void paint(Graphics g) {
gm.paint(g);
}
class MykeyListener extends KeyAdapter {
boolean bL=false;
boolean bR=false;
boolean bU=false;
boolean bD=false;
@Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_LEFT:
bL=true;
break;
case KeyEvent.VK_RIGHT:
bR=true;
break;
case KeyEvent.VK_UP:
bU=true;
break;
case KeyEvent.VK_DOWN:
bD=true;
break;
case KeyEvent.VK_CONTROL:
gm.getMainTank().fire(FourDirFireStrategy.getFireStrategy());
default:
break;
}
// x+=200;
// y+=10;
// repaint();
setMainTankDir();
new Thread(()->new Audio("audio/tank_move.wav").play()).start();
/*
* if (bL) { x-=10; } if (bR) { x+=10; } if (bU) { y-=10; } if (bD) { y+=10; }
*/
}
private void setMainTankDir() {
Tank myTank=gm.getMainTank();
if (!bL && !bR && !bU && !bD) {
myTank.setMoving(false);
}else {
myTank.setMoving(true);
if (bL) {
myTank.setDir(Dir.LEFT);
}
if (bR) {
myTank.setDir(Dir.RIGHT);
}
if (bU) {
myTank.setDir(Dir.UP);
}
if (bD) {
myTank.setDir(Dir.DOWN);
}
}
}
@Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_LEFT:
bL=false;
break;
case KeyEvent.VK_RIGHT:
bR=false;
break;
case KeyEvent.VK_UP:
bU=false;
break;
case KeyEvent.VK_DOWN:
bD=false;
break;
default:
break;
}
setMainTankDir();
}
}
}
主要更改是paint方法以及对Tank、Bullet的初始化等交由外观类GameModelFacade完成。
package phs999.tank;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
public class GameModelFacade {
Tank myTank = new Tank(200, 400, Dir.UP,Group.GOOD,this);
List<Bullet> bullets =new ArrayList<>();
List<Tank> enemyTanks=new ArrayList<>();
List<Explode> explodes=new ArrayList<>();
public GameModelFacade() {
int initTankCount=Integer.parseInt((String)PropertyMgr.get("initTankCount"));
//初始化敌方坦克
for (int i = 0; i < initTankCount; i++) {
enemyTanks.add(new Tank(50+80*i, 200, Dir.DOWN,Group.BAD, this));
}
}
public void paint(Graphics g) {
Color color=g.getColor();
g.setColor(Color.WHITE);
g.drawString("子弹数量:"+bullets.size(), 10, 60);
g.drawString("敌人数量:"+enemyTanks.size(), 10, 80);
g.drawString("爆炸数量:"+explodes.size(), 10, 100);
g.setColor(color);
myTank.paint(g);
for (int i = 0; i < bullets.size(); i++) {
bullets.get(i).paint(g);
}
for (int i = 0; i < enemyTanks.size();i++) {
enemyTanks.get(i).paint(g);
}
for (int i = 0; i <bullets.size(); i++) {
for (int j = 0; j < enemyTanks.size(); j++) {
bullets.get(i).collideWith(enemyTanks.get(j));
}
}
for (int i = 0; i < explodes.size(); i++) {
explodes.get(i).paint(g);
}
/*
* for (Bullet bullet : bullets) { bullet.paint(g); }
*/
}
public Tank getMainTank() {
return myTank;
}
}
完整代码在这里: