I've been dabbling with the 4.3 2D tools for the last week trying to get a tight 2D platformer controller working. I have used several methods to move the player around - Addforce(), velocity, and transform. I've found that I can get the "tightest" controls via either transform or velocity changes, but most suggestions including the documentation suggest to only manipulate the rigidbody's movement via addforce. I found the character controller in the 3D tools nice for achieving a 2D platformer controller, but there is not one in the 2D tools. What I am looking to achieve is instantaneous movement, and make it so the player doesn't maintain momentum after player input is not present (I made a script that set rigidbody drag higher when there's no input and it worked ok.) Has anyone achieved a nice feeling player control via addforce? Should I just stick to manipulating the velocity directly?
This is a nice tool from prime31 that's worth checking out: https://github.com/prime31/CharacterController2D. I've had the most success rolling my own movement and collision code. All you really need for a platformer are rectangular bounding boxes and the ability to check if two rectangles are overlapping.
Hi, thanks for this! Can you please help me to hack the script to avoid double jump? I'm not a coder but i think it will need a simple Code (csharp): StartCoroutine(waitForSeconds()); somewhere in the PlayerTester.cs - maybe after the.. Code (csharp): if( Input.GetKeyDown( KeyCode.UpArrow ) ) { var targetJumpHeight = 2f; velocity.y = Mathf.Sqrt( 2f * targetJumpHeight * -gravity ); _animator.Play( Animator.StringToHash( "Jump" ) ); } This could be an opportunity for me to begin to study.. Thanks in advance, -elvis
I haven't used that CharacterController2D stuff myself, so I won't be much help. But I think it contains a variable called "isGrounded" that becomes true when your character is touching the ground. To remove double jump, you would only add the jump velocity if the character is currently grounded.
Thanks! I think i've found where to make the changes and it actually work Thanks also to prime31 on twitter for the hint! Here's my modified version Code (csharp): using UnityEngine; using System.Collections; public class PlayerTester : MonoBehaviour { // movement config public float gravity = -15f; public float runSpeed = 8f; public float groundDamping = 20f; // how fast do we change direction? higher means faster public float inAirDamping = 5f; // public float jumpWaitTime = 2.0; [HideInInspector] public float rawMovementDirection = 1; //[HideInInspector] public float normalizedHorizontalSpeed = 0; CharacterController2D _controller; Animator _animator; public RaycastHit2D lastControllerColliderHit; [HideInInspector] public Vector3 velocity; void Awake() { _animator = GetComponent<Animator>(); _controller = GetComponent<CharacterController2D>(); _controller.onControllerCollidedEvent += onControllerCollider; } void onControllerCollider( RaycastHit2D hit ) { // bail out on plain old ground hits if( hit.normal.y == 1f ) return; // logs any collider hits //Debug.Log( "flags: " + _controller.collisionState + ", hit.normal: " + hit.normal ); } void Update() { // grab our current velocity to use as a base for all calculations velocity = _controller.velocity; if( _controller.isGrounded ) velocity.y = 0; if( Input.GetKey( KeyCode.RightArrow ) ) { normalizedHorizontalSpeed = 1; if( transform.localScale.x < 0f ) transform.localScale = new Vector3( -transform.localScale.x, transform.localScale.y, transform.localScale.z ); if( _controller.isGrounded ) _animator.Play( Animator.StringToHash( "Run" ) ); } else if( Input.GetKey( KeyCode.LeftArrow ) ) { normalizedHorizontalSpeed = -1; if( transform.localScale.x > 0f ) transform.localScale = new Vector3( -transform.localScale.x, transform.localScale.y, transform.localScale.z ); if( _controller.isGrounded ) _animator.Play( Animator.StringToHash( "Run" ) ); } else { normalizedHorizontalSpeed = 0; if( _controller.isGrounded ) _animator.Play( Animator.StringToHash( "Idle" ) ); } if( Input.GetKeyDown( KeyCode.UpArrow ) ) { //to avoid DOUBLE JUMP if( _controller.isGrounded ) { var targetJumpHeight = 2f; velocity.y = Mathf.Sqrt( 2f * targetJumpHeight * -gravity ); _animator.Play( Animator.StringToHash( "Jump" ) ); } } // apply horizontal speed smoothing it var smoothedMovementFactor = _controller.isGrounded ? groundDamping : inAirDamping; // how fast do we change direction? velocity.x = Mathf.Lerp( velocity.x, normalizedHorizontalSpeed * rawMovementDirection * runSpeed, Time.deltaTime * smoothedMovementFactor ); // apply gravity before moving velocity.y += gravity * Time.deltaTime; _controller.move( velocity * Time.deltaTime ); } } Thanks again, -elvis
I have been searching for a 2D version of CharacterController for a week. Thanks for supplying the solution and many thanks to prime31studios for this.
I think the prime31studios solution is great but I must ask- is there a way for the player to control jump height (like mario or megaman) to make tighter platforming? Can someone please give a few guidelines on how to achieve this.
I'm looking for the same thing. Need some very tight controls for my platformer, but I have literally no idea where to start and I've been having a nightmare even getting Prime31's script installed and running. I'm getting a different set of errors everytime I try it seems. Very frustrating. I've followed the instruction on how to install script, but for some reason I'm missing something. ANy helps at all, or links to a better tutorial than the unity one.
You can use the first person controller by placing the camera far away on z axis facing the player, and only moving in xy axes... that's what i did for this level generator: https://dl.dropboxusercontent.com/u/114667999/2dfdemo.html Indeed you shouldnt use rigidbody.velocity, unless it's for a shadow or folowing object... you can make a transform.position controlled player, and then slave a physicial rigidbody to that player object by making it move onto him using velocity, so the physical object is 1 frame behind on where the player is, but it is controlled by transform position and has am independent physics rigidbody.