OOP h17
某一款游戏,其主要角色如下:
- 游戏中每个对象有当前 x,y 坐标,坐标值取值范围为整数
- 每种对象的攻击力 strength、攻击范围 range、初始健康值 health 通过BattleField.init(String fileName) 从配置文件中初始化
- 非建筑物可以通过 move(dx,dy) 来移动坐标值,dx,dy 表示 x轴,y轴增量, 取值范围为整数
- 对象 A 攻击 B 的时候,要满足两个对象之间直线距离小于等于 A 的攻击范围,否则攻击无效(被攻击方不减健康值)
- 任何对象有 getHealth() 方法,返回当前生命值,如果已经死亡则返回 <=0 的一个数字
- 任何对象有 isDestroyed() 方法,如果生命值 <=0 则 true,否则 false
- GameBase 初始 x,y 值在创建时指定
- Barrack 兵营,可以训练出步枪兵、 RPG兵、军犬,初始 x,y 值在创建时指定
- RifleSoldier 步枪兵,初始 x,y 值就是兵营的 x,y
- RPGSoldier 火箭兵,初始 x,y 值就是兵营的 x,y
- Dog 军犬,初始 x,y 值就是兵营的 x,y
- A.attack(B),表示 A 攻击 B 对象,B.health=B.health-A.strength,注意这次没有一击毙命方法
- A.attack(),表示 A 寻找距离他最近、非己方、且活着的对象 B 进行攻击,如果攻击范围内没有符合要求对象则什么也不做
- 如果 A.isDestroyed() 则 A.attack() 没有任何效果
需要在原来的基础上实现读取文件、创建玩家和自定义攻击的功能。
0x00 BattleField
新的类,用于初始化属性值(生命值、攻击力和攻击范围),还包括玩家。
在上一次程序中,属性值由 Param 类中的一些 public 常量来定义。这次需要实现根据文件更改属性值。
成员变量包括所有玩家列表(new)。
init 方法中,可以调用 readLines 读取文件转换格式,将信息存入字符串数组列表中,遍历每一个字符串数组(即每一行)赋值。
createPlayer 方法中,传入玩家名字,就新建一个玩家,加入列表中。
getAllPlayer 列出所有玩家,只需返回所有玩家列表。
readLines 和之前用的一样,格式化的时候需要注意细节。
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
| package com.huawei.classroom.student.h17;
import java.io.*; import java.util.ArrayList; import java.util.List;
public class BattleField { private static List<Player> players = new ArrayList<>();
public BattleField() { players = null; }
public static void init(String filename) { List<String[]> rule = readLines(filename); if (rule == null) { return; } for (String[] ruleEle : rule) { setValue(ruleEle); } }
public static void createPlayer(String playerName) { if (playerName == null) { return; } Player newPlayer = new Player(playerName); players.add(newPlayer); }
public static List<Player> getAllPlayer() { return players; }
public static GameBase createGameBase(Player player, int x, int y) { return new GameBase(player, x, y); }
private static List<String[]> readLines(String filename) { String line = ""; Reader reader = null; List<String[]> result = new ArrayList<>(); try { reader = new FileReader(filename); } catch (FileNotFoundException e) { e.printStackTrace(); } if (reader == null) { return null; } LineNumberReader lineReader = new LineNumberReader(reader);
try { while (true) { line = lineReader.readLine(); if (line == null) { break; } if (line.trim().length() == 0 || line.startsWith("#")) { continue; } result.add(line.trim().split("\\.|=")); } } catch (IOException e) { e.printStackTrace(); } return result; }
private static void setValue(String[] rule) { if (EnumObjectType.base.toString().equals(rule[0])) { if (EnumObjectType.health.toString().equals(rule[1])) { Param.baseHealth = Integer.parseInt(rule[2]); } else if (EnumObjectType.strength.toString().equals(rule[0])) { Param.baseStrength = Integer.parseInt(rule[2]); } else if (EnumObjectType.range.toString().equals(rule[0])) { Param.baseRange = Integer.parseInt(rule[2]); } } else if (EnumObjectType.heavyTank.toString().equals(rule[0])) { if (EnumObjectType.health.toString().equals(rule[1])) { Param.heavyTankHealth = Integer.parseInt(rule[2]); } else if (EnumObjectType.strength.toString().equals(rule[1])) { Param.heavyTankStrength = Integer.parseInt(rule[2]); } else if (EnumObjectType.range.toString().equals(rule[1])) { Param.heavyTankRange = Integer.parseInt(rule[2]); } } else if (EnumObjectType.mediumTank.toString().equals(rule[0])) { if (EnumObjectType.health.toString().equals(rule[1])) { Param.mediumTankHealth = Integer.parseInt(rule[2]); } else if (EnumObjectType.strength.toString().equals(rule[1])) { Param.mediumTankStrength = Integer.parseInt(rule[2]); } else if (EnumObjectType.range.toString().equals(rule[1])) { Param.mediumTankRange = Integer.parseInt(rule[2]); } } else if (EnumObjectType.rifleSoldier.toString().equals(rule[0])) { if (EnumObjectType.health.toString().equals(rule[1])) { Param.rifleSoldierHealth = Integer.parseInt(rule[2]); } else if (EnumObjectType.strength.toString().equals(rule[1])) { Param.rifleSoldierStrength = Integer.parseInt(rule[2]); } else if (EnumObjectType.range.toString().equals(rule[1])) { Param.rifleSoldierRange = Integer.parseInt(rule[2]); } } else if (EnumObjectType.RPGSoldier.toString().equals(rule[0])) { if (EnumObjectType.health.toString().equals(rule[1])) { Param.RPGSoldierHealth = Integer.parseInt(rule[2]); } else if (EnumObjectType.strength.toString().equals(rule[1])) { Param.RPGSoldierStrength = Integer.parseInt(rule[2]); } else if (EnumObjectType.range.toString().equals(rule[1])) { Param.RPGSoldierRange = Integer.parseInt(rule[2]); } } else if (EnumObjectType.dog.toString().equals(rule[0])) { if (EnumObjectType.health.toString().equals(rule[1])) { Param.dogHealth = Integer.parseInt(rule[2]); } else if (EnumObjectType.strength.toString().equals(rule[1])) { Param.dogStrength = Integer.parseInt(rule[2]); } else if (EnumObjectType.range.toString().equals(rule[1])) { Param.dogRange = Integer.parseInt(rule[2]); } } else if (EnumObjectType.warFactory.toString().equals(rule[0])) { if (EnumObjectType.health.toString().equals(rule[1])) { Param.warFactoryHealth = Integer.parseInt(rule[2]); } else if (EnumObjectType.strength.toString().equals(rule[1])) { Param.warFactoryStrength = Integer.parseInt(rule[2]); } else if (EnumObjectType.range.toString().equals(rule[1])) { Param.warFactoryRange = Integer.parseInt(rule[2]); } } else if (EnumObjectType.barrack.toString().equals(rule[0])) { if (EnumObjectType.health.toString().equals(rule[1])) { Param.barrackHealth = Integer.parseInt(rule[2]); } else if (EnumObjectType.strength.toString().equals(rule[1])) { Param.barrackStrength = Integer.parseInt(rule[2]); } else if (EnumObjectType.range.toString().equals(rule[1])) { Param.barrackRange = Integer.parseInt(rule[2]); } } } }
|
0x01 Player
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.huawei.classroom.student.h17;
public class Player { private String name;
public Player(String name) { this.name = name; }
public void setName(String name) { this.name = name; }
public String getName() { return name; } }
|
0x02 GameObject
增加自定义攻击方法。
因为要在范围内找所有对象,需要新建成员变量 gameObject(GameObject 列表)用于遍历,每新建对象是存入(add)到此列表。
新建成员变量 player 代表所属玩家、objectType 代表所属类型。分别新建 getter 方法和 setter 方法。
重写 toString 方法,用于 debug:
1 2 3 4
| @Override public String toString() { return "["+player.getName() + "." + objectType +" live=" + (!isDestroyed()) + " x=" + x + " y=" + y+ " health=" + lifeValue+"]"; }
|
修改 attack(GameObject) 方法(不再有一击毙命):
1 2 3 4 5 6 7 8 9 10 11
| public void attack(GameObject obj) { if (obj.isDestroyed() || this.isDestroyed()) { return; } if (this.attackRange >= this.getDistance(obj)) { String debug=this+" 攻击 "+obj; obj.changeHealth(this.attackPower); debug=debug+" 攻击后 health="+obj.getHealth(); System.out.println(debug); } }
|
新建 attack() 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public void attack() { if (this.isDestroyed()) { return; } double min = this.attackRange; for (GameObject obj : GameObject.gameObjects) { if (obj.isDestroyed() || obj.player == this.player) { continue; } if (this.getDistance(obj) <= min) { min = this.getDistance(obj); } } for (GameObject obj : GameObject.gameObjects) { if (obj.isDestroyed() || obj.player == this.player) { continue; } if (this.getDistance(obj) - min < 0.000001) { attack(obj); } } }
|
0x03 Others
Param 中变量不再是 final。
继承 GameObject 的类均需在构造方法中调用 setObjectType 方法,指明自身类型,便于 debug。
继承 GameObject 的类的构造方法均需传入参数「玩家」。
gameBase 创建 barrack 和 warFactory 、barrack 和 warFactory 创建 soldier、dog 和 tank 时,需传入自身的 getPlayer。
building、tank 和 soldier 起传递作用。