From eb89138e236c2f6c4adbca7df21b5945c42b692a Mon Sep 17 00:00:00 2001 From: terry <724796052@qq.com> Date: Thu, 30 Jun 2022 20:50:17 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=B9=9D=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/坦克大战笔记.docx | Bin 78631 -> 79769 bytes src/com/demo/tank/course8/Tank.java | 8 + .../demo/tank/course8/TankTankCollider.java | 4 +- src/com/demo/tank/course9/Bullet.java | 117 +++++++++++ .../demo/tank/course9/BulletTankCollider.java | 25 +++ .../demo/tank/course9/BulletWallCollider.java | 18 ++ src/com/demo/tank/course9/Collider.java | 5 + src/com/demo/tank/course9/ColliderChain.java | 25 +++ .../tank/course9/DefaultFireStrategy.java | 14 ++ src/com/demo/tank/course9/Explode.java | 45 +++++ src/com/demo/tank/course9/FireStrategy.java | 5 + .../course9/FourDirectionFireStrategy.java | 17 ++ src/com/demo/tank/course9/GameModel.java | 67 +++++++ src/com/demo/tank/course9/GameObject.java | 8 + src/com/demo/tank/course9/MainV9.java | 16 ++ src/com/demo/tank/course9/Tank.java | 184 ++++++++++++++++++ src/com/demo/tank/course9/TankFrameV9.java | 113 +++++++++++ .../demo/tank/course9/TankTankCollider.java | 21 ++ .../demo/tank/course9/TankWallCollider.java | 18 ++ src/com/demo/tank/course9/Wall.java | 24 +++ 20 files changed, 732 insertions(+), 2 deletions(-) create mode 100644 src/com/demo/tank/course9/Bullet.java create mode 100644 src/com/demo/tank/course9/BulletTankCollider.java create mode 100644 src/com/demo/tank/course9/BulletWallCollider.java create mode 100644 src/com/demo/tank/course9/Collider.java create mode 100644 src/com/demo/tank/course9/ColliderChain.java create mode 100644 src/com/demo/tank/course9/DefaultFireStrategy.java create mode 100644 src/com/demo/tank/course9/Explode.java create mode 100644 src/com/demo/tank/course9/FireStrategy.java create mode 100644 src/com/demo/tank/course9/FourDirectionFireStrategy.java create mode 100644 src/com/demo/tank/course9/GameModel.java create mode 100644 src/com/demo/tank/course9/GameObject.java create mode 100644 src/com/demo/tank/course9/MainV9.java create mode 100644 src/com/demo/tank/course9/Tank.java create mode 100644 src/com/demo/tank/course9/TankFrameV9.java create mode 100644 src/com/demo/tank/course9/TankTankCollider.java create mode 100644 src/com/demo/tank/course9/TankWallCollider.java create mode 100644 src/com/demo/tank/course9/Wall.java diff --git a/docs/坦克大战笔记.docx b/docs/坦克大战笔记.docx index e411e9b1ce0c287d2da71c6fcd55b34cf1eb9922..e0753c6a1ab40d6c359fc87d3b82dd8da9712bda 100644 GIT binary patch delta 16977 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 z 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 bMhnI}(|;N8Qk{?R}7+N)~s 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 diff --git a/src/com/demo/tank/course8/Tank.java b/src/com/demo/tank/course8/Tank.java index 9a4331b..7ecda1a 100644 --- a/src/com/demo/tank/course8/Tank.java +++ b/src/com/demo/tank/course8/Tank.java @@ -9,6 +9,7 @@ import java.util.Random; public class Tank extends GameObject{ private int x,y; + int oldX, oldY; private Direction dir; private static final int SPEED = 8; private boolean moving = true; @@ -70,6 +71,8 @@ public class Tank extends GameObject{ } public void move(){ + oldX = x; + oldY = y; //如果没有移动 return if(!moving) return; switch (dir){ @@ -100,6 +103,11 @@ public class Tank extends GameObject{ rect.y = this.y; } + public void back(){ + this.x = oldX; + this.y = oldY; + } + private void boundsCheck() { if(x < 0) x = 0; if(x > TankFrameV8.GAME_WIDTH - Tank.WIDTH) x = TankFrameV8.GAME_WIDTH - Tank.WIDTH; diff --git a/src/com/demo/tank/course8/TankTankCollider.java b/src/com/demo/tank/course8/TankTankCollider.java index 33682a8..64930ae 100644 --- a/src/com/demo/tank/course8/TankTankCollider.java +++ b/src/com/demo/tank/course8/TankTankCollider.java @@ -13,8 +13,8 @@ public class TankTankCollider implements Collider{ Tank t2 = (Tank) g2; if(t1.rect.intersects(t2.rect)){ // simple deal - t1.setDir(Direction.values()[random.nextInt(4)]); - t2.setDir(Direction.values()[random.nextInt(4)]); + t1.back(); + t2.back(); } }else{ return; diff --git a/src/com/demo/tank/course9/Bullet.java b/src/com/demo/tank/course9/Bullet.java new file mode 100644 index 0000000..902efe2 --- /dev/null +++ b/src/com/demo/tank/course9/Bullet.java @@ -0,0 +1,117 @@ +package com.demo.tank.course9; + +import com.demo.tank.enums.Direction; +import com.demo.tank.enums.Group; +import com.demo.tank.util.ResourceManager; + +import java.awt.*; + +public class Bullet extends GameObject { + 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; + Rectangle rect = new Rectangle(); + + public Bullet(int x, int y, Direction direction, Group group) { + this.x = x; + this.y = y; + this.direction = direction; + this.group = group; + + rect.x = this.x; + rect.y = this.y; + rect.width = Bullet.WIDTH; + rect.height = Bullet.HEIGHT; + GameModel.getInstance().add(this); + } + + public void paint(Graphics g){ + if(!live){ + GameModel.getInstance().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 > TankFrameV9.GAME_WIDTH || y > TankFrameV9.GAME_HEIGHT){ + live = false; + } + rect.x = this.x; + rect.y = this.y; + } + + public 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/course9/BulletTankCollider.java b/src/com/demo/tank/course9/BulletTankCollider.java new file mode 100644 index 0000000..d943f8f --- /dev/null +++ b/src/com/demo/tank/course9/BulletTankCollider.java @@ -0,0 +1,25 @@ +package com.demo.tank.course9; + +public class BulletTankCollider implements Collider { + @Override + public void collide(GameObject g1, GameObject g2) { + if(g1 instanceof Bullet && g2 instanceof Tank){ + Bullet b = (Bullet) g1; + Tank t = (Tank) g2; + //关闭队友伤害 + if(b.getGroup() == t.getGroup()) return; + if(b.rect.intersects(t.rect)){ + t.die(); + b.die(); + //爆炸 + int ex = t.getX() + Tank.WIDTH/2 - Explode.WIDTH/2; + int ey = t.getY() + Tank.HEIGHT/2 - Explode.HEIGHT/2; + GameModel.getInstance().add(new Explode(ex, ey)); + } + }else if(g1 instanceof Tank && g2 instanceof Bullet){ + collide(g2, g1); + }else{ + return; + } + } +} diff --git a/src/com/demo/tank/course9/BulletWallCollider.java b/src/com/demo/tank/course9/BulletWallCollider.java new file mode 100644 index 0000000..3071f20 --- /dev/null +++ b/src/com/demo/tank/course9/BulletWallCollider.java @@ -0,0 +1,18 @@ +package com.demo.tank.course9; + +public class BulletWallCollider implements Collider { + @Override + public void collide(GameObject g1, GameObject g2) { + if(g1 instanceof Bullet && g2 instanceof Wall){ + Bullet b = (Bullet) g1; + Wall w = (Wall) g2; + if(b.rect.intersects(w.rect)){ + b.die(); + } + }else if(g1 instanceof Wall && g2 instanceof Bullet){ + collide(g2, g1); + }else{ + return; + } + } +} diff --git a/src/com/demo/tank/course9/Collider.java b/src/com/demo/tank/course9/Collider.java new file mode 100644 index 0000000..7ab6d92 --- /dev/null +++ b/src/com/demo/tank/course9/Collider.java @@ -0,0 +1,5 @@ +package com.demo.tank.course9; + +public interface Collider { + void collide(GameObject g1, GameObject g2); +} diff --git a/src/com/demo/tank/course9/ColliderChain.java b/src/com/demo/tank/course9/ColliderChain.java new file mode 100644 index 0000000..3ed6a94 --- /dev/null +++ b/src/com/demo/tank/course9/ColliderChain.java @@ -0,0 +1,25 @@ +package com.demo.tank.course9; + +import java.util.LinkedList; +import java.util.List; + +public class ColliderChain { + private List colliders = new LinkedList<>(); + + public ColliderChain(){ + add(new BulletTankCollider()); + add(new TankTankCollider()); + add(new BulletWallCollider()); + add(new TankWallCollider()); + } + + public void add(Collider collider){ + colliders.add(collider); + } + + public void collide(GameObject g1, GameObject g2) { + for (Collider c : colliders){ + c.collide(g1, g2); + } + } +} diff --git a/src/com/demo/tank/course9/DefaultFireStrategy.java b/src/com/demo/tank/course9/DefaultFireStrategy.java new file mode 100644 index 0000000..ec2d86d --- /dev/null +++ b/src/com/demo/tank/course9/DefaultFireStrategy.java @@ -0,0 +1,14 @@ +package com.demo.tank.course9; + +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()); + if (tank.getGroup() == Group.GOOD) new Thread(() -> new Audio("audio/tank_fire.wav").play()).start(); + } +} diff --git a/src/com/demo/tank/course9/Explode.java b/src/com/demo/tank/course9/Explode.java new file mode 100644 index 0000000..3a8c16d --- /dev/null +++ b/src/com/demo/tank/course9/Explode.java @@ -0,0 +1,45 @@ +package com.demo.tank.course9; + +import com.demo.tank.util.Audio; +import com.demo.tank.util.ResourceManager; + +import java.awt.*; + +public class Explode extends GameObject { + private int x, y; + public static final int WIDTH = ResourceManager.explodes[0].getWidth(); + public static final int HEIGHT = ResourceManager.explodes[0].getHeight(); + + private int step = 0; + + public Explode(int x, int y) { + this.x = x; + this.y = y; + 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 + GameModel.getInstance().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/course9/FireStrategy.java b/src/com/demo/tank/course9/FireStrategy.java new file mode 100644 index 0000000..e2c0e41 --- /dev/null +++ b/src/com/demo/tank/course9/FireStrategy.java @@ -0,0 +1,5 @@ +package com.demo.tank.course9; + +public interface FireStrategy { + void fire(Tank tank); +} diff --git a/src/com/demo/tank/course9/FourDirectionFireStrategy.java b/src/com/demo/tank/course9/FourDirectionFireStrategy.java new file mode 100644 index 0000000..0b508d1 --- /dev/null +++ b/src/com/demo/tank/course9/FourDirectionFireStrategy.java @@ -0,0 +1,17 @@ +package com.demo.tank.course9; + +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()); + } + if (tank.getGroup() == Group.GOOD) new Thread(() -> new Audio("audio/tank_fire.wav").play()).start(); + } +} diff --git a/src/com/demo/tank/course9/GameModel.java b/src/com/demo/tank/course9/GameModel.java new file mode 100644 index 0000000..1e05609 --- /dev/null +++ b/src/com/demo/tank/course9/GameModel.java @@ -0,0 +1,67 @@ +package com.demo.tank.course9; + +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 { + private static final GameModel GM = new GameModel(); + static { + GM.init(); + } + + private List gameObjects = new ArrayList<>(); + +// Collider collider = new BulletTankCollider(); +// Collider collider2 = new TankTankCollider(); + ColliderChain chain = new ColliderChain(); + Tank tank; + + private GameModel(){ + + } + private void init(){ + tank = new Tank(380, 660, Direction.UP, Group.GOOD); + int enemyTankNum = PropertyManager.getInt("enemy.tank.number"); + for(int i = 0; i < enemyTankNum; i++){ + add(new Tank(50 + i*80, 200, Direction.DOWN, Group.BAD)); + } + add(new Wall(150, 150, 200, 50)); + add(new Wall(550, 150, 200, 50)); + add(new Wall(300, 300, 50, 200)); + add(new Wall(550, 300, 50, 200)); + } + + public static GameModel getInstance(){ + return GM; + } + + public void add(GameObject go){ + gameObjects.add(go); + } + + public void remove(GameObject go){ + gameObjects.remove(go); + } + + public void paint(Graphics g){ + tank.paint(g); + + for(int i = 0; i< gameObjects.size(); i++){ + gameObjects.get(i).paint(g); + } + + //碰撞检测 + for(int i = 0; i< gameObjects.size(); i++){ + for(int j=i+1; j< gameObjects.size(); j++){ + GameObject g1 = gameObjects.get(i); + GameObject g2 = gameObjects.get(j); + chain.collide(g1, g2); + } + } + } +} diff --git a/src/com/demo/tank/course9/GameObject.java b/src/com/demo/tank/course9/GameObject.java new file mode 100644 index 0000000..21dce58 --- /dev/null +++ b/src/com/demo/tank/course9/GameObject.java @@ -0,0 +1,8 @@ +package com.demo.tank.course9; + +import java.awt.*; + +public abstract class GameObject { + int x, y; + public abstract void paint(Graphics g); +} diff --git a/src/com/demo/tank/course9/MainV9.java b/src/com/demo/tank/course9/MainV9.java new file mode 100644 index 0000000..38064b2 --- /dev/null +++ b/src/com/demo/tank/course9/MainV9.java @@ -0,0 +1,16 @@ +package com.demo.tank.course9; + +import java.io.IOException; + +public class MainV9 { + public static void main(String[] args) throws InterruptedException, IOException { + TankFrameV9 tf = new TankFrameV9(); + +// new Thread(() -> new Audio("audio/war1.wav").loop()).start(); + + while (true){ + Thread.sleep(50); + tf.repaint(); + } + } +} diff --git a/src/com/demo/tank/course9/Tank.java b/src/com/demo/tank/course9/Tank.java new file mode 100644 index 0000000..2e36d22 --- /dev/null +++ b/src/com/demo/tank/course9/Tank.java @@ -0,0 +1,184 @@ +package com.demo.tank.course9; + +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 extends GameObject { + private int x,y; + int oldX, oldY; + private Direction dir; + private static final int SPEED = 8; + private boolean moving = true; + private boolean living = true; + private Group group = Group.BAD; + 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) { + this.x = x; + this.y = y; + this.dir = dir; + this.group = group; + + 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.course9.FourDirectionFireStrategy").newInstance(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + }else if(this.group == Group.BAD) fireStrategy = new DefaultFireStrategy(); + } + + @Override + public void paint(Graphics g) { + if(!living) GameModel.getInstance().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(){ + oldX = x; + oldY = y; + //如果没有移动 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; + } + + public void back(){ + this.x = oldX; + this.y = oldY; + } + + private void boundsCheck() { + if(x < 0) x = 0; + if(x > TankFrameV9.GAME_WIDTH - Tank.WIDTH) x = TankFrameV9.GAME_WIDTH - Tank.WIDTH; + if(y < 30) y = 30; //算上菜单条 + if(y > TankFrameV9.GAME_HEIGHT - Tank.HEIGHT) y = TankFrameV9.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; + } + +} diff --git a/src/com/demo/tank/course9/TankFrameV9.java b/src/com/demo/tank/course9/TankFrameV9.java new file mode 100644 index 0000000..29ec300 --- /dev/null +++ b/src/com/demo/tank/course9/TankFrameV9.java @@ -0,0 +1,113 @@ +package com.demo.tank.course9; + +import com.demo.tank.enums.Direction; + +import java.awt.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +public class TankFrameV9 extends Frame { + GameModel gm = GameModel.getInstance(); + public static final int GAME_WIDTH = 1080; + public static final int GAME_HEIGHT = 800; + Image image = null; + + public TankFrameV9(){ + 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); + } + } + } +} diff --git a/src/com/demo/tank/course9/TankTankCollider.java b/src/com/demo/tank/course9/TankTankCollider.java new file mode 100644 index 0000000..310016a --- /dev/null +++ b/src/com/demo/tank/course9/TankTankCollider.java @@ -0,0 +1,21 @@ +package com.demo.tank.course9; + +import java.util.Random; + +public class TankTankCollider implements Collider { + Random random = new Random(); + @Override + public void collide(GameObject g1, GameObject g2) { + if(g1 instanceof Tank && g2 instanceof Tank){ + Tank t1 = (Tank) g1; + Tank t2 = (Tank) g2; + if(t1.rect.intersects(t2.rect)){ + // simple deal + t1.back(); + t2.back(); + } + }else{ + return; + } + } +} diff --git a/src/com/demo/tank/course9/TankWallCollider.java b/src/com/demo/tank/course9/TankWallCollider.java new file mode 100644 index 0000000..773713d --- /dev/null +++ b/src/com/demo/tank/course9/TankWallCollider.java @@ -0,0 +1,18 @@ +package com.demo.tank.course9; + +public class TankWallCollider implements Collider{ + @Override + public void collide(GameObject g1, GameObject g2) { + if(g1 instanceof Tank && g2 instanceof Wall){ + Tank t = (Tank) g1; + Wall w = (Wall) g2; + if(t.rect.intersects(w.rect)){ + t.back(); + } + }else if(g1 instanceof Wall && g2 instanceof Bullet){ + collide(g2, g1); + }else{ + return; + } + } +} diff --git a/src/com/demo/tank/course9/Wall.java b/src/com/demo/tank/course9/Wall.java new file mode 100644 index 0000000..60910db --- /dev/null +++ b/src/com/demo/tank/course9/Wall.java @@ -0,0 +1,24 @@ +package com.demo.tank.course9; + +import java.awt.*; + +public class Wall extends GameObject{ + int width, height; + Rectangle rect; + + public Wall(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.rect = new Rectangle(x, y, width, height); + } + + @Override + public void paint(Graphics g) { + Color c = g.getColor(); + g.setColor(Color.DARK_GRAY); + g.fillRect(x, y, width, height); + g.setColor(c); + } +}