背景
こちらの変数、タイマー、イベントのチュートリアルを見ながら実装したところ、コンパイルエラーが起きたので、直し方を書きます。
結論
- GetWorldTimerManager()使う時は
#include "TimerManager.h"
を追加する - UTextRenderComponentなどコンポーネント使う時は、
.hファイル
にinclude忘れずに -
.generated.h
はincludeヘッダー群の一番最後に書く
コンパイルエラーがでたコード
CppTurorial2というプロジェクトにCountDown.hとCountDown.cppを実装しました。(チュートリアルではCountdown.cppと小文字である)
// Copyright 1998-2018 Epic Games, Inc.All Rights Reserved.
#pragma once
#include "GameFramework/Actor.h"
#include "CountDown.generated.h"
UCLASS()
class CPPTUTORIAL2_API ACountDown : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ACountDown();
protected:
// Called when the game starts or when spawned (ゲーム開始時またはスポーン時に呼び出されます)
virtual void BeginPlay() override;
public:
// Called every frame (フレーム毎に呼び出されます)
virtual void Tick(float DeltaSeconds) override;
//How long, in seconds, the countdown will run
int32 CountdownTime;
UTextRenderComponent* CountdownText;
void UpdateTimerDisplay();
void AdvanceTimer();
void CountdownHasFinished();
FTimerHandle CountdownTimerHandle;
};
// Copyright 1998-2018 Epic Games, Inc.All Rights Reserved.
#include "Components/TextRenderComponent.h"
#include "Countdown.h"
// Sets default values
ACountDown::ACountDown()
{
// Set this actor to call Tick() every frame.You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
CountdownText = CreateDefaultSubobject<UTextRenderComponent>(TEXT("CountdownNumber"));
CountdownText->SetHorizontalAlignment(EHTA_Center);
CountdownText->SetWorldSize(150.0f);
RootComponent = CountdownText;
CountdownTime = 3;
}
// Called when the game starts or when spawned (ゲーム開始時またはスポーン時に呼び出されます)
void ACountDown::BeginPlay()
{
Super::BeginPlay();
UpdateTimerDisplay();
GetWorldTimerManager().SetTimer(CountdownTimerHandle, this, &ACountDown::AdvanceTimer, 1.0f, true);
}
// Called every frame (フレーム毎に呼び出されます)
void ACountDown::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ACountDown::UpdateTimerDisplay()
{
CountdownText->SetText(FString::FromInt(FMath::Max(CountdownTime, 0)));
}
void ACountDown::AdvanceTimer()
{
--CountdownTime;
UpdateTimerDisplay();
if (CountdownTime < 1)
{
// We're done counting down, so stop running the timer.
GetWorldTimerManager().ClearTimer(CountdownTimerHandle);
//Perform any special actions we want to do when the timer ends.
CountdownHasFinished();
}
}
void ACountDown::CountdownHasFinished()
{
//Change to a special readout
CountdownText->SetText(TEXT("GO!"));
}
エラー内容
これを見ると
GetWorldTimerManager()
と UTextRenderComponent
にエラーが出ています。
チュートリアル通りなのになぜ?調べてみた
GetWorldTimerManager()について
不完全な型は使用できません。でググると
https://docs.microsoft.com/ja-jp/cpp/c-language/incomplete-types?view=vs-2019
... わからん、メンバーがまだ指定されていない構造体型。なのか?
GetWorldTimerManager()でググると、
ちゃんと、#include "GameFramework/Actor.h"してるんだけどな...
UE4.20の記事、期待できそう。
サンプルコードを見てみると
#include "TimerManager.h"
お?試しに、CountDown.cppに追加して、ビルドしてみる。
不完全な型は使用できません。がなくなった!
UTextRenderComponentについて
同じく、includeのし忘れを疑ってみる。文字化けしてみれない...
UTextRenderComponentでググる
#include "Components/TextRenderComponent.h"
かぁ、そういえばCountDown.hになかったな、追加してみよう。ビルド。
#include "CountDown.generated.h"
はincludeヘッダの最後でなければならないらしい
#include "GameFramework/Actor.h"
#include "CountDown.generated.h"
#include "Components/TextRenderComponent.h"
ほんとだ
#include "GameFramework/Actor.h"
#include "Components/TextRenderComponent.h"
#include "CountDown.generated.h"
これでビルド。
やった正常終了!
再生すると?
ちゃんとGO!が表示されました。
最終コード
残りのチュートリアルもやってみた後のコード
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/TextRenderComponent.h"
#include "CountDown.generated.h"
UCLASS()
class CPPTUTORIAL2_API ACountDown : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ACountDown();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
//How long, in seconds, the countdown will run
UPROPERTY(EditAnywhere)
int32 CountdownTime;
UTextRenderComponent* CountdownText;
void UpdateTimerDisplay();
void AdvanceTimer();
UFUNCTION(BlueprintNativeEvent)
void CountdownHasFinished();
virtual void CountdownHasFinished_Implementation();
FTimerHandle CountdownTimerHandle;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "CountDown.h"
#include "Components/TextRenderComponent.h"
#include "TimerManager.h"
// Sets default values
ACountDown::ACountDown()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
CountdownText = CreateDefaultSubobject<UTextRenderComponent>(TEXT("CountdownNumber"));
CountdownText->SetHorizontalAlignment(EHTA_Center);
CountdownText->SetWorldSize(150.0f);
RootComponent = CountdownText;
CountdownTime = 3;
}
// Called when the game starts or when spawned
void ACountDown::BeginPlay()
{
Super::BeginPlay();
UpdateTimerDisplay();
GetWorldTimerManager().SetTimer(CountdownTimerHandle, this, &ACountDown::AdvanceTimer, 1.0f, true);
}
// Called every frame
void ACountDown::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ACountDown::UpdateTimerDisplay()
{
CountdownText->SetText(FString::FromInt(FMath::Max(CountdownTime, 0)));
}
void ACountDown::AdvanceTimer()
{
--CountdownTime;
UpdateTimerDisplay();
if (CountdownTime < 1) {
GetWorldTimerManager().ClearTimer(CountdownTimerHandle);
CountdownHasFinished();
}
}
void ACountDown::CountdownHasFinished_Implementation() {
CountdownText->SetText(TEXT("GO!"));
}