4.使用facade外观模式优化坦克大战代码-设计模式之坦克大战

复习facade外观模式:

https://blog.csdn.net/phs999/article/details/107298881

使用facade外观模式简化TankFrame类,将炮弹类、坦克类、爆炸类之间的逻辑关系、碰撞检测等进行封装,封装为GameModelFacade类。

修改前的版本看这里:

https://github.com/phs999/DesignPatterns/tree/35436e83f8eb0664abe5503637ed130321194890/tank/src/phs999/tank

其中,修改优化前的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;
	}
}

完整代码在这里:

https://github.com/phs999/DesignPatterns/tree/63279d90ea7da97e8a94bb24ecd9d7da7d75535f/tank/src/phs999/tank

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值