Workaround for Character Controller?

I’ve been using the Starter Assets - First Person Character Controller (https://tinyurl.com/4h6dfukr) for this course since the old assets are gone and I wanted to be using the new Input System anyways.

However, for this lesson, Rick attaches a Physics material to the player as a way of making the player slide against walls instead of getting ‘stuck’ on them. This doesn’t work with the character controller because it acts outside of the physics engine. So the only workaround I can think of is to actually alter the C# script that handles the player’s movement, but I’m not really sure how to approach it. There’s a lot of syntax that I don’t follow, even after watching some youtube videos deconstructing it.

So can anyone help me with the code or is there another approach to solving this issue that I’m missing? Thanks.

Hi,

Welcome to our community! :slight_smile:

Does your character get stuck? If you don’t get the same problem as Rick with “your” FPS Controller, don’t try to find a solution for a non-existent problem in your game.

If you have a Rigidbody attached to your player, try to set the Collision Detection to “Continuous”.

If the issue persists, please feel free to ask our helpful community of students over on our Discord chat server.

If nobody knows a solution, I would suggest to download Rick’s project and copy and paste the Standard Assets folder into your project folder.

1 Like

Thanks for the reply.

My character does stick to walls, and I’m trying to figure out how to implement the same sort of effect that adding a Physics Material to a collider would have but for a player that is controlled by ‘Character Controller’. Adding a physics material to the collider component on the player does nothing in this case. I’ll try again on the discord today, but I wanted to share what I’ve come up with since yesterday.

I implemented a raycast to check for wall collision, and then calculated a normal from where the ray hits, which when added to the ray vector3 produces a left or right Vector3 parallel to the wall:

Vector3 RaycastCalcs(Vector3 inputDirection)
		{
			RaycastHit hit;
			Ray ray = new Ray(transform.position, inputDirection);
			Vector3 slideVec = new Vector3();
			Vector3 spherePosition = transform.position + (transform.forward * wallOffset) + transform.up;
			wallCollision = Physics.CheckSphere(spherePosition, wallRadius, wallLayers, QueryTriggerInteraction.Ignore);

			if (wallCollision)
			{
				if (Physics.Raycast(ray, out hit, 0.75f))
				{
					Vector3 incomingVec = hit.point - transform.position;

					// Use the point's normal to calculate the reflection vector.
					Vector3 reflectVec = Vector3.Reflect(incomingVec, hit.normal);

					slideVec = incomingVec + reflectVec;

					// Draw lines to show the incoming "beam" and the reflection.
					Debug.DrawLine(transform.position, hit.point, Color.red);
					Debug.DrawRay(hit.point, reflectVec, Color.green);
					Debug.DrawRay(transform.position, slideVec, Color.blue);

				}
            }
			return slideVec.normalized;
        }
if(slideVec != Vector3.zero)
            {
				_controller.Move(slideVec * (_speed * Time.deltaTime) + new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);
			} 
			else
            {
				_controller.Move(inputDirection.normalized * (_speed * Time.deltaTime) + new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);
			}

This works somewhat, when the ray actually connects with the wall, but my problem now is when the character is still stuck on the edge of the wall, and the ray doesn’t hit it, the player gets stuck. I tried to use multiple raycasts but couldn’t figure out how to get the code to work.

Any input would be appreciated. I’ll continue trying to work through this.

Update: I think I’ve gotten a solution that works pretty well by expanding on my ideas from before. The only remaining issue I have is behavior on outside corners, which I’m fine with at this point.
Essentially, I added two more raycasts at the flank left & right of the player, added up all the slide vectors and normalized them so the player wouldn’t shoot off the wall in either direction.

Vector3 RaycastCalcs(Vector3 inputDirection)
		{
			RaycastHit hit;
			Vector3 rotation = transform.eulerAngles;
			Ray fwdRay = new Ray(transform.position, inputDirection);
			Ray rightRay = new Ray(transform.position + (new Vector3(Mathf.Cos(Mathf.Deg2Rad * rotation.y), 0f, -Mathf.Sin(Mathf.Deg2Rad * rotation.y))) * _controller.radius, inputDirection);
			Ray leftRay = new Ray(transform.position + (new Vector3(-Mathf.Cos(Mathf.Deg2Rad * rotation.y), 0f, Mathf.Sin(Mathf.Deg2Rad * rotation.y))) * _controller.radius, inputDirection);
			Vector3 slideVec = new Vector3();
			Vector3 fwdSlideVec = new Vector3();
			Vector3 rightSlideVec = new Vector3();
			Vector3 leftSlideVec = new Vector3();
			Vector3 spherePosition = transform.position + (transform.forward * wallOffset) + transform.up;
			wallCollision = Physics.CheckSphere(spherePosition, wallRadius, wallLayers, QueryTriggerInteraction.Ignore);

			if (wallCollision)
			{
				if (Physics.Raycast(fwdRay, out hit, rayLength))
				{
					Vector3 incomingVec = hit.point - fwdRay.origin;

					// Use the point's normal to calculate the reflection vector.
					Vector3 reflectVec = Vector3.Reflect(incomingVec, hit.normal);

					fwdSlideVec = incomingVec + reflectVec;

					// Draw lines to show the incoming "beam" and the reflection.
					Debug.DrawLine(fwdRay.origin, hit.point, Color.red);
					Debug.DrawRay(hit.point, reflectVec, Color.green);
					Debug.DrawRay(transform.position, slideVec, Color.blue);

				}
				if (Physics.Raycast(rightRay, out hit, rayLength))
				{
					Vector3 incomingVec = hit.point - rightRay.origin;

					// Use the point's normal to calculate the reflection vector.
					Vector3 reflectVec = Vector3.Reflect(incomingVec, hit.normal);

					rightSlideVec = incomingVec + reflectVec;

					// Draw lines to show the incoming "beam" and the reflection.
					Debug.DrawLine(rightRay.origin, hit.point, Color.red);
					Debug.DrawRay(hit.point, reflectVec, Color.green);
					Debug.DrawRay(transform.position, slideVec, Color.blue);

				}
				if (Physics.Raycast(leftRay, out hit, rayLength))
				{
					Vector3 incomingVec = hit.point - leftRay.origin;

					// Use the point's normal to calculate the reflection vector.
					Vector3 reflectVec = Vector3.Reflect(incomingVec, hit.normal);

					leftSlideVec = incomingVec + reflectVec;

					// Draw lines to show the incoming "beam" and the reflection.
					Debug.DrawLine(leftRay.origin, hit.point, Color.red);
					Debug.DrawRay(hit.point, reflectVec, Color.green);
					Debug.DrawRay(transform.position, slideVec, Color.blue);

				}
				slideVec = fwdSlideVec + rightSlideVec + leftSlideVec;
			}
			return slideVec.normalized;
        }

I’m of course open to any suggestions on how to improve this code, but I thought I’d share what I had so future folks could use this as a workaround.

1 Like

Great job! Thanks a lot for sharing your solution. I’m sure it’ll be helpful for other students who would like to test Unity’s Character Controller. :slight_smile:

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms