Movement Question

Discussions about Coding and Scripting
Post Reply
User avatar
ANUBITEK
Adept
Posts: 261
Joined: Sun Dec 28, 2014 1:10 am
Location: Anubitek

Movement Question

Post by ANUBITEK »

Right now I have an actor telling my floating camera to do some things that makes the camera strafe to a location, looking at the player. It will move to an actor (Keypoint, CameraNode) before stopping once it touches said node, but I sometimes lock the x/y/z movement or pitch/yaw/roll rotators of the camera. I also give the camera new rotation values, which creates a problem: my camera will move to this node and stop, but not move to where this new offset should be based on it's new location, rotation values, and where the player is (camera is supposed to track the player).

I need the camera to move to the node's location, with an offset based on where the player is and line up the camera with the player. I know how to make my camera strafe to this location, I just need to set this location.

So it would be something like StrafeTo(AdjustLocation, LocalPlayer), but I need to know how to set that adjusted location. I have sort of an idea:

Code: Select all

function AdjustLoc (CameraNode CamNode, Camera Cam, PlayerPawn LocalPlayer, out vector AdjustLocation)
{
	local vector v1, v2;
	
	v1=Cam.Location;
	v2=CamNode.Location;

	AdjustLocation = vector(rotator(v1-v2)+CamNode.NewRotation);
}
<<| http://uncodex.ut-files.com/ |>>

Code reference for UGold, UT99, Unreal2, UT2k3, UT3
Additional Beyond Unreal Wiki Links
wiki.beyondunreal.com/Legacy:Console_Bar
wiki.beyondunreal.com/Exec_commands#Load
wiki.beyondunreal.com/Legacy:Exec_Directive#Loading_Other_Packages
wiki.beyondunreal.com/Legacy:Config_Vars_And_.Ini_Files
wiki.beyondunreal.com/Legacy:INT_File
nogardilaref
Masterful
Posts: 577
Joined: Tue Jun 20, 2017 1:00 pm
Personal rank: ⚋⚊⚌☰⚞⌖⚟☰⚌⚊⚋

Re: Movement Question

Post by nogardilaref »

I am sorry, but I am not really getting what exactly you want to do... however, from what I gather, you just want to move the camera from the player to some "point", but always looking at the player while it does it, correct?

If that's the case, then probably what you want to do is:

Code: Select all

CameraNode CamNode; //the camera node
Camera Cam; //the camera itself
PlayerPawn LocalPlayer; //the local player
float Alpha; //a number between 0.0 and 1.0 to state the progress of movement (0.0 = at the player, 1.0 = at the node)
which can then be used as:

Code: Select all

Cam.SetLocation(LocalPlayer.Location + (CamNode.Location - LocalPlayer.Location) * Alpha);
Cam.SetRotation(rotator(LocalPlayer.Location - Cam.Location));
From here you can modify this to lock the rotation to some angle, or even to keep it (as the conversion from a vector to a rotator has always Roll=0), as well as add any offset you wish.
Alpha can be incremented from 0.0 to 1.0 over time for a movement over time. This is linear interpolation, but if you want it to be more "smooth", you can use smooth interpolation (the quickest way is replacing the Alpha with a Smerp call).
If I understood what you want to do, that is...
User avatar
ANUBITEK
Adept
Posts: 261
Joined: Sun Dec 28, 2014 1:10 am
Location: Anubitek

Re: Movement Question

Post by ANUBITEK »

xmr4axBG2bk

Okay, I can better articulate my issue now after cleaning up some of my code. I have a 3D camera that is told to move from one point to another, either through a setlocation call and some other code (which works), or a strafe:
Spoiler

Code: Select all

				else if ( bInstantLocTransition == false) {
					if ( P.ActiveCamera.CameraMode != CM_MoveTransition ) {
						P.ActiveCamera.CameraMode = CM_MoveTransition;
					}
					P.ActiveCamera.NewLoc = CamNode.location;
				}

Code: Select all

[...]
//================
			case CM_MoveTransition:
				OldRoll=DesiredRotation.Roll;
				bTransitionMoving=true;
				bCamXAxisLock=false;
				bCamYAxisLock=false;
				bCamZAxisLock=false;
				bRestorePitch=false;
				bRestoreYaw=false;
				bRestoreRoll=true;
				if (bRestoreRoll==true) {DesiredRotation.Roll = OldRoll;}
				SetRotation(rotator(Owner.Location-location));
				break;
			//================
[...]

Move:
	if ( CameraMode != CM_MoveTransition && bTransitionMoving == true ) {
		CurCamNode = none;
	    Velocity = vect(0.0,0.0,0.0);
        Acceleration = vect(0.0,0.0,0.0);
		/*if ( NewLoc != vect(0,0,0) )
			SetLocation( NewLoc );*/
		sleep(0.0);
		bTransitionMoving = false;
		GoTo('Reset');
	}
	else if ( CameraMode == CM_MoveTransition && CurCamNode != none ) {
		Velocity = Vector(Rotator(NewLoc - Location)) * 100.0;
		Acceleration = AccelRate * Normal(NewLoc - Location);
		NewLocAdjust = vector(rotator(LocalPlayer.Location-NewLoc)+CurCamNode.NewRotation) + NewLoc;
		StrafeTo(NewLocAdjust, LocalPlayer.Location);
		//MoveTo(NewLoc, Airspeed);
		sleep(0.0);
		GoTo('Move');
	}
Reset:
	sleep(0.0);
	GoTo('Begin');
My issue is that I need to set a New Location once a player touches and actor or moves into a certain part of a zone that makes a camera move to a different location. I have both of these already working. After you watch the short video above, you will notice that my middle camera position causes my camera to snap around quite a bit and my issue is here:

Code: Select all

NewLocAdjust = vector(rotator(LocalPlayer.Location-NewLoc)+CurCamNode.NewRotation) + NewLoc;
My question: how do I make it so my camera moves into a node, then moves to an offset location that would start from said node, rotating to a preset rotation that is lined up with the player and I mean sliding into this new rotation instead of just rotating to the player, make sense? So if my desired pitch is to be -4096 stored in the node and passed to my camera, which my camera will strafe to as it faces my playerpawn, and will be given this new rotation of -4096, which it will rotate into but adjust its Z-axis upward to face down toward my playerpawn, and also strafe with the playerpawn if they move around?
<<| http://uncodex.ut-files.com/ |>>

Code reference for UGold, UT99, Unreal2, UT2k3, UT3
Additional Beyond Unreal Wiki Links
wiki.beyondunreal.com/Legacy:Console_Bar
wiki.beyondunreal.com/Exec_commands#Load
wiki.beyondunreal.com/Legacy:Exec_Directive#Loading_Other_Packages
wiki.beyondunreal.com/Legacy:Config_Vars_And_.Ini_Files
wiki.beyondunreal.com/Legacy:INT_File
nogardilaref
Masterful
Posts: 577
Joined: Tue Jun 20, 2017 1:00 pm
Personal rank: ⚋⚊⚌☰⚞⌖⚟☰⚌⚊⚋

Re: Movement Question

Post by nogardilaref »

Well, I think your first mistake is to make location decisions based on rotation values.
Vectors are easy to deal with, they are linear and follow each axis in a clean scalar way.
Rotators however have a limited range of values, and once you "overflow" it will turn around, and since they're Euler angles, you will get into gimbal locks.

So the first thing you should do is to never decide camera locations based on a rotation, it will only make things harder for you.
Handle locations with vectors alone, and handle rotations with both (since vectors ease the work with rotators transitions a lot).
Ideally you would want to use quartenions instead, but there's really no need to complicate right now.

The second thing is to handle the rate of change over time with "states" rather than incremental progress.
By "states" I don't mean "UScript states", I mean saving the starting and ending locations/rotations in the camera itself, and then interpolate between both over time.
You're using Velocity and Acceleration, and these will always cause issues, and you will keep patching things up to be smooth, and never quite get there that way.
What you want is a precise way of mathetically go from A to B, regardless if you do it linearly or non-linearly.

Physics in general is very flawed in this engine, since it handles non-linear physics in a linear fashion over time.
There are better ways of doing it, which are as fast to run and follow the real physics equations to the letter, but they depend on the same kind of "states" of change.



In other words, you should use the exact kind of functions I posted in my previous post to update the camera over time directly through SetLocation and SetRotation.
All you need to actually do is refactor your camera code so that:

1 - You have a Start and End location and rotation at all times defined in the class itself (StartLocation, EndLocation, StartRotation and EndRotation) and make them private:

Code: Select all

private Vector StartLocation, EndLocation;
private Rotator StartRotation, EndRotation;
They're private so they can be changed by methods you implement in your class alone, and nowhere else, not even from subclasses (and because they're either public or private, you cannot have "protected" in this engine).

2 - The same for the control of time you want to transition from Start to End (TransitionTime and CurrentTime):

Code: Select all

private float TransitionTime, CurrentTime;
3 - You have nothing more than methods which you call like SetEndLocation and SetEndRotation, for example:

Code: Select all

function SetEndLocation(vector Loc, float Time)
{
	StartLocation = Location;
	EndLocation = Loc;
	TransitionTime = Time;
	CurrentTime = 0.0;
}
Same for SetEndRotation.

4 - Then you use the Tick event to update it:

Code: Select all

event Tick(float DeltaTime)
{
	local float Alpha;
	local Vector RVStart, RVEnd;
	local Rotator R;

	//time increase
	CurrentTime += DeltaTime;

	//already finished
	if (CurrentTime >= TransitionTime) {
		if (Location != EndLocation) {
			SetLocation(EndLocation);
		}
		if (Rotation != EndRotation) {
			SetRotation(EndRotation);
		}

	//transition
	} else {
		//alpha
		Alpha = CurrentTime / TransitionTime;

		//location
		SetLocation(StartLocation + (EndLocation - StartLocation) * Alpha);

		//rotation
		RVStart = Vector(StartRotation);
		RVEnd = Vector(EndRotation);
		R = rotator(RVStart + (RVEnd - RVStart) * Alpha);
		//todo: calculate roll as well, a bit more tricky, but easily manageable between "StartRoll" and "EndRoll"
		SetRotation(R);
	}
}
Something like this.


This is a rough version of what you can do, so it can be optimized and whatnot, but this way you're able to have the smoothest camera you can possibly have, and it's not hard to implement.
From here, you could even modify it so the transitions could be non-linear (accelerate when starting and slow down when ending) and add other features such as detect when it's already at the middle of another transition and adjust the time accordingly.
Post Reply