Hello, this is Youngho Lee
In this lecture, we will learn about Respawn
What you will learn is
to implement the first respawn logic
When the user clicks the Retry UI button
a location for respawning is selected
and player respawning is processed through RPC communication
Second, you will learn about the respawn problem and lifecycle function analysis
When respawning, problems may arise with the player's initialization settings
This part can be solved through lifecycle function processing between the server and the client
Let's learn how this information is processed
Implementing Respawn Logic
This time, we will implement the respawn logic
The way the player is
created now is
when you press the play button
if you look at this as the world screen
the screen looks like this
There will be various level designs here
And this is where the player appears
So here we have the player start
The player is currently running
in the area where the player start actor is located
At this time, it's spawned
and our team is strategically located at the point we want
Then, if I were to create a structure like this
so that the opposing team could come out
players would have to be created
exactly at this point that I specified, right?
Or, in this part, I think we need logic to make it
randomly created around here or in some specific area
like this
Right now, the player is at this point
but I don't want this to be where the player spawns
when he dies or when he spawns
Or, I hope it gets to this point
The player is created at a point that we specify
and then when the player dies, it respawns at this point
and we want to do something like this
So first, there is only one player starting, so let's put the player starting
in two locations as a sample
So, let's think of it as a two-player game
and by putting one here and one here
I will work on making it possible to respawn
I duplicate the player by pressing the Alt key again
and then I rotate them like this so they're facing each other
Let's rotate it 180 degrees
and make it look like this
We're going to do this so that some players will respawn here
and other players will respawn here
We will put two players in positions like this
Okay?
Then
at the player start location
it is a process of spawning when a player is created
To do this
you need to request that the server respawn the player for these parts
We continue to do the same things
but when we make these requests
we process them using RPC, not attribute replication
Now, let's create a C++ class
Let's specify the player control as the parent class
Next
I'll name it NetPlayerController
NetPlayerController, then Create Class
When classes are created, reload them all
Let's move on to the header file
Let's move to the header file of NetPlayerController
Below this, as members
the logic that causes players to respawn
and rejoin the game needs to be done using game modes
Now, we already have a game mode class
There is already a class called NetTPS Game Mode
Let's first create a game mode so that we can access the game mode
from the PlayerController and utilize the features in the game mode
Let's write down, public, then UPROPERTY
class ANetTPSGameMode*
and put it as game mode, gm
Next, I will redefine the BeginPlay function
I will call it virtual void BeginPlay
and put an override like this
I will make BeginPlay auto-complete in the cpp file
Super::
BeginPlay()
And what role does this NetPlayerController
want to play in this BeginPlay? Game mode
I want to play the role of adding value to the class
In this BeginPlay
I will create a GameMode class, create an instance
and put it in the gm variable
When getting a game mode in BeginPlay
we must determine
whether the currently executing PlayerController runs on the client or server
So, if(HasAuthority)
What are the rules for this HasAuthority?
When the local role is set to ROLE Authority
the hasAuthority value is true
In other words, in the case of a server, if this is running on the server
we will add gm, why? Because game modes
only exist on servers
Do Cast ANetTPSGameMode
Getworld
and put GetAuthGameMode instance
We will process it so that
NetTPSGameMode can be added
Now, let's create a serverRPC function
to request that
the client respawn from the server
Let's move to the header file
I'll put it separately by making it public at the bottom
It's a respawn function
UFUNCTION
Since we will add serverRPC, we will set it as server
and then as Reliable
Then I will put void ServerRPC_RespawnPlayer()
Then I will implement ServerRPC_RespawnPlayer
at .cpp
So, the header authority has been entered under BeginPlay
and one more function has been added below that
I put ServerRPC_RespawnPlayer_Implementation
Then, here at ServerRPC_RepawnPlayer
I will implement the respawning in the serverRPC respawning player
First
the Pawn you were
using previously This is player, right?
This is player character NetTPSCharacter
Let's remember
Then, at the back, we will
newly spawn again
But there is a function that automatically does this spawning
There is a thing called Restart Player in the game mode
If you use this, it will spawn you internally
Remember the Pawn
and then UnPossess
Then what? Let's remove the previously used Pawn
from memory
The logic is to add this new spawning content after that
So, I set the Pawn I previously used as an auto player
In GetPawn
GetPawn returns the Pawn
currently owned by PlayerController
Shall we try building it here first?
Now, the build was successful Then, let's do UnPossess
The one we're doing now
When you UnPossess and go into this UnPossess function
the Pawn you were using is retrieved from GetPawn
Then, we take the current Pawn and UnPossess it
Then, I will distroy
the player again
At Player, Destory
Then, we take the player, and do UnPossess
destroy this player because we need to remove it from memory
and now we need a function to respawn the player
by respawning it again
Where is it? It's right there in GameMode
That's why we came up with the game mode
Whether we call a function in the game mode or do something else, we need this game mode instant to be able to use it
There is a thing called RestartPlayer in the GameMode
Now, if you look here, there is RestartPlayer
and if you look below, there is something called RestartPlayerAtPlayerStart
Next, there is something called RestartPlayerAtTransform below
If you look at the restart player, the thing to add here is PlayerController
Who will take charge of the newly created player Pawn object?
It's me As this NetPlayerController, I will Possess
I added this, and I'll build now
Okay, then you don't have to call this serverRPC from somewhere
When will we call?
When the player dies, we create a retry button in the game over UI
At GameOver UI
When we press Retry button
this code will run to respawn at that time
Then, where is the content?
It's in the mainUI header file, so go to the mainUI header
This controls the game over UI in our mainUI
The retry button is also here Now, let's create an event function
to react when clicking this button
Then, you need to add a form that links this retry button with that event function
Let me add that part below here
Now, do public first
Like our Beginfly, the lifecycle function executed when this UI is
first run is a virtual void native construct
Let me clarify this When it runs inside this function, what is it going to do?
There is a retry button and a binding that actually performs the function
I'll take care of the content that ties together the events
Then, I will set the processing function
to UFUNCTION and create this void button on retry
Now, let's add the native construct implementation part
Next, we will add the on retry implementation
It's MainUI.cpp
Now, Super
Native
Construct, right? Write down NativeConstruct, and then
you can implement the part that connects the two functions
in this NativeConstruct below
Now, we're going to connect
the retry button and the processing function connection event
Now, it says btn_retry like this
You can use the OnClicked event for this
This is delegate, and if you go to the implementation department
to see how it is structured, it says on clicked
Now, if you search for this
there is simply no DYNAMIC_MULTICAST_DELEGATE parameter at the moment
So I think you can write it like this
If it is created like this and is DYNAMIC_MULTICAST
it can be called from the Blueprint because DYNAMIC_MULTICAST is included
OnClicked in MainUI can also be called from Blueprint
So, I wrote UFUNCTION in the header file
Now, let’s group the functions to be performed here
Since this is multicast, add dynamic
Then this
It's on retry in MainUI
Let me connect it like this
Now, if you build it, there is currently no information about the UI button
So, you need to include it at the top
Now, I'm adding a button below the image here
Now, let's build it like this and add the content
you want to add in on retry
Now, you need to call Server RPC respawn OnRetry
Let's try this OnRetry
First, the game-ending UI is floating on the screen
If the game is over, you won't see them on-retry button when it's floating
If you just click the button, it disappears from the screen
Let's process this UI
so it disappears and becomes invisible
and then request a respawn from the server
As for the game end UI, what we have now is called Gameover UI
That's right; it's declared that way in the main UI header file
So, in the game over UI
I'll add the SetVisibility property
and set it to hidden like this
Then, it will not be visible on the screen like this
Next, I will request a respawn from the server
This is now created in PlayerController
Since we created Server RPC in NetPlayerController
we need NetPlayerController
So bring Cas ANetPlayerController
and in world, when you do GetFirstPlayerController
it will hand over the player it is using
If PlayerController is brought in properly
I first output the mouse cursor on the screen
so that the current UI can show the screen
The mouse cursor
If you press the retry button again, it should disappear
Then, when the game is over, the UI will pop up
so I will process it so that the mouse cursor is visible again
Here, when repawning, to not show the mouse cursor, at PlayerController
there is SetShow
MouseCursor
Let's add false here
And you have to call serverRPC
Now, this is the ServerRPC_RespawnPlayer function in PlayerController, right?
I'll handle it like this
Well, we have to use ANetPlayerController, too, right?
Next, this GameoverUI is a horizontal box
This horizontal box must also be included so it can be used here
So, I will add a horizontal box like this at the bottom
And what else do you need?
ANetPlayerController must also have a header added like this to use it
Now, let's try building it
Cast in the main UI, oh, I missed the t Let's put it like this: cast
There you go
Once it's built, I'll go to Unreal Editor and make it a Blueprint
Coming from C++, the NetPlayerController we created
has a C++ class here
I'll right-click and make it a Blueprint class
For the location, put BP_NetPlayerController
in the blueprint folder of NetTPS
and Create Blueprint Class
Then, a Blueprint is created like this
Let me save and close it
Now, I created a blueprint class like this, and if you go to that folder
you will find BP_NetTPS GameMode
Okay, let's open this Blueprint
If you go here and look at the current PlayerController
the PlayerController class here is just this default PlayerController
So, we just created a PlayerController using NetTPS
Let's change it to NetPlayerController
If you look here, PlayerController is BP_NetPlayerController, modify it to this
Only then will the class we have created operate normally, compile
Then play, play one more
Well, there is a client
and there is a server If you look at the server first, the user is
created normally there
Since there are two player starts, one will be created here, and one will be created there
So, let's grab a gun and shoot another user
Bang, bang, bang
Then
there is a Retry button and an Exit button on the client screen like this, right?
If you can't see the Retry button on the screen right now, I'll put it like this
There's a Retry button, let's click on it
Then it's respawned normally
Again, I can move and jump while holding the gun
Now, I'll fight I'll shoot the sub-character
Bang, bang, bang
Then, the Gameover UI will appear on the server as well
There is a Retry button
Right?
Then, I'll click the Retry button
Click
Then, it Retry normally, and respawn will work well
Respawn Problem and Lifecycle Function Analysis
But I think there is a problem here
What's the problem on the screen?
This part is the problem
In its main UI, this is not filled in properly
and this part is now created anew above the head
Weird, what about the main player?
When I used it, I processed it so that it wouldn't be visible
but the fact that
it's showing up now means there's some kind of problem
Let's find out what the problem is
So let's come to our code
and go to the cpp of NetTPSCharacter
Here, we have InitUIWidget
If you come to the InitUIWidget function in NetTPSCharacter
it doesn't process anything if the PlayerController is not in control
Right?
Then, if it's a PlayerController, how about creating a new main UI underneath
and then initializing the bullet?
I need to make the health bar above my head invisible
In other words, this is supposed to run, but it hasn't run now
so it seems like it keeps popping up over my head
So what is the problem?
We need to learn a little about lifecycle functions to do this now
Because the InitUIWidget function is
called in BeginPlay
Then, if there is a PlayerController, it shouldn't float above your head
but since there is no PlayerController, it seems to float above your head
Then, I think there's something wrong
with the point where the PlayerController do Possess it and the point at which this BeginPlay is now called
So for this we need to look up this order of lifecycle functions
To make printing easier
we will move to the NetTPS header file
and add some macros
to make printing easier
In addition to this part, we have also added a NetMode
Now, I'm trying to be able to take a picture like this to see
whether it's running on the server or the client
Enter it in define, leave a space, and write NetMode
Leave a space and get GetNetMode like this
If this function is a client in this NetMode
we put a client
in that NetMode like this
When you call this NetMode
it internally checks to see if you are the client
and then passes the client character
Otherwise
get NetMode, which may not necessarily be a server
Since it can simply run in Standalone mode
it may be NM_Standalone in this NetMode
In cases like this, TEXT
Standalone
Did I put it here like this?
Since it is a ternary operator, let's put it like this
To make it a little easier to see
at NetMode, it's cliented like get
Let's make this with a line break
I've placed a newline character
won symbol
and a backlash And then do line-break
If get NetMode is like this, Standalone
Otherwise, it's called Server
Server
If I close one more horizontal line
NetMode will be done with the opening and closing parentheses here
So what happens then?
First, get the NetMode
and this NetMode value is the client
Then, there was a server window and a client window
With that, you can tell whether
it is currently running in the server
or client window
At that time, I put the string 'client' in this NetMode
and when I looked later, I saw that the NetMode was Standalone
It's not like it's either the client or the server
Standalone, in other words, when we press play in Unreal Editor
there are three NetMode options
There is Standalone, there is a server, and there is a client
In other words, when we run it for the first time, we run it in Standalone mode
In that case, we might just be Standalone
Right, so there are cases where we need to determine
whether it is a Standalone, server, or client in NetMode
So now, when it's a client, it's a client
and when it's a Standalone, it's a Standalone
If not, it was the server, right? Let's say server
Shall we set this to lowercase?
We'll put it like this: Client Standalone Server
Okay, then, let's create another defined macro function this time
I'll put the information on how this is called here
In other words, to display where the function is called
and what line it is on
we will add a macro called callinfo
In this callinfo, open the parenthesis, enter FString
and then insert _ _ function _ _ like this
There are two _ below
Put it like this and then add it
The operator of this FString is overloaded
and the overloading is related to addition
You can link it here by adding additional text
You can leave the text and paste it all with FString
but I will add the text here and then open the parentheses like this
Let's add an opening parenthesis character to the text
Now, let's add a letter after this
FString
Let's do FromInt_ _
This time, we will place the line number line _ _ like this
Then, even the line number is printed
Next, I'll close the text I'll close the parenthesis
It happened like this
Then, if you close one more parenthesis, you'll end up here
You need to open the parenthesis in CALLINFO, close the parenthesis after it
CALLINFO, and leave this macro floating
That's the only way for him to receive this price
If you paste it, it will be called a function, so you must put it like this
Now, let's begin
creating a macro function that prints this
and add the content to be printed using these
Do #define
This time, let's say PRINTLOG
This doesn't have to be left out by one space You have to add it to open the parenthesis
Then, put it in fmt format
Next, we process it to receive the variable argument like this
Next, a space
called UE_LOG can be displayed in the console window in Unreal Engine
Please enter LogTemp here
Let's put a warning, and to display the screen in yellow
open the text brackets
and print the NetMode value here first
It comes in as a %s string value, so put it like this
Next, let's add call info information to see where it is currently being called
Put %s again
Then, some content is output on a few lines in a certain function
So, I'll put a colon like this
and next to it, I'll put the content we want to add, like %s
Now, add NetMode here with a comma
I entered NetMode and will add call info information using a comma
Since CALLINFO is passed as a FString type
we put a pointer to pass the value
CALLINFO
Then, we have to finally display the value here, which came in as a variable argument value, on the screen
So, put it in like this
and use %s string printf
fmt, ##_ _
VA_ARGS, like this
Then, _ _
Close the parentheses and do that
Shall we add one more of these? I tried to search with LogTemp
but I don't like this category either
I don't like this log category either, so I'll put it at the top like this
so we can use our own log category
To declare, DECLARE_LOG_
CATEGORY_EXTERN
Then, we can add our categories
We created our Netlog category
to put everything into the log like this
Are you done?
Insert Netlog in place of the LogTemp
Then, on the screen, we will name this netlog
as a category, and the name we want to record will be displayed in the console window
Done
Now, we added a new NetLog like this, it's DECLARE
This is in the declaration part, so we need one more define
It is at NetTPS.cpp
You need to add it
to the NetTPS.cpp file DEFINE_LOG_CATEGORY
In this way, we have to add a NetLog here
so that the NetLog added to the header is defined and can be used
Now, NetLog is added to NetTPSh and can be used
Now, let's check and process what is being output normally
Now, I told you there was a problem with the lifecycle function when respawning
So, when a character is created
InitUIWidget is called in BeginPlay
but at this time, PlayerController is not Possessing
Right? Currently, the PlayerController is not Possessed
so the lower part of the HUD is disabled
and the part that makes it invisible was not executed
So, let's look at a few lifecycle functions and deal with them
First, if you have Possess
PlayerController will be here
That's right, this NetTPSCharacter is a Pawn
This Pawn is spawned, and when it is spawned, BeginPlay will be called
Right, what should we do at this time?
PlayerController should have been spawned first
I think there is a PlayerController when this is called, so the structure below is displayed
When being Possessed
we need to check
whether this character was Possessed first
or when BeginPlay was called first
So, let's add this to the bottom of
this NetTPSCharacter, public
From PlayerController
when it is Possessed
there is a function We will implement that first
and figure out whether it or BeginPlay is called first
if BeginPlay is called even though Possess is not possible
then there is no PlayerController
Let's check if that's the case
There's a function virtual void PossedBy
It is overrided
Now, let's add the implementation part
Let's declare PossessedBy
and add it to .cpp
To make things a little easier
I will take this to the BeginPlay location
Now, there is an Init widget in BeginPlay
Let's put it below the InitUIWidget
Then, you can check whether PossessedBy
or InitUIWidget is called first
And where is InitUIWidget being called now?
It's being called from BeginPlay
If you call it from BeginPlay
you only need a PlayerController now
But since there isn't one, let's check it here
Add PossessedBy to Super
Now, let's do it in front, PRINTLOG
Let's go to PRINTLOG NetTPS.h and put 'begin' here
Then, I'll put an end to this
What happens in this PossessedBy?
If you put a controller in PossessedBy in Super
and go to the current character class here
you also put PossessedBy's new controller in Super
If you go into this too
what is this doing as the owner of the Pawn?
PlayerController, this is being passed on to the owner of the controller handed over here
Set it up like this
Well, how about that?
Let's put this newly created controller in the controller like this
In PossessedBy
Now, this is how it should be so that the lower part is executed since the value is
entered into the controller in InitUIWidget
But PossessedBy currently has begin
and end rather than begin
If begin play is called before these two, a problem may arise
PlayerController is called even though it is not yet Possessed
So, let's try printing it here as well
I also add 'begin' to InitUIWidget here
I think you just need to click it
Then, wouldn't it be okay to just check if there's a current controller?
Now, let's determine whether there is a player or a controller
so let's set it to begin and put %s at the front
If there is a player here right now
you can mark it as that player
and do Begin
Then, put comma, and if there's that controller
what if it's not null? At TEXT
I'll put PLAYER
Or not
No Player
If you have a controller here, you have a player
Otherwise, let's put it like this: No Player
Oh, I forgot TEXT here
Please enter TEXT
You need to add a macro
This is missing
Now, put the text up here
and at the bottom like this
I forgot the text macro here
so you have to pass it to the text part like this
You have to wrap it once because it is put into
the T character type in Unreal Editor
so you can't pass the FString
Now, let's build it like this
Let's go to Unreal Editor and open the output log window
If you look at the Outpool Log window in the Windows menu
You will see Outpool Log Let me open this
Then, I will search for the NetLog in the filter section
Now, let's play it first
Now, how does it pop up?
If you look at everything here, it's floating on the server PossessedBy begin is displayed on the server
Then PossessedBy End appeared, right?
Then, the PlayerController has been Possessed
Then, begin
Here, in InitUIWidget
PLAYER Begin appears, which means there is a player
In other words, it is called
after PossessedBy is set
It means there are players
Then, let's add a client
Let's add a client play
Now, what are you going to print next?
Let's print the result when it respawns
In this case, when the server shoots the client
I'll press the retry button
I will try the clear log again here and print it again here
Retry, now, what happens? It happens when InitUIWidget is called
This means that the begin play comes first
What happens next?
No Player, there is no player Then the server calls this
What happens?
Possess, there's no problem with this, why?
What do you do first on the server?
You ask to respawn to Server RPC Then I'll first spawn and create it on the server
Just like spawning an actor, since this Pawn is also an actor
So I created this Pawn because it is also an actor
At that time, BeginPlay was called first, and InitUIWidget was called first
At that time, what?
Player, does this have a player?
No, of course not
Then, PossessedBy is called from the server
These are all being called from the server now
PossessedBy is called now
Then, this finally gets a controller, at this pawn
Then, when the client looks at the end, the client
this one
this client becomes spawn
Then, what happens when BeginPlay is called? InitUIWidget is called
This is because the server has already Possessed by when BeginPlay is called
so what about this case?
There's a controller
Now, let's change it and run the server from the client
Bang, bang, bang
Okay, so the above 4 are the contents from before
If things go as planned, what should happen?
BeginPlay is called first at the server
then PossessedBy, and then again called at client
It's like that
Now, let's press the retry button this time
Now, I will clear the log for easier viewing and press the retry button on the server
Click, the UI HUD now appears on the screen
Let's take a quick look at the structure What happens the same way?
InitUIWidget is called
In other words, BeginPlay was called because it had to be spawned first
BeginPlay
But this BeginPlay calls InitUIWidget
So what about this when BeginPlay is called?
Right now
Is controller Possessed or not?
It's not
First, it has to be spawned, and the actor has to be created
Then, what happens is PossessedBy on the server
Then the controller tries to own it like this
In other words, at the point when BeginPlay is called
when BeginPlay is called for this server character, is there a controller present or not?
Does not exist
Then, the PossessedBy controller finally catches it
Only then is the owner relationship established, and a controller is created
Right
And then, at the end, the client is called
At this client, this one at the back
PossessedBy is on this, but what about this?
This thing doesn't have a controller, so it comes out like this normally
In other words, what we can see here is that there is a problem
Not all children start the lifecycle the same way
Looking at it now, when initUI is called on this server, in this case, the UI pops up
because the controller does not Possess it
Then why did it appear in the first place? Let's look at the beginning
Now, I'll leave this as is, and press play
Okay, if you check at this time, from this point to this point
this is the result of the previous execution
What happened when his HUD came out this wrong?
We did respawn, then InitUI, in other words, when BeginPlay was called first
there was no PlayerController, so the UI was displayed above
Then PossessedBy happened
Now, let's take a look below
Now, the three below are newly executed
and in this case, PossessedBy is created first
How do I make a call?
PossessedBy is called first
and then InitUIWidget is called from the server
The flow is different
What should have happened the way it was supposed to?
InitUI should have been called first
When you run it for the first time, what happens first?
It started with PossessedBy and then InitUI
So, it's like this, as if there's no problem
So the lifecycle function comes in like this
so we have to take this into consideration and implement it
Now, let's take a look at an implementation that considers this
Now, come to Visual Studio
and go to BeginPlay, which is the InitUIWidget part
At this time, I think we shouldn't just use one like this; we should verify it and move on
Now, let's analyze when InitUIWidget is called
This is not called unconditionally during BeginPlay, but when do you want it to be called?
When the client is
the main character
I wish it would be called
Why? What does InitUIWidget do?
You only want to work on the UI when there is a PlayerController
In other words, when there is a PlayerController
On the client side, there is also a client on the server
Where do you want this server's client done?
At this Possessed, why? There was a problem running this on the server
There's the problem when run it on server
When you run it for the first time, Possessed happens first
and then InitUI, right?
But how about respawning if you run it again on the server?
At that time, it becomes BeginPlay
So, I want to handle this part where InitUIWidget is called
on the server to run only in PossessedBy on the server
It doesn't matter to the client right now
But since the problem is on the server, InitUIWidget
has to be executed in PossessedBy on the server, and then PossessedBy
has to be like this, and then InitUI has to happen, right?
Now, let's handle it like this
Now, this part called InitUIWidget is called only by the client
If this is locally controlled
but since this locally controlled server also has a client
its character will also be called
But if there's no controller, it doesn't happen
So this part with authority explicitly means that when this is false
I will run the InitUIWidget in this BeginPlay
that does not exist on the client
And on the server
it doesn't matter if you run it in BeginPlay on the client, right?
Where on the server?
It would be a good idea to do it this way so that PossessedBy can run it
And in this PossessedBy, it only runs
At the server
So, in a function that runs only on the server
InitUI is called after PossessedBy
and then in BeginPlay, only on the client
conditions are created
and this has to be executed on the client as well
Next, since it needs to run even when it is a server
let's classify it into two categories
I categorized these two
into server and client and put them like this
So where in PossessedBy?
After the end
the Begin here ends, and after PossessedBy, the controller is created here
In this part, if it is IsLocallyControlled
when it is the main character I am controlling internally
please do InitUIWidget
You can handle it like this Now, build
Okay, I'll go and take another look
This cannot be considered completely resolved
since there may be other problems
Do another one
Now go to the server and bang, bang, bang
Then, when the client plays again
you can see that it appears normally
Now, let's go ahead and shoot the character on the server from the client window
Bang, bang, bang
Then, when you press the retry button on the character on the server
you can see the HPbar above your head like this
but when you press the retry button, it is no longer visible
Now, let's take a look at shooting a gun
When you shoot a gun at the client, press the R key to reload
Look at the UI Is the UI being updated properly now?
This part is not being updated
Should we just keep shooting now? No
Then, let's go to the server and take a look
I will also grab a gun and shoot on the server
Is it working properly on the server?
This isn't working either What's the problem?
We keep calling this UI, InitUI
Since it is called every time it dies, what is being done in this InitUI
creates a new mainUI widget
Then, add it to the viewport and print it on the screen
In other words, there is already an existing UI
but it is continuously overwritten on top of it
It looks like this on the screen
Let's say I already have a widget like this
Like this, right?
On top of this, when it respawns
the player kills it, but on screen, it was blown away by destroying
But this mainUI widget didn't blow up the mainUI
So what else on top? Adding it again like this
If you turn it off and on again, when it dies
you put it back on top again, and so on
So, if we look at this at the top, no matter how hard I try to delete this
it still stays behind
So it looks like it doesn't shrink, as if it doesn't exist
By keep adding more and more, did you understand?
Because of this problem, the existing afterimage remains even though the UI is normally reduced
If there are remnants, what should I do?
This problem is because it keeps creating the MainUI widget if it already exists
If it already exists, we will take care of not creating it
So, because this part is in NetTPSCharacter, it is a problem, why?
This goes along with the lifecycle of NetTPSCharacter
In what way? When NetTPSCharacter is created, the MainUI also exists
Then, when NetTPSCharacter disappears, the reference to it disappears
It's not that the object itself disappears from the world
but the value of this variable that it has disappears
Right? If this thing is reborn
we must keep making it again because it has no value
So, let's try to make this MainUI maintain the data in this variable
instead of going back and forth
So, where are you going to put this MainUI variable? I'm going to move it
Now, we have the MainUI in NetTPSCharacter
There are widget classes to use
I will press Ctrl+C
to import all of this into NetPlayerCharacter.h by pressing Ctrl+C
I'll make it public and paste everything
Next, I will save the ones that were originally in NetTPSCharacter
Let's just leave the variable as is to make it easier to use
The one above
the MainUI widget, will not be received here
but will be assigned to PlayerController
Then, where do this move?
At NetTPSCharacter.cpp file, and here's InitUIWidget
ere, we are importing APlayerController into this PlayerController
which changes our PlayerController to ALetPlayerController
Okay? Change ALetPlayerController, and there is this if part
I don't want to touch this logic part, so I'm putting it like this
When there is a MainUI widget in PlayerController, I try to handle it like this
Change it to the one in PlayerController
Then below this, MainUI
What if the mainUI on PC is
nullptr, we will make this
We're just adding a new value to the MainUI
And how do we put the value in this MainUI as the Main UI on the PC?
And here's the MainUI widget on the PC
Then, the MainUI now has the MainUI on the PC
And then, let's not change all of these main on the PC like this
for ease of use
put the MainUI on the PC as the MainUI
Then, you can just write the following as it is
so let's build it
I'll turn off and turn on the Unreal Editor
I should include this NetPlayerController as well
I'll do #include at the top
and add NetPlayerController.h here
The Unreal Editor appears
Double-click on the BPNetPlayerController to open it
I'll search for MainUI, MainUIWidget
The MainUI widget doesn't have a value right now
so I'll choose the WBP Main UI
BPNetPlayerController used the Main UI widget as the WBP MainUI
Press Compilation, and then go back and run it again
Play
Then it's normal
and now let's see if other users come out
It comes out from far away
I'll grab the gun and shoot the user It's dead now
And then, I'll press the retry button in the client window
Then it respawns again
Okay, let's grab the gun and shoot the gun
So what do you think?
It keeps being added to the side of the screen right now
Added to the side
That means the UI has not yet been updated
The part that resets the UI is missing when it's being answered
So, let's go to InitUIWidget
It comes down from InitUIWidget
which is the problem when you initialize the bullet
If it's already there, you should not do AddBullet
Reset this bullet first
And do it there, but it's missing
And I see it now when the player dies when I play
I will shoot, then HP is all out
Even though you press Retry, it becomes respawned, but HP is not filling up again
In other words, HP hasn't been reset
So, what do we do
when InitUIWidget is called
There's initialization of HP
and what do we do before we do this in this bullet initialization?
We have to remove all the bullets After it's done, we have to add the UI
and we will blow it out and fill it up again
As we continue filling in what was already there
we end up overflowing this content
So, in the health reset section, I will set the HP to MaxHP
and in the MainUI, I will set the value to 1.0 for HP
Was it lowercase?
If the HP in the MainUI is 1.0
then when InitUIWidget is called, it will be initialized and come out in a fully populated state
Then, let's remove all the bullets
It has a RemoveAllAmmo function that we created in the MainUI
Then, all UI will be completely removed to Bullet UI
and initialized again like this
It was InitUIWidget in the cpp file of the NetTPSCharacter
Here, I reset the health
and then added a part to remove all bullets, build again
Let's go ahead and run it
I'll grab the gun and shoot the opponent
Then, if you look at the client window, the HP has decreased
If you press retry, it will refill Then, the user will also shoot
When you fire a gun, the number of bullets should decrease
If it wasn't reduced because it overlapped earlier, I'll shoot it this time
Then, you can check that it is decreasing normally
If you shoot the server character, he dies, and if you press retry normally
the UI is reset to normal
After that, the gun is dropped here, so if you hold it and shoot it
you can see that the UI is updated properly
Now, we have analyzed the respawn and lifecycle function
Let's wrap up what we learned in this lecture
Implementing respawn logic Respawn Logic
Added PlayerStart actor to handle spawn location Create an ANetPlayerController class that inherits APlayerController and implements respawn logic
and restarting the player to respawn is done in the GameMode class
The Retry button and respawn logic are connected in the UI displayed when the player dies
Respawn problem and lifecycle function analysis
Solved the UI problem when the server character respawns in the client window by utilizing the life cycle function
The End