- Home /
CharacterController Hops along upward slopes
Facts:
My character controller uses a Capsule Collider
I check the isGrounded bool to see if my character can jump or is falling.
The problem:
My character hops along an upward slope, inhibiting jumping (You can't jump when you fall) and forcing me to use raycasts to see if I'm "on ground" or not (useless expensive check, if you ask me...).
So, given that Character Controllers are spastic, and that It's late in the dev to rip it out and use my own implementation, what can I do to resolve this issue?
Answer by stingman · May 21, 2012 at 05:01 AM
If you post your movement script this might be easier to solve. But in general have you tried working with the angle of movement to control this behavior? You could try using Vector3.Angle (in the docs) and adjust your movement based on the angle associated with your player's direction of movement along the Y axis when he's not jumping. For example apply more gravity if the angle is above a certain degree. The behavior sounds very weird, so seeing a script could help but I'd start there.
Here's a postup of my PlayerController class with all his movement code. A lot of comments have been removed, but there still is quite a bit of debug code.
using UnityEngine;
using System.Collections; [RequireComponent(typeof(CharacterController))] public class PlayerController : $$anonymous$$onoBehaviour { public Transform GunPosition = null; public GameObject playerProjectileObject; public GameObject SpriteObject = null; public Sprite$$anonymous$$anager playerSprite$$anonymous$$anager; public float playerSpeed = 6.0f; public float playerJumpSpeed = 8.0f; public float gravity = 20.0f; public float firingInterval = 0.5f;
public bool facingRight = true;
private bool isAlive = true;
private bool playerFireReadyNow = true;
private Vector3 directionVector = Vector3.zero;
private PlayerProgress progress = null;
CharacterController controller;
public float YApexOffset = 5.0f;
float YApex = 0.0f;
bool flagHitApex = false;
void Awake()
{
controller = GetComponent<CharacterController>();
GunPosition = transform.FindChild("GunPos");
GameObject progressObj = GameObject.Find("PlayerProgress");
progress = progressObj.GetComponent<PlayerProgress>();
}
// Use this for initialization
void Start ()
{
if(SpriteObject == null)
{
Debug.LogError("There's no sprite! UH-OH!!!!");
}
InitializePlayerObject();
}
void OnDrawGizmosSelected()
{
Gizmos.DrawRay(transform.position, transform.forward * 20);
}
void Update()
{
if (isAlive)
{
PlayerActions();
}
}
void InitializePlayerObject()
{
transform.rotation = Quaternion.LookRotation(Vector3.right);
facingRight = true;
}
void PlayerActions()
{
Player$$anonymous$$ove();
PlayerJump();
PlayerFire();
Vector3 current$$anonymous$$ovementOffset = new Vector3(directionVector.x, directionVector.y, 0);
controller.$$anonymous$$ove(current$$anonymous$$ovementOffset * Time.deltaTime);
}
void Player$$anonymous$$ove()
{
bool is$$anonymous$$ovementInput = Input.GetButtonDown("Horizontal");
float movementDirection = Input.GetAxis("Horizontal");
{
if($$anonymous$$athf.Abs(movementDirection) > 0.1)
{
Debug.Log("Walking...");
playerSprite$$anonymous$$anager.ChangeAnimation("Walk");
}
else
{
Debug.Log("Idle...");
playerSprite$$anonymous$$anager.ChangeAnimation("Idle");
}
directionVector = new Vector3(movementDirection * playerSpeed, 0, 0);
if($$anonymous$$athf.Abs(movementDirection) > 0.1f)
{
transform.rotation = Quaternion.LookRotation(directionVector);
}
}
if (!controller.isGrounded && GroundCheck() == false)
{
playerSprite$$anonymous$$anager.ChangeAnimation("Jump");
}
}
float CurJumpSpeed = 0.0f;
float GroundY = 0.0f;
void PlayerJump()
{
//apply gravity
directionVector.y = controller.velocity.y - gravity * Time.deltaTime;
float curY = transform.position.y;
bool GroundCheckFail = !GroundCheck();
//are we jumping?
if ((Input.GetButtonDown("Jump") || Input.GetButtonDown("JumpAxis")) && controller.isGrounded && GroundCheckFail == false)
{
directionVector.y = playerJumpSpeed * gravity * Time.deltaTime;
YApex = curY + YApexOffset;
flagHitApex = false;
}
else if (!flagHitApex && (Input.GetButton("Jump") || Input.GetAxis("JumpAxis") > 0) && !controller.isGrounded && GroundCheckFail == true)
{
directionVector.y = playerJumpSpeed * gravity * Time.deltaTime;
if (curY >= YApex - 0.1f)
flagHitApex = true;
}
else if (!controller.isGrounded && GroundCheckFail == true && (!Input.GetButton("Jump") || Input.GetAxis("JumpAxis") <= 0))
{
flagHitApex = true;
}
}
public float GroundCheckRayDistance = 1.2f;
bool GroundCheck()
{
RaycastHit hit;
Debug.DrawRay(transform.position, Vector3.down, Color.green, 16.0f);
if (Physics.Raycast(transform.position, Vector3.down, out hit, GroundCheckRayDistance) == true)
{
Debug.DrawLine(transform.position, hit.point, Color.red);
Debug.Log("Ground is " + hit.collider.name + ":" + hit.collider.tag);
return true;
}
return false;
}
void PlayerFire()
{
bool isFireInput = Input.GetButton("Fire");
if (isFireInput && playerFireReadyNow)
{
StartCoroutine(PlayerFireCoroutine());
}
}
IEnumerator PlayerFireCoroutine()
{
playerFireReadyNow = false;
GameObject playerProjectileClone = (GameObject)Instantiate(playerProjectileObject, GunPosition.position, Quaternion.LookRotation(GunPosition.forward));
Physics.IgnoreCollision(playerProjectileClone.collider, collider);
yield return new WaitForSeconds(firingInterval);
playerFireReadyNow = true;
}
void OnCollisionEnter(Collision collision)
{
if (isAlive)
{
string tag = collision.gameObject.tag;
if(tag == "Enemy" || tag == "EnemyProjectile")
{
$$anonymous$$ill();
return;
}
}
}
public void $$anonymous$$ill()
{
//TODO Run subroutine to play death
Debug.Log("DEAD PLAYER!!!");
StartCoroutine("PlayDeath");
}
IEnumerator PlayDeath()
{
isAlive = false;
SpriteObject.renderer.enabled = false;
yield return new WaitForSeconds(2);
//If this is the last life, switch to Game Over,
progress.PlayerLives -= 1;
if(progress.PlayerLives <= 0)
{
Debug.Log("Game Over, man! Game over!");
}
//If not, reload the level.
Application.LoadLevel("PreLevel");
}
}
ok based on your original post saying the player hops along upward slopes you are saying he hops when running up a hill? this is correct? or did you mean downward slopes? Because after reading your movement section of your script there is technically nothing wrong with it but it could be an issue with changing values of your variables and/or changing the rotation based on your movedirection. Does your character stay facing straight on a slope or does he change his angle to face the direction? Based on what I'm reading it appears he changes his rotation to the face his direction of movement, but this is not restricted to any axis. Am I right? Also, is this a 2D game?
This is a 2D game, yes, and he is locked so he is facing straight along the X axis when traversing slopes (So his Up axis, no matter what the slope is, is {0, 1, 0} in the world, not the slopes Up). The problem is only occurring when going up hills - when he goes down, he moves and behaves absolutely fine.
One thing that caught my attention is how you use Raycasting to detect the ground. Since you are stating that the ray is being cast from the player's position directly below him this may produce some odd behavior when going up slopes. I suggest checking out the 2D tutorial to see how they detect collisions. It's very straightforward and works great... Just a thought. Wish I could help more but best of luck to you
Did you ever manage to fix this? I'm doing something very similar and have been running into this issue ever since I started.
Your answer
![](https://koobas.hobune.stream/wayback/20220613071732im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Rigidbody controller and slopes 1 Answer
NEW CONTROLLER, NO SLOPE 0 Answers
[Character controller] run faster on slopes and jetpack 1 Answer
2D Slope Sliding: how to prevent with transform.translate logic 0 Answers
CharacterController Slope Problems 0 Answers