Having problems with C++ Tanks vs Zombies Training

I’m sure this is because things have changed within Unreal and Visual Studio within a year and a half, but I’m having two errors following along with the C++ Tanks vs Zombies tutorial on YouTube from Unreal. To make sure I didn’t mistype something, I downloaded the source code and imported it into my project, but the problems still persist. Here’s the code from the .cpp file:

if (!RootComponent)
	{
		RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("TankBase"));
	}

	TankDirection = CreateDefaultSubobject<UArrowComponent>(TEXT("TankDirection"));
	TankDirection->AttachTo(RootComponent);

	TankSprite = CreateDefaultSubobject<UPaperSpriteComponent>(TEXT("TankSprite"));
	TankSprite->AttachTo(TankDirection);

And this is from the private sector of the class declaration in the header file:

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Tank", meta = (AllowPrivateAccess = "true"))
	class UArrowComponent* TankDirection;
	
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Tank", meta = (AllowPrivateAccess = "true"))
	class UPaperSpriteComponent* TankSprite;

The two main errors I get are on the TankDirection assignment and the AttachTo(TankDirection). TankDirection says “pointer to incomplete class type is not allowed” and for the TankSprite assignment. AttackTo says “argument of type ‘UArrowComponent*’ is incompatible with parameter of type ‘USceneComponent*’”

mine 4.18 tanks vs zombies work just fine!

/// Tank.h

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

#pragma once

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

// This struct covers all possible tank input schemes
// What the inputs do can vary by tank
// but the scheme inputs will always exist.
USTRUCT(BlueprintType)
struct FTankInput
{
	GENERATED_USTRUCT_BODY()

	/** Sanitized movement input, usable for game logic  */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "TankInput")
	FVector2D MovementInput;

	/** shows whether fire1 button is pressed or not  */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "TankInput")
	uint32 bFire1 : 1;

	/** shows whether fire2 button is pressed or not  */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "TankInput")
	uint32 bFire2 : 1;
	
	/** makes correct movement input from all received raw movement input
	*  for example you can have 2 buttons e.g. "W" and "UpArraow" to move tank up
	* for user convenience
	* and if user press this two buttons at the same time we will have AxisValue = 2.f 
	* per frame and we will have double speed . . . so anyway we must be able to have 
	* AxisValue = 1.f  maximum per frame.
	*/
	void Sanitize()
	{
		// FVector2D::ClampAxes
		// Creates a copy of this vector with both axes clamped to the given range. 
		// New vector with clamped axes.
		MovementInput = RawMovementInput.ClampAxes(-1.f, 1.f);

		// FVector2D::GetSafeNormal
		// Gets a normalized copy of the vector, checking it is safe to do so based on the length.
		// Returns zero vector if vector length is too small to safely normalize. 
		// A normalized copy of the vector if safe, (0, 0) otherwise
		MovementInput = MovementInput.GetSafeNormal();

		// Set the values of the vector directly
		RawMovementInput.Set(0.f, 0.f);
	}

	/** movement  */
	void MoveX(float AxisValue) { RawMovementInput.X += AxisValue; }
	void MoveY(float AxisValue) { RawMovementInput.Y += AxisValue; }

	/** fire  */
	void Fire1(bool bPressed) { bFire1 = bPressed; }
	void Fire2(bool bPressed) { bFire2 = bPressed; }

private:

	// Private because it's internal. Game code should never see this
	FVector2D RawMovementInput;

};

UCLASS()
class TANKS_API ATank : public APawn
{
	GENERATED_BODY()
	
	// Helpful debug tool - which way is the tank facing
	// @API A simple arrow rendered using lines. Useful for indicating which way an object is facing.
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Tank", meta = (AllowPrivateAccess = "true"))
	class UArrowComponent* TankDirection;

	// Sprite for the tank body
	// @API A component that handles rendering and collision for a single instance of a UPaperSprite asset. 
	// This component is created when you drag a sprite asset from the content browser into a Blueprint, 
	// or contained inside of the actor created when you drag one into the level.
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Tank", meta = (AllowPrivateAccess = "true"))
	class UPaperSpriteComponent* TankSprite;

	// The Actor used as the turret
	// @API A component that spawns an Actor when registered, and destroys it when unregistered.
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Tank", meta = (AllowPrivateAccess = "true"))
	class UChildActorComponent* ChildTurret;
	
	// Camera Boom
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Tank", meta = (AllowPrivateAccess = "true"))
	class USpringArmComponent* SpringArm;
	
	// Our in-game camera
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Tank", meta = (AllowPrivateAccess = "true"))
	class UCameraComponent* TankCamera;

public:

	// Sets default values for this pawn's properties
	ATank();

	// 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;

	UFUNCTION(BlueprintCallable, Category = "Tank")
	const FTankInput& GetCurrentInput() { return TankInput; }

protected:

	/**  Our Input Structure */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "TankInput")
	FTankInput TankInput;

	/**  Maximum Turn  Rate (degrees/second) of the tank */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Tank", meta = (ClampMin = "0.0"))
	float YawSpeed = 180.f;

	/**  Maximum Movement Rate (units/seconds) of the tank */
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Tank", meta = (ClampMin = "0.0"))
	float MoveSpeed = 100.f;
	
	/** movement  */
	void MoveX(float AxisValue);
	void MoveY(float AxisValue);

	/** fire  */
	void Fire1Pressed();
	void Fire1Released();
	void Fire2Pressed();
	void Fire2Released();
	
};



/// Tank.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "Tank.h"
#include "Tanks.h"
#include "PaperSpriteComponent.h"
#include "TankStatics.h"
#include "Components/ArrowComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
#include "ConstructorHelpers.h"

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

	if (!RootComponent)
	{
		RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("TankBase"));
	}

	TankDirection = CreateDefaultSubobject<UArrowComponent>(TEXT("TankDirection"));
	TankDirection->SetupAttachment(RootComponent);

	TankSprite = CreateDefaultSubobject<UPaperSpriteComponent>(TEXT("TankSprite"));
	TankSprite->SetupAttachment(TankDirection);
	TankSprite->SetRelativeRotation(FRotator(0.f, 90.0f, -90.0f)); // PYR
	TankSprite->SetRelativeLocation(FVector(0.0f, 0.0f, 1.f));

	ChildTurret = CreateDefaultSubobject<UChildActorComponent>(TEXT("Turret"));
	ChildTurret->SetupAttachment(TankDirection);

	SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
	SpringArm->SetupAttachment(RootComponent);
	SpringArm->TargetArmLength = 500.f;
	SpringArm->bEnableCameraLag = true;
	SpringArm->bEnableCameraRotationLag = false;
	SpringArm->bUsePawnControlRotation = false;
	SpringArm->CameraLagSpeed = 2.f;
	SpringArm->bDoCollisionTest = false;
	SpringArm->SetWorldRotation(FRotator(-90.f, 0.0f, 0.0f));

	TankCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("TankCamera"));
	TankCamera->SetupAttachment(SpringArm, USpringArmComponent::SocketName);
	TankCamera->bUsePawnControlRotation = false;
	// flat view
	TankCamera->ProjectionMode = ECameraProjectionMode::Orthographic;
	TankCamera->OrthoWidth = 2048.f; // 1024.f by default
	TankCamera->AspectRatio = 3.f / 4.f;
	TankCamera->SetWorldRotation(FRotator(-90.f, 0.0f, 0.0f));
}

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

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

	TankInput.Sanitize();

	// Move the tank this frame
	{
		FVector DesiredMovementDirection = FVector(TankInput.MovementInput.X, TankInput.MovementInput.Y, 0.f);
		
		if (!DesiredMovementDirection.IsNearlyZero())
		{
			// Rotate The tank! Note that we rotate the TankDirection component, not the RootComponent !
			FRotator MovementAngle = DesiredMovementDirection.Rotation();
			float DeltaYaw = UTankStatics::FindDeltaAngleDegrees(TankDirection->GetComponentRotation().Yaw, MovementAngle.Yaw);

			bool bReverse = false;
			if (DeltaYaw != 0.0f)
			{
				float AdjustedDeltaYaw = DeltaYaw;

				if (AdjustedDeltaYaw < -90.f)
				{
					AdjustedDeltaYaw += 180.f;
					bReverse = true;
				}
				else if (AdjustedDeltaYaw > 90.f)
				{
					AdjustedDeltaYaw -= 180.f;
					bReverse = true;
				}

 				// Turn toward the desired angle. Stop if we can get there in one frame
				float MaxYawThisFrame = YawSpeed * DeltaTime;

				if (MaxYawThisFrame >= FMath::Abs(AdjustedDeltaYaw))
				{
					if (bReverse)
					{
						// move backward
						FRotator FacingAngle = MovementAngle;
						FacingAngle.Yaw = MovementAngle.Yaw + 180.f;
						TankDirection->SetWorldRotation(FacingAngle);
					}
					else
					{
						TankDirection->SetWorldRotation(MovementAngle);
					}
				}
				else
				{
					// Can't reach our desired angle this frame, rotate part way
					TankDirection->AddLocalRotation(FRotator(0.f, FMath::Sign(AdjustedDeltaYaw) * MaxYawThisFrame, 0.f));
				}
			}

			// Move the tank
			{
				FVector MovementDirection = TankDirection->GetForwardVector() * (bReverse ? -1.f : 1.f);

				FVector TankLocation = GetActorLocation();

				TankLocation.X += MovementDirection.X * MoveSpeed * DeltaTime;
				TankLocation.Y += MovementDirection.Y * MoveSpeed * DeltaTime;

				SetActorLocation(TankLocation);
			}
		}
	}
}

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

	InputComponent->BindAxis("MoveY", this, &ATank::MoveY);
	InputComponent->BindAxis("MoveX", this, &ATank::MoveX);

	InputComponent->BindAction("Fire1", IE_Pressed, this, &ATank::Fire1Pressed);
	InputComponent->BindAction("Fire1", IE_Released, this, &ATank::Fire1Released);
	InputComponent->BindAction("Fire2", IE_Pressed, this, &ATank::Fire2Pressed);
	InputComponent->BindAction("Fire2", IE_Released, this, &ATank::Fire2Released);
}

void ATank::MoveX(float AxisValue)
{
	TankInput.MoveX(AxisValue);
}

void ATank::MoveY(float AxisValue)
{
	TankInput.MoveY(AxisValue);
}

void ATank::Fire1Pressed()
{
	TankInput.Fire1(true);
}

void ATank::Fire1Released()
{
	TankInput.Fire1(false);
}

void ATank::Fire2Pressed()
{
	TankInput.Fire2(true);
}

void ATank::Fire2Released()
{
	TankInput.Fire2(false);
}