Crear Juego Touch Mobile en Unity FPS desde Cero.

Hola muy buenas a todos y bienvenidos a este vídeo donde les mostraré cómo crear una primera versión de un juego mobile para shooter en primera persona desde cero con touch pad para controles de dispositivos móviles. El cual nos sirve de gran ayuda a la hora de implementar un juego totalmente funcional y completo del tipo shooter para ejecutarlo en nuestros dispositivos móviles. Requiere ciertos conocimientos de programación. En los enlaces encontrarán los links para acceder a nuestro portal web y obtener los códigos fuentes comentados en el vídeo. Espero que lo disfruten y dejen sus comentarios de que tal les parece.

Códigos para anexar a tu Character First Person utilizados en el vídeo.

using UnityEngine;
using System.Collections;

public class FirstPersonCharacter : MonoBehaviour
{
	[SerializeField] private float runSpeed = 8f;                                       // The speed at which we want the character to move
	[SerializeField] private float strafeSpeed = 4f;                                    // The speed at which we want the character to be able to strafe
	[SerializeField] private float jumpPower = 5f;                                      // The power behind the characters jump. increase for higher jumps
	
	[SerializeField] private AdvancedSettings advanced = new AdvancedSettings();        // The container for the advanced settings ( done this way so that the advanced setting are exposed under a foldout
	[SerializeField] private bool lockCursor = true;

	[System.Serializable]
	public class AdvancedSettings                                                       // The advanced settings
	{
		public float gravityMultiplier = 1f;                                            // Changes the way gravity effect the player ( realistic gravity can look bad for jumping in game )
		public PhysicMaterial zeroFrictionMaterial;                                     // Material used for zero friction simulation
		public PhysicMaterial highFrictionMaterial;                                     // Material used for high friction ( can stop character sliding down slopes )
		public float groundStickyEffect = 5f;											// power of 'stick to ground' effect - prevents bumping down slopes.
	}
	
	private CapsuleCollider capsule;                                                    // The capsule collider for the first person character
	private const float jumpRayLength = 0.7f;                                           // The length of the ray used for testing against the ground when jumping
	public bool grounded { get; private set; }
	private Vector2 input;
	private IComparer rayHitComparer;
	
	void Awake ()
	{
		// Set up a reference to the capsule collider.
		capsule = GetComponent() as CapsuleCollider;
		grounded = true;
		rayHitComparer = new RayHitComparer();

		if (lockCursor)
		{
			Cursor.lockState = CursorLockMode.Locked;
			Cursor.visible = false;
		}
		else
		{
			Cursor.lockState = CursorLockMode.None;
			Cursor.visible = true;
		}
	}

	void OnDisable()
	{
		Cursor.lockState = CursorLockMode.None;
		Cursor.visible = true;
	}
	
	void Update()
	{
		if (Input.GetMouseButtonUp(0))
		{
			Cursor.lockState = CursorLockMode.Locked;
			Cursor.visible = false;
		}
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            Cursor.lockState = CursorLockMode.None;
            Cursor.visible = true;
        }
	}
	
	
	public void FixedUpdate ()
	{
		float speed = runSpeed;
		
		float h = Input.GetAxis("Horizontal");
		float v = Input.GetAxis("Vertical");
		
		bool jump = Input.GetButton("Jump");
		
		input = new Vector2( h, v );

		// normalize input if it exceeds 1 in combined length:
		if (input.sqrMagnitude > 1) input.Normalize();
		
		// Get a vector which is desired move as a world-relative direction, including speeds
		Vector3 desiredMove = transform.forward * input.y * speed + transform.right * input.x * strafeSpeed;
		
		// preserving current y velocity (for falling, gravity)
		float yv = GetComponent().velocity.y;
		
		// add jump power
		if (grounded && jump) {
			yv += jumpPower;
			grounded = false;
		}
		
		// Set the rigidbody's velocity according to the ground angle and desired move
		GetComponent().velocity = desiredMove + Vector3.up * yv;
		
		// Use low/high friction depending on whether we're moving or not
		if (desiredMove.magnitude > 0 || !grounded)
		{
			GetComponent().material = advanced.zeroFrictionMaterial;
		} else {
			GetComponent().material = advanced.highFrictionMaterial;
		}

		
		// Ground Check:
		
		// Create a ray that points down from the centre of the character.
		Ray ray = new Ray(transform.position, -transform.up);
		
		// Raycast slightly further than the capsule (as determined by jumpRayLength)
		RaycastHit[] hits = Physics.RaycastAll(ray, capsule.height * jumpRayLength );
		System.Array.Sort (hits, rayHitComparer);
		
		
		if (grounded || GetComponent().velocity.y < jumpPower * .5f)
		{
			// Default value if nothing is detected:
			grounded = false;
			// Check every collider hit by the ray
			for (int i = 0; i < hits.Length; i++)
			{
				// Check it's not a trigger
				if (!hits[i].collider.isTrigger)
				{
					// The character is grounded, and we store the ground angle (calculated from the normal)
					grounded = true;
					
					// stick to surface - helps character stick to ground - specially when running down slopes
					//if (rigidbody.velocity.y <= 0) {
					GetComponent().position = Vector3.MoveTowards (GetComponent().position, hits[i].point + Vector3.up * capsule.height*.5f, Time.deltaTime * advanced.groundStickyEffect);
					//}
					GetComponent().velocity = new Vector3(GetComponent().velocity.x, 0, GetComponent().velocity.z);
					break;
				}
			}
		}
		
		Debug.DrawRay(ray.origin, ray.direction * capsule.height * jumpRayLength, grounded ? Color.green : Color.red );


		// add extra gravity
		GetComponent().AddForce(Physics.gravity * (advanced.gravityMultiplier - 1));
	}

	
	//used for comparing distances
	class RayHitComparer: IComparer
	{
		public int Compare(object x, object y)
		{
			return ((RaycastHit)x).distance.CompareTo(((RaycastHit)y).distance);
		}	
	}
	
}
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
public class MouseRotator : MonoBehaviour {
	
	// A mouselook behaviour with constraints which operate relative to
	// this gameobject's initial rotation.
	
	// Only rotates around local X and Y.
	
	// Works in local coordinates, so if this object is parented
	// to another moving gameobject, its local constraints will
	// operate correctly
	// (Think: looking out the side window of a car, or a gun turret
	// on a moving spaceship with a limited angular range)
	
	// to have no constraints on an axis, set the rotationRange to 360 or greater.

	public Vector2 rotationRange = new Vector3(70,70); 
	public float rotationSpeed = 10;
	public float dampingTime = 0.2f;
	public bool autoZeroVerticalOnMobile = true;
	public bool autoZeroHorizontalOnMobile = false;
	public bool relative = true;
	Vector3 targetAngles;
	Vector3 followAngles;
	Vector3 followVelocity;
	Quaternion originalRotation;

	
	// Use this for initialization
	void Start () {
		originalRotation = transform.localRotation;
	}
	
	// Update is called once per frame
	void Update () {
		
		// we make initial calculations from the original local rotation
		transform.localRotation = originalRotation;

		// read input from mouse or mobile controls
		float inputH = 0;
		float inputV = 0;
		if (relative)
		{
			
			inputH = CrossPlatformInputManager.GetAxis("Horizontal");
			inputV = CrossPlatformInputManager.GetAxis("Vertical");
			
			// wrap values to avoid springing quickly the wrong way from positive to negative
			if (targetAngles.y > 180) { targetAngles.y -= 360; followAngles.y -= 360; }
			if (targetAngles.x > 180) { targetAngles.x -= 360; followAngles.x-= 360; }
			if (targetAngles.y < -180) { targetAngles.y += 360; followAngles.y += 360; }
			if (targetAngles.x < -180) { targetAngles.x += 360; followAngles.x += 360; }

			// with mouse input, we have direct control with no springback required.
			targetAngles.y += inputH * rotationSpeed;
			targetAngles.x += inputV * rotationSpeed;

			// clamp values to allowed range
			targetAngles.y = Mathf.Clamp ( targetAngles.y, -rotationRange.y * 0.5f, rotationRange.y * 0.5f );
			targetAngles.x = Mathf.Clamp ( targetAngles.x, -rotationRange.x * 0.5f, rotationRange.x * 0.5f );

		} else {

			inputH = Input.mousePosition.x;
			inputV = Input.mousePosition.y;

			// set values to allowed range
			targetAngles.y = Mathf.Lerp ( -rotationRange.y * 0.5f, rotationRange.y * 0.5f, inputH/Screen.width );
			targetAngles.x = Mathf.Lerp ( -rotationRange.x * 0.5f, rotationRange.x * 0.5f, inputV/Screen.height );



		}





		// smoothly interpolate current values to target angles
		followAngles = Vector3.SmoothDamp( followAngles, targetAngles, ref followVelocity, dampingTime );

		// update the actual gameobject's rotation
		transform.localRotation = originalRotation * Quaternion.Euler( -followAngles.x, followAngles.y, 0 );
		
	}


}
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class FirstPersonHeadBob : MonoBehaviour {

	// Head bobbing is controlled by a sine wave and the character's speed, modulated by a handful of values.
	// This script also controls sound effects for footsteps, landing and jumping
	// (because the footsteps are tied to the head bob cycle)
	// When jumping or landing, the head also moves and tilts based on some simple springy calculations.

	[SerializeField] Transform head;							// the object to which the head-bob movement should be applied

	// these modulate the head bob movement
	[SerializeField] float headBobFrequency = 1.5f;				// the base speed of the head bobbing (in cycles per metre)
	[SerializeField] float headBobHeight = 0.3f;				// the height range of the head bob
	[SerializeField] float headBobSwayAngle = 0.5f;				// the angle which the head tilts to left & right during the bob cycle
	[SerializeField] float headBobSideMovement = 0.05f;			// the distance the head moves to left & right during the bob cycle
	[SerializeField] float bobHeightSpeedMultiplier = 0.3f;		// the amount the bob height increases as the character's speed increases (for a good 'run' effect compared with walking)
	[SerializeField] float bobStrideSpeedLengthen = 0.3f;		// the amount the stride lengthens based on speed (so that running isn't like a silly speedwalk!)

	// these control the amount of movement applied to the head when the character jumps or lands
	[SerializeField] float jumpLandMove = 3;
	[SerializeField] float jumpLandTilt = 60;
	
	// audio clip references
	[SerializeField] AudioClip[] footstepSounds;		// an array of footstep sounds that will be randomly selected from.
	[SerializeField] AudioClip jumpSound;				// the sound played when character leaves the ground.
	[SerializeField] AudioClip landSound;				// the sound played when character touches back on ground.

	// private vars:
	FirstPersonCharacter character;						// a reference to the First Person Character component (on the parent gameobject)
	Vector3 originalLocalPos;							// the original local position of this gameobject at Start

	//float nextStepTime = 0.5f;									// the time at which the next footstep sound is due to occur
	float headBobCycle = 0;								// the current position through the headbob cycle
	float headBobFade = 0;								// the current amount to which the head bob position is being applied or not (it is faded out when the character is not moving)


	// Fields for simple spring calculation:
	float springPos = 0;
	float springVelocity = 0;
	float springElastic = 1.1f;		
	float springDampen = 0.8f;
	float springVelocityThreshold = 0.05f;
	float springPositionThreshold = 0.05f;


	Vector3 prevPosition;								// the position from last frame
	Vector3 prevVelocity = Vector3.zero;				// the velocity from last frame
	bool prevGrounded = true;							// whether the character was grounded last frame


	// Use this for initialization
	void Start () {

		originalLocalPos = head.localPosition;
		character = GetComponent();
		if (GetComponent() == null)
		{
			// we automatically add an audiosource, if one has not been manually added.
			// (if you want to control the rolloff or other audio settings, add an audiosource manually)
			gameObject.AddComponent();
		}
		prevPosition = GetComponent().position;




		ShootParticle = GetComponentInChildren();

        rb = GetComponent();
		anima = GetComponent();
        //Control = GetComponent();
        Control = GetComponent();       
        health = GetComponent();
 //       floorMask = LayerMask.GetMask("floor");
        txtLives.text = "Lives: " + lives.ToString();
        txtZombies.text = "" + zombiesCount.ToString();
        PlayerController = GetComponent();
        Actions = GetComponent();
//        PlayerController.SetArsenal("Rifle");
 //       audio = GetComponent();
 //       camera= GetComponent();
        shootableMask = LayerMask.GetMask("Shooteable");
	}


	
	// Update is called once per frame
	void FixedUpdate () {

		// we use the actual distance moved as the velocity since last frame, rather than reading
		//the rigidbody's velocity, because this prevents the 'running against a wall' effect.
		Vector3 velocity = (GetComponent().position - prevPosition) / Time.deltaTime;
		Vector3 velocityChange = velocity - prevVelocity;
		prevPosition = GetComponent().position;
		prevVelocity = velocity;

                  // vertical head position "spring simulation" for jumping/landing impacts
		springVelocity -= velocityChange.y;							// input to spring from change in character Y velocity
		springVelocity -= springPos*springElastic;					// elastic spring force towards zero position
		springVelocity *= springDampen;								// damping towards zero velocity
		springPos += springVelocity * Time.deltaTime;				// output to head Y position
		springPos = Mathf.Clamp( springPos, -.3f, .3f );			// clamp spring distance

		// snap spring values to zero if almost stopped:
		if (Mathf.Abs(springVelocity) < springVelocityThreshold && Mathf.Abs (springPos) < springPositionThreshold)
		{
			springVelocity = 0;
			springPos = 0;
		}

		// head bob cycle is based on "flat" velocity (i.e. excluding Y)
		float flatVelocity = new Vector3(velocity.x,0,velocity.z).magnitude;

		// lengthen stride based on speed (so run bobbing isn't lots of little steps)
		float strideLengthen = 1 + (flatVelocity * bobStrideSpeedLengthen);

		// increment cycle
		headBobCycle += (flatVelocity / strideLengthen) * (Time.deltaTime / headBobFrequency);

		// actual bobbing and swaying values calculated using Sine wave
		float bobFactor = Mathf.Sin(headBobCycle*Mathf.PI*2); 
		float bobSwayFactor = Mathf.Sin(headBobCycle*Mathf.PI*2 + Mathf.PI*.5f); // sway is offset along the sin curve by a quarter-turn in radians
		bobFactor = 1-(bobFactor*.5f+1); // bob value is brought into 0-1 range and inverted
		bobFactor *= bobFactor;	// bob value is biased towards 0

		// fade head bob effect to zero if not moving
		if (new Vector3(velocity.x,0,velocity.z).magnitude < 0.1f)
		{
			headBobFade = Mathf.Lerp(headBobFade,0,Time.deltaTime);
		} else {
			headBobFade = Mathf.Lerp(headBobFade,1,Time.deltaTime);
		}

		// height of bob is exaggerated based on speed
		float speedHeightFactor = 1 + (flatVelocity * bobHeightSpeedMultiplier);

		// finally, set the position and rotation values
		float xPos = -headBobSideMovement * bobSwayFactor;
		float yPos = springPos * jumpLandMove + bobFactor*headBobHeight*headBobFade*speedHeightFactor;
		float xTilt = -springPos*jumpLandTilt;
		float zTilt = bobSwayFactor*headBobSwayAngle*headBobFade;
		head.localPosition = originalLocalPos + new Vector3(xPos, yPos, 0);
		head.localRotation = Quaternion.Euler(xTilt,0,zTilt);


		// Play audio clips based on leaving ground/landing and head bob cycle
		if (character.grounded )
		{
			if (!prevGrounded)
			{
				GetComponent().clip = landSound;
				GetComponent().Play();
				//nextStepTime = headBobCycle + .5f;
				
			} else {
				/*		// Don't play footstep sounds for this demo
				if ( headBobCycle > nextStepTime)
				{
					// time for next footstep sound:

					nextStepTime = headBobCycle + .5f;
					
					// pick & play a random footstep sound from the array,
					// excluding sound at index 0
					int n = Random.Range(1,footstepSounds.Length);
					audio.clip = footstepSounds[n];
					audio.Play();

					// move picked sound to index 0 so it's not picked next time
					footstepSounds[n] = footstepSounds[0];
					footstepSounds[0] = audio.clip;

				}
				 */
			}
			prevGrounded = true;
			
		} else {
			
			if (prevGrounded)
			{
				GetComponent().clip = jumpSound;
				GetComponent().Play();
			}
			prevGrounded = false;
		}
	}

	public float speed = 2f;
    public int lives = 10;
    public int zombiesCount = 0;
    public Text txtLives;
    public Text txtZombies;
    private Animator anima;
    private bool walking;
    Vector3 playerToMouse;
//    int floorMask;
//    float camRayLength = 100f;
    Rigidbody rb;
    Vector3 move;
    float timeLimit = 2f;
  //  AudioSource audio;
//    public Camera camera;

    public FixedJoystick LeftJoystick;
    public FixedButton Button;
    public FixedTouchField TouchField;
    //protected ThirdPersonUserControl Control;
    protected FirstPersonHeadBob Control;
	protected Actions Actions;
	//protected Rigidbody Rigidbody;
	protected PlayerController PlayerController;
    protected float CameraAngle;
    protected float CameraAngleY;
    protected float CameraAngleSpeed = 0.3f;
	protected float CameraPosY;
	protected float CameraPosSpeed = 0.3f;
    private CharacterHealth health;
	protected ParticleSystem ShootParticle;
	protected float CoolDown;

    Ray shootRay;
    RaycastHit shootHit;
    int shootableMask;
//    LineRenderer gunLine;
//    Light gunLight;
//    float effectGun = 0.2f;

    ShootController shootController;
    public float TimeBullet = 0.15f;
    float timer;
    public float range = 100f;

    // Use this for initialization

	
	// Update is called once per frame
	void Update () {
		//var input = new Vector3(LeftJoystick.Horizontal,0,LeftJoystick.Vertical);
        /* var vel = Quaternion.AngleAxis(CameraAngleY + 180, Vector3.up) * input *5f;

        rb.velocity = new Vector3(vel.x, rb.velocity.y, vel.z);
        transform.rotation = Quaternion.AngleAxis(CameraAngleY + 180 + Vector3.SignedAngle(Vector3.forward, input.normalized + Vector3.forward * 0.001f, Vector3.up),Vector3.up);
        CameraAngleY += TouchField.TouchDist.x * CameraAngleSpeed;
        //CameraAngle += Mathf.Clamp(CameraAngleY - TouchField.TouchDist.x * CameraAngleSpeed, 0, 5f);

        CameraPosY = Mathf.Clamp(CameraPosY - TouchField.TouchDist.y * CameraPosSpeed,0, 5f);
        //CameraPosY += TouchField.TouchDist.y * CameraAngleSpeed;

        Camera.main.transform.position = transform.position + Quaternion.AngleAxis(CameraAngleY, Vector3.up) * new Vector3(0, CameraPosY, 1);
        Camera.main.transform.rotation = Quaternion.LookRotation(transform.position + Vector3.up * 2f - Camera.main.transform.position, Vector3.up);
*/
/*
		var ray = Camera.main.ScreenPointToRay(new Vector3(Screen.width / 2f, Screen.height / 2f,0));
		Debug.DrawRay(ray.origin, ray.direction, Color.red);

		
		CoolDown += Time.deltaTime;

        if(Button.Pressed && CoolDown >= TimeBullet){
            //audio.Play();

            Actions.Attack();
			if(CoolDown>=0f){
				CoolDown = 0f;

 //               ShootParticle.Play();
				RaycastHit hitinfo;
				if(Physics.Raycast(ray, out hitinfo, range, shootableMask)){
                    Enemy other =hitinfo.collider.GetComponent();
					if(other != null){
						other.GetComponent().AddForceAtPosition((hitinfo.point - ShootParticle.transform.position).normalized * 500f, hitinfo.point);
                        other.takeDamage();
					}
				}
			}
		} else {
//            ShootParticle.Stop();
			if(rb.velocity.magnitude > 3f){
				Actions.Run();
			} else if(rb.velocity.magnitude > 0.5f){
				Actions.Walk();
			} else {
				Actions.Stay();
			}
		}*/

        if (lives <= 0)
        {
            /*if (timeLimit > 1)
            {
                timeLimit -= Time.deltaTime;
            }
            else
            {*/
                SceneManager.LoadScene("Perdiste");
            //}
        }
        if (zombiesCount >= 100)
        {
            /*if (timeLimit > 1)
            {
                timeLimit -= Time.deltaTime;
            }
            else
            {*/
                SceneManager.LoadScene("Ganaste");
            //}
        }

	}
  /*  public void DisabledEffects()
    {
        gunLine.enabled = false;
        gunLight.enabled = false;
    }*/
    public void Attack()
    {
        lives -= 1;

        txtLives.text = "Lives: " + lives.ToString();
        health.DealDamage(1);
        if (lives <= 0)
        {
            //anima.SetTrigger("Death");
            //GetComponent().isTrigger = true;
            //GetComponent().enabled = false;
        }
    }

    public void updateZombiesCount()
    {
        zombiesCount += 1;
        txtZombies.text = "" + zombiesCount.ToString();

    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CharacterHealth : MonoBehaviour {
	public float CurrentHealth {
		get;
		set;
	}
	public float MaxHealth {
		get;
		set;
	}
    private Animator anima;
	public Slider HealthBar;
	// Use this for initialization
	void Start () {
		MaxHealth = 50f;
        CurrentHealth = MaxHealth;
        anima = GetComponent();
		HealthBar.value = CalculateHealth();
    }
	
	// Update is called once per frame
	void Update () {
		if(Input.GetKeyDown(KeyCode.X)){
			DealDamage(1);
		}
	}

	public void DealDamage(float damageValue){
        CurrentHealth -= damageValue;
		HealthBar.value= CalculateHealth();
		if(CurrentHealth <= 0){
			Die();
		}
	}

	float CalculateHealth(){
		return CurrentHealth /MaxHealth;
	}

	void Die(){
		CurrentHealth = 0;
		anima.SetTrigger("Death");
		//GetComponent().isTrigger = true;
		//GetComponent().enabled = false;
        
	}
}
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
using UnityStandardAssets.Utility;
using Random = UnityEngine.Random;

namespace UnityStandardAssets.Characters.FirstPerson
{
    [RequireComponent(typeof (CharacterController))]
    [RequireComponent(typeof (AudioSource))]
    public class FirstPersonController : MonoBehaviour
    {
        [SerializeField] private bool m_IsWalking;
        [SerializeField] private float m_WalkSpeed;
        [SerializeField] private float m_RunSpeed;
        [SerializeField] [Range(0f, 1f)] private float m_RunstepLenghten;
        [SerializeField] private float m_JumpSpeed;
        [SerializeField] private float m_StickToGroundForce;
        [SerializeField] private float m_GravityMultiplier;
        [SerializeField] private MouseLook m_MouseLook;
        [SerializeField] private bool m_UseFovKick;
        [SerializeField] private FOVKick m_FovKick = new FOVKick();
        [SerializeField] private bool m_UseHeadBob;
        [SerializeField] private CurveControlledBob m_HeadBob = new CurveControlledBob();
        [SerializeField] private LerpControlledBob m_JumpBob = new LerpControlledBob();
        [SerializeField] private float m_StepInterval;
        [SerializeField] private AudioClip[] m_FootstepSounds;    // an array of footstep sounds that will be randomly selected from.
        [SerializeField] private AudioClip m_JumpSound;           // the sound played when character leaves the ground.
        [SerializeField] private AudioClip m_LandSound;           // the sound played when character touches back on ground.

        private Camera m_Camera;
        private bool m_Jump;
        private float m_YRotation;
        private Vector2 m_Input;
        private Vector3 m_MoveDir = Vector3.zero;
        private CharacterController m_CharacterController;
        private CollisionFlags m_CollisionFlags;
        private bool m_PreviouslyGrounded;
        private Vector3 m_OriginalCameraPosition;
        private float m_StepCycle;
        private float m_NextStep;
        private bool m_Jumping;
        private AudioSource m_AudioSource;

        // Use this for initialization
        private void Start()
        {
            m_CharacterController = GetComponent();
            m_Camera = Camera.main;
            m_OriginalCameraPosition = m_Camera.transform.localPosition;
            m_FovKick.Setup(m_Camera);
            m_HeadBob.Setup(m_Camera, m_StepInterval);
            m_StepCycle = 0f;
            m_NextStep = m_StepCycle/2f;
            m_Jumping = false;
            m_AudioSource = GetComponent();
			m_MouseLook.Init(transform , m_Camera.transform);
        }


        // Update is called once per frame
        private void Update()
        {
            RotateView();
            // the jump state needs to read here to make sure it is not missed
            if (!m_Jump)
            {
                m_Jump = CrossPlatformInputManager.GetButtonDown("Jump");
            }

            if (!m_PreviouslyGrounded && m_CharacterController.isGrounded)
            {
                StartCoroutine(m_JumpBob.DoBobCycle());
                PlayLandingSound();
                m_MoveDir.y = 0f;
                m_Jumping = false;
            }
            if (!m_CharacterController.isGrounded && !m_Jumping && m_PreviouslyGrounded)
            {
                m_MoveDir.y = 0f;
            }

            m_PreviouslyGrounded = m_CharacterController.isGrounded;
        }


        private void PlayLandingSound()
        {
            m_AudioSource.clip = m_LandSound;
            m_AudioSource.Play();
            m_NextStep = m_StepCycle + .5f;
        }


        private void FixedUpdate()
        {
            float speed;
            GetInput(out speed);
            // always move along the camera forward as it is the direction that it being aimed at
            Vector3 desiredMove = transform.forward*m_Input.y + transform.right*m_Input.x;

            // get a normal for the surface that is being touched to move along it
            RaycastHit hitInfo;
            Physics.SphereCast(transform.position, m_CharacterController.radius, Vector3.down, out hitInfo,
                               m_CharacterController.height/2f, Physics.AllLayers, QueryTriggerInteraction.Ignore);
            desiredMove = Vector3.ProjectOnPlane(desiredMove, hitInfo.normal).normalized;

            m_MoveDir.x = desiredMove.x*speed;
            m_MoveDir.z = desiredMove.z*speed;


            if (m_CharacterController.isGrounded)
            {
                m_MoveDir.y = -m_StickToGroundForce;

                if (m_Jump)
                {
                    m_MoveDir.y = m_JumpSpeed;
                    PlayJumpSound();
                    m_Jump = false;
                    m_Jumping = true;
                }
            }
            else
            {
                m_MoveDir += Physics.gravity*m_GravityMultiplier*Time.fixedDeltaTime;
            }
            m_CollisionFlags = m_CharacterController.Move(m_MoveDir*Time.fixedDeltaTime);

            ProgressStepCycle(speed);
            UpdateCameraPosition(speed);

            m_MouseLook.UpdateCursorLock();
        }


        private void PlayJumpSound()
        {
            m_AudioSource.clip = m_JumpSound;
            m_AudioSource.Play();
        }


        private void ProgressStepCycle(float speed)
        {
            if (m_CharacterController.velocity.sqrMagnitude > 0 && (m_Input.x != 0 || m_Input.y != 0))
            {
                m_StepCycle += (m_CharacterController.velocity.magnitude + (speed*(m_IsWalking ? 1f : m_RunstepLenghten)))*
                             Time.fixedDeltaTime;
            }

            if (!(m_StepCycle > m_NextStep))
            {
                return;
            }

            m_NextStep = m_StepCycle + m_StepInterval;

            PlayFootStepAudio();
        }


        private void PlayFootStepAudio()
        {
            if (!m_CharacterController.isGrounded)
            {
                return;
            }
            // pick & play a random footstep sound from the array,
            // excluding sound at index 0
            int n = Random.Range(1, m_FootstepSounds.Length);
            m_AudioSource.clip = m_FootstepSounds[n];
            m_AudioSource.PlayOneShot(m_AudioSource.clip);
            // move picked sound to index 0 so it's not picked next time
            m_FootstepSounds[n] = m_FootstepSounds[0];
            m_FootstepSounds[0] = m_AudioSource.clip;
        }


        private void UpdateCameraPosition(float speed)
        {
            Vector3 newCameraPosition;
            if (!m_UseHeadBob)
            {
                return;
            }
            if (m_CharacterController.velocity.magnitude > 0 && m_CharacterController.isGrounded)
            {
                m_Camera.transform.localPosition =
                    m_HeadBob.DoHeadBob(m_CharacterController.velocity.magnitude +
                                      (speed*(m_IsWalking ? 1f : m_RunstepLenghten)));
                newCameraPosition = m_Camera.transform.localPosition;
                newCameraPosition.y = m_Camera.transform.localPosition.y - m_JumpBob.Offset();
            }
            else
            {
                newCameraPosition = m_Camera.transform.localPosition;
                newCameraPosition.y = m_OriginalCameraPosition.y - m_JumpBob.Offset();
            }
            m_Camera.transform.localPosition = newCameraPosition;
        }


        private void GetInput(out float speed)
        {
            // Read input
            float horizontal = CrossPlatformInputManager.GetAxis("Horizontal");
            float vertical = CrossPlatformInputManager.GetAxis("Vertical");

            bool waswalking = m_IsWalking;

#if !MOBILE_INPUT
            // On standalone builds, walk/run speed is modified by a key press.
            // keep track of whether or not the character is walking or running
            m_IsWalking = !Input.GetKey(KeyCode.LeftShift);
#endif
            // set the desired speed to be walking or running
            speed = m_IsWalking ? m_WalkSpeed : m_RunSpeed;
            m_Input = new Vector2(horizontal, vertical);

            // normalize input if it exceeds 1 in combined length:
            if (m_Input.sqrMagnitude > 1)
            {
                m_Input.Normalize();
            }

            // handle speed change to give an fov kick
            // only if the player is going to a run, is running and the fovkick is to be used
            if (m_IsWalking != waswalking && m_UseFovKick && m_CharacterController.velocity.sqrMagnitude > 0)
            {
                StopAllCoroutines();
                StartCoroutine(!m_IsWalking ? m_FovKick.FOVKickUp() : m_FovKick.FOVKickDown());
            }
        }


        private void RotateView()
        {
            m_MouseLook.LookRotation (transform, m_Camera.transform);
        }


        private void OnControllerColliderHit(ControllerColliderHit hit)
        {
            Rigidbody body = hit.collider.attachedRigidbody;
            //dont move the rigidbody if the character is on top of it
            if (m_CollisionFlags == CollisionFlags.Below)
            {
                return;
            }

            if (body == null || body.isKinematic)
            {
                return;
            }
            body.AddForceAtPosition(m_CharacterController.velocity*0.1f, hit.point, ForceMode.Impulse);
        }
    }
}

Descarga el Juego gratis en nuestra tienda de Google Play Store! https://play.google.com/store/apps/de

Asset en la Unity Asset Store: https://bit.ly/2YlPLbZ

Apóyanos a seguir creciendo con tu donación a través de Paypal: https://www.paypal.me/zoegeop

Visita nuestro sitio web conoce nuestros proyectos y suscríbete a nuestro boletín https://www.zoegeop.com.pe

Suscríbete a mi canal: https://www.youtube.com/channel/UCazd

Sígueme en mis redes sociales: https://www.facebook.com/ZoeGeopTech

https://discordapp.com/invite/FjJ8Ggz

https://www.instagram.com/zoegeop/

https://www.linkedin.com/company/zoeg

https://www.pinterest.es/zoegeoptechn

https://twitter.com/ZoeGeop

Zoe Geop

Written by 

Servicios en Marketing Digital y Alojamiento Web.