Войти
ПрограммированиеСтатьиОбщее

MMO на Unreal Engine #2 (4 стр)

Внимание! Этот документ ещё не опубликован.

Автор:

Чего нам щас нехватает? Ну сомневаюсь что к этому времени вы ещё со мной, как никак второй день пишу статью.
Нам не хватает сейчас, двух методов.
1) будет очищать мир от всех наших блоков, проще говоря ClearMap
2) ну а второй метод, должен естественно строить нашу карту в мире по подгруженной карте BuildMap. При чем нам для блупринтов нужен лишь второй, а первый будет вызываться отсюда же. Перед построением карты будет не лишним очистить старую карту в мире, согласны? Ок

так что давайте объявим их в .h, вы же помните куда мы должны добавить? Правильно в конец. Разбуди вас в 4е ночи и вы должны правильно отвечать на этот вопрос 8)

void ClearMap();

  UFUNCTION(BlueprintCallable, Category = Game)
  void BuildMap();

Ну и опишем эти методы в CMap.cpp:

void ACMap::ClearMap()
{
  UE_LOG(LogTemp, Warning, TEXT("ClearMap"));

  TArray<AActor*> FoundActors;
  // получаем список всех акторов с таким классом как наш блупринт BP_Wall
  UGameplayStatics::GetAllActorsOfClass(GetWorld(), bpwallClass, FoundActors);

  for (AActor *actor : FoundActors)
    actor->Destroy(false, true);

}

void ACMap::BuildMap()
{

  UE_LOG(LogTemp, Warning, TEXT("CreateMap"));

  // проверка на вшивость, если bpwallClass не установлен, то всё остальное просто крашнется, лучше вообще ничего тыды не делать
  // так уж и быть, сообщим в консоли об этом
  if (bpwallClass)
  {
    // вызываем полную очистку мира от наших блоков
    ClearMap();

    int x = 0;
    int y = 0;
    FActorSpawnParameters params;
    FTransform transform;
    FVector Location;
    FOutputDeviceNull ar;
    FOutputDeviceDebug debug;
    FString command;

    for (int i = 0; i < Map.Num(); i++)
    {
      int blockID = Map[i];
      Location = FVector(x * 100, y * 100, 0);
      transform.SetLocation(Location);

      AActor* wall = GetWorld()->SpawnActor<AActor>(bpwallClass, transform, params);

      // для вызова функций блупринта, существует CallFunctionByNameWithArguments 
      // более подробнее можно почитать в оф. документации
      command = FString::Printf( TEXT("UpdateBlockID %d"), blockID );
      wall->CallFunctionByNameWithArguments(*command, debug, this, true);

      x++;
      if (x >= map_width)
      {
        x = 0;
        y++;
      }
    }
  }
  else
    UE_LOG(LogTemp, Error, TEXT("Set BP_Wall value!"));
}

Компилим Ctrl_Shift+B (у меня это на автомате). Ну и наверное пока всё по коду, что нам осталось, это внутри BP_Map, установить переменную bpwallClass. Что мы и сделаем, открывайте его в редакторе.
Делаем мы это в конструкторе, тяните нить (судьбы))) от конструктора и пишите set bp wall остальное она выдаст сам
Изображение
Задайте значение BP_Wall (наш блупринт).
Изображение
ну вот мы и подружили С++ и наши блупринты.

Теперь давайте откроем вкладку Events в BP_Map, там у нас щас стоит только LoadMap, надо ещё добавить блок BuildMap, тянем от LoadMap и пишем BuildMap. Если помните, то мы как раз её описали в CMap и сделали видимой для блупринта.
Изображение
Сделали? Гуд. Компилим блупринт.

Теперь декоративная составляющая, но не менее важная. Так уж получилось что блок стен, дверей, стекла имеет положение. И если рядом поставить два из них в разных направлениях, то они могут не сойтись. Поэтому нам надо сделать так, что если рядом с нашим блоком, стоит какой нибудь блок, мы должна его повернуть. Поэтому открываем BP_Wall, и идем в UpdateBlockID. Вот как раз И для этого мы сделали видимым GetBlockID. Описывать по шагам не буду, просто добейте как на картинке.
Ещё такой момент, у нас по сути аж 4 блока. А у нас сделано лишь 3, как то я упустил этот момент, так что тут он уже исправлен.
Давайте в начале добавим новый блок, который мы упустили, смотрите на значение NewMesh, потому что разница лишь в нём.
Изображение
Значения должны быть BlockWall, BlockWall_01, BlockWall_02_glass, Block_Wall_03_plate

Теперь нажмите ПКМ в пустом месте пространства и наберите Get Actor Location, далее ПКМ по желтому кругу (значению) и там выбираем Split Struct
Изображение
вместо значения вектора, появится привычные обывателю X,Y,Z. Нам нужны от сюда X и Y. По ним мы будем определять позицию в карте. Проще говоря, все блоки ставятся в позиции (X*100, Y*100), если поделить на 100, то как разу будет значение (X,Y) в CMap->Map
Тянем от X и пишем / (знак деления), там выбираем float/float. В появившимся блоке пишем вторым значение 100. Также делаем для Y, должно получится примерно так.
Изображение
Ну и теперь от блоков SetStaticMesh ID блока которых 2,3,4, сделаем такую штуку.
ПКМ в пустом месте и пишем Get All Actors of Class, в поле выбираем наш BP_Map, этот блок ищет все блупринты в мире такого класса и возвращает их (если они вообще есть, а у нас на карте он есть в единственном экземпляре). Возвращает в виде списка, поэтому мы достаем из списка первое же значение. Тянем за OutActors и пишем Get. Так как он возвращает массив типа AActor, нам ещё придется сделать Cast. Тянем синий кружок и пишем Cast To BP_Map.
Изображение
Берем за синий кружок BP_Map и тянем, пишем там GetBlockID (то есть вызываем метод)
Изображение
Чуть чуть отводим вправо блок GetBlockID, ну и подсоединяем наши деленные значения X и Y. Так как GetBlockID(int32 X, int32 Y), просит целые числа, редактор сам сделает перевод из float в int32.
Изображение
Ошибку допустил, ну ничего щас поправим.
И так снова опишу: нам надо знать есть ли блоки от нас по соседству. Сверху и Снизу (остальные нас не интересуют). И если есть, то повернуть нашу стену к ним также. Чтобы рядом стоящие смотрелись едино.
Поэтому всё что нам надо. это из ЦЕЛЫХ значений вычесть 1 в начале по Y (верхняя стена), затем Y+ (нижняя стена от нас).
Теперь от блока GetBlockID тянем и пишем Branch (этот тот же IF в коде, только он может сверять лишь булевые переменные, то есть либо истина, либо ложь).

Тянем от GetBlockID->ReturnVaule (зеленого) и знак >= и результат соединяем с Branch
Я наверное уже не буду писать что от чего тянуть, просто смотрите картинки.
Изображение
Ну и добавим для проверку на нижний блок, в том случае если сверху оказался пустым.
Изображение
Ну и теперь самый важный момент, надо соединить 2,3,4 с нашей созданной цепочкой.
Изображение

Ещё такой момент. Я упустил из виду, когда мы сюда попадаем из конструктора, то blockID уже задан и мы лишь меняем модель. А вот когда мы строим блок из карты, blockID не меняется, это бы надо поправить от тянув  от функции и написав SetBlockID, ну и соеденить значения
Изображение

Ну что, возрадуйтесь!
Давайте дам вам перевести дух...
Вы дошли, добрались до этого гребанного Евереста. Время пришло.
Компилируем блупринт BP_Wall.
Закрываем его и
Запускаем игру. Ну а что вы увидите, останется только между нами 8)

С уважением, Ваш Salamandr ;)

* Для тех кто начал проходить урок до того как появилась 4 страница.
Просьба перекачать файл карты https://drive.google.com/open?id=0Bzl8pH3p1mHRdWx0VlVNdVlVaWc и файл с моделями https://drive.google.com/open?id=0Bzl8pH3p1mHRcFBseWxBekg5cFU

Также, если вы хотите сами поучаствовать в создании этой ММО. Например вы 3д моделлер или текстурщик, или художник, оставляйте координаты в комментариях.
В каждой статье будет упоминание о Вас, о вашей безвозмездной помощи проекту в роли 3д моделлера (к примеру).
Сделаем эту ММО силами форума GameDev.ru все вместе! 8)

Все статьи безвозмедно передаются форуму gamadev.ru с полными полномочиями на исправление ошибок.
PS: Знания это сила! Но лишь тогда, когда ими делятся с другими.

Страницы: 1 2 3 4

#Blockmap, #debug, #MMO, #Tilemap, #Unreal Engine

23 мая 2017 (Обновление: 28 мая 2020)

Комментарии [5]