diff --git a/docs/坦克大战笔记.docx b/docs/坦克大战笔记.docx index 87fdd1d..e1d5c20 100644 Binary files a/docs/坦克大战笔记.docx and b/docs/坦克大战笔记.docx differ diff --git a/src/com/demo/tank/course8/Bullet.java b/src/com/demo/tank/course8/Bullet.java new file mode 100644 index 0000000..70372ca --- /dev/null +++ b/src/com/demo/tank/course8/Bullet.java @@ -0,0 +1,132 @@ +package com.demo.tank.course8; + +import com.demo.tank.enums.Direction; +import com.demo.tank.enums.Group; +import com.demo.tank.util.ResourceManager; + +import java.awt.*; + +public class Bullet { + private int x, y; + private Direction direction; + private static final int SPEED = 10; + public static final int WIDTH = ResourceManager.bulletD.getWidth(); + public static final int HEIGHT = ResourceManager.bulletD.getHeight(); + private boolean live = true; + private Group group = Group.BAD; + private GameModel gm; + Rectangle rect = new Rectangle(); + + public Bullet(int x, int y, Direction direction, Group group, GameModel gm) { + this.x = x; + this.y = y; + this.direction = direction; + this.group = group; + this.gm = gm; + + rect.x = this.x; + rect.y = this.y; + rect.width = Bullet.WIDTH; + rect.height = Bullet.HEIGHT; + gm.bullets.add(this); + } + + public void paint(Graphics g){ + if(!live){ + gm.bullets.remove(this); + } + switch (direction){ + case UP: + g.drawImage(ResourceManager.bulletU, x, y, null); + break; + case DOWN: + g.drawImage(ResourceManager.bulletD, x, y, null); + break; + case LEFT: + g.drawImage(ResourceManager.bulletL, x, y, null); + break; + case RIGHT: + g.drawImage(ResourceManager.bulletR, x, y, null); + break; + } + move(); + } + + private void move() { + switch (direction){ + case UP: y -= SPEED; + break; + case DOWN: y += SPEED; + break; + case LEFT: x -= SPEED; + break; + case RIGHT: x += SPEED; + break; + default: + break; + } + if(x < 0 || y < 0 || x > TankFrameV8.GAME_WIDTH || y > TankFrameV8.GAME_HEIGHT){ + live = false; + } + rect.x = this.x; + rect.y = this.y; + } + + //检测是否跟坦克碰撞 + public void collideWith(Tank tank){ + //关闭队友伤害 + if(this.group == tank.getGroup()) return; + if(rect.intersects(tank.rect)){ + tank.die(); + this.die(); + //爆炸 + int ex = tank.getX() + Tank.WIDTH/2 - Explode.WIDTH/2; + int ey = tank.getY() + Tank.HEIGHT/2 - Explode.HEIGHT/2; + gm.explodes.add(new Explode(ex, ey , gm)); + } + } + + private void die() { + this.live = false; + } + + 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 Direction getDirection() { + return direction; + } + + public void setDirection(Direction direction) { + this.direction = direction; + } + + public boolean isLive() { + return live; + } + + public void setLive(boolean live) { + this.live = live; + } + + public Group getGroup() { + return group; + } + + public void setGroup(Group group) { + this.group = group; + } +} diff --git a/src/com/demo/tank/course8/DefaultFireStrategy.java b/src/com/demo/tank/course8/DefaultFireStrategy.java new file mode 100644 index 0000000..1ed8fab --- /dev/null +++ b/src/com/demo/tank/course8/DefaultFireStrategy.java @@ -0,0 +1,14 @@ +package com.demo.tank.course8; + +import com.demo.tank.enums.Group; +import com.demo.tank.util.Audio; + +public class DefaultFireStrategy implements FireStrategy { + @Override + public void fire(Tank tank) { + int bx = tank.getX() + Tank.WIDTH/2 - Bullet.WIDTH/2; + int by = tank.getY() + Tank.HEIGHT/2 - Bullet.HEIGHT/2; + new Bullet(bx, by, tank.getDir(), tank.getGroup(),tank.getGm()); + if (tank.getGroup() == Group.GOOD) new Thread(() -> new Audio("audio/tank_fire.wav").play()).start(); + } +} diff --git a/src/com/demo/tank/course8/Explode.java b/src/com/demo/tank/course8/Explode.java new file mode 100644 index 0000000..e662896 --- /dev/null +++ b/src/com/demo/tank/course8/Explode.java @@ -0,0 +1,47 @@ +package com.demo.tank.course8; + +import com.demo.tank.util.Audio; +import com.demo.tank.util.ResourceManager; + +import java.awt.*; + +public class Explode { + private int x, y; + public static final int WIDTH = ResourceManager.explodes[0].getWidth(); + public static final int HEIGHT = ResourceManager.explodes[0].getHeight(); + private GameModel gm; + + private int step = 0; + + public Explode(int x, int y, GameModel gm) { + this.x = x; + this.y = y; + this.gm = gm; + new Thread(() -> new Audio("audio/explode.wav").play()).start(); + } + + public void paint(Graphics g){ + g.drawImage(ResourceManager.explodes[step++], x, y, null); + if(step >= ResourceManager.explodes.length){ + //播放完爆炸效果图片, remove + gm.explodes.remove(this); + } + } + + 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; + } + +} diff --git a/src/com/demo/tank/course8/FireStrategy.java b/src/com/demo/tank/course8/FireStrategy.java new file mode 100644 index 0000000..cf97e75 --- /dev/null +++ b/src/com/demo/tank/course8/FireStrategy.java @@ -0,0 +1,5 @@ +package com.demo.tank.course8; + +public interface FireStrategy { + void fire(Tank tank); +} diff --git a/src/com/demo/tank/course8/FourDirectionFireStrategy.java b/src/com/demo/tank/course8/FourDirectionFireStrategy.java new file mode 100644 index 0000000..182ece2 --- /dev/null +++ b/src/com/demo/tank/course8/FourDirectionFireStrategy.java @@ -0,0 +1,17 @@ +package com.demo.tank.course8; + +import com.demo.tank.enums.Direction; +import com.demo.tank.enums.Group; +import com.demo.tank.util.Audio; + +public class FourDirectionFireStrategy implements FireStrategy { + @Override + public void fire(Tank tank) { + int bx = tank.getX() + Tank.WIDTH/2 - Bullet.WIDTH/2; + int by = tank.getY() + Tank.HEIGHT/2 - Bullet.HEIGHT/2; + for(Direction direction : Direction.values()){ + new Bullet(bx, by, direction, tank.getGroup(),tank.getGm()); + } + if (tank.getGroup() == Group.GOOD) new Thread(() -> new Audio("audio/tank_fire.wav").play()).start(); + } +} diff --git a/src/com/demo/tank/course8/GameModel.java b/src/com/demo/tank/course8/GameModel.java new file mode 100644 index 0000000..70b3380 --- /dev/null +++ b/src/com/demo/tank/course8/GameModel.java @@ -0,0 +1,66 @@ +package com.demo.tank.course8; + +import com.demo.tank.enums.Direction; +import com.demo.tank.enums.Group; +import com.demo.tank.util.PropertyManager; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class GameModel { + Tank tank = new Tank(380, 660, Direction.UP, Group.GOOD,this); + // Bullet bullet = new Bullet(520, 440, Direction.UP); + List bullets = new ArrayList(); + List enemyTanks = new ArrayList<>(); + + List explodes = new ArrayList<>(); + + public GameModel(){ + int enemyTankNum = PropertyManager.getInt("enemy.tank.number"); + for(int i = 0; i < enemyTankNum; i++){ + enemyTanks.add(new Tank(50 + i*80, 200, Direction.DOWN, Group.BAD, this)); + } + } + + public void paint(Graphics g){ + //打印出子弹数量 + Color color = g.getColor(); + g.setColor(Color.WHITE); + g.drawString("当前子弹数量:" + bullets.size(), 60, 50); + g.drawString("当前敌人数量:" + enemyTanks.size(), 60, 80); + g.drawString("当前爆炸数量:" + explodes.size(), 60, 100); + g.setColor(color); + + tank.paint(g); + + for(int i = 0; i< enemyTanks.size(); i++){ + enemyTanks.get(i).paint(g); + } + + for (int i = 0; i< bullets.size(); i++){ + bullets.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(Iterator it = bullets.iterator(); it.hasNext();){ +// Bullet b = it.next(); +// if(!b.isLive()){ +// it.remove(); +// } +// } +// +// for (Bullet b : bullets){ +// b.paint(g); +// } + } +} diff --git a/src/com/demo/tank/course8/MainV8.java b/src/com/demo/tank/course8/MainV8.java new file mode 100644 index 0000000..e08a2f4 --- /dev/null +++ b/src/com/demo/tank/course8/MainV8.java @@ -0,0 +1,20 @@ +package com.demo.tank.course8; + +import com.demo.tank.enums.Direction; +import com.demo.tank.enums.Group; +import com.demo.tank.util.PropertyManager; + +import java.io.IOException; + +public class MainV8 { + public static void main(String[] args) throws InterruptedException, IOException { + TankFrameV8 tf = new TankFrameV8(); + +// new Thread(() -> new Audio("audio/war1.wav").loop()).start(); + + while (true){ + Thread.sleep(50); + tf.repaint(); + } + } +} diff --git a/src/com/demo/tank/course8/Tank.java b/src/com/demo/tank/course8/Tank.java new file mode 100644 index 0000000..30d0533 --- /dev/null +++ b/src/com/demo/tank/course8/Tank.java @@ -0,0 +1,185 @@ +package com.demo.tank.course8; + +import com.demo.tank.enums.Direction; +import com.demo.tank.enums.Group; +import com.demo.tank.util.ResourceManager; + +import java.awt.*; +import java.util.Random; + +public class Tank { + private int x,y; + private Direction dir; + private static final int SPEED = 8; + private boolean moving = true; + private boolean living = true; + private Group group = Group.BAD; + GameModel gm = null; + public static final int WIDTH = ResourceManager.tankD.getWidth(); + public static final int HEIGHT = ResourceManager.tankD.getHeight(); + private Random random = new Random(); + Rectangle rect = new Rectangle(); + FireStrategy fireStrategy; + + + public Tank(int x, int y, Direction dir, Group group, GameModel gm) { + this.x = x; + this.y = y; + this.dir = dir; + this.group = group; + this.gm = gm; + + rect.x = this.x; + rect.y = this.y; + rect.width = Tank.WIDTH; + rect.height = Tank.HEIGHT; + + if(this.group == Group.GOOD) { +// String className = PropertyManager.getString("good.tank.fire.strategy"); + try { + fireStrategy = (FireStrategy) Class.forName("com.demo.tank.course8.FourDirectionFireStrategy").newInstance(); + System.out.println(fireStrategy); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + }else if(this.group == Group.BAD) fireStrategy = new DefaultFireStrategy(); + } + + public void paint(Graphics g) { + if(!living) gm.enemyTanks.remove(this); + //根据方向绘制坦克 + switch (dir){ + case UP: + g.drawImage(this.group == Group.GOOD ? ResourceManager.tankU : ResourceManager.badTankU, x, y, null); + break; + case DOWN: + g.drawImage(this.group == Group.GOOD ? ResourceManager.tankD : ResourceManager.badTankD, x, y, null); + break; + case LEFT: + g.drawImage(this.group == Group.GOOD ? ResourceManager.tankL: ResourceManager.badTankL, x, y, null); + break; + case RIGHT: + g.drawImage(this.group == Group.GOOD ? ResourceManager.tankR : ResourceManager.badTankR, x, y, null); + break; + } + move(); + } + + public void move(){ + //如果没有移动 return + if(!moving) return; + switch (dir){ + case UP: y -= SPEED; + break; + case DOWN: y += SPEED; + break; + case LEFT: x -= SPEED; + break; + case RIGHT: x += SPEED; + break; + default: + break; + } + if(this.group == Group.BAD) { + if(random.nextInt(10) == 5){ + this.fire(); + } + if(random.nextInt(100) > 95){ + this.randomDirection(); + } + } + + //边界检测 + boundsCheck(); + + rect.x = this.x; + rect.y = this.y; + } + + private void boundsCheck() { + if(x < 0) x = 0; + if(x > TankFrameV8.GAME_WIDTH - Tank.WIDTH) x = TankFrameV8.GAME_WIDTH - Tank.WIDTH; + if(y < 30) y = 30; //算上菜单条 + if(y > TankFrameV8.GAME_HEIGHT - Tank.HEIGHT) y = TankFrameV8.GAME_HEIGHT - Tank.HEIGHT; + } + + private void randomDirection() { + this.dir = Direction.values()[random.nextInt(4)]; + } + + public void fire() { + fireStrategy.fire(this); + } + + public void die(){ + this.living = false; + } + + 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 Direction getDir() { + return dir; + } + + public void setDir(Direction dir) { + this.dir = dir; + } + + public boolean isMoving() { + return moving; + } + + public void setMoving(boolean moving) { + this.moving = moving; + } + + public boolean isLiving() { + return living; + } + + public void setLiving(boolean living) { + this.living = living; + } + + public Group getGroup() { + return group; + } + + public void setGroup(Group group) { + this.group = group; + } + + public Rectangle getRect() { + return rect; + } + + public void setRect(Rectangle rect) { + this.rect = rect; + } + + public GameModel getGm() { + return gm; + } + + public void setGm(GameModel gm) { + this.gm = gm; + } +} diff --git a/src/com/demo/tank/course8/TankFrameV8.java b/src/com/demo/tank/course8/TankFrameV8.java new file mode 100644 index 0000000..6c0d73a --- /dev/null +++ b/src/com/demo/tank/course8/TankFrameV8.java @@ -0,0 +1,116 @@ +package com.demo.tank.course8; + +import com.demo.tank.enums.Direction; +import com.demo.tank.enums.Group; + +import java.awt.*; +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 TankFrameV8 extends Frame { + GameModel gm = new GameModel(); + public static final int GAME_WIDTH = 1080; + public static final int GAME_HEIGHT = 800; + Image image = null; + + public TankFrameV8(){ + setVisible(true); + setBounds(400, 100 , GAME_WIDTH, GAME_HEIGHT); + setResizable(false); + setTitle("tank war"); + this.addKeyListener(new MyKeyListener()); + this.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + System.exit(0); + } + }); + } + + @Override + public void update(Graphics g) { + if(image == null){ + image = this.createImage(GAME_WIDTH, GAME_HEIGHT); + } + Graphics imgGraphic = image.getGraphics(); + Color color = g.getColor(); + imgGraphic.setColor(Color.BLACK); + imgGraphic.fillRect(0,0, GAME_WIDTH, GAME_HEIGHT); + imgGraphic.setColor(color); + paint(imgGraphic); + g.drawImage(image, 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) { + switch (e.getKeyCode()){ + case KeyEvent.VK_A: + bL = true; + break; + case KeyEvent.VK_D: + bR = true; + break; + case KeyEvent.VK_W: + bU = true; + break; + case KeyEvent.VK_S: + bD = true; + break; + default: + break; + } + setTankDirection(); + } + + @Override + public void keyReleased(KeyEvent e) { + switch (e.getKeyCode()){ + case KeyEvent.VK_A: + bL = false; + break; + case KeyEvent.VK_D: + bR = false; + break; + case KeyEvent.VK_W: + bU = false; + break; + case KeyEvent.VK_S: + bD = false; + break; + case KeyEvent.VK_SPACE: + gm.tank.fire(); + break; + default: + break; + } + setTankDirection(); + } + + public void setTankDirection(){ + if(!bL && !bR && !bU && !bD){ + gm.tank.setMoving(false); + }else{ + gm.tank.setMoving(true); + if(bL) gm.tank.setDir(Direction.LEFT); + if(bR) gm.tank.setDir(Direction.RIGHT); + if(bU) gm.tank.setDir(Direction.UP); + if(bD) gm.tank.setDir(Direction.DOWN); + } + } + } +}