Jump to content
UnitySpain
Sign in to follow this  
Antonio

ANSWERED Problema con la colisión del Character Controller (no hay deslizamiento).

Recommended Posts

Tengo un problema recurrente, varias veces he hecho algún código para mover el jugador utilizando el Character Controller pero a la hora de aplicar gravedad, doy con un problema.

 

A diferencia del controlador de rigid body, el character controller no tiene physic materials, así que cuando este colisiona no hay deslizamiento, eso hace que mi personaje, al pasar por algún bordillo se quede atascado en el aire (a menos que vaya corriendo, entonces la velocidad de desplazamiento es tan alta que al caer está más alejado del borde y no colisiona). Pero aunque parezca un caso raro, resulta que ocurre mucho cuando lo pruebo, jugando a escalar y bajar, muchas veces se me queda el personaje congelado ahí por esto mismo.  (Como no puede bajar hasta el suelo, se queda congelado con la animación de caida en el estado de caida).

ddlgek1-c3bab7b3-9736-4bc4-bd49-1fe0a18a

 


En el Update, para el movimiento había intentado esto:

//Move
				if ((AllowControls) && (GravState == GravityState.Land))
				{
					moveDirection = vertical * (Vector3.Scale(cam.forward, new Vector3(1, 0, 1)).normalized) + horizontal * cam.right;
					IsMoving = (moveDirection.magnitude > 0.1f)? true : false;
					moveDirection.Normalize();
					moveDirection = transform.InverseTransformDirection(moveDirection);
				}

                if ((GravState == GravityState.Falling) || (GravState == GravityState.FreeFalling))
                {
                        //moveDirection = transform.forward * 0.02f * Time.deltaTime;
                }

                moveDirection.y = moveDirection.y - verticalDirection;


Esa línea que esta comentada, pretendía mover al jugador hacia delante (y después un poco hacia abajo) en caso de que estuviera cayendo, pero la cosa tampoco me funciona, al activarla, el personaje va haciendo glitches hasta llegar al suelo, (como si se saliese del estado de caída y volviese a entrar continuamente).

También probé reducir el tamaño de la cápsula (está a 0.4 y la puse a 0.2) efectivamente reduce las veces en las que este problema se da, pero me causa otros problemas de clipping en la animación de esacalada (el personaje entra más de lo que está previsto y escala con las piernas hundidas en el bloque), así que lo he vuelto a poner a 0.4 para que haya más espacio entre la colisión y el origen del jugador.

¿Alguien se le ocurre alguna manera de como enfocar esto? No creo que sea algo que sólo me pase a mi, ¿como se suele solventar este problema con los bordillos? O_ò
 

 

 

Pongo aquí el código del jugador que estoy escribiendo en spoiler porque es un poco largo.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(Animator))]
public class GO_Player : MonoBehaviour 
{
	//REFERENCES
	Player_Input PI;
	Camera_Manager CM;

	Animator anim;
	CharacterController controller;
	public GameObject Model; //This need to be public to can be accessed from the outside.
	public Transform CameraTarget;
	public Transform cam;		//Used to update the camForward.

	//INPUTS
	
	public float horizontal;
	public float vertical;
	public bool walk;
	public bool sprint;
	public bool jump =false;
	public bool crouch = false;
	public bool action = false;
	public bool aim = false;
	public bool inv = false;
	public bool speak = false;
	
	public float mouseX;
	public float mouseY;

	//VARS
	public	enum State {Explorer, Aiming, AimingCorner, Lay, Crawling, Sneaking, Covering, Sliding, Escalating, Special, Swimming, Diving, Driving, Death};
    public enum GravityState { Land, Falling, FreeFalling, Jumping, Floating, Deactivated};
    public State CurrentState = State.Explorer;
	public State AnimState = State.Explorer;
    public GravityState GravState = GravityState.Land;
    
	private Vector3 moveDirection = Vector3.zero;
    public float MoveSpeed = 6.0f;

    private float verticalDirection = 0.0f;
    public float gravity = 20.0f;

    private Vector3 rotDirection = Vector3.zero; //This is variable, to calculate the progress of the rotation
	private Vector3 rotTarget = Vector3.zero; //This is a reference, used when this is not calculated in the update because AllowRot is false.
    public float NormalRotationSpeed = 360.0f;
    public float AimingRotationSpeed = 360.0f;

    //Blockers
    public bool StopInputUpdate = false; //Debug
	public bool AllowControls = true;
	public bool AllowRot = true;
	public bool AllowGravity = true;
	public bool AllowAnimationMatch = false;

	//Sensors
	public bool IsMoving = false;
	public bool IsGrounded = true;
	RaycastHit hit;
	public float DistanceToFloor;
	public LayerMask GroundLayer;
	public float TimeStartedToFall;
	
	//Weights of Animator Layers
	float LayerFallingWeight = 0.0f;
	float AimingCornerWeight = 0.0f;

	//For special animations, set by external triggers
	Transform AnimIKTransform; //For edge climbing or switches interactions.
	Transform DynamicIKTransform; //For edge climbing that can happens anywhere. Instead to go creating and erasing, ensures that there is only one and reuses it.
	AvatarTarget AnimAvatarTarget; //Chose which piece of the body match with the AnimIKTransform.

	void Start () 
	{
		Model.transform.SetAsFirstSibling();
		controller = GetComponent<CharacterController>();
		PI = GetComponent<Player_Input>();
		SetupAnimator();
		
		CM = cam.gameObject.GetComponent<Camera_Manager>();
		CM.PI = PI;
		if (CameraTarget != null)
		{
			CM.target = CameraTarget;
		}else{
			CM.target = transform;
			print ("Error: No camera target in player");
		}

		DynamicIKTransform = new GameObject().transform;
	}

	public void SetupAnimator (Animator targetAnim = null)
	{
		anim = GetComponent<Animator>();

		if (targetAnim == null) //Destroy all the animators that were in the children object.
		{
			Animator[] anims = GetComponentsInChildren<Animator> ();

			for (int i = 0; i < anims.Length; i++) 
			{
				if (anims [i] != anim) 
				{
					anim.avatar = anims [i].avatar;
					Model =  anims[i].gameObject;
					Destroy (anims [i]);
					break;
				}
			}
		} else {
			anim.avatar = targetAnim.avatar;
			Model =  targetAnim.gameObject;
			Destroy (targetAnim);
		}
	}
	

	/*
	It sets the direction of the camera, according to the pressed keys. 
	Then it uses it to find out, if the player is actually moving, (to activate the walk animation that makes the player actually move)
	And also it uses that direction to find out where the player needs to be facing.
	 */
	 
	void Update () 
	{
		//INPUTS
		if (!StopInputUpdate)	PI.UpdateInput ();
        verticalDirection = CheckGravity();
        
		//Compute actions //{Explorer, Aiming, Lay, Crawling, Sneaking, Covering, Sliding, Escalating, Special, Swimming, Diving, Driving, Death};
		switch (CurrentState)
		{
			case State.Explorer://-------------------------------------------------------------------------------------------------------------//
			{
				//Move
				if ((AllowControls) && (GravState == GravityState.Land))
				{
					moveDirection = vertical * (Vector3.Scale(cam.forward, new Vector3(1, 0, 1)).normalized) + horizontal * cam.right;
					IsMoving = (moveDirection.magnitude > 0.1f)? true : false;
					moveDirection.Normalize();
					moveDirection = transform.InverseTransformDirection(moveDirection);
				}

                if ((GravState == GravityState.Falling) || (GravState == GravityState.FreeFalling))
                {
                        //moveDirection = transform.forward * 0.02f * Time.deltaTime;
                }

                moveDirection.y = moveDirection.y - verticalDirection;

                //Rotation
                if (AllowRot)
				{
					//rotDirection = transform.InverseTransformDirection(moveDirection);
					rotDirection = moveDirection;
				}else{
					rotDirection = transform.InverseTransformDirection(rotTarget); //Rotation from the target.
				}

				// Apply rotation
				float GoalRotation = Mathf.Atan2(rotDirection.x, rotDirection.z);
				transform.Rotate(0, GoalRotation * NormalRotationSpeed * Time.deltaTime, 0);

				//Sensors
				//Climb
				RaycastHit wallhit;
				Debug.DrawRay (transform.position + new Vector3 (0.0f,0.5f,0.0f), transform.forward * 0.75f,Color.green);
				if (Physics.Raycast(transform.position + new Vector3 (0.0f,0.5f,0.0f), transform.forward, out wallhit, 0.75f, GroundLayer))
				{
					Col_Tags tags = wallhit.transform.GetComponent<Col_Tags>();
					if (tags != null)
					{
						if (tags.Climb)
						{
							if ((AllowControls) && (action))
							{
								
								//1st, check the height
								RaycastHit heighthit;
								Vector3 WallhitPoint = wallhit.point - (wallhit.normal * 0.1f);
        						if (Physics.Raycast(WallhitPoint + Vector3.up * 100, -Vector3.up, out heighthit, 105, GroundLayer))
        						{
									//Get the height and set the climb animation.
									//Set the low climb by default
									float EdgeHeight = Vector3.Distance (WallhitPoint, heighthit.point) + 0.5f;
									int AnimationType = 1;
									if (EdgeHeight > 1.25f)//It the medium climb
									{
										AnimationType = 2;
									}
									//print (EdgeHeight + " " + Time.time);

									//2nd, check if theres is space
									if (!Physics.CapsuleCast(heighthit.point + (Vector3.up * 0.1f), heighthit.point + (Vector3.up * controller.height), controller.radius, transform.forward, 0.3f, GroundLayer))
									{
										AvatarTarget at = AvatarTarget.RightHand;
										//3rd, place the HelperPoint.	
											if (AnimationType == 1)
											{
												DynamicIKTransform.position = transform.position - (wallhit.normal * 0.2f) + (Vector3.up * EdgeHeight * 2.0f);
												at = AvatarTarget.RightHand;
											}else{
												DynamicIKTransform.position = transform.position + (wallhit.normal * 0.5f) +  (Vector3.up * EdgeHeight);
											}

											Vector3 dir = (-wallhit.normal);
											MatchAnim (DynamicIKTransform, AnimationType, dir, at );

											//print ("It is climbing" + Time.time);
									}else{
										print ("There is not space to climb: " + Time.time + ", : " + wallhit.transform.name);
									}
								}else{
									print ("It's too high to climb: " + Time.time + ", : " + wallhit.transform.name);
								}
							}
						}//End of tag.climb
					}
				}

                break;
			}

			case State.Special://-------------------------------------------------------------------------------------------------------------//
			{
				//Rotation
				rotDirection = transform.InverseTransformDirection(rotTarget); //Rotation from the target.

				// Apply rotation
				float GoalRotation = Mathf.Atan2(rotDirection.x, rotDirection.z);
				transform.Rotate(0, GoalRotation * NormalRotationSpeed * Time.deltaTime, 0);
				break;
			}

			default:
			{
				break;
			}
		}

		UpdateAnimator();		
    }

    float CheckGravity ()
    {

        float result = 0.0f; 

        //Ground Sensor
        if (!AllowGravity)
        {
            GravState = GravityState.Deactivated;
            anim.SetBool("Falling", false);
            anim.SetBool("Landing", false);
            return result;
        }

        switch (GravState)
        {
            case GravityState.Land:

                //Update Distance To Floor
                //if (Physics.SphereCast(transform.position + Vector3.up* (controller.stepOffset + 0.1f), 0.1f , -Vector3.up, out hit, Mathf.Infinity, GroundLayer))
                if (Physics.Raycast(transform.position + Vector3.up * controller.stepOffset, -Vector3.up, out hit, Mathf.Infinity, GroundLayer))
                {
                    DistanceToFloor = hit.distance - controller.stepOffset;
                }else{
                    DistanceToFloor = 100.0f; //Doesn´t detect anything, let´s suposse that there are nothing, and leave the rest of the code manage if it has to fall or not.
                }
                
                if (DistanceToFloor > controller.stepOffset) //too much space below, is not grounded anymore.
                {//But, because this situation can happens in many circunstancies, we are not activating state changes yet. We are calculating the time it will be on non-ground contact, and if it´s a meaningful value, then consider it.
                    if (IsGrounded)
                    {
                        TimeStartedToFall = Time.time;
                        IsGrounded = false;
                    }else{
                        if (Time.time - TimeStartedToFall > 0.15f)//If it's not Grounded and has been falling for more than 0.15 secs, start the falling state.
                        {
                            anim.SetBool("Falling", true);
                            anim.SetBool("Landing", false);
                            GravState = GravityState.Falling;
                        }
                    }
                }else{//DistanceToFloor is short, so it's on the floor again (before the 0.15 time), return IsGrounded and remain in this Land state.
                    IsGrounded = true;
                }
                break;

            case GravityState.Falling:

                result = gravity * Time.deltaTime / 2;

                //Update Distance To Floor
                //if (Physics.SphereCast(transform.position + Vector3.up* (controller.stepOffset + 0.1f), 0.1f , -Vector3.up, out hit, Mathf.Infinity, GroundLayer))
                if (Physics.Raycast(transform.position + Vector3.up * controller.stepOffset, -Vector3.up, out hit, Mathf.Infinity, GroundLayer))
                {
                    DistanceToFloor = hit.distance - controller.stepOffset;
                }else{
                    DistanceToFloor = 100.0f; //Doesn´t detect anything, let´s suposse that there are nothing, and leave the rest of the code manage if it has to fall or not.
                }

                if (DistanceToFloor < controller.stepOffset)//If now is grounded again...
                {
                    //But, we must consider if it's a flat ground or not, because depending of that, there is a landing or more falling yet.
                    if (Vector3.Dot(transform.up, hit.normal) >= 0.95f) //Is flat floor.
                    {
                        //Keeps falling normally till the distance to floor were lower than 0.01f to remain sticked on the ground.
                        if (DistanceToFloor < 0.01f)
                        {
                            anim.SetBool("Falling", false);
                            anim.SetBool("Landing", true);
                            GravState = GravityState.Land;
                        }
                    }else{
                        //Is not flat. So land inmediately, but doing the ground fix teleportation to stick the feets on the ground.
                        anim.SetBool("Falling", false);
                        anim.SetBool("Landing", true);
                        GravState = GravityState.Land;
                        transform.position = new Vector3(transform.position.x, transform.position.y - DistanceToFloor, transform.position.z);
                    }
                }else{ //there are not ground, so keep falling. (Check if has been falling for too long to change the Free fall state).
                    if (Time.time - TimeStartedToFall > 0.3f) //Has been falling for too much time
                    {
                        GravState = GravityState.FreeFalling;
                    }
                }
                break;
            case GravityState.FreeFalling:

                result = gravity * Time.deltaTime;

                //Update Distance To Floor
                //if (Physics.SphereCast(transform.position + Vector3.up* (controller.stepOffset + 0.1f), 0.1f , -Vector3.up, out hit, Mathf.Infinity, GroundLayer))
                if (Physics.Raycast(transform.position + Vector3.up * controller.stepOffset, -Vector3.up, out hit, Mathf.Infinity, GroundLayer))
                {
                    DistanceToFloor = hit.distance - controller.stepOffset;
                }else{
                    DistanceToFloor = 100.0f; //Doesn´t detect anything, let´s suposse that there are nothing, and leave the rest of the code manage if it has to fall or not.
                }

                //Something similar to the Falling state, but with different animations.
                if (DistanceToFloor < controller.stepOffset)//If now is grounded again...
                {
                    //But, we must consider if it's a flat ground or not, because depending of that, there is a landing or more falling yet.
                    if (Vector3.Dot(transform.up, hit.normal) >= 0.95f) //Is flat floor.
                    {
                        //Keeps falling normally till the distance to floor were lower than 0.01f to remain sticked on the ground.
                        if (DistanceToFloor < 0.01f)
                        {
                            anim.SetBool("Falling", false);
                            anim.SetBool("Landing", true);
                            GravState = GravityState.Land;
                        }
                    }else{
                        //Is not flat. So land inmediately, but doing the ground fix teleportation to stick the feets on the ground.
                        anim.SetBool("Falling", false);
                        anim.SetBool("Landing", true);
                        GravState = GravityState.Land;
                        transform.position = new Vector3(transform.position.x, transform.position.y - DistanceToFloor, transform.position.z);
                    }
                }
                break;

            case GravityState.Jumping:
                //Is moving up, check for the celling
                //Has it end the moving "up" movement? if so, it´s time to start check for the ground.
                //If it has been checking for the ground too much time, it can pass to the FreeFalling state directly.

                break;
            case GravityState.Floating:
                //There is not gravity fall, but it yes manage to keep the acceleration (up and down) for a short time.

                break;
            case GravityState.Deactivated:
                //For example, for the climbing or monkey bars.

                break;
            default:
                break;
        }

        return result;
    }

	void UpdateAnimator()
	{
		switch (AnimState)
		{
			case State.Explorer:
				//Action
				if (IsMoving)
				{
					anim.SetBool ("IsMoving", true);//Only reaches here if IsMoving is true.

					float vel = 1.0f;
					if (walk)
					{
						vel = 0.5f;
					}else if (sprint)
					{//It's sprinting
								vel = 2.0f;
					}//Else, it's because it's normal running, do nothing

					anim.SetFloat ("Forward", vel);
					anim.SetFloat ("Sidewalk", moveDirection.x);
				}else{
					anim.SetBool ("IsMoving", false);
					anim.SetFloat ("Forward", 0.0f);
					anim.SetFloat ("Sidewalk", 0.0f);
				}

				if ((anim.GetCurrentAnimatorStateInfo(2).IsTag("Falling")) || (anim.GetCurrentAnimatorStateInfo(2).IsTag("Matching"))) //Looking at tags temporally in layer 2
				{
					if (LayerFallingWeight < 1.0f)
					{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, LayerFallingWeight));
						LayerFallingWeight += 5.0f * Time.deltaTime;
					}else{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, 1.0f));
					}
				}else{
					if (LayerFallingWeight > 0.0f)
					{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, LayerFallingWeight));
						LayerFallingWeight -= 5.0f * Time.deltaTime;
					}else{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, 0.0f));
					}
				}

				//Transitions
				if (CurrentState != AnimState)//This is the mega state, it can changes towards any other!! D:
				{//We are in Explorer
					switch (CurrentState)
					{
						case State.Special:
							AnimState = CurrentState;
							break;

						default:
							Debug.Log ("Error, state transition without describe at AnimState: " + AnimState + ", willing to enter in CurrentState: " + CurrentState );
							break;
					}
				}
				break;

			case State.Special:
				
				if ((anim.GetCurrentAnimatorStateInfo(2).IsTag("Falling")) || (anim.GetCurrentAnimatorStateInfo(2).IsTag("Matching")))
				{
					if (LayerFallingWeight < 1.0f)
					{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, LayerFallingWeight));
						LayerFallingWeight += 5.0f * Time.deltaTime;
					}else{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, 1.0f));
					}
				}else{
					if (LayerFallingWeight > 0.0f)
					{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, LayerFallingWeight));
						LayerFallingWeight -= 5.0f * Time.deltaTime;
					}else{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, 0.0f));
					}
				}

				//Transition 
				if (AnimState != CurrentState)//It can changes to Explorer, and Aiming. 
				{//We are in Covering
					switch (CurrentState)
					{	
						case State.Explorer:
							AnimState = CurrentState;
							break;
						default:
							Debug.Log ("Error, state transition without describe at AnimState: " + AnimState + ", willing to enter in CurrentState: " + CurrentState );
							break;
					}
				}
				break;

			default:

				break;
		}
	}
    
	public void OnAnimatorMove()
	{
		Vector3 v = (anim.deltaPosition * MoveSpeed) / Time.deltaTime;

		//If Animation Match is active, it has to stop the Projection Plane, or it won't be able to move up and down.
		//Also, it ensures that there is falling animation nor gravity application.
		if (!AllowAnimationMatch) 
		{
			if (IsGrounded)
			{
				v = Vector3.ProjectOnPlane(v, hit.normal);
			}else{
				v = Vector3.ProjectOnPlane(v, Vector3.up);
			}

            v.y = moveDirection.y;
        }

        controller.Move(v * Time.deltaTime);
	}

	public void MatchAnim (Transform HelperPoint, int AnimType, Vector3 TriggerFw, AvatarTarget BodyPiece)
	{
		BlockActions();
		rotTarget = TriggerFw; //The direction that must look now


		if (HelperPoint != null)	AnimIKTransform = HelperPoint; //The point that it will use to situate.
		AnimAvatarTarget = BodyPiece;
		anim.SetInteger ("Animation", AnimType);
		anim.SetTrigger ("DoAnimation");

		//To stop the floor projection, allowing the vertical movement and to start to check the moment that actually activates it
		AllowAnimationMatch = true; 

		CurrentState = State.Special;	
	}

	void MatchAnimStart (int DeactivateCollisions)
	{
		if (DeactivateCollisions <= 0)	gameObject.layer = 9; //To avoid collisions

		float normalisedStartTime =anim.GetFloat ("MatchStart");
		float normalisedEndTime = anim.GetFloat ("MatchEnd");
		
		//Layer 0	
		if ((anim.GetCurrentAnimatorStateInfo(0).IsTag("Matching")) && (anim.GetCurrentAnimatorStateInfo(0).normalizedTime < normalisedStartTime))
		{
			anim.MatchTarget(AnimIKTransform.position, AnimIKTransform.rotation, AnimAvatarTarget, new MatchTargetWeightMask(Vector3.one, 0.0f), normalisedStartTime, normalisedEndTime );
		}else if(anim.GetCurrentAnimatorStateInfo(0).IsTag("Matching")&&anim.GetCurrentAnimatorStateInfo(0).normalizedTime > normalisedStartTime && anim.isMatchingTarget)
		{
 			anim.InterruptMatchTarget(true);
		}
		
		//Check Layer 2, but still execute the match in layer 0.
		if ((anim.GetCurrentAnimatorStateInfo(2).IsTag("Matching")) && (anim.GetCurrentAnimatorStateInfo(2).normalizedTime < normalisedStartTime))
		{
			anim.MatchTarget(AnimIKTransform.position, AnimIKTransform.rotation, AnimAvatarTarget, new MatchTargetWeightMask(Vector3.one, 0.0f), normalisedStartTime, normalisedEndTime );
		}else if(anim.GetCurrentAnimatorStateInfo(2).IsTag("Matching")&&anim.GetCurrentAnimatorStateInfo(2).normalizedTime > normalisedStartTime && anim.isMatchingTarget)
		{
 			anim.InterruptMatchTarget(true);
		}
	}

	public void MatchAnimEnd ()
	{
		AllowActions();
		AllowAnimationMatch = false;
		anim.SetInteger ("Animation", 0);
		gameObject.layer = 10; //To recover collisions
		CurrentState = State.Explorer;
	}



	public void AllowActions ()
	{
		AllowControls = true;
		AllowRot = true;
		AllowGravity = true;
        GravState = GravityState.Land;
    }

	public void BlockActions ()
	{
		AllowControls = false;
		moveDirection = Vector3.zero;
		IsMoving = false;

		AllowRot = false;
		AllowGravity = false;
	} 


	public void ChangeChar (GameObject newModel, Vector3 newOffset)
    {
        Destroy (Model);

        Model = Instantiate(newModel, transform.position, transform.rotation) as GameObject;
		Model.transform.parent = transform;
		Model.transform.SetSiblingIndex (0);
		SetupAnimator();
    }
}

 

 

Edited by Antonio
Sacando un trozo que se había quedado dentro del Spoiler.

Share this post


Link to post
Share on other sites

No sé la respuesta, pero te agradezco MUCHÍSIMO lo que has hecho con el formato del mensaje. Si el código es demasiado largo, igual te sale más a cuenta poner un link a PasteBin o el equivalente. Pero bueno, que ésto también es lo correcto. :27_sunglasses::91_thumbsup:

Share this post


Link to post
Share on other sites

La vagueritis XD tengo que acostumbrarme a los pastebins y a los githubs (que a veces aún me pierdo buscando el botón para descargar las cosas de ahí @_@) Pero bueno, probé con el spoiler, tuve un problema con él, parece que el spoiler se comía todo lo que había en el mensaje desde el tag [ spoiler] que lo abría hasta el final. Como si ignorase el tag [ / spoiler]. O_ò  

Pero bueno, aún así me ha servido bien en este caso :)

 

Y sobre el problema del tema en sí, hoy estoy dándole otro intento, leyendo otros códigos, he visto uno que utiliza la función "OnControllerColliderHit" que efectivamente es de Unity:

https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnControllerColliderHit.html

No la había visto, ( Ahora no paro de verla en todas partes por la documentación x_x ) pero si esta función/evento efectivamente registra el punto de impacto hit que se produce cuando el character controller está en movimiento, quizás debería poder usar esa información como...

Mientras esté en el estado de caída, si hay alguna colisión (que no sea la que detecta el centro de personaje, porque esa es la del suelo) entonces si hay una colisión más como la del bordillo, entonces empezar a mover al personaje en dirección opuesta (la dirección desde el punto de impacto y el origen del personaje).

 

La idea ¿podría funcionar? En fin, voy a ver si logro realizarla.

Share this post


Link to post
Share on other sites

Lo hice :D

Al final tuve que dar un poco más de vuelta pero ya me funciona. Recapitulando, para arreglar el bloqueo de la caída que se me producía cuando chocaba con algún collider:

He creado dos vectores nuevos:

  • Pushdir este guardará la dirección a la que empujar un personaje para evitar la última colisión detectada.
  • ExtraMoveDir que guardaría una dirección para empujar al personaje cuando sea necesario. (el personaje se mueve por el input del jugador pero ahora cuando las físicas lo requieran, cambio ese nuevo Vector3 para añadir un nuevo movimiento además del que tenía).

Ese Pushdir lo actualizo en varios casos, uno de ellos es la función OnControllerCollisionHit, el problema es que no sé como encaja esa función en el tinglado general, es como si fuera una co-rutina, una función en un nuevo thread, a veces puedo ejecutar mi algoritmo pero no llamar esa función, (puede que se active antes o después, depende de la colisión de las físicas), por eso, como no tengo control sobre ella, lo que hago es que cuando se active (cuando sea), guarde la información que me interesa en Pushdir, y ahí si puedo reclamarla cuando mi algoritmo principal la necesite.

Así, en la función CheckGravity, cojo esos dato y los paso al ExtraMoveDir, esta variable se resetea en cada frame así que si el jugador "aterriza" ExtraMoveDir es cero en el siguiente frame, dejaría de afectar el movimiento del GameObject y no tengo que preocuparme por anular Pushdir dentro de la función OnControllerCollisionHit.

Ya con ese valor de Extra MoveDir, lo paso al valor de la función .Move (en mi caso lo tengo en OnAnimationMove).

 

Como extra, he actualizado la gravedad, en vez de modificar el moveDirection (que se modifica con el input del jugador), he puesto la gravedad en la Y de este ExtraMoveDir, reduciendo algunas líneas así en las funciones OnAnimationMove y Update.


Y bueno, ese error ya no se me da, una cosa menos y problema resuelto :D (Ahora a esperar al siguiente @_@)

Dejo el código con las modificaciones.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(Animator))]
public class GO_Player : MonoBehaviour 
{
	//REFERENCES
	Player_Input PI;
	Camera_Manager CM;

	Animator anim;
	CharacterController controller;
	public GameObject Model; //This need to be public to can be accessed from the outside.
	public Transform CameraTarget;
	public Transform cam;		//Used to update the camForward.

	//INPUTS
	
	public float horizontal;
	public float vertical;
	public bool walk;
	public bool sprint;
	public bool jump =false;
	public bool crouch = false;
	public bool action = false;
	public bool aim = false;
	public bool inv = false;
	public bool speak = false;
	
	public float mouseX;
	public float mouseY;

	//VARS
	public	enum State {Explorer, Aiming, AimingCorner, Lay, Crawling, Sneaking, Covering, Sliding, Escalating, Special, Swimming, Diving, Driving, Death};
    public enum GravityState { Land, Falling, FreeFalling, Jumping, Floating, Deactivated};
    public State CurrentState = State.Explorer;
	public State AnimState = State.Explorer;
    public GravityState GravState = GravityState.Land;
    
	private Vector3 moveDirection = Vector3.zero;
    public float MoveSpeed = 6.0f;
    private Vector3 PushDir = Vector3.zero;
    
    private float verticalDirection = 0;
    public float gravity = 20.0f;
    private Vector3 ExtraMoveDir = Vector3.zero;

    private Vector3 rotDirection = Vector3.zero; //This is variable, to calculate the progress of the rotation
	private Vector3 rotTarget = Vector3.zero; //This is a reference, used when this is not calculated in the update because AllowRot is false.
    public float NormalRotationSpeed = 360.0f;
    public float AimingRotationSpeed = 360.0f;

    //Blockers
    public bool StopInputUpdate = false; //Debug
	public bool AllowControls = true;
	public bool AllowRot = true;
	public bool AllowGravity = true;
	public bool AllowAnimationMatch = false;

	//Sensors
	public bool IsMoving = false;
	public bool IsGrounded = true;
	RaycastHit hit;
	public float DistanceToFloor;
	public LayerMask GroundLayer;
	public float TimeStartedToFall;
	
	//Weights of Animator Layers
	float LayerFallingWeight = 0.0f;
	float AimingCornerWeight = 0.0f;

	//For special animations, set by external triggers
	Transform AnimIKTransform; //For edge climbing or switches interactions.
	Transform DynamicIKTransform; //For edge climbing that can happens anywhere. Instead to go creating and erasing, ensures that there is only one and reuses it.
	AvatarTarget AnimAvatarTarget; //Chose which piece of the body match with the AnimIKTransform.

	void Start () 
	{
		Model.transform.SetAsFirstSibling();
		controller = GetComponent<CharacterController>();
		PI = GetComponent<Player_Input>();
		SetupAnimator();
		
		CM = cam.gameObject.GetComponent<Camera_Manager>();
		CM.PI = PI;
		if (CameraTarget != null)
		{
			CM.target = CameraTarget;
		}else{
			CM.target = transform;
			print ("Error: No camera target in player");
		}

		DynamicIKTransform = new GameObject().transform;
	}

	public void SetupAnimator (Animator targetAnim = null)
	{
		anim = GetComponent<Animator>();

		if (targetAnim == null) //Destroy all the animators that were in the children object.
		{
			Animator[] anims = GetComponentsInChildren<Animator> ();

			for (int i = 0; i < anims.Length; i++) 
			{
				if (anims [i] != anim) 
				{
					anim.avatar = anims [i].avatar;
					Model =  anims[i].gameObject;
					Destroy (anims [i]);
					break;
				}
			}
		} else {
			anim.avatar = targetAnim.avatar;
			Model =  targetAnim.gameObject;
			Destroy (targetAnim);
		}
	}
	

	/*
	It sets the direction of the camera, according to the pressed keys. 
	Then it uses it to find out, if the player is actually moving, (to activate the walk animation that makes the player actually move)
	And also it uses that direction to find out where the player needs to be facing.
	 */
	 
	void Update () 
	{
        moveDirection = Vector3.zero;

        //INPUTS
        if (!StopInputUpdate)	PI.UpdateInput ();
        ExtraMoveDir = CheckGravity();
        
		//Compute actions //{Explorer, Aiming, Lay, Crawling, Sneaking, Covering, Sliding, Escalating, Special, Swimming, Diving, Driving, Death};
		switch (CurrentState)
		{
			case State.Explorer://-------------------------------------------------------------------------------------------------------------//
			{
				//Move
				if ((AllowControls) && (GravState == GravityState.Land))
				{
					moveDirection = vertical * (Vector3.Scale(cam.forward, new Vector3(1, 0, 1)).normalized) + horizontal * cam.right;
					IsMoving = (moveDirection.magnitude > 0.1f)? true : false;
					moveDirection.Normalize();
					moveDirection = transform.InverseTransformDirection(moveDirection);
                }

                //Rotation
                if (AllowRot)
				{
					//rotDirection = transform.InverseTransformDirection(moveDirection);
					rotDirection = moveDirection;
				}else{
					rotDirection = transform.InverseTransformDirection(rotTarget); //Rotation from the target.
				}

				// Apply rotation
				float GoalRotation = Mathf.Atan2(rotDirection.x, rotDirection.z);
				transform.Rotate(0, GoalRotation * NormalRotationSpeed * Time.deltaTime, 0);

				//Sensors
				//Climb
				RaycastHit wallhit;
				Debug.DrawRay (transform.position + new Vector3 (0.0f,0.5f,0.0f), transform.forward * 0.75f,Color.green);
				if (Physics.Raycast(transform.position + new Vector3 (0.0f,0.5f,0.0f), transform.forward, out wallhit, 0.75f, GroundLayer))
				{
					Col_Tags tags = wallhit.transform.GetComponent<Col_Tags>();
					if (tags != null)
					{
						if (tags.Climb)
						{
							if ((AllowControls) && (action))
							{
								
								//1st, check the height
								RaycastHit heighthit;
								Vector3 WallhitPoint = wallhit.point - (wallhit.normal * 0.1f);
        						if (Physics.Raycast(WallhitPoint + Vector3.up * 100, -Vector3.up, out heighthit, 105, GroundLayer))
        						{
									//Get the height and set the climb animation.
									//Set the low climb by default
									float EdgeHeight = Vector3.Distance (WallhitPoint, heighthit.point) + 0.5f;
									int AnimationType = 1;
									if (EdgeHeight > 1.25f)//It the medium climb
									{
										AnimationType = 2;
									}
									//print (EdgeHeight + " " + Time.time);

									//2nd, check if theres is space
									if (!Physics.CapsuleCast(heighthit.point + (Vector3.up * 0.1f), heighthit.point + (Vector3.up * controller.height), controller.radius, transform.forward, 0.3f, GroundLayer))
									{
										AvatarTarget at = AvatarTarget.RightHand;
										//3rd, place the HelperPoint.	
											if (AnimationType == 1)
											{
												DynamicIKTransform.position = transform.position - (wallhit.normal * 0.2f) + (Vector3.up * EdgeHeight * 2.0f);
												at = AvatarTarget.RightHand;
											}else{
												DynamicIKTransform.position = transform.position + (wallhit.normal * 0.5f) +  (Vector3.up * EdgeHeight);
											}

											Vector3 dir = (-wallhit.normal);
											MatchAnim (DynamicIKTransform, AnimationType, dir, at );

											//print ("It is climbing" + Time.time);
									}else{
										print ("There is not space to climb: " + Time.time + ", : " + wallhit.transform.name);
									}
								}else{
									print ("It's too high to climb: " + Time.time + ", : " + wallhit.transform.name);
								}
							}
						}//End of tag.climb
					}
				}

                break;
			}

			case State.Special://-------------------------------------------------------------------------------------------------------------//
			{
				//Rotation
				rotDirection = transform.InverseTransformDirection(rotTarget); //Rotation from the target.

				// Apply rotation
				float GoalRotation = Mathf.Atan2(rotDirection.x, rotDirection.z);
				transform.Rotate(0, GoalRotation * NormalRotationSpeed * Time.deltaTime, 0);
				break;
			}

			default:
			{
				break;
			}
		}

		UpdateAnimator();		
    }

    Vector3 CheckGravity ()
    {

        Vector3 result = Vector3.zero;

        //Ground Sensor
        if (!AllowGravity)
        {
            GravState = GravityState.Deactivated;
            anim.SetBool("Falling", false);
            anim.SetBool("Landing", false);
            return result;
        }

        switch (GravState)
        {
            case GravityState.Land:

                //Update Distance To Floor
                //if (Physics.SphereCast(transform.position + Vector3.up* (controller.stepOffset + 0.1f), 0.1f , -Vector3.up, out hit, Mathf.Infinity, GroundLayer))
                if (Physics.Raycast(transform.position + Vector3.up * controller.stepOffset, -Vector3.up, out hit, Mathf.Infinity, GroundLayer))
                {
                    DistanceToFloor = hit.distance - controller.stepOffset;
                }else{
                    DistanceToFloor = 100.0f; //Doesn´t detect anything, let´s suposse that there are nothing, and leave the rest of the code manage if it has to fall or not.
                }
                
                if (DistanceToFloor > controller.stepOffset) //too much space below, is not grounded anymore.
                {//But, because this situation can happens in many circunstancies, we are not activating state changes yet. We are calculating the time it will be on non-ground contact, and if it´s a meaningful value, then consider it.
                    if (IsGrounded)
                    {
                        TimeStartedToFall = Time.time;
                        IsGrounded = false;
                    }else{
                        if (Time.time - TimeStartedToFall > 0.15f)//If it's not Grounded and has been falling for more than 0.15 secs, start the falling state.
                        {
                            anim.SetBool("Falling", true);
                            anim.SetBool("Landing", false);
                            GravState = GravityState.Falling;
                        }
                    }
                }else{//DistanceToFloor is short, so it's on the floor again (before the 0.15 time), return IsGrounded and remain in this Land state.
                    IsGrounded = true;
                }
                break;

            case GravityState.Falling:

                //VerticalDirection reminds after the frame, result doesn´t.
                if (verticalDirection < gravity) verticalDirection = verticalDirection + gravity * Time.deltaTime / 2;
                
                result.y = verticalDirection * (-1);

                if ((controller.collisionFlags & CollisionFlags.Below) != 0)
                {
                    result = result + PushDir;
                }


                //Update Distance To Floor
                //if (Physics.SphereCast(transform.position + Vector3.up* (controller.stepOffset + 0.1f), 0.1f , -Vector3.up, out hit, Mathf.Infinity, GroundLayer))
                if (Physics.Raycast(transform.position + Vector3.up * controller.stepOffset, -Vector3.up, out hit, Mathf.Infinity, GroundLayer))
                {
                    DistanceToFloor = hit.distance - controller.stepOffset;
                }else{
                    DistanceToFloor = 100.0f; //Doesn´t detect anything, let´s suposse that there are nothing, and leave the rest of the code manage if it has to fall or not.
                }

                if (DistanceToFloor < controller.stepOffset)//If now is grounded again...
                {
                    //But, we must consider if it's a flat ground or not, because depending of that, there is a landing or more falling yet.
                    if (Vector3.Dot(transform.up, hit.normal) >= 0.95f) //Is flat floor.
                    {
                        //Keeps falling normally till the distance to floor were lower than 0.01f to remain sticked on the ground.
                        if (DistanceToFloor < 0.01f)
                        {
                            anim.SetBool("Falling", false);
                            anim.SetBool("Landing", true);
                            GravState = GravityState.Land;
                            verticalDirection = 0;
                        }
                    }else{
                        //Is not flat. So land inmediately, but doing the ground fix teleportation to stick the feets on the ground.
                        anim.SetBool("Falling", false);
                        anim.SetBool("Landing", true);
                        GravState = GravityState.Land;
                        verticalDirection = 0;
                        transform.position = new Vector3(transform.position.x, transform.position.y - DistanceToFloor, transform.position.z);
                    }
                }else{ //there are not ground, so keep falling. (Check if has been falling for too long to change the Free fall state).
                    if (Time.time - TimeStartedToFall > 0.3f) //Has been falling for too much time
                    {
                        GravState = GravityState.FreeFalling;
                    }
                }
                break;
            case GravityState.FreeFalling:

                if (verticalDirection < gravity) verticalDirection = verticalDirection + gravity * Time.deltaTime;

                result.y = verticalDirection * (-1);

                if ((controller.collisionFlags & CollisionFlags.Below) != 0)
                {
                    result = result + PushDir;
                }

                //Update Distance To Floor
                //if (Physics.SphereCast(transform.position + Vector3.up* (controller.stepOffset + 0.1f), 0.1f , -Vector3.up, out hit, Mathf.Infinity, GroundLayer))
                if (Physics.Raycast(transform.position + Vector3.up * controller.stepOffset, -Vector3.up, out hit, Mathf.Infinity, GroundLayer))
                {
                    DistanceToFloor = hit.distance - controller.stepOffset;
                }else{
                    DistanceToFloor = 100.0f; //Doesn´t detect anything, let´s suposse that there are nothing, and leave the rest of the code manage if it has to fall or not.
                }

                //Something similar to the Falling state, but with different animations.
                if (DistanceToFloor < controller.stepOffset)//If now is grounded again...
                {
                    //But, we must consider if it's a flat ground or not, because depending of that, there is a landing or more falling yet.
                    if (Vector3.Dot(transform.up, hit.normal) >= 0.95f) //Is flat floor.
                    {
                        //Keeps falling normally till the distance to floor were lower than 0.01f to remain sticked on the ground.
                        if (DistanceToFloor < 0.01f)
                        {
                            anim.SetBool("Falling", false);
                            anim.SetBool("Landing", true);
                            GravState = GravityState.Land;
                            verticalDirection = 0;
                        }
                    }else{
                        //Is not flat. So land inmediately, but doing the ground fix teleportation to stick the feets on the ground.
                        anim.SetBool("Falling", false);
                        anim.SetBool("Landing", true);
                        GravState = GravityState.Land;
                        verticalDirection = 0;
                        transform.position = new Vector3(transform.position.x, transform.position.y - DistanceToFloor, transform.position.z);
                    }
                }
                break;

            case GravityState.Jumping:
                //Is moving up, check for the celling
                //Has it end the moving "up" movement? if so, it´s time to start check for the ground.
                //If it has been checking for the ground too much time, it can pass to the FreeFalling state directly.

                break;
            case GravityState.Floating:
                //There is not gravity fall, but it yes manage to keep the acceleration (up and down) for a short time.

                break;
            case GravityState.Deactivated:
                //For example, for the climbing or monkey bars.

                break;
            default:
                break;
        }

        return result;
    }

	void UpdateAnimator()
	{
		switch (AnimState)
		{
			case State.Explorer:
				//Action
				if (IsMoving)
				{
					anim.SetBool ("IsMoving", true);//Only reaches here if IsMoving is true.

					float vel = 1.0f;
					if (walk)
					{
						vel = 0.5f;
					}else if (sprint)
					{//It's sprinting
								vel = 2.0f;
					}//Else, it's because it's normal running, do nothing

					anim.SetFloat ("Forward", vel);
					anim.SetFloat ("Sidewalk", moveDirection.x);
				}else{
					anim.SetBool ("IsMoving", false);
					anim.SetFloat ("Forward", 0.0f);
					anim.SetFloat ("Sidewalk", 0.0f);
				}

				if ((anim.GetCurrentAnimatorStateInfo(2).IsTag("Falling")) || (anim.GetCurrentAnimatorStateInfo(2).IsTag("Matching"))) //Looking at tags temporally in layer 2
				{
					if (LayerFallingWeight < 1.0f)
					{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, LayerFallingWeight));
						LayerFallingWeight += 5.0f * Time.deltaTime;
					}else{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, 1.0f));
					}
				}else{
					if (LayerFallingWeight > 0.0f)
					{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, LayerFallingWeight));
						LayerFallingWeight -= 5.0f * Time.deltaTime;
					}else{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, 0.0f));
					}
				}

				//Transitions
				if (CurrentState != AnimState)//This is the mega state, it can changes towards any other!! D:
				{//We are in Explorer
					switch (CurrentState)
					{
						case State.Special:
							AnimState = CurrentState;
							break;

						default:
							Debug.Log ("Error, state transition without describe at AnimState: " + AnimState + ", willing to enter in CurrentState: " + CurrentState );
							break;
					}
				}
				break;

			case State.Special:
				
				if ((anim.GetCurrentAnimatorStateInfo(2).IsTag("Falling")) || (anim.GetCurrentAnimatorStateInfo(2).IsTag("Matching")))
				{
					if (LayerFallingWeight < 1.0f)
					{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, LayerFallingWeight));
						LayerFallingWeight += 5.0f * Time.deltaTime;
					}else{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, 1.0f));
					}
				}else{
					if (LayerFallingWeight > 0.0f)
					{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, LayerFallingWeight));
						LayerFallingWeight -= 5.0f * Time.deltaTime;
					}else{
						anim.SetLayerWeight (2, Mathf.Lerp(0.0f, 1.0f, 0.0f));
					}
				}

				//Transition 
				if (AnimState != CurrentState)//It can changes to Explorer, and Aiming. 
				{//We are in Covering
					switch (CurrentState)
					{	
						case State.Explorer:
							AnimState = CurrentState;
							break;
						default:
							Debug.Log ("Error, state transition without describe at AnimState: " + AnimState + ", willing to enter in CurrentState: " + CurrentState );
							break;
					}
				}
				break;

			default:

				break;
		}
	}

    void OnControllerColliderHit(ControllerColliderHit hit)
    {
        //print("NORMAL : " + hit.normal);
        if (hit.normal.y < 1)
        {
            PushDir = hit.normal; // new Vector3(transform.position.x - hit.point.x, 0, transform.position.z - hit.point.x);
            PushDir.y = 0;
        }else{
            PushDir = new Vector3(transform.position.x - hit.point.x, 0, transform.position.z - hit.point.x);
        }

        PushDir.Normalize();
        PushDir = PushDir * 1.0f;
        
    }

    public void OnAnimatorMove()
	{
		Vector3 v = (anim.deltaPosition * MoveSpeed) / Time.deltaTime;

		//If Animation Match is active, it has to stop the Projection Plane, or it won't be able to move up and down.
		//Also, it ensures that there is falling animation nor gravity application.
		if (!AllowAnimationMatch) 
		{
			if (IsGrounded)
			{
				v = Vector3.ProjectOnPlane(v, hit.normal);
			}else{
				v = Vector3.ProjectOnPlane(v, Vector3.up);
			}

            v = v + ExtraMoveDir;
        }

        controller.Move(v * Time.deltaTime);
	}

	public void MatchAnim (Transform HelperPoint, int AnimType, Vector3 TriggerFw, AvatarTarget BodyPiece)
	{
		BlockActions();
		rotTarget = TriggerFw; //The direction that must look now


		if (HelperPoint != null)	AnimIKTransform = HelperPoint; //The point that it will use to situate.
		AnimAvatarTarget = BodyPiece;
		anim.SetInteger ("Animation", AnimType);
		anim.SetTrigger ("DoAnimation");

		//To stop the floor projection, allowing the vertical movement and to start to check the moment that actually activates it
		AllowAnimationMatch = true; 

		CurrentState = State.Special;	
	}

	void MatchAnimStart (int DeactivateCollisions)
	{
		if (DeactivateCollisions <= 0)	gameObject.layer = 9; //To avoid collisions

		float normalisedStartTime =anim.GetFloat ("MatchStart");
		float normalisedEndTime = anim.GetFloat ("MatchEnd");
		
		//Layer 0	
		if ((anim.GetCurrentAnimatorStateInfo(0).IsTag("Matching")) && (anim.GetCurrentAnimatorStateInfo(0).normalizedTime < normalisedStartTime))
		{
			anim.MatchTarget(AnimIKTransform.position, AnimIKTransform.rotation, AnimAvatarTarget, new MatchTargetWeightMask(Vector3.one, 0.0f), normalisedStartTime, normalisedEndTime );
		}else if(anim.GetCurrentAnimatorStateInfo(0).IsTag("Matching")&&anim.GetCurrentAnimatorStateInfo(0).normalizedTime > normalisedStartTime && anim.isMatchingTarget)
		{
 			anim.InterruptMatchTarget(true);
		}
		
		//Check Layer 2, but still execute the match in layer 0.
		if ((anim.GetCurrentAnimatorStateInfo(2).IsTag("Matching")) && (anim.GetCurrentAnimatorStateInfo(2).normalizedTime < normalisedStartTime))
		{
			anim.MatchTarget(AnimIKTransform.position, AnimIKTransform.rotation, AnimAvatarTarget, new MatchTargetWeightMask(Vector3.one, 0.0f), normalisedStartTime, normalisedEndTime );
		}else if(anim.GetCurrentAnimatorStateInfo(2).IsTag("Matching")&&anim.GetCurrentAnimatorStateInfo(2).normalizedTime > normalisedStartTime && anim.isMatchingTarget)
		{
 			anim.InterruptMatchTarget(true);
		}
	}

	public void MatchAnimEnd ()
	{
		AllowActions();
		AllowAnimationMatch = false;
		anim.SetInteger ("Animation", 0);
		gameObject.layer = 10; //To recover collisions
		CurrentState = State.Explorer;
	}



	public void AllowActions ()
	{
		AllowControls = true;
		AllowRot = true;
		AllowGravity = true;
        GravState = GravityState.Land;
    }

	public void BlockActions ()
	{
		AllowControls = false;
		moveDirection = Vector3.zero;
		IsMoving = false;

		AllowRot = false;
		AllowGravity = false;
	} 


	public void ChangeChar (GameObject newModel, Vector3 newOffset)
    {
        Destroy (Model);

        Model = Instantiate(newModel, transform.position, transform.rotation) as GameObject;
		Model.transform.parent = transform;
		Model.transform.SetSiblingIndex (0);
		SetupAnimator();
    }
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

×
×
  • Create New...