Проект Blocks на Unreal Engine 4

Проект Blocks

Проект Blocks на Unreal Engine 4

00) Сполер проекат Blocks на Unreal Engine 4


В общем собрал проект и это результат что  у нас получиться в итоге после создания кода на C++ в движке Unreal Engine 4


01) Подготовка редактора и создание заготовок для игры

Если вы умете создавать пустой проект, то можно и пропустить данное видео :) 

1) Создание пустого проекта игры в Unreal Engine 4

2) Подготовка сцены и сохранение ее в виде карты Unreal Engine 4

3) Создание классов которые станут основой игры:

• Пустой класс на C++ игрового режима в Unreal Engine 4

• Пустой класс на C++ игрового контроллера в Unreal Engine 4

• 2 пустых класса на C++ актеров в Unreal Engine 4

4) Настройка редактора на автоматический запуск нашей карты и нашего режима игры как в редакторе так м в собранном проекте.

01) Подготовка редактора и создание заготовок для игры

02) Настраиваем PlayerController на C++ для игры Block на Unreal Engine 4

1) Дополняем класс PlayerController набором функций и переменных.

2) Опишем переменную отображение и скрытие курсора.

3) Опишем функцию скрытия и отображения курсора.

02) Настраиваем PlayerController на C++ для игры Block на Unreal Engine 4

03) Настройка класса GameMode в Unreal Engine 4 на C++

Редактируем режим игры в Unreal Engine на C++

1) Создание конструктора класса

2) Настройка связи игрового режима с контроллером управления 

3) Удаление игрового персонажа из режима игры.

03) Настройка класса GameMode в Unreal Engine 4 на C++

04) Создание актера блока в Unreal Engine для использования в игре

1) Рассчитываем размер блока для отображения его в окне игры 

2) Создаем модель блока в 3d max и экспортируем ее в ресурсы проекта Unreal Engine 4

3) Создаем простые материалы с разным цветом для блока

04) Создание актера блока в Unreal Engine для использования в игре

05) Настройка класса актера в Unreal Engine 4 для использования в игре

1) Описание класса катера на C++ 

2) Добавление свойств UPROPERTY() в класс катера и описание данных свойств

3) Объявление функции CreateBlock()  для создания актера

4) Получаем модель из Content Browser и создаем из нее актера

5) Получаем материал из  Content Browser и покрываем им модель

6) Создаем иерархию актера для отображения его на сцене

05) Настройка класса актера в Unreal Engine 4 для использования в игре

06) Генератор случайного цвета для отображения актеров в Unreal Engine 4

1) Создаем список материалов для актера

2) Создаем функцию генерации случайного цвета актера

06) Генератор случайного цвета для отображения актеров в Unreal Engine 4

07) Добавляем классу актера  на C++,  реакцию на событие нажатия кнопки мышки Unreal Engine 4

1) Создаем функцию обработки события OnClick на C++ в Unreal Engine 4

2) Настраиваем связь класса Actor с событием OnClick на C++ в Unreal Engine 4

07) Добавляем классу актера на C++, реакцию на событие нажатия кнопки мышки Unreal Engine 4

08) Задаем точку старта рисования поля. 

Создание UBoxComponent для задания точки старта рисования карты в Unreal Engine 4

08) Задаем точку старта рисования поля.

9) Генерация игрового поля из Block из Actor на Unreal engine 4

1) Создаем 2 мерный массив для хранения блоков

2) Объявляем размеры блока

3) Получаем точку отсчета поля блоков

4) Проверяем существование карты для создания блоков

5) Создаем блоки на карте основываясь на точке

9) Генерация игрового поля из Block из Actor на Unreal engine 4

10) Настройка передачи сообщений от блока в карту

1) Создание переменных для идентификации блока на карте 

2) Создание ссылки на карту в блоке

3) Описание функции обработки сообщения на карте от блока

4) Вызов данной функции во время щелчка по блоку

10) Настройка передачи сообщений от блока в карту

11) Алгоритм поиска соседних блоков с одинаковым цветом.
1) Создание специальности структуры для хранения координат 

2) Создаем функцию поиска соседних точек на карте

3) Создаем функцию проверки блоков по цвету

4) Обнуляем цвет найденных блоков

11) Алгоритм поиска соседних блоков с одинаковым цветом.

12) Добавляем блокам физику и ограничиваем удаление блоков до 3 в ряд

12) Добавляем блокам физику и ограничиваем удаление блоков до 3 в ряд

13) Добавляем в игре вывод очков набранных игроком

1) Вывод текста на экран 

2) Привязка текста к блоку карты 

3) Позиционирование и масштабирование текста

13) Добавляем в игре вывод очков набранных игроком

14) Компиляция проекта
Создание проекта из Unreal engin редактора под Windows 64.

Создание отдельного exe файла запускающего нашу игры без Unreal engine editor

14) Компиляция проекта

Исходные коды проекта

Класс MyPlayerController - класс настройки управления 

 MyPlayerController.cpp MyPlayerController.h
 

Описание кода класса

#include "Blocks.h"

#include "MyPlayerController.h"

AMyPlayerController::AMyPlayerController() 

{

//показываем курсор

bShowMouseCursor = true;

//включаем реакцию на клик мышкой

bEnableClickEvents = true;

//показываем курсор на экране 

DefaultMouseCursor = EMouseCursor::Crosshairs;

}

 

Класс описания управления

#pragma once

#include "GameFramework/PlayerController.h"

#include "MyPlayerController.generated.h"

UCLASS()

class BLOCKS_API AMyPlayerController : public APlayerController

{

GENERATED_BODY()

public:AMyPlayerController();

};

Класс BlocksGameMode - класс описания игрового режима 

 MyGameMode.cpp MyGameMode.h
 

Игровой режим исходный код

#include "Blocks.h"

#include "BlocksGameMode.h"

#include "MyPlayerController.h"

ABlocksGameMode::ABlocksGameMode() 

{

//игрок по умолчанию отсутсвует 

DefaultPawnClass = NULL;

//управление игрой будет использовать свой класс 

PlayerControllerClass = AMyPlayerController::StaticClass();

}

 

заголовочный файл игрового режима

#pragma once

#include "GameFramework/GameMode.h"

#include "MyGameMode.generated.h"

/**

 * 

 */

UCLASS()

class MYBLOKS_API AMyGameMode : public AGameMode

{

GENERATED_BODY()

public:

//обьявляем конструктор класса

AMyGameMode();

};


Класс MyActor - класс описывающий один блок игрового поля
 MyBox.cpp MyBox.h
 

Описание класса блока

// Fill out your copyright notice in the Description page of Project Settings.

#include "MyBloks.h"

#include "MyBox.h"

//потключаем класс карты 

#include "MyMap.h"

// конструктор класса и задание начальных параметров

AMyBox::AMyBox()

{

 /** 

включаем обновление информации об актере каждый кадр 

если установить False обновление не будет происходить 

*/

PrimaryActorTick.bCanEverTick = true;

//функция создания актера 

CreateBlock();

//загружаем список материалов

LoadListMaterial();

}

// функция срабатывает во время создания пешки в игре

void AMyBox::BeginPlay()

{

Super::BeginPlay();

RandomColor();

}

// таймер обновляющий информацию каждый кадр

void AMyBox::Tick(float DeltaTime)

{

Super::Tick(DeltaTime);

//задаем цвет 

BlockMesh->SetMaterial(0, MyListMaterial[IndexCurrentMateril]);

}

//функция создания актера 

void AMyBox::CreateBlock()

{

// создаем корневей элемент для сцены

DummyRoot = CreateDefaultSubobject<USceneComponent>(TEXT("Dummy0"));

//пристваиваем созданный элемент переменной 

RootComponent = DummyRoot;

//получаем модель из обозревателя рессурсов 

class  UStaticMesh* BlocStatickMesh;

//получаем модель из обозревателя рессурсов 

BlocStatickMesh = ConstructorHelpers::FObjectFinderOptional<UStaticMesh>(TEXT("StaticMesh'/Game/MyBlockActor.MyBlockActor'")).Get();

//задаем имя блока

BlockMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BlockMesh0"));

//загружаем блок в UStaticMeshComponent

BlockMesh->SetStaticMesh(BlocStatickMesh);

//загружаем синий материал                                                

tempMaterial = ConstructorHelpers::FObjectFinderOptional<UMaterial>(TEXT("Material'/Game/RedMaterial.RedMaterial'")).Get();

BlockMesh->SetMaterial(0, tempMaterial);

//Указываем что блок будет прикреплен к коневому элементу сцены

BlockMesh->AttachTo(DummyRoot);

//свзяываем событие щелчека мышкой по блоку с функцией обработки щелчка

BlockMesh->OnClicked.AddDynamic(this, &AMyBox::BlockClicked);

}

//функция дла загрузки списка материалов

void AMyBox::LoadListMaterial()

{

//загружаем синий материал                                                

tempMaterial = ConstructorHelpers::FObjectFinderOptional<UMaterial>(TEXT("Material'/Game/TransperantMaterial.TransperantMaterial'")).Get();

//добавляем материал в список 

MyListMaterial.Add(tempMaterial);

//загружаем синий материал                                                

tempMaterial = ConstructorHelpers::FObjectFinderOptional<UMaterial>(TEXT("Material'/Game/BlueMaterial.BlueMaterial'")).Get();

//добавляем материал в список 

MyListMaterial.Add(tempMaterial);

//загружаем синий материал                                                

tempMaterial = ConstructorHelpers::FObjectFinderOptional<UMaterial>(TEXT("Material'/Game/GreenMaterial.GreenMaterial'")).Get();

//добавляем материал в список 

MyListMaterial.Add(tempMaterial);

//загружаем синий материал                                                

tempMaterial = ConstructorHelpers::FObjectFinderOptional<UMaterial>(TEXT("Material'/Game/RedMaterial.RedMaterial'")).Get();

//добавляем материал в список 

MyListMaterial.Add(tempMaterial);

//загружаем синий материал                                                

tempMaterial = ConstructorHelpers::FObjectFinderOptional<UMaterial>(TEXT("Material'/Game/WiteMaterial.WiteMaterial'")).Get();

//добавляем материал в список 

MyListMaterial.Add(tempMaterial);

//загружаем синий материал                                                

tempMaterial = ConstructorHelpers::FObjectFinderOptional<UMaterial>(TEXT("Material'/Game/Yello.Yello'")).Get();

//добавляем материал в список 

MyListMaterial.Add(tempMaterial);

}

void AMyBox::RandomColor()

{

//получим размер массива из блоков

int32 ListMaterialLengh = MyListMaterial.Num() - 1;

//задаем случайны цвет блока от 1 до размер массива блоков -1

IndexCurrentMateril = FMath::RandRange(1, ListMaterialLengh);

}

void AMyBox::BlockClicked(UPrimitiveComponent* ClickedComp)

{

//зададим блоку случайный цвет 

//RandomColor();

//IndexCurrentMateril = 0;

OwnMap->SelectBlock(X, Y);

}

 

Заголовочный файл описания блока

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/Actor.h"

#include "MyBox.generated.h"

UCLASS()

class MYBLOKS_API AMyBox : public AActor

{

GENERATED_BODY()

public:

// конструктор класса задание основных параметров блока

AMyBox();

// срабатывает при создании блока на сцене

virtual void BeginPlay() override;

//функция срабатываем каждый кадр 

virtual void Tick( float DeltaSeconds ) override;

/** Корневая точка модели */

UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class USceneComponent* DummyRoot;

/** Наш игровой блок */

UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class UStaticMeshComponent* BlockMesh;

//переменная получения материала из обозревателя ресурсов

UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) class UMaterial* tempMaterial;

//функция создания блока 

void CreateBlock();

UPROPERTY()int32 IndexCurrentMateril; //текущий цвет материала

//список материалов для актера

TArray<class UMaterial*> MyListMaterial;

//функция дла загрузки списка материалов

void LoadListMaterial();

//случайный выбор материала

void RandomColor();

//функция обработки щелчка мышкой по блоку 

UFUNCTION() void BlockClicked(UPrimitiveComponent* ClickedComp);

//Переменные для хранение позиции данного блока в сетке 

UPROPERTY()int32 X;//позиция по Х

UPROPERTY()int32 Y;//позиция по Y

UPROPERTY() class AMyMap* OwnMap;//Карта кто создал блок

};


Класс GameMap  - класс создания карты игры
 MyMap.cpp MyMap.h
 

Исходный код создания поля блоков

// Fill out your copyright notice in the Description page of Project Settings.

#include "MyBloks.h"

#include "MyMap.h"

//потключаем класс MyBox к классу карты

#include "MyBox.h"

//размер поля игрока 

const int32 COL = 36,  //количество блоков по горизонтали

            ROW = 22;  //количество блоков по вертикали 

  //создание поля нужного размера 

class AMyBox* Map[COL][ROW];

//обьявим структуру хранения координат проверяемой и удаляемых точек

struct MyPoint

{

int32 XX, YY; //координаты блока у которого будем проверять цвет 

 //конструктор структуры точки 

MyPoint()

{

XX = 0; YY = 0;

}

//Переопределение оператора сравнения 

inline bool operator == (MyPoint a)

{

//возвращаем результат сравнение полей

return ((a.XX == XX) && (a.YY == YY));

}

};

//список блоков на удаление

TArray<MyPoint> DeletePretindent;

//список точек на проверку 

TArray<MyPoint> TestPointList(MyPoint coord)

{

//структура, хранения и  заноса в список подходящей точки 

MyPoint T;

//список точек которые нужно проверить

TArray<MyPoint> Result;

/*  __

___ __ __

_X_ __ __

__

*/

//рассчитываем координаты точки с права

T.XX = coord.XX - 1;//заполняем Х

T.YY = coord.YY;//заполняем У

//проверяем левую сторону поля X >=0

if (T.XX >= 0)  Result.Add(T);//добавляем точку в список  

/* __

__ __ ___

__ __ _X_

  __

*/

//рассчитываем координаты точки слева

T.XX = coord.XX + 1;//заполняем Х

T.YY = coord.YY;//заполняем У

//проверяем правую сторону X< количество столбцов

if (T.XX < COL)  Result.Add(T);//добавляем точку в список  

/*  ___

___ _X_ ___

___ ___ ___

___

*/

//рассчитываем координаты точки сверху

T.XX = coord.XX;//заполняем Х

T.YY = coord.YY + 1;//заполняем У

//проверяем правую сторону Y < количества строк 

if (T.YY < ROW)  Result.Add(T); //добавляем точку в список

/*  ___

___ ___ ___

___ ___ ___

_X_

*/

//рассчитываем координаты точки снизу

T.XX = coord.XX;//заполняем Х

T.YY = coord.YY - 1;//заполняем У

//проверяем левую сторону поля Y >=0

if (T.YY >= 0)   Result.Add(T); //добавляем точку в список 

//возвращаем результат 

return Result;

}

// функция вернет индекс найденного элемента

int32 SerchPoint(MyPoint P)

{

//перебираем все собранные в массиве блоки 

for (int s = 0; s < DeletePretindent.Num(); s++)

//если нашли такую же точку

if (P == DeletePretindent[s])

//вернем номер точки 

return s;

//вернем -1 если не нашли точку 

return -1;

}

//функция проверки блока 

void TestBlok(int32 _X, int32 _Y, int32 IndexColor)

{

MyPoint coord; //собираем точку 

coord.XX = _X; //задаем кординату по Х

coord.YY = _Y; //задаем координату по Y

//проверяем есть ли такая точка в списке

int32 Find = SerchPoint(coord);

//если на нешли то есть резон проверять точку 

if (Find == -1)

{

//получим цвет точки 

int32 ColorIndex = Map[_X][_Y]->IndexCurrentMateril;

//Если цвет подходит то будем что то делать

if (IndexColor == ColorIndex)

{

//добавляем претиндента в список 

DeletePretindent.Add(coord);

//расчитываем соседние точки 

TArray<MyPoint> test = TestPointList(coord);

//получаем количество найденных точек 

for (int TestPoint = 0; TestPoint < test.Num(); TestPoint++)

{

//перебираем список точек с проверкой точек

TestBlok(test[TestPoint].XX, test[TestPoint].YY, IndexColor);

}

}

}

}

// Конструктор класса Actor и задание значений по умолчанию

AMyMap::AMyMap()

{

 // Задает нужно ли обновлять данные актера каждый кадр игры

PrimaryActorTick.bCanEverTick = true;

//создаем блок 

SpawnPoint = CreateDefaultSubobject<UBoxComponent>(TEXT("PointSpawnMyMap"));

//указываем что это будет корневая точка модели 

RootComponent = SpawnPoint;

GreateMyScoreText();

}

// функция срабатывает во время создания актера на сцене

void AMyMap::BeginPlay()

{

Super::BeginPlay();

//запустим генерацию карты

GenerateMap();

}

// функция вызываеться каждый кадр 

void AMyMap::Tick( float DeltaTime )

{

Super::Tick( DeltaTime );

//MoveBlockDown();

}

//создаем поле игры во время старта игры

void AMyMap::GenerateMap()

{

//координаты ширины и высоты блока 

float DZ = 1.05f,  

 DY = 1.05f;

//получаем точку начала координат сохраняем для востановления в будущем

FVector StartPointtmp = SpawnPoint->Bounds.Origin;

//переменная по которой будем расчитывать данные блоки 

FVector StartPoint = SpawnPoint->Bounds.Origin;

FRotator SpawnRotate = FRotator(0, 0, 0);//задаем позицию вращения блоков

FActorSpawnParameters SpawnParam;//настраиваем обьект создания актеров

SpawnParam.Owner = this;//указываем кто создает обьект

SpawnParam.Instigator = Instigator;//кто являеться инициатором создания блока 

class UWorld* W = GetWorld();

if (W)

{

//двигаемся вверх по вертикали

for (int32 yy = 0; yy < ROW; yy++)

{

for (int32 xx = 0; xx < COL; xx++)

{

//создаем блок и сохраняем его в масив

Map[xx][yy] = GetWorld()->SpawnActor<AMyBox>(StartPoint, SpawnRotate);

//передаем блоку его статус 

Map[xx][yy]->X = xx;//позиция по Х

Map[xx][yy]->Y = yy;//позиция по Y

Map[xx][yy]->OwnMap = this;//Карта кто создал блок

//расчитываем нокую координату по вертикали 

StartPoint.Y += DY;

}

//возвращаем блоки на начальную позицию

StartPoint.Y = StartPointtmp.Y;

//задаем позицию по вертикали

StartPoint.Z += DZ;

}

}

}

//функция которая будет получать координаты блока на который нажал игрок

void AMyMap::SelectBlock(int32 X, int32 Y)

{

//обнуляем блок из класса Map

//Map[X][Y]->IndexCurrentMateril = 0;

//обнуляем список претиндентов 

DeletePretindent.Empty();

//получим цвет точки 

int32 ColorIndex = Map[X][Y]->IndexCurrentMateril;

//запускаем поиск блоков

TestBlok(X, Y, ColorIndex);

//если блоков найдено больше 2 значит удаляем их

if (DeletePretindent.Num() > 2)

{

//обнулим блоки

for (int b = 0; b < DeletePretindent.Num(); b++)

{

//обнуляем блок из класса Map

Map[DeletePretindent[b].XX][DeletePretindent[b].YY]->IndexCurrentMateril = 0;

}

ScorePlayer += DeletePretindent.Num();

//обновляем текстовые поля 

MyScoreText->SetText(FText::AsNumber(ScorePlayer));

}

while (SerchZeroBloks())

{

MoveBlockDown();

}

}

/** функция движения блоков вниз */

void AMyMap::MoveBlockDown()

{

//перебираем все блоки поля 

for (int32 yy = 0; yy < ROW; yy++)

{

for (int32 xx = 0; xx < COL; xx++)

{

//если есть пустой блок

if (Map[xx][yy]->IndexCurrentMateril == 0)

{

//расчитываем новую точку 

int32 DY = yy + 1;

//проверяем что над нами находиться

if (DY < ROW)

{

//забираем цвет у верхнего блока 

Map[xx][yy]->IndexCurrentMateril = Map[xx][DY]->IndexCurrentMateril;

//Затираем цвет верхнего блока

Map[xx][DY]->IndexCurrentMateril = 0;

}

else

{

//задаем блоку случайный цвет 

Map[xx][yy]->RandomColor();

}

}

}

}

}

/** функция проверки пустых блоков */

bool AMyMap::SerchZeroBloks()

{

//перебираем все блоки поля 

for (int32 yy = 0; yy < ROW; yy++)

{

for (int32 xx = 0; xx < COL; xx++)

{

//если есть пустой блок то возвращаем true

if (Map[xx][yy]->IndexCurrentMateril == 0) return true;

}

}

//если нет пустых блоков значит льжь

return false;

}

void AMyMap::GreateMyScoreText()

{

//создаем обьект текста текст

MyScoreText = CreateDefaultSubobject<UTextRenderComponent>(TEXT("ScoreText"));

//получаем начальные координаты карты 

FVector StartPointtmp = SpawnPoint->Bounds.Origin;

StartPointtmp.Z -= 2.f; //опускаем координату по Z вниз на 1 сантиметр 

StartPointtmp.Y += 15.f; //разместим по центру блока

//разворачиваем текст на 180 градусов 

FRotator SpawnRotate = FRotator(0, 180, 0);

//задаем угол поворота текста  относительно камеры

MyScoreText->SetRelativeRotation(SpawnRotate);

//задаем координаты для текста

MyScoreText->SetRelativeLocation(StartPointtmp);

MyScoreText->SetXScale(0.05f);

MyScoreText->SetYScale(0.05f);

//привязываем текст к корневой точке нашей карты

MyScoreText->AttachTo(SpawnPoint);

//заполняем текст символом 0

MyScoreText->SetText("123456789");

}

 

Описание заголовочного файла класса создания поля

#pragma once

#include "GameFramework/Actor.h"

#include "MyMap.generated.h"

UCLASS()

class MYBLOKS_API AMyMap : public AActor

{

GENERATED_BODY()

public:

// Конструктор класса Actor и задание значений по умолчанию

AMyMap();

// функция срабатывает во время создания актера на сцене

virtual void BeginPlay() override;

// функция вызываеться каждый кадр 

virtual void Tick( float DeltaSeconds ) override;

//обьявляем точку отсчета создания поля

UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "MySpawnPoint", meta = (AllowPrivateAccess = "true")) class UBoxComponent* SpawnPoint;

//создаем поле игры во время старта игры

void GenerateMap();

//функция которая будет получать координаты блока на который нажал игрок

UFUNCTION() void SelectBlock(int32 X, int32 Y);

//во время обновления экрана сдвигаем блоки вниз если они есть 

void MoveBlockDown();

//провека есть ли пустые блоки 

bool SerchZeroBloks();

//текст с количеством очков опыта

class UTextRenderComponent* MyScoreText;

//функция создания текста

void GreateMyScoreText();

//количество блоков разбитых 

int32 ScorePlayer = 0;

};


144 0 850 1
0
RENDER.RU