Войти
ПрограммированиеФорумГрафика

Ue4 Как определить по какому мешу класса APawn кликнули внутри класса APawn?

#0

Есть ли в классе Pawn функционал для отслеживания событий мыши, клавиатуры по конкретному мешу внутри Pawn?

Есть Pawn, в нем определены несколько мешей, функция шаблон для OnClicked.AddDynamic, переопределенная функция для настройки контроллера:

.h

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
#include "Components/BoxComponent.h"
#include "Components/Button.h"
#include "PlayerPawn.generated.h"


UCLASS()
class ANONIMMATHPROJECT_API APlayerPawn : public APawn
{
    GENERATED_BODY()

public:
    // Sets default values for this pawn's properties
    APlayerPawn();

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

    virtual void PossessedBy(AController* NewController) override;

    APlayerController* PlayerController;

public: 
    // Called every frame
    virtual void Tick(float DeltaTime) override;

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

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn")
    UBoxComponent* PawnCollision;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Pawn")
    UStaticMeshComponent* PawnPlane;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn")
    UStaticMeshComponent* PawnButton;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn")
    UStaticMeshComponent* PawnButton1;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn")
    USpringArmComponent* CamSpringArm;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn")
    UCameraComponent* PawnCamera;

    UFUNCTION()
    void OnSelecded(AActor* Target, FKey Key);
};

.cpp

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

#include "PlayerPawn.h"
#include "Components/StaticMeshComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/PlayerController.h"

// Sets default values
APlayerPawn::APlayerPawn()
{
    // 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;

    OnClicked.AddDynamic(this, &APlayerPawn::OnSelecded);
    PawnCollision = CreateDefaultSubobject<UBoxComponent>(TEXT("PawnCollision"));
    SetRootComponent(PawnCollision);

    PawnButton = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("PawmButton"));
    PawnButton->SetupAttachment(PawnCollision);

    PawnButton1 = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("PawmButton1"));
    PawnButton1->SetupAttachment(PawnCollision);

    PawnPlane = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("PawnPlane"));
    PawnPlane->SetupAttachment(PawnCollision);

    CamSpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("CamSpringArm"));
    CamSpringArm->SetupAttachment(PawnCollision);

    PawnCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("PawnCamera"));
    PawnCamera->SetupAttachment(CamSpringArm);
}

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

}


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

}


// Called to bind functionality to input
void APlayerPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

}


void APlayerPawn::OnSelecded(AActor* Target, FKey Key)
{
    UE_LOG(LogTemp, Warning, TEXT("Pawn selected"));
}



void APlayerPawn::PossessedBy(AController* NewController)
{
    APlayerController* PlayerController = Cast<APlayerController>(NewController);

    PlayerController->bShowMouseCursor = true;
    PlayerController->bEnableClickEvents = true;
    PlayerController->bEnableMouseOverEvents = true;
    PlayerController->DefaultClickTraceChannel = ECollisionChannel::ECC_Pawn;
}

Все три меша настроены в блупринтах, для примера выбраны кубы. При клике по одному из кубов в лог выводится сообщение, то есть клики работают. Как определить имя меша, по которому произошел клик? Неужели в AActor* Target при выполнении клика нет этой информации?

15 сен. 2018

#1

Можно вручную определить, что был клик мышью и сделать так:

  
  FVector2D position;
  GetWorld()->GetFirstPlayerController()->GetMousePosition(position.X, position.Y);

  FVector rayStart;
  FVector rayEnd;
  if (GetWorld()->GetFirstPlayerController()->DeprojectScreenPositionToWorld(position.X, position.Y, rayStart, rayEnd))
  {
    FHitResult hit;
    if (GetWorld()->LineTraceSingleByChannel(hit, rayStart, rayEnd, ECollisionChannel::ECC_Visibility))
    {
      hit.GetActor();          // актер
      hit.GetComponent(); // компонент
    }
  }

15 сен. 2018 (Правка: 11:18)

#2

BingoBongo
Спасибо! Буду пробовать.

15 сен. 2018

#3

Там ошибка, надо сделать rayEnd = rayStart + rayEnd * 10000.0f; перед linetrace'ом.

15 сен. 2018 (Правка: 14:26)

#4

BingoBongo
Спасибо за помощь, работает, я запихнул Ваш код в OnSelected. А насколько этот код оптимален или правилен с точки зрения использования движка? Мне он нравится, удобно, узнал объект по которому тыкнули - выполнил нужное действие. Если имеется порядка 20 объектов на сцене, с которыми игрок постоянно взаимодействует с помощью мыши как лучше всего это реализовать?

16 сен. 2018 (Правка: 2:31)

#5

Странный момент, перестали работать клики, код OnSelected не менял, просто в один прекрасный момент скомпилировал, запустил, и в лог перестало выводится сообщение. Удалил все строки, которые добавил, привел код к виду как в моём посте, не помогло. Перезапускал UE4 и Visual Studio, не помогло, перезагрузил систему) не помогло. И он кстати у меня сразу тоже не работал, заработал как-то внезапно , я даже не помню что сделал для этого.

16 сен. 2018

#6

fredwriter
> насколько этот код оптимален или правилен с точки зрения использования движка?
Это нормальная практика, трейсинг работает на PhysX. Только само событие OnClicked для этого не очень подходит, т.к. в таком случае каждый раз выполняется двойная работа.

>перестали работать клики
Перенеси OnClicked.AddDynamic(this, &APlayerPawn::OnSelecded); в BeginPlay(); если не поможет, то хз

16 сен. 2018

#7

Скопировал код отсюда, и заработало). Затем немного изменил Ваш код чтобы покороче были 2 строки. 

FVector2D position;
  PlayerController->GetMousePosition(position.X, position.Y);

  FVector rayStart;
  FVector rayEnd;
  if (PlayerController->DeprojectScreenPositionToWorld(position.X, position.Y, rayStart, rayEnd))
  {
    FHitResult hit;
    rayEnd = rayStart + rayEnd * 10000.0f;
    if (GetWorld()->LineTraceSingleByChannel(hit, rayStart, rayEnd, ECollisionChannel::ECC_Visibility))
    {
      hit.GetActor();          // актер
      hit.GetComponent(); // компонент
    }
  }

BingoBongo
> Только само событие OnClicked для этого не очень подходит
А какое подходит? Куда этот код лучше запихнуть? Как по другому определить, что был клик мышкой - BindAction?

16 сен. 2018

#8

Есть метод GetWorld()->GetFirstPlayerController()->GetInputAnalogKeyState(EKeys::LeftMouseButton), который возвращает 1 если кнопка нажата, 0 если нет.

16 сен. 2018

#9

автор добавь тег Ue4 в название темы

16 сен. 2018

#10

BingoBongo
Спасибо, добавил на тик этот код:

if (PlayerController->GetInputAnalogKeyState(EKeys::LeftMouseButton)) {
  OnSelected();
}
Все работает. Прошелся отладчиком в обоих вариантах с OnClicked он сразу заходит в
if (GetWorld()->LineTraceSingleByChannel(hit, rayStart, rayEnd, ECollisionChannel::ECC_Visibility))
А при ловле клика GetInputAnalogKeyState он почему-то делает дважды назад на rayEnd = rayStart + rayEnd * 10000.0f;

Хотя на тик не очень удачная идея, OnSelected теперь постоянно выполняется когда кнопка нажата.

17 сен. 2018 (Правка: 1:25)

#11

Вопрос немного не по теме, как создать массив структур UStaticMeshComponent, для массива мешей доступных для настройки в UE-редакторе?
Пробовал вот так:

USTRUCT()
struct ButtonsStruct
{
  GENERATED_USTRUCT_BODY()

  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Pawn")
    UStaticMeshComponent* PawnButtonArr;

  ButtonsStruct()
  {
    PawnButtonArr = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("PawnButtonArr"));
  }
};

Подчеркивает красным строку в конструкторе ButtonsStruct(): "Идентификатор CreateDefaultSubobject не определён" и "использование имени типа не допускается".
Как правильно создается?

18 сен. 2018 (Правка: 1:35)

#12

В этом легко разобраться, если понять кому вообще принадлежит метод CreateDefaultSubobject(), и что от чего наследуется.

18 сен. 2018

#13

что эта тема вообще делает в разделе графика? харэ спамить уже

18 сен. 2018

ПрограммированиеФорумГрафика