Связывание игровой логики и действий пользователя через программирование в 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”.
Окончательный код:
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; }
Ссылка на оригинал статьи
Если есть вопросы, задавайте их в комментариях.