├── gif ├── demo1.gif └── demo2.gif ├── src ├── images │ ├── blood.png │ ├── box.png │ ├── ghost.png │ ├── hero.png │ ├── wall.png │ ├── double.jpg │ ├── monster.png │ ├── single.jpg │ ├── fireball.png │ ├── gameover.png │ └── ghostball.png └── Game │ ├── Main.java │ ├── Ghostball.java │ ├── Fireball.java │ ├── Wall.java │ ├── Sword.java │ ├── Hand.java │ ├── Blood.java │ ├── Border.java │ ├── Ghost.java │ ├── Monster.java │ ├── Direction.java │ ├── PathNode.java │ ├── Box.java │ ├── Start.java │ ├── GameClient.java │ ├── Ball.java │ ├── Weapon.java │ ├── Hero.java │ ├── WorldGrids.java │ ├── Enemy.java │ ├── GameObject.java │ ├── Role.java │ ├── World.java │ └── Pathfinder.java └── README.md /gif/demo1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hpasserby/ZombieCrisis/HEAD/gif/demo1.gif -------------------------------------------------------------------------------- /gif/demo2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hpasserby/ZombieCrisis/HEAD/gif/demo2.gif -------------------------------------------------------------------------------- /src/images/blood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hpasserby/ZombieCrisis/HEAD/src/images/blood.png -------------------------------------------------------------------------------- /src/images/box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hpasserby/ZombieCrisis/HEAD/src/images/box.png -------------------------------------------------------------------------------- /src/images/ghost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hpasserby/ZombieCrisis/HEAD/src/images/ghost.png -------------------------------------------------------------------------------- /src/images/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hpasserby/ZombieCrisis/HEAD/src/images/hero.png -------------------------------------------------------------------------------- /src/images/wall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hpasserby/ZombieCrisis/HEAD/src/images/wall.png -------------------------------------------------------------------------------- /src/images/double.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hpasserby/ZombieCrisis/HEAD/src/images/double.jpg -------------------------------------------------------------------------------- /src/images/monster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hpasserby/ZombieCrisis/HEAD/src/images/monster.png -------------------------------------------------------------------------------- /src/images/single.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hpasserby/ZombieCrisis/HEAD/src/images/single.jpg -------------------------------------------------------------------------------- /src/images/fireball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hpasserby/ZombieCrisis/HEAD/src/images/fireball.png -------------------------------------------------------------------------------- /src/images/gameover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hpasserby/ZombieCrisis/HEAD/src/images/gameover.png -------------------------------------------------------------------------------- /src/images/ghostball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hpasserby/ZombieCrisis/HEAD/src/images/ghostball.png -------------------------------------------------------------------------------- /src/Game/Main.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | public class Main { 4 | public static void main(String[] args) { 5 | new Start(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZombieCrisis 2 | JAVA 射击生存类小游戏 3 | 4 | 操作说明: 5 | 1P: WASD + J(攻击) + K(切换武器) + L(大招) 6 | 2P: 上下左右 + 1(攻击) + 2(切换武器) + 3(大招) 7 | 8 | 效果演示: 9 | ![demo1](./gif/demo1.gif) 10 | 11 | ![demo2](./gif/demo2.gif) 12 | -------------------------------------------------------------------------------- /src/Game/Ghostball.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | public class Ghostball extends Ball { 4 | public Ghostball(Role role, World world) { 5 | super("Ghostball", 7, 8, 80, 30, role, world); 6 | this.setNum(10000); 7 | this.picOffset = 8; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Game/Fireball.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | public class Fireball extends Ball { 4 | int maxNum = 80; 5 | public Fireball(Role role, World world) { 6 | super("Fireball", 15, 15, 55, 10, role, world); 7 | setNum(maxNum); 8 | this.picOffset = 16; 9 | } 10 | 11 | public int getMaxNum() { 12 | return maxNum; 13 | } 14 | } 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Game/Wall.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.awt.*; 4 | 5 | public class Wall extends GameObject{ 6 | 7 | public Wall(int x, int y, World world) { 8 | super("Wall", 50, 0, 99999, x, y, true, world); 9 | } 10 | 11 | public void draw(Graphics g){ 12 | g.drawImage(imgMap.get(name), x - 50, y - 75, 100, 150, null); 13 | } 14 | public void collisionResponse(GameObject object){ 15 | 16 | } 17 | public void onAttack(Weapon weapon){ 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Game/Sword.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.util.Iterator; 4 | 5 | public class Sword extends Weapon{ 6 | 7 | public Sword(Role role, World world){ 8 | super("Sword", 0, 15, 80, 12, role, 80, 42, false, world); 9 | } 10 | 11 | public void Attack(){ 12 | super.Attack(); 13 | } 14 | 15 | public int getX(){ 16 | return this.host.getX(); 17 | } 18 | 19 | public int getY(){ 20 | return this.host.getY(); 21 | } 22 | 23 | public int getAttackRange() { 24 | return attackRange; 25 | } 26 | 27 | public void setAttackRange(int attackRange) { 28 | this.attackRange = attackRange; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Game/Hand.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.util.Iterator; 4 | 5 | public class Hand extends Weapon{ 6 | private int attackRange; 7 | 8 | public Hand(Role role, World world){ 9 | super("Hand", 0, 15, 60,12, role, 55, 70, false, world); 10 | } 11 | 12 | public void Attack(){ 13 | super.Attack(); 14 | } 15 | 16 | public int getX(){ 17 | return this.host.getX(); 18 | } 19 | 20 | public int getY(){ 21 | return this.host.getY(); 22 | } 23 | 24 | public int getAttackRange() { 25 | return attackRange; 26 | } 27 | 28 | public void setAttackRange(int attackRange) { 29 | this.attackRange = attackRange; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Game/Blood.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.awt.*; 4 | import java.util.Random; 5 | 6 | public class Blood extends GameObject{ 7 | private int picX; 8 | private int picY; 9 | 10 | public Blood(int x, int y, World world) { 11 | super("Blood", 0, 0, 99999, x, y, false, world); 12 | Random rand = new Random(); 13 | int picX = Math.abs(rand.nextInt()) % 2; 14 | int picY = Math.abs(rand.nextInt()) % 2; 15 | this.picX = picX * 475; 16 | this.picY = picY * 475; 17 | } 18 | 19 | public void draw(Graphics g){ 20 | 21 | g.drawImage(imgMap.get(name), x- 30, y, x + 30, y + 45, picX, picY, picX + 475, picY + 475, null); 22 | // g.drawImage(imgMap.get(name)) 23 | } 24 | public void collisionResponse(GameObject object){ 25 | 26 | } 27 | public void onAttack(Weapon weapon){ 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Game/Border.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.awt.*; 4 | 5 | public class Border extends GameObject { 6 | private int position; 7 | 8 | public Border(int position, World world){ 9 | super("Border", 100000000, 0, 100000000,0, 0, true, world); 10 | switch(position){ 11 | case 0: 12 | this.x = 0; 13 | this.y = -100000000 + Role.PICOFFSET + 10; 14 | break; 15 | case 1: 16 | this.x = 0; 17 | this.y = 100000000 + world.getHeight() - Role.PICOFFSET; 18 | break; 19 | case 2: 20 | this.x = -100000000 + 10; 21 | this.y = 0; 22 | break; 23 | case 3: 24 | this.x = 100000000 + world.getWidth() - 10; 25 | this.y = 0; 26 | break; 27 | } 28 | } 29 | 30 | public void draw(Graphics g){ 31 | g.drawArc(this.x,this.y, 100000000, 100000000, 0, 360); 32 | } 33 | 34 | public void collisionResponse(GameObject object){ 35 | return; 36 | } 37 | 38 | public void onAttack(Weapon weapon){ } 39 | } 40 | -------------------------------------------------------------------------------- /src/Game/Ghost.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.awt.*; 4 | 5 | public class Ghost extends Enemy { 6 | private int attackRange = 300; 7 | 8 | public Ghost(int x, int y, World world){ 9 | super("Ghost", 130, 14, 2, x, y, world); 10 | addWeapon(new Ghostball(this, world)); 11 | setCurrentWeapon(getWeapons().get(0)); 12 | } 13 | 14 | public void draw(Graphics g) { 15 | if(getTarget() != null && getTarget().getHP() > 0 && this.getHP() > 0) { 16 | int distance = (int) getDistance(this.getX(), this.getY(), getCurrentTarget().getX(), getCurrentTarget().getY()); 17 | if (distance <= attackRange && this.getCurrentWeapon().getColdDown() == 0) { 18 | double currentDegree = Direction.toDegree(this.dir == Direction.STOP ? oldDir : dir); 19 | double targetDegree = getDeltaDegree(getTarget().getX(), getTarget().getY()); 20 | if(Math.abs(targetDegree - currentDegree) < 60 || Math.abs(360 - targetDegree + currentDegree) < 60) { 21 | this.getCurrentWeapon().setState(); 22 | this.getCurrentWeapon().setColdDown(); 23 | getPath(); 24 | } 25 | } 26 | } 27 | locateDirection(); 28 | super.draw(g); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Game/Monster.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.awt.*; 4 | import java.lang.annotation.Target; 5 | 6 | public class Monster extends Enemy { 7 | 8 | public Monster(int x, int y, World world){ 9 | super("Monster", 170, 14, 2, x, y, world); 10 | addWeapon(new Hand(this, world)); 11 | setCurrentWeapon(getWeapons().get(0)); 12 | getCurrentWeapon().setDamage(100); 13 | getCurrentWeapon().setColdDownTime(24); 14 | ((Hand)getCurrentWeapon()).setAttackRange(50); 15 | } 16 | 17 | public void draw(Graphics g) { 18 | if(getTarget() != null && getTarget().getHP() > 0) { 19 | int distance = (int) getDistance(this.getX(), this.getY(), getCurrentTarget().getX(), getCurrentTarget().getY()); 20 | if (distance <= ((Hand) getCurrentWeapon()).getAttackRange() && this.getCurrentWeapon().getColdDown() == 0) { 21 | Direction dir = judgeAccurateDir(getTarget().getX(), getTarget().getY()); 22 | this.dir = dir; 23 | this.oldDir = (dir == Direction.STOP ? oldDir : dir); 24 | this.getCurrentWeapon().setState(); 25 | this.getCurrentWeapon().setColdDown(); 26 | getPath(); 27 | } 28 | } 29 | locateDirection(); 30 | super.draw(g); 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/Game/Direction.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | public enum Direction { 4 | LD, RU, LU, RD, L, R, U, D, STOP; 5 | 6 | public static double toDegree(Direction dir){ 7 | switch (dir){ 8 | case R: return 0; 9 | case RU: return 45; 10 | case U: return 90; 11 | case LU: return 135; 12 | case L: return 180; 13 | case LD: return 225; 14 | case D: return 270; 15 | case RD: return 315; 16 | default: return 360; 17 | } 18 | } 19 | 20 | public static double getVectorX(Direction dir){ 21 | switch (dir){ 22 | case R: return 1; 23 | case RU: return Math.cos(Math.toRadians(45)); 24 | case U: return 0; 25 | case LU: return -Math.cos(Math.toRadians(45)); 26 | case L: return -1; 27 | case LD: return -Math.cos(Math.toRadians(45)); 28 | case D: return 0; 29 | case RD: return Math.cos(Math.toRadians(45)); 30 | default: return -2; 31 | } 32 | } 33 | 34 | public static double getVectorY(Direction dir){ 35 | switch (dir){ 36 | case R: return 0; 37 | case RU: return Math.cos(Math.toRadians(45)); 38 | case U: return 1; 39 | case LU: return Math.cos(Math.toRadians(45)); 40 | case L: return 0; 41 | case LD: return -Math.cos(Math.toRadians(45)); 42 | case D: return -1; 43 | case RD: return -Math.cos(Math.toRadians(45)); 44 | default: return -2; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Game/PathNode.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | public class PathNode implements Comparable{ 4 | private Grid stateData; 5 | private PathNode parentNode; 6 | private int g, h, f, depth; //g 从起点移动到指定方格的移动代价, h 从指定的方格移动到终点的估算成本 7 | 8 | public PathNode getParentNode() { 9 | return parentNode; 10 | } 11 | 12 | public void setParentNode(PathNode parentNode) { 13 | this.parentNode = parentNode; 14 | } 15 | 16 | public int getG() { 17 | return g; 18 | } 19 | 20 | public void setG(int g) { 21 | this.g = g; 22 | } 23 | 24 | public int getH() { 25 | return h; 26 | } 27 | 28 | public void setH(int h) { 29 | this.h = h; 30 | } 31 | 32 | public int getF() { 33 | return f; 34 | } 35 | 36 | public void setF(int f) { 37 | this.f = f; 38 | } 39 | 40 | public int getDepth() { 41 | return depth; 42 | } 43 | 44 | public void setDepth(int depth) { 45 | this.depth = depth; 46 | } 47 | 48 | public Grid getStateData() { 49 | return stateData; 50 | } 51 | 52 | public void setStateData(Grid stateData) { 53 | this.stateData = stateData; 54 | } 55 | 56 | public PathNode(Grid stateData, PathNode parentNode, int g, int h, int depth) { 57 | this.stateData = stateData; 58 | this.parentNode = parentNode; 59 | this.g = g; 60 | this.h = h; 61 | this.f = this.g + this.h; 62 | this.depth = depth; 63 | } 64 | 65 | @Override 66 | public int compareTo(PathNode other) 67 | { 68 | int NodeComp = (this.f - other.getF()) * -1; 69 | if (NodeComp == 0) 70 | { 71 | NodeComp = (this.depth - other.getDepth()); 72 | } 73 | return NodeComp; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Game/Box.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.awt.*; 4 | import java.util.Random; 5 | 6 | public class Box extends GameObject{ 7 | public static final int DELAYTIME = 800; 8 | private int delay = 0; 9 | 10 | public Box(int x, int y, World world) { 11 | super("Box", 14, 0, 99999, x, y, false, world); 12 | } 13 | 14 | public void draw(Graphics g){ 15 | world.collisionDetection(this); 16 | g.drawImage(imgMap.get(name), x - 20, y - 10, 60, 60, null); 17 | } 18 | public void collisionResponse(GameObject object){ 19 | if(object instanceof Hero) { 20 | Random rand = new Random(); 21 | int n = Math.abs(rand.nextInt()) % 100; 22 | if(n < 45) 23 | fireballBox((Hero) object); 24 | else if(n < 90) 25 | bloodBox((Hero) object); 26 | // System.out.println(n); 27 | world.pickUpBox(this); 28 | setDelay(DELAYTIME); 29 | } 30 | } 31 | 32 | public void setDelay(int delay){ 33 | this.delay = delay; 34 | } 35 | 36 | public int getDelay() { 37 | return delay; 38 | } 39 | 40 | public void onAttack(Weapon weapon){ 41 | } 42 | 43 | public void fireballBox(Hero hero) { 44 | for (Weapon weapon : hero.getWeapons()) 45 | if (weapon instanceof Fireball) { 46 | ((Fireball) weapon).setNum(((Fireball) weapon).getMaxNum()); 47 | break; 48 | } 49 | } 50 | 51 | public void bloodBox(Hero hero) { 52 | hero.setHP(Hero.MAX_HP); 53 | } 54 | 55 | public boolean collisionDetection(GameObject object){ 56 | if(!(object instanceof Hero)) return false; 57 | double deltaX = this.x - object.getX(); 58 | double deltaY = (this.y - object.getY()); 59 | double d = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); 60 | int R = this.getRadius() + object.getRadius(); 61 | if(d <= R) return true; 62 | return false; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Game/Start.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | import java.awt.event.*; 6 | 7 | 8 | public class Start extends JFrame{ 9 | public static final int WIDTH = 400; 10 | public static final int HEIGHT = 350; 11 | private boolean flag; 12 | 13 | class SinglePlayerListener implements ActionListener { 14 | @Override 15 | public void actionPerformed(ActionEvent e) { 16 | new GameClient(false).lauchFrame(); 17 | setVisible(false); 18 | } 19 | } 20 | 21 | class DoublePlayerListener implements ActionListener { 22 | @Override 23 | public void actionPerformed(ActionEvent e) { 24 | new GameClient(true).lauchFrame(); 25 | setVisible(false); 26 | } 27 | } 28 | 29 | class WindowDestroyer extends WindowAdapter{ 30 | public void windowClosing(WindowEvent e){ 31 | 32 | } 33 | } 34 | 35 | 36 | public Start(){ 37 | setSize(WIDTH, HEIGHT); 38 | setResizable(false); 39 | setLocationRelativeTo(null); 40 | addWindowListener(new WindowDestroyer()); 41 | setTitle("Zombie Crsis"); 42 | Container contentPane = getContentPane(); 43 | contentPane.setBackground(Color.LIGHT_GRAY); 44 | 45 | 46 | JPanel buttonPanel = new JPanel(); 47 | buttonPanel.setBackground(Color.WHITE); 48 | 49 | contentPane.setLayout(new FlowLayout()); 50 | 51 | ImageIcon singleIcon = new ImageIcon(Start.class.getResource("/images/single.jpg")); 52 | singleIcon.setImage(singleIcon.getImage().getScaledInstance(380,140,Image.SCALE_DEFAULT)); 53 | JButton singleButton = new JButton(singleIcon); 54 | singleButton.setIcon(singleIcon); 55 | singleButton.addActionListener(new SinglePlayerListener()); 56 | contentPane.add(singleButton); 57 | 58 | 59 | ImageIcon doubleIcon = new ImageIcon(Start.class.getResource("/images/double.jpg")); 60 | doubleIcon.setImage(doubleIcon.getImage().getScaledInstance(380,140,Image.SCALE_DEFAULT)); 61 | JButton doubleButton = new JButton(doubleIcon); 62 | doubleButton.setIcon(doubleIcon); 63 | doubleButton.addActionListener(new DoublePlayerListener()); 64 | contentPane.add(doubleButton); 65 | 66 | setVisible(true); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Game/GameClient.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | import java.awt.event.WindowAdapter; 6 | import java.awt.event.WindowEvent; 7 | import java.awt.event.KeyAdapter; 8 | import java.awt.event.KeyEvent; 9 | 10 | public class GameClient extends Frame { 11 | public static final int WORLD_WIDTH = 960; 12 | public static final int WORLD_HEIGHT = 720; 13 | private Image offScreenImage; 14 | private World world; 15 | 16 | public GameClient(boolean Doubleplayer){ 17 | this.world = new World(WORLD_WIDTH, WORLD_HEIGHT, Doubleplayer); 18 | offScreenImage = null; 19 | } 20 | 21 | private class PaintThread implements Runnable { 22 | public void run() { 23 | while(true) { 24 | repaint(); //璋冪敤鐨勫閮ㄧ被鐨刾aint()鏂规硶锛� repaint()棣栧厛璋冪敤update()鏂规硶锛屽啀璋冪敤paint()鏂规硶 25 | try { 26 | Thread.sleep(30); 27 | } catch (InterruptedException e) { 28 | e.printStackTrace(); 29 | } 30 | } 31 | } 32 | } 33 | 34 | public void paint(Graphics g) { 35 | if(!world.End()) 36 | world.drawWorld(g); 37 | else { 38 | world.drawEnd(g); 39 | } 40 | } 41 | 42 | public void update(Graphics g) { 43 | if(offScreenImage == null) { 44 | offScreenImage = this.createImage(WORLD_WIDTH, WORLD_HEIGHT); //鍒涘缓鍥剧墖 45 | } 46 | Graphics gOffScreen = offScreenImage.getGraphics(); 47 | Color c = gOffScreen.getColor(); 48 | gOffScreen.setColor(Color.lightGray); 49 | gOffScreen.fillRect(0, 0, WORLD_WIDTH, WORLD_HEIGHT); 50 | gOffScreen.setColor(c); 51 | paint(gOffScreen); 52 | g.drawImage(offScreenImage, 0, 0, null); 53 | } 54 | 55 | public void lauchFrame() { 56 | this.setLocation(400, 100); 57 | this.setSize(WORLD_WIDTH, WORLD_HEIGHT); 58 | this.setTitle("ZombieCrisis"); 59 | this.addWindowListener(new WindowAdapter() { 60 | public void windowClosing(WindowEvent e) { 61 | System.exit(0); 62 | } 63 | }); 64 | this.setResizable(false); //鍙皟鏁村ぇ灏� 65 | this.setBackground(Color.lightGray); 66 | this.addKeyListener(new KeyMonitor((Hero) world.getObject(0))); 67 | if(world.getObject(1) instanceof Hero) 68 | this.addKeyListener(new KeyMonitor((Hero) world.getObject(1))); 69 | setVisible(true); 70 | new Thread(new PaintThread()).start(); 71 | } 72 | 73 | private class KeyMonitor extends KeyAdapter { 74 | Hero hero; 75 | public KeyMonitor(Hero hero){ 76 | this.hero = hero; 77 | } 78 | public void keyReleased(KeyEvent e) { 79 | this.hero.keyReleased(e); 80 | } 81 | public void keyPressed(KeyEvent e) { 82 | this.hero.KeyPressed(e); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Game/Ball.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.awt.*; 4 | 5 | public class Ball extends Weapon implements Cloneable{ 6 | private final int attackRange = 40; 7 | private boolean ultimateState; 8 | private int num; 9 | protected int picOffset; 10 | private int[] imgOrder = {4,7,5,6,1,2,3,0}; 11 | 12 | public Ball(String name, int radius, int speed, int damage, int coldDownTime, Role role, World world){ 13 | super(name, radius, speed, damage, coldDownTime, role, 300, 360,true, world); 14 | } 15 | 16 | public void initFireball(Direction dir){ 17 | if(this.num <= 0) return; 18 | this.setDir(dir); 19 | double cosA = (Math.cos(Math.toRadians(Direction.toDegree(dir)))); 20 | double sinA = -(Math.sin(Math.toRadians(Direction.toDegree(dir)))); 21 | this.x = (int)(this.host.getX() + this.host.getRadius() * cosA); 22 | this.y = (int)(this.host.getY() + this.host.getRadius() * sinA); 23 | this.xIncrement = (int)(this.speed * cosA); 24 | this.yIncrement = (int)(this.speed * sinA); 25 | world.addObject((Ball) this.clone()); 26 | this.num--; 27 | } 28 | 29 | public int getNum() { 30 | return num; 31 | } 32 | 33 | public void setNum(int num) { 34 | this.num = num; 35 | } 36 | 37 | public void Attack(){ 38 | } 39 | 40 | @Override 41 | public boolean collisionDetection(GameObject object) { 42 | return ((!object.equals(this.host)) && !(object instanceof Weapon) && super.collisionDetection(object)); 43 | } 44 | 45 | public void draw(Graphics g){ 46 | int picY = imgOrder[dir == Direction.STOP ? oldDir.ordinal() : dir.ordinal()]; 47 | int picX = maintainState(3); 48 | this.x += xIncrement; 49 | this.y += yIncrement; 50 | drawOneImage(g, this.name, getPicOffset(), this.x, this.y, picX, picY); 51 | world.collisionDetection(this); 52 | } 53 | 54 | public void setState(){ 55 | initFireball(this.host.getDir() == Direction.STOP ? host.getOldDir() : host.getDir()); 56 | super.setState(); 57 | } 58 | 59 | public void setUltimateState(){ 60 | if(getNum() < 8) return; 61 | for(Direction dir : Direction.values()){ 62 | if(dir == Direction.STOP) continue; 63 | initFireball(dir); 64 | } 65 | super.setState(); 66 | } 67 | 68 | public int maintainState(int n){ 69 | this.state++; 70 | if(state >= n) { 71 | state = 0; 72 | } 73 | return state; 74 | } 75 | 76 | public void collisionResponse(GameObject object){ 77 | world.removeObject(this); 78 | resetState(); 79 | object.onAttack(this); 80 | } 81 | 82 | public int getPicOffset(){ 83 | return picOffset; 84 | } 85 | 86 | @Override 87 | public String toString(){ 88 | String strBuf = name; 89 | strBuf += ":"; 90 | strBuf += String.valueOf(getNum()); 91 | return strBuf; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Game/Weapon.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.awt.*; 4 | import java.util.Iterator; 5 | 6 | public abstract class Weapon extends GameObject { 7 | protected int state; 8 | protected Role host; 9 | protected int coldDownTime; 10 | protected int coldDown; 11 | protected int damage; 12 | protected int attackRange; 13 | protected int attackAngle; 14 | 15 | 16 | public Weapon(String name, int radius, int speed, int damage, int coldDownTime, Role host, int attackRange,int attackAngle, boolean collidable, World world) { 17 | super(name, radius, speed, host.getDir(), 9999, host.x, host.y, collidable, world); 18 | this.damage = damage; 19 | this.coldDownTime = coldDownTime; 20 | this.coldDown = 0; 21 | this.host = host; 22 | this.attackRange = attackRange; 23 | this.attackAngle = attackAngle; 24 | state = -1; 25 | } 26 | 27 | public void setDamage(int damage) { 28 | this.damage = damage; 29 | } 30 | 31 | public int drawNomalAttack(Graphics g){ 32 | if(state < 0) return state; 33 | int lastState = state; 34 | int picX = getState() / 3 + 5; 35 | int picY = (host.getDir() == Direction.STOP ? host.getOldDir() : host.getDir()).ordinal(); 36 | drawOneImage(g, host.name, Role.PICOFFSET, host.x, host.y, picX, picY); 37 | maintainState(9); 38 | return lastState; 39 | } 40 | 41 | public void Attack(){ 42 | Iterator iter = world.getObjectsIterator(); 43 | while(iter.hasNext()){ 44 | GameObject object = iter.next(); 45 | if(this.host.equals(object)) continue; 46 | if(this.host instanceof Enemy && object instanceof Enemy) continue; 47 | int objX = object.getX(); 48 | int objY = object.getY(); 49 | int deltaX = objX - this.getX(); 50 | int deltaY = - objY + this.getY(); 51 | double D = getDistance(objX, objY, this.getX(),this.getY()); 52 | if(D < getAttackRange()){ 53 | double sinA = deltaY / D; 54 | double cosA = deltaX / D; 55 | double angle1 = Math.toDegrees(Math.asin(sinA)); 56 | double angle2 = Math.toDegrees(Math.acos(cosA)); 57 | double angle = angle2; 58 | if(angle1 < 0) angle = 360 - angle; 59 | double myangle = Direction.toDegree(this.host.getDir()); 60 | if(myangle == 360) myangle = Direction.toDegree(this.host.getOldDir()); 61 | if(Math.abs(myangle - angle) < attackAngle || 360 - Math.abs(myangle - angle) < attackAngle) 62 | object.onAttack(this); 63 | } 64 | } 65 | } 66 | 67 | public int getAttackRange() { 68 | return attackRange; 69 | } 70 | 71 | public int maintainState(int n){ 72 | this.state++; 73 | if(state >= n) { 74 | state = -1; 75 | } 76 | return state; 77 | } 78 | 79 | public int maintainColdDown(){ 80 | if(coldDown > 0) 81 | coldDown--; 82 | return coldDown; 83 | } 84 | 85 | public void setColdDownTime(int coldDownTime) { 86 | this.coldDownTime = coldDownTime; 87 | } 88 | 89 | public void setColdDown(){ 90 | coldDown = coldDownTime; 91 | } 92 | 93 | public int getColdDown() { 94 | return coldDown; 95 | } 96 | 97 | public void onAttack(Weapon weapon){ } 98 | 99 | public void draw(Graphics g){ 100 | } 101 | 102 | public void collisionResponse(GameObject object){ 103 | } 104 | 105 | public int getDamage(){ 106 | return this.damage; 107 | } 108 | 109 | public int getState(){ 110 | return this.state; 111 | } 112 | 113 | public void setState(){ 114 | this.state = 0; 115 | } 116 | 117 | public void resetState(){ 118 | this.state = -1; 119 | } 120 | 121 | public boolean isHost(Role role){ 122 | if(this.host.equals(role)){ 123 | return true; 124 | } 125 | return false; 126 | } 127 | 128 | @Override 129 | public String toString() { 130 | return this.name; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/Game/Hero.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.awt.*; 4 | import java.awt.event.KeyEvent; 5 | import java.util.Random; 6 | 7 | public class Hero extends Role { 8 | public static final int MAX_HP = 1200; 9 | private int[] keys; 10 | private boolean bL=false, bU=false, bR=false, bD=false; //閿洏鏂瑰悜閿� 11 | 12 | public Hero(int x, int y, int keyGroup, World world) { 13 | super("Hero", MAX_HP,14, 5, x, y, world); 14 | addWeapon(new Sword(this, world)); 15 | addWeapon(new Fireball(this, world)); 16 | setCurrentWeapon(getWeapons().get(0)); 17 | keys = new int[7]; 18 | if(keyGroup == 0){ 19 | keys[0] = KeyEvent.VK_LEFT; 20 | keys[1] = KeyEvent.VK_UP; 21 | keys[2] = KeyEvent.VK_RIGHT; 22 | keys[3] = KeyEvent.VK_DOWN; 23 | keys[4] = KeyEvent.VK_NUMPAD1; 24 | keys[5] = KeyEvent.VK_NUMPAD2; 25 | keys[6] = KeyEvent.VK_NUMPAD3; 26 | } else { 27 | keys[0] = KeyEvent.VK_A; 28 | keys[1] = KeyEvent.VK_W; 29 | keys[2] = KeyEvent.VK_D; 30 | keys[3] = KeyEvent.VK_S; 31 | keys[4] = KeyEvent.VK_J; 32 | keys[5] = KeyEvent.VK_K; 33 | keys[6] = KeyEvent.VK_L; 34 | } 35 | } 36 | 37 | public void keyReleased(KeyEvent e) { 38 | int key = e.getKeyCode(); 39 | if(key == keys[0]) bL = false; 40 | else if(key == keys[1]) bU = false; 41 | else if(key == keys[2]) bR = false; 42 | else if(key == keys[3]) bD = false; 43 | else if(key == keys[4]); 44 | else if(key == keys[5]); 45 | else if(key == keys[6]); 46 | locateDirection(); 47 | } 48 | 49 | public void KeyPressed(KeyEvent e) { 50 | int key = e.getKeyCode(); 51 | if(key == keys[0]) bL = true; 52 | else if(key == keys[1]) bU = true; 53 | else if(key == keys[2]) bR = true; 54 | else if(key == keys[3]) bD = true; 55 | else if(key == keys[4] && this.getCurrentWeapon().getColdDown() == 0) { 56 | this.getCurrentWeapon().setState(); 57 | this.getCurrentWeapon().setColdDown(); 58 | } else if(key == keys[5]){ 59 | this.NextWeapon(); 60 | } else if(key == keys[6] && this.getCurrentWeapon().getColdDown() == 0){ 61 | Weapon weapon = this.getCurrentWeapon(); 62 | if(weapon instanceof Fireball) { 63 | ((Fireball) this.getCurrentWeapon()).setUltimateState(); 64 | this.getCurrentWeapon().setColdDown(); 65 | } 66 | } 67 | locateDirection(); 68 | } 69 | 70 | 71 | public void locateDirection() { 72 | if(bL && !bU && !bR && !bD) dir = Direction.L; 73 | else if(bL && bU && !bR && !bD) dir = Direction.LU; 74 | else if(!bL && bU && !bR && !bD) dir = Direction.U; 75 | else if(!bL && bU && bR && !bD) dir = Direction.RU; 76 | else if(!bL && !bU && bR && !bD) dir = Direction.R; 77 | else if(!bL && !bU && bR && bD) dir = Direction.RD; 78 | else if(!bL && !bU && !bR && bD) dir = Direction.D; 79 | else if(bL && !bU && !bR && bD) dir = Direction.LD; 80 | else if(!bL && !bU && !bR && !bD) dir = Direction.STOP; 81 | } 82 | 83 | public void draw(Graphics g){ 84 | g.drawString(getCurrentWeapon().toString(), this.x - 20, this.y - 45); 85 | //g.drawString("HP: " + String.valueOf(this.HP),this.x-8,this.y-28); 86 | drawBloodBar(g); 87 | int b = this.getBegin(); 88 | if(b > 0 && (b / 3) % 2 == 0) { 89 | this.getCurrentWeapon().maintainColdDown(); 90 | mainTainWalkState(16); 91 | move(); 92 | } else { 93 | super.draw(g); 94 | } 95 | } 96 | 97 | public void setDeadState(){ 98 | this.setxIncrement(0, 0); 99 | this.setyIncrement(0, 0); 100 | this.onAttackState = 0; 101 | this.deadState = 600; 102 | } 103 | 104 | public void resetBegin() { 105 | this.x = (new Random().nextInt(100) % 2 == 0) ? 340 : 620; 106 | this.y = 280; 107 | this.setHP(MAX_HP); 108 | this.deadState = -1; 109 | super.resetBegin(); 110 | } 111 | 112 | public void maintainDeadState() { 113 | world.searchHero(); 114 | if(deadState <= 0) { 115 | if(world.searchHero()) { 116 | this.resetBegin(); 117 | } else { 118 | world.objDead(this); 119 | } 120 | } else { 121 | this.deadState--; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/Game/WorldGrids.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.awt.*; 4 | import java.util.ArrayList; 5 | import java.util.GregorianCalendar; 6 | import java.util.Iterator; 7 | import java.util.List; 8 | 9 | class Grid implements Cloneable{ 10 | public static final int LENGTH = 10; 11 | private int gridX, gridY; 12 | private int x, y; 13 | private boolean accessible; 14 | private GameObject object; 15 | private boolean isBorder; 16 | 17 | public Grid(int gridX, int gridY, boolean isBorder) { 18 | this.gridX = gridX; 19 | this.gridY = gridY; 20 | this.x = gridX * LENGTH; 21 | this.y = gridY * LENGTH; 22 | this.isBorder = isBorder; 23 | this.accessible = !isBorder; 24 | this.object = null; 25 | } 26 | 27 | public int getGridX() { 28 | return gridX; 29 | } 30 | 31 | public void setGridX(int gridX) { 32 | this.gridX = gridX; 33 | } 34 | 35 | public int getGridY() { 36 | return gridY; 37 | } 38 | 39 | public void setGridY(int gridY) { 40 | this.gridY = gridY; 41 | } 42 | 43 | public int getX() { 44 | return x; 45 | } 46 | 47 | public void setX(int x) { 48 | this.x = x; 49 | } 50 | 51 | public int getY() { 52 | return y; 53 | } 54 | 55 | public void setY(int y) { 56 | this.y = y; 57 | } 58 | 59 | public boolean isAccessible() { 60 | return accessible; 61 | } 62 | 63 | public void setAccessible(boolean accessible) { 64 | this.accessible = accessible; 65 | } 66 | 67 | public GameObject getObject() { 68 | return object; 69 | } 70 | 71 | public void setObject(GameObject object) { 72 | this.object = object; 73 | } 74 | 75 | @Override 76 | public Object clone() { 77 | Grid tmp = null; 78 | try{ 79 | tmp = (Grid) super.clone(); 80 | }catch(CloneNotSupportedException e) { 81 | e.printStackTrace(); 82 | } 83 | return tmp; 84 | } 85 | } 86 | 87 | public class WorldGrids { 88 | private List grids; 89 | private World world; 90 | private List unaccessibleGrids; 91 | private int w, h; 92 | 93 | public WorldGrids(World world) { 94 | this.world = world; 95 | w = world.getWidth() / Grid.LENGTH; 96 | h = world.getHeight() / Grid.LENGTH; 97 | this.grids = new ArrayList<>(); 98 | this.unaccessibleGrids = new ArrayList<>(); 99 | for(int i = 0; i < h; i++){ 100 | for(int j = 0; j < w; j++){ 101 | if(j == 0 || j == 1 || i <= 5) 102 | grids.add(new Grid(j, i, true)); 103 | else 104 | grids.add(new Grid(j, i, false)); 105 | } 106 | } 107 | } 108 | 109 | public void updateGrids(){ 110 | resetGrid();; 111 | 112 | Iterator objIter = world.getObjectsIterator(); 113 | while(objIter.hasNext()){ 114 | GameObject object = objIter.next(); 115 | if(!object.isCollidable() || object instanceof Border) continue; 116 | Iterator tmpIt = getGrid(object).iterator(); 117 | while(tmpIt.hasNext()){ 118 | Grid tmp = tmpIt.next(); 119 | tmp.setObject(object); 120 | tmp.setAccessible(false); 121 | unaccessibleGrids.add(tmp); 122 | } 123 | } 124 | } 125 | 126 | public void resetGrid(){ 127 | Iterator unAcGridIter = getUnaccessibleGridsIterator(); 128 | while(unAcGridIter.hasNext()){ 129 | Grid tmp = unAcGridIter.next(); 130 | tmp.setAccessible(true); 131 | tmp.setObject(null); 132 | unAcGridIter.remove(); 133 | } 134 | } 135 | 136 | public List getGrid(GameObject obj){ 137 | List grids = new ArrayList<>(); 138 | int objX = obj.getX() - obj.getRadius(); 139 | int objY = obj.getY() - obj.getRadius(); 140 | int length = obj.getRadius() * 2; 141 | int t = length / Grid.LENGTH + 1; 142 | for(int x = objX, i = 0; i < t && i < w; i++, x += Grid.LENGTH) 143 | for(int y = objY, j = 0; j < t && j < h; j++, y += Grid.LENGTH) { 144 | Grid tmp = getGrid(x+Grid.LENGTH, y+Grid.LENGTH); 145 | if(grids.indexOf(tmp) < 0) 146 | grids.add(tmp); 147 | } 148 | return grids; 149 | } 150 | 151 | public Grid getGrid(int x, int y){ 152 | int gridX = x / Grid.LENGTH; 153 | int gridY = y / Grid.LENGTH; 154 | return this.grids.get(gridY * w + gridX); 155 | } 156 | 157 | public Grid get(int gridX, int gridY){ 158 | if(gridX < 0) gridX = 0; 159 | if(gridY < 0) gridY = 0; 160 | if(gridX >= w) gridX = w-1; 161 | if(gridY >= h) gridY = h-1; 162 | return this.grids.get(gridY * w + gridX); 163 | } 164 | 165 | public Iterator getUnaccessibleGridsIterator(){ 166 | return unaccessibleGrids.iterator(); 167 | } 168 | 169 | public Iterator getGridsIterator(){ 170 | return grids.iterator(); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/Game/Enemy.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.awt.*; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | public class Enemy extends Role { 8 | private Pathfinder pathfinder; 9 | private Role target; 10 | private List path; 11 | private int refreshPath; 12 | private int collisionDelay; 13 | 14 | public Enemy(String name, int HP, int radius, int speed,int x, int y, World world){ 15 | super(name, HP, radius, speed, x, y, world); 16 | this.pathfinder = new Pathfinder(new WorldGrids(world), this); 17 | this.target = getTarget(); 18 | this.refreshPath = 0; 19 | this.collisionDelay = 0; 20 | } 21 | 22 | public Role getTarget() { 23 | Iterator tmp = world.getObjectsIterator(); 24 | Role target = null; 25 | double minDistance = 10000000; 26 | while(tmp.hasNext()){ 27 | GameObject obj = tmp.next(); 28 | if(obj instanceof Hero && obj.getHP() > 0){ 29 | double distance = Math.pow(this.x - obj.getX(), 2) + Math.pow(this.y - obj.getY(), 2); 30 | target = minDistance < distance ? target : (Role) obj; 31 | minDistance = minDistance < distance ? minDistance : distance; 32 | } 33 | } 34 | return target; 35 | } 36 | 37 | public Role getCurrentTarget(){ 38 | return this.target; 39 | } 40 | 41 | public int mainTainRefreshPath(int n){ 42 | return refreshPath = (refreshPath + 1) % n; 43 | } 44 | 45 | public int maintainCollisionDelay(int n){ 46 | return collisionDelay = (collisionDelay + 1) % n; 47 | } 48 | 49 | public Grid getCurrentGrid(){ 50 | return pathfinder.getWorldGrids().getGrid(this.x, this.y); 51 | } 52 | 53 | public Grid getTargetGrid(){ 54 | return pathfinder.getWorldGrids().getGrid(target.getX(), target.getY()); 55 | } 56 | 57 | public void getPath(){ 58 | path = pathfinder.shortestPath(getTargetGrid()); 59 | } 60 | 61 | public Direction judgeDirection(int deltaX, int deltaY){ 62 | if (deltaX == 0 && deltaY < 0) return Direction.U; 63 | else if (deltaX < 0 && deltaY < 0) return Direction.LU; 64 | else if (deltaX < 0 && deltaY == 0) return Direction.L; 65 | else if (deltaX < 0 && deltaY > 0) return Direction.LD; 66 | else if (deltaX == 0 && deltaY > 0) return Direction.D; 67 | else if (deltaX > 0 && deltaY > 0) return Direction.RD; 68 | else if (deltaX > 0 && deltaY == 0) return Direction.R; 69 | else if (deltaX > 0 && deltaY < 0) return Direction.RU; 70 | else return Direction.STOP; 71 | } 72 | 73 | public double getDeltaDegree(int anotherX, int anotherY){ 74 | int deltaX = anotherX - this.getX(); 75 | int deltaY = - anotherY + this.getY(); 76 | double D = getDistance(anotherX, anotherY, this.getX(),this.getY()); 77 | double sinA = deltaY / D; 78 | double cosA = deltaX / D; 79 | double angle1 = Math.toDegrees(Math.asin(sinA)); 80 | double angle2 = Math.toDegrees(Math.acos(cosA)); 81 | double angle = angle2; 82 | if(angle1 < 0) angle = 360 - angle; 83 | return angle; 84 | } 85 | 86 | public Direction judgeAccurateDir(int anotherX, int anotherY){ 87 | double angle = getDeltaDegree(anotherX, anotherY); 88 | if((angle >= 0 && angle <= 22.5) || (angle >= 337.5 && angle <= 360)) return Direction.R; 89 | else if(angle >= 22.5 && angle < 67.5) return Direction.RU; 90 | else if(angle >= 67.5 && angle < 112.5) return Direction.U; 91 | else if(angle >= 112.5 && angle < 157.5) return Direction.LU; 92 | else if(angle >= 157.5 && angle < 202.5) return Direction.L; 93 | else if(angle >= 202.5 && angle < 247.5) return Direction.LD; 94 | else if(angle >= 247.5 && angle < 292.5) return Direction.D; 95 | else if(angle >= 292.5 && angle < 337.5) return Direction.RD; 96 | else return Direction.STOP; 97 | } 98 | 99 | public Direction getNextDir(Grid nextGrid){ 100 | if(nextGrid != null) { 101 | int deltaX = nextGrid.getX() - this.getX(); 102 | int deltaY = nextGrid.getY() - this.getY(); 103 | return judgeDirection(deltaX, deltaY); 104 | } 105 | return Direction.STOP; 106 | } 107 | 108 | public void locateDirection() { 109 | if(getTarget() == null) return; 110 | if(mainTainRefreshPath(30) == 0) { 111 | this.target = getTarget(); 112 | this.pathfinder = new Pathfinder(new WorldGrids(world), this); 113 | getPath(); 114 | } 115 | if(this.path == null || this.path.size() == 0){ 116 | this.dir = Direction.STOP; 117 | return; 118 | } 119 | if(getCurrentGrid().getGridX() == path.get(0).getGridX() && getCurrentGrid().getGridY() == path.get(0).getGridY()) 120 | path.remove(0); 121 | if(this.path.size() > 0) { 122 | Grid nextGrid = path.get(0); 123 | this.oldDir =(this.dir == Direction.STOP) ? oldDir : dir; 124 | this.dir = getNextDir(nextGrid); 125 | } 126 | if(this.getDir() == Direction.STOP) { 127 | this.oldDir = (judgeAccurateDir(target.getX(), target.getY()) == Direction.STOP) ? oldDir : judgeAccurateDir(target.getX(), target.getY()); 128 | } 129 | } 130 | 131 | public void draw(Graphics g) { 132 | locateDirection(); 133 | super.draw(g); 134 | } 135 | 136 | public void collisionResponse(GameObject object){ 137 | this.dir = Direction.STOP; 138 | 139 | if(maintainCollisionDelay(3) > 0) return; 140 | else{ 141 | collisionDelay = 3; 142 | this.pathfinder = new Pathfinder(new WorldGrids(world), this); 143 | getPath(); 144 | } 145 | super.collisionResponse(object); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/Game/GameObject.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import javax.naming.event.ObjectChangeListener; 4 | import java.awt.*; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | public abstract class GameObject implements Cloneable{ 9 | protected String name; 10 | protected int radius; //半径 11 | protected int speed; 12 | protected int xIncrement; 13 | protected int yIncrement; 14 | protected Direction dir; 15 | protected Direction oldDir; 16 | protected int x, y; 17 | protected int HP; 18 | protected int onAttackState; 19 | protected boolean collidable; 20 | protected World world; 21 | protected static Toolkit tk = Toolkit.getDefaultToolkit(); 22 | protected static Image[] imgs = null; 23 | protected static Map imgMap = new HashMap(); 24 | 25 | public abstract void draw(Graphics g); 26 | public abstract void collisionResponse(GameObject object); 27 | public abstract void onAttack(Weapon weapon); 28 | 29 | static { 30 | imgs = new Image[] { 31 | tk.getImage(GameObject.class.getClassLoader().getResource("images/hero.png")), 32 | tk.getImage(GameObject.class.getClassLoader().getResource("images/monster.png")), 33 | tk.getImage(GameObject.class.getClassLoader().getResource("images/fireball.png")), 34 | tk.getImage(GameObject.class.getClassLoader().getResource("images/ghost.png")), 35 | tk.getImage(GameObject.class.getClassLoader().getResource("images/ghostball.png")), 36 | tk.getImage(GameObject.class.getClassLoader().getResource("images/wall.png")), 37 | tk.getImage(GameObject.class.getClassLoader().getResource("images/blood.png")), 38 | tk.getImage(GameObject.class.getClassLoader().getResource("images/box.png")) 39 | }; 40 | imgMap.put("Hero", imgs[0]); 41 | imgMap.put("Monster", imgs[1]); 42 | imgMap.put("Fireball", imgs[2]); 43 | imgMap.put("Ghost", imgs[3]); 44 | imgMap.put("Ghostball", imgs[4]); 45 | imgMap.put("Wall", imgs[5]); 46 | imgMap.put("Blood", imgs[6]); 47 | imgMap.put("Box", imgs[7]); 48 | } 49 | 50 | public GameObject(String name, int radius, int speed, int HP, int x, int y, boolean collidable, World world) { 51 | this.name = name; 52 | this.radius = radius; 53 | this.speed = speed; 54 | this.xIncrement = 0; 55 | this.yIncrement = 0; 56 | this.onAttackState = 0; 57 | this.HP = HP; 58 | this.dir = Direction.STOP; 59 | this.oldDir = Direction.D; 60 | this.x = x; 61 | this.y = y; 62 | this.collidable = collidable; 63 | this.world = world; 64 | } 65 | 66 | public GameObject(String name, int radius, int speed, Direction dir, int HP, int x, int y, boolean collidable, World world) { 67 | this.name = name; 68 | this.radius = radius; 69 | this.speed = speed; 70 | this.xIncrement = 0; 71 | this.yIncrement = 0; 72 | this.onAttackState = 0; 73 | this.dir = dir; 74 | this.HP = HP; 75 | this.oldDir = Direction.D; 76 | this.x = x; 77 | this.y = y; 78 | this.collidable = collidable; 79 | this.world = world; 80 | } 81 | 82 | public void drawOneImage(Graphics g, String name, int picOffset,int x, int y, int picX, int picY){ 83 | g.drawImage( 84 | imgMap.get(name), 85 | x - picOffset - 4, 86 | y - picOffset - 4, 87 | x + picOffset + 4, 88 | y + picOffset + 4, 89 | picX * picOffset * 2, 90 | picY * picOffset * 2, 91 | picX * picOffset * 2 + picOffset * 2 - 1, 92 | picY * picOffset * 2 + picOffset * 2 - 1, 93 | null); 94 | 95 | } 96 | 97 | public boolean collisionDetection(GameObject object){ 98 | if(!object.isCollidable()) return false; 99 | if(this.getDir() == Direction.STOP && this.checkOnAttack() <= 0) return false; 100 | double deltaX = this.x - object.getX(); 101 | double deltaY = (this.y - object.getY()); 102 | double d = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); 103 | int R = this.getRadius() + object.getRadius(); 104 | if(d <= R){ 105 | double cosValue = deltaX / d; 106 | double sinValue = deltaY / d; 107 | int offsetY = (int)((R - d + 2) * sinValue); 108 | int offsetX = (int)((R - d + 2) * cosValue); 109 | this.x += offsetX; 110 | this.y += offsetY; 111 | return true; 112 | } 113 | return false; 114 | } 115 | 116 | public int checkOnAttack(){ 117 | return (this.onAttackState); 118 | } 119 | 120 | public void resetOnAttackState(){ 121 | this.onAttackState = 0; 122 | } 123 | 124 | public int getSpeed() { 125 | return this.speed; 126 | } 127 | 128 | public int getRadius() { 129 | return this.radius; 130 | } 131 | 132 | public Direction getDir() { 133 | return this.dir; 134 | } 135 | 136 | public void setDir(Direction dir) { 137 | this.dir = dir; 138 | } 139 | 140 | public Direction getOldDir() { 141 | return this.oldDir; 142 | } 143 | 144 | public void setRadius(int radius) { 145 | this.radius = radius; 146 | } 147 | 148 | public int getX() { 149 | return this.x; 150 | } 151 | 152 | public int getY() { 153 | return this.y; 154 | } 155 | 156 | public int getHP() { 157 | return this.HP; 158 | } 159 | 160 | public void setHP(int HP) { 161 | if(HP == 0 && !(this instanceof Hero)) 162 | this.collidable = false; 163 | this.HP = HP; 164 | } 165 | 166 | public boolean isCollidable() { 167 | return collidable; 168 | } 169 | 170 | public int getxIncrement() { 171 | return xIncrement; 172 | } 173 | 174 | public void setxIncrement(double degree, int speed) { 175 | this.xIncrement = (int)(getSpeed() * Math.cos(Math.toRadians(degree))); 176 | } 177 | 178 | public int getyIncrement() { 179 | return yIncrement; 180 | } 181 | 182 | public void setyIncrement(double degree, int speed) { 183 | this.yIncrement = -(int)(getSpeed() * Math.sin(Math.toRadians(degree))); 184 | } 185 | 186 | public double getDistance(int x1, int y1, int x2, int y2){ 187 | double deltaX = x1 - x2; 188 | double deltaY = y1 - y2; 189 | return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); 190 | } 191 | 192 | @Override 193 | public Object clone() { 194 | GameObject obj = null; 195 | try{ 196 | obj = (GameObject) super.clone(); 197 | }catch(CloneNotSupportedException e) { 198 | e.printStackTrace(); 199 | } 200 | return obj; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/Game/Role.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.awt.*; 4 | import java.util.*; 5 | import java.util.List; 6 | 7 | public class Role extends GameObject{ 8 | public static final int PICOFFSET = 32; 9 | private int walkState; //鍦ㄨ鏂瑰悜绉诲姩鐨勬鏁� 10 | private List weapons; 11 | private Weapon currentWeapon; 12 | protected int deadState; 13 | private int maxHP; 14 | private int begin; 15 | private class BloodBar { 16 | public void draw(Graphics g) { 17 | int maxLength = 40; 18 | int length = (int)((double)getHP() / (double)getMaxHP() * 40); 19 | Color c = g.getColor(); 20 | g.setColor(Color.RED); 21 | g.drawRect(x - 20, y - 40, maxLength, 7); 22 | g.fillRect(x - 20, y - 40, length, 7); 23 | g.setColor(c); 24 | 25 | } 26 | } 27 | private BloodBar bloodBar; 28 | 29 | public Role(String name, int HP, int radius, int speed,int x, int y, World world) { 30 | super(name , radius, speed, HP, x, y, true, world); 31 | this.maxHP = this.HP; 32 | this.weapons = new ArrayList<>(); 33 | this.walkState = 0; 34 | this.deadState = -1; 35 | if(this instanceof Hero) 36 | this.begin = 250; 37 | else this.begin = 0; 38 | bloodBar = new BloodBar(); 39 | } 40 | 41 | public int mainTainWalkState(int n){ 42 | if(dir != Direction.STOP) { 43 | if (dir == oldDir) { 44 | walkState++; 45 | } else { 46 | walkState = 0; 47 | oldDir = dir; 48 | } 49 | } else { 50 | walkState = -1; 51 | } 52 | if(walkState >= n) walkState = 0; 53 | return walkState; 54 | } 55 | 56 | public void drawWalkImage(Graphics g) { 57 | if(mainTainWalkState(16) < 0){ 58 | drawOneImage(g, name, PICOFFSET,this.x, this.y, 0, this.oldDir.ordinal()); 59 | } else { 60 | drawOneImage(g, name, PICOFFSET, this.x, this.y, walkState / 4 + 1, this.dir.ordinal()); 61 | } 62 | } 63 | 64 | public void draw(Graphics g) { 65 | if(deadState >= 0){ 66 | this.drawOneImage(g, name, PICOFFSET, this.x, this.y, 13, 0); 67 | this.maintainDeadState(); 68 | return; 69 | } 70 | if(checkOnAttack() > 0){ 71 | this.drawOneImage(g, name, PICOFFSET, this.x, this.y, 0, this.oldDir.ordinal()); 72 | Random rand = new Random(); 73 | if(Math.abs(rand.nextInt(100)) > 20) world.addBlood(this.x, this.y); 74 | onAttackState--; 75 | } else if (currentWeapon.getState() >= 0 && (currentWeapon instanceof Sword || currentWeapon instanceof Hand)) { 76 | this.currentWeapon.drawNomalAttack(g); 77 | if (this.currentWeapon.getState() == 1) 78 | this.currentWeapon.Attack(); 79 | this.currentWeapon.maintainColdDown(); 80 | return; 81 | } 82 | this.drawWalkImage(g); 83 | 84 | this.currentWeapon.maintainColdDown(); 85 | //g.drawString("("+String.valueOf(this.x) +","+ String.valueOf(this.y)+")", this.x-8, this.y - 40); 86 | move(); 87 | } 88 | 89 | 90 | public void move(){ 91 | if((getDir() == Direction.STOP && checkOnAttack() <= 0) || getHP() <= 0) return; 92 | double degree = Direction.toDegree(getDir()); 93 | if(checkOnAttack() <= 0) { 94 | setxIncrement(degree, speed); 95 | setyIncrement(degree, speed); 96 | } 97 | world.collisionDetection(this); 98 | this.x += getxIncrement(); 99 | this.y += getyIncrement(); 100 | } 101 | 102 | public void collisionResponse(GameObject object){ 103 | if(this.dir == Direction.STOP) return; 104 | int deltaX = object.getX() - this.getX(); 105 | int deltaY = object.getY() - this.getY(); 106 | double tmpVectorX = 1.0 / deltaX; 107 | double tmpVectorY = -1.0 / deltaY; 108 | double normOfTmp = Math.sqrt(Math.pow(tmpVectorX, 2) + Math.pow(tmpVectorY, 2)); 109 | double dirX = Math.cos(Math.toRadians(Direction.toDegree(this.dir))); 110 | double dirY = -Math.sin(Math.toRadians(Direction.toDegree(this.dir))); 111 | double newSpeed = (tmpVectorX * dirX + tmpVectorY * dirY) / normOfTmp * getSpeed(); 112 | int newDirX = (int) (newSpeed * tmpVectorX); 113 | int newDirY = (int) (newSpeed * tmpVectorY); 114 | this.x += newDirX; 115 | this.y += newDirY; 116 | } 117 | 118 | public void onAttack(Weapon weapon){ 119 | if(getHP() <= 0 || begin > 0) return; 120 | this.onAttackState = 5; 121 | this.setHP(this.getHP() - weapon.getDamage()); 122 | if(getHP() <= 0) { 123 | this.setHP(0); 124 | this.setDeadState(); 125 | return; 126 | } 127 | int weaponX = weapon.getX(); 128 | int weaponY = weapon.getY(); 129 | int deltaX = weaponX - this.x; 130 | int deltaY = weaponY - this.y; 131 | double D = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); 132 | double cosA = deltaX / D; 133 | double sinA = deltaY / D; 134 | this.xIncrement = (int)(-cosA * 8); 135 | this.yIncrement = (int)(-sinA * 8); 136 | world.addBlood(this.x, this.y); 137 | } 138 | 139 | public void setDeadState(){ 140 | this.deadState = 150; 141 | } 142 | 143 | public int getWeaponsAmount(){ 144 | return weapons.size(); 145 | } 146 | 147 | public void addWeapon(Weapon weapon){ 148 | weapons.add(weapon); 149 | } 150 | 151 | public void setCurrentWeapon(Weapon currentWeapon) { 152 | this.currentWeapon = currentWeapon; 153 | } 154 | 155 | public Weapon getCurrentWeapon() { 156 | return currentWeapon; 157 | } 158 | 159 | public List getWeapons() { 160 | return weapons; 161 | } 162 | 163 | public void setWeapons(List weapons) { 164 | this.weapons = weapons; 165 | } 166 | 167 | public void maintainDeadState() { 168 | if(deadState > 0) 169 | deadState--; 170 | else 171 | world.objDead(this); 172 | } 173 | 174 | public void NextWeapon() { 175 | int index = weapons.indexOf(currentWeapon); 176 | if(index + 1 < this.getWeaponsAmount()){ 177 | currentWeapon = weapons.get(index + 1); 178 | } else { 179 | currentWeapon = weapons.get(0); 180 | } 181 | } 182 | 183 | public boolean collisionDetection(GameObject object){ 184 | if(object instanceof Weapon && ((Weapon) object).isHost(this)){ 185 | return false; 186 | } 187 | return super.collisionDetection(object); 188 | } 189 | 190 | public int getMaxHP() { 191 | return maxHP; 192 | } 193 | 194 | public void drawBloodBar(Graphics g){ 195 | bloodBar.draw(g); 196 | } 197 | 198 | public int getBegin() { 199 | return begin--; 200 | } 201 | 202 | public void resetBegin() { 203 | this.begin = 350; 204 | } 205 | } -------------------------------------------------------------------------------- /src/Game/World.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import javax.imageio.ImageIO; 4 | import java.io.*; 5 | import java.awt.*; 6 | import java.util.*; 7 | import java.util.List; 8 | import java.util.concurrent.CopyOnWriteArrayList; 9 | 10 | public class World { 11 | private CopyOnWriteArrayList objects; 12 | private CopyOnWriteArrayList bloods; 13 | private List pickedBoxes; 14 | private int maxBloodNum = 5000; 15 | private int bloodNum; 16 | private int width; 17 | private int height; 18 | private int maxEnemyNum; 19 | private int currentEnemyNum; 20 | private int producedEnemyNum; 21 | private int produceDelay; 22 | private int boxDelay; 23 | private Image endImg; 24 | private int end; 25 | 26 | 27 | public World(int width, int height, boolean Doubleplayer) { 28 | this.width = width; 29 | this.height = height; 30 | this.objects = new CopyOnWriteArrayList<>(); 31 | this.bloods = new CopyOnWriteArrayList<>(); 32 | this.pickedBoxes = new ArrayList<>(); 33 | this.bloodNum = 0; 34 | this.maxEnemyNum = 3; 35 | this.currentEnemyNum = 0; 36 | this.producedEnemyNum = 0; 37 | this.boxDelay = 0; 38 | this.end = -1; 39 | this.endImg = Toolkit.getDefaultToolkit().getImage(World.class.getClassLoader().getResource("images/gameover.png")); 40 | objects.add(new Hero(340, 180, 1, this)); 41 | if(Doubleplayer) 42 | objects.add(new Hero(620, 180, 0, this)); 43 | objects.add(new Border(0, this)); 44 | objects.add(new Border(1, this)); 45 | objects.add(new Border(2, this)); 46 | objects.add(new Border(3, this)); 47 | objects.add(new Box(320, 360, this)); 48 | objects.add(new Box(640, 360, this)); 49 | for(int i = 1; i <= 2; i++) 50 | for(int j = 1; j <= 3; j++){ 51 | objects.add(new Wall(width / 4 * j, height / 3 * i, this)); 52 | } 53 | } 54 | 55 | public Iterator getObjectsIterator(){ 56 | return objects.iterator(); 57 | } 58 | 59 | public void removeObject(GameObject obj){ 60 | objects.remove(obj); 61 | } 62 | 63 | public void addObject(GameObject obj){ 64 | objects.add(obj); 65 | } 66 | 67 | public GameObject getObject(int index){ 68 | return objects.get(index); 69 | } 70 | 71 | public int getWidth() { 72 | return width; 73 | } 74 | 75 | public int getHeight() { 76 | return height; 77 | } 78 | 79 | public int getCurrentEnemyNum() { 80 | return currentEnemyNum; 81 | } 82 | 83 | public void setCurrentEnemyNum(int currentEnemyNum) { 84 | this.currentEnemyNum = currentEnemyNum; 85 | } 86 | 87 | public void setProduceDelay(){ 88 | this.produceDelay = 50; 89 | } 90 | 91 | public void pickUpBox(Box box){ 92 | this.removeObject(box); 93 | pickedBoxes.add(box); 94 | box.setDelay(Box.DELAYTIME); 95 | } 96 | 97 | public void produceBox(){ 98 | for(Box box : pickedBoxes){ 99 | if(box.getDelay() == 0){ 100 | this.addObject(box); 101 | pickedBoxes.remove(box); 102 | break; 103 | } else { 104 | box.setDelay(box.getDelay() - 1); 105 | } 106 | } 107 | } 108 | 109 | public void produceEnemy(){ 110 | produceDelay = (produceDelay - 1 > 0? produceDelay - 1 : 0); 111 | if(currentEnemyNum >= 100) return; 112 | if(producedEnemyNum < maxEnemyNum && produceDelay <= 0){ 113 | Random rand = new Random(); 114 | int pos = Math.abs(rand.nextInt()) % 4; 115 | int type = Math.abs(rand.nextInt()) % 100; 116 | int t = (rand.nextInt() % 2) * Role.PICOFFSET * 2; 117 | int off = Role.PICOFFSET + 10; 118 | switch (pos){ 119 | case 0: 120 | objects.add(type < 10 ? new Ghost(width / 2 + t, off, this) : new Monster(width / 2 + t, off, this)); 121 | break; 122 | case 1: 123 | objects.add(type < 10 ? new Ghost(off, height / 2 + t, this) : new Monster(off, height / 2 + t, this)); 124 | break; 125 | case 2: 126 | objects.add(type < 10 ? new Ghost(width / 2 + t, height - off, this) : new Monster(width / 2 + t, height - off, this)); 127 | break; 128 | case 3: 129 | objects.add(type < 10 ? new Ghost(width - off, height / 2 + t, this) : new Monster(width -off, height / 2 + t, this)); 130 | break; 131 | default: 132 | break; 133 | } 134 | currentEnemyNum++; 135 | producedEnemyNum++; 136 | setProduceDelay();; 137 | } else if(currentEnemyNum <= 0 && producedEnemyNum == maxEnemyNum) { 138 | maxEnemyNum += 3; 139 | producedEnemyNum = 0; 140 | } 141 | } 142 | 143 | public boolean collisionDetection(GameObject obj){ 144 | Iterator iter = this.getObjectsIterator(); 145 | int flag = 0; 146 | while(iter.hasNext()){ 147 | GameObject tmpObj = iter.next(); 148 | if(!obj.equals(tmpObj) && tmpObj.getHP() > 0){ 149 | if(obj.collisionDetection(tmpObj)){ 150 | obj.collisionResponse(tmpObj); 151 | flag = 1; 152 | } 153 | } 154 | } 155 | if(flag == 1) return true; 156 | else return false; 157 | } 158 | 159 | public void objectSort(){ 160 | Collections.sort(objects, new Comparator() { 161 | @Override 162 | public int compare(GameObject obj1, GameObject obj2) { 163 | int i = obj1.getY() - obj2.getY(); 164 | if(i == 0){ 165 | return obj1.getX() - obj2.getX(); 166 | } 167 | return i; 168 | } 169 | }); 170 | } 171 | 172 | public void drawWorld(Graphics g){ 173 | if(isEnd()) { 174 | end--; 175 | } 176 | produceEnemy(); 177 | produceBox(); 178 | for(Blood blood : bloods){ 179 | blood.draw(g); 180 | } 181 | this.objectSort(); 182 | Iterator iter =this.getObjectsIterator(); 183 | while(iter.hasNext()){ 184 | iter.next().draw(g); 185 | } 186 | } 187 | 188 | public void objDead(Object obj){ 189 | if(obj instanceof Enemy) currentEnemyNum--; 190 | this.objects.remove(obj); 191 | } 192 | 193 | public int addBloodNum(){ 194 | bloodNum = (bloodNum + 1) % maxBloodNum; 195 | return bloodNum; 196 | } 197 | 198 | public boolean searchHero() { 199 | Iterator iter = getObjectsIterator(); 200 | while(iter.hasNext()) { 201 | GameObject obj = iter.next(); 202 | if(obj instanceof Hero && obj.getHP() > 0) return true; 203 | } 204 | gameOver(); 205 | return false; 206 | } 207 | 208 | public void addBlood(int x, int y){ 209 | int n = addBloodNum(); 210 | if(bloods.size() < maxBloodNum){ 211 | bloods.add(new Blood(x, y, this)); 212 | } else { 213 | bloods.set(n, new Blood(x, y, this)); 214 | } 215 | } 216 | 217 | public void drawEnd(Graphics g) { 218 | g.drawImage(endImg, 0, 0, width, height, null); 219 | } 220 | 221 | public void gameOver() { 222 | if(!isEnd()) 223 | this.end = 30; 224 | } 225 | 226 | public boolean isEnd() { 227 | return this.end >= 0; 228 | } 229 | 230 | public boolean End() { 231 | return this.end == 0; 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /src/Game/Pathfinder.java: -------------------------------------------------------------------------------- 1 | package Game; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | 8 | public class Pathfinder{ 9 | private List openNodes; 10 | private List closedNodes; 11 | private List nodesToGoal; 12 | private List pathToGoal; 13 | private WorldGrids worldGrids; 14 | private int depth; 15 | private GameObject object; 16 | private List gridsOfObject; 17 | private int centre; 18 | 19 | public Pathfinder(WorldGrids worldGrids, GameObject object) { 20 | this.worldGrids = worldGrids; 21 | this.object = object; 22 | this.pathToGoal = new ArrayList<>(); 23 | this.nodesToGoal = new ArrayList<>(); 24 | this.gridsOfObject = worldGrids.getGrid(object); 25 | Grid tmp = this.worldGrids.getGrid(object.getX(), object.getY()); 26 | for(int i = 0; i < gridsOfObject.size(); i++){ 27 | if(gridsOfObject.get(i).equals(tmp)){ 28 | centre = i; 29 | break; 30 | } 31 | } 32 | } 33 | 34 | public List getOpenNodes() { 35 | return openNodes; 36 | } 37 | 38 | public void setOpenNodes(List openNodes) { 39 | this.openNodes = openNodes; 40 | } 41 | 42 | public List getClosedNodes() { 43 | return closedNodes; 44 | } 45 | 46 | public void setClosedNodes(List closedNodes) { 47 | this.closedNodes = closedNodes; 48 | } 49 | 50 | public int getDepth() { 51 | return depth; 52 | } 53 | 54 | public void setDepth(int depth) { 55 | this.depth = depth; 56 | } 57 | 58 | public List getNodesToGoal() { 59 | return nodesToGoal; 60 | } 61 | 62 | public void setNodesToGoal(List nodesToGoal) { 63 | this.nodesToGoal = nodesToGoal; 64 | } 65 | 66 | public List getPathToGoal() { 67 | return pathToGoal; 68 | } 69 | 70 | public void setPathToGoal(List pathToGoal) { 71 | this.pathToGoal = pathToGoal; 72 | } 73 | 74 | public WorldGrids getWorldGrids() { 75 | return worldGrids; 76 | } 77 | 78 | public boolean ownGrid(Grid currentGrid, Grid otherGird){ 79 | int deltaX = currentGrid.getGridX() - getCentreGrid().getGridX(); 80 | int deltaY = currentGrid.getGridY() - getCentreGrid().getGridY(); 81 | for(Grid grid : gridsOfObject){ 82 | Grid tmp = worldGrids.get(grid.getGridX() + deltaX, grid.getGridY() + deltaY); 83 | if(tmp.equals(otherGird)){ 84 | return true; 85 | } 86 | } 87 | return false; 88 | } 89 | 90 | public List nextMoves(Grid grid){ 91 | List moves = new ArrayList<>(); 92 | int[] x = {0, 0, -1, 1, -1, -1, 1, 1}; 93 | int[] y = {-1, 1, 0, 0, -1, 1, 1, -1}; 94 | int deltaX = grid.getGridX() - getCentreGrid().getGridX(); 95 | int deltaY = grid.getGridY() - getCentreGrid().getGridY(); 96 | for(int i = 0; i < 8; i++){ 97 | boolean flag = true; 98 | for(int j = 0; j < gridsOfObject.size(); j++){ 99 | int nextX = gridsOfObject.get(j).getGridX() + deltaX + x[i]; 100 | int nextY = gridsOfObject.get(j).getGridY() + deltaY + y[i]; 101 | Grid next = worldGrids.get(nextX, nextY); 102 | if(!ownGrid(grid, next) && !next.isAccessible()){ 103 | flag = false; 104 | break; 105 | } 106 | } 107 | if(flag){ 108 | moves.add(worldGrids.get(grid.getGridX() + x[i], grid.getGridY() + y[i])); 109 | } 110 | } 111 | return moves; 112 | } 113 | 114 | public int getHeuristic(Grid currentPos, Grid goalPos){ 115 | return (Math.abs(goalPos.getGridX() - currentPos.getGridX()) + Math.abs(goalPos.getGridY() - currentPos.getGridY())) * 10; 116 | } 117 | 118 | public int getCost(Grid currentPos, Grid goalPos){ 119 | if(Math.abs(goalPos.getGridX() - currentPos.getGridX()) != 0 && Math.abs(goalPos.getGridY() - currentPos.getGridY()) != 0){ 120 | return 14; 121 | } else { 122 | return 10; 123 | } 124 | } 125 | 126 | public int getDistance(int x1, int y1, int x2, int y2){ 127 | double deltaX = x1 - x2; 128 | double deltaY = y1 - y2; 129 | return (int)Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); 130 | } 131 | 132 | public Grid getCentreGrid(){ 133 | return this.gridsOfObject.get(centre); 134 | } 135 | 136 | public List shortestPath(Grid goalPos){ 137 | if(((Enemy)object).getTarget() == null) return null; 138 | worldGrids.updateGrids(); 139 | 140 | Grid startPos = (Grid) getCentreGrid().clone(); 141 | 142 | openNodes = new ArrayList<>(); 143 | closedNodes = new ArrayList<>(); 144 | depth = 0; 145 | boolean hasGoal = false; 146 | 147 | openNodes.add(new PathNode(startPos, null, 0, getHeuristic(startPos, goalPos), depth)); 148 | 149 | while(openNodes.size() != 0){ 150 | closedNodes.add(openNodes.get(openNodes.size() - 1)); 151 | PathNode currentNode = closedNodes.get(closedNodes.size() - 1); 152 | Grid current = currentNode.getStateData(); 153 | openNodes.remove(openNodes.size() - 1); 154 | 155 | int distance = getDistance(current.getX(), current.getY(), goalPos.getX(), goalPos.getY()); 156 | int r = ((Enemy)object).getTarget().getRadius(); 157 | if (distance < object.getRadius() + r + 10 || currentNode.getDepth() > 25) { 158 | hasGoal = true; 159 | break; 160 | } 161 | 162 | List expanded = nextMoves(current); 163 | 164 | NodeLoop: 165 | for(int i = 0; (i < openNodes.size() || i < closedNodes.size()); i++){ 166 | int s = expanded.size() - 1; 167 | while(s >= 0){ 168 | if(i < openNodes.size()){ 169 | Grid OpenstateData = openNodes.get(i).getStateData(); 170 | if(OpenstateData.equals(expanded.get(s))){ 171 | if((currentNode.getG() + getCost(current, OpenstateData)) < openNodes.get(i).getG()){ 172 | openNodes.get(i).setG(currentNode.getG() + getCost(current, OpenstateData)); 173 | openNodes.get(i).setH(getHeuristic(expanded.get(s), goalPos)); 174 | openNodes.get(i).setF(openNodes.get(i).getG() + openNodes.get(i).getH()); 175 | openNodes.get(i).setParentNode(currentNode); 176 | } 177 | expanded.remove(s); 178 | if (expanded.isEmpty()) { 179 | break NodeLoop; 180 | } 181 | s--; 182 | continue ; 183 | } 184 | } 185 | if(i < closedNodes.size()){ 186 | if (closedNodes.get(i).getStateData().equals(expanded.get(s))){ 187 | expanded.remove(s); 188 | if (expanded.isEmpty()) 189 | { 190 | break NodeLoop; 191 | } 192 | } 193 | } 194 | s--; 195 | } 196 | } 197 | if (!expanded.isEmpty()) { 198 | for (int i = 0; i < expanded.size(); i++) { 199 | openNodes.add(new PathNode( 200 | expanded.get(i), 201 | currentNode, 202 | currentNode.getG() + getCost(current, expanded.get(i)), 203 | getHeuristic(expanded.get(i), goalPos), 204 | currentNode.getDepth() + 1)); 205 | } 206 | } 207 | Collections.sort(openNodes); 208 | } 209 | try { 210 | if (hasGoal) { 211 | int depth = closedNodes.get(closedNodes.size() - 1).getDepth(); 212 | PathNode parent = closedNodes.get(closedNodes.size() - 1); 213 | 214 | for (int s = 0; s <= depth; s++) { 215 | nodesToGoal.add(parent); 216 | pathToGoal.add(parent.getStateData()); 217 | parent = nodesToGoal.get(s).getParentNode(); 218 | } 219 | Collections.reverse(pathToGoal); 220 | return pathToGoal; 221 | } 222 | return null; 223 | } catch (NullPointerException e){ 224 | if(pathToGoal != null) return pathToGoal; 225 | return null; 226 | } 227 | } 228 | } 229 | --------------------------------------------------------------------------------