Эта проблема:
Я командую одним роботом и хочу уничтожить своих врагов. Снова сталкиваться с однотипными врагами скучно. Мне нужны новые вызовы, а это означает новые типы врагов. Например, на первом уровне я хочу только практиковать свою цель. Поэтому мне нужен довольно тупой враг, который мало что делает, но делает снимки. После того, как я освоил это умение (стреляя в беспомощного дроида), мне нужно немного бросить вызов, и я хочу, чтобы вражеский дроид сопротивлялся, но, поскольку я все еще новичок, я не хочу быстро умирать, поэтому мне нужны слабые дроиды. После того, как я закончу с ними, я хочу более сложный вызов. Мне нужны лучшие и сильные дроиды. Не только сильнее, но и отличается по поведению, так как скучно убивать врагов одного и того же типа снова и снова.
Очевидное решение:
Создайте 3 класса для 3 типов вражеских дроидов. Для простоты у каждого дроида есть 2 способности: двигаться и атаковать. Имеет смысл создать интерфейс Droid с помощью этих двух методов, и каждый дроид должен их реализовать.
Они могут двигаться и стрелять . Ну, не все из них, но мы можем предоставить пустую реализацию для тех, которые ничего не делают.
Типы дроидов:
- Decoy Droid — не будет оружия и не сможет двигаться.
- Scout Droid — будет иметь слабое оружие и быстро двигаться.
- Assault Droid — будет иметь тяжелое оружие и медленно двигаться.
Рассматривая 3 типа, мы можем реализовать следующую простую диаграмму классов:
Интерфейс имеет 3 простых метода, которые должны реализовать дроиды:
01
02
03
04
05
06
07
08
09
10
11
|
public interface Droid { // display some info of the droid public void display(); // move the droid public void move( int x, int y); // attack position public void shoot( int x, int y); } |
3 класса следующие:
DecoyDroid.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
public class DecoyDroid implements Droid { @Override public void display() { System.out.println( "I am a DECOY droid" ); } @Override public void move( int x, int y) { System.out.println( "Can't move." ); } @Override public void shoot( int x, int y) { System.out.println( "Have no weapon." ); } } |
ScoutDroid.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
public class ScoutDroid implements Droid { private float damage = 0 .5f; @Override public void display() { System.out.println( "I am a scout droid" ); } @Override public void move( int x, int y) { System.out.println( "Moving QUICKLY to: " + x + "," + y + "." ); } @Override public void shoot( int x, int y) { System.out.println( "Light Laser Canon targeting: " + x + "," + y + ". Damage: " + damage); } } |
AssaultDroid.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public class AssaultDroid implements Droid { private float damage = 2 .5f; private boolean loaded = true ; @Override public void display() { System.out.println( "I am an ASSAULT droid" ); } @Override public void move( int x, int y) { System.out.println( "Moving SLOWLY to: " + x + "," + y + "." ); } @Override public void shoot( int x, int y) { if (loaded) { System.out.println( "Heavy laser targeting: " + x + "," + y + ". Damage: " + damage); loaded = false ; } else { System.out.println( "Reloading..." ); loaded = true ; } } } |
И ScoutDroid, и AssaultDroid имеют повреждения аргумента. Это содержит значение ущерба, нанесенного ими.
Чтобы дать AssaultDroid тяжелое оружие с медленным временем перезарядки, мы добавили загруженную переменную. Таким образом, штурмовому дроиду требуется один ход, чтобы выстрелить из своего оружия.
Я создал простой симулятор для дроидов по очереди, чтобы двигаться и стрелять.
Запустите симулятор для этого дизайна:
BadDroidSimulator.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
public class BadDroidSimulator { public static void main(String[] args) { // for generating random numbers Random rand = new Random(); Droid scout = new ScoutDroid(); Droid assailant = new AssaultDroid(); Droid decoy = new DecoyDroid(); scout.display(); assailant.display(); decoy.display(); // shoot-out - each droid fires once per turn for ( int i = 1 ; i <= 5 ; i++) { System.out.println( "\n<=== BEGIN TURN " + i + " ===>" ); scout.shoot(rand.nextInt( 10 ), rand.nextInt( 10 )); // we assume this is an enemy position scout.move(rand.nextInt( 10 ), rand.nextInt( 10 )); System.out.println(); assailant.shoot(rand.nextInt( 10 ), rand.nextInt( 10 )); assailant.move(rand.nextInt( 10 ), rand.nextInt( 10 )); System.out.println(); decoy.shoot(rand.nextInt( 10 ), rand.nextInt( 10 )); decoy.move(rand.nextInt( 10 ), rand.nextInt( 10 )); System.out.println( "<=== END TURN " + i + " ===>" ); } } } |
Результат (вывод консоли) будет выглядеть так:
01
02
03
04
05
06
07
08
09
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
|
I am a scout droid I am an ASSAULT droid I am a DECOY droid <=== BEGIN TURN 1 ===> Light Laser Canon targeting: 9,0. Damage: 0.5 Moving QUICKLY to: 4,6. Heavy laser targeting: 6,2. Damage: 2.5 Moving SLOWLY to: 9,1. Have no weapon. Can’t move. <=== END TURN 1 ===> <=== BEGIN TURN 2 ===> Light Laser Canon targeting: 3,4. Damage: 0.5 Moving QUICKLY to: 6,5. Reloading… Moving SLOWLY to: 1,6. Have no weapon. Can’t move. <=== END TURN 2 ===> <=== BEGIN TURN 3 ===> Light Laser Canon targeting: 6,7. Damage: 0.5 Moving QUICKLY to: 9,7. Heavy laser targeting: 7,1. Damage: 2.5 Moving SLOWLY to: 2,0. Have no weapon. Can’t move. <=== END TURN 3 ===> <=== BEGIN TURN 4 ===> Light Laser Canon targeting: 3,7. Damage: 0.5 Moving QUICKLY to: 1,4. Reloading… Moving SLOWLY to: 5,9. Have no weapon. Can’t move. <=== END TURN 4 ===> <=== BEGIN TURN 5 ===> Light Laser Canon targeting: 0,8. Damage: 0.5 Moving QUICKLY to: 3,9. Heavy laser targeting: 1,2. Damage: 2.5 Moving SLOWLY to: 3,2. Have no weapon. Can’t move. <=== END TURN 5 ===> |
Проблемы по расширению дизайна
Дроиды сменяются, чтобы двигаться и стрелять. Это все хорошо, но:
- Что если вы хотите создать гибридного дроида? Дроид, который движется так же быстро, как разведчик, но с тяжелым оружием? Вам придется создать новый класс и скопировать и вставить соответствующие методы из дроида Scout и Assault, верно?
- Также представьте, что механизм стрельбы не так прост и требует обнаружения столкновений и так далее. Для каждого дроида должен быть переписан один и тот же избыточный код.
- Что если огневая мощь может быть увеличена с помощью бонусов?
- Что, если дроид обретает самосознание и находит оружие, чтобы использовать его вместо текущего?
Я уверен, что у вас есть много идей о том, как улучшить игровой процесс и расширить мир, но наиболее очевидное решение (описанное выше) кажется неподходящим для этого. Это требует создания новых классов дроидов, и каждый тип дроидов будет реализовывать свои методы отдельно. Многие из этих методов идентичны. Текущий дизайн не позволяет вам изменять внутренности дроида во время выполнения без значительных усилий.
Вот одно из предложенных решений: композиция и шаблон стратегии .
Проектирование дроида (правильно)
Очень простой дроид состоит из оружия, надетого на шасси . Первый дизайн состоял из отношения типа « есть ». ScoutDroid — это общий дроид с некоторыми особенностями.
Композиция основана на « имеет » отношения. У дроида есть шасси . У дроида есть оружие . Какой тип компонентов имеет дроид, определяет его тип.
Давайте разложим Скаутского Дроида, например.
Скаутский дроид — это дроид, у которого есть световой лазер. У Canon есть набор колес для перемещения. Мы хотим, чтобы разведчик быстро двигался с помощью легкого оружия.
Штурмовой дроид, с другой стороны , тоже дроид, но у него есть тяжелый лазерный канон, и он работает на треках . Это делает его чрезвычайно мощным, но немного медленным.
Думайте с точки зрения фабрики. Как работает линия по производству автомобилей? Вы получаете шасси с определенным местом для двигателя, колес, приводного вала, коробки передач и так далее.
Все эти компоненты производятся отдельно. Команды, которые их производят, не имеют представления о других частях. Они должны соответствовать одному критерию: коробка передач должна идеально вписываться в свое место и соединяться с двигателем. Разные марки делают это по-разному. Разъем в этом случае является интерфейсом .
У двигателя похожая история. Если он хорошо соединяется с колесами и коробкой передач, его можно установить. Его внутренний дизайн, вместимость, мощность, расход топлива могут быть совершенно разными. Двигатель является одним из компонентов автомобиля.
Так же и наш дроид. Но для простоты у нас есть только 2 компонента. Нам нужен один общий дроид, у которого есть все встроенные соединения, поэтому его компоненты будут запускаться дроидом через эти интерфейсы. Например, дроиду нужно только нажать на курок оружия, и ему все равно, какое у него оружие, если у него есть курок. Дроид должен понимать метод pullTrigger, и для этого он должен быть реализован, чтобы мы могли дать дроиду оружие для использования.
То же самое с изменением местоположения. Это должно вызвать движение. Колеса, гусеницы или антигравитационные двигатели доставят туда дроида. Дроиду нужно только установить координаты.
Для этого нам нужен класс с реализованными методами вместо интерфейса.
Мы создаем абстрактный класс Droid . Мы делаем это абстрактным, потому что мы фактически реализуем методы, которые запускают оружие, и приводим в действие движущийся механизм, но у нас нет конкретного оружия и механизмов движения, прикрепленных к дроиду. Сборка конкретного дроида будет делегирована конструктору типов вместе с методом описания.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public abstract class Droid { protected Weapon weapon; // the weapon which will be used in fights protected Chassis chassis; // the chassis on which the droid is placed public void moveToPosition( int x, int y) { System.out.print(id + " > " ); chassis.moveTo(x, y); } /** * Engages the position on the screen whether it is occupied by * an enemy or not. Each strategy should decide how to do it. */ public void attackPosition( int x, int y) { System.out.print(id + " > " ); weapon.useWeapon( new Vector2f(x, y)); } /** * Displays some info on the droid */ public abstract void display(); } |
Если вы изучите класс, вы увидите, что у Droid есть 3 метода, из которых 2 реализованы. Он также имеет два компонента : оружие и шасси .
Компоненты являются интерфейсами, поэтому дроид не знает, что он делает, когда запускает действия над ними. Все это делегировано для реализации.
Интерфейсы следующие:
Weapon.java
01
02
03
04
05
06
07
08
09
10
11
12
|
public interface Weapon { /** * The trigger to use the weapon. * @param target - where on the map is the target */ public void useWeapon(Vector2f target); /** * Returns the description of the weapon */ public String getDescription(); } |
Chassis.java
01
02
03
04
05
06
07
08
09
10
11
12
|
public interface Chassis { /** * Delegates the movement to the supporting chassis and * tries to move the unit to x,y */ public void moveTo( int x, int y); /** * Returns the description of the chassis */ public String getDescription(); } |
Мы улучшим наш базовый класс Droid . Мы добавим методы установки и получения как для оружия, так и для шасси . Это позволит нам изменить поведение дроида во время выполнения. Это то, что такое шаблон стратегии . У дроида есть поведение: он может использовать оружие и может двигаться . Эти две стратегии (поведения) должны быть реализованы.
Мы также добавляем идентификатор, который будет уникальным в нашей игре для каждого экземпляра дроида. Я использую очень простую стратегию генерации идентификаторов. Я увеличиваю статическое поле nextId и добавляю его к конкретному префиксу типа дроида в конструкторе для каждого типа.
Вот новый класс Droid:
01
02
03
04
05
06
07
08
09
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
|
public abstract class Droid { protected static int nextId = 0 ; // the next available ID protected String id; // unique id protected Weapon weapon; // the weapon which will be used in fights protected Chassis chassis; // the chassis on which the droid is placed // the unique ID of the droid in the game public String getId() { return id; } public Weapon getWeapon() { return weapon; } public void setWeapon(Weapon weapon) { this .weapon = weapon; } public Chassis getChassis() { return chassis; } public void setChassis(Chassis chassis) { this .chassis = chassis; } public void moveToPosition( int x, int y) { System.out.print(id + " > " ); chassis.moveTo(x, y); } /** * Engages the position on the screen whether it is occupied by * an enemy or not. Each strategy should decide how to do it. */ public void attackPosition( int x, int y) { System.out.print(id + " > " ); weapon.useWeapon( new Vector2f(x, y)); } /** * Displays some info on the droid */ public abstract void display(); } |
Давайте создадим немного оружия
NoWeapon.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
/** * This is a null object. A null object is a dummy that does nothing and it * is a mere place-holder and eliminates the need to check for null. * @author impaler * */ public class NoWeapon implements Weapon { @Override public void useWeapon(Vector2f target) { // We are doing nothing System.out.println( "No weapon equipped!" ); } @Override public String getDescription() { return "Nothing" ; } } |
Это нулевой объект. Описание класса должно дать вам представление о том, что это такое.
LightLaserCanon.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
/** * This is a light laser cannon whit a quick reload time and high accuracy * * @author impaler * */ public class LightLaserCanon implements Weapon { private float damage = 0 .5f; // the damage inflicted @Override public void useWeapon(Vector2f target) { System.out.println( "Shooting my laser canon to " + ( int )target.getX() + "," + ( int )target.getY() + ". Bang on! Done " + damage + " damage." ); } @Override public String getDescription() { return "First generation laser canon. Street use only!" ; } } |
HeavyLaserCanon.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
/** * This is a heavy assault laser cannon with high accuracy but slow reload time. * @author impaler */ public class HeavyLaserCanon implements Weapon { private boolean loaded = true ; // after fire needs to be reloaded private float damage = 1 .5f; // the damage is considerable @Override public void useWeapon(Vector2f target) { if (loaded) { // we fire the canon System.out.println( "Eat this! Laser beam hit target (" + ( int )target.getX() + "," + ( int )target.getY() + ") and dealt " + damage + " damage." ); // next time needs reloading loaded = false ; } else { System.out.println( "Darn! Out of ammo! Reloading..." ); loaded = true ; } } @Override public String getDescription() { return "DASS-5000 - The ultimate in siege weaponry provided by Obviam Enterprises." ; } } |
Вы можете заметить класс Vector2f . Это очень простой 2D векторный класс, который в настоящее время содержит координаты x и y. Больше ничего. Вы можете найти его в загруженном источнике.
Давайте построим немного шасси
Метод getDescription () сообщает, на что похоже шасси.
NoChassis.java — нулевой объект (см. Оружие)
01
02
03
04
05
06
07
08
09
10
11
12
|
public class NoChassis implements Chassis { @Override public void moveTo( int x, int y) { System.out.println( "It's just a frame. Can't move." ); } @Override public String getDescription() { return "It's just a frame." ; } } |
SteelStand.java
01
02
03
04
05
06
07
08
09
10
11
12
|
public class SteelStand implements Chassis { @Override public void moveTo( int x, int y) { System.out.println( "Can't move." ); } @Override public String getDescription() { return "Unmovable reinforced steel stand ideal for turrets and defensive units." ; } } |
Wheels.java
01
02
03
04
05
06
07
08
09
10
11
12
|
public class Wheels implements Chassis { @Override public void moveTo( int x, int y) { System.out.println( "Speeding to " + x + "," + y + " on my wheels!" ); } @Override public String getDescription() { return "4 wheel drive, very fast on flat terrain but struggling through obstacles." ; } } |
Track.java
01
02
03
04
05
06
07
08
09
10
11
12
|
public class Track implements Chassis { @Override public void moveTo( int x, int y) { System.out.println( "Don't get in my way! Moving slowly to: " + x + "," + y + "." ); } @Override public String getDescription() { return "Slow moving tracks but able to go through many obstacles." ; } } |
Теперь мы можем собрать наших дроидов
Сначала давайте создадим DecoyDroid . У этого дроида не будет оружия, и он будет размещен на стальной подставке. Это для нашей целевой практики, помнишь?
DecoyDroid.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
public class DecoyDroid extends Droid { public DecoyDroid() { id = "DCY-" + (++Droid.nextId); weapon = new NoWeapon(); chassis = new SteelStand(); } @Override public void display() { System.out.println( "+--------------------------------------------------------------------------------------------+" ); System.out.println( "| I am a DECOY droid." ); System.out.println( "|\tID: " + id); System.out.println( "|\tWeapon: " + weapon.getDescription()); System.out.println( "|\tChassis: " + chassis.getDescription()); System.out.println( "+--------------------------------------------------------------------------------------------+" ); } } |
Изучите конструктор по умолчанию. Он создает идентификатор и назначает экземпляр NoWeapon и SteelStand дроиду.
Метод display () более сложный, чем прежде, но просто для лучшего описания дроида. Он также использует описания компонентов.
Если вы создадите экземпляр DecoyDroid и вызовете его метод отображения, вы получите его хорошее описание.
1
2
3
4
5
6
|
+——————————————————————————————–+ | I am a DECOY droid. | ID: DCY-3 | Weapon: Nothing | Chassis: Unmovable reinforced steel stand ideal for turrets and defensive units . +——————————————————————————————–+ |
Давайте построим остальные типы:
ScoutDroid.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
public class ScoutDroid extends Droid { public ScoutDroid() { id = "SCT-" + (++Droid.nextId); weapon = new LightLaserCanon(); chassis = new Wheels(); } @Override public void display() { System.out.println( "+--------------------------------------------------------------------------------------------+" ); System.out.println( "| I am a SCOUT droid." ); System.out.println( "|\tID: " + id); System.out.println( "|\tWeapon: " + weapon.getDescription()); System.out.println( "|\tChassis: " + chassis.getDescription()); System.out.println( "+--------------------------------------------------------------------------------------------+" ); } } |
AssaultDroid.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
public class AssaultDroid extends Droid { public AssaultDroid() { id = "ASS-" + (++Droid.nextId); weapon = new HeavyLaserCanon(); chassis = new Track(); } @Override public void display() { System.out.println( "+--------------------------------------------------------------------------------------------+" ); System.out.println( "| I am an ASSAULT droid." ); System.out.println( "|\tID: " + id); System.out.println( "|\tWeapon: " + weapon.getDescription()); System.out.println( "|\tChassis: " + chassis.getDescription()); System.out.println( "+--------------------------------------------------------------------------------------------+" ); } } |
Вы заметите, что единственное, что нужно реализовать, — это конструктор, который добавляет шасси и оружие, и метод display () .
Следующая диаграмма показывает новую архитектуру:
Давайте создадим тестовый скрипт для него. Мы смоделируем 5 ходов, в которых каждый дроид будет использовать свое оружие и перемещаться в случайное место. Проверьте поведение каждого оружия, и вы заметите, что тяжелый лазер будет стрелять каждые 2 хода. Чтобы сделать это интересным, в четвертом повороте мы даем HeavyLaserCanon для DecoyDroid . Посмотрите, как он меняет поведение дроида и начинает стрелять. Это гибридный дроид, созданный на лету во время выполнения.
Код симулятора (DroidSimulator.java):
01
02
03
04
05
06
07
08
09
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
|
public class DroidSimulator { public static void main(String[] args) { // for generating random numbers Random rand = new Random(); Droid scout = new ScoutDroid(); Droid assailant = new AssaultDroid(); Droid decoy = new DecoyDroid(); scout.display(); assailant.display(); decoy.display(); // shoot-out - each droid fires once per turn for ( int i = 1 ; i <= 5 ; i++) { System.out.println( "\n<=== BEGIN TURN " + i + " ===>" ); // in turn 3 decoy droid is given an assault canon if (i == 4 ) { decoy.setWeapon( new HeavyLaserCanon()); System.out.println( "* " + decoy.getId() + " acquired " + decoy.getWeapon().getDescription() + "\n" ); } scout.attackPosition(rand.nextInt( 10 ), rand.nextInt( 10 )); // we assume this is an enemy position scout.moveToPosition(rand.nextInt( 10 ), rand.nextInt( 10 )); System.out.println(); assailant.attackPosition(rand.nextInt( 10 ), rand.nextInt( 10 )); assailant.moveToPosition(rand.nextInt( 10 ), rand.nextInt( 10 )); System.out.println(); decoy.attackPosition(rand.nextInt( 10 ), rand.nextInt( 10 )); decoy.moveToPosition(rand.nextInt( 10 ), rand.nextInt( 10 )); System.out.println( "<=== END TURN " + i + " ===>" ); } } } |
Выход:
01
02
03
04
05
06
07
08
09
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
|
+——————————————————————————————–+ | I am a SCOUT droid. | ID: SCT-1 | Weapon: First generation laser canon. Street use only! | Chassis: 4 wheel drive, very fast on flat terrain but struggling through obstacles. +——————————————————————————————–+ +——————————————————————————————–+ | I am an ASSAULT droid. | ID: ASS-2 | Weapon: DASS-5000 – The ultimate in siege weaponry provided by Obviam Enterprises. | Chassis: Slow moving tracks but able to go through many obstacles. +——————————————————————————————–+ +——————————————————————————————–+ | I am a DECOY droid. | ID: DCY-3 | Weapon: Nothing | Chassis: Unmovable reinforced steel stand ideal for turrets and defensive units . +——————————————————————————————–+ <=== BEGIN TURN 1 ===> SCT-1 > Shooting my laser canon to 0,3. Bang on! Done 0.5 damage. SCT-1 > Speeding to 0,2 on my wheels! ASS-2 > Eat this! Laser beam hit target (3,4) and dealt 1.5 damage. ASS-2 > Don’t get in my way! Moving slowly to: 3,8. DCY-3 > No weapon equipped! DCY-3 > Can’t move. <=== END TURN 1 ===> <=== BEGIN TURN 2 ===> SCT-1 > Shooting my laser canon to 4,0. Bang on! Done 0.5 damage. SCT-1 > Speeding to 5,0 on my wheels! ASS-2 > Darn! Out of ammo! Reloading… ASS-2 > Don’t get in my way! Moving slowly to: 1,6. DCY-3 > No weapon equipped! DCY-3 > Can’t move. <=== END TURN 2 ===> <=== BEGIN TURN 3 ===> SCT-1 > Shooting my laser canon to 3,0. Bang on! Done 0.5 damage. SCT-1 > Speeding to 0,6 on my wheels! ASS-2 > Eat this! Laser beam hit target (9,1) and dealt 1.5 damage. ASS-2 > Don’t get in my way! Moving slowly to: 8,0. DCY-3 > No weapon equipped! DCY-3 > Can’t move. <=== END TURN 3 ===> <=== BEGIN TURN 4 ===> * DCY-3 acquired DASS-5000 – The ultimate in siege weaponry provided by Obviam Enterprises. SCT-1 > Shooting my laser canon to 8,6. Bang on! Done 0.5 damage. SCT-1 > Speeding to 2,3 on my wheels! ASS-2 > Darn! Out of ammo! Reloading… ASS-2 > Don’t get in my way! Moving slowly to: 0,6. DCY-3 > Eat this! Laser beam hit target (9,4) and dealt 1.5 damage. DCY-3 > Can’t move. <=== END TURN 4 ===> <=== BEGIN TURN 5 ===> SCT-1 > Shooting my laser canon to 1,7. Bang on! Done 0.5 damage. SCT-1 > Speeding to 1,9 on my wheels! ASS-2 > Eat this! Laser beam hit target (1,4) and dealt 1.5 damage. ASS-2 > Don’t get in my way! Moving slowly to: 3,6. DCY-3 > Darn! Out of ammo! Reloading… DCY-3 > Can’t move. <=== END TURN 5 ===> |
Обратите внимание на 4-м ходу, как DecoyDroid получил новое оружие и изменил его поведение (желтая линия). Теперь вы также должны понимать шаблон нулевого объекта.
В его нынешнем виде легко создавать новое оружие, шасси и дроидов, сводя код к минимуму. В этих ситуациях всегда отдавайте предпочтение композиции, а не наследованию. Вы можете создать очень сложного дроида со щитами, сенсорами, набором оружия, а также компонентом ИИ, который решает, какое оружие использовать в зависимости от ситуации. Если вы заметили, я использовал термин «использование» вместо огня, потому что оружие также может быть рукопашным и не обязательно оружием дальнего боя.
Загружаемый проект содержит только реализацию шаблона стратегии. Простой подход наследования опущен. Поиграйте с ним и возьмите в руки этот полезный шаблон, так как я буду широко его использовать, и это считается хорошим дизайном. Это простое Java-приложение, оно не поддерживает Android.
Загрузите источник здесь (obviam.compositions.part1.tgz) .
В следующих частях я попытаюсь добавить некоторые возможности ИИ и как составить финального дроида из изображений его компонентов.
Справка: Дизайн внутриигровых сущностей. Стратегии составления объектов. Часть 1 — Шаблон стратегии от нашего партнера JCG Тамаса Яно из блога « Против зерна ».
- Введение в разработку игр для Android Введение
- Разработка игр для Android — Идея игры
- Разработка игр для Android — Создать проект
- Разработка игр для Android — базовая игровая архитектура
- Разработка игр для Android — основной игровой цикл
- Разработка игр для Android — Отображение изображений с Android
- Разработка игр для Android — перемещение изображений на экране
- Разработка игр для Android — The Game Loop
- Разработка игр для Android — Измерение FPS
- Разработка игр для Android — Sprite Animation
- Разработка игр для Android — Particle Explosion
- Разработка игр для Android — Использование растровых шрифтов
- Разработка игр для Android — переход с Canvas на OpenGL ES
- Разработка игр для Android — отображение графических элементов (примитивов) с помощью OpenGL ES
- Разработка игр для Android — OpenGL Texture Mapping
- Разработка игр для Android — Дизайн игровых сущностей — Государственный паттерн
- Серия игр для Android