Открыть список
Как стать автором
Обновить

Пишем игру для Android c помощью AndEngine. Часть 4

Разработка под Android
Привет всем!

Четвертая чать обещает быть очень интересной. В ней я собираюсь рассмотреть создание лазерных пушек, зеркал и отражений. Перед прочтением ознакомьтесь с предыдущими частями.

Часть 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.

В итоге мы увидим что то на пободие:
image

На сегодня достаточно. Спасибо за внимание. Буду рад вопросам, советам и предложениям.
Исходный код.
Теги:androidandEngineиграпримерjavaлазерыполезеркалоотражение
Хабы: Разработка под Android
Всего голосов 26: ↑25 и ↓1 +24
Просмотры10.4K

Комментарии 13

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Похожие публикации

Программист Android
20 апреля 202184 000 ₽GeekBrains
Программист Java
20 апреля 202177 000 ₽GeekBrains
Профессия Android-разработчик
20 апреля 202185 200 ₽SkillFactory
React.js. Разработка веб-приложений
26 апреля 202127 000 ₽Loftschool
Веб-разработка для начинающих
26 апреля 202125 000 ₽Loftschool

Лучшие публикации за сутки