AddMovementInput with additional angles

Hi all, this is actually posted also in the forums : AddMovementInput with additional angles - C++ - Epic Developer Community Forums

I’m using the 3rd person c++ template.
What I am trying to do is set up my character so when he runs through a trigger, it changes his direction by 45 degrees and just keeps running in the correct new direction. The whole time you just hold right on the stick. If you can imagine a camera looking at the guy, he eventually will run in a large octagon around the camera, where there are 8 distinct turns to ensure he gets back to his start position.

in the Character class, the template has :

void ATheTowerCharacter::MoveRight(float Value)
{
	// add movement in that direction
	AddMovementInput(FVector(0.f,1.f,0.f), Value);
}

In my overlap function I capture running over the trigger, then change the angle:

void ATheTowerCharacter::OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	//GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Blue, "OverlapEvent: " + OtherActor->GetName());

	if ((OtherActor != nullptr) && (OtherActor != this))
	{
		// cast actor to AngleChangeTrigger
		AAngleChangeTrigger* const changeTrigger = Cast<AAngleChangeTrigger>(OtherActor);
		if (changeTrigger != nullptr)
		{
			float direction = this->InputComponent->GetAxisValue("MoveRight");
			ChangeAngle(direction);
		}
	}
}

void ATheTowerCharacter::ChangeAngle(float direction)
{
	int multiplayer = FMath::Abs(direction);
	FTransform transform = this->GetTransform();
	transform.ConcatenateRotation(FRotator(0, direction * 45, 0).Quaternion());
	transform.NormalizeRotation();
	this->SetActorTransform(transform);
}

I’m unsure at this stage if I am rotating the right object? ‘this’ is the PlayerCharacter class in the template.
Looking at the screen shot, the guy is rotated but his rotation in the transform view does not appear to have any rotation applied?
I expected when the MoveRight method says move right, it is relative to it’s transform, but it does not appear so?

Cheers

Easier to use AddActorLocalRotation(FRot(0.f, 45.f, 0.f)) for your trigger event.

AddMovementInput moves the character by world axis. So you need to use either a different function or use this vector GetActorRightVector(). GetActorRightVector gives you a normalized 1 length vector, so your speed should be the same.

Thanks mate, you have put me on a good path here.

I changed my code to this now:

constructor....
MovementVector  = this->GetActorForwardVector();

void ATheTowerCharacter::MoveRight(float Value)
{
	AddMovementInput(MovementVector, Value);
}

void ATheTowerCharacter::ChangeAngle()
{
	float multiplyer = this->InputComponent->GetAxisValue("MoveRight");

	if (multiplyer >= 0)
		multiplyer = 1.0f;
	else multiplyer = -1.0f;

	this->AddActorLocalRotation(FRotator(0.f, multiplyer * 11.250f, 0.f));
	MovementVector = this->GetActorForwardVector();
}

So I still am using that AddMovementInput, though I would prefer not to.
I think another issue I am having is the fact the player has to ‘turn’ when I change direction. So If I am going left, he does a turn before going right. This leads to a situation where my player is on the trigger while turning, no matter if I use BeginOverlap or EndOverlap, can I turn this ‘turning’ off, or is that due to me using AddMovementInput?

It’s hard to explain, but before I go for a long search would it be better to do something like this:

MoveRight Method:

  • Get forward Vector

  • Is Vector facing left?

  • Am I attempting to turn right?

  • Rotate 180

  • OR Is Vector facing right?

  • Am I attempting to turn left?

  • Rotate 180

  • List item

  • Get forward Vector

  • this->AddLocalOffset(ForwardVector * speed);

though this feels clunky.
Another option is to keep my own Z rotation…

I’m at a bit of a loss here as I can’t really understand your problem. You mean that the character does a turning animation you’d like to get rid of or that the beginoverlap is applied twice if you change direction on the trigger?

I actually had a similar problem with my own game (although visually not similar, but technically fairly similar) where I adjust gravity direction. What I did was: I made a separate object called Graviton with a massive overlap event that added the character into an array called “overlappers”. The tick function for Graviton goes through all of the characters in the overlappers array (my game is multiplayer) and adjust their gravity towards the vector that points from the actor to the Graviton. The object is then placed inside a planet’s so the planet has a gravity field and the planet functions as the walking surface. Thus the gravity always points to the middle.

For your application you could make something similar - but with the following adjustment: when the angle of your actor’s forward vector and the vector to the middle becomes too large/small it adjusts automatically. This way you are constantly checking it and you don’t have to rely on overlap events that might not work very well, especially if you double back on them. Overlap events also don’t fire if you happen to spawn on one or something else a bit weird happens.

Thanks for your help Groatse, you led me down a dark path of unreal documentation and reading to eventually get to some kind of answer :slight_smile: I think I should have waited to type in some of the comments I made because looking at them, they don’t make sense. No wonder it sounded confusing.

In the end for a prototype I have decided to ‘teleport’ to a final spot, rather then work with running through the trigger and changing direction.
As a VR prototype test, this means I can go through a ‘door’ (trigger) and be teleported to another spot - so in my case, walk through the teleport, move the character, deactivate the old ‘area’ and activate the new ‘area’ the player now finds himself in.

this is the core code of what I ended up with to get me to the correct spot and running in a continuous direction:

void ATheTowerCharacter::OnOverlapEnd(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{

	if ((OtherActor != nullptr) && (OtherActor != this))
	{
		// cast actor to AngleChangeTrigger
		AAngleChangeTrigger* const changeTrigger = Cast<AAngleChangeTrigger>(OtherActor);
		if (changeTrigger != nullptr)
		{
			// First determine if we can enter the trigger this way
			float multiplyer = this->InputComponent->GetAxisValue("MoveRight");

			// travelling right AND is a right entered trigger...
			// OR 
			// travelling left and is a left entered trigger...
			if (multiplyer >= 0 && changeTrigger->IsRightSideTrigger() ||
				multiplyer < 0 && !changeTrigger->IsRightSideTrigger())
			{
				AActor* spawnTarget = changeTrigger->GetSpawnTarget();

				this->TeleportTo(spawnTarget->GetActorLocation(), spawnTarget->GetActorRotation());
				if (multiplyer >= 0)
					MovementVector = this->GetActorForwardVector();
				else MovementVector = this->GetActorForwardVector() * -1;

				spawnTarget = nullptr;
			}
		}
	}
}