Привет всем!
Четвертая чать обещает быть очень интересной. В ней я собираюсь рассмотреть создание лазерных пушек, зеркал и отражений. Перед прочтением ознакомьтесь с предыдущими частями.
Часть 1.
Часть 2.
Часть 3.
Интересно?
Шаг 1. Ограничения.
Начнем немного из далека. Как все знают идеальный лазер движется со скоростью света и если не его пути нет препятствий врядли он когда либо остановится. Наш LaserLine не будет идеальным и первое что нужно сделать, это не дать ему возможности «улететь» за пределы игрового поля. Для этого добавим в класс GameObjectsMap метод:
Будем проверять положения лазера этим методом при его построении.
Шаг 2. LaserGun.
Надеюсь все помнят вторую часть статьи, где помимо класса лазера у нас был класс лазерной пушки которая могла поворачиваться и препятствовать движению лазера. Добавим к ней поле:
В конструктор добавим:
В attachTo метод добавим:
Ну вот теперь у нашей пушки есть лазер, вот только его не видно. Чтоб его видеть нужно задать ему последовательность точек через которые он будет проходить. Для этого в классе LaserGun напишем метод:
Здесь на первый взгляд все понятно, путь лазера зависит от первоначального направления и от объектов на его пути, как раз для этого нам и понадобилась карта. Но метода LaserLine.build() еще не существует. Займемся им.
Метод короткий но про sBuilder я еще не рассказывал. Там то и скрыта магия. Не забываем добавить в класс LaserLine:
Сделав его статическим мы будем уверены что у нас не будет отдельного его экземпляра для каждого лазера, что немного съэкономит нам памяти и положительно отразится на скорости.
Шаг 3. LaserBuilder
Пришло время показать как выглядит построение лазера:
Идем по порядку. Ограничение на 200 шагов лазера думаю понятно зачем. Далее, первая точка лазера добавляется при создании и совпадает с координатами LaserGun, остальные же точки добавляются при выходе из игровой зоны, при остановке и при отражении. Замечу что изначально точки добавлялись по прохождению каждой клетки, в Mirrors Maze до сих пор так. Но там и не был использван AndEngine.
nextPosition, надеюсь, не нуждается в объяснении.
Шаг 4. Зеркало.
До сих пор у нас не было объектов позволяющих отражать лазеры. Теперь нам нужно сделать один такой, и проверить все ли работает как задуманно. Не забываем добавить нужных текстур.
Создать новый игровой объект очень просто. Обойдемся без спойлеров и я предоставлю заинтересованному читателю самому разобраться в том, как работает метод onLaser. Двустороннее зеркало готово. Осталось добавить его инициализацию в GameObjectsMap.
Шаг 4.Инициализация лазера.
После всех манипуляций метод add теперь выглядит так:
Но мы не ограничлись добавлением зеркала, еще для более удобной работы и пушками нам понадобится:
Ну вот теперь посмотрим что у нас получилось. Добавим с StageActivity код:
В итоге мы увидим что то на пободие:

На сегодня достаточно. Спасибо за внимание. Буду рад вопросам, советам и предложениям.
Исходный код.
Четвертая чать обещает быть очень интересной. В ней я собираюсь рассмотреть создание лазерных пушек, зеркал и отражений. Перед прочтением ознакомьтесь с предыдущими частями.
Часть 1.
Часть 2.
Часть 3.
Интересно?
Шаг 1. Ограничения.
Начнем немного из далека. Как все знают идеальный лазер движется со скоростью света и если не его пути нет препятствий врядли он когда либо остановится. Наш LaserLine не будет идеальным и первое что нужно сделать, это не дать ему возможности «улететь» за пределы игрового поля. Для этого добавим в класс GameObjectsMap метод:
public static boolean outOfArea(Point pos) {
return pos.x < 0 || pos.y < 0 || pos.x > WIDTH - 1
|| pos.y > HEIGHT - 1;
}
* This source code was highlighted with Source Code Highlighter.Будем проверять положения лазера этим методом при его построении.
Шаг 2. LaserGun.
Надеюсь все помнят вторую часть статьи, где помимо класса лазера у нас был класс лазерной пушки которая могла поворачиваться и препятствовать движению лазера. Добавим к ней поле:
private LaserLine mLaserLine;В конструктор добавим:
mLaserLine = new LaserLine(new Point(posX, posY), angle);В attachTo метод добавим:
scene.getChild(GameObjectsMap.LASER_LAYER).attachChild(mLaserLine);Ну вот теперь у нашей пушки есть лазер, вот только его не видно. Чтоб его видеть нужно задать ему последовательность точек через которые он будет проходить. Для этого в классе LaserGun напишем метод:
public void buildLaser(GameObject[][] map) {
mLaserLine.setAngle(getAngle());
mLaserLine.build(map);
}
* This source code was highlighted with Source Code Highlighter.Здесь на первый взгляд все понятно, путь лазера зависит от первоначального направления и от объектов на его пути, как раз для этого нам и понадобилась карта. Но метода LaserLine.build() еще не существует. Займемся им.
public void build(GameObject[][] map) {
sBuilder.buildPath(this, map);
buildLines();
}
* This source code was highlighted with Source Code Highlighter.Метод короткий но про sBuilder я еще не рассказывал. Там то и скрыта магия. Не забываем добавить в класс LaserLine:
private static LaserLineBuilder sBuilder = new LaserLineBuilder();Сделав его статическим мы будем уверены что у нас не будет отдельного его экземпляра для каждого лазера, что немного съэкономит нам памяти и положительно отразится на скорости.
Шаг 3. LaserBuilder
Пришло время показать как выглядит построение лазера:
public class LaserLineBuilder {
private static final int MAX_STEPS = 200;
public void buildPath(LaserLine laserLine, GameObject[][] map) {
laserLine.clearPoints();
int step = 0;
int angle = laserLine.getAngle();
Point position = new Point(laserLine.getStartPosition());
GameObject gameObject;
while (step < MAX_STEPS) {
nextPosition(position, angle);
if (GameObjectsMap.outOfArea(position)) {
laserLine.addPoint(position);
return;
}
gameObject = map[position.x][position.y];
if (gameObject == null) {
continue;
} else {
laserLine.addPoint(position);
int reflection = gameObject.onLaser(angle);
if (reflection < 0) {
return;
} else {
angle = reflection;
}
}
}
laserLine.addPoint(position);
}
private void nextPosition(Point position, final int angle) {
switch (angle) {
case DynamicGameObject.DEG_0:
position.x++;
break;
case DynamicGameObject.DEG_90:
position.y++;
break;
case DynamicGameObject.DEG_180:
position.x--;
break;
case DynamicGameObject.DEG_270:
position.y--;
break;
case DynamicGameObject.DEG_45:
position.x++;
position.y++;
break;
case DynamicGameObject.DEG_135:
position.x--;
position.y++;
break;
case DynamicGameObject.DEG_225:
position.x--;
position.y--;
break;
case DynamicGameObject.DEG_315:
position.x++;
position.y--;
break;
default:
break;
}
}
}
* This source code was highlighted with Source Code Highlighter.Идем по порядку. Ограничение на 200 шагов лазера думаю понятно зачем. Далее, первая точка лазера добавляется при создании и совпадает с координатами LaserGun, остальные же точки добавляются при выходе из игровой зоны, при остановке и при отражении. Замечу что изначально точки добавлялись по прохождению каждой клетки, в Mirrors Maze до сих пор так. Но там и не был использван AndEngine.
nextPosition, надеюсь, не нуждается в объяснении.
Шаг 4. Зеркало.
До сих пор у нас не было объектов позволяющих отражать лазеры. Теперь нам нужно сделать один такой, и проверить все ли работает как задуманно. Не забываем добавить нужных текстур.
public class Mirror extends DynamicGameObject {
public Mirror(final int posX, final int posY, final int angle,
final TextureRegion region) {
super(posX, posY, angle, region);
}
@Override
void attachTo(Scene scene) {
scene.getChild(GameObjectsMap.GAME_OBJECTS_LAYER).attachChild(
getSprite());
}
@Override
int onLaser(int angle) {
int a = getAngle() % 4;
if (angle == (a + 1) % 8) return (a + 7) % 8;
if (angle == (a + 7) % 8) return (a + 1) % 8;
if (angle == (a + 3) % 8) return (a + 5) % 8;
if (angle == (a + 5) % 8) return (a + 3) % 8;
return -1;
}
}
* This source code was highlighted with Source Code Highlighter.Создать новый игровой объект очень просто. Обойдемся без спойлеров и я предоставлю заинтересованному читателю самому разобраться в том, как работает метод onLaser. Двустороннее зеркало готово. Осталось добавить его инициализацию в GameObjectsMap.
Шаг 4.Инициализация лазера.
После всех манипуляций метод add теперь выглядит так:
public void add(Type type, final int posH, final int posW, final int angle) {
GameObject object = null;
switch (type) {
case lasergun:
LaserGun l = new LaserGun(posH, posW, angle, mTextures
.getLaserGun());
mLaserGuns.add(l);
object = l;
break;
case mirror:
object = new Mirror(posH, posW, angle, mTextures.getMirror());
break;
case target:
break;
default:
break;
}
mMap[posH][posW] = object;
}
* This source code was highlighted with Source Code Highlighter.Но мы не ограничлись добавлением зеркала, еще для более удобной работы и пушками нам понадобится:
private LinkedList mLaserGuns;
иpublic void buildLasers() {
for (LaserGun gun : mLaserGuns) {
gun.buildLaser(mMap);
}
}
* This source code was highlighted with Source Code Highlighter.Ну вот теперь посмотрим что у нас получилось. Добавим с StageActivity код:
private void initMap() {
mGameObjectsMap = new GameObjectsMap(mTextures);
mGameObjectsMap.add(Type.lasergun, 0, 0, 3);
mGameObjectsMap.add(Type.lasergun, 3, 2, 7);
mGameObjectsMap.add(Type.lasergun, 3, 4, 4);
mGameObjectsMap.add(Type.mirror, 3, 3, 3);
mGameObjectsMap.addToScene(mEngine.getScene());
mGameObjectsController = new GameObjectsController(mGameObjectsMap, this);
final Scene scene = getEngine().getScene();
mGameObjectsMap.buildLasers();
}
* This source code was highlighted with Source Code Highlighter.В итоге мы увидим что то на пободие:

На сегодня достаточно. Спасибо за внимание. Буду рад вопросам, советам и предложениям.
Исходный код.
