Семь правил хорошего комментария к коммиту

– Отделяйте заголовок от тела пустой строкой
– Ограничивайте заголовок 50 символами
– Пишите заголовок с заглавной буквы
– Не ставьте точку в конце заголовка
– Используйте повелительное наклонение в заголовке
– Переходите на следующую строку в теле на 72 символах
– В теле отвечайте на вопросы что и почему, а не как

 

Рекоммендация по написанию коммитов https://habr.com/ru/post/416887/

Полезный сайт по unreal engine 4

http://www.acclivitygamestudios.com/?p=4386 сборник рецептов

http://www.youtube.com/channel/UCIEqFMmWhxF4yA4gowhFjNA/videos видео туториал

Пока все, потом дополню

UTextRenderComponent – функция рендеринга текста

 

Рендер текста с заданым шрифтом. Контент содержит обычный шрифт, аттрибуты, выравнивание, цвет и так далее.

UCLASS(ClassGroup=Rendering,
       HideCategories=(Object, LOD, Physics, TextureStreaming, Activation, "Components|Activation", Collision),
       EditInlineNew, Meta=(BlueprintSpawnableComponent=""))
class UTextRenderComponent : public UPrimitiveComponent

 

 

Module Engine
Header Runtime/Engine/Classes/Components/TextRenderComponent.h

 

Контроль камер в игре

Game-Controlled Cameras

Это руководство покажет как сделать активной камеру, и переместиться от одной активной камеры к другой.

В итоге должно получиться следующее

[wpdevart_youtube]hwErvhNdc9c[/wpdevart_youtube]


 

1) Place Cameras in the World

Размещение камер в мире

1) Начнём данный урок с создания базового проекта с базовым контентом который будет иметь название “HowTo_AutoCamera”. Первое что необходимо сделать, это разместить две камеры в нашем мире. Существует большое количество способов по добавлению камер в мир, мы сделаем это достаточно распространённым способом. Чтоб разместить первую камеру, перейдите в вкладку Modes  и в Placement Browser, то что справа кликните Place, или Shift+1. В разделе классов вы найдёте Camera actor. Перетащите камеру на уровень и расположите камеру так чтобы видеть достаточно удобно все предметы на сцене.

PlaceCameraActor

Когда вы всё сделаете правильно, по идее вы должны видеть картинку в картинке, так как будто вы снимаете самого себя.

CameraOnePlacement

2) При размещении второй камеры мы будем использовать метода которые дадут нам больше контроля. Для начала кликните на Basic в Mode(табе) на куб и перетащите его на уровень редактирования.

PlaceCube

3) Когда переместите наш куб на уровень, добавьте CameraComponent кликнув “Add” в компонентах в панели “Details”. Теперь вы можете установить позицию, а так же угол, вращая CameraComponent, что даст нам другой вид на нашу сцену, чем камера расположенная ранее.

CameraTwoPlacement

4) Теперь нам необходимо настроить наши камеры (CameraComponen) на плавный переход между камерами. Это делается в Constrain Aspect Ratio в менб details

CameraAspect

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


2. Control Camera View in C++

1) Теперь у нас всё готово чтобы создать свой класс для управления переходом между камерами. Для этого урока мы расширим класс Actor и назовём его  CameraDirector.NameActorClass

2) В файл CameraDirector.h добавим следующий код для определения класса:

UPROPERTY(EditAnywhere)
AActor* CameraOne;

UPROPERTY(EditAnywhere)
AActor* CameraTwo;

float TimeToNextCameraChange;

3) В файл CameraDirector.cpp добавить следующий код, прям по дерективой #include

#include "Kismet/GameplayStatics.h"

Заголовок GameplayStatics даёт нам доступ к некоторым полезным функциям, один из которых нам необходим для текущего урока. Когда вы всё сделаете , добавьте следующий код в метод ACameraDirector::Tick

const float TimeBetweenCameraChanges = 2.0f;
const float SmoothBlendTime = 0.75f;
TimeToNextCameraChange -= DeltaTime;
if (TimeToNextCameraChange <= 0.0f)
{
    TimeToNextCameraChange += TimeBetweenCameraChanges;

    // Find the actor that handles control for the local player.
    APlayerController* OurPlayerController = UGameplayStatics::GetPlayerController(this, 0);
    if (OurPlayerController)
    {
        if ((OurPlayerController->GetViewTarget() != CameraOne) && (CameraOne != nullptr))
        {
            // Cut instantly to camera one.
            OurPlayerController->SetViewTarget(CameraOne);
        }
        else if ((OurPlayerController->GetViewTarget() != CameraTwo) && (CameraTwo != nullptr))
        {
            // Blend smoothly to camera two.
            OurPlayerController->SetViewTargetWithBlend(CameraTwo, SmoothBlendTime);
        }
    }
}

Этот код заставит нас изменить вид просмотр игрока между камерами каждые 3 секунды.

4) Наш код подготовлен для компиляции. Откомпилируйте код нажав кнопку Compile в Unreal Engine

 

3. Place a Camera Director in the World

1) После того как откомпилируете код, перетащите Экземпляр нашего нового класса из “Content Browser” в редактор уровня.
CameraDirectorInContentBrowser

2) Далее нам необходимо установить переменные CameraOne и CameraTwo. Найдите наш CameraDirector в панели и перейдите в панель Details. CameraDirectorDetails111

Кликните на выпадающие боксы которые имеют значение “None” и установим переменные Cube и CameraActor созданные ранее.CameraDirectorDetails2

3) Если вы нажмёте клавишу PLAY  то увидим камеру привязанную к точке.

CameraOneView3

А потом плавно передвигаемся к другой точке.CameraTwoView4

Через несколько секунд камера вернётся в исходное положение.

MyPawn.h

#pragma once

#include "GameFramework/Actor.h"
#include "CameraDirector.generated.h"

UCLASS()
class HOWTO_AUTOCAMERA_API ACameraDirector : public AActor
{
    GENERATED_BODY()

public: 
    // Sets default values for this actor's properties
    ACameraDirector();

    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

    // Called every frame
    virtual void Tick( float DeltaSeconds ) override;

    UPROPERTY(EditAnywhere)
    AActor* CameraOne;

    UPROPERTY(EditAnywhere)
    AActor* CameraTwo;

    float TimeToNextCameraChange;
};

MyPawn.cpp

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.

#include "HowTo_AutoCamera.h"
#include "CameraDirector.h"
#include "Kismet/GameplayStatics.h"

// Sets default values
ACameraDirector::ACameraDirector()
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void ACameraDirector::BeginPlay()
{
    Super::BeginPlay();

}

// Called every frame
void ACameraDirector::Tick( float DeltaTime )
{
    Super::Tick( DeltaTime );

    const float TimeBetweenCameraChanges = 2.0f;
    const float SmoothBlendTime = 0.75f;
    TimeToNextCameraChange -= DeltaTime;
    if (TimeToNextCameraChange <= 0.0f)
    {
        TimeToNextCameraChange += TimeBetweenCameraChanges;

        //Find the actor that handles control for the local player.
        APlayerController* OurPlayerController = UGameplayStatics::GetPlayerController(this, 0);
        if (OurPlayerController)
        {
            if (CameraTwo && (OurPlayerController->GetViewTarget() == CameraOne))
            {
                //Blend smoothly to camera two.
                OurPlayerController->SetViewTargetWithBlend(CameraTwo, SmoothBlendTime);
            }
            else if (CameraOne)
            {
                //Cut instantly to camera one.
                OurPlayerController->SetViewTarget(CameraOne);
            }
        }
    }
}

Если у Вас всё получилось, попробуйте самостоятельно:

  • Прикрепить камеру к движущему  Actor или выстрелу
  • Использовать массив переменных для создания множества камер, вместо двух

Оригинал статьи

UInputComponent::BindAction

UInputComponent::BindAction

Делегирует связь определённого действия на функцию, Указанную в настройках проекта. Различные действия между собой не связаны.

Можно например отслеживать клавиши пользователя и вызывать при нажатии определённую функцию. Пример здесь

Синтаксис

template<class UserClass>
FInputActionBinding & BindAction
(
    const FName ActionName,
    const EInputEvent KeyEvent,
    UserClass * Object,
    typename FInputActionHandlerSignature::TUObjectMethodDelegate< UserClass >::FMethodPtr Func
)

Пример кода

    // The bindings are defined within the editor  
    // When any keys/buttons bound to the "Jump" binding are pressed call a function called Jump.   
    InputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);  
    // When any keys/buttons bound to the "Jump" binding are released call a function called StopJumping  
    InputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);

Первый параметр, это назначенная клавиша

Второй, параметр отвечает, нажата ли клавиша(IE_Pressed) или на оборот, не задействована(IE_Released)

Четвёртый параметр отвечает за вызываемую функцию.

Module Engine
Header Runtime/Engine/Classes/Components/InputComponent.h

Ссылка на док

ADefaultPawn::SetupPlayerInputComponent

ADefaultPawn::SetupPlayerInputComponent

Вызывается при нажатии клавиш. Необходимо например при привязке игровой логики и ввода пользовательских клавиш.

Пример можно посмотреть здесь (ссылка)

virtual void SetupPlayerInputComponent
(
    UInputComponent * InInputComponent
)

 

Module Engine
Header Runtime/Engine/Classes/GameFramework/DefaultPawn.h
Source Runtime/Engine/Private/DefaultPawn.cpp

 

Player Input and Pawns 3 часть

Связывание игровой логики и действий пользователя через программирование в unreal

Program and Bind Game Actions

1) В visual studio необходимо открыть файл MyPawn.h  и добавить в него следующий код в конце определения всех функций.

//Input functions
void Move_XAxis(float AxisValue);
void Move_YAxis(float AxisValue);
void StartGrowing();
void StopGrowing();

//Input variables
FVector CurrentVelocity;
bool bGrowing;

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

2) Переключившись на MyPawn.cpp нам необходимо запрограммировать наши функции которые мы объявили раньше.

Добавьте следующий код:

void AMyPawn::Move_XAxis(float AxisValue)
{
    // Move at 100 units per second forward or backward
    CurrentVelocity.X = FMath::Clamp(AxisValue, -1.0f, 1.0f) * 100.0f;
}

void AMyPawn::Move_YAxis(float AxisValue)
{
    // Move at 100 units per second right or left
    CurrentVelocity.Y = FMath::Clamp(AxisValue, -1.0f, 1.0f) * 100.0f;
}

void AMyPawn::StartGrowing()
{
    bGrowing = true;
}

void AMyPawn::StopGrowing()
{
    bGrowing = false;
}

В коде мы используем FMath::Clamp который промежуток входных данных (от -1 до +1), за пределы которых запрещено отходить. В текущем примере это не являеться какой либо проблемой, но в других случаях, при нескольких различных входных данных(при нескольких клавишах при определяющих движение в определённом направлении) это могло бы вызвать определённую проблему, например если игрок нажал сразу несколько клавиш одновременно. Для примера: когда определены две клавиши для движения в одном направлении, при одновременном зажатии которых игрок двигался бы в два раза быстрее.

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

Добавьте следующий код внутрь AMyPawn::SetupPlayerInputComponent

// Respond when our "Grow" key is pressed or released.
InputComponent->BindAction("Grow", IE_Pressed, this, &AMyPawn::StartGrowing);
InputComponent->BindAction("Grow", IE_Released, this, &AMyPawn::StopGrowing);

// Respond every frame to the values of our two movement axes, "MoveX" and "MoveY".
InputComponent->BindAxis("MoveX", this, &AMyPawn::Move_XAxis);
InputComponent->BindAxis("MoveY", this, &AMyPawn::Move_YAxis);

4) Теперь у нас есть переменные которые обновляются при получении входных данных.Всё что нам остаётся сделать это написать код, который будет меняться каждый кадр.

Добавьте следующий код в AMyPawn::Tick:

// Handle growing and shrinking based on our "Grow" action
{
    float CurrentScale = OurVisibleComponent->GetComponentScale().X;
    if (bGrowing)
    {
        // Grow to double size over the course of one second
        CurrentScale += DeltaTime;
    }
    else
    {
        // Shrink half as fast as we grow
        CurrentScale -= (DeltaTime * 0.5f);
    }
    // Make sure we never drop below our starting size, or increase past double size.
    CurrentScale = FMath::Clamp(CurrentScale, 1.0f, 2.0f);
    OurVisibleComponent->SetWorldScale3D(FVector(CurrentScale));
}

// Handle movement based on our "MoveX" and "MoveY" axes
{
    if (!CurrentVelocity.IsZero())
    {
        FVector NewLocation = GetActorLocation() + (CurrentVelocity * DeltaTime);
        SetActorLocation(NewLocation);
    }
}

5) После компиляции нашего кода мы можем вернуться в редактор Unreal и запустите команду play. Теперь, если вы сделали всё правильно, то вы будете полностью управлять вашим предметом. Если удерживать клавишу пробел, предмет будет рости в размере, соответственно если отпустить, предмет будет уменьшаться. Управление предметом можно клавишами “WASD”.

PlayingGame1 PlayingGame2

Окончательный код:

MyPawn.h

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "GameFramework/Pawn.h"
#include "MyPawn.generated.h"

UCLASS()
class HOWTO_PLAYERINPUT_API AMyPawn : public APawn
{
    GENERATED_BODY()

public:
    // Sets default values
    AMyPawn();

    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

    // Called every frame
    virtual void Tick(float DeltaSeconds) override;

    // Called to bind functionality to input
    virtual void SetupPlayerInputComponent(class UInputComponent* InputComponent) override;

    UPROPERTY(EditAnywhere)
    USceneComponent* OurVisibleComponent;

    // Input functions
    void Move_XAxis(float AxisValue);
    void Move_YAxis(float AxisValue);
    void StartGrowing();
    void StopGrowing();

    // Input variables
    FVector CurrentVelocity;
    bool bGrowing;
};

MyPawn.cpp

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.

#include "HowTo_PlayerInput.h"
#include "MyPawn.h"

// Sets default values
AMyPawn::AMyPawn()
{
    // Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

    // Set this pawn to be controlled by the lowest-numbered player
    AutoPossessPlayer = EAutoReceiveInput::Player0;

    // Create a dummy root component we can attach things to.
    RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
    // Create a camera and a visible object
    UCameraComponent* OurCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("OurCamera"));
    OurVisibleComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("OurVisibleComponent"));
    // Attach our camera and visible object to our root component. Offset and rotate the camera.
    OurCamera->AttachTo(RootComponent);
    OurCamera->SetRelativeLocation(FVector(-250.0f, 0.0f, 250.0f));
    OurCamera->SetRelativeRotation(FRotator(-45.0f, 0.0f, 0.0f));
    OurVisibleComponent->AttachTo(RootComponent);
}

// Called when the game starts or when spawned
void AMyPawn::BeginPlay()
{
    Super::BeginPlay();

}

// Called every frame
void AMyPawn::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    // Handle growing and shrinking based on our "Grow" action
    {
        float CurrentScale = OurVisibleComponent->GetComponentScale().X;
        if (bGrowing)
        {
            // Grow to double size over the course of one second
            CurrentScale += DeltaTime;
        }
        else
        {
            // Shrink half as fast as we grow
            CurrentScale -= (DeltaTime * 0.5f);
        }
        // Make sure we never drop below our starting size, or increase past double size.
        CurrentScale = FMath::Clamp(CurrentScale, 1.0f, 2.0f);
        OurVisibleComponent->SetWorldScale3D(FVector(CurrentScale));
    }

    // Handle movement based on our "MoveX" and "MoveY" axes
    {
        if (!CurrentVelocity.IsZero())
        {
            FVector NewLocation = GetActorLocation() + (CurrentVelocity * DeltaTime);
            SetActorLocation(NewLocation);
        }
    }
}

// Called to bind functionality to input
void AMyPawn::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
    Super::SetupPlayerInputComponent(InputComponent);

    // Respond when our "Grow" key is pressed or released.
    InputComponent->BindAction("Grow", IE_Pressed, this, &AMyPawn::StartGrowing);
    InputComponent->BindAction("Grow", IE_Released, this, &AMyPawn::StopGrowing);

    // Respond every frame to the values of our two movement axes, "MoveX" and "MoveY".
    InputComponent->BindAxis("MoveX", this, &AMyPawn::Move_XAxis);
    InputComponent->BindAxis("MoveY", this, &AMyPawn::Move_YAxis);
}

void AMyPawn::Move_XAxis(float AxisValue)
{
    // Move at 100 units per second forward or backward
    CurrentVelocity.X = FMath::Clamp(AxisValue, -1.0f, 1.0f) * 100.0f;
}

void AMyPawn::Move_YAxis(float AxisValue)
{
    // Move at 100 units per second right or left
    CurrentVelocity.Y = FMath::Clamp(AxisValue, -1.0f, 1.0f) * 100.0f;
}

void AMyPawn::StartGrowing()
{
    bGrowing = true;
}

void AMyPawn::StopGrowing()
{
    bGrowing = false;
}

 

Ссылка на оригинал статьи

Если есть вопросы, задавайте их в комментариях.

GENERATED_BODY() или GENERATED_UCLASS_BODY() Разное поведение

Пытаясь собрать проект, после создания пауна или актёра, проект просто ругался в студии и создаваться на отрез отказывался. После долгих манипуляций, я выяснил, что причина была в том что он не мог сгенерировать файл по умолчанию который прописывается в заголовке и по факту не существует(генерируется после старта сборки проекта) Причина до банальности проста, надо заменить GENERATED_BODY() на GENERATED_UCLASS_BODY().

Данную особенность в unreal engine я заметил достаточно давно, но решил разобраться с чем связано это и наткнулся на пост, процитирую.

Hello, ubi

Please note that with GENERATED_BODY(), a constructor is no longer necessary for each class (however, if you need a constructor, you can declare and define it as usual). The other difference is that, in comparison to GENERATED_UCLASS_BODY(), GENERATED_BODY() doesn’t have the public specifier in it, so any class members that are declared after it are private by default (you can explicitly declare them as public). In your situation, please make sure that you have your constructor declared and defined correctly:

     //.h file
     //...
         GENERATED_BODY()
         
     public:
         AFPSGameMode(const class FObjectInitializer& ObjectInitializer);
     
     // .cpp file
     AFPSGameMode::AFPSGameMode(const class FObjectInitializer& ObjectInitializer)
     {
            // constructor functionality
     }

Простыми словами. Все классы по умолчанию в С++ являются приватными. Обявляя или переопределяя новый класс, вы его должны определить как публичный, иначе проект не скомпрометируется.

Если у вас есть необходимость скомпилировать класс с приватным методом доступа в Unreal необходимо прописывать GENERATED_UCLASS_BODY(). Для публичных классов следует ставить макрос GENERATED_BODY().

 

Player Input and Pawns 2 часть

Первая часть Настройка Pawn(Customize a Pawn)

Конфигурация игрового управления в unreal engine 4

Конфигурация игрового управления (Configure Game Input)

Есть два типа отображения игрового входа, это действие и оси.

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

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

Управление меняется прям в проекте, через редактирование текущего проекта.

1) В Unreal Engine редакторе в меню “edit” необходимо найти пункт “Project Settings” EditProjectSettings

После открытия меню, необходимо найти опцию “input” из раздела “engine”. Мы можем расширить категорию связью(Bindings), добавив ещё какое  действие отображение (Action Mapping) и второе отображение осей (Axis Mappings).

Знак плюса после Action Mapping и Axis Mappings добавит ещё одно действие. Стрелка слево предназначена для скрытия или сопоставления наших действий. Для добавления дополнительного отображения входных данных, кликните на признак плюса в отображении. Ниже привидена таблица входных данных которые мы установим. Следует особо обратит внимание на отрицательные значения для  S и A.

 

Action Mapping
Grow Space Bar
 
Axis Mapping
MoveX W 1.0
S -1.0
MoveY A -1.0
D 1.0

ConfigureInput

4) Теперь когда мы настроили наш вход в игру, давайте настроим наш MyPawn на уровне.

ClassInContentBrowser

PawnInSceneView

4) Теперь нам необходимо сопоставить  MyPawn. Для того чтобы увидеть его в игре, необходимо добавить Static Mesh. Мы можем сделать это выбрав MyPawn в только что созданных компонентах, унаследованых в панепени деталей (Details), через выпадающий список в категории Static Mesh. Когда я сам попробовал выбрать элемент в Static Mesh, то список был пуст. Для того чтобы это исправить, достаточно перетащить тот предмет который будет у вас отображаться из BSP

StaticMesh

5) Теперь можно вернутся в Visual Studio и написать код который будет реагировать на нажатие клавиш, которые мы установили в панели.

MyPawn.h

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "GameFramework/Pawn.h"
#include "MyPawn.generated.h"

UCLASS()
class HOWTO_PLAYERINPUT_API AMyPawn : public APawn
{
    GENERATED_BODY()

public:
    // Sets default values
    // Устанавливаем значения по умолчанию
    AMyPawn();

    // Called when the game starts or when spawned
    // Вызываем этот метод при старте игры
    virtual void BeginPlay() override;

    // Called every frame
    // Вызываем метод который повторяется каждый кадр
    virtual void Tick( float DeltaSeconds ) override;

    // Called to bind functionality to input
    // Вызываем функцию которая реагирует при нажатие клавиш
    virtual void SetupPlayerInputComponent(class UInputComponent* InputComponent) override;

    UPROPERTY(EditAnywhere)
    USceneComponent* OurVisibleComponent;
};

MyPawn.cpp

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.

#include "HowTo_PlayerInput.h"
#include "MyPawn.h"

// Sets default values
AMyPawn::AMyPawn()
{
    // Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

    // Set this pawn to be controlled by the lowest-numbered player
    AutoPossessPlayer = EAutoReceiveInput::Player0;

    // Create a dummy root component we can attach things to.
    // Создаём корневой элемент к которому будем прикреплять все наши элементы
    RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
    // Create a camera and a visible object
    // Создаём  камеру и видимые элементы
    UCameraComponent* OurCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("OurCamera"));
    OurVisibleComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("OurVisibleComponent"));
    // Attach our camera and visible object to our root component. 
    //Offset and rotate the camera.
    // Подкрепляем нашу камеру и видимый компонент к корневому компоненту
    // Устанавливаем значение положения камеры

    OurCamera->AttachTo(RootComponent);
    OurCamera->SetRelativeLocation(FVector(-250.0f, 0.0f, 250.0f));
    OurCamera->SetRelativeRotation(FRotator(-45.0f, 0.0f, 0.0f));
    OurVisibleComponent->AttachTo(RootComponent);
}

// Called when the game starts or when spawned
void AMyPawn::BeginPlay()
{
    Super::BeginPlay();

}

// Called every frame
void AMyPawn::Tick( float DeltaTime )
{
    Super::Tick( DeltaTime );

}

// Called to bind functionality to input
void AMyPawn::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
    Super::SetupPlayerInputComponent(InputComponent);

}

Следующий урок

Связывание игровой логики и действий пользователя через программирование