- Home /
Capsule collider not touching the ground.
Hi,
i have a character, which has functions from mecanim. My problem is that on my character, capsule collider is attached. So whenever I jump the collider rescales while jumping (new feature in Unity4) which is a good thing. However, when my player runs from the stairs to somewhere where it should fall on the ground. So rather than falling on the ground he continues on(does not fall down to the ground). But when i move my character sideways, then he starts moving down slowly, or if i just completely stop he will fall to the ground. I have tried changing the capsule to character Controller but then when i jump the collider does not scale down when i jump which i don't like. i don't know why but I have applied gravity swell. Did not help. This picture will help you understand. Picture is here
Here is the code i am using for the character to move.
using UnityEngine;
using System;
using System.Collections;
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(CapsuleCollider))]
[RequireComponent(typeof(Rigidbody))]
public class BotCtrl : MonoBehaviour {
[System.NonSerializedAttribute]
public bool gotWrench;
protected Animator animator;
CapsuleCollider col;
float h;
float v;
AnimatorStateInfo baseCurrentState;
AnimatorStateInfo baseNextState;
AnimatorStateInfo otherMovesCurrentState;
public float DirectionDampTime = 0.15f;
public float AnimSpeed = 1.2f;
public float MoveSpeed = 1.5f;
public float rotSpeed = 90.0f;
public float JumpHeight = 70.0f;
public bool useCurves;
Transform grabbableObj;
public bool ApplyGravity = true;
void Awake(){
if(gameObject.tag != "Player")
gameObject.tag="Player";
}
void Start () {
animator = GetComponent<Animator>();
animator.speed=AnimSpeed;
if(animator.layerCount>1){
animator.SetLayerWeight(1,1.0f);
}
col = GetComponent<CapsuleCollider>();
grabbableObj = GameObject.FindWithTag("grabbable").transform;
}
void FixedUpdate () {
// Grab Input each frame
h = Input.GetAxis("Horizontal");
v = Input.GetAxis("Vertical");
if(animator){
// Set Speed and Direction Parameters to H and V axes
animator.SetFloat ("Speed", v);
animator.SetFloat("Direction", h, DirectionDampTime, Time.deltaTime);
// Set variables for info on states
baseCurrentState = animator.GetCurrentAnimatorStateInfo(0);
baseNextState = animator.GetNextAnimatorStateInfo(0);
if(animator.layerCount>1){
otherMovesCurrentState = animator.GetCurrentAnimatorStateInfo(1);
}
//Trigger Jump if we are running
if(baseCurrentState.IsName("Base.Locomotion")){
if(Input.GetButtonDown("Jump")){
animator.SetBool("Jump", true );
}
}
// Are we in idle state in Base Layer? set actions
else if(baseCurrentState.IsName("Base.Idle")){
// allow pivot on spot with Horizontal axis keys
transform.Rotate (new Vector3(0,h*Time.deltaTime*rotSpeed,0));
// make fire button cause a Wave during idle
if(Input.GetButtonDown("Jump")){
animator.SetBool("Wave", true );
}
}
else if(baseCurrentState.IsName("Base.idleGrab")){
// allow pivot on spot with Horizontal axis keys
transform.Rotate (new Vector3(0,h*Time.deltaTime*rotSpeed,0));
animator.SetBool("Grab", false );
}
else if(baseCurrentState.IsName("Base.Jump") && !animator.IsInTransition(0)){
// Reset our parameter to avoid looping
animator.SetBool("Jump", false);
// allow half as much rotation during jump
transform.Rotate (new Vector3(0,h*Time.deltaTime*rotSpeed*0.5f,0));
if(useCurves){
//set the collider height and Y center during the jumps, based on curves
col.center=new Vector3(0, animator.GetFloat("ColliderY"), 0);
col.height=animator.GetFloat("ColliderHeight");
//add extra force to main jump
rigidbody.AddForce(Vector3.up * animator.GetFloat("Jumper") * JumpHeight);
}
}
else if(baseCurrentState.IsName("Base.JumpDownRollRun") && !animator.IsInTransition(0)){
if(useCurves){
col.center=new Vector3(0,animator.GetFloat("ColliderY"),0);
col.height=animator.GetFloat("ColliderHeight");
}
}
else{
// fallback to reset collider height & position
col.center = new Vector3(0,1,0);
col.height=2;
}
// Check other moves layer for status
}
}
void OnAvatarIK(){
if(baseCurrentState.IsName("Base.idleGrab") || baseNextState.IsName("Base.idleGrab")){
float grabCurve = animator.GetFloat ("GrabCurve");
AvatarIKGoal rightHand = AvatarIKGoal.RightHand;
if(grabbableObj != null && !gotWrench) {
if(useCurves){
// Use the Curve from grabbing animation to drive smoothing of avatar hand position
animator.SetIKPositionWeight(rightHand, grabCurve);
animator.SetIKRotationWeight(rightHand, grabCurve);
}
// Set IK hand position and rotation destination
animator.SetIKPosition(rightHand, grabbableObj.position);
animator.SetIKRotation(rightHand, grabbableObj.rotation);
}
else{
// Reset Hand to be controlled by animation
animator.SetIKPositionWeight(rightHand, 0);
animator.SetIKRotationWeight(rightHand, 0);
}
}
}
void OnAvatarMove(){
// Set up for a rigidbody - set the RB position equal to the animator deltaPosition and increase by MoveSpeed
rigidbody.position += animator.deltaPosition * MoveSpeed;
transform.rotation *= animator.deltaRotation;
}
}
Tell me what should i do in order to make him touché the ground ? Please help here
2 questions
A. are you using a kinematic rigidbody? You appear to be because you don't appear to be moving the animator through addforce but through direct movement of the transform.
please note that gravity doesnt apply to kinematic rigidbodies. the whole point of marking an object kinematic is to avoid physics stuff done to it.
If you'd like to have gravity do a raycast to the ground and whenever the distance between the bottom of the collider and the terrain (or any box or any object really) is greater than epsilon (epsilon if you don't know is a math term, it just means a really small number number, a number greater than zero but close to it, it can be found in mathf.epsilon for a unity representation or you can just pick a small number.
if the difference is greater than epsilon you move it DURING FIXED UPDATE lerping it towards the ground at 9.8 meters per second squared if you want
B. if so are you applying animations during physics?
is kinematic is unchecked but i hv the rigid body component. can you give me some more info on how i should add ray-cast to the ground and player so that they meet ? please :)
void FixedUpdate(){
//first we set up an empty ray and raycasthit
Ray myray;
Raycasthit ObjectHit;
//we assign the ray so it casts from the right spot
//in the right direction
myray.origin = player.transform.position;
//notice the negative sign, it inverses the vector. up == down
myray.direction = -player.transform.up;
//now we raycast, notice the out, that just means
//the raycast modifies the value of ObjectHit
//basically ObjectHit now contains info about what we hit
physics.raycast(ray,out ObjectHit);
//now we'll check to see how far what we hit is
//from the nearest point to it on the collider
//if the collider is on the ground
//or another object and the ray is
//casting down, which it is casting down
//the distance between what we hit and the collider
//should basically be zero.
//ClosestPointOnBounds just finds the closet
//point on a collider to another point you give it.
//objectHit.point is the point we hit on whatever
//object is directly below the player. Since there
//should always be terrain or something eventually
//below the player at some point we'll hit something.
float distance = vector3.distance(player.collider.ClosestPointOnBounds(ObjectHit.point), Hit.point);
//now we have the distance between the collider and the ground/object/etc whatever is below us.
if(distance > mathf.epsilon)
{
//this will only be ran if the distance between the
//player and the ground is not zero, basically your
//airborne
//you can sub in a small number you chose for epsilon
//if you want.
//moves the player down at 1meter per second
player.rigidbody.addforce(-vector3.up);
//moves the player down at 9.8meters per second
player.rigidbody.addforce (-vector3.up * 9.8);
}
}
just to be clear, i didn't actually try this code at all. But thats pretty much it. Think that add force code is right to add force properly. i'm not sure if you add force with time.deltatime or not. You might need to but I don't think so. Unless you do it in Update ins$$anonymous$$d of FixedUpdate. You should just used fixedupdate though.
yea he said he doesnt want one because he cant modify the size of the collider during a jump like he wants.
Answer by munaeem · Nov 22, 2012 at 05:28 PM
Hi, i have fixed it and found solution to my own problem. I don't know why I always solve my own problem (unity). Well anyways, there are some changes in the engine or script what ever and if you are getting this problem from BotCtrl.cs script re-place this script and you'll be done with it. and also make sure in the animator window to the base layer 'IK something' is checked. It is the box right under it. Good luck.
using UnityEngine;
using System;
using System.Collections;
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(CapsuleCollider))]
[RequireComponent(typeof(Rigidbody))]
public class BotCtrl : MonoBehaviour {
[System.NonSerializedAttribute]
public bool gotWrench;
protected Animator animator;
CapsuleCollider col;
float h;
float v;
AnimatorStateInfo baseCurrentState;
AnimatorStateInfo baseNextState;
AnimatorStateInfo otherMovesCurrentState;
public float DirectionDampTime = 0.15f;
public float AnimSpeed = 1.2f;
public float MoveSpeed = 1.5f;
public float rotSpeed = 90.0f;
public float JumpHeight = 70.0f;
public bool useCurves;
Transform grabbableObj;
void Awake(){
if(gameObject.tag != "Player")
gameObject.tag="Player";
}
void Start () {
animator = GetComponent<Animator>();
animator.speed=AnimSpeed;
if(animator.layerCount>1){
animator.SetLayerWeight(1,1.0f);
}
col = GetComponent<CapsuleCollider>();
grabbableObj = GameObject.FindWithTag("grabbable").transform;
}
void FixedUpdate () {
// Grab Input each frame
h = Input.GetAxis("Horizontal");
v = Input.GetAxis("Vertical");
if(animator){
// Set Speed and Direction Parameters to H and V axes
animator.SetFloat ("Speed", v);
animator.SetFloat("Direction", h, DirectionDampTime, Time.deltaTime);
// Set variables for info on states
baseCurrentState = animator.GetCurrentAnimatorStateInfo(0);
baseNextState = animator.GetNextAnimatorStateInfo(0);
if(animator.layerCount>1){
otherMovesCurrentState = animator.GetCurrentAnimatorStateInfo(1);
}
//Trigger Jump if we are running
if(baseCurrentState.IsName("Base.Locomotion")){
if(Input.GetButtonDown("Jump")){
animator.SetBool("Jump", true );
}
}
// Are we in idle state in Base Layer? set actions
else if(baseCurrentState.IsName("Base.Idle")){
// allow pivot on spot with Horizontal axis keys
transform.Rotate (new Vector3(0,h*Time.deltaTime*rotSpeed,0));
// make fire button cause a Wave during idle
if(Input.GetButtonDown("Jump")){
animator.SetBool("Wave", true );
}
}
else if(baseCurrentState.IsName("Base.idleGrab")){
// allow pivot on spot with Horizontal axis keys
transform.Rotate (new Vector3(0,h*Time.deltaTime*rotSpeed,0));
animator.SetBool("Grab", false );
}
else if(baseCurrentState.IsName("Base.Jump") && !animator.IsInTransition(0)){
// Reset our parameter to avoid looping
animator.SetBool("Jump", false);
// allow half as much rotation during jump
transform.Rotate (new Vector3(0,h*Time.deltaTime*rotSpeed*0.5f,0));
if(useCurves){
//set the collider height and Y center during the jumps, based on curves
col.center=new Vector3(0, animator.GetFloat("ColliderY"), 0);
col.height=animator.GetFloat("ColliderHeight");
//add extra force to main jump
rigidbody.AddForce(Vector3.up * animator.GetFloat("Jumper") * JumpHeight);
}
}
else if(baseCurrentState.IsName("Base.JumpDownRollRun") && !animator.IsInTransition(0)){
if(useCurves){
col.center=new Vector3(0,animator.GetFloat("ColliderY"),0);
col.height=animator.GetFloat("ColliderHeight");
}
}
else{
// fallback to reset collider height & position
col.center = new Vector3(0,1,0);
col.height=2;
}
// Check other moves layer for status
if(otherMovesCurrentState.IsName("OtherMoves.Wave")){
animator.SetBool("Wave", false );
}
}
}
void OnAnimatorIK(){
if(baseCurrentState.IsName("Base.idleGrab") || baseNextState.IsName("Base.idleGrab")){
float grabCurve = animator.GetFloat ("GrabCurve");
AvatarIKGoal rightHand = AvatarIKGoal.RightHand;
if(grabbableObj != null && !gotWrench) {
if(useCurves){
// Use the Curve from grabbing animation to drive smoothing of avatar hand position
animator.SetIKPositionWeight(rightHand, grabCurve);
animator.SetIKRotationWeight(rightHand, grabCurve);
}
// Set IK hand position and rotation destination
animator.SetIKPosition(rightHand, grabbableObj.position);
animator.SetIKRotation(rightHand, grabbableObj.rotation);
}
else{
// Reset Hand to be controlled by animation
animator.SetIKPositionWeight(rightHand, 0);
animator.SetIKRotationWeight(rightHand, 0);
}
}
}
void OnAnimatorMove(){
// Set up for a rigidbody - set the RB position equal to the animator deltaPosition and increase by MoveSpeed
rigidbody.position += animator.deltaPosition * MoveSpeed;
transform.rotation *= animator.deltaRotation;
}
}
Answer by ippdev · Nov 16, 2012 at 05:25 PM
Try setting the Y Transform Based on Feet in the Preview clip setup.
no actually its mecanim and some problem with script i got it fixed
Your answer
Follow this Question
Related Questions
How to maintain collision while moving the player? 2 Answers
How to change gravity direction on Character Motor 0 Answers
Error when colliding and calling a IEnumerator 1 Answer
gravity or others. i don't get it. what i suppose to coding it 1 Answer
Simple Circular jump along local normal- similar to planetary gravity 0 Answers