En esta oportunidad les mostraré cómo crear una primera versión de un juego mobile de modalidad RPG /Shooter en primera y tercera persona con el Asset UFPS Ultimate. El cual es de gran ayuda a la hora de implementar un juego totalmente funcional y completo del tipo Shooter o RPG para ejecutarlo en nuestros dispositivos Standalone o Consolas. No requiere ciertos conocimientos de programación. En los enlaces encontrarán los links comentados en el video para acceder a nuestro portal web. Espero que lo disfruten y dejen sus comentarios contándome que tal les parece.

✔️Características únicas

El controlador contiene muchas características que normalmente no se encuentran en otros controladores de personajes, desde el cambio de perspectiva en primera y tercera persona hasta el sistema de resorte que permite animaciones fluidas y procedimentales en primera persona. Los modelos de personajes se pueden cambiar en tiempo de ejecución. El sistema de artículos modulares le permite ajustar el comportamiento de un artículo a sus especificaciones exactas. Otras características únicas incluyen el sistema de habilidades, la gravedad dinámica y la posibilidad de cambiar la escala de tiempo por personaje.

✔️Calidad y modularidad excepcionales

Muchos activos intentan hacer demasiado. El enfoque completo del Ultimate Character Controller es ser un gran controlador de personajes. El diseño modular permite integraciones con activos que sobresalen en otras áreas.

Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios, web y más.

Suscríbete



Siguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

 

Únete a nuestro Discord

 

Twitter

 

Facebook

 

Instagram

 

Linkedin

 

Pinterest

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

ZoeGeop Technologies
MarketPlace

Crea tu cuenta

La industria de videojuegos genera cada año más de 726.000 millones de dólares, un indicador del creciente auge en los últimos tiempos.

Lo que antes era considerado un negocio únicamente enfocado al ocio, ahora esta llegando a sectores mucho más especializados para sacarle mayor provecho económicamente mediante  eventos de torneos de jugadores apasionados.

No paran de crecer los números y las ventas del sector de los videojuegos, es un constante crecimiento que le permite colarse como uno de los que más facturan dinero proporcionalmente, más que el cine, la literatura y la música juntos.

Con esta salud de hierro, queremos traeros los espectaculares números estratosféricos que tienen los juegos más vendidos de la historia, si quieres saber cuales son y el ranking de copias vendidas, este listado te lo va a dejar claro.

Los videojuegos más vendidos de la historia tienen en común muchas cosas, aparte de que probablemente hayas jugado a más de uno, y es que por la época de salida además del boca a boca, han hecho que tengan un flujo de venta casi constante durante muchos más años de los habituales.

Los juegos más vendidos de la historia forman una lista con diferentes géneros que integran diversos estilos y formatos. Desde títulos recientes a clásicos sempiternos que han marcado generaciones a través del tiempo.

 

Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios, web y más.

Suscríbete



Siguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

 

Únete a nuestro Discord

 

Twitter

 

Facebook

 

Instagram

 

Linkedin

 

Pinterest

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

ZoeGeop Technologies
MarketPlace

Crea tu cuenta


¡Hola! En esta oportunidad te presentamos el asset más completo hasta la fecha para modificar y crear juegos en primera y tercera persona: el Ultimate Character Controller. Con este asset pagado de la tienda de Unity podrás ver todas las funcionalidades que te ofrece y enfocarte en una modalidad bastante utilizada en la actualidad, que nos sirve para crear juegos 2.5D.

El desarrollo completo de un videojuego, aunque sea a pequeña escala, requiere de una buena planificación y distribución de todas las funciones a realizar. Esto es debido a que para la creación de un buen producto son necesarios conocimientos de muchos ámbitos diferentes (programación, diseño 3D, diseño de videojuegos…) para poder crear e implementar todos los elementos necesarios para el juego, por esto mismo, si no se tiene una buena planificación del desarrollo y se tienen claramente definidos sus requisitos, la correcta combinación de estos elementos en un producto unificado y de calidad se vuelve prácticamente una misión imposible.

Asimismo, considero que se ha demostrado que se han adquirido unos conocimientos suficientes en los diferentes ámbitos del desarrollo de este proyecto. Además de que, en este punto, con más tiempo y recursos a mi disposición se podría mejorar el juego e intentar alcanzar el nivel de un pequeño producto a nivel comercial.

Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios, web y más.

Suscríbete



Siguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

 

Únete a nuestro Discord

 

Twitter

 

Facebook

 

Instagram

 

Linkedin

 

Pinterest

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

ZoeGeop Technologies
MarketPlace

Crea tu cuenta

2D GAME KIT UNITY


¡Hola! Les compartimos en esta oportunidad un tutorial que nos ofrece un nuevo activo gratuito en la tienda de activos de Unity: el Kit de Juego 2D. El cual es libre de modificación y adecuación para desarrollos de juegos propios garantizado oficialmente por unidad. Esperamos les sea de mucho provecho.

Unity le da poder a los diseñadores de juego en hacer juegos. Lo que es realmente especial de Unity es que no se necesita años de experiencia programando o un titulo universitario en arte para hacer juegos divertidos. Hay un conjunto de conceptos de trabajo que se necesitan para aprender a utilizar Unity. Una vez se entiendan estos, uno va a poder encontrarse a sí mismo haciendo juegos en un instante. Con el tiempo que se va ahorrar poniendo sus juegos en funcionamiento, va a poder usar mucho más tiempo para refinar, balancear, y ajustar su juego a la perfección.

Esta sección va a explicar los conceptos básicos que se necesitara para crear una experiencia de juego única, increíble, y divertida. La mayoría de estos conceptos requieren que escriba Scripts. Para una visión generar de crear y trabajar con scripts, lea la página Scripting

Las escenas contienen los objetos de su juego. Pueden ser usadas para crear un menú principal, niveles individuales, y cualquier otra cosa. Piense en cada archivo de escena, como un nivel único. En cada escena, usted va a colocar su ambiente, obstáculos, y decoraciones, el diseño esencial y la construcción de su juego en pedazos.

Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios, web y más.

Suscríbete



Siguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

 

Únete a nuestro Discord

 

Twitter

 

Facebook

 

Instagram

 

Linkedin

 

Pinterest

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

ZoeGeop Technologies
MarketPlace

Crea tu cuenta

El tiempo para crear la obra de arte, brindar atención al cliente y mantener las cosas actualizadas fue demasiado abrumador como un estudio de un solo hombre además de su trabajo de tiempo completo. En 2022, con algunos amigos, nació la idea de un estudio completamente nuevo. Sierra Division fue cofundada por Game and Film Industry Veterans y es el futuro de Top Tier Artwork disponible para el público. La compañía se dedica a crear obras de arte de la más alta calidad y brindar un servicio al cliente acogedor y rápido. Si está buscando más ilustraciones de PurePolygons, puede encontrar a Jacob y sus equipos trabajando en Sierra Division. Gracias a todos por el apoyo a lo largo de los años y la abrumadora positividad para la obra de arte. ¡Esto no es un adiós!

https://linktr.ee/sierradivision

R: Todos los paquetes de PurePolygons actuales permanecerán activos y actualizados a las últimas versiones de Unreal Engine, pero si está buscando nuevas ilustraciones y activos en Marketplace, Jacob (PurePolygons) ahora dedica su tiempo por completo a Sierra Division y al increíble equipo de personas que crean contenido allí. Gracias de nuevo

Todos los ríos son spline generados con un material que aumenta la velocidad del río en función de los ángulos de pendiente de la geo y agrega espuma al agua en la parte superior y la base de cualquier caída de agua. Así que no hay trabajo extra de su parte. ¡Simplemente colóquelo y listo!

 

Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios, web y más.

Suscríbete



Siguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

 

Únete a nuestro Discord

 

Twitter

 

Facebook

 

Instagram

 

Linkedin

 

Pinterest

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

ZoeGeop Technologies
MarketPlace

Crea tu cuenta

Solo se necesita un sueño para crear un nuevo mundo. Unity te ofrece las herramientas necesarias para convertir ese sueño en realidad. Aquí encontrarás muchos consejos para comenzar a crear tu primer videojuego. No importa qué tantas habilidades o experiencia previa tengas: ¡lo importante es que tengas la motivación para crear algo extraordinario! 

Unity es la plataforma de creación de juegos más utilizada del mundo: el 50 % de los juegos móviles se crean con esta plataforma, el 60 % del contenido de realidad aumentada y realidad virtual está impulsado por Unity. Además, el «desarrollador Unity» ocupa el puesto número 7 en la lista de los empleos de más rápido crecimiento, según un informe reciente de LinkedIn sobre nuevos empleos en los Estados Unidos.

Comienza a crear con un microjuego listo para utilizarse en Unity. Cada microjuego incluye su propia colección de mods, los cuales son personalizaciones sencillas y divertidas que también funcionan como introducción al diseño de juegos, la lógica, los elementos visuales y más.

Los nuevos creadores pueden descargar Unity de forma gratuita y comenzar a trabajar con los microjuegos y mods listos para utilizarse en Unity. Aprende con cientos de tutoriales, cursos, términos y kits de juego gratuitos y económicos, creados por Unity y por nuestra fabulosa comunidad.

Códigos para anexar a tu Character First Person utilizados en el video

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!

 

Suscríbete a nuestro canal

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios, web y más.

Suscríbete



Siguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

 

Únete a nuestro Discord

 

Twitter

 

Facebook

 

Instagram

 

Linkedin

 

Pinterest

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

ZoeGeop Technologies
MarketPlace

Crea tu cuenta

 

¡Descarga el juego gratis en nuestra tienda de Google Play Store!

 

Crossy Road ha sido un juego móvil popular para teléfonos inteligentes y tabletas, y sus anuncios de video en el juego están dando sus frutos para el desarrollador Hipster Whale.

Crossy Road se puede descargar y jugar gratis, pero gana dinero con los anuncios de video y también con las compras en la aplicación cuando los jugadores compran personajes, que van desde pingüinos, gatos y cerdos hasta magos y robots. Los personajes también se pueden desbloquear gastando monedas obtenidas al ver los anuncios.

“Queríamos que fuera gratis, para que todos tuvieran la oportunidad de jugar”, dijo Hall, citando otro juego móvil independiente, Disco Zoo, como inspiración.

“Jugué a Disco Zoo y pensé que los anuncios de video eran una forma realmente buena de ganar dinero sin estar en la cara de la gente. Solo necesitábamos encontrar una razón divertida para que los jugadores los vieran”, dijo.

“No queríamos ninguna compra de consumibles, queríamos hacer algo por lo que todos pudieran pagar un poco si quisieran, pero donde no fuera necesario seguir pagando”.

El desarrollador Hipster Whale ve su estrategia publicitaria como «una muy buena manera de ganar dinero sin meterse en las narices de las personas».

Suscríbete a nuestro canal

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios, web y más.

Suscríbete



Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

 

Únete a nuestro Discord

 

Twitter

 

Facebook

 

Instagram

 

Linkedin

 

Pinterest

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

ZoeGeop Technologies
MarketPlace

Crea tu cuenta


¡Hola! Muy buenas a todos y bienvenidos a este video donde les mostraré una revisión de este útil asset pagado en la tienda de Unity. El cual es de gran ayuda a la hora de implementar un juego totalmente funcional y completo para ejecutarlo en un entorno de producción.Está diseñado tanto para no programadores como para los que sí lo son. Espero que lo disfruten y dejen sus comentarios de qué tal les parece.

1. What is Unity?

Unity is a powerful game engine that can be used to develop mobile applications and games. It is popular for its ease of use and allows for cross-platform development, so it can be used to create applications for Android, iOS, Windows, and more. Unity also has a large community that provides support for developers.

2. How does Unity work?

Unity works by allowing you to create 3D worlds and scenes. You can then add objects, animations, and sounds to your scene to create an immersive experience for your players. Unity also supports the development of multiplayer games, which makes it a powerful tool for developing MMOs and other online games.

3. What can I make with Unity?

With Unity, you can create mobile applications and games, as well as desktop applications using the same engine. Some common uses For Unity include creating iPhone and iPad apps, developing 3D games, creating web Applications using HTML5 & CSS3, creating graphics intensive apps like medical imagingapps etc.

¿Quieres publicar tus propios proyectos?¡No esperes más!

ZoeGeop Technologies
MarketPlace

Crea tu cuenta


Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios, web y más.

Suscríbete



Siguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

 

Únete a nuestro Discord

 

Twitter

 

Facebook

 

Instagram

 

Linkedin

 

Pinterest


¡Hola! Bienvenidos a nuestro primer TOP de los mejores assets para crear videojuegos en Unity para el 2019.

Si eres un desarrollador de videojuegos, entonces Unity es el mejor lugar para comenzar. Esta plataforma se ha convertido en la herramienta favorita para los desarrolladores, ya que ofrece un gran número de recursos increíbles para crear juegos de calidad. En este artículo, te presentaremos los 10 mejores assets para crear videojuegos en Unity 2019 y cómo usarlos para aprovechar al máximo esta plataforma.

Unity es el motor de juego multiplataforma más popular del mundo

Es el motor de juego más popular porque ofrece una gran cantidad de funcionalidades a los desarrolladores y permite crear juegos para prácticamente cualquier plataforma. Tiene una gran comunidad de desarrolladores y hay muchos recursos disponibles para ayudarte a crear tus juegos. En esta lista, hemos seleccionado los 10 mejores assets (recursos) para crear videojuegos en Unity 2019.

Ofrece una interfaz de usuario intuitiva y un potente motor de renderizado para crear videojuegos en 2D y 3D

La interfaz de Unity está diseñada para ser intuitiva y fácil de usar, lo que permite a los desarrolladores concentrarse en lo que realmente importa: crear juegos. Unity tiene un potente motor de renderizado en 2D y 3D, que permite crear juegos increíbles con gráficos impactantes.

Los desarrolladores de videojuegos pueden publicar sus juegos en las principales tiendas digitales, como Steam,

Los desarrolladores de videojuegos pueden publicar sus juegos en las principales tiendas digitales, como Steam. Aunque estas tiendas ofrecen servicios para simplificar el proceso de publicación, los desarrolladores deben asegurarse de que sus juegos cumplen con los requisitos técnicos y de calidad de la tienda. Los jugadores pueden comprar y descargar juegos directamente en sus ordenadores o dispositivos móviles.

Suscríbete a nuestro canal de YouTube

Síguenos en nuestro canal de YouTube dedicado a tecnología, marketplace de proyectos tecnológicos, cursos online y tutoriales de desarrollo de videojuegos. Ofrecemos consultoría en desarrollo de software, marketing online, servicios de TI, hosting web, dominios, web y más.

Suscríbete


¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

ZoeGeop Technologies
MarketPlace

Crea tu cuenta


Siguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

 

Únete a nuestro Discord

 

Twitter

 

Facebook

 

Instagram

 

Linkedin

 

Síguenos en Pinterest


Hola bienvenidos a este vídeo donde les mostraremos una revisión de éste útil asset pagado en la tienda de Unity. Beat Em Up Figth ?✊. El cual nos sirve de gran ayuda a la hora de implementar un juego totalmente funcional y completo del tipo figther para ejecutarlo en un entorno de producción. Sin previos conocimientos de programación está diseñado tanto para no programadores como para los que si lo son. Espero que lo disfruten y dejen sus comentarios de que tal les parece.

¿Estás listo para un combate? Los juegos Beat Em Up Fight son entretenimiento de lucha para todos los gustos y edades. ¡Explora esta clase de juegos en este artículo para descubrir la diversión que traen!

Introducción

Los juegos de lucha o «beat ‘em up» han estado presentes desde los primeros días de los videojuegos. Aunque el género ha tenido altibajos, siempre ha logrado mantener un cierto nivel de popularidad. Los juegos de lucha se caracterizan por su combate en tiempo real, en el que los jugadores controlan a un personaje y lo mueven por un escenario para enfrentarse a otros personajes controlled por la CPU o por otros jugadores.

El objetivo principal de los juegos de lucha es derrotar al oponente mediante el uso de puñetazos y patadas, aunque algunos juegos incorporan armas blancas o de fuego. A menudo, los juegos cuentan con un sistema de combate basado en combos, en el que los jugadores pueden realizar una serie de movimientos seguidos para infligir más daño.

Qué es un juego de lucha?

Un juego de lucha, también conocido como «beat ‘em up», es un videojuego en el que el jugador controla a un personaje y lo mueve por un escenario mientras ataca a los enemigos que aparecen. Los juegos de lucha suelen ser de acción y combates cuerpo a cuerpo, aunque algunos incluyen elementos de juegos de plataformas o tiroteos. El objetivo del juego suele ser derrotar a todos los enemigos del nivel, o bien completar una serie de objetivos específicos.

Géneros de juegos de lucha

En los últimos años, los juegos de lucha se han popularizado en todo el mundo. Estos juegos suelen incluir una gran variedad de géneros, desde simuladores realistas hasta juegos de cartas coleccionables. A continuación se presentan algunos de los géneros más populares de los juegos de lucha.

Los simuladores de lucha son probablemente el género más popular entre los aficionados a los juegos de lucha. Estos juegos suelen intentar imitar la experiencia real del combate, ya sea mediante el uso de gráficos realistas o mecánicas complicadas. Los jugadores pueden elegir entre una variedad de ataques y técnicas para derrotar a sus oponentes, lo que hace que estos juegos sean extremadamente competitivos. Algunos ejemplos populares de este género incluyen la serie Tekken y Virtua Fighter.

Los juegossubpunto 2 son un tipo relativamente nuevo de l

Características de los juegos de lucha

Los juegos de lucha son un subgénero de los videojuegos que se caracterizan por el combate cuerpo a cuerpo entre dos o más jugadores. A menudo, los juegos de lucha incluyen una variedad de movimientos especiales y ataques especiales que pueden ser utilizados por los personajes para derrotar a sus oponentes. Los juegos de lucha también suelen incluir un sistema de combate en el que los jugadores deben usar sus habilidades para vencer a sus adversarios.

Cómo se juega un juego de lucha?

Los juegos de lucha, también conocidos como beat em up, son un género de videojuegos en el que el jugador controla a un personaje que tiene que luchar contra un grupo de adversarios. A menudo, los juegos de lucha se caracterizan por su ritmo rápido y sus gráficos llamativos.

Los juegos de lucha suelen incluir una variedad de golpes y movimientos especiales que pueden usar el jugador para derrotar a sus adversarios. Algunos juegos también permiten a los jugadores usar objetos del escenario para golpear a sus enemigos o interactuar con ellos de otras maneras.

A menudo, los juegos de lucha se centran en la historia y los personajes, y muchos incluyen elementos de RPG para permitir al jugador mejorar las habilidades y el equipo del personaje principal a medida que avanza la historia.

Consejos para mejorar en los juegos de lucha

En los juegos de lucha, hay muchas cosas que puedes hacer para mejorar tu rendimiento. Estos son algunos consejos para ayudarte a sacar el máximo provecho de tus sesiones de juego:

-Practica: la mejor manera de mejorar en los juegos de lucha es practicar. Asegúrate de estar jugando con frecuencia y trata de aprender todo lo que puedas acerca del juego. Observa las técnicas de otros jugadores y trata de imitarlas. También puedes encontrar tutoriales online o en videos que te ayuden a mejorar tus habilidades.
-Analiza tus partidas: después de cada partida, analiza cuidadosamente lo que hiciste bien y lo que hiciste mal. Trata de identificar qué fue lo que te hizo ganar o perder cada round. De esta manera, podrás concentrarte en mejorar tus debilidades y reforzar tus puntos fuertes.
-Estudia a tus oponent

Los mejores juegos de lucha

Los mejores juegos de lucha se caracterizan por su intensidad y el desafío que presentan. A menudo, estos juegos involucran a personajes fuertemente animados y ofrecen una experiencia de combate única e intensa. La mayoría de los juegos de lucha se centran en el combate cuerpo a cuerpo, pero también hay juegos que incorporan armas y otros elementos. Aquí están algunos de los mejores juegos de lucha disponibles:

-Injustice: Gods Among Us: Este es uno de los últimos lanzamientos en la categoría de los mejores juegos de lucha. El juego cuenta con personajes populares del Universo DC, como Superman, Batman y Wonder Woman. Ofrece una amplia variedad de modos para mantenerte ocupado, incluyendo batallas multijugador en línea.

-Mortal Kombat X: Mortal Kombat X es el último lanzamiento en la serie Mortal Kombat. El juego se caracteriza por su violencia gráfica y sus

PlayerCombat

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
[RequireComponent (typeof(Rigidbody))]
[RequireComponent (typeof(UnitState))]
public class PlayerCombat : MonoBehaviour, IDamagable<DamageObject> {
	[Header ("Linked Components")]
	public Transform weaponBone; //the bone were weapon will be parented on
	private UnitAnimator animator; //link to the animator component
	private UnitState playerState; //the state of the player
	private Rigidbody rb;
	[Header("Attack Data & Combos")]
	public float hitZRange = 2f; //the z range of attacks
	private int attackNum = -1; //the current attack combo number
	[Space(5)]
	public DamageObject[] PunchCombo; //a list of punch attacks
	public DamageObject[] KickCombo; //a list of kick Attacks
	public DamageObject JumpKickData; //jump kick Attack
	public DamageObject GroundPunchData; //Ground punch Attack
	public DamageObject GroundKickData; //Ground kick Attack
	public DamageObject RunningPunch; //punch attack during the run animation
	public DamageObject RunningKick; //kick attack during the run animation
	private DamageObject lastAttack; //data from the last attack that has taken place
	[Header("Settings")]
	public bool blockAttacksFromBehind = false; //block enemy attacks coming from behind
	public bool comboContinueOnHit = true; //only continue a combo when the previous attack was a hit
	public bool resetComboChainOnChangeCombo; //restart a combo when switching to a different combo chain
	public bool invulnerableDuringJump = false; //check if the player can be hit during a jump
	public float hitRecoveryTime = .4f; //the time it takes to recover from a hit
	public float hitThreshold = .2f; //the time before we can get hit again
	public float hitKnockBackForce = 1.5f; //the knockback force when we get hit
	public float GroundAttackDistance = 1.5f; //the distance from an enemy at which a ground attack can be preformed
	public int knockdownHitCount = 3; //the number of times the player can be hit before being knocked down
	public float KnockdownTimeout = 0; //the time before we stand up after a knockdown
	public float KnockdownUpForce = 5; //the Up force of a knockDown
	public float KnockbackForce = 4; //the horizontal force of a knockDown
	public float KnockdownStandUpTime = .8f; //the time it takes for the stand up animation to finish
	[Header("Audio")]
	public string knockdownVoiceSFX = "";
	public string hitVoiceSFX = "";
	public string deathVoiceSFX = "";
	public string defenceHitSFX = "";
	public string dropSFX = "";
	[Header ("Stats")]
	public DIRECTION currentDirection; //the current direction
	public GameObject itemInRange; //an item that is currently in interactable range
	private Weapon currentWeapon; //the current weapon the player is holding
	private DIRECTION defendDirection; //the direction while defending
	private bool continuePunchCombo; //true if a punch combo needs to continue
	private bool continueKickCombo; //true if the a kick combo needs to  continue
	private float lastAttackTime = 0; //time of the last attack
	[SerializeField]
	private bool targetHit; //true if the last hit has hit a target
	private int hitKnockDownCount = 0; //the number of times the player is hit in a row
	private int hitKnockDownResetTime = 2; //the time before the hitknockdown counter resets
	private float LastHitTime = 0; // the last time when we were hit 
	private bool isDead = false; //true if this player has died
	private int EnemyLayer; // the enemy layer
	private int DestroyableObjectLayer; // the destroyable object layer
	private int EnvironmentLayer; //the environment layer
	private LayerMask HitLayerMask; // a list of all hittable objects
	private bool isGrounded;
	private Vector3 fixedVelocity;
	private bool updateVelocity;
	private string lastAttackInput;
	private DIRECTION lastAttackDirection;
	//a list of states when the player can attack
	private List<UNITSTATE> AttackStates = new List<UNITSTATE> {
		UNITSTATE.IDLE, 
		UNITSTATE.WALK, 
		UNITSTATE.RUN, 
		UNITSTATE.JUMPING, 
		UNITSTATE.PUNCH,
		UNITSTATE.KICK, 
		UNITSTATE.DEFEND,
	};
	//list of states where the player can be hit
	private List<UNITSTATE> HitableStates = new List<UNITSTATE> {
		UNITSTATE.DEFEND,
		UNITSTATE.HIT,
		UNITSTATE.IDLE,
		UNITSTATE.LAND,
		UNITSTATE.PUNCH,
		UNITSTATE.KICK,
		UNITSTATE.THROW,
		UNITSTATE.WALK,
		UNITSTATE.RUN,
		UNITSTATE.GROUNDKICK,
		UNITSTATE.GROUNDPUNCH,
	};
	//list of states where the player can activate defence
	private List<UNITSTATE> DefendStates = new List<UNITSTATE> {
		UNITSTATE.IDLE,
		UNITSTATE.DEFEND,
		UNITSTATE.WALK,
		UNITSTATE.RUN,
	};
	//a list of states where the player can change direction
	private List<UNITSTATE> MovementStates = new List<UNITSTATE> {
		UNITSTATE.IDLE,
		UNITSTATE.WALK,
		UNITSTATE.RUN,
		UNITSTATE.JUMPING,
		UNITSTATE.JUMPKICK,
		UNITSTATE.LAND,
		UNITSTATE.DEFEND,
	};
	//---
	void OnEnable(){
		InputManager.onInputEvent += OnInputEvent;
		InputManager.onDirectionInputEvent += OnDirectionInputEvent;
	}
	void OnDisable() {
		InputManager.onInputEvent -= OnInputEvent;
		InputManager.onDirectionInputEvent -= OnDirectionInputEvent;
	}
	//awake
	void Start() {
		animator = GetComponentInChildren<UnitAnimator>();
		playerState = GetComponent<UnitState>();
		rb = GetComponent<Rigidbody>();
		//assign layers and layermasks
		EnemyLayer = LayerMask.NameToLayer("Enemy");
		DestroyableObjectLayer = LayerMask.NameToLayer("DestroyableObject");
		EnvironmentLayer = LayerMask.NameToLayer("Environment");
		HitLayerMask = (1 << EnemyLayer) | (1 << DestroyableObjectLayer);
		//display error messages for missing components
		if (!animator) Debug.LogError ("No player animator found inside " + gameObject.name);
		if (!playerState) Debug.LogError ("No playerState component found on " + gameObject.name);
		if (!rb) Debug.LogError ("No rigidbody component found on " + gameObject.name);
		//set invulnerable during jump
		if (!invulnerableDuringJump) {
			HitableStates.Add (UNITSTATE.JUMPING);
			HitableStates.Add (UNITSTATE.JUMPKICK);
		}
	}
	void Update() {
		//the player is colliding with the ground
		if(animator) isGrounded = animator.animator.GetBool("isGrounded");
		//update defence state every frame
		Defend(InputManager.defendKeyDown);
	}
	//physics update
	void FixedUpdate(){
		if (updateVelocity){
			rb.velocity = fixedVelocity;
			updateVelocity = false;
		}
	}
	//late Update
	void LateUpdate(){
		//apply any root motion offsets to parent
		if(animator && animator.GetComponent<Animator>().applyRootMotion && animator.transform.localPosition != Vector3.zero) {
			Vector3 offset = animator.transform.localPosition;
			animator.transform.localPosition = Vector3.zero;
			transform.position += offset * -(int)currentDirection;
		}
	}
	//set velocity in next fixed update
	void SetVelocity(Vector3 velocity){
		fixedVelocity = velocity;
		updateVelocity = true;
	}
	//movement input event
	void OnDirectionInputEvent(Vector2 inputVector, bool doubleTapActive){
		if(!MovementStates.Contains(playerState.currentState)) return;
		int dir = Mathf.RoundToInt(Mathf.Sign((float)-inputVector.x));
		if(Mathf.Abs(inputVector.x)>0) currentDirection = (DIRECTION)dir;
	}
	#region Combat Input Events
	//combat input event
	private void OnInputEvent(string action, BUTTONSTATE buttonState) {
		if (AttackStates.Contains (playerState.currentState) && !isDead) {
			//running punch
			if(action == "Punch" && buttonState == BUTTONSTATE.PRESS && playerState.currentState == UNITSTATE.RUN && isGrounded){
				animator.SetAnimatorBool("Run", false);
				if(RunningPunch.animTrigger.Length>0) doAttack(RunningPunch, UNITSTATE.ATTACK, "Punch");
				return;
			}
			//running kick
			if(action == "Kick" && buttonState == BUTTONSTATE.PRESS && playerState.currentState == UNITSTATE.RUN && isGrounded){
				animator.SetAnimatorBool("Run", false);
				if(RunningKick.animTrigger.Length>0) doAttack(RunningKick, UNITSTATE.ATTACK, "Kick");
				return;
			}
			//pick up an item
			if (action == "Punch" && buttonState == BUTTONSTATE.PRESS && itemInRange != null && isGrounded && currentWeapon == null) {
				interactWithItem();
				return;
			}
			//use an weapon
			if (action == "Punch" && buttonState == BUTTONSTATE.PRESS && isGrounded && currentWeapon != null) {
				useCurrentWeapon();
				return;
			}
			//ground punch
			if (action == "Punch" && buttonState == BUTTONSTATE.PRESS && (playerState.currentState != UNITSTATE.PUNCH && NearbyEnemyDown()) && isGrounded) {
				if(GroundPunchData.animTrigger.Length > 0) doAttack(GroundPunchData, UNITSTATE.GROUNDPUNCH, "Punch");
				return;
			}
			//ground kick
			if (action == "Kick" && buttonState == BUTTONSTATE.PRESS && (playerState.currentState != UNITSTATE.KICK && NearbyEnemyDown()) && isGrounded) {
				if(GroundKickData.animTrigger.Length > 0) doAttack(GroundKickData, UNITSTATE.GROUNDKICK, "Kick");
				return;
			}
			//reset combo when switching to another combo chain (user setting)
			if (resetComboChainOnChangeCombo && (action != lastAttackInput)){
				attackNum = -1;
			}
			//default punch
			if (action == "Punch" && buttonState == BUTTONSTATE.PRESS && playerState.currentState != UNITSTATE.PUNCH && playerState.currentState != UNITSTATE.KICK && isGrounded) {
				//continue to the next attack if the time is inside the combo window
				bool insideComboWindow = (lastAttack != null && (Time.time < (lastAttackTime + lastAttack.duration + lastAttack.comboResetTime)));
				if (insideComboWindow && !continuePunchCombo && (attackNum < PunchCombo.Length -1)) {
					attackNum += 1;
				} else {
					attackNum = 0;
				}
				if(PunchCombo[attackNum] != null && PunchCombo[attackNum].animTrigger.Length > 0) doAttack(PunchCombo[attackNum], UNITSTATE.PUNCH, "Punch");
				return;
			}
			//advance the punch combo if "punch" was pressed during a punch attack
			if (action == "Punch" && buttonState == BUTTONSTATE.PRESS && (playerState.currentState == UNITSTATE.PUNCH) && !continuePunchCombo && isGrounded) {
				if (attackNum < PunchCombo.Length - 1){
					continuePunchCombo = true;
					continueKickCombo = false;
					return;
				}
			}
			//jump punch
			if (action == "Punch" && buttonState == BUTTONSTATE.PRESS && !isGrounded) {
				if(JumpKickData.animTrigger.Length > 0) {	
					doAttack(JumpKickData, UNITSTATE.JUMPKICK, "Kick");
					StartCoroutine(JumpKickInProgress());
				}
				return;
			}
			//jump kick
			if (action == "Kick" && buttonState == BUTTONSTATE.PRESS && !isGrounded) {
				if(JumpKickData.animTrigger.Length > 0) {
					doAttack(JumpKickData, UNITSTATE.JUMPKICK, "Kick");
					StartCoroutine(JumpKickInProgress());
				}
				return;
			}
			//default kick
			if (action == "Kick" && buttonState == BUTTONSTATE.PRESS && playerState.currentState != UNITSTATE.KICK && playerState.currentState != UNITSTATE.PUNCH && isGrounded) {
				//continue to the next attack if the time is inside the combo window
				bool insideComboWindow = (lastAttack != null && (Time.time < (lastAttackTime + lastAttack.duration + lastAttack.comboResetTime)));
				if (insideComboWindow && !continueKickCombo && (attackNum < KickCombo.Length -1)) {
					attackNum += 1;
				} else {
					attackNum = 0;
				}
				doAttack(KickCombo[attackNum], UNITSTATE.KICK, "Kick");
				return;
			}
			//advance the kick combo if "kick" was pressed during a kick attack
			if (action == "Kick" && buttonState == BUTTONSTATE.PRESS && (playerState.currentState == UNITSTATE.KICK) && !continueKickCombo && isGrounded) {
				if (attackNum < KickCombo.Length - 1){
					continueKickCombo = true;
					continuePunchCombo = false;
					return;
				}
			}
		}
	}
	#endregion
	#region Combat functions
	private void doAttack(DamageObject damageObject, UNITSTATE state, string inputAction){
		animator.SetAnimatorTrigger(damageObject.animTrigger);
		playerState.SetState(state);
		//save attack data
		lastAttack = damageObject;
		lastAttack.inflictor = gameObject;
		lastAttackTime = Time.time;
		lastAttackInput = inputAction;
		lastAttackDirection = currentDirection;
		//turn towards current input direction
		TurnToDir(currentDirection);
		if(isGrounded) SetVelocity(Vector3.zero);
		if(damageObject.forwardForce>0) animator.AddForce(damageObject.forwardForce);
		if(state == UNITSTATE.JUMPKICK)	return;
		Invoke ("Ready", damageObject.duration);
	}
	//use the currently equipped weapon
	void useCurrentWeapon(){
		playerState.SetState (UNITSTATE.USEWEAPON);
		TurnToDir(currentDirection);
		SetVelocity(Vector3.zero);
		//save attack data
		lastAttackInput = "WeaponAttack";
		lastAttackTime = Time.time;
		lastAttack = currentWeapon.damageObject;
		lastAttack.inflictor = gameObject;
		lastAttackDirection = currentDirection;
		if(!string.IsNullOrEmpty(currentWeapon.damageObject.animTrigger)) animator.SetAnimatorTrigger(currentWeapon.damageObject.animTrigger);
		if(!string.IsNullOrEmpty(currentWeapon.useSound)) GlobalAudioPlayer.PlaySFX(currentWeapon.useSound);
		Invoke ("Ready", currentWeapon.damageObject.duration);
		//weapon degeneration
		if(currentWeapon.degenerateType == DEGENERATETYPE.DEGENERATEONUSE) currentWeapon.useWeapon();
		if(currentWeapon.degenerateType == DEGENERATETYPE.DEGENERATEONUSE && currentWeapon.timesToUse == 0) StartCoroutine(destroyCurrentWeapon(currentWeapon.damageObject.duration));
		if(currentWeapon.degenerateType == DEGENERATETYPE.DEGENERATEONHIT && currentWeapon.timesToUse == 1) StartCoroutine(destroyCurrentWeapon(currentWeapon.damageObject.duration));
	}
	//remove the current weapon
	IEnumerator destroyCurrentWeapon(float delay){
		yield return new WaitForSeconds(delay);
		if(currentWeapon.degenerateType == DEGENERATETYPE.DEGENERATEONUSE) GlobalAudioPlayer.PlaySFX(currentWeapon.breakSound);
		Destroy(currentWeapon.playerHandPrefab);
		currentWeapon.BreakWeapon();
		currentWeapon = null;
	}
	//returns the current weapon
	public Weapon GetCurrentWeapon(){
		return currentWeapon;
	}
	//jump kick in progress
	IEnumerator JumpKickInProgress(){
		animator.SetAnimatorBool ("JumpKickActive", true);
		//a list of enemies that we have hit
		List<GameObject> enemieshit = new List<GameObject>();
		//small delay so the animation has time to play
		yield return new WaitForSeconds(.1f);
		//check for hit
		while (playerState.currentState == UNITSTATE.JUMPKICK) {
			//draw a hitbox in front of the character to see which objects it collides with
			Vector3 boxPosition = transform.position + (Vector3.up * lastAttack.collHeight) + Vector3.right * ((int)currentDirection * lastAttack.collDistance);
			Vector3 boxSize = new Vector3 (lastAttack.CollSize/2, lastAttack.CollSize/2, hitZRange/2);
			Collider[] hitColliders = Physics.OverlapBox(boxPosition, boxSize, Quaternion.identity, HitLayerMask); 
			//hit an enemy only once by adding it to a list
			foreach (Collider col in hitColliders) {
				if (!enemieshit.Contains (col.gameObject)) { 
					enemieshit.Add(col.gameObject);
					//hit a damagable object
					IDamagable<DamageObject> damagableObject = col.GetComponent(typeof(IDamagable<DamageObject>)) as IDamagable<DamageObject>;
					if (damagableObject != null) {
						damagableObject.Hit(lastAttack);
						//camera Shake
						CamShake camShake = Camera.main.GetComponent<CamShake> ();
						if (camShake != null) camShake.Shake (.1f);
					}
				}
			}
			yield return null;
		}
	}
	//set defence on/off
	private void Defend(bool defend){
		if(!DefendStates.Contains(playerState.currentState)) return;
		animator.SetAnimatorBool("Defend", defend);
		if (defend) {
			TurnToDir(currentDirection);
			SetVelocity(Vector3.zero);
			playerState.SetState (UNITSTATE.DEFEND);
			animator.SetAnimatorBool("Run", false); //disable running
		} else{
			if(playerState.currentState == UNITSTATE.DEFEND) playerState.SetState(UNITSTATE.IDLE);
		}
	}
	#endregion
	#region Check For Hit
	//check if we have hit something (Animation Event)
	public void CheckForHit() {
		//draw a hitbox in front of the character to see which objects it collides with
		Vector3 boxPosition = transform.position + (Vector3.up * lastAttack.collHeight) + Vector3.right * ((int)lastAttackDirection * lastAttack.collDistance);
		Vector3 boxSize = new Vector3 (lastAttack.CollSize/2, lastAttack.CollSize/2, hitZRange/2);
		Collider[] hitColliders = Physics.OverlapBox(boxPosition, boxSize, Quaternion.identity, HitLayerMask); 
		int i=0;
		while (i < hitColliders.Length) {
			//hit a damagable object
			IDamagable<DamageObject> damagableObject = hitColliders[i].GetComponent(typeof(IDamagable<DamageObject>)) as IDamagable<DamageObject>;
			if (damagableObject != null) {
				damagableObject.Hit(lastAttack);
				//we have hit something
				targetHit = true;
			}
			i++;
		}
		//nothing was hit
		if(hitColliders.Length == 0) targetHit = false;
		//on weapon hit
		if(lastAttackInput == "WeaponAttack" && targetHit) currentWeapon.onHitSomething();
	}
	//Display hit box in Unity Editor (Debug)
	#if UNITY_EDITOR 
	void OnDrawGizmos(){
		if (lastAttack != null && (Time.time - lastAttackTime) < lastAttack.duration) {
			Gizmos.color = Color.red;
			Vector3 boxPosition = transform.position + (Vector3.up * lastAttack.collHeight) + Vector3.right * ((int)lastAttackDirection * lastAttack.collDistance);
			Vector3 boxSize = new Vector3 (lastAttack.CollSize, lastAttack.CollSize, hitZRange);
			Gizmos.DrawWireCube (boxPosition, boxSize);
		}
	}
	#endif
	#endregion
	#region We Are Hit
	//we are hit
	public void Hit(DamageObject d) {
		//check if we can get hit again
		if(Time.time < LastHitTime + hitThreshold) return;
		//check if we are in a hittable state
		if (HitableStates.Contains (playerState.currentState)) {
			CancelInvoke();
			//camera Shake
			CamShake camShake = Camera.main.GetComponent<CamShake>();
			if (camShake != null) camShake.Shake(.1f);
			//defend incoming attack
			if(playerState.currentState == UNITSTATE.DEFEND && !d.DefenceOverride && (isFacingTarget(d.inflictor) || blockAttacksFromBehind)) {
				Defend(d);
				return;
			} else {
				animator.SetAnimatorBool("Defend", false);	
			}
			//we are hit
			UpdateHitCounter ();
			LastHitTime = Time.time;
			//show hit effect
			animator.ShowHitEffect ();
			//substract health
			HealthSystem healthSystem = GetComponent<HealthSystem>();
			if (healthSystem != null) {
				healthSystem.SubstractHealth (d.damage);
				if (healthSystem.CurrentHp == 0)
					return;
			}
			//check for knockdown
			if ((hitKnockDownCount >= knockdownHitCount || !IsGrounded() || d.knockDown) && playerState.currentState != UNITSTATE.KNOCKDOWN) {
				hitKnockDownCount = 0;
				StopCoroutine ("KnockDownSequence");
				StartCoroutine ("KnockDownSequence", d.inflictor);
				GlobalAudioPlayer.PlaySFXAtPosition (d.hitSFX, transform.position + Vector3.up);
				GlobalAudioPlayer.PlaySFXAtPosition (knockdownVoiceSFX, transform.position + Vector3.up);
				return;
			}
			//default hit
			int i = Random.Range (1, 3);
			animator.SetAnimatorTrigger ("Hit" + i);
			SetVelocity(Vector3.zero);
			playerState.SetState (UNITSTATE.HIT);
			//add a small force from the impact
			if (isFacingTarget(d.inflictor)) { 
				animator.AddForce (-1.5f);
			} else {
				animator.AddForce (1.5f);
			}
			//SFX
			GlobalAudioPlayer.PlaySFXAtPosition (d.hitSFX, transform.position + Vector3.up);
			GlobalAudioPlayer.PlaySFXAtPosition (hitVoiceSFX, transform.position + Vector3.up);
			Invoke("Ready", hitRecoveryTime);
		}
	}
	//update the hit counter
	void UpdateHitCounter() {
		if (Time.time - LastHitTime < hitKnockDownResetTime) { 
			hitKnockDownCount += 1;
		} else {
			hitKnockDownCount = 1;
		}
		LastHitTime = Time.time;
	}
	//defend an incoming attack
	void Defend(DamageObject d){
		//show defend effect
		animator.ShowDefendEffect();
		//play sfx
		GlobalAudioPlayer.PlaySFXAtPosition (defenceHitSFX, transform.position + Vector3.up);
		//add a small force from the impact
		if (isFacingTarget(d.inflictor)) { 
			animator.AddForce (-hitKnockBackForce);
		} else {
			animator.AddForce (hitKnockBackForce);
		}
	}
	#endregion
	#region Item interaction
	//item in range
	public void ItemInRange(GameObject item){
		itemInRange = item;
	}
	//item out of range
	public void ItemOutOfRange(GameObject item){
		if(itemInRange == item) itemInRange = null;
	}
	//interact with an item in range
	public void interactWithItem(){
		if (itemInRange != null){
			animator.SetAnimatorTrigger ("Pickup");
			playerState.SetState(UNITSTATE.PICKUPITEM);
			SetVelocity(Vector3.zero);
			Invoke ("Ready", .3f);
			Invoke ("pickupItem", .2f);
		}
	}
	//pick up item
	void pickupItem(){
		if(itemInRange != null)	itemInRange.SendMessage("OnPickup", gameObject, SendMessageOptions.DontRequireReceiver);
	}
	//equip current weapon
	public void equipWeapon(Weapon weapon){
		currentWeapon = weapon;
		currentWeapon.damageObject.inflictor = gameObject;
		//add player hand weapon
		if(weapon.playerHandPrefab != null) {
			GameObject PlayerWeapon = GameObject.Instantiate(weapon.playerHandPrefab, weaponBone) as GameObject;
			currentWeapon.playerHandPrefab = PlayerWeapon;
		}
	}
	#endregion
	#region KnockDown Sequence
	//knockDown sequence
	public IEnumerator KnockDownSequence(GameObject inflictor) {
		playerState.SetState (UNITSTATE.KNOCKDOWN);
		animator.StopAllCoroutines();
		yield return new WaitForFixedUpdate();
		//look towards the direction of the incoming attack
		int dir = inflictor.transform.position.x > transform.position.x ? 1 : -1;
		currentDirection = (DIRECTION)dir;
		TurnToDir(currentDirection);
		//update playermovement
		var pm = GetComponent<PlayerMovement>();
		if(pm != null) {
			pm.CancelJump();
			pm.SetDirection(currentDirection);
		}
		//add knockback force
		animator.SetAnimatorTrigger("KnockDown_Up");
		while(IsGrounded()){
			SetVelocity(new Vector3 (KnockbackForce * -dir , KnockdownUpForce, 0));
			yield return new WaitForFixedUpdate();
		}
		//going up...
		while(rb.velocity.y >= 0) yield return new WaitForFixedUpdate();
		//going down
		animator.SetAnimatorTrigger ("KnockDown_Down");
		while(!IsGrounded()) yield return new WaitForFixedUpdate();
		//hit ground
		animator.SetAnimatorTrigger ("KnockDown_End");
		CamShake camShake = Camera.main.GetComponent<CamShake>();
		if (camShake != null) camShake.Shake(.3f);
		animator.ShowDustEffectLand();
		//sfx
		GlobalAudioPlayer.PlaySFXAtPosition(dropSFX, transform.position);
		//ground slide
		float t = 0;
		float speed = 2;
		Vector3 fromVelocity = rb.velocity;
		while (t<1){
			SetVelocity(Vector3.Lerp (new Vector3(fromVelocity.x, rb.velocity.y + Physics.gravity.y * Time.fixedDeltaTime, fromVelocity.z), new Vector3(0, rb.velocity.y, 0), t));
			t += Time.deltaTime * speed;
			yield return null;
		}
		//knockDown Timeout
		SetVelocity(Vector3.zero);
		yield return new WaitForSeconds(KnockdownTimeout);
		//stand up
		animator.SetAnimatorTrigger ("StandUp");
		playerState.currentState = UNITSTATE.STANDUP;
		yield return new WaitForSeconds (KnockdownStandUpTime);
		playerState.currentState = UNITSTATE.IDLE;
	}
	#endregion
	//returns true if the closest enemy is in a knockdowngrounded state
	bool NearbyEnemyDown(){
		float distance = GroundAttackDistance;
		GameObject closestEnemy = null;
		foreach (GameObject enemy in EnemyManager.activeEnemies) {
			//only check enemies in front of us
			if(isFacingTarget(enemy)){
				//find closest enemy
				float dist2enemy = (enemy.transform.position - transform.position).magnitude;
				if (dist2enemy < distance) {
					distance = dist2enemy;
					closestEnemy = enemy;
				}
			}
		}
		if (closestEnemy != null) {
			EnemyAI AI = closestEnemy.GetComponent<EnemyAI>();
			if (AI != null && AI.enemyState == UNITSTATE.KNOCKDOWNGROUNDED) {
				return true;
			}
		}
		return false;
	}
	//the attack is finished and the player is ready for new actions
	public void Ready() {
		//only continue a combo when we have hit something
		if (comboContinueOnHit && !targetHit) {
			continuePunchCombo = continueKickCombo = false;
			lastAttackTime = 0;
		}
		//continue a punch combo
		if (continuePunchCombo) {
			continuePunchCombo = continueKickCombo = false;
			if (attackNum < PunchCombo.Length-1) {
				attackNum += 1;
			} else {
				attackNum = 0;
			}
			if(PunchCombo[attackNum] != null && PunchCombo[attackNum].animTrigger.Length>0) doAttack(PunchCombo[attackNum], UNITSTATE.PUNCH, "Punch");
			return;
		}
		//continue a kick combo
		if (continueKickCombo) {
			continuePunchCombo = continueKickCombo = false;
			if (attackNum < KickCombo.Length-1) {
				attackNum += 1;
			} else {
				attackNum = 0;
			}
			if(KickCombo[attackNum] != null && KickCombo[attackNum].animTrigger.Length>0) doAttack(KickCombo[attackNum], UNITSTATE.KICK, "Kick");
			return;
		}
		playerState.SetState (UNITSTATE.IDLE);
	}
	//returns true is the player is facing a gameobject
	public bool isFacingTarget(GameObject g) {
		return ((g.transform.position.x > transform.position.x && currentDirection == DIRECTION.Left) || (g.transform.position.x < transform.position.x && currentDirection == DIRECTION.Right));
	}
	//returns true if the player is grounded
	public bool IsGrounded(){
		CapsuleCollider c = GetComponent<CapsuleCollider> ();
		float colliderSize = c.bounds.extents.y;
		#if UNITY_EDITOR 
		Debug.DrawRay (transform.position + c.center, Vector3.down * colliderSize, Color.red); 
		#endif
		return Physics.Raycast (transform.position + c.center, Vector3.down, colliderSize + .1f, 1 << EnvironmentLayer );
	}
	//turn towards a direction
	public void TurnToDir(DIRECTION dir) {
		transform.rotation = Quaternion.LookRotation(Vector3.forward * -(int)dir);
	}
	//the player has died
	void Death(){
		if (!isDead){
			isDead = true;
			StopAllCoroutines();
			animator.StopAllCoroutines();
			CancelInvoke();
			SetVelocity(Vector3.zero);
			GlobalAudioPlayer.PlaySFXAtPosition(deathVoiceSFX, transform.position + Vector3.up);
			animator.SetAnimatorBool("Death", true);
			EnemyManager.PlayerHasDied();
			StartCoroutine(ReStartLevel());
		}
	}
	//restart this level
	IEnumerator ReStartLevel(){
		yield return new WaitForSeconds(2);
		float fadeoutTime = 1.3f;
		UIManager UI = GameObject.FindObjectOfType<UIManager>();
		if (UI != null){
			//fade out
			UI.UI_fader.Fade (UIFader.FADE.FadeOut, fadeoutTime, 0);
			yield return new WaitForSeconds (fadeoutTime);
			//show game over screen
			UI.DisableAllScreens();
			UI.ShowMenu("GameOver");
		}
	}
}

PlayerMovement

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(UnitState))]
[RequireComponent(typeof(CapsuleCollider))]
public class PlayerMovement : MonoBehaviour {
	[Header("Linked Components")]
	private UnitAnimator animator;
	private Rigidbody rb;
	private UnitState playerState;
	private CapsuleCollider capsule;
	[Header("Settings")]
	public float walkSpeed = 3f;
	public float runSpeed = 6f;
	public float ZSpeed = 1.5f;
	public float JumpForce = 8f;
	public bool AllowDepthJumping;
	public float AirAcceleration = 3f;
	public float AirMaxSpeed = 3f;
	public float rotationSpeed = 15f;
	public float jumpRotationSpeed = 30f;
	public float lookAheadDistance = .2f;
	public float landRecoveryTime = .1f;
	public float landTime = 0;
	public LayerMask CollisionLayer;
	[Header("Audio")]
	public string jumpUpVoice = "";
	public string jumpLandVoice = "";
	[Header("Stats")]
	public DIRECTION currentDirection;
	public Vector2 inputDirection;
	public bool jumpInProgress;
	private bool isDead = false;
	private bool JumpNextFixedUpdate;
	private float jumpDownwardsForce = .3f;
	//a list of states where movement can take place
	private List<UNITSTATE> MovementStates = new List<UNITSTATE> {
		UNITSTATE.IDLE,
		UNITSTATE.WALK,
		UNITSTATE.RUN,
		UNITSTATE.JUMPING,
		UNITSTATE.JUMPKICK,
		UNITSTATE.LAND,
		UNITSTATE.DEFEND,
	};
	//--
	void OnEnable() {
		InputManager.onInputEvent += OnInputEvent;
		InputManager.onDirectionInputEvent += OnDirectionInputEvent;
	}
	void OnDisable() {
		InputManager.onInputEvent -= OnInputEvent;
		InputManager.onDirectionInputEvent -= OnDirectionInputEvent;
	}
	void Start(){
		//find components
		if(!animator) animator = GetComponentInChildren<UnitAnimator>();
		if(!rb) rb = GetComponent<Rigidbody>();
		if(!playerState) playerState = GetComponent<UnitState>();
		if(!capsule) capsule = GetComponent<CapsuleCollider>();
		//error messages for missing components
		if(!animator) Debug.LogError("No animator found inside " + gameObject.name);
		if(!rb) Debug.LogError("No Rigidbody component found on " + gameObject.name);
		if(!playerState) Debug.LogError("No UnitState component found on " + gameObject.name);
		if(!capsule) Debug.LogError("No Capsule Collider found on " + gameObject.name);
	}
	void FixedUpdate() {
		if(!MovementStates.Contains(playerState.currentState) || isDead) return;
		//defend
		if(playerState.currentState == UNITSTATE.DEFEND){
			TurnToCurrentDirection();
			return;
		}
		//start a jump
		if(JumpNextFixedUpdate){
			Jump();
			return;
		}
		//land after a jump
		if(jumpInProgress && IsGrounded()){
			HasLanded();
			return;
		}
		//A short recovery time after landing
		if(playerState.currentState == UNITSTATE.LAND && Time.time - landTime > landRecoveryTime) playerState.SetState(UNITSTATE.IDLE);
		//air and ground Movement
		bool isGrounded = IsGrounded();
		animator.SetAnimatorBool("isGrounded", isGrounded);
		if(isGrounded) animator.SetAnimatorBool("Falling", false);
		if(isGrounded){
			MoveGrounded();
		} else {
			MoveAirborne();
		}
		//always turn towards the current direction
		TurnToCurrentDirection();
	}
	//movement on the ground
	void MoveGrounded(){
		//do nothing when landing
		if(playerState.currentState == UNITSTATE.LAND) return;
		//move when there is no wall in front of us and input is detected
		if(rb != null && (inputDirection.sqrMagnitude>0 && !WallInFront())) {
			//set movement speed to run speed or walk speed depending on the current state
			float movementSpeed = playerState.currentState == UNITSTATE.RUN? runSpeed : walkSpeed;
			rb.velocity = new Vector3( inputDirection.x * -movementSpeed, rb.velocity.y + Physics.gravity.y * Time.fixedDeltaTime, inputDirection.y * -ZSpeed);
			if(animator) animator.SetAnimatorFloat("MovementSpeed", rb.velocity.magnitude);
		} else {
			//stop moving, but still apply gravity
			rb.velocity = new Vector3(0, rb.velocity.y + Physics.gravity.y * Time.fixedDeltaTime, 0);
			if(animator) animator.SetAnimatorFloat("MovementSpeed", 0);
			playerState.SetState(UNITSTATE.IDLE);
		}
		//sets the run state in the animator to true or false
		animator.SetAnimatorBool("Run", playerState.currentState == UNITSTATE.RUN);
	}
	//movement in the air
	void MoveAirborne(){
		//falling down
		if(rb.velocity.y < 0.1f && playerState.currentState != UNITSTATE.KNOCKDOWN)	animator.SetAnimatorBool("Falling", true);
		if(!WallInFront()) {
			//movement direction based on current input
			int dir = Mathf.Clamp(Mathf.RoundToInt(-inputDirection.x), -1, 1);
			float xpeed = Mathf.Clamp(rb.velocity.x + AirMaxSpeed * dir * Time.fixedDeltaTime * AirAcceleration, -AirMaxSpeed, AirMaxSpeed);
			float downForce = rb.velocity.y>0? 0 : jumpDownwardsForce; //adds a small downwards force when going down 
			//apply movement
			if(AllowDepthJumping) {
				rb.velocity = new Vector3(xpeed, rb.velocity.y - downForce, -inputDirection.y * ZSpeed);
			} else {
				rb.velocity = new Vector3(xpeed, rb.velocity.y - downForce, 0);
			}
		}
	}
	//perform a jump
	void Jump(){
		playerState.SetState(UNITSTATE.JUMPING);
		JumpNextFixedUpdate = false;
		jumpInProgress = true;
		rb.velocity = Vector3.up * JumpForce;
		//play animation
		animator.SetAnimatorBool("JumpInProgress", true);
		animator.SetAnimatorBool("Run", false);
		animator.SetAnimatorTrigger("JumpUp");
		animator.ShowDustEffectJump();
		//play sfx
		if(jumpUpVoice != "") GlobalAudioPlayer.PlaySFXAtPosition(jumpUpVoice, transform.position);
	}
	//player has landed after a jump
	void HasLanded(){
		jumpInProgress = false;
		playerState.SetState(UNITSTATE.LAND);
		rb.velocity = Vector2.zero;
		landTime = Time.time;
		//set animator properties
		animator.SetAnimatorFloat("MovementSpeed", 0f);
		animator.SetAnimatorBool("JumpInProgress", false);
		animator.SetAnimatorBool("JumpKickActive", false);
		animator.SetAnimatorBool("Falling", false);
		animator.ShowDustEffectLand();
		//sfx
		GlobalAudioPlayer.PlaySFX("FootStep");
		if(jumpLandVoice != "") GlobalAudioPlayer.PlaySFXAtPosition(jumpLandVoice, transform.position);
	}
	#region controller input
	//set current direction to input direction
	void OnDirectionInputEvent(Vector2 dir, bool doubleTapActive) {
		//ignore input when we are dead or when this state is not active
		if(!MovementStates.Contains(playerState.currentState) || isDead) return;
		//set current direction based on the input vector. Mathf.sign is used because we want the player to stay in the left or right direction when moving up/down)
		int dir2 = Mathf.RoundToInt(Mathf.Sign((float)-inputDirection.x));
		if(Mathf.Abs(inputDirection.x) > 0) SetDirection((DIRECTION)dir2);
		inputDirection = dir;
		//start running on double tap
		if(doubleTapActive && IsGrounded() && Mathf.Abs(dir.x)>0) playerState.SetState(UNITSTATE.RUN);
	}
	//input actions
	void OnInputEvent(string action, BUTTONSTATE buttonState) {
		//ignore input when we are dead or when this state is not active
		if(!MovementStates.Contains(playerState.currentState) || isDead) return;
		//start a jump
		if(action == "Jump" && buttonState == BUTTONSTATE.PRESS && IsGrounded() && playerState.currentState != UNITSTATE.JUMPING) JumpNextFixedUpdate = true;
		//start running when a run button is pressed (e.g. Joypad controls)
		if(action == "Run") playerState.SetState(UNITSTATE.RUN);
	}
	#endregion
	//interrups an ongoing jump
	public void CancelJump(){
		jumpInProgress = false;
	}
	//set current direction
	public void SetDirection(DIRECTION dir) {
		currentDirection = dir;
		if(animator) animator.currentDirection = currentDirection;
	}
	//returns the current direction
	public DIRECTION getCurrentDirection() {
		return currentDirection;
	}
	//returns true if the player is grounded
	public bool IsGrounded() {
		//check for capsule collisions with a 0.1 downwards offset from the capsule collider
		Vector3 bottomCapsulePos = transform.position + (Vector3.up) * (capsule.radius - 0.1f);
		return Physics.CheckCapsule(transform.position + capsule.center, bottomCapsulePos, capsule.radius, CollisionLayer);
	}
	//look (and turns) towards a direction
	public void TurnToCurrentDirection() {
		if(currentDirection == DIRECTION.Right || currentDirection == DIRECTION.Left) {
			float turnSpeed = jumpInProgress? jumpRotationSpeed : rotationSpeed;
			Vector3 newDir = Vector3.RotateTowards(transform.forward, Vector3.forward * -(int)currentDirection, turnSpeed * Time.fixedDeltaTime, 0.0f);
			transform.rotation = Quaternion.LookRotation(newDir);
		}
	}
	//update the direction based on the current input
	public void updateDirection() {
		TurnToCurrentDirection();
	}
	//the player has died
	void Death() {
		isDead = true;
		rb.velocity = Vector3.zero;
	}
	//returns true if there is a environment collider in front of us
	bool WallInFront() {
		var MovementOffset = new Vector3(inputDirection.x, 0, inputDirection.y) * lookAheadDistance;
		var c = GetComponent<CapsuleCollider>();
		Collider[] hitColliders = Physics.OverlapSphere(transform.position + Vector3.up * (c.radius + .1f) + -MovementOffset, c.radius, CollisionLayer);
		int i = 0;
		bool hasHitwall = false;
		while(i < hitColliders.Length) {
			if(CollisionLayer == (CollisionLayer | 1 << hitColliders[i].gameObject.layer)) hasHitwall = true;
			i++;
		}
		return hasHitwall;
	}
	//draw a lookahead sphere in the unity editor
	#if UNITY_EDITOR
	void OnDrawGizmos() {
		var c = GetComponent<CapsuleCollider>();
		Gizmos.color = Color.yellow;
		Vector3 MovementOffset = new Vector3(inputDirection.x, 0, inputDirection.y) * lookAheadDistance;
		Gizmos.DrawWireSphere(transform.position + Vector3.up * (c.radius + .1f) + -MovementOffset, c.radius);
	}
	#endif
}
public enum DIRECTION {
	Right = -1,
	Left = 1,
	Up = 2,
	Down = -2,
};

EnemyAI

using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
    private PhotonView PV;
    private CharacterController myCC;
    public float movementSpeed;
    public float rotationSpeed;
    // Start is called before the first frame update
    void Start()
    {
        PV = GetComponent<PhotonView>();
        myCC = GetComponent<CharacterController>();
    }
    // Update is called once per frame
    void Update()
    {
        if(PV.IsMine && PhotonNetwork.IsConnected)
        {
            BasicMovement();
            BasicRotation();
        }
    }
    void BasicMovement()
    {
        if(Input.GetKey(KeyCode.W))
        {
            myCC.Move(transform.forward * Time.deltaTime * movementSpeed);
        }
        if (Input.GetKey(KeyCode.A))
        {
            myCC.Move(-transform.right * Time.deltaTime * movementSpeed);
        }
        if (Input.GetKey(KeyCode.S))
        {
            myCC.Move(-transform.forward * Time.deltaTime * movementSpeed);
        }
        if (Input.GetKey(KeyCode.D))
        {
            myCC.Move(transform.right * Time.deltaTime * movementSpeed);
        }
    }
    void BasicRotation()
    {
        float mouseX = Input.GetAxis("Mouse X") * Time.deltaTime * rotationSpeed;
        transform.Rotate(new Vector3(0, mouseX, 0));
    }
}using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyAI : EnemyActions, IDamagable<DamageObject>{
	[Space(10)]
	public bool enableAI;
	//a list of states where the AI is executed
	private List<UNITSTATE> ActiveAIStates = new List<UNITSTATE> { 
		UNITSTATE.IDLE, 
		UNITSTATE.WALK 
	};
	void Start(){
		//add this enemy to the enemylist
		EnemyManager.enemyList.Add(gameObject);
		//set z spread (zspread is used to keep space between the enemies)
		ZSpread = (EnemyManager.enemyList.Count-1);
		Invoke ("SetZSpread", .1f);	
		//randomize values to avoid synchronous movement
		if(randomizeValues) SetRandomValues();
		OnStart();
	}
	void FixedUpdate(){
		OnFixedUpdate();
	}
	void LateUpdate(){
		OnLateUpdate();
	}
	void Update(){
		//do nothing when there is no target or when AI is disabled
		if (target == null || !enableAI) {
			Ready ();
			return;
		} else {
			//get range to target
			range = GetDistanceToTarget ();
		}
		if(!isDead && enableAI){
			if(ActiveAIStates.Contains(enemyState) && targetSpotted) {
				//AI active 
				AI();
			} else {
				//try to spot the player
				if(distanceToTarget.magnitude < sightDistance) targetSpotted = true;
			}
		}
	}
	void AI(){
		LookAtTarget(target.transform);
		if (range == RANGE.ATTACKRANGE){
			//attack the target
			if (!cliffSpotted){
				if (Time.time - lastAttackTime > attackInterval) {
					ATTACK();
				} else {
					Ready();
				}
				return;
			}
			//actions for ATTACKRANGE distance
			if (enemyTactic == ENEMYTACTIC.KEEPCLOSEDISTANCE) WalkTo(closeRangeDistance, 0f);
			if (enemyTactic == ENEMYTACTIC.KEEPMEDIUMDISTANCE) WalkTo(midRangeDistance, RangeMarging);
			if (enemyTactic == ENEMYTACTIC.KEEPFARDISTANCE) WalkTo(farRangeDistance, RangeMarging);
			if (enemyTactic == ENEMYTACTIC.STANDSTILL) Ready ();
		} else {
			//actions for CLOSERANGE, MIDRANGE & FARRANGE distances
			if (enemyTactic == ENEMYTACTIC.ENGAGE) WalkTo (attackRangeDistance, 0f);
			if (enemyTactic == ENEMYTACTIC.KEEPCLOSEDISTANCE) WalkTo(closeRangeDistance, RangeMarging);
			if (enemyTactic == ENEMYTACTIC.KEEPMEDIUMDISTANCE) WalkTo(midRangeDistance, RangeMarging);
			if (enemyTactic == ENEMYTACTIC.KEEPFARDISTANCE) WalkTo(farRangeDistance, RangeMarging);
			if (enemyTactic == ENEMYTACTIC.STANDSTILL) Ready();
		}
	}
	//update the current range
	private RANGE GetDistanceToTarget(){
		if (target != null) {
			//get distance from the target
			distanceToTarget = target.transform.position - transform.position;
			distance = Vector3.Distance (target.transform.position, transform.position);
			float distX = Mathf.Abs(distanceToTarget.x);
			float distZ = Mathf.Abs(distanceToTarget.z);
			//AttackRange
			if(distX <= attackRangeDistance){
				if(distZ < (hitZRange/2f)) 
					return RANGE.ATTACKRANGE;
				else
					return RANGE.CLOSERANGE;
			}
			//Close Range
			if (distX > attackRangeDistance && distX < midRangeDistance) return RANGE.CLOSERANGE;
			//Mid range
			if(distX > closeRangeDistance && distance < farRangeDistance) return RANGE.MIDRANGE;
			//Far range
			if(distX > farRangeDistance) return RANGE.FARRANGE;
		}
		return RANGE.FARRANGE;
	}
	//set an enemy tactic
	public void SetEnemyTactic(ENEMYTACTIC tactic){
		enemyTactic = tactic;
	}
	//spread enemies out in z distance
	void SetZSpread(){
		ZSpread = (ZSpread - (float)(EnemyManager.enemyList.Count - 1) / 2f) * (capsule.radius*2) * zSpreadMultiplier;
		if (ZSpread > attackRangeDistance) ZSpread = attackRangeDistance - 0.1f;
	}
	//Unit has died
	void Death(){
		StopAllCoroutines();
		CancelInvoke();
		enableAI = false;
		isDead = true;
		animator.SetAnimatorBool("isDead", true);
		Move(Vector3.zero, 0);
		EnemyManager.RemoveEnemyFromList(gameObject);
		gameObject.layer = LayerMask.NameToLayer ("Default");
		//ground death
		if(enemyState == UNITSTATE.KNOCKDOWNGROUNDED) {
			StartCoroutine(GroundHit());
		} else {
			//normal death
			animator.SetAnimatorTrigger("Death");
		}
		GlobalAudioPlayer.PlaySFXAtPosition("EnemyDeath", transform.position);
		StartCoroutine (animator.FlickerCoroutine(2));
		enemyState = UNITSTATE.DEATH;
		DestroyUnit();
	}
}
public enum ENEMYTACTIC {
	ENGAGE = 0,
	KEEPCLOSEDISTANCE = 1,
	KEEPMEDIUMDISTANCE = 2,
	KEEPFARDISTANCE = 3,
	STANDSTILL = 4,
}
public enum RANGE {
	ATTACKRANGE,
	CLOSERANGE,
	MIDRANGE,
	FARRANGE,
}

EnemyAction

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(CapsuleCollider))]
public class EnemyActions : MonoBehaviour {
	[Space(10)]
	[Header ("Linked components")]
	public GameObject target; //current target
	public UnitAnimator animator; //animator component
	public GameObject GFX; //GFX of this unit
	public Rigidbody rb; //rigidbody component
	public CapsuleCollider capsule; //capsule collider
	[Header("Attack Data")]
	public DamageObject[] AttackList; //a list of attacks
	public bool PickRandomAttack; //choose a random attack from the list
	public float hitZRange = 2; //the z range of all attacks
	public float defendChance = 0; //the chance that an incoming attack is defended %
	public float hitRecoveryTime = .4f; //the timeout after a hit before the enemy can do an action
	public float standUpTime = 1.1f; //the time it takes for this enemy to stand up
	public bool canDefendDuringAttack; //true if the enemy is able to defend an incoming attack while he is doing his own attack
	public bool AttackPlayerAirborne; //attack a player while he is in the air
	private DamageObject lastAttack; //data from the last attack that has taken place
	private int AttackCounter = 0; //current attack number
	public bool canHitEnemies; //true is this enemy can hit other enemies
	public bool canHitDestroyableObjects; //true is this enemy can hit destroyable objects like crates, barrels.
	[HideInInspector]
	public float lastAttackTime; //time of the last attack
	[Header ("Settings")]
	public bool pickARandomName; //assign a random name
	public TextAsset enemyNamesList; //the list of enemy names
	public string enemyName = ""; //the name of this enemy
	public float attackRangeDistance = 1.4f; //the distance from the target where the enemy is able to attack
	public float closeRangeDistance = 2f; //the distance from the target at close range
	public float midRangeDistance = 3f; //the distance from the target at mid range
	public float farRangeDistance = 4.5f; //the distance from the target at far range
	public float RangeMarging = 1f; //the amount of space that is allowed between the player and enemy before we reposition ourselves
	public float walkSpeed = 1.95f; //the speed of a walk
	public float walkBackwardSpeed = 1.2f; //the speed of walking backwards
	public float sightDistance = 10f; //the distance when we can see the target
	public float attackInterval = 1.2f; //the time inbetween attacking
	public float rotationSpeed = 15f; //the rotation speed when switching directions
	public float lookaheadDistance; //the distance at which we check for obstacles in from of us
	public bool ignoreCliffs; //ignore cliff detection
	public float KnockdownTimeout = 0f; //the time before we stand up after a knockdown
	public float KnockdownUpForce = 5f; //the up force of a knockDown
	public float KnockbackForce = 4; //the horizontal force of a knockDown
	private LayerMask HitLayerMask; //the layermask for damagable objects
	public LayerMask CollisionLayer; //the layers we check collisions with
	public bool randomizeValues = true; //randomize values to avoid enemy synchronization
	[HideInInspector]
	public float zSpreadMultiplier = 2f; //multiplyer for the z distance between enemies
	[Header ("Stats")]
	public RANGE range;
	public ENEMYTACTIC enemyTactic;
	public UNITSTATE enemyState;
	public DIRECTION currentDirection; 
	public bool targetSpotted;
	public bool cliffSpotted;
	public bool wallspotted;
	public bool isGrounded;
	public bool isDead;
	private Vector3 moveDirection;
	public float distance;
	private Vector3 fixedVelocity;
	private bool updateVelocity;
	//list of states where the enemy cannot move
	private List<UNITSTATE> NoMovementStates = new List<UNITSTATE> {
		UNITSTATE.DEATH,
		UNITSTATE.ATTACK,
		UNITSTATE.DEFEND,
		UNITSTATE.GROUNDHIT,
		UNITSTATE.HIT,
		UNITSTATE.IDLE,
		UNITSTATE.KNOCKDOWNGROUNDED,
		UNITSTATE.STANDUP,
	};
	//list of states where the player can be hit
	private List<UNITSTATE> HitableStates = new List<UNITSTATE> {
		UNITSTATE.ATTACK,
		UNITSTATE.DEFEND,
		UNITSTATE.HIT,
		UNITSTATE.IDLE,
		UNITSTATE.KICK,
		UNITSTATE.PUNCH,
		UNITSTATE.STANDUP,
		UNITSTATE.WALK,
		UNITSTATE.KNOCKDOWNGROUNDED,
	};
	[HideInInspector]
	public float ZSpread; //the distance between enemies on the z-axis
	//[HideInInspector]
	public Vector3 distanceToTarget;
	private List<UNITSTATE> defendableStates = new List<UNITSTATE> { UNITSTATE.IDLE, UNITSTATE.WALK, UNITSTATE.DEFEND }; //a list of states where the enemy is able to defend an incoming attack
	//global event handler for enemies
	public delegate void UnitEventHandler(GameObject Unit);
	//global event Handler for destroying units
	public static event UnitEventHandler OnUnitDestroy;
	//---
	public void OnStart(){
		//assign a name to this enemy
		if(pickARandomName) enemyName = GetRandomName();
		//set player as target
		if(target == null) target = GameObject.FindGameObjectWithTag("Player");
		//tell enemymanager to update the list of active enemies
		EnemyManager.getActiveEnemies();
		//enable defending during an attack
		if (canDefendDuringAttack) defendableStates.Add (UNITSTATE.ATTACK);
		//set up HitLayerMask
		HitLayerMask = 1 << LayerMask.NameToLayer("Player");
		if(canHitEnemies)HitLayerMask |= (1 << LayerMask.NameToLayer("Enemy"));
		if(canHitDestroyableObjects)HitLayerMask |= (1 << LayerMask.NameToLayer("DestroyableObject"));
	}
	#region Update
	//late Update
	public void OnLateUpdate(){
		//apply any root motion offsets to parent
		if(animator && animator.GetComponent<Animator>().applyRootMotion && animator.transform.localPosition != Vector3.zero) {
			Vector3 offset = animator.transform.localPosition;
			animator.transform.localPosition = Vector3.zero;
			transform.position += offset * (int)currentDirection;
		}
	}
	//physics update
	public void OnFixedUpdate() {
		if(updateVelocity) {
			rb.velocity = fixedVelocity;
			updateVelocity = false;
		}
	}
	//set velocity on next fixed update
	void SetVelocity(Vector3 velocity) {
		fixedVelocity = velocity;
		updateVelocity = true;
	}
	#endregion
	#region Attack
	//Attack
	public void ATTACK() {
		//don't attack when player is jumping
		var playerMovement = target.GetComponent<PlayerMovement>();
		if (!AttackPlayerAirborne && playerMovement != null && playerMovement.jumpInProgress) {
			return;
		} else {
			//init
			enemyState = UNITSTATE.ATTACK;
			Move(Vector3.zero, 0f);
			LookAtTarget(target.transform);
			TurnToDir(currentDirection);
			//pick random attack
			if (PickRandomAttack) AttackCounter = Random.Range (0, AttackList.Length);
			//play animation
			animator.SetAnimatorTrigger (AttackList[AttackCounter].animTrigger);
			//go to the next attack in the list
			if (!PickRandomAttack) {
				AttackCounter += 1;
				if (AttackCounter >= AttackList.Length) AttackCounter = 0;
			}
			lastAttackTime = Time.time;
			lastAttack = AttackList [AttackCounter];
			lastAttack.inflictor = gameObject;
			//resume
			Invoke ("Ready", AttackList [AttackCounter].duration);
		}
	}
	#endregion
	#region We are Hit
	//Unit was hit
	public void Hit(DamageObject d){
		if(HitableStates.Contains(enemyState)) {
			//only allow ground attacks to hit us when we are knocked down
			if(enemyState == UNITSTATE.KNOCKDOWNGROUNDED && !d.isGroundAttack) return;
			CancelInvoke();
			StopAllCoroutines();
			animator.StopAllCoroutines();
			Move(Vector3.zero, 0f);
			//add attack time out so this enemy cannot attack instantly after a hit
			lastAttackTime = Time.time;
			//don't hit this unit when it's allready down
			if((enemyState == UNITSTATE.KNOCKDOWNGROUNDED || enemyState == UNITSTATE.GROUNDHIT) && !d.isGroundAttack)
				return;
			//defend an incoming attack
			if(!d.DefenceOverride && defendableStates.Contains(enemyState)) {
				int rand = Random.Range(0, 100);
				if(rand < defendChance) {
					Defend();
					return;
				}
			}
			//hit sfx
			GlobalAudioPlayer.PlaySFXAtPosition(d.hitSFX, transform.position);
			//hit particle effect
			ShowHitEffectAtPosition(new Vector3(transform.position.x, d.inflictor.transform.position.y + d.collHeight, transform.position.z));
			//camera Shake
			CamShake camShake = Camera.main.GetComponent<CamShake>();
			if(camShake != null)
				camShake.Shake(.1f);
			//activate slow motion camera
			if(d.slowMotionEffect) {
				CamSlowMotionDelay cmd = Camera.main.GetComponent<CamSlowMotionDelay>();
				if(cmd != null)
					cmd.StartSlowMotionDelay(.2f);
			}
			//substract health
			HealthSystem healthSystem = GetComponent<HealthSystem>();
			if(healthSystem != null) {
				healthSystem.SubstractHealth(d.damage);
				if(healthSystem.CurrentHp == 0)
					return;
			}
			//ground attack
			if(enemyState == UNITSTATE.KNOCKDOWNGROUNDED) {
				StopAllCoroutines();
				enemyState = UNITSTATE.GROUNDHIT;
				StartCoroutine(GroundHit());
				return;
			}
			//turn towards the direction of the incoming attack
			int dir = d.inflictor.transform.position.x > transform.position.x? 1 : -1;
			TurnToDir((DIRECTION)dir);
			//check for a knockdown
			if(d.knockDown) {
				StartCoroutine(KnockDownSequence(d.inflictor));
				return;
			} else {
				//default hit
				int rand = Random.Range(1, 3);
				animator.SetAnimatorTrigger("Hit" + rand);
				enemyState = UNITSTATE.HIT;
				//add small force from the impact
				LookAtTarget(d.inflictor.transform);
				animator.AddForce(-KnockbackForce);
				//switch  enemy state from passive to aggressive when attacked
				if(enemyTactic != ENEMYTACTIC.ENGAGE) {
					EnemyManager.setAgressive(gameObject);
				}
				Invoke("Ready", hitRecoveryTime);
				return;
			}
		}
	}
	//Defend
	void Defend(){
		enemyState = UNITSTATE.DEFEND;
		animator.ShowDefendEffect();
		animator.SetAnimatorTrigger ("Defend");
		GlobalAudioPlayer.PlaySFX ("DefendHit");
		animator.SetDirection (currentDirection);
	}
	#endregion
	#region Check for hit
	//checks if we have hit something (Animation Event)
	public void CheckForHit() {
		//draws a hitbox in front of the character to see which objects are overlapping it
		Vector3 boxPosition = transform.position + (Vector3.up * lastAttack.collHeight) + Vector3.right * ((int)currentDirection * lastAttack.collDistance);
		Vector3 boxSize = new Vector3 (lastAttack.CollSize/2, lastAttack.CollSize/2, hitZRange/2);
		Collider[] hitColliders = Physics.OverlapBox(boxPosition, boxSize, Quaternion.identity, HitLayerMask); 
		int i=0;
		while (i < hitColliders.Length) {
			//hit a damagable object
			IDamagable<DamageObject> damagableObject = hitColliders[i].GetComponent(typeof(IDamagable<DamageObject>)) as IDamagable<DamageObject>;
			if (damagableObject != null && damagableObject != (IDamagable<DamageObject>)this) {
				damagableObject.Hit(lastAttack);
			}
			i++;
		}
	}
	//Display hit box + lookahead sphere in Unity Editor (Debug)
	#if UNITY_EDITOR 
	void OnDrawGizmos(){
		//visualize hitbox
		if (lastAttack != null && (Time.time - lastAttackTime) < lastAttack.duration) {
			Gizmos.color = Color.red;
			Vector3 boxPosition = transform.position + (Vector3.up * lastAttack.collHeight) + Vector3.right * ((int)currentDirection * lastAttack.collDistance);
			Vector3 boxSize = new Vector3 (lastAttack.CollSize, lastAttack.CollSize, hitZRange);
			Gizmos.DrawWireCube (boxPosition, boxSize);
		}
		//visualize lookahead sphere
		Gizmos.color = Color.yellow;
		Vector3 offset = -moveDirection.normalized * lookaheadDistance;
		Gizmos.DrawWireSphere (transform.position + capsule.center - offset, capsule.radius); 
	}
	#endif
	#endregion
	#region KnockDown Sequence
	//knockDown sequence
	IEnumerator KnockDownSequence(GameObject inflictor) {
		enemyState = UNITSTATE.KNOCKDOWN;
		yield return new WaitForFixedUpdate();
		//look towards the direction of the incoming attack
		int dir = 1;
		if(inflictor != null) dir = inflictor.transform.position.x > transform.position.x? 1 : -1;
		currentDirection = (DIRECTION)dir;
		animator.SetDirection(currentDirection);
		TurnToDir(currentDirection);
		//add knockback force
		animator.SetAnimatorTrigger("KnockDown_Up");
		while(IsGrounded()){
			SetVelocity(new Vector3(KnockbackForce * -dir, KnockdownUpForce, 0));
			yield return new WaitForFixedUpdate();
		}
		//going up...
		while(rb.velocity.y >= 0) yield return new WaitForFixedUpdate();
		//going down
		animator.SetAnimatorTrigger ("KnockDown_Down");
		while(!IsGrounded()) yield return new WaitForFixedUpdate();
		//hit ground
		animator.SetAnimatorTrigger ("KnockDown_End");
		GlobalAudioPlayer.PlaySFXAtPosition("Drop", transform.position);
		animator.SetAnimatorFloat ("MovementSpeed", 0f);
		animator.ShowDustEffectLand();
		enemyState = UNITSTATE.KNOCKDOWNGROUNDED;
		Move(Vector3.zero, 0f);
		//cam shake
		CamShake camShake = Camera.main.GetComponent<CamShake>();
		if (camShake != null) camShake.Shake(.3f);
		//dust effect
		animator.ShowDustEffectLand();
		//stop sliding
		float t = 0;
		float speed = 2;
		Vector3 fromVelocity = rb.velocity;
		while (t<1){
			SetVelocity(Vector3.Lerp (new Vector3(fromVelocity.x, rb.velocity.y + Physics.gravity.y * Time.fixedDeltaTime, fromVelocity.z), new Vector3(0, rb.velocity.y, 0), t));
			t += Time.deltaTime * speed;
			yield return new WaitForFixedUpdate();
		}
		//knockDown Timeout
		Move(Vector3.zero, 0f);
		yield return new WaitForSeconds(KnockdownTimeout);
		//stand up
		enemyState = UNITSTATE.STANDUP;
		animator.SetAnimatorTrigger ("StandUp");
		Invoke("Ready", standUpTime);
	}
	//ground hit
	public IEnumerator GroundHit(){
		CancelInvoke();
		GlobalAudioPlayer.PlaySFXAtPosition ("EnemyGroundPunchHit", transform.position);
		animator.SetAnimatorTrigger ("GroundHit");
		yield return new WaitForSeconds(KnockdownTimeout);
		if(!isDead)	animator.SetAnimatorTrigger ("StandUp");
		Invoke("Ready", standUpTime);
	}
	#endregion
	#region Movement
	//walk to target
	public void WalkTo(float proximityRange, float movementMargin){
		Vector3 dirToTarget;
		LookAtTarget(target.transform);
		enemyState = UNITSTATE.WALK;
		//clamp zspread to attackDistance when ENGAGED, otherwise we might not be able to reach the player at all
		if (enemyTactic == ENEMYTACTIC.ENGAGE) {
			dirToTarget = target.transform.position - (transform.position + new Vector3 (0, 0, Mathf.Clamp(ZSpread, 0, attackRangeDistance)));
		} else {
			dirToTarget = target.transform.position - (transform.position + new Vector3 (0, 0, ZSpread));
		}
		//we are too far away, move closer
		if (distance >= proximityRange ) {
			moveDirection = new Vector3(dirToTarget.x,0,dirToTarget.z);
			if (IsGrounded() && !WallSpotted() && !PitfallSpotted()) {
				Move(moveDirection.normalized, walkSpeed);
				animator.SetAnimatorFloat ("MovementSpeed", rb.velocity.sqrMagnitude);
				return;
			}
		}
		//we are too close, move away
		if (distance <= proximityRange - movementMargin) {
			moveDirection = new Vector3(-dirToTarget.x,0,0);
			if (IsGrounded() && !WallSpotted() && !PitfallSpotted()) {
				Move(moveDirection.normalized, walkBackwardSpeed);
				animator.SetAnimatorFloat ("MovementSpeed", -rb.velocity.sqrMagnitude);
				return;
			}
		}
		//otherwise do nothing
		Move(Vector3.zero, 0f);
		animator.SetAnimatorFloat ("MovementSpeed", 0);
	}
	//move towards a vector
	public void Move(Vector3 vector, float speed){
		if(!NoMovementStates.Contains(enemyState)) {
			SetVelocity(new Vector3(vector.x * speed, rb.velocity.y + Physics.gravity.y * Time.fixedDeltaTime, vector.z * speed));
		} else {
			SetVelocity(Vector3.zero);
		}
	}
	//returns true if there is an environment collider in front of us
	bool WallSpotted(){
		Vector3 Offset =  moveDirection.normalized * lookaheadDistance;
		Collider[] hitColliders = Physics.OverlapSphere (transform.position + capsule.center + Offset, capsule.radius, CollisionLayer);
		int i = 0;
		bool hasHitwall = false;
		while (i < hitColliders.Length) {
			if(CollisionLayer == (CollisionLayer | 1 << hitColliders[i].gameObject.layer)) {
				hasHitwall = true;
			}
			i++;
		}
		wallspotted = hasHitwall;
		return hasHitwall;
	}
	//returns true if there is a cliff in front of us
	bool PitfallSpotted(){
		if (!ignoreCliffs) {
			float lookDownDistance = 1f;
			Vector3 StartPoint = transform.position + (Vector3.up * .3f) + (Vector3.right * (capsule.radius + lookaheadDistance) * moveDirection.normalized.x);
			RaycastHit hit;
			#if UNITY_EDITOR 
			Debug.DrawRay (StartPoint, Vector3.down * lookDownDistance, Color.red);
			#endif
			if (!Physics.Raycast (StartPoint, Vector3.down, out hit, lookDownDistance, CollisionLayer)) {
				cliffSpotted = true;
				return true;
			}
		}
		cliffSpotted = false;
		return false;
	}
	//returns true if this unit is grounded
	public bool IsGrounded(){
		float colliderSize = capsule.bounds.extents.y - .1f;
		if (Physics.CheckCapsule (capsule.bounds.center, capsule.bounds.center + Vector3.down*colliderSize, capsule.radius, CollisionLayer)) {
			isGrounded = true;
			return true;
		} else {
			isGrounded = false;
			return false;
		}
	}
	//turn towards a direction
	public void TurnToDir(DIRECTION dir) {
		transform.rotation = Quaternion.LookRotation(Vector3.forward * (int)dir);
	}
	#endregion
	//show hit effect
	public void ShowHitEffectAtPosition(Vector3 pos) {
		GameObject.Instantiate (Resources.Load ("HitEffect"), pos, Quaternion.identity);
	}
	//unit is ready for new actions
	public void Ready()	{
		enemyState = UNITSTATE.IDLE;
		animator.SetAnimatorTrigger("Idle");
		animator.SetAnimatorFloat ("MovementSpeed", 0f);
		Move(Vector3.zero, 0f);
	}
	//look at the current target
	public void LookAtTarget(Transform _target){
		if(_target != null){
			Vector3 newDir = Vector3.zero;
			int dir = _target.transform.position.x >= transform.position.x ? 1 : -1;
			currentDirection = (DIRECTION)dir;
			if (animator != null) animator.currentDirection = currentDirection;
			newDir = Vector3.RotateTowards(transform.forward, Vector3.forward * dir, rotationSpeed * Time.deltaTime, 0.0f);	
			transform.rotation = Quaternion.LookRotation(newDir);
		}
	}
	//randomizes values
	public void SetRandomValues(){
		walkSpeed *= Random.Range(.8f, 1.2f);
		walkBackwardSpeed *= Random.Range(.8f, 1.2f);
		attackInterval *= Random.Range(.7f, 1.5f);
		KnockdownTimeout *= Random.Range(.7f, 1.5f);
		KnockdownUpForce *= Random.Range(.8f, 1.2f);
		KnockbackForce *= Random.Range(.7f, 1.5f);
	}
	//destroy event
	public void DestroyUnit(){
		if(OnUnitDestroy != null) OnUnitDestroy(gameObject);
	}
	//returns a random name
	string GetRandomName(){
		if(enemyNamesList == null) {
			Debug.Log("no list of names was found, please create 'EnemyNames.txt' that contains a list of enemy names and put it in the 'Resources' folder.");
			return "";
		}
		//convert the lines of the txt file to an array
		string data = enemyNamesList.ToString();
		string cReturns = System.Environment.NewLine + "n" + "r"; 
		string[] lines = data.Split(cReturns.ToCharArray());
		//pick a random name from the list
		string name = "";
		int cnt = 0;
		while(name.Length == 0 && cnt < 100) {
			int rand = Random.Range(0, lines.Length);
			name = lines[rand];
			cnt += 1;
		}
		return name;
	}
}

¿Quieres acceder al proyecto completo?

¡Registrate y hazte Premium!

  • Si quieres avanzar a un nuevo nivel en tus proyectos tecnológicos con este plan de suscripción no solamente tendrás acceso a los vídeos e información detallada de tutoriales y temas de intereses dentro de ZoeGeop, sino que también dispondrás de acceso exclusivo a materiales, soporte y recursos de nuestros proyectos en curso los cuales iremos actualizando constantemente para que puedas utilizarlos libremente e implementarlos en tus propios proyectos. Contarás además con 3 sesiones de asesoría a tu proyecto por parte del equipo de ZoeGeop al mes.
    Nota: Por cada sesión adicional tendrá un costo adicional.Si quieres avanzar a un nuevo nivel en tus proyectos tecnológicos con este plan de suscripción no solamente tendrás acceso a los vídeos e información detallada de tutoriales y temas de intereses dentro de ZoeGeop, sino que también dispondrás de acceso exclusivo a materiales, soporte y recursos de nuestros proyectos en curso los cuales iremos actualizando constantemente para que puedas utilizarlos libremente e implementarlos en tus propios proyectos. Contarás además con 1 sesión de asesoría a tu proyecto por parte del equipo de ZoeGeop al mes.
    Nota: Por cada sesión adicional tendrá un costo adicional.Si quieres disfrutar y difundir tus proyectos tecnológicos con este plan de suscripción no solamente tendrás acceso a los vídeos e información detallada de tutoriales y temas de interés dentro de ZoeGeop, sino que también podrás dar a conocer tus proyectos en nuestro marketplace global para que cualquier comprador o donante pueden contribuir al crecimiento de tu proyecto.

Processing. Please wait…

 

Suscribete a nuestro canal de Youtube

Siguenos en nuestro canal de Youtube
Síguenos en nuestro canal de Youtube dedicado a Tecnología, MarketPlace de Proyectos Tecnológicos, Cursos Online y Tutoriales de Desarrollo de Videojuegos. Ofrecemos consultoría en Desarrollo de Software, Marketing Online, Servicios de TI, Hosting Web, dominios web entre otros.

Suscribete



Siguenos en Patreon

Si quieres contribuir con cualquier aporte o donación hacia nuestros proyectos y el canal puedes hacerlo a través de nuestra cuenta en Patreon.

 

Únete a nuestro Discord

 

Twitter

 

Facebook

 

Instagram

 

Linkedin

 

Pinterest

¿Quieres publicar tus propios proyectos?. ¡Pues que esperas!

ZoeGeop Technologies
MarketPlace

Crea tu cuenta