Announcing Section #1 for Survival Game - Third-person Player Setup

I may be a little behind on this, but while looking at the code, I see in the ASCharacter class this line in the constructor

class SURVIVALGAME_API ASCharacter : public ACharacter

I recognize most of that syntax except for ‘SURVIVALGAME_API’ I would expect this instead

class ASCharacter : public ACharacter

What is that extra part of the class declaration?

It’s specific to UE4 way of dealing with modules, if you’re just dealing with one module (which is the default) you need not worry about it, it becomes relevant when dealing with multiple game modules to import classes into another module.

Some info on here: Unreal Engine 4 Programming API Fundamentals

Hi, i’m studying this project, specially the networking stuff, cause i didn’t do anything networked before , so I am sorry for this question with probably a obvious answer.
I’m a little confused about how do you get the local player controller or the character, because i’m trying to extend some functionality and i dont know how do you do that.
For example on SWeapon you return “MyPawn”



class ASCharacter* ASWeapon::GetPawnOwner() const
{
	return MyPawn;
}


So how does SWeapon know about the local ASCharacter? where is MyPawn initialized?

What i’m trying to do?
Well, Im just trying to get the Local Player Controller or the Character in other Actor class
Probably i need to get better informed, so im sorry for the very basic question :), oh and for my English.

It’s the function below GetPawnOwner, called SetOwningPawn() which is set by OnEnterInventory() in our weapon class.

This is one of those things you’ll have some difficulty wrapping your head around when you’re starting to deal with the game framework and replication.

If you have any interaction with the Actor that requires the Character, eg. check out ASCharacter::Use() and ASUsableActor::OnUsed(APawn* InstigatorPawn) for one example on how I pass a reference of my character into an actor.

Another way is to grab all pawns in your level through GetWorld()->GetPawnIterator() and use that in a for-loop like so:

(Example from PawnSensingComponent)

If you want to make your game for multiplayer you cannot simply pick the first character reference you can grab, you’ll need to figure out what character you need to deal with by doing something with the iterator of all pawns in the world, or by passing a reference of the character that currently interacts with the object, like I did with Use() in my Character.

I hope that helps! Let me know if something is still unclear.

Thanks for your time, yes i understand what you said and i had an idea about that, but i didn’t know how to properly implement this, so thanks again for the help :slight_smile:

Hello :slight_smile:

I a bit late following the tutorial, but there’s something I’m having some trouble to understand.

When creating a FPS Template for C++, the default Jump binding is:


	InputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
	InputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);

And inspecting these functions, I find this code:


void ACharacter::Jump()
{
	bPressedJump = true;
	JumpKeyHoldTime = 0.0f;
}

void ACharacter::StopJumping()
{
	bPressedJump = false;
	JumpKeyHoldTime = 0.0f;
}


Your code is far more complex. I’ll copy and paste here, in case someone else, in future, have trouble understanding it:


void ASCharacter::OnStartJump()
{
	bPressedJump = true;

	SetIsJumping(true);
}


void ASCharacter::OnStopJump()
{
	bPressedJump = false;
}


bool ASCharacter::IsInitiatedJump() const
{
	return bIsJumping;
}


void ASCharacter::SetIsJumping(bool NewJumping)
{
	bIsJumping = NewJumping;

	if (Role < ROLE_Authority)
	{
		ServerSetIsJumping(NewJumping);
	}
}


void ASCharacter::OnLanded(const FHitResult& Hit)
{
	Super::OnLanded(Hit);

	SetIsJumping(false);
}

void ASCharacter::ServerSetIsJumping_Implementation(bool NewJumping)
{
	SetIsJumping(NewJumping);
}

bool ASCharacter::ServerSetIsJumping_Validate(bool NewJumping)
{
	return true;
}


and



void ASCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	// Removed some unrelated code here

	DOREPLIFETIME_CONDITION(ASCharacter, bIsJumping, COND_SkipOwner);
}


Apparently, the default jump from UE4 works, without the need to replicate the bPressedJump boolean to clients.
This is where confusion starts. Why make it in such different way?
Are there any advantages?
And… Is there a reason why there’s no (at least not explicit) replication of bPressedJump boolean on UE4 default code?

Thank you in advance!

Hi Zoc,

Mine is more complicated because we have to replicate the animation for the third person meshes which relies on this bIsJumping value. This requires the clients to know that is jump is happening.

@what is the way to check if the character is idle or is moving ?

In the AnimBlueprint I use the Velocity of the player for this. You should have access to GetVelocity()

Thanks you i going to try that! ^^

Hey !
Thank you for your reply!
I was about to thank you for your explanation and I thought I understood… Until I remembered I did some testing with default jump, and I got this:

http://files.1337upload.net/default-jump-27f7d7.gif

I’m sorry to ask again about this, but… I’m having trouble to understand why it’s working with the default code.
I found this article aboutit, but it’s a bit too much for me (at least for now, while I’m still learning a LOT about UE4).

About the project, I’m using the protocharacters pack (just because I like them more than the standard blue one), with the animations imported from the third person shooter C++ template, and these were added to the FPS C++ template.
There’s no custom work in the animations or the way they are handled.

If you can give me some insight on the matter, you’d really make a student very happy! :smiley:

Thank you again!

Interesting! I don’t have enough details on your implementation though. I am seeing a networked client in that GIF or is it just a placed character with animBP? Did you record it from the server side (eg. the first player) or from a client?

That’s a networked client (by setting the number of players to 2 in UE4 editor) :slight_smile:

Instead of trying to explain what I did, I create a new project and submitted it to GitHub: https://github.com/TheZoc/UE4Jump

This is what I changed:

Code side:

  • Moved the source files to Private and Public folders (I really like them this way)
  • On the UE4JumpCharacter.cpp file, I added this to the constructor:

	// Let's hide our 3rd person mesh for ourselves
	GetMesh()->SetOwnerNoSee(true);

Editor Side:

  • Merged Third Person Model and Animations (from the template).
  • Added Third person mesh to the Character blueprint.

And that was it. Oh, I also added my .gitignore file (maybe it is useful to you :slight_smile: ).

EDIT: Forgot to mention: That gif could have been recorded either in listen server or in the client, the behavior is the same :slight_smile:

So I had a look at the source with bPressedJump and it’s not replicated across the server/client. So a client shouldn’t be able to ‘see’ the other character jump animation unless I’m missing something in the source of bPressedJump. I suspect it’s being pushed around to clients through the FSavedMove_Character data in the CharacterMovementComponent.

One difference between the two variables is that bPressedJump can become false even while still in the air, while we keep bIsJumping to remain true while airborne. bPressedJump is used for example to allow continuous Z-velocity force pushes while the jump-key remains pressed down to give variable jump height to your character. With that in mind it might not be the best place to attach your jumping animation to.

Thanks for these tutorials! I am a little late to the party and just starting off with Section 1… Quick question: This is for OSX as well, right? I got a compilation error in SLocalPlayer.cpp at



FString USLocalPlayer::GetNickname() const
{
	/* Try to fetch a nickname from the online subsystem (eg. Steam) if available */
	FString NickName = Super::GetNickname();

	if (NickName.IsEmpty())
	{
		// Fall back if no nickname was available through the online subsystem.
		**NickName = FWindowsPlatformProcess::ComputerName() + FString::FromInt(FMath::RandRange(0, 999));**
	}

	return NickName;
}


flagging FWindowsPlatformProcess. Couldn’t find this in the API and replaced it with FGenericPlatformProcess which seemed to work - is that a valid replacement?

Hey thanks for spotting this! I’ll see if I can get this fixed to work on all platforms. FGenericPlatformProcess will only return a “GenericComputer”, so that’s not what we’re looking for. (I’ll see what #if platform defines are available for compilation)

Hey , I’ve only just started looking at this now and it is really great what you are doing.

Couple of questions.

  1. How come you don’t use the Character Movement Component to handle jumping for the player like they do in the Shooter Game example?

  2. Would it be better to make Useable a component that can be attached to an actor (to make it useable) rather than requiring an actor to inherit from Useable (which could end up in inheritance spaghetti if you later need something to be both Useable and something else at the same time)?

Cheers.

Perhaps this is reverting back some…

This project has


TArray<ASWeapon*> Inventory;

In my project, I have an error on a line like this telling me undeclared identifier. I’m wondering if I’m missing an include in another file or something.

You could be missing an include of include “SWeapon.h” in the file of the inventory, or you need to change it to:


TArray<class ASWeapon*> Inventory;

the “class” keyword is a forward declaration and tells the compiler it will be a class. There is a pretty good explanation on forward declaration on StackOverflow.

Hi Wilberolive,

  1. I am using the same method as ShooterGame to handle jumping with some extra functionality.

  2. That is a very viable option! With the recent improvements to component editing this is an good alternative.