Jump to content


Photo

Wall-Walking


  • Please log in to reply
6 replies to this topic

#1 ambershee

ambershee

    Nimbusfish Rawks

  • Hosted
  • 3,114 posts
  • Location:Derby, UK
  • Projects:Mutator Week & Unreal 3 Projects
  •  Mad Mod Boffin

Posted 24 April 2008 - 12:42 PM

Ok, here's what we have - we have the player able to traverse any surface, and the camera is automatically correctly orientated to the correct rotation.

We are currently rotating the player based upon the view rotation - which causes a number of issues. Firstly, the player is not correctly aligned to the surface it is walking on; it will often sink into the floor. Secondly, the player rotation is determined by the view rotation - which means it will rotate based upon where the camera is looking. This does not work unless the camera is always perfectly behind the player; which it is not, as the pitch and yaw can be altered at any time - only the roll is correct. If the player looks up or down, the player rotates up or down.

So, how are we going to solve this? The theoretical best solution, would be to somehow determine the rotation (pitch, roll, yaw) for the player not based upon the view rotation, but based upon the normal to the plane surface the player is currently standing on. Easy? Probably not.

Mathematical thinking caps people. We can only rotate the player using a rotator.

Current code:
state PlayerSpidering
{
ignores SeePlayer, HearNoise, Bump;

	event bool NotifyHitWall(vector HitNormal, actor HitActor)
	{
		Pawn.SetPhysics(PHYS_Spider);
		Pawn.SetBase(HitActor, HitNormal);
		return true;
	}

	// if spider mode, update rotation based on floor
	function UpdateRotation(float DeltaTime)
	{
		local rotator ViewRotation, PlayerRotation;
		local vector MyFloor, CrossDir, FwdDir, OldFwdDir, OldX, RealFloor;

		if ( (Pawn.Base == None) || (Pawn.Floor == vect(0,0,0)) )
		{
			MyFloor = vect(0,0,1);
		}
		else
		{
			MyFloor = Pawn.Floor;
		}
		if ( MyFloor != OldFloor )
		{
			// smoothly transition between floors
			RealFloor = MyFloor;
			MyFloor = Normal(6*DeltaTime * MyFloor + (1 - 6*DeltaTime) * OldFloor);

			if ( (RealFloor dot MyFloor) > 0.999 )
			{
				MyFloor = RealFloor;
			}
			else
			{
				// translate view direction
				CrossDir = Normal(RealFloor Cross OldFloor);
				FwdDir = CrossDir cross MyFloor;
				OldFwdDir = CrossDir cross OldFloor;
				ViewX = MyFloor * (OldFloor dot ViewX) + CrossDir * (CrossDir dot ViewX) + FwdDir * (OldFwdDir dot ViewX);
				ViewX = Normal(ViewX);
				ViewZ = MyFloor * (OldFloor dot ViewZ) + CrossDir * (CrossDir dot ViewZ) + FwdDir * (OldFwdDir dot ViewZ);
				ViewZ = Normal(ViewZ);
				OldFloor = MyFloor;
				ViewY = Normal(MyFloor cross ViewX);
			}
		}
		
		Pawn.mesh.SetRotation(OrthoRotation(ViewX,ViewY,ViewZ));

		if ( (PlayerInput.aTurn != 0) || (PlayerInput.aLookUp != 0) )
		{
			// adjust Yaw based on aTurn
			if ( PlayerInput.aTurn != 0 )
			{
				ViewX = Normal(ViewX + 2 * ViewY * Sin(0.0005*DeltaTime*PlayerInput.aTurn));
			}

			// adjust Pitch based on aLookUp
			if ( PlayerInput.aLookUp != 0 )
			{
				OldX = ViewX;
				ViewX = Normal(ViewX + 2 * ViewZ * Sin(0.0005*DeltaTime*PlayerInput.aLookUp));
				ViewZ = Normal(ViewX Cross ViewY);

				// bound max pitch
				if ( (ViewZ dot MyFloor) < 0.707   )
				{
					OldX = Normal(OldX - MyFloor * (MyFloor Dot OldX));
					if ( (ViewX Dot MyFloor) > 0)
					{
						ViewX = Normal(OldX + MyFloor);
					}
					else
					{
						ViewX = Normal(OldX - MyFloor);
					}

					ViewZ = Normal(ViewX cross ViewY);
				}
			}

			// calculate new Y axis
			ViewY = Normal(MyFloor cross ViewX);
		}
		ViewRotation =  OrthoRotation(ViewX,ViewY,ViewZ);
		SetRotation(ViewRotation);
		Pawn.FaceRotation(ViewRotation, deltaTime );
   }

	function bool NotifyLanded(vector HitNormal, Actor FloorActor)
	{
		Pawn.SetPhysics(PHYS_Spider);
		return bUpdating;
	}

	event NotifyPhysicsVolumeChange( PhysicsVolume NewVolume )
	{
		if ( NewVolume.bWaterVolume )
		{
			GotoState(Pawn.WaterMovementState);
		}
	}

	function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot)
	{
		if ( Pawn.Acceleration != NewAccel )
		{
			Pawn.Acceleration = NewAccel;
		}

		if ( bPressedJump )
		{
			Pawn.DoJump(bUpdating);
		}
	}

	function PlayerMove( float DeltaTime )
	{
		local vector NewAccel;
		local eDoubleClickDir DoubleClickMove;
		local rotator OldRotation, ViewRotation;
		local bool  bSaveJump;

		GroundPitch = 0;
		ViewRotation = Rotation;

		//Pawn.CheckBob(DeltaTime,vect(0,0,0));

		// Update rotation.
		SetRotation(ViewRotation);
		OldRotation = Rotation;
		UpdateRotation(DeltaTime);

		// Update acceleration.
		NewAccel = PlayerInput.aForward*Normal(ViewX - OldFloor * (OldFloor Dot ViewX)) + PlayerInput.aStrafe*ViewY;

		if ( VSize(NewAccel) < 1.0 )
		{
			NewAccel = vect(0,0,0);
		}

		if ( bPressedJump && Pawn.CannotJumpNow() )
		{
			bSaveJump = true;
			bPressedJump = false;
		}
		else
			bSaveJump = false;

		ProcessMove(DeltaTime, NewAccel, DoubleClickMove, OldRotation - Rotation);
		bPressedJump = bSaveJump;
	}

	event BeginState(Name PreviousStateName)
	{
		//if ( Pawn.Mesh == None )
		//	Pawn.SetMesh();
		OldFloor = vect(0,0,1);
		GetAxes(Rotation,ViewX,ViewY,ViewZ);
		DoubleClickDir = DCLICK_None;
		Pawn.ShouldCrouch(false);
		bPressedJump = false;

		if (Pawn.Physics != PHYS_Falling)
		{
			Pawn.SetPhysics(PHYS_Spider);
		}

		GroundPitch = 0;
		Pawn.bCrawler = true;
	}

	event EndState(Name NextStateName)
	{
		GroundPitch = 0;
		if ( Pawn != None )
		{
			Pawn.ShouldCrouch(false);
			Pawn.bCrawler = Pawn.default.bCrawler;
		}
	}
}


#2 xiongmao

xiongmao
  • Members
  • 175 posts
  • Location:Paris

Posted 25 April 2008 - 01:12 PM

I checked my old math books interesting ^^

Got two question:
1) Why Pawn.floor is never set? Modify this field will perhaps affect pawn rotation

2) Following lines are base on fields ViewX and ViewZ of Controller:
ViewX = MyFloor * (OldFloor dot ViewX) + CrossDir * (CrossDir dot ViewX) + FwdDir * (OldFwdDir dot ViewX);
ViewZ = MyFloor * (OldFloor dot ViewZ) + CrossDir * (CrossDir dot ViewZ) + FwdDir * (OldFwdDir dot ViewZ);

Why not using Pawn.getAxis() or something like that and apply the same computation for pawn mesh ?

These are all suppositions, I'll make some tests when I 'll find time.

#3 ambershee

ambershee

    Nimbusfish Rawks

  • Hosted
  • 3,114 posts
  • Location:Derby, UK
  • Projects:Mutator Week & Unreal 3 Projects
  •  Mad Mod Boffin

Posted 25 April 2008 - 01:28 PM

I wish I still had my old maths books :(

1) Are you sure it's never set? Floor is used by PHYS_Walking, for example DoJump and I didn't overwrite many functions for PHYS_Spider. If it isn't, then it may explain a lot. Notably, there appears to be console command exec ShowDebug that should display the Floor information. It may not still be implemented, but we can give it a try.

2) It was written pretty quickly (two or three hours), so I used the first solution that came to mind. GetAxis() may or may not work. I'm not sure it's useful.

This is a native (cpptext) function in Pawn. Could be very useful, could be not from the name, return type and parameters. Something to look into.

FRotator FindSlopeRotation(FVector FloorNormal, FRotator NewRotation);

Looks like we have testing to do. I want to wrap up the HUD for Five Week this weekend, and it's probably advisable to wrap up the Scoreboards. If we can get that done, then we can look into this :p

#4 joshjoneswol

joshjoneswol
  • New Members
  • 1 posts

Posted 03 June 2008 - 05:02 PM

Hey Amber, Thanks for the location, if you don't mind I would like to invite some IGDA Game Club Student Programmers in here, and see if we can't work something out with you and get this thing finished up.

That ok?

#5 ZacharyWOL

ZacharyWOL
  • New Members
  • 1 posts

Posted 03 June 2008 - 05:46 PM

Hi Guys,
I understand the code inside the state, but how/where do you change the state that a current player is in? I've been trying to get the whole PHYS_Spider thing to work, but I just don't understand how to change the state that the player is in by using a mutator...Any direction you can point me would be great.

#6 xiongmao

xiongmao
  • Members
  • 175 posts
  • Location:Paris

Posted 03 June 2008 - 08:06 PM

You won't be able to do this using Mutator. A GameType suits better for those modifications. This state is located in a subclass of PlayerController.
How do you enter this state ?
Well, in our test, we use the pawn's field LandMovementState=PlayerSpidering(a subclass of Pawn class is also required). You could also use the method GoToState('PlayerSpidering(') in controller class.
Ambershee has updated the code (not release yet I think) which allow the player to enter this state by doubleJump or dodge and hitwall. I guess he will answer soon :p

Welcome here , Feel free to post ;)

#7 ambershee

ambershee

    Nimbusfish Rawks

  • Hosted
  • 3,114 posts
  • Location:Derby, UK
  • Projects:Mutator Week & Unreal 3 Projects
  •  Mad Mod Boffin

Posted 03 June 2008 - 10:31 PM

A game type is indeed the way to do it, with a custom pawn, which has a changed movement state to PlayerSpidering, which this implements. The code for this hasn't been updated; the infinite-dodge was completely separate.

If you can compile and run the code after creating a simple game mode, you'll quickly see what's wrong with it.




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users