Camera Dragging

Not really making a game, just learning how to do different things right now.

So I’ve been working with cameras lately. I’ve built a ‘top down’ type system where the camera is the player pawn. So far, I can click on an actor and the camera moves to that actor. I can hold the right mouse button and rotate my camera up/down and left/right and all this is working fine.

The next thing I was trying to do is drag by holding the left mouse button. Hold the LMB and drag the map to reposition the camera. This works fine as long as I’m facing north (I guess what I’m defining as north) However, if I rotate around and do it, everything moves backwards. Negative X on the mouse is now opposite of what negative x in the world is.

How do I compensate for this? I’ve tried a dozen different things, but they were not successful. I’m not fully wrapping my brain around what needs to happen to make this work properly. I could use some advice or maybe a pointer to a tutorial or something.

Thanks.

You need some trig.

Take the current actor location. use the forward vector. and always just pan around based on the forward vector so that up is always up and the rest of it follows.
I guess you don’t even really need trig. just using the forward vector to define what’s + and what’s -

This is assuming that your actor actually rotates around during the other functions.

If you are actually moving the camera actor around this becomes rather easy.

There is no great top down tutorial because literally everyone likes different setups.
You can try to emulate the game you like best / find a guide for it.

Please explain what you mean by using the forward vector to define what + and - are.

I thought that using SetRelativeLocation instead of SetWorldLocation would do that, but both are producing the exact same result.

I assumed some trig would be involved and I’ve no issue with that, just don’t know what trig to do.

I have no frame of reference to be able to tell you what to do or explain.

Normally, you take the actor forward vector and you add impulse on that vector or subtract from it to go forward or backwards.
That makes it so that no matter what, in 3D space your actor walks forward when you press forward.

For right left you can do the same user Right Vector.

It’s rather straightforward, you’ll find it in ANY of the template for basic movement.

I have no idea HOW you are moving your camera pawn, but I would assume this to be very much the same if you are using Pawn Movement.
You can lift the exact behavior off the space ship template thing. twin stick shooter ? can’t recall the name of it.

Project: CameraLearning
Blank project, no starter content

Entire contents: 1 blueprint called CameraPawn_BP (and the default map)

The CameraPawn blueprint has a scene component as the root, a spring arm attached to that, and a camera attached to the spring arm.

All the “movement” is controlled by SetActorWorldRotation, SetActorLocalRotation, SetActorLocation, AddActorWorldRotation etc, based on mouse inputs. I use a timeline and lerp when I select an actor which moves the camera to that actor.

… and that’s it. I deleted everything but the floor, dupped it a few times to test the “movement” between them when selected.

No movement component, no player controller, no anything else.

I’m just trying to learn, not build a game.

Anyway, none of the templets have the functionality I’m trying to build, so there was no point in using any of them.

I want to left click and drag the map under the camera (technically it’s the camera that moves not the map) … and it works, but only in world space. So moving the mouse in a -X directions results in the camera moving in a +X direction (simulating the world moving underneath) The problem is when I rotate my camera to another direction. Now I’m facing “south” and moving the mouse in a -X direction results in the world STILL moving in the +X direction, but I need it to move relative to my facing and NOT according to absolute world space direction. Unfortunately, none of the relative functions, like SetRelativeLocation, seem to function.

Plugging my mouse inputs to all of the following have produced the exact same results:

SetActorLocation
AddActorLocalTransform (Splitting the pins and using just the location ones.)
SetActorRelativeLocation
SetRelativeLocation
SetWorldLocation

All of these work, as long as I’m only facing north, and don’t work as intended if I’m facing any other direction.

I tried some others that didn’t seem to work at all like

AddActorLocalOffset
and others I don’t remember now

Thanks for the help

You have decoupling happening.

When you drag Left to Right you expect to pan on X.
This isn’t true if your actor is rotated by 90 for instance, you’d be panning on Y.

As such, you need to define what Left to Right means in reference to the Actor.

You can use something like LookAtRotation to determine the Z value of the rotation.

OR you can do trig.
AcosD ( dot ( click location normalized , actor forward vector) )
Essentially the same as lookat but done manually.
You get a result in degrees of where the click was compared to the forward vector.

If you remove acosD it’s cheaper, and you just test it knowing that 1 as a result means same direction, and -1 means opposite.
0 can be either left or right, but you won’t know which.
You can use GetDotProductTo as well

To re-iterate.
What moves the camera around should be the exact same function that you also use with key presses. So Direction (forward vector or right vector) * Axis value.

What determines if you are going left or right when the camera is separated/rotated is a function call (or an exec connection to the same function the movement calls for) determined by the angle result.

Does that make any more sense?

The DotProduct didn’t work for me, (or I couldn’t figure out how to make it work) but when I looked into it, it reoriented my thinking along the right path.

I got it working using the trig. I was forgetting that I may only be moving the mouse in the X direction, but when I’m rotated, some of that will have to be added to the Y, (all of it if I’m facing 90 or -90 degrees)

Appreciate your help once again. Thanks for offering suggests!!! They put my brain on the right path. If you’re interested, here’s the final product which works very well:

1 Like

It’s likely faster than solving dot product so it seems like a good solution.

Is there a difference in practice between using sind / cosd and sin / cos ?

their value will be 0 to 1 instead of 0 to 360
90 + would then be .5

Wouldn’t change much performance wise, but it’s cheaper not to have to multiply the value by 57.2958 to get to degrees. Kinda talking nonesens in terms of final cost. Still.

The options were “SIN (degrees)” and “SIN (radians)”. They show as SINd and SINr in the graph. The rotation is already in degrees, so SINd and COSd seemed the way to go rather than first converting to radians. A more efficient way wouldn’t hurt my feelings, but this works and I have no thoughts on how to make it better.

sin and cos are always a ratio. Doesn’t matter what the measure you feed them is.
SOHCAHTOA and all that.

You have to accommodate the type of value you pass in. with DegCos
you are going from degrees to radians before using a cosine.
The result you get is always in radians.

So yea. because you are coming off a measure that’s already in degrees it’s what you use.

Under the hood it goes something like COS (PI/180 * float )
That’s not necessarily cheap.

if you took the value and did * PI / 180 once, then used COS and SIN instead, you’d get the same result and save up on 3 calculations.

The end result should be faster despite the difference being infinitesimal.
– Someone correct me if I’m wrong.

IF you didn’t do PI / 180 but used 0.01745 directly to multiply, you’d cut that by one operation more. even if you loose precision, which generally speaking doesn’t matter all that much past the 6th or 7th decimal.

And I’m literally only pointing this out because you are learning to do stuff.
Optimizing things – even unimportant things like this – is something everyone should consider.

Also, always because you are learning stuff.
You can make a C++ project, create a class, add a UKismetMathLibrary header to it, and peek at the function definitions to see what the engine actually does when you call the blueprint functions.

Thanks for this tip. I’ve been thinking to convert that whole mess I showed you into a C++ function (as a learning exercise.) I haven’t done much programming in years (25 years, give or take), and I’ve never used C++ at all, but I bet it will come back pretty quick. I am (was) well versed in C (and a few other languages) and I’m guessing that C++ won’t be too far removed from C.

I did play around a little bit with Python a year or so ago, and I found that I picked it up rather quickly. It’s just a matter of learning the syntax, the concepts don’t really change. (A ‘do while’ loop is a ‘do while’ loop, regardless of which language it’s in, just different syntax required.) So I expect when I get to the point that I’m ready to start with the C++ that it won’t be a big challenge.

I added another movement ability to my camera, moving the mouse the the edge of the viewport now scrolls the map in that direction. That turned out to be pretty easy as the hard part, adjusting for the camera rotation, was already taken care of by the code shown above. I just collapsed it into a function and reused it. I have one more camera manipulation ability I want to tackle then maybe I’ll jump headlong into the C++ thing.

P.S. I never did figure out the POV hat thing, but I did get my ‘space flight simulator’ working quite well though. I can fly around in the vast empty nothingness of my vast empty level just as well as in any space flight simulator game I’ve played.