Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / Ue4 Как определить по какому мешу класса APawn кликнули внутри класса APawn?

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

fredwriterПостоялецwww15 сен. 201810:09#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 при выполнении клика нет этой информации?

BingoBongoПостоялецwww15 сен. 201811:17#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

fredwriterПостоялецwww15 сен. 201811:31#2
BingoBongo
Спасибо! Буду пробовать.
BingoBongoПостоялецwww15 сен. 201814:21#3
Там ошибка, надо сделать rayEnd = rayStart + rayEnd * 10000.0f; перед linetrace'ом.

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

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

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

fredwriterПостоялецwww16 сен. 20184:46#5
Странный момент, перестали работать клики, код OnSelected не менял, просто в один прекрасный момент скомпилировал, запустил, и в лог перестало выводится сообщение. Удалил все строки, которые добавил, привел код к виду как в моём посте, не помогло. Перезапускал UE4 и Visual Studio, не помогло, перезагрузил систему) не помогло. И он кстати у меня сразу тоже не работал, заработал как-то внезапно , я даже не помню что сделал для этого.
BingoBongoПостоялецwww16 сен. 201813:40#6
fredwriter
> насколько этот код оптимален или правилен с точки зрения использования движка?
Это нормальная практика, трейсинг работает на PhysX. Только само событие OnClicked для этого не очень подходит, т.к. в таком случае каждый раз выполняется двойная работа.

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

fredwriterПостоялецwww16 сен. 201814:20#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?

BingoBongoПостоялецwww16 сен. 201814:56#8
Есть метод GetWorld()->GetFirstPlayerController()->GetInputAnalogKeyState(EKeys::LeftMouseButton), который возвращает 1 если кнопка нажата, 0 если нет.
endeavour_prПостоялецwww16 сен. 201823:10#9
автор добавь тег Ue4 в название темы
fredwriterПостоялецwww17 сен. 20180:47#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

fredwriterПостоялецwww18 сен. 20181:35#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

BingoBongoПостоялецwww18 сен. 20182:05#12
В этом легко разобраться, если понять кому вообще принадлежит метод CreateDefaultSubobject(), и что от чего наследуется.
Mephisto stdПостоялецwww18 сен. 20184:02#13
что эта тема вообще делает в разделе графика? харэ спамить уже

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

2001—2018 © GameDev.ru — Разработка игр