TankAIController fails to cast the tank pawn it owns into a tank pawn

I dunno man, I’ll continue to investigate.

Wait a minute I just realized, get display name in blueprints is almost the same as what we are doing in code!

What else can the controller do to the pawn to test if it is possessed?

Okay I have an explaination. So the code’s BeginPlay will run when it’s spawned, so between the spawn node and the spawn default controller node. So the code’s BeginPlay for the spawned tank won’t have a contoller on it at that instance, since it’s during that really short period in which it doesn’t have a controller.

Funny I just came to the near similar conclusion in that when printing its name during tick, after 1 tick it finds it

Perhaps then the tank controller is constructed before its pawn class is when spawned in a level, thus being unable to print out the value of the controller class, since it doesnt exist yet?

I originally tested it in blueprint then came up with the idea to do it in code.

Another thing is that in blueprints the spawning of both actors are complete before it proceeds onto the next step

Also in blueprints you can print the controller name without doing the “spawn default controller” function we added to debug earlier.

This also implies that when actors are placed in the level, they are constructed before begin play is called on them, which is why the tanks placed in the level did not have trouble getting their pawn

Hello Den I want to define something if I understood it correctly or not:
TankPlayerController_BP has a connection Tank_BP in GameMode_BP

and with help of inheritance TankPlayerController C++ file (from which is derived TankPlayerController_BP ) can get Tank_BP as a Pawn. because I have the code in my cpp file: [there is not #include “Tank.h”]

Cpp File

and output Log

outLog

then I suspected why we need Tank C++ file (from which derived Tank_BP) and as I guess we need it for the future to modify Tank_BP. am I right?

Your function is upcasting and not what you want. Ben has a function GetControlledTank that looks like

ATank* TankPlayerController::GetControlledTank() const
{
    return Cast<ATank>(GetPawn());
}

Which is a downcast. The hierarchy looks like this

- AActor
|- APawn
 |- ATank

What you did is go up APawn -> AActor instead of down APawn -> ATank. The reason you are casting is so you are able to access members on ATank.

1 Like
  1. Yes and from ATank (C++ file) we can access and modify Tank_BP, am I right?

  2. if I am upcasting and get Pawn in my code ( return GetPawn() ) how it know about Tank name ID?

3)

with this connection TankPlayerController_BP get what? Tank_BP or upcasting Pawn?

  1. What do you mean by modify and access?

  2. Because ATank nor APawn for that matter, define GetName(). That’s much higher in the hierarchy and when an instance of either gets created a name will be set for it. Here’s some example code

    #include <string>
    #include <iostream>
    using FString = std::string;
    class APawn 
    {
    	FString Name;
    public:
    	APawn() :  Name("Pawn"){};
    	void SetName(FString InName) { Name = InName; }
    	FString GetName() { return Name; }
    };
    class ATank : public APawn
    {
    public:
    	ATank() { SetName("Tank"); }
    	void AimAt() { std::cout << "Aiming" << std::endl; }
    };
    
    
    class ATankPlayerController
    {
    	APawn* Pawn;
    public:
    	ATankPlayerController(APawn* InPawn) { Pawn = InPawn; }
    	APawn* GetPawn() { return Pawn; }
    };
    
    int main()
    {
    	ATank Tank;
    	ATankPlayerController TankPlayerController(&Tank);
    	std::cout << TankPlayerController.GetPawn()->GetName() << std::endl;
        TankPlayerController.GetPawn()->AimAt(); //error APawn doesn't have AimAt member
    }
    

    Here I’ve made APawn have a member Name with functions to get and set it. In ATank I have the constructor set that name to “Tank”, In main I print it’s name out and the last line I attempt to call a function on ATank which is a compilatation error since GetPawn returns an APawn not an ATank and thus needs to be casted down to ATank in order to call that function.

    Compiled: https://ideone.com/RFXQ2N

  3. That’s not upcasting or downcasting. There’s no inheritance involved in that, that’s just setting the default pawn and default player controller. What that means is that the player controller will use that pawn class when it spawns a pawn.

Thank Den answer is comprehensive for me

  1. what Cast is look like it’s not like C++ standard library static_cast or dynamic_cast. I think it’s just the same:

     class Mom {};
     class Baby : public Mom {};
    
     int main() {
         Mom *Pmom;
         Baby *Pbaby, baby;
         Pmom = &baby;
         Pbaby = (Baby*)Pmom;
    

is not it?

  1. There are so many TankAIController in the World as an enemy Tank and this happens because in Tank_BP we indicate Place in World is not it?

AIController

all of them (TankAIController) based on a C++ file. Can we write individual Controller some or other Tank?

  1. Yes, Cast is something defined by Unreal; I would imagine it would be akin to dynamic_cast.

  2. If you really wanted to, yes.

than you Den
and why we add our Project C++ files we can’t built Aiming() function code in blueprint?

Not sure what you’re trying to say.

I only mean why we don’t carry on code’s writing in Blueprint?
Is there something in Unreal that can’t write in Blueprint and for that necessary C++ ?

Because this is a course aimed at C++. Also yes in some cases.

Tank you Den :slight_smile:

Privacy & Terms