Side scroller controller advice

I’m working on a custom side scroller controller in C# because none of the standard controllers really work for what I’m doing. I’m having problems with the character falling out of the stage sometimes, sliding downhill, and sometimes sliding backwards for no apparent reason. I’m doing this because not only will it let me make my character move how I want them to move, but also so I can have water affect the movement speed and gravity.

I need to be able to move along the X axis, have my position locked along the Z axis (so I don’t fall out of the stage), have gravity, jumping, etc. and be able to aim upwards and forwards (also downwards while I’m midair). Also transition from jumping to falling when my character hits the ceiling.

I’m not asking for an entire script here. Does anybody have any advice as to how I can do these things?

EDIT: I feel I should mention that it is a 3D side scroller.

(I have to post this as an answer because it’s too long to be posted as a comment)

I got jumping and aiming working correctly, but I’m having problems.

  1. If I let go of jump at the right time and hit the ceiling while in Falling state, I will end up going back to Idle while still falling.
  2. I have no clue where to start as far as actually moving.

Here is my code so far:

using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour {

	#region Animations
	public AnimationClip[] IdleAnimations;
	public AnimationClip[] WalkAnimations;
	public AnimationClip[] JumpAnimations;
	public AnimationClip[] FallAnimations;
	#endregion

	#region Variables
	public float WalkSpeed;
	public float Gravity;
	public float JumpForce;
	bool IsGrounded;
	bool HasJumped;
	bool HasHitCeiling;
	Vector3 Forward;
	CharacterController controller;
	//Object LevelMesh;
	//Object Player;
	//RaycastHit hit;
	#endregion

	#region Enums
	enum PlayerDirection
	{
		Forward = 0,
		Up = 1,
		Down = 2
	}
	enum PlayerState
	{
		Idle = 0,
		Walking = 1,
		Jumping = 2,
		Falling = 3,
		Dead = 4
	}
	PlayerDirection playerDirection;
	PlayerState playerState;
	#endregion

	// Use this for initialization
	void Start () {
		Forward = transform.forward;
		playerState = PlayerState.Idle;
		//LevelMesh = GameObject.FindGameObjectWithTag ("Level");
		//Player = gameObject;
	}
	
	// Update is called once per frame
	void Update () {
		ChangeAnimation ();
		AimGun ();
		print ("State: " + playerState + "; Direction: " + playerDirection);
		//MOVE THE PLAYER IN FORWARD AT WALKSPEED

		float h = Input.GetAxis ("Horizontal");


		//JUMP
		if (Input.GetButtonDown ("Jump") && playerState != PlayerState.Jumping && playerState != PlayerState.Falling)
		{
			rigidbody.AddForce (new Vector3(0, JumpForce, 0));
			//print ("You are jumping.");
			playerState = PlayerState.Jumping;
			IsGrounded = false;
		}
		if (Input.GetButtonUp ("Jump") && playerState == PlayerState.Jumping)
		{
			playerState = PlayerState.Falling;
		}
		switch (playerState)
		{
		case PlayerState.Falling:
			rigidbody.AddForce (new Vector3(0,-Gravity,0));
			IsGrounded = false;
			break;
		}

	}
	void OnCollisionEnter (Collision col)
	{
		if (col.gameObject.tag == "LevelMesh")
		{
			if (playerState == PlayerState.Falling)
			{
				IsGrounded = true;
				playerState = PlayerState.Idle;
			}
			if (playerState == PlayerState.Jumping && !IsGrounded || playerState == PlayerState.Falling && !IsGrounded)
			{
				playerState = PlayerState.Falling;
			}
		}
	}
	void ChangeAnimation()
	{
		switch (playerState)
		{
			case PlayerState.Idle:
				if (playerDirection == PlayerDirection.Forward)
				{
					animation.Play (IdleAnimations[0].name);
				}
				if (playerDirection == PlayerDirection.Up)
				{
					animation.Play (IdleAnimations[1].name);
				}
			break;
		case PlayerState.Walking:
			if (playerDirection == PlayerDirection.Forward)
			{
				animation.Play (WalkAnimations[0].name);
			}
			if (playerDirection == PlayerDirection.Up)
			{
				animation.Play (WalkAnimations[1].name);
			}
			break;
		case PlayerState.Jumping:
			if (playerDirection == PlayerDirection.Forward)
			{
				animation.Play (JumpAnimations[0].name);
			}
			if (playerDirection == PlayerDirection.Up)
			{
				animation.Play (JumpAnimations[1].name);
			}
			if (playerDirection == PlayerDirection.Down)
			{
				animation.Play (JumpAnimations[2].name);
			}
			break;
		case PlayerState.Falling:
			if (playerDirection == PlayerDirection.Forward)
			{
				animation.Play (FallAnimations[0].name);
			}
			if (playerDirection == PlayerDirection.Up)
			{
				animation.Play (FallAnimations[1].name);
			}
			if (playerDirection == PlayerDirection.Down)
			{
				animation.Play (FallAnimations[2].name);
			}
			break;
		}
	}
	void AimGun()
	{
		if (Input.GetButton ("AimUp"))
		{
			playerDirection = PlayerDirection.Up;
		}
		if (Input.GetButton ("AimDown") && playerState == PlayerState.Jumping || Input.GetButton ("AimDown") && playerState == PlayerState.Falling)
		{
			playerDirection = PlayerDirection.Down;
		}
		if (!Input.GetButton ("AimUp") && !Input.GetButton ("AimDown"))
		{
			playerDirection = PlayerDirection.Forward;
		}
	}
}