Move Camera in Direction Character is facing (->mouse is pointing)

Hello guys
I’ve got a Top-Down prototype and my character is always facing the mouse pointer.
Now I want the character to see more of the terrain in the direction he is currently facing, like this when facing top (mouse is at top right of the screen):

http://i.imgur.com/HestzP5.jpg++

Or like this when the mouse is on the bottom right of the screen:

http://i.imgur.com/CB3RhoP.jpg

As you can see, I somehow got it to working by simply adding
CameraSpringArm->RelativeLocation = FVector(300.f, 0.f, 0.f);
to my SpringArmComponent.

There is a problem with that though: I cannot move the mouse closer than 300 units near the character, or the springarm will twitch like crazy. I guess it can’t go lower than 300 because of the RelativeLocation.

How can I keep the camera offset (ANY solution is welcome) in the direction the character is facing (->mouse is pointing), and be able to move the mouse pointer over the character without the camera twitching and turning like crazy?

Note: 300 should be the maxvalue the camera lets the user see more of the terrain.

Thanks for your time and help!

Hi ,

It looks like to me the best way to fix your problem of the camera twitching like crazy would be to add a dead-zone for when the cursor gets within that twitchy range. This could be easily implemented using a if/else check before the calculation for the RelativeLocation is made. This would however cause the camera to stay where it was before entering the dead-zone, or cause it to focus on the character again.

If that doesn’t work for your needs or just doesn’t look right, you could also go for a smooth approach where the camera moves in and out based on how far the mouse is from the character. This could be done by taking the offset of the cursor’s location from the character and halving it, so that the camera is always focused on the median between the two positions.

If neither of these work out for you, please let me know. I’d be happy to think of some other ways.

Have a nice day,

Hey , thanks for taking the time and helping me!

I tried some stuff for the last few hours and it’s getting late here but I can’t get it to work. Maybe you can help me out?
This is my attempt at doing it the first way (deadzone):

void ARPGTestCharacter::CalculateCamera()
{
	APlayerController *playerController = Cast<APlayerController>(GetController());
	float xMouse;
	float yMouse;
	playerController->GetMousePosition(xMouse, yMouse);
	FVector2D mousePosition = FVector2D(xMouse, yMouse);

	FVector charLoc = currentChar->GetActorLocation();
	FVector2D charInScreen;
	playerController->ProjectWorldLocationToScreen(charLoc, charInScreen);

	// FVector2D upperRight = FVector2D(charInScreen.X + xMouse, charInScreen.Y + yMouse);
	// FVector2D bottomLeft = FVector2D(charInScreen.X - xMouse, charInScreen.Y - yMouse);
	
	FVector2D upperLeft = FVector2D(charInScreen.X - xMouse, charInScreen.Y + yMouse);
	FVector2D bottomRight = FVector2D(charInScreen.X + xMouse, charInScreen.Y - yMouse);
	
	if (bZoom)
	{
		if (((mousePosition.X >= upperLeft.X) && (mousePosition.Y <= upperLeft.Y)) && ((mousePosition.X <= bottomRight.X) && (mousePosition.Y >= bottomRight.Y)))
		{
			CameraSpringArm->RelativeLocation = FVector(0.f, 0.f, 0.f);
		}
		else
		{
			CameraSpringArm->RelativeLocation = FVector(300.f, 0.f, 0.f);
		}
	}
	else if (!bZoom)
	{
		CameraSpringArm->RelativeLocation = FVector(0.f, 0.f, 0.f);
	}
}

I’m new to all this, so please bear with me! :slight_smile:

I’ve tried creating a rectangle around my character and if the mouse moves in that rectangle, the camera location switches back to normal. This works fine, but ONLY for up, up/left, left, and down/left. It doesn’t work if my mouse is on the right side of the screen or at the bottom or bottom/right.

I’ve tried scribbling some diagrams to see where I’m wrong, but as I said it’s getting late and I cannot trust my mind, maybe you can see some error in my logic? (Hopefully probably)

I haven’t tried the smooth way since I’m doing TurnToMouse() stuff for my character

with the help of FVector2Ds and I can’t convert them to FVector for

CameraSpringArm->RelativeLocation to work.
I’d be deeply grateful if you could guide me through this and/or maybe even write

some pseudo code.

Again, thanks for your time!

Hi ,

Looking at the code and calculations you provided, I think the problem is the calculations that you’re using. The origin for the on-screen coordinates for things like MousePosition and interface elements is at the top left of the game window, instead of the middle like a normal graph. In this case, the higher the Y coordinate in the positive direction, the further down the screen it will go. This would explain why half of your calculations are working but the others are not. One way you could test this would be to set up the MousePosition to be printed to the screen on tick through a debug message.

This should fix the problem for you, but if you need any further help, please let me know.

Have a nice day,

Thank you and I want to apologize for the inconvenience I’ll be causing now but now I tried the smooth approach since it really just looks nicer and this is my code so far:

void ARPGTestCharacter::CalculateCamera()
{
	APlayerController *playerController = Cast<APlayerController>(GetController());
	float xMouse;
	float yMouse;
	playerController->GetMousePosition(xMouse, yMouse);

	FVector2D mousePosition = FVector2D(xMouse, yMouse);

	float xCamera;
	float yCamera;
	float finalCam;

	FVector charLoc = currentChar->GetActorLocation();
	FVector2D charInScreen;
	playerController->ProjectWorldLocationToScreen(charLoc, charInScreen);

	xCamera = (mousePosition.X - charInScreen.X) / 2;
	if (xCamera <= 0)
	{
		xCamera *= -1;
	}

	yCamera = (mousePosition.Y - charInScreen.Y) / 2;
	if (yCamera <= 0)
	{
		yCamera *= -1;
	}

	finalCam = xCamera + yCamera;
	
	GEngine->AddOnScreenDebugMessage(5, 5.f, FColor::Green, FString::SanitizeFloat(finalCam));

	if (finalCam <= 300 && finalCam >= 0)
	{
		CameraSpringArm->SetRelativeLocation(FVector(finalCam, 0.f, 0.f));
	}
}

It works fine except when one I move the mouse over the zero-point of my new axis, here’s a picture of what I mean:

It’s kinda hard to describe but I hope I could explain well enough whats happening.
Sorry for the awful picture, I hope it serves it’s purpose.
Just imagine that I move the mouse along the line, but the camera behaves like the blue line

=> Distance to character decreases when the axis value gets lower.

Any idea how to fix this?
Again: sorry for the inconvenience I may be causing.
Thanks for your time and help!

Hi ,

Don’t worry about inconvenience, I’m here to help. I believe this issue is being caused by your calculations as well. One thing that would help a lot with the calculations would be to convert things into to percentages, as the max X and max Y are different due to the wide-screen configuration. Currently your calculations are perfect for corners, but fall short when exiting the corners, which is causing the camera to go in a little further at those spots. I’ll explain what is happening your calculations currently

For simplicity, lets assume that the top left is (0,0) and the bottom right is (100,100). The character is in the middle of the screen, making his coordinates (50,50).

If the cursor is in the top right, the coordinates are (100,0). The xMouse is subtracted by xChar giving us (50,0). It is then divided by 2, giving us (25,0). Next, the yMouse is subtracted by yChar, giving us (25,-50). It is then divided by 2, giving us (25,-25). This y is negative so it fails the if check, causing it to be turned into a positive, so we have (25,25). After that they are added together for finalcam giving us 50. This causes the camera to go to the correct position, at the top right of the blue box in your picture.

If the cursor is at the far right of the screen but half way between top and bottom, the coordinates are (100, 50). The X formula gives us (25,50) again. The difference this time is the Y coordinate. yMouse is subtracted by yChar, giving us (25,0). Dividing by 2 does nothing and it’s equal to 0 so we skip the if. This gives us an ending coordinate of (25,0). The two coordinates are added together to be 25, causing the camera to only go out half as far as it did before. This causes the dip.

The best solution would probably be to set up all your calculations so that they consider your character to be the origin. You could base everything off of an offset of the character instead of off the top left of the screen to make the calculations more direct.

I hope this is enough to help you nail down this mechanic, it sure is a tricky one. If you need anything else, please don’t hesitate to respond.

Have a nice day,

So I’ve tried some stuff to no avail.
First I was projecting the mouse position to the 3D world, subtracted that FVector from the GetActorLocation() of my character and halved it, then set my camera to that position, but the results were strange and worse than the old calculation with the “bumping”, kinda hard to explain but it didn’t work at all :/.

I know you’re using clear and huge signs to hint me in the right direction but I feel like giving up right now. It may be hard but could you be more specific in what exactly I have to do?
I can’t seem to get it right now and I yearn an “aha-moment”.
Everything would work for me (as long as I can hover the mouse over 3D objects without the camera twitching).
Huge thanks in advance!

Hi ,

The way that it seems your camera is being moved, you shouldn’t even need to factor in the actual position of the cursor, but only the offset of the cursor and the character. From what I understand of your code so far, finalcam is a number that is dictating how far the camera moves out from the character in the direction that the character is facing. If this is correct, the easiest way to do this would to modify the calculations from your previous post.

Start by removing the division part. If you subtract the xMouse by the xChar and the yMouse by the yChar and then make them both positive (If either went negative), you can then ignore whichever value is the lower of the two. You can then use the number you’re not ignoring to position the camera. This should make it so that if the cursor is brought around the border as in your picture, it’ll follow without dipping back in as it did before.

If I’m wrong in assuming that the camera is being moved in the direction the camera is facing, I’m going to need to know how it is being moved to be able to help further.

Have a nice day,

This works almost perfect! Since I want the camera to move a max distance of 300, this is my condition for it moving:

    	if (finalCam <= 300 && finalCam >= 0)
    	{
    		CameraSpringArm->SetRelativeLocation(FVector(finalCam, 0.f, 0.f));
    	}

A few thoughts though:
1: It works perfectly only if my mouse cursor is out of 300 range from my character.
Lets say I enter the 300 range “sphere” around my character with my mouse from the right. It then pushes the camera, therefore the mouse and therefore again the camera to the units 300 left of my character. One movement triggers the other I guess.

Turning the character around with the mouse inside 300 range of the character is impossible to do controlled. Could this be because I adjust the CameraSpringArm instead of the CameraComponent?

2: I tried stuff and when I change the condition and the SetRelativeLocation()
to if (finalCam <= 900 && finalCam >= 0) { CameraSpringArm->SetRelativeLocation(FVector(finalCam / 3, 0.f, 0.f)); }

it works much better when the mouse is inside the 300 range of the character. I still get the same vision bonus as before, too. But the “bumps” are back when I move the mouse a little further out from the character. This time the mouse moves outward which makes sense since the mouse it on the center (x-axis) top/bottom and the camera needs to move outwards at that point, it just looks a little sluggish but that’s all.

If this can be fixed by making “top-right” and “top-left” go as far out to the top as “top-center” I’d love to know how this could be done!

3: All these literal values I’m using, can they cause problems with other displays? E.g. some players being able to look further/not as far as others?

Thanks for taking the time to solve my problem!
I hope you have a nice day and hopefully encounter less needing people as me, haha.

  1. The best way to counteract this would be to implement the deadzone that was previously mentioned. I would suggest having it so that if the cursor gets that close, the camera centers on the player until the cursor exits that limit again.

  2. I’m not sure why you’re receiving the opposite effect now with your camera movement when at the bounds. If you need help with figuring this section out, can you post your code that does the calculations with the new revisions?

  3. I personally am unsure if this would cause a problem. I would suggest using less ‘Magic numbers’, as they are often referred to, and assigning numbers to appropriately named variables. This also makes for more readability in your code. Converting values to percentages could eliminate that issue.

No problem, I’m glad to help. Follow up if you need any more input.

Have a nice day,