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

Столкновения с Ландшафтом

Опубликованно: 24.06.2017, 17:01
Последняя редакция, Andry: 01.07.2017 19:51

Этот урок расширяет урок HelloTerrain и в нём вы делаете ландшафт твердым. Вы комбинируете то, что вы узнали в Hello Terrain и Hello Collision, и добавляете CollisionShape в ландшафт. CollisionShape местности позволяет игроку от первого лица (который тоже является CollisionShape) сталкиваться с рельефом, т.е. ходить по нему и стоять на нем.

Пример кода

package jme3test.helloworld;

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.scene.Node;
import com.jme3.terrain.geomipmap.TerrainLodControl;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
import java.util.ArrayList;
import java.util.List;
import jme3tools.converters.ImageToAwt;

/**
 * Эта демонстрация показывает обнаружением столкновения с местностью,
 * по которой вы можете ходить, с перспективой от первого лица.
 * Этот код объединяет HelloCollision и HelloTerrain.
 */
public class HelloTerrainCollision extends SimpleApplication
        implements ActionListener {

  private BulletAppState bulletAppState;
  private RigidBodyControl landscape;
  private CharacterControl player;
  private Vector3f walkDirection = new Vector3f();
  private boolean left = false, right = false, up = false, down = false;
  private TerrainQuad terrain;
  private Material mat_terrain;

  public static void main(String[] args) {
    HelloTerrainCollision app = new HelloTerrainCollision();
    app.start();
  }

  @Override
  public void simpleInitApp() {
    /** Настроить физику */
    bulletAppState = new BulletAppState();
    stateManager.attach(bulletAppState);
    //Раскомментирование для отладки.
    //bulletAppState.setDebugEnabled(true);

    flyCam.setMoveSpeed(100);
    setUpKeys();

    /** 1. Создайте материал ландшафта и загрузите в него четыре текстуры. */
    mat_terrain = new Material(assetManager,
            "Common/MatDefs/Terrain/Terrain.j3md");

    /** 1.1) Добавьте ALPHA map (для splat текстур с красно-сине-зелеными кодами) */
    mat_terrain.setTexture("Alpha", assetManager.loadTexture(
            "Textures/Terrain/splat/alphamap.png"));

    /** 1.2) Добавьте GRASS(ТРАВЫ) текстуру в красный слой (Tex1). */
    Texture grass = assetManager.loadTexture(
            "Textures/Terrain/splat/grass.jpg");
    grass.setWrap(WrapMode.Repeat);
    mat_terrain.setTexture("Tex1", grass);
    mat_terrain.setFloat("Tex1Scale", 64f);

    /** 1.3) Добавьте DIRT(ПОЧВА) текстуру в зелёный слой (Tex2) */
    Texture dirt = assetManager.loadTexture(
            "Textures/Terrain/splat/dirt.jpg");
    dirt.setWrap(WrapMode.Repeat);
    mat_terrain.setTexture("Tex2", dirt);
    mat_terrain.setFloat("Tex2Scale", 32f);

    /** 1.4) Добавьте ROAD(ДОРОГА) текстуру в голубой слой (Tex3) */
    Texture rock = assetManager.loadTexture(
            "Textures/Terrain/splat/road.jpg");
    rock.setWrap(WrapMode.Repeat);
    mat_terrain.setTexture("Tex3", rock);
    mat_terrain.setFloat("Tex3Scale", 128f);

    /** 2. Создайте height map */
    AbstractHeightMap heightmap = null;
    Texture heightMapImage = assetManager.loadTexture(
            "Textures/Terrain/splat/mountains512.png");
    heightmap = new ImageBasedHeightMap(heightMapImage.getImage());
    heightmap.load();

    /** 3. Мы подготовили material и heightmap.
     * Теперь мы создаем сам ландшафт:
     * 3.1) Создайте TerrainQuad и назовите его "my terrain".
     * 3.2) Хорошее значение для плиток ландшафта 64x64 -- поэтому мы предоставляем 64+1=65.
     * 3.3) Мы подготовили  heightmap размером 512x512 -- поэтому мы предоставляем 512+1=513.
     * 3.4) В качестве шага масштаба LOD мы предоставляем Vector3f(1,1,1).
     * 3.5) Мы предоставляем подготовленную себе heightmap.
     */
    terrain = new TerrainQuad("my terrain", 65, 513, heightmap.getHeightMap());

    /** 4. Мы даем ландшафту его материал, расположение и его масштаб и прикрепляем. */
    terrain.setMaterial(mat_terrain);
    terrain.setLocalTranslation(0, -100, 0);
    terrain.setLocalScale(2f, 1f, 2f);
    rootNode.attachChild(terrain);

    /** 5. LOD (Уровень деталей) зависит от того, того есть ли камера: */
    List<Camera> cameras = new ArrayList<Camera>();
    cameras.add(getCamera());
    TerrainLodControl control = new TerrainLodControl(terrain, cameras);
    terrain.addControl(control);

    /** 6. Добавим физику: */
    // Мы установили обнаружение столкновения для сцены, создав статический 
    RigidBodyControl с нулевой массой.*/
    terrain.addControl(new RigidBodyControl(0));

    // Мы установили обнаружение столкновения для player, создав
    // фигуру столкновения капсул и CharacterControl..
    // CharacterControl предлагает дополнительные настройки для
    // размера, высоты шага, прыжка, падения и силы тяжести.
    // Мы также ставим игрока в исходное положение.
    CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
    player = new CharacterControl(capsuleShape, 0.05f);
    player.setJumpSpeed(20);
    player.setFallSpeed(30);
    player.setGravity(30);
    player.setPhysicsLocation(new Vector3f(-10, 10, 10));

    // ы присоединяем сцену и игрока к rootnode и physics space,
    // чтобы они появились в игровом мире.
    bulletAppState.getPhysicsSpace().add(terrain);
    bulletAppState.getPhysicsSpace().add(player);

  }
  /** Мы переписываем некоторые сопоставления навигационных клавиш здесь, так мы можем
   * добавить контролируемую физикой ходьбу и прыжки: */
  private void setUpKeys() {
    inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
    inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
    inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W));
    inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S));
    inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));
    inputManager.addListener(this, "Left");
    inputManager.addListener(this, "Right");
    inputManager.addListener(this, "Up");
    inputManager.addListener(this, "Down");
    inputManager.addListener(this, "Jump");
  }

  /** Это наши пользовательские действия, вызванные нажатиями клавиш.
   * Мы еще не ходим, мы просто отслеживаем направление, которое пользователь нажал. */
  public void onAction(String binding, boolean value, float tpf) {
    if (binding.equals("Left")) {
      if (value) { left = true; } else { left = false; }
    } else if (binding.equals("Right")) {
      if (value) { right = true; } else { right = false; }
    } else if (binding.equals("Up")) {
      if (value) { up = true; } else { up = false; }
    } else if (binding.equals("Down")) {
      if (value) { down = true; } else { down = false; }
    } else if (binding.equals("Jump")) {
      player.jump();
    }
  }

  /**
   * Это главный цикл события--ходьбы, ходьба происходит здесь.
   * Мы проверяем, в каком направлении идет игрок, интерпретируя
   * направление камеры вперед (camDir) и в стороны (camLeft).
   * Команда setWalkDirection() это то что позволяет физике контролировать ходьбу player.
   * Мы также следим за тем, чтобы камера двигалась вместе с игроком.
   */
  @Override
  public void simpleUpdate(float tpf) {
    Vector3f camDir = cam.getDirection().clone().multLocal(0.6f);
    Vector3f camLeft = cam.getLeft().clone().multLocal(0.4f);
    walkDirection.set(0, 0, 0);
    if (left)  { walkDirection.addLocal(camLeft); }
    if (right) { walkDirection.addLocal(camLeft.negate()); }
    if (up)    { walkDirection.addLocal(camDir); }
    if (down)  { walkDirection.addLocal(camDir.negate()); }
    player.setWalkDirection(walkDirection);
    cam.setLocation(player.getPhysicsLocation());
  }
}

Чтобы попробовать этот код, создайте новый проект Создать проект ▸ JME3 ▸ BasicGame, используя настройки по умолчанию. Вставьте код примера поверх предварительно сгенерированного класса Main.java. При необходимости измените пакет на «mygame». Откройте Свойства ▸ Свойства проект ▸ Библиотеки и добавьте библиотеку jme3-test-data, чтобы убедиться, что у вас есть все файлы.

Скомпилируйте и запустите код. Вы должны увидеть ландшафт. Вы можете использовать клавиши WASD и мышь, чтобы бегать вверх и вниз по холмам.

Понимание кода

Код Ландшафта

Прочтите урок Hello Terrain для получения информации о следующих частях, которые мы повторно используем:

  • AbstractHeightMap — эффективный способ описания формы поверхности местности.
  • Материал Terrain.j3md и его текстурные слои позволяют вам раскрашивать скалистые горы, травянистые долины и проложенную дорожку, пересекающую ландшафт.
  • TerrainQuad — это законченный Spatial terrain, который вы прикрепляете к rootNode.

Код обнаружения столкновений

Прочтите Hello Collision для получения информации о следующих частях, которые мы повторно используем:

  1. Строки BulletAppState активируют физику.
  2. ActionListener (onAction()) позволяет перенастроить обработку ввода для игрока от первого лица, поэтому он учитывает обнаружение конфликтов.
  3. Пользовательский метод setUpKeys() загружает перенастроенные обработчики ввода. Теперь они не просто идут куда-то, но и вычисляют вектор направления walkDirection, который нам нужен для обнаружения столкновения.
  4. simpleUpdate() использует вектор walkDirection и осуществляет ходьбу персонажа, принимая во внимание препятствия и сплошные стены/пол.
    player.setWalkDirection(walkDirection);
  5. Пейзаж RigidBodyControl — это CollisionShape местности.
  6. Игрок с физикой и от первого лица является CapsuleCollisionShape с CharacterControl.

Объединение двух

Вот измененные части, чтобы объединить эти два аспекта:

  1. Вы создаете статический (нулевой-массы) RigidBodyControl.
  2. Добавьте control в terrain, чтобы сделать его с физикой.
/** 6. Добавим физику: */
    terrain.addControl(new RigidBodyControl(0));

Вы прикрепляете terrain и player от первого лица к rootNode и к physics space, чтобы они отображались в игровом мире.

    bulletAppState.getPhysicsSpace().add(terrain);
    bulletAppState.getPhysicsSpace().add(player);

Заключение

Вы видите, что вы можете комбинировать фрагменты образцов кода (например из, HelloTerrain и HelloCollision) и создавать из него новое приложение, которое объединяет две функции в новое.

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

Смотрите также:

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

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

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