- Home /
Midair movement with the character controller?
I'm working on a 3D platformer where the character needs to be able to move around and be capable of performing single and double jumps. I'm using the character controller and the example code on the CharacterController.Move page of the scripting reference. The problem inherent in this script is that the character cannot be controlled in midair. First, my current script, which is a modified version of the script shown on the CharacterController.Move page, changed to allow for double jumping, in its entirety:
using UnityEngine;
using System.Collections;
public class PlayerMove : MonoBehaviour {
public float speed = 6.0F;
public float jumpSpeed = 8.0F;
public float gravity = 20.0F;
private Vector3 moveDirection = Vector3.zero;
int maxJumps = 2;
int currentJumps;
void Start()
{
currentJumps = 0;
}
void Update()
{
CharacterController controller = GetComponent<CharacterController>();
if (controller.isGrounded)
{
currentJumps = 0;
moveDirection = new Vector3(Input.GetAxis("Horizontal"), moveDirection.y, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
if (Input.GetButtonDown("Jump"))
{
moveDirection.y = jumpSpeed;
currentJumps++;
}
}
if (!controller.isGrounded)
{
if (Input.GetButtonDown("Jump") && currentJumps < maxJumps)
{
moveDirection.y = jumpSpeed;
currentJumps++;
}
}
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
}
}
Now I want to be able to move the character around in midair, so I would think that taking these three lines:
moveDirection = new Vector3(Input.GetAxis("Horizontal"), moveDirection.y, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
And moving them before the first if statement starts would work, but this causes jumping to behave incorrectly and causes the object to fall much slower. I get the same effect if those three lines are copied/pasted into the if (!controller.isGrounded) statement before the nested if statement for detecting the jump input.
Any help is appreciated. Javascript and C# are fine for answers.
Answer by scott95 · Oct 11, 2017 at 07:00 PM
I think i found a solution sorry if my code is a bit messy.
CharacterController controller = GetComponent(); if (controller.isGrounded) {
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
//moveDirection.y = 0;
//if (Input.GetButton("Jump"))
if (Input.GetButtonDown("XboxA") || Input.GetKey(KeyCode.Space))
moveDirection.y = jumpSpeed;
//
}else if (controller.isGrounded == false) // Here I independently allow for both X and Z movement.
{
moveDirection.x = Input.GetAxis("Horizontal") * speed;
moveDirection.z = Input.GetAxis("Vertical") * speed;
moveDirection = transform.TransformDirection(moveDirection);// Then reassign the current transform to the Vector 3.
}
Answer by amphoterik · Jul 16, 2013 at 12:01 PM
I did something similar like this last night. Simply take the part that moves you along the x and z axis out of the grounding conditional:
moveDirection = new Vector3(Input.GetAxis("Horizontal"), moveDirection.y, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
if (controller.isGrounded)
{
currentJumps = 0;
if (Input.GetButtonDown("Jump"))
{
moveDirection.y = jumpSpeed;
currentJumps++;
}
}
That will do what you want. You may want to dampen the control while in the air so that they cannot move perfectly while on the ground.
Yeah, I tried that. It causes some strange issue where gravity has a significantly lower effect on the character as it falls. Jumping also doesn't work correctly, the character just moves up however many units the jump height is set to, and then falls slowly. Any idea why this is happening?
In case it matters, here is my code:
using UnityEngine;
using System.Collections;
public class Player$$anonymous$$ove : $$anonymous$$onoBehaviour
{
public float speed = 6.0F;
public float jumpSpeed = 8.0F;
public float gravity = 20.0F;
public int maxJumps = 2;
private Vector3 moveDirection = Vector3.zero;
private float usedSpeed;
private int jumps;
void Start()
{
usedSpeed = speed;
jumps = 0;
}
void Update()
{
CharacterController controller = GetComponent<CharacterController>();
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= usedSpeed;
if (controller.isGrounded)
{
jumps = 0;
usedSpeed = speed;
if (Input.GetButtonDown("Jump"))
{
moveDirection.y = jumpSpeed;
jumps++;
}
}
if (!controller.isGrounded)
{
usedSpeed = speed * 0.5f;
if (Input.GetButtonDown("Jump") && jumps < maxJumps)
{
moveDirection.y = jumpSpeed;
jumps++;
}
}
moveDirection.y -= gravity * Time.deltaTime;
controller.$$anonymous$$ove(moveDirection * Time.deltaTime);
}
}
Here's your problem:
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
Compare yours to $$anonymous$$e.
Tried that. The capsule seems to fall properly, but freaks out whenever it hits something. Tried both a flat terrain and a cube mesh and got the following error in both cases:
transform.position assign attempt for 'Capsule' is not valid. Input position is { NaN, -Infinity, NaN }.
I'm starting my player object in midair, as well.
Yeah, here's the section I changed. If you want I can post the whole thing, but the rest of it is the same:
void Update()
{
CharacterController controller = GetComponent<CharacterController>();
moveDirection = new Vector3(Input.GetAxis("Horizontal"), moveDirection.y, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= usedSpeed;
if (controller.isGrounded)
Answer by SmileyMerx · Jan 28, 2015 at 11:41 AM
I had some problems and none of your solutions worked, so here is my solution. It is really easy and allows mid-air movement left/right. If you also want to turn around, or forward, backward. Just add it in the suitable location:
using UnityEngine; using System.Collections;
public class MovementWorm3 : MonoBehaviour {
float speed = 6.0f;
float jumpSpeed = 8.0f;
float gravity = 20.0f;
private Vector3 moveDirection = Vector3.zero;
private CharacterController controller;
// Use this for initialization
void Start () {
controller = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update () {
if (controller.isGrounded) {
// We are grounded, so recalculate
// move direction directly from axes
moveDirection = new Vector3(Input.GetAxis ("Horizontal"), 0, 0);
moveDirection = transform.TransformDirection(moveDirection);
moveDirection = moveDirection * speed;
if (Input.GetButton ("Jump")) {
moveDirection.y = jumpSpeed;
}
}
else {
// Apply right/left, if we are NOT grounded
// --> Left/Right movement in mid air allowed
moveDirection.x = Input.GetAxis ("Horizontal") * speed;
}
// Apply gravity
moveDirection.y -= gravity * Time.deltaTime;
// Move the controller
controller.Move(moveDirection * Time.deltaTime);
}
}
Answer by GameDev_Chuck · Jul 30, 2016 at 04:46 PM
if(grounded)
{
//grounded controls
}
else //in air controls
{
/* this works but doesnt clamp horizontal velocity:
Vector3 inputVector = new Vector3(Input.GetAxis("Horizontal"), 0, verticalInput);
inputVector = transform.TransformDirection(inputVector);
moveDirection = controller.velocity + (inputVector * Time.deltaTime * airSpeed);
*/
Vector3 inputVector = new Vector3(horizontalInput, 0, verticalInput);
inputVector = transform.TransformDirection(inputVector);
Vector2 clampedHorizontalVelocity = Vector2.ClampMagnitude(new Vector2(controller.velocity.x, controller.velocity.z), runSpeed);
moveDirection = new Vector3(clampedHorizontalVelocity.x, controller.velocity.y, clampedHorizontalVelocity.y) + (inputVector * Time.deltaTime * airSpeed);
}
Answer by iuripujol · Jun 20, 2018 at 05:38 PM
Guys take it easy...
float v = Input.GetAxis ("Vertical");
float h = Input.GetAxis ("Horizontal");
float Angle = Mathf.Atan2 (h,v) * Mathf.Rad2Deg;
Vector3 m = transform.forward * new Vector3 (h, 0, v).magnitude;
transform.eulerAngles = new Vector3 (0, cam.eulerAngles.y + Angle, 0);
if (cc.isGrounded) {
move = m ;
move *= Input.GetKey (KeyCode.LeftShift) ? 1 : .5f;
if (Input.GetKey (KeyCode.Space))
move.y = JumpSpeed;
} else {
move = new Vector3(m.x, move.y, m.z);
}
move.y -= 3 * Time.deltaTime;
cc.Move (move * MoveSpeed * Time.deltaTime);
Final solution:
float v = Input.GetAxis ("Vertical"); float h = Input.GetAxis ("Horizontal");
Vector3 m = Quaternion.Euler(0, cam.eulerAngles.y, 0) * new Vector3 (h, 0, v);//move direction
Vector3 dir = transform.InverseTransformDirection (m); float Turn = $$anonymous$$athf.Atan2 (dir.x, dir.z); transform.Rotate (0, Turn * 20, 0);//handle rotation
if (cc.isGrounded) { move = m.normalized; move *= Input.Get$$anonymous$$ey ($$anonymous$$eyCode.LeftShift) ? 1 : .5f;
if (Input.Get$$anonymous$$ey ($$anonymous$$eyCode.Space)) move.y = JumpSpeed; } else { move = new Vector3(m.x, move.y, m.z); }
move.y -= 3 * Time.deltaTime;//gravity
cc.$$anonymous$$ove (move $$anonymous$$oveSpeed Time.deltaTime);
Your answer
Follow this Question
Related Questions
Making a bubble level (not a game but work tool) 1 Answer
Cant Jump ?c# please 2 Answers
MidAir Strafing 0 Answers
Player Jumps instead of moving forward 0 Answers