Making a ScriptedPawn move (via Player input)

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

Making a ScriptedPawn move (via Player input)

Post by ANUBITEK »

I've made a ScriptedPawn that can be passed player input (RPG_Puppet) from a now arbitrary player class (PlayerPawn -> RPG_Controller). I use a function call in RPG_Controller:

Code: Select all

event PlayerInput( float DeltaTime )
{
	[...]
	ActivePuppet.ControlMove(DeltaTime, aForward, aStrafe, aUp, bUp, bDown, bLeft, bRight, bPressedJump, rot(0,0,0));
	[...]
}
to pass in a bunch of byte values for debugging (bUp, bDown, bLeft, bRight) and aForward (float value) which is set via:

Code: Select all

aBaseY = 300.0 [THIS IS AN AXIS VALUE VIA INPUT]
aForward+=aBaseY;
And I have a state set up with the ControlMove() function in it, which is being successfully called and makes my pawn slide around. But I have a problem: my pawn slides and stops with no slowing/easing, it is an immediate stop. Can anyone help me understand Acceleration, Velocity, and Speed2D in the context of trying to make a pawn move around? Here is the code I have so far:
Spoiler

Code: Select all

function ControlMove(float DeltaTime, float aForward, float aStrafe, float aUp, byte bUp, byte bDown, byte bLeft, byte bRight, bool bPressedJump, rotator DeltaRot)
	{
		local vector X,Y,Z, OldAccel, NewAccel;
		local rotator OldRotation;
		local float Speed2D;
		local bool    bSaveJump;

		aForward *= 0.1;
		aStrafe  *= 0.1;
		GetAxes(Rotation,X,Y,Z);
		Acceleration = aForward*X + aStrafe*Y + aUp*Z;

		if ( bPressedJump ) {DoJump();}

		if ( Physics!=PHYS_Spider ) {NewAccel.Z = 0;}

		if (Physics == PHYS_Walking) {
			Speed2D = Sqrt(Velocity.X * Velocity.X + Velocity.Y * Velocity.Y);
		}

		// Update rotation.
		OldRotation = Rotation;
		UpdateRotation(DeltaTime, 0);

		if ( bPressedJump ) {
			bSaveJump = true;
			bPressedJump = false;
		}
		else {bSaveJump = false;}

		bPressedJump = bSaveJump;
		MoveSmooth(Acceleration * DeltaTime);
	}
<<| 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
User avatar
Feralidragon
Godlike
Posts: 5498
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Making a ScriptedPawn move (via Player input)

Post by Feralidragon »

Well, instead of explicitly using the original Actor movement functions such as Move and MoveSmooth, you could use Pawn specific movement functions, such as MoveTo, MoveToward, StrafeTo, StrafeFacing, TurnTo, TurnToward, and a few others.

I am not entirely sure which behavior you want to have when controlling other pawns, but these would probably be good starting points rather than doing all the physics part yourself, even because Pawns behave a bit differently to begin with.
User avatar
ANUBITEK
Adept
Posts: 261
Joined: Sun Dec 28, 2014 1:10 am
Location: Anubitek

Re: Making a ScriptedPawn move (via Player input)

Post by ANUBITEK »

I would like for my ScriptedPawn to move like a player, so pressing a move button would make them move in that direction. An idea I had was project a move checkpoint actor, or do something like what CheckWaterJump() or whatever it is called does which would be project a checkpoint set of coordinates and if X is true then move to that point. The idea is just to read regular player inputs, like when you press forward you are changing aBaseY from 0 to 300 and it is added to the player's current aForward and it would make them move forward, but instead of passing it into ProcessMove() pass it into a custom function on an owned and ForEach()-found scriptedpawn. I'll try the MoveTo() method and see what I can come up with though.

How could I project a waypoint just ahead of an actor and constantly update it? That seems like it would be the best idea.
<<| 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
User avatar
Feralidragon
Godlike
Posts: 5498
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Making a ScriptedPawn move (via Player input)

Post by Feralidragon »

While a waypoint actor may sound like a "hack"-ish way of doing things, it does indeed seem to be the best approach in this case, since the alternative would be to build the entirety of the code to account of all the player input and the pawn movement, which due to the way things are designed, it's not as trivial.

By using already existing movement functions, all the pawn movement code, replication and whatnot have already been abstracted from you, and they work well enough for this, so I believe it's preferable.
User avatar
ANUBITEK
Adept
Posts: 261
Joined: Sun Dec 28, 2014 1:10 am
Location: Anubitek

Re: Making a ScriptedPawn move (via Player input)

Post by ANUBITEK »

I decided this would be a decent practice in trying to get a better understanding of how Acceleration and Velocity work, so I kept up trying to figure out how the two work. This is working code so far in that my guy still slides around, but faster than the regular player pawn and while his velocity is still not high enough to make my animation actor play animations, the guy will move smoothly and can rotate properly:

Code: Select all

		Acceleration = normal(aForward*X + aStrafe*Y + aUp*Z) * GroundSpeed;
		Velocity += (Acceleration);
		log(Velocity);
		MoveSmooth(Velocity*DeltaTime);
He doesn't slow to a stop though, still immediately stopping. I'll upload a video when I get this working properly. Any suggestions on that code?
<<| 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
User avatar
Feralidragon
Godlike
Posts: 5498
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Making a ScriptedPawn move (via Player input)

Post by Feralidragon »

To be bluntly honest with you, I think you need first to understand how velocity and acceleration work from a physics point of view:
https://www.khanacademy.org/science/phy ... on-article

Since your code does not reflect how acceleration should work, although even the native physics code in this engine doesn't follow the laws of physics on acceleration anyway, causing some inconsistencies depending on tick rate which causes inconsistency problems for online games, so a perfect application of the acceleration rules is not needed either in your case.
And unless there's something elsewhere reducing or capping the Velocity (I don't remember if there is in the original Pawn code), I wonder how come you don't get infinitely faster while you're pressing to move forward, as you're constantly incrementing it.

Either way, I will suggest this again: you should first use the functions I mentioned, and after you got it working fine like that, you could advance in doing your own thing and customize it if you like, since by then you will be sure that at least the basics work for you.
The pawn code for dealing with movement is not trivial, there is a lot of replication stuff going on, although I would argue that it's unnecessarily complex and convoluted, but it's proven to work reasonably well at least.

From there, as for suddenly stopping, notice how you're using MoveSmooth, maybe meaning that without it the pawn doesn't move at all, so I wonder if that log(Velocity) is showing up at all in the logs after you stop?
I would say that either it doesn't appear at all, or is printing vect(0,0,0), even because I don't know if PlayerInput is called in every tick or if it only runs on actual input.
User avatar
ANUBITEK
Adept
Posts: 261
Joined: Sun Dec 28, 2014 1:10 am
Location: Anubitek

Re: Making a ScriptedPawn move (via Player input)

Post by ANUBITEK »

EDIT, REPOST:
Edited the code some more and I have it working very similarly to how the stock playerpawn moves, MoveTo(), SetMovementPhysics, Acceleration, Velocity, AccelRate, and bIsWalking were important for this.
Video
0k3AOe5r3f8
All Movement Code

Code: Select all

ActivePuppet.ControlMove(DeltaTime, aForward, aStrafe, aUp, bUp, bDown, bLeft, bRight, bPressedJump, rot(0,0,0));

Code: Select all

function UpdateRotation(float DeltaTime, float maxPitch)
{
	local rotator newRotation;

	//DesiredRotation = ViewRotation; //save old rotation
	ViewRotation.Pitch = ViewRotation.Pitch & 65535;
	If ((ViewRotation.Pitch > 0) || (ViewRotation.Pitch < 0)) {ViewRotation.Pitch = 0;}
	//ViewRotation.Yaw += 32.0 * DeltaTime; //* aTurn;

	DesiredRotation = ViewRotation;
	UpdatePawnRotation(DesiredRotation);
}

function UpdatePawnRotation( rotator Rot )
{
	if( Rotation!=Rot )
		SetRotation(Rot);
}

function HandleWalking(byte bRun)
{
	bIsWalking = (bRun == 0 && !Region.Zone.IsA('WarpZoneInfo'));
}

function DoJump( optional float F )
{
	if ( CarriedDecoration != None )
		return;
	if ( /*!bIsCrouching &&*/ (Physics == PHYS_Walking) )
	{
		if ( Role == ROLE_Authority )
			PlaySound(JumpSound, SLOT_Talk, 1.5, true, 1200, 1.0 );
		if ( (Level.Game != None) && (Level.Game.Difficulty > 0) )
			MakeNoise(0.1 * Level.Game.Difficulty);
//		PlayInAir();
		if ( bCountJumps && (Role == ROLE_Authority) )
			Inventory.OwnerJumped();
		Velocity.Z = JumpZ;
		if ( Base!=Level && Base!=None )
 			Velocity.Z += Base.Velocity.Z;
		SetPhysics(PHYS_Falling);
	}
}

Code: Select all

auto state Walking
{
	ignores SeePlayer, HearNoise, Bump;

	function BeginState()
	{
		//bPressedJump = false;
		if (Physics != PHYS_Falling)
			SetPhysics(PHYS_Walking);
	}

	function ZoneChange( ZoneInfo NewZone )
	{
		if (NewZone.bWaterZone)
		{
			setPhysics(PHYS_Swimming);
			GotoState('Swimming');
		}
	}

	function Landed(vector HitNormal)
	{
		Global.Landed(HitNormal);
	}

	function ControlMove(float DeltaTime, float aForward, float aStrafe, float aUp, byte bUp, byte bDown, byte bLeft, byte bRight, bool bPressedJump, byte NewbRun, rotator DeltaRot)
	{
		local vector X,Y,Z;
		local rotator OldRotation;
		local bool    bSaveJump, bUpdateRun;
		
		aForward *= 0.1;
		aStrafe  *= 0.1;
		GetAxes(Rotation,X,Y,Z);
		
		HandleWalking(NewbRun);

		if ( Physics == PHYS_Walking ) {
			if ( aForward > 0 || aStrafe > 0) {
				Destination = Location + (aForward*X + aStrafe*Y + aUp*Z);
			}
			else if (aForward == 0 && aStrafe == 0) {
				Destination = Location;
			}
			Acceleration = normal(Destination - Location);
			Velocity += Acceleration*(DeltaTime*(AccelRate/2));
			
			// Update rotation.
			OldRotation = Rotation;
			UpdateRotation(DeltaTime, 0);
		}

		if ( Physics!=PHYS_Spider ) {Acceleration.Z = 0;}

		if ( bPressedJump ) {
			bSaveJump = true;
			DoJump();
			bPressedJump = false;
		}
		else {bSaveJump = false;}

		bPressedJump = bSaveJump;
	}
Begin:
	SetMovementPhysics();
	if (Physics != PHYS_Falling)
		SetPhysics(PHYS_Walking);
Move:
	MoveTo(Destination);
}
defaultproperties

Code: Select all

defaultproperties
{
	AccelRate=2048.0
	AirControl=0.05
	AirSpeed=400.0
	GroundSpeed=400.0
	JumpZ=350.000000
	BaseEyeHeight=23.000000
	AttitudeToPlayer=ATTITUDE_Ignore
	Land=Sound'UnrealShare.Generic.Land1'
	WaterStep=Sound'UnrealShare.Generic.LSplash'
	DrawScale=0.500000
	CollisionRadius=17.000000
	CollisionHeight=39.000000
}
<<| 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