Докуметация Cтарт Статьи Форум Лента Вход
Не официальное русскоязычное сообщество
Главная
    Документация jMonkeyEngine
        jMonkeyEngine Уроки и Документация
            Вклады
                Система Сущностей Zay-ES
                    Визуализация

Визуализация

Опубликованно: 10.01.2019, 15:34
Последняя редакция, Andry: 18.04.2019 8:14

В первой части мы имели дело с настройкой и некоторым грубым скелетом и просто кораблем на экране, но все еще без системы сущностей. Ну, мы сделали настройку, но ещё не использовали систему сущностей. В этой части мы действительно будем её использовать. Обещаю!

Мы хотим захватчиков

Действительно, игра про захватчиков без захватчиков не является игрой о захватчиках, поэтому снова запустите ваш blender и смоделируйте захватчика. Конечно, у меня есть один для вас на моем Google диске, чтобы поделиться с вами. Я назвал его BasicInvader.

А теперь, мой друг, мы будем использовать систему сущностей для хранения данных группы захватчиков и звездного корабля на базе. Что нам нужно, чтобы указать корабль и захватчиков, которые должны появиться на экране? Нам нужна позиция и модель, чтобы иметь возможность напечатать ее на экране. Хорошо, обычно вы начинаете с какого-то игрового объекта и наследуете от него свой корабль, своего захватчика и так далее, и так далее. Возможно, вы бы злоупотребили JME Spatial, чтобы даже придерживаться некоторой игровой логики, и довольно скоро начали бы создавать беспорядочные спагетти, подобные архитектуре. По крайней мере, это происходит со мной. Поэтому очень хорошая идея отделить логику от визуализации. С системой сущностей вы делаете это в экстремальных условиях. С помощью системы управления сущностями мы можем в любое время расширить наш корабль с помощью любого необходимого нам компонента, не затрагивая большую часть существующего кода, в основном ни одного. Даже данные и методы разделены, что полностью противоположно объектно-ориентированному программированию, и если вы глубоко в объектно-ориентированном программировании, этот подход может вас или не может сбить с толку. Но будь терпелив со мной и с самим собой.

Какова моя позиция

Наш корабль, а также наши захватчики нуждаются в позиции, и это делается с помощью компонента позиции.

package mygame;

import com.jme3.math.Vector3f;
import com.simsilica.es.EntityComponent;

public class Position implements EntityComponent {

private final Vector3f location;

public Position(Vector3f location) {
this.location = location;
}

public Vector3f getLocation() {
return location;
}

@Override
public String toString() {
return getClass().getSimpleName() + "[" + location + "]";
}
}

Вы видите, что компонент — это исходные и чистые данные, которые помогают запускать системы в разных потоках, не мешая синхронизации. Мы будем иметь дело с многопоточностью позже.

Кто, черт возьми, я

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

package mygame;

import com.simsilica.es.EntityComponent;

public class Model implements EntityComponent {
private final String name;
public final static String SpaceShip = "SpaceShip";
public final static String BasicInvader = "BasicInvader";

public Model(String name) {
this.name = name;
}

public String getName() {
return name;
}

@Override
public String toString() {
return "Model[" + name + "]";
}
}

Чтобы избежать опечаток, я ввел некоторые статические строки для космических кораблей и базовых кораблей захватчиков. Теперь, как это входит в игру?

Генерировать энтиты

Наконец, мы будем использовать систему сущностей для хранения данных захватчиков и корабля, в данный момент графического представления нет. Сущности просто больше ничего. Вы должны добавить компоненты к этой сущности, чтобы придать ей смысл. А затем вы запрашиваете сущности с конкретными компонентами, в нашем случае Position и Model. Это как база данных. Итак, что нам сейчас нужно, так это GameAppState, в котором мы выстраиваем наши уровни, осуществляем переходы от начала к игре, от игры к мертвому и от мертвого к возрожденному и тому подобное. Но давайте сначала сделаем это глупо простым, а потом уточним.

package mygame;

import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.math.Vector3f;
import com.simsilica.es.EntityData;
import com.simsilica.es.EntityId;

public class GameAppState extends AbstractAppState {

private EntityData ed;
private SimpleApplication app;

@Override
public void initialize(AppStateManager stateManager, Application app) {

this.app = (SimpleApplication) app;
this.app.setPauseOnLostFocus(true);
this.app.setDisplayStatView(true);

this.ed = this.app.getStateManager().getState(EntityDataState.class).getEntityData();

EntityId ship = ed.createEntity();
this.ed.setComponents(ship,
new Position(new Vector3f(0, -20, 0)),
new Model(Model.SpaceShip));
for (int x = -20; x < 20; x += 4) {
for (int y = 0; y < 20; y += 4) {
EntityId invader = ed.createEntity();
this.ed.setComponents(invader,
new Position(new Vector3f(x, y, 0)),
new Model(Model.BasicInvader));
}
}
}

@Override
public void cleanup() {
}

@Override
public void update(float tpf) {
}

}

Таким образом, мы генерируем только корабли, которые достаточно, чтобы показать вам систему сущностей в действии.

Покажи что у тебя есть

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

package mygame;

import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.light.DirectionalLight;
import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
import com.simsilica.es.Entity;
import com.simsilica.es.EntityData;
import com.simsilica.es.EntityId;
import com.simsilica.es.EntitySet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class VisualAppState extends AbstractAppState {

private SimpleApplication app;
private EntityData ed;
private EntitySet entities;
private final Map<EntityId, Spatial> models;
private ModelFactory modelFactory;

public VisualAppState() {
this.models = new HashMap<>();
}

@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
this.app = (SimpleApplication) app;

ed = this.app.getStateManager().getState(EntityDataState.class).getEntityData();
entities = ed.getEntities(Position.class, Model.class);

app.getCamera().lookAt(Vector3f.UNIT_Z, Vector3f.UNIT_Y);
app.getCamera().setLocation(new Vector3f(0, 0, 60));

DirectionalLight light = new DirectionalLight();
light.setDirection(new Vector3f(1, 1, -1));
this.app.getRootNode().addLight(light);

modelFactory = new ModelFactory(this.app.getAssetManager());
}

@Override
public void cleanup() {
entities.release();
entities = null;
}

@Override
public void update(float tpf) {
if (entities.applyChanges()) {
removeModels(entities.getRemovedEntities());
addModels(entities.getAddedEntities());
updateModels(entities.getChangedEntities());
}
}

private void removeModels(Set<Entity> entities) {
for (Entity e : entities) {
Spatial s = models.remove(e.getId());
s.removeFromParent();
}
}

private void addModels(Set<Entity> entities) {
for (Entity e : entities) {
Spatial s = createVisual(e);
models.put(e.getId(), s);
updateModelSpatial(e, s);
this.app.getRootNode().attachChild(s);
}
}

private void updateModels(Set<Entity> entities) {
for (Entity e : entities) {
Spatial s = models.get(e.getId());
updateModelSpatial(e, s);
}
}

private void updateModelSpatial(Entity e, Spatial s) {
Position p = e.get(Position.class);
s.setLocalTranslation(p.getLocation());
}

private Spatial createVisual(Entity e) {
Model model = e.get(Model.class);
return modelFactory.create(model.getName());
}
}

это, кстати, своего рода первый шаблон проектирования в программировании систем сущностей, поскольку вы наверняка будете использовать его во всех своих играх, по крайней мере, на стороне клиента.

Подробности пожалуйста

Так что у нас здесь. Сначала мы определяем набор сущностей, с которыми мы хотим работать

        ed = this.app.getStateManager().getState(EntityDataState.class).getEntityData();
entities = ed.getEntities(Position.class, Model.class);

Нас интересуют все лица с позицией и моделью. Это работает для захватчиков и для нашего космического корабля, так как оба имеют эти компоненты.

Следующая часть — это цикл обновления, сердце каждой игры. JME предлагает это для каждого зарегистрированного состояния приложения.

    public void update(float tpf) {
if (entities.applyChanges()) {
removeModels(entities.getRemovedEntities());
addModels(entities.getAddedEntities());
updateModels(entities.getChangedEntities());
}
}

Мы проверяем, есть ли изменения в наборе сущностей, а затем обрабатываем удаленные сущности, добавленные сущности и измененные сущности. Все пространственные объекты и соответствующий идентификатор сущности управляются с помощью «локальной» хэш-карты

    private final Map<EntityId, Spatial> models;

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

    private void removeModels(Set<Entity> entities) {
for (Entity e : entities) {
Spatial s = models.remove(e.getId());
s.removeFromParent();
}
}

Пространство удерживается в хэш-карте моделей и получается с идентификатором удаленного объекта, поэтому я могу удалить его из визуального узла. Это все. Хорошо, прежде чем мы можем удалить что-то, это должно быть добавлено некоторое время, прежде чем, конечно. Добавленные объекты обрабатываются методом addModels

    private void addModels(Set<Entity> entities) {
for (Entity e : entities) {
Spatial s = createVisual(e);
models.put(e.getId(), s);
updateModelSpatial(e, s);
this.app.getRootNode().attachChild(s);
}
}

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

UpdateModel довольно прост и просто обновляет позицию пространства, в которой изменяются соответствующие сигналы идентификатора объекта.

В конце вы должны зарегистрировать все эти новые состояния приложения в Main, как это

    public Main() {
super(new VisualAppState(),
new GameAppState(),
new EntityDataState());
}

Вот и все. Ваш первый программный продукт, управляемый ES.


Переведено для jmonkeyengine.ru, оригинал.
Автор перевода: Andry

Добавить комментарий

Содержание

jMonkeyEngine.ru © 2017. Все права сохранены.