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

Создание 3D шутер ч2

Опубликованно: 06.09.2015, 1:27
Последняя редакция, AdiDOS: 28.04.2017 10:14

В прошлой статье мы привязали автомат к камере да и привязали прицел , а в этой я решил сделать анимацию перезарядки , звук перезарядки и плюс поменять нашу сцену, сделать её более красивей , не пугайтесь размера кода по другому ни как и не нужно комментировать «То ты не видел большого кода»  , мое мнение  код должен быть как минимум упрощен в рамках обучения.

package weapons;

import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.animation.AnimEventListener;
import com.jme3.animation.LoopMode;
import com.jme3.asset.AssetLocator;
import com.jme3.asset.AssetManager;
import com.jme3.asset.plugins.FileLocator;
import com.jme3.audio.AudioNode;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.system.AppSettings;

public class Weapon extends Node implements ActionListener {
 protected AssetManager assetManager;
 protected InputManager inputManager;
 protected AnimChannel channel;
 protected Camera cam;
 protected AudioNode reload;
 protected Node guiNode;
 protected BitmapText ch;
 protected boolean animComplete = true;

 protected Spatial weapon;

 protected Vector3f rotate = new Vector3f(0,0,0); //Вращение оружия
 protected Vector3f move = new Vector3f(0, 0, 0);//Перемещение оружия
 protected Vector3f scale = new Vector3f(0, 0, 0);//Масштабирование оружия

 /**
 *
 * @return Возвращает масштабирование оружия на камере
 */
 public Vector3f getScale() {
   return scale;
 }
 /**
 *
 * @param scale Установка масштабирование оружия на камере
 */
 public void setScale(Vector3f scale) {
   this.scale = scale;
   weapon.setLocalScale(scale);
 }
 /**
 * @param rotate Возвращает угол поворота оружия на камере
 */
 public Vector3f getRotate() {
   return rotate;
 }
 /**
 * @param rotate Установка поворота оружия на камере
 */
 public void setRotate(Vector3f rotate) {
   this.rotate = rotate;
 }
 /**
 * @param move Возвращает позицию оружия на камере
 */
 public Vector3f getMove() {
   return move;
 }
 /**
 * @param move Установка смещения оружия на камере
 */
 public void setMove(Vector3f move) {
   this.move = move;
 }
 /**
 * В этой функции передаем параметры сцены <br>
 * @param assetManager Мэнеджер ресурсов
 * @param cam камера сцены
 */
 public void init(AssetManager assetManager, Camera cam, InputManager inputManager){
   this.assetManager = assetManager;
   this.inputManager = inputManager;
   this.cam = cam;

 }
 /**
 * Функция загрузки модели <br>
 * @param rootPath Путь к корневому каталогу
 * @param name Имя Файла
 * @param locatorClass Локатор
 */
 public void loadModel(String rootPath, String name, Class<? extends AssetLocator> locatorClass){
   assetManager.registerLocator("E:/Models/Weapons/animAk47", FileLocator.class);
   weapon = assetManager.loadModel(name);
   this.setCullHint(CullHint.Never);
   this.attachChild(weapon);
 }

 /**
 * Функция разчета и маштабирования оружия с камерой
 */
 public void update(){

   //Перемещение оружия по координатам камеры
   Vector3f vectorDifference = new Vector3f(cam.getLocation().subtract(weapon.getWorldTranslation()));
   this.setLocalTranslation(vectorDifference.addLocal(this.getLocalTranslation()));
   Quaternion worldDiff = new Quaternion(cam.getRotation().mult(this.getWorldRotation().inverse()));
   this.setLocalRotation(worldDiff.multLocal(this.getLocalRotation()));

 //Позиционированние оружия
   this.move(cam.getDirection().mult(move.x));
   this.move(cam.getUp().mult(move.y));
   this.move(cam.getLeft().mult(move.z));
   this.rotate(rotate.x,rotate.y, rotate.z);
 }
 /**
 * Функция инициализация кнопок
 */
 public void initKeys(){
   inputManager.addMapping("reload", new KeyTrigger(KeyInput.KEY_R));
   inputManager.addListener(this,"reload");
 }
 /**
 * Инициализация анимаций
 */
 public void initAnim(){
   AnimControl control = (AnimControl) weapon.getControl(AnimControl.class);
   channel = control.createChannel();
   channel.setTime(1);
   channel.setAnim("1");
   channel.setLoopMode(LoopMode.DontLoop);
   control.addListener(new AnimationEvents());
 }
 /**
 * Функция загрузки модели <br>
 * @param rootPath Путь к корневому каталогу
 * @param name Имя Файла
 * @param locatorClass Локатор
 */
 public void loadAudioReload(String rootPath, String name, Class<? extends AssetLocator> locatorClass){
   assetManager.registerLocator("E:/AssetsTest/Sounds/ak47/", FileLocator.class);
   reload = new AudioNode(assetManager, "Zvuk_-Perezaryadki_Avtomata.wav");
 }

 @Override
 public void onAction(String name, boolean isPressed, float tpf) {
   //Обработка событий по нажатию кнопки R
   if (animComplete && isPressed && name.equals("reload")){

   channel.setAnim("1");
   channel.setLoopMode(LoopMode.DontLoop);
   reload.play();
 }

 }
 /** Создание прицела
 * @param settings
 * @param guiNode
 */
 public void createBreechSight(AppSettings settings, Node guiNode) {
   this.guiNode = guiNode;
   BitmapFont guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
   ch = new BitmapText(guiFont, false);
   ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
   ch.setText("+");
   ch.setLocalTranslation(settings.getWidth() / 2 - ch.getLineWidth() / 2,

   settings.getHeight() / 2 + ch.getLineHeight() / 2, 0);
 }

 public void attachBreechSight() {
   if (ch != null)guiNode.attachChild(ch);
 }

 public void detachBreechSight() {
   if (ch != null)guiNode.detachChild(ch);
 }

 /**
 * Класс обработки событий Анимаций
 *
 */
 class AnimationEvents implements AnimEventListener{

   @Override
   public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
     if (animName.equals("1")) {
     animComplete = true;
     attachBreechSight();
 }
 }

     @Override
     public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
   if (animName.equals("1")) {
     animComplete = false;
     detachBreechSight();
 }

 }

 }
}

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

ПРИЦЕЛ

В прошлой статье я в классе АК47 создал функцию attachBreechSight она была нужна для привязки прицела оружия, но когда я дошел до анимации то подумал а неплохо бы  при перезарядке скрывать прицел и пришлось мне перенести эту функцию в класс Weapon дабы не строить велосипед , да я её разбил на три функции.

Функция создает прицел

public void createBreechSight(AppSettings settings, Node guiNode);

Добавление прицела на сцену

public void attachBreechSight();

Удаление прицела из сцены

public void detachBreechSight();

Суть басни такова мы при инициализации нашей сцены создаем саму модель прицела  а потом в нужное нам время добавляем или удаляем из сцены.

КНОПКА ПЕРЕЗАРЯДКИ

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

Инициализация событий кнопок

public void initKeys()

Событие нажатия кнопок

@Override
 public void onAction(String name, boolean isPressed, float tpf) {
   //Обработка событий по нажатию кнопки R
   if (animComplete && isPressed && name.equals("reload")){
     channel.setAnim("1");
     channel.setLoopMode(LoopMode.DontLoop);
     reload.play();
   }

 }

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

ВСЕ ОСТАЛЬНОЕ

Функция загрузки звука перезарядки

public void loadAudioReload(String rootPath, String name, Class<? extends AssetLocator> locatorClass)

Функция инициализации анимации

public void initAnim()

Функция установки масштабирования

public void setScale(Vector3f scale)

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

 

package weapons;

import com.jme3.asset.AssetManager;
import com.jme3.asset.plugins.FileLocator;
import com.jme3.input.InputManager;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.scene.Node;
import com.jme3.system.AppSettings;

public class AK47 extends Weapon{

 /**
 * Конструктор АК47
 * @param assetManager
 * @param cam
 * @param inputManager
 * @param settings
 * @param guiNode
 */
 public AK47(AssetManager assetManager, Camera cam, InputManager inputManager, AppSettings settings, Node guiNode) {
   init(assetManager, cam, inputManager);
   loadModel("E:/Models/Weapons/animAk47", "ak47.mesh.xml", FileLocator.class);
   loadAudioReload("E:/AssetsTest/Sounds/ak47/", "Zvuk_-Perezaryadki_Avtomata.wav", FileLocator.class);
   setMove(new Vector3f(4.7f, 0.5f, -1.6f));
   setRotate(new Vector3f(0,-1.5f,0));
   setScale(new Vector3f(0.16f,0.16f,0.16f));
   initAnim();
   initKeys();

   createBreechSight(settings, guiNode);
   attachBreechSight();
 }

}

Здесь все я думаю ясно вызываем по очереди все функции передаем параметры единственно что я добавил InputManager  он нужен для обработки событий кнопок , ну а далее код который все это запустит.

package test;

import com.jme3.app.SimpleApplication;
import com.jme3.math.Vector3f;

import weapons.AK47;

public class SceneControl extends SimpleApplication {
 AK47 player;

 public static void main(String[] args) {
   new SceneControl().start();

 }
 //Инициализация
 @Override
 public void simpleInitApp() {
   cam.setLocation(new Vector3f(-27.0f, 1.0f, 75.0f));
   flyCam.setMoveSpeed(10);
   //flyCam.setDragToRotate(true);
   setDisplayStatView(false);
   new Scene(assetManager, rootNode, viewPort).createScene(); //Создание сцены неба ланшафта и прочее 

   player = new AK47(assetManager, cam, inputManager, settings, guiNode);//Создание оружия
   rootNode.attachChild(player);

 }

 @Override
 public void simpleUpdate(float tpf) {
   player.update();
   super.simpleUpdate(tpf);
 }

}

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

1

2

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

Исходники можете скачать здесь

Модель здесь

Звук тоже тут

Спасибо за внимание!!!

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

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