{"id":67405,"date":"2025-05-24T07:10:30","date_gmt":"2025-05-24T12:10:30","guid":{"rendered":"https:\/\/niixer.com\/?p=67405"},"modified":"2025-05-31T06:06:13","modified_gmt":"2025-05-31T11:06:13","slug":"desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender","status":"publish","type":"post","link":"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/","title":{"rendered":"Desarrollo de Personajes 3D y Sistema de IA para Videojuegos con Unity y Blender"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Introducci\u00f3n<\/h2>\n\n\n\n<p>Una gu\u00eda para el desarrollo de personajes <a href=\"https:\/\/es.wikipedia.org\/wiki\/Tridimensional\">3D<\/a> animados y la implementaci\u00f3n de sistemas de inteligencia artificial para <a href=\"https:\/\/es.wikipedia.org\/wiki\/Videojuego\">videojuegos<\/a>. El proceso abarca desde la creaci\u00f3n y personalizaci\u00f3n de personajes utilizando las plataformas Mixamo y Blender, hasta la programaci\u00f3n de comportamientos de <a href=\"https:\/\/es.wikipedia.org\/wiki\/Inteligencia_artificial\">IA<\/a> avanzados en Unity.<\/p>\n\n\n\n<p>La gu\u00eda detalla el flujo de trabajo completo que incluye la selecci\u00f3n e importaci\u00f3n de modelos 3D desde Mixamo, la personalizaci\u00f3n de personajes mediante el intercambio de cabezas utilizando Facebuilder en Blender, y la configuraci\u00f3n de sistemas de animaci\u00f3n complejos en Unity. Adem\u00e1s, se profundiza en la implementaci\u00f3n de un sistema de IA para enemigos <a href=\"https:\/\/niixer.com\/index.php\/2025\/04\/14\/animacion-de-modelos-3d-en-plataformas\/\">zombie<\/a> que utiliza el sistema de <a href=\"https:\/\/niixer.com\/index.php\/2025\/05\/23\/needle-engine-con-unity-o-blender\/\">navegaci\u00f3n<\/a> NavMesh de Unity, permitiendo comportamientos realistas de persecuci\u00f3n y ataque.<\/p>\n\n\n\n<p>El documento cubre aspectos t\u00e9cnicos esenciales como la configuraci\u00f3n del Animator Controller, la creaci\u00f3n de sistemas de apuntado con IK (Inverse Kinematics), y la soluci\u00f3n de problemas comunes relacionados con la f\u00edsica y navegaci\u00f3n de personajes. Esta gu\u00eda est\u00e1 dirigida a desarrolladores de videojuegos que buscan crear experiencias inmersivas con personajes inteligentes y sistemas de animaci\u00f3n fluidos.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Se realiza selecci\u00f3n de los personajes en la plataforma mixamo<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"975\" height=\"492\" src=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-517.png\" alt=\"mixamo\" class=\"wp-image-67413\" srcset=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-517.png 975w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-517-300x151.png 300w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-517-768x388.png 768w\" sizes=\"auto, (max-width: 975px) 100vw, 975px\" \/><figcaption class=\"wp-element-caption\">Selecci\u00f3n de personaje<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Se procede a importar los personajes en la <a href=\"https:\/\/es.wikipedia.org\/wiki\/Plataforma\">plataforma <\/a>de Blender<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"975\" height=\"604\" src=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-521.png\" alt=\"Blender - carga de personaje\" class=\"wp-image-67421\" srcset=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-521.png 975w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-521-300x186.png 300w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-521-768x476.png 768w\" sizes=\"auto, (max-width: 975px) 100vw, 975px\" \/><figcaption class=\"wp-element-caption\">Importar personaje<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Se realiza la importaci\u00f3n del facebuilder de los personajes<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"975\" height=\"521\" src=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-523.png\" alt=\"Blender - Modificaci\u00f3n de personaje\" class=\"wp-image-67425\" srcset=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-523.png 975w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-523-300x160.png 300w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-523-768x410.png 768w\" sizes=\"auto, (max-width: 975px) 100vw, 975px\" \/><figcaption class=\"wp-element-caption\">Facebuilder<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Se retira la cabeza de los personajes para adaptar la nueva<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"975\" height=\"608\" src=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-525.png\" alt=\"Blender - Actualizaci\u00f3n de personaje\" class=\"wp-image-67428\" srcset=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-525.png 975w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-525-300x187.png 300w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-525-768x479.png 768w\" sizes=\"auto, (max-width: 975px) 100vw, 975px\" \/><figcaption class=\"wp-element-caption\">Cambio de cabeza<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"975\" height=\"590\" src=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-526.png\" alt=\"Blender - Ajuste de personaje\" class=\"wp-image-67429\" srcset=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-526.png 975w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-526-300x182.png 300w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-526-768x465.png 768w\" sizes=\"auto, (max-width: 975px) 100vw, 975px\" \/><figcaption class=\"wp-element-caption\">Ajuste del cambio de cabeza<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Se realiza <a href=\"https:\/\/niixer.com\/index.php\/2022\/02\/18\/responsive-design-una-tecnica-de-adaptacion-para-cualquier-tamano-de-pantalla\/\">adaptaci\u00f3n <\/a>de la nueva cabeza de los personajes en malla de blender<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"975\" height=\"525\" src=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-527.png\" alt=\"Blender - Ajuste de cabeza\" class=\"wp-image-67430\" srcset=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-527.png 975w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-527-300x162.png 300w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-527-768x414.png 768w\" sizes=\"auto, (max-width: 975px) 100vw, 975px\" \/><figcaption class=\"wp-element-caption\">Cambio de cabeza completo<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Para el segundo personaje se realiza el mismo proceso, descargamos el personaje por la <a href=\"https:\/\/niixer.com\/index.php\/2024\/10\/02\/pagina-web-informativa-con-java-y-mysql\/\">pagina <\/a>de Mixamo<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"975\" height=\"575\" src=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-529.png\" alt=\"Blender - Personaje 2\" class=\"wp-image-67432\" srcset=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-529.png 975w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-529-300x177.png 300w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-529-768x453.png 768w\" sizes=\"auto, (max-width: 975px) 100vw, 975px\" \/><figcaption class=\"wp-element-caption\">Importaci\u00f3n de personaje en blender<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Retiramos la cabeza e importamos la cabeza nueva<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"811\" height=\"489\" src=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-530.png\" alt=\"Importaci\u00f3n de cabeza\" class=\"wp-image-67433\" srcset=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-530.png 811w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-530-300x181.png 300w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-530-768x463.png 768w\" sizes=\"auto, (max-width: 811px) 100vw, 811px\" \/><figcaption class=\"wp-element-caption\">Se importa la nueva cabeza<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ajustamos la cabeza a la posici\u00f3n y el tama\u00f1o necesario<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"975\" height=\"556\" src=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-531.png\" alt=\"Ajuste de cabeza\" class=\"wp-image-67434\" srcset=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-531.png 975w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-531-300x171.png 300w, https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-531-768x438.png 768w\" sizes=\"auto, (max-width: 975px) 100vw, 975px\" \/><figcaption class=\"wp-element-caption\">Ajuste de cabeza<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Configuraci\u00f3n del Animator Controller<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXddLdM28dbC3nc5mW80VMHZ_HVlRtoIgxBTc6-x_abMDhaIdZpbxgiyVD78REHsdcKD8sz-aBF4ig6KfIRcFjPgF2mK5N4IuEuXtpdjgzSHWpLr3f5d4wbDJR_DgMiNs1Gng8dgt_D5PdpicSzjkQ?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"Animator controller\"\/><figcaption class=\"wp-element-caption\">Animator Controller<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>1: Abrir el Animator<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Lograr\u00e1 ver el Animator Controller en la ventana Animator<\/li>\n\n\n\n<li>En la ventana de Unity, ve a&nbsp;<a href=\"https:\/\/niixer.com\/index.php\/2020\/11\/02\/editores-de-videos\/\">Window<\/a> &gt; Animation &gt; Animator<\/li>\n\n\n\n<li>Selecciona tu personaje en la <a href=\"https:\/\/niixer.com\/index.php\/2025\/05\/24\/unity\/\">jerarqu\u00eda<\/a><\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfVyouWbaHj6nsNUgOp67idMQYiIeX2bOf4gU4TBvf5xMpapGJ1CP8In0PPmmbJgcjnJrAA7O3hem2fqXyQzkyz_A4go9tYkV9z9sxfxp5DHFE5IbgDn_F_b4imORjwAsex1ATcBjLRhp2NTP_lHDI?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"Animator apertura\"\/><figcaption class=\"wp-element-caption\">Animator<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXdpYESxUAZ4Ms8uW9pnX8hBlYaUbd0oTlHjA5_hSOMmFR95lrqepmRVCXJknltcG3eBFGuA7GVbGy-yirbXX0bMniv0P2wXq6sTEWsvT-X9etzohjqXKVZ2_T9FDJT8Y-_VISNghQ95uEVBk_r8jK8?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"Datos\"\/><figcaption class=\"wp-element-caption\">Tipo de datos<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>2: Crear par\u00e1metros<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>En la pesta\u00f1a &#8220;Parameters&#8221; (esquina superior izquierda), haz clic en el &#8220;+&#8221;<\/li>\n\n\n\n<li>Selecciona &#8220;Bool&#8221; y n\u00f3mbralo &#8220;IsAiming&#8221;<\/li>\n\n\n\n<li>Haz clic nuevamente en &#8220;+&#8221; y selecciona &#8220;Trigger&#8221;, n\u00f3mbralo &#8220;Shoot&#8221;<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>3: Configurar transiciones<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Arrastra tu animaci\u00f3n de idle\/movimiento normal al Animator (normalmente ya est\u00e1)<\/li>\n\n\n\n<li>Arrastra tu animaci\u00f3n de apuntado al <a href=\"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-videojuego-en-realidad-mixta-con-unity-e-inteligencia-artificial\/\">Animator<\/a><\/li>\n\n\n\n<li>Haz clic derecho en la animaci\u00f3n normal &gt; &#8220;Make Transition&#8221; &gt; arrastra a la animaci\u00f3n de apuntado<\/li>\n\n\n\n<li>Selecciona la flecha de transici\u00f3n y en el inspector:\n<ul class=\"wp-block-list\">\n<li>En &#8220;Conditions&#8221; a\u00f1ade &#8220;IsAiming&#8221; = true<\/li>\n\n\n\n<li>Ajusta &#8220;Transition Duration&#8221; a ~0.1 para que sea suave<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>4: Activar IK Pass<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>En el Animator, ve a la pesta\u00f1a &#8220;<a href=\"https:\/\/niixer.com\/index.php\/2025\/05\/23\/a-contrarreloj-supera-el-desafio-del-tiempo-en-3d-plataformas-precision-y-presion\/\">Layers<\/a>&#8220;<\/li>\n\n\n\n<li>Si no existe, crea una nueva capa con el &#8220;+&#8221; y n\u00f3mbrala &#8220;UpperBody&#8221;<\/li>\n\n\n\n<li>Selecciona la capa y marca &#8220;IK Pass&#8221;<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>2. Crear el objeto AimTarget (personajes)<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXd6CFZRDQRlO-AQ-ctOVBWKj7xcnxwNwYaHlke1xsZPWUTAFGA3ziL6z8ZsWE9kGA6Xl9JEpmmNE3XHDph0QXgwh_-r6fKnk0p_-9JN49QtlJmmprqc568CeCLujvuOUB9hfVCJuxvE1CiFUdl7sp8?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"Objeto AimTarget\"\/><figcaption class=\"wp-element-caption\">Personaje imagen<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>1: Crear el objeto vac\u00edo<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Haz clic derecho en tu personaje en la jerarqu\u00eda<\/li>\n\n\n\n<li>Selecciona &#8220;Create Empty&#8221;<\/li>\n\n\n\n<li>Renombra el nuevo objeto como &#8220;AimTarget&#8221;<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>2: Posicionar el objeto<\/strong> <strong>(personajes)<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Selecciona &#8220;AimTarget&#8221;<\/li>\n\n\n\n<li>En el inspector (Transform), col\u00f3calo a unos metros delante del personaje:\n<ul class=\"wp-block-list\">\n<li>Position Z: 3-5 (dependiendo de tu escena)<\/li>\n\n\n\n<li>Position Y: ~1.5 (altura del brazo)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>3. Configurar la capa UpperBody<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>1: A\u00f1adir animaci\u00f3n a la capa<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>En el Animator, selecciona la capa &#8220;UpperBody&#8221;<\/li>\n\n\n\n<li>Arrastra tu animaci\u00f3n de apuntado\/disparo a esta capa<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>2: Configurar peso<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>En la pesta\u00f1a Layers, ver\u00e1s un slider &#8220;Weight&#8221; para la capa UpperBody<\/li>\n\n\n\n<li>Pon este valor a 1 (para que se tenga prioridad sobre las animaciones base)<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>3: Ajustar m\u00e1scara (opcional &#8211; Personajes)<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Si solo quieres que afecte a la parte superior del cuerpo:\n<ul class=\"wp-block-list\">\n<li>Haz clic en el engranaje de la capa<\/li>\n\n\n\n<li>En &#8220;Avatar Mask&#8221;, crea o selecciona una m\u00e1scara que solo incluya torso y brazos<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfiq6Jd8Bj2x29sCbB4O5Cb-G0qkaBu4Oy13l9ibTXtMcmcGAtf8ekQmfKyVLOR9hjFX399HWLYMS4g-edowupaEQ_w2K1o5JqvIQiLiO1g5lVE9RBch5gBCquJrHc137KKPPkjQKQvp2mPRuftOok?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"Ajuste de mascara\"\/><figcaption class=\"wp-element-caption\">Escena<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Configuraci\u00f3n del Canvas para los movimientos del jugador. <\/p>\n\n\n\n<p>Se selecciona el player, se pone la vista 2D y comenzamos con la configuraci\u00f3n y los plugins.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXddPdb-uAkV3lJuRMKfeoki6GXjFJBqJxRPwYgM_3gx3nMEfLPjiTI4CrzfbhErdDH9YHIHGHp1--4ClV5m5nKDzA6PLrgQGVPwvfKA60dZ-_BcB5zy-8DtwWusrgoEORLouSmnnLAzd7lmqXY-Ld4?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"Configuraciones\"\/><figcaption class=\"wp-element-caption\">Verificaci\u00f3n escena<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXdVkrv0LmTsjScteGDlAQnVCUu33fF46pdYcB10KxgSWkjoqKTAVB1mEoGV9HI6kPzyEtQbT5tYKGdq-8dZYIBx0uffpAeEoc449zXc42tfg6PBWuXtZJIA_h6S0G34Oz9_CWu1qKKgvBBjSuWsNSg?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"Posiciones\"\/><figcaption class=\"wp-element-caption\">Posiciones<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfUIj_Gb6ngTO05DpAfdls9Gvalnsow1_rVelc084ezYk2dOtcu9X7l6BiB94V0f43eghQ3ytK3wqSOv1EZkjIlZ94Ma6ZlLLeTOr2kVAaUnumWarLPu6C6k-26wdXcA-_ZRu0EbUrFCUzYN0FAswY?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"Informaci\u00f3n juego\"\/><figcaption class=\"wp-element-caption\">Datos Animator<\/figcaption><\/figure>\n\n\n\n<p>Se crea un espacio vacio para agregar una nueva animaci\u00f3n de arma<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Hornear la NavMesh Usando el Componente NavMeshSurface<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u00bfQu\u00e9 es?<\/strong> El NavMeshSurface es el componente que se encarga de definir qu\u00e9 geometr\u00eda debe ser usada para la NavMesh y de realizar el proceso de &#8220;baking&#8221;.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Instrucciones:<\/strong><\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Crea un Objeto Vac\u00edo para la NavMesh (Recomendado):<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>En la ventana &#8220;Hierarchy&#8221; (Jerarqu\u00eda), haz clic derecho en un espacio vac\u00edo.<\/li>\n\n\n\n<li>Selecciona Create Empty (Crear Vac\u00edo).<\/li>\n\n\n\n<li>Renombra este nuevo GameObject (objeto de juego) a algo como <strong>&#8220;NavMeshBaker&#8221;<\/strong> o <strong>&#8220;LevelNavMesh&#8221;<\/strong>. Esto es \u00fatil para organizar tu escena.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>Agrega el Componente <\/strong><strong>NavMeshSurface<\/strong><strong>:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>Con tu nuevo objeto &#8220;NavMeshBaker&#8221; seleccionado en la &#8220;Hierarchy&#8221;.<\/li>\n\n\n\n<li>Ve a la ventana &#8220;Inspector&#8221; (normalmente a la derecha).<\/li>\n\n\n\n<li>Haz clic en el bot\u00f3n A\u00f1adir Componente.<\/li>\n\n\n\n<li>En la barra de b\u00fasqueda, escribe <strong>&#8220;NavMeshSurface&#8221;<\/strong>.<\/li>\n\n\n\n<li>Selecci\u00f3nalo para agregarlo a tu objeto.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>Configura y Hornea la NavMesh:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>Una vez que el componente NavMeshSurface est\u00e9 en tu objeto &#8220;NavMeshBaker&#8221;, ver\u00e1s sus propiedades en el Inspector.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXcKXNzg8ZFxt5coXET6TYSOjNxT4fdFNdiEQLrsZbXYSIYK0Hvh62hL1dqg1BG66G44j_ZoLQ5R683oqiWAX3hXtzZ_gU36BFxg9Na19OvhJvI9hVSxs7lxrglssE1gaiuhDudil74aL5VgWIBlvKg?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"Hornea la NavMesh\"\/><figcaption class=\"wp-element-caption\">Escena ampliada<\/figcaption><\/figure>\n\n\n\n<p>Si todo est\u00e1 configurado correctamente, ver\u00e1s la capa azul de la NavMesh superpuesta en las \u00e1reas transitables de tu escenario en la vista &#8220;Scene&#8221;.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Escribir el C\u00f3digo del ZombieIA (personaje) <\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u00bfQu\u00e9 es?<\/strong> Aqu\u00ed es donde programaremos al zombie para que busque al jugador, lo persiga y lo ataque.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p>Instrucciones:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Haz doble clic en el script <strong>&#8220;ZombieAI&#8221;<\/strong> en tu ventana &#8220;Project&#8221;. Esto abrir\u00e1 Visual Studio (o el editor de c\u00f3digo que tengas configurado con Unity).<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Codigo:<\/h4>\n\n\n\n<p>using UnityEngine;<\/p>\n\n\n\n<p>using UnityEngine.AI; \/\/ Necesitamos esto para usar NavMeshAgent<\/p>\n\n\n\n<p>using- System.Collections; \/\/ Necesitamos esto para las corrutinas<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">public class ZombieAI : MonoBehaviour<\/h6>\n\n\n\n<p>{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public- Transform playerTransform; \/\/ Variable para almacenar la referencia al jugador<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public float chaseRange = 10f; \/\/ Distancia a la que el zombie empezar\u00e1 a perseguir<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public float attackRange = 1.5f; \/\/ Distancia a la que el zombie empezar\u00e1 a atacar<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public- float attackCooldown = 2f; \/\/ Tiempo entre ataques<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public int attackDamage = 10; \/\/ Da\u00f1o que inflige el zombie por ataque<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp; private NavMeshAgent agent; \/\/ Referencia al componente NavMeshAgent<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;private bool isAttacking = false; \/\/ Bandera para controlar si el zombie ya est\u00e1 atacando<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp;void Start()<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Obtener la referencia al componente NavMeshAgent en este GameObject<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;agent = GetComponent&lt;NavMeshAgent&gt;();<\/p>\n\n\n\n<p>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ Intentar encontrar al jugador por su Tag, esto es crucial para que el zombie sepa a qui\u00e9n seguir.<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GameObject playerObject = GameObject.FindWithTag(&#8220;Player&#8221;);<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (playerObject != null)<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;playerTransform = playerObject.transform;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.LogError(&#8220;\u00a1No se encontr\u00f3 el objeto con el Tag &#8216;Player&#8217;! Aseg\u00farate de que tu jugador tiene el tag &#8216;Player&#8217;.&#8221;, this);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enabled = false; \/\/ Desactiva el script si no se encuentra al jugador<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp;void Update()<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (playerTransform == null) return; \/\/ Si no hay jugador, no hacer nada<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Calcular la distancia entre el zombie y el jugador<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float distanceToPlayer = Vector3.Distance(transform.position, playerTransform.position);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Si el jugador est\u00e1 dentro del rango de persecuci\u00f3n<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (distanceToPlayer &lt;= chaseRange)<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Mover el agente hacia la posici\u00f3n del jugador<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Unity NavMeshAgent se encargar\u00e1 de la ruta inteligente<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;agent.SetDestination(playerTransform.position);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Si el jugador est\u00e1 dentro del rango de ataque y no estamos atacando<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (distanceToPlayer &lt;= attackRange &amp;&amp; !isAttacking)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Detener el movimiento del agente para atacar<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;agent.isStopped = true;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StartCoroutine(AttackRoutine()); \/\/ Iniciar la rutina de ataque<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (distanceToPlayer &gt; attackRange &amp;&amp; agent.isStopped)<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Si el jugador se alej\u00f3 del rango de ataque, reanudar la persecuci\u00f3n<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;agent.isStopped = false;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Si el jugador est\u00e1 fuera del rango de persecuci\u00f3n, detener el movimiento<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Opcional: Podr\u00edas hacer que el zombie patrulle o est\u00e9 ocioso aqu\u00ed<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (agent.hasPath) \/\/ Solo si tiene una ruta activa<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;agent.isStopped = true;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;IEnumerator AttackRoutine()<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isAttacking = true; \/\/ Establecer bandera de ataque<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.Log(&#8220;Zombie atacando!&#8221;); \/\/ Mensaje de depuraci\u00f3n<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ TODO: Aqu\u00ed pondr\u00edas la l\u00f3gica de aplicar da\u00f1o al jugador.<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Por ahora, solo lo imprimimos. Necesitar\u00edas un script de &#8220;Health&#8221; en el jugador.<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/Ejemplo: PlayerHealth playerHealth = playerTransform.GetComponent&lt;PlayerHealth&gt;();<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ if (playerHealth != null) { playerHealth.TakeDamage(attackDamage); }<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Esperar el tiempo de cooldown antes de poder atacar de nuevo<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;yield return new WaitForSeconds(attackCooldown);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isAttacking = false; \/\/ Resetear bandera de ataque<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Reanudar el movimiento del agente si el jugador sigue en rango y no se ha movido<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (Vector3.Distance(transform.position, playerTransform.position) &lt;= attackRange)<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Mantenerse detenido si a\u00fan est\u00e1 en rango de ataque<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;agent.isStopped = true;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Si el jugador se alej\u00f3, reanudar la persecuci\u00f3n<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;agent.isStopped = false;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Esta funci\u00f3n dibuja las esferas de rango en el editor para que las veas<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp;void OnDrawGizmosSelected()<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Rango de persecuci\u00f3n (amarillo)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gizmos.color = Color.yellow;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gizmos.DrawWireSphere(transform.position, chaseRange);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Rango de ataque (rojo)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gizmos.color = Color.red;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gizmos.DrawWireSphere(transform.position, attackRange);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>Esto es un problema com\u00fan y tiene varias causas posibles, especialmente cuando se trabaja con NavMeshAgent y la configuraci\u00f3n inicial de un personaje.<\/p>\n\n\n\n<p>Que el zombie &#8220;desaparezca&#8221; (generalmente significa que cae infinitamente o se teletransporta a un lugar inesperado) casi siempre est\u00e1 relacionado con c\u00f3mo se est\u00e1 manejando su f\u00edsica o su posici\u00f3n inicial.<\/p>\n\n\n\n<p>Vamos a depurar esto paso a paso.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Diagn\u00f3stico del Problema: Zombie Desaparece<\/strong><\/h3>\n\n\n\n<p>Esto suele ocurrir por una de las siguientes razones:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Cae por el escenario:<\/strong> El zombie no tiene un Collider o Rigidbody configurado correctamente, o su posici\u00f3n inicial est\u00e1 por debajo de la NavMesh o de cualquier superficie.<\/li>\n<\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>Se teletransporta al origen (0,0,0) o a otro lugar:<\/strong> Esto puede pasar si el NavMeshAgent no encuentra una NavMesh v\u00e1lida para moverse o si hay un problema con su Base Offset.<\/li>\n<\/ol>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>El modelo es tan peque\u00f1o que parece desaparecer:<\/strong> Menos probable, pero a veces pasa si la escala es incorrecta.<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Soluciones y Verificaciones Paso a Paso:<\/strong><\/h2>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Verificaci\u00f3n 1: Posici\u00f3n Inicial del Zombie (Personaje)<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Problema:<\/strong> Si el zombie empieza <em>ligeramente por debajo<\/em> de la NavMesh o de un objeto con un Collider, puede caer al vac\u00edo.<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Soluci\u00f3n:<\/strong><\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li>En la vista &#8220;Scene&#8221; (Escena), selecciona tu zombie.<\/li>\n\n\n\n<li>Mira su posici\u00f3n en el &#8220;Inspector&#8221; (Transform &gt; Position).<\/li>\n\n\n\n<li>Aseg\u00farate de que su coordenada Y (altura) est\u00e9 por encima de la superficie de la NavMesh. debe ser solo lo suficiente para que no se &#8220;incruste&#8221;. Puedes arrastrarlo un poco hacia arriba con la herramienta de movimiento (icono de flechas) para levantarlo visualmente.<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Verificaci\u00f3n 2: Componentes F\u00edsicos (Collider y Rigidbody)<\/strong><\/h3>\n\n\n\n<p>Aunque el NavMeshAgent se encarga del movimiento, los colliders y rigidbodies son importantes para la interacci\u00f3n f\u00edsica y para que el agente se &#8220;apoye&#8221; en el suelo.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Problema:<\/strong> Un NavMeshAgent necesita un Collider en el mismo GameObject para funcionar correctamente. A veces, si se usa un Rigidbody sin las configuraciones adecuadas, puede interferir.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Soluci\u00f3n:<\/h4>\n\n\n\n<h4 class=\"wp-block-heading\">1: Selecciona tu zombie en la &#8220;Hierarchy&#8221;.<\/h4>\n\n\n\n<h4 class=\"wp-block-heading\">2: En el &#8220;Inspector&#8221;, verifica si tiene un componente <strong>Collider<\/strong> (por ejemplo, Capsule Collider o Box Collider).<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Si es un modelo 3D con animaciones, un <strong>Capsule Collider<\/strong> suele ser lo mejor para personajes.<\/li>\n\n\n\n<li>Si no tiene ninguno, haz clic en &#8220;Add Component&#8221;, busca &#8220;Capsule Collider&#8221; (o &#8220;Box Collider&#8221; si el dise\u00f1o del zombie es simple).<\/li>\n\n\n\n<li>Ajusta el tama\u00f1o y la posici\u00f3n del collider para que cubra a tu zombie. El Capsule Collider tiene Center (centro), Radius (radio) y Height (altura).<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">3: Rigidbody (Cuerpo R\u00edgido):<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Si tu zombie <em>tiene<\/em> un Rigidbody, aseg\u00farate de que la opci\u00f3n <strong>&#8220;Is Kinematic&#8221;<\/strong> est\u00e9 marcada. Esto es crucial cuando se usa NavMeshAgent. El NavMeshAgent se encarga del movimiento, y si el Rigidbody no es cinem\u00e1tico, intentar\u00e1 moverlo tambi\u00e9n, lo que causa conflictos y ca\u00eddas.<\/li>\n\n\n\n<li>Si no tiene un Rigidbody y solo tiene un Collider, el NavMeshAgent puede funcionar sin Rigidbody para la navegaci\u00f3n b\u00e1sica. Sin embargo, para colisiones con otros objetos m\u00f3viles o balas, un Rigidbody (cinem\u00e1tico) es necesario.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXc4FPAZvRI4mJaZf1goV0kfnLEEAN01EA2mK8JEhHRg8ocU3qpS343hn5T2WUsGSiAZRQQuhlK6Z0ykYZewLMsl7QusIh6No5mcAh4nFzClQOIchGFrMqdVOAwcJ0hMcanf1IL_uhvthdFyUy7jEKY?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"Cuerpo\"\/><figcaption class=\"wp-element-caption\">Actualizaci\u00f3n animator<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfMT81KLjYVL3-_gyAZ2k2etl977NO5pT-8cfwNNz8hE-6gH6Yl35wy4Egkn_F05z_xMp6LHO98ocmBR-3vseUbMpLdG0rgkQu-_uMcZtC5M2vka6-knjDDVaciSdzz8uiXJpvO6CrEfddkJTGKFA?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"Navegaci\u00f3n\"\/><figcaption class=\"wp-element-caption\">Navegaci\u00f3n<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Ve a la barra de men\u00fa superior de Unity: Window &gt; AI &gt; Navigation. Esto abrir\u00e1 la ventana &#8220;Navigation&#8221;.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">En la ventana &#8220;Navigation&#8221;, haz clic en la pesta\u00f1a <strong>Agents<\/strong>.<\/h4>\n\n\n\n<p>Deber\u00edas ver una lista de &#8220;Agent Types&#8221;. Selecciona el que dice <strong>Humanoid<\/strong> (es el predeterminado y el que usaremos).<\/p>\n\n\n\n<p>A la derecha de la ventana &#8220;Navigation&#8221;, ver\u00e1s la configuraci\u00f3n de ese tipo de agente. Ajusta estos valores:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Radius<\/strong><strong>:<\/strong> Este es el radio del personaje. Para tu zombie, un valor de <strong>0.5<\/strong> metros es un buen punto de partida (si tu zombie es m\u00e1s grande o m\u00e1s peque\u00f1o, aj\u00fastalo).<\/li>\n\n\n\n<li><strong>Height<\/strong><strong>:<\/strong> La altura del personaje. Para tu zombie, un valor de <strong>1.8<\/strong> a <strong>2.0<\/strong> metros es bueno.<\/li>\n\n\n\n<li><strong>Step Height<\/strong><strong>:<\/strong> <strong>\u00a1Este es clave para las cuestas!<\/strong> Es la altura m\u00e1xima de un &#8220;escal\u00f3n&#8221; que el agente puede subir. Para terrenos irregulares como &#8220;Flooded Ground&#8221;, un valor de <strong>0.3<\/strong><strong> a <\/strong><strong>0.4<\/strong> metros suele funcionar bien. Esto permite que el zombie suba peque\u00f1as elevaciones sin problema.<\/li>\n\n\n\n<li><strong>Max Slope<\/strong><strong>:<\/strong> El \u00e1ngulo m\u00e1ximo de inclinaci\u00f3n que el agente puede caminar. Un valor de <strong>45<\/strong> grados es est\u00e1ndar y bueno para la mayor\u00eda de las pendientes.<\/li>\n\n\n\n<li><strong>Drop Height<\/strong><strong>:<\/strong> La altura m\u00e1xima que el agente puede caer sin considerar un borde como obst\u00e1culo. Un valor de <strong>0.5<\/strong><strong> a <\/strong><strong>1.0<\/strong> es seguro.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Configurar el GameManager en el Inspector:<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Selecciona tu GameObject <strong>GameManager<\/strong> en la <strong>Hierarchy<\/strong>.<\/li>\n\n\n\n<li>En el <strong>Inspector<\/strong>, en el componente <strong>Wave Spawner<\/strong>, ver\u00e1s muchos campos nuevos. Necesitas arrastrar y configurar:\n<ul class=\"wp-block-list\">\n<li><strong>Zombie Prefabs (Array):<\/strong>\n<ul class=\"wp-block-list\">\n<li>Cambia el Size a 3.<\/li>\n\n\n\n<li>Arrastra tus tres Prefabs (Zombie1 (1), Zombie_Fast, FatZombie) desde la ventana Project a las ranuras Element 0, Element 1, Element 2.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Zombie Count Text:<\/strong> Arrastra tu texto de UI (ZombieCountText) desde el GameUICanvas en la Hierarchy.<\/li>\n\n\n\n<li><strong>Wave Message Text:<\/strong> Arrastra tu texto de UI (WaveMessageText) desde el GameUICanvas en la Hierarchy.<\/li>\n\n\n\n<li><strong>Ajusta los valores de las nuevas variables a tu gusto para equilibrar la dificultad:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Base Time Between Waves, Min Time Between Waves, Time Between Waves Decrease Per Wave<\/li>\n\n\n\n<li>Base Zombie Count, Zombies Increase Per Wave<\/li>\n\n\n\n<li>Base Spawn Delay, Min Spawn Delay, Spawn Delay Decrease Per Wave<\/li>\n\n\n\n<li>Base Zombie Health, Health Increase Per Wave<\/li>\n\n\n\n<li>Base Zombie Damage, Damage Increase Per Wave<\/li>\n\n\n\n<li>Spawn Radius, Min Distance From Player, Max Height Difference<\/li>\n\n\n\n<li>Message Display Time, Message Move Time<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfdedfFRiWRLt7kydzEek9qfLn-sB5FKTe9ECf38NuNO3CGkihGHqZibG4TvOELisfrFvuj4Vql0ig-k6bJXTWDpSEZeb8ASZDXF1EClj-jCyme60GnCqsS0YjGhUqevuKAhkAYKsy6PrnLeVj3z5c?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Inspector<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXegkChF5RWK4q-QNyzECErePY_a80yG9NJx1nQ4b96JySjfUHO5Fu6Asw-nGBUbwSWd00DF7Tuao14GnQblOnPW98bg2b1eky_ixVT4hyI2ujN40pzxkxxqjtyZiUeGv_Gp49nF6kVF9MUw3F5eYy4?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"Una captura de pantalla de una computadora\n\nEl contenido generado por IA puede ser incorrecto.\"\/><figcaption class=\"wp-element-caption\">Configuraci\u00f3n inspector<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Sistema de Disparo del Jugador (PlayerShooting.cs)<\/strong><\/h4>\n\n\n\n<p>Este script ir\u00e1 adjunto a tu jugador o a tu c\u00e1mara principal.<\/p>\n\n\n\n<p><strong>A. Crea el Script:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>En la ventana Project, ve a tu carpeta Scripts.<\/li>\n\n\n\n<li>Haz clic derecho > Create > cripting > empty C# Script y n\u00f3mbralo PlayerShooting.<\/li>\n\n\n\n<li>Abre el script y pega el siguiente c\u00f3digo:<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h6 class=\"wp-block-heading\">using UnityEngine;<\/h6>\n\n\n\n<h6 class=\"wp-block-heading\">public class PlayerShooting : MonoBehaviour<\/h6>\n\n\n\n<p>{<\/p>\n\n\n\n<p>public float damagePerShot = 20f; \/\/ Cu\u00e1nto da\u00f1o hace cada disparo<\/p>\n\n\n\n<p>public- float fireRate = 0.5f; \/\/ Tiempo entre disparos (0.5 significa 2 disparos por segundo)<\/p>\n\n\n\n<p>public float weaponRange = 100f;&nbsp; \/\/ Alcance del arma (raycast)<\/p>\n\n\n\n<p>public LayerMask shootableLayer; \/\/ Define qu\u00e9 capas pueden ser impactadas por el disparo (\u00a1Configurar en Inspector!)<\/p>\n\n\n\n<p>private Camera playerCamera;<\/p>\n\n\n\n<p>private float nextFireTime; \/\/ Para controlar el fire rate<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">void Start()<\/h6>\n\n\n\n<p>{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; playerCamera = GetComponentInChildren&lt;Camera&gt;(); \/\/ Busca la c\u00e1mara como hijo (si la tienes como hijo del player)<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp; if (playerCamera == null)<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.LogError(&#8220;PlayerShooting: No se encontr\u00f3 una c\u00e1mara en el jugador o sus hijos. Aseg\u00farate de que el script est\u00e1 en el objeto correcto o que la c\u00e1mara es hija.&#8221;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enabled = false; \/\/ Desactiva el script si no hay c\u00e1mara<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">void Update()<\/h6>\n\n\n\n<p>{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Disparar con el click izquierdo del rat\u00f3n y si ha pasado suficiente tiempo desde el \u00faltimo disparo<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; if (Input.GetMouseButtonDown(0) &amp;&amp; Time.time &gt;= nextFireTime)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Shoot();<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nextFireTime = Time.time + fireRate; \/\/ Establecer el tiempo del pr\u00f3ximo disparo<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">void Shoot()<\/h6>\n\n\n\n<p>{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; RaycastHit hit; \/\/ Almacena la informaci\u00f3n de lo que golpe\u00f3 el raycast<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; Ray ray = playerCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0)); \/\/ Rayo desde el centro de la pantalla<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Realiza el raycast<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; if (Physics.Raycast(ray, out hit, weaponRange, shootableLayer))<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.Log(&#8220;Golpe\u00f3: &#8221; + hit.collider.name);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Intentar obtener el componente ZombieAI del objeto golpeado<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ZombieAI zombie = hit.collider.GetComponent&lt;ZombieAI&gt;();<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (zombie != null)<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zombie.TakeDamage(damagePerShot); \/\/ Llama al m\u00e9todo TakeDamage del zombie<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Opcional: Si tienes efectos de disparo o impacto, act\u00edvalos aqu\u00ed<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Instantiate(hitEffectPrefab, hit.point, Quaternion.LookRotation(hit.normal));<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; else<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.Log(&#8220;No golpe\u00f3 nada o solo golpe\u00f3 capas no disparables.&#8221;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p><strong>B. Configuraci\u00f3n en Unity:<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Adjunta PlayerShooting.cs:<\/strong> Arrastra este script a tu GameObject Player (o el que contenga tu c\u00e1mara principal).<\/li>\n<\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>Configura la LayerMask:<\/strong>\n<ul class=\"wp-block-list\">\n<li>En el Inspector del PlayerShooting script, ver\u00e1s un campo Shootable Layer.<\/li>\n\n\n\n<li>Haz clic en el men\u00fa desplegable y selecciona Add Layer&#8230;.<\/li>\n\n\n\n<li>Crea una nueva Layer (Capa) llamada <strong>&#8220;Enemy&#8221;<\/strong> (o &#8220;Zombie&#8221;).<\/li>\n\n\n\n<li>Vuelve al PlayerShooting script en el Inspector y ahora <strong>selecciona la capa &#8220;Enemy&#8221;<\/strong> en Shootable Layer.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>Asigna la Capa &#8220;Enemy&#8221; a tus Prefabs de Zombies:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Selecciona cada uno de tus Prefabs de zombies (Zombie1 (1), Zombie_Fast, FatZombie) en la ventana Project.<\/li>\n\n\n\n<li>En el Inspector de cada Prefab, arriba de su nombre, ver\u00e1s un men\u00fa desplegable Layer.<\/li>\n\n\n\n<li>Selecciona la capa <strong>&#8220;Enemy&#8221;<\/strong> que acabas de crear. \u00a1Esto es crucial para que el raycast los detecte!<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\">\n<li><strong>Ajusta el Damage Per Shot, Fire Rate y Weapon Range<\/strong> en el Inspector del PlayerShooting seg\u00fan tu gusto.<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>2. Indicador de Vida para Zombies (ZombieAI.cs y UI)<\/strong><\/h4>\n\n\n\n<p>Cada zombie tendr\u00e1 su propia barra de vida flotante.<\/p>\n\n\n\n<p><strong>A. Modificaciones en el Prefab de Zombie (UI):<\/strong><\/p>\n\n\n\n<p><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Abre uno de tus Prefabs de Zombie<\/strong> en modo de edici\u00f3n (haz doble clic en el Prefab en la ventana Project)<\/li>\n<\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>Crea un Canvas para la barra de vida:<\/strong>\n<ul class=\"wp-block-list\">\n<li>En la Hierarchy del Prefab, haz clic derecho &gt; UI &gt; Canvas.<\/li>\n\n\n\n<li>Selecciona el nuevo Canvas. En su Inspector, cambia Render Mode a <strong>World Space<\/strong>.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXcHoqYvrGcQEPRhUwtxJOvwG1LN5v0QlHprQd1KEhOtXMnNUQldwKimRICpwgTVFP0AERUE9hHKW3E5bjv34HRJT0mGoe1gl887azOXZbbVXwBYiqT7jtcf7-IkkwnsSX37aHvFK6umS4ppogZ-bQ?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"Captura de pantalla de computadora\n\nEl contenido generado por IA puede ser incorrecto.\"\/><figcaption class=\"wp-element-caption\">Zombie &#8211; Prefab<\/figcaption><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ajusta el Rect Transform del Canvas:\n<ul class=\"wp-block-list\">\n<li>Pos Y: Un valor positivo para que est\u00e9 sobre la cabeza del zombie (ej. 2).<\/li>\n\n\n\n<li>Width: 100 (o 1000, depende de tu escala, tendr\u00e1s que ajustar).<\/li>\n\n\n\n<li>Height: 10 (o 100).<\/li>\n\n\n\n<li>Scale: Ajusta X, Y, Z a un valor muy peque\u00f1o (ej. 0.01 o 0.005) para que la barra de vida no sea gigante en el mundo.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Quita el componente Canvas Scaler<\/strong> del Canvas (haz clic en los tres puntos y Remove Component).<\/li>\n<\/ul>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>Crea la Barra de Vida (UI Image):<\/strong>\n<ul class=\"wp-block-list\">\n<li>Dentro del Canvas que acabas de crear (en la Hierarchy del Prefab), haz clic derecho &gt; UI &gt; Image. Este ser\u00e1 el fondo de la barra de vida.<\/li>\n\n\n\n<li>N\u00f3mbralo HealthBarBackground.<\/li>\n\n\n\n<li>Cambia su Color a un gris oscuro o negro.<\/li>\n\n\n\n<li>Ajusta su Rect Transform para que ocupe todo el Canvas: Left: 0, Top: 0, Right: 0, Bottom: 0.<\/li>\n\n\n\n<li>Dentro de HealthBarBackground, haz clic derecho &gt; UI &gt; Image. Este ser\u00e1 el relleno de la barra de vida.<\/li>\n\n\n\n<li>N\u00f3mbralo HealthBarFill.<\/li>\n\n\n\n<li>Cambia su Color a verde.<\/li>\n\n\n\n<li>En su Inspector, en Image (Script), cambia Image Type a <strong>Filled<\/strong>.<\/li>\n\n\n\n<li>Cambia Fill Method a <strong>Horizontal<\/strong>.<\/li>\n\n\n\n<li>Fill Origin a <strong>Left<\/strong>.<\/li>\n\n\n\n<li>Ajusta su Rect Transform para que ocupe el mismo espacio que el fondo.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\">\n<li><strong>Haz que la Barra de Vida Mire a la C\u00e1mara (Nuevo Script Billboard.cs):<\/strong>\n<ul class=\"wp-block-list\">\n<li>Crea un nuevo script llamado Billboard.cs.<\/li>\n\n\n\n<li>Pega el siguiente c\u00f3digo<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<h6 class=\"wp-block-heading\">using UnityEngine;<\/h6>\n\n\n\n<p>public class Billboard : MonoBehaviour<\/p>\n\n\n\n<p>{<\/p>\n\n\n\n<p>public Camera mainCamera; \/\/ Asigna_c\u00e1mara_principal<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">void Start()<\/h6>\n\n\n\n<p>{<\/p>\n\n\n\n<h6 class=\"wp-block-heading\"> if (mainCamera == null)<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mainCamera = Camera.main; <\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp; if (mainCamera == null)<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.LogError(&#8220;Billboard: No_se_encontr\u00f3_la c\u00e1mara_principal. Aseg\u00farate_de_que_tu_c\u00e1mara_tenga_el_Tag_&#8217;MainCamera&#8217;.&#8221;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enabled = false;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>void LateUpdate() \/\/ LateUpdate asegura ejecutar despu\u00e9s de movimiento de c\u00e1mara<\/p>\n\n\n\n<p>{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; if (mainCamera != null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \/\/ Objeto mira c\u00e1mara, solo en el eje Y (para que no se incline)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;transform.LookAt(transform.position + mainCamera.transform.rotation * Vector3.forward,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mainCamera.transform.rotation * Vector3.up);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXdDkJZkfmcMEF1oXuA596pM8RonfTEg8vD91YBoPxs1TAZV-lGHSLFuRqNp2tBDanYZ5wrlReP_s10-5Lp-RDXmtvcKg_RbH_tUF1R_ItImUjiJidAzSnfitmxT2pJ13H1OKvsCYYDEDMmMnMs1PA?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Scene &#8211; Zombie<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Configuraci\u00f3n Final en los Prefabs de Zombies:<\/strong><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Selecciona cada uno de tus Prefabs de Zombies<\/strong> en la ventana Project.<\/li>\n\n\n\n<li>En el Inspector, en el componente Zombie AI (Script), arrastra el HealthBarFill (la imagen verde que creaste dentro del Canvas del zombie) a la ranura Health Bar Fill Image.<\/li>\n\n\n\n<li><strong>En el Canvas de cada Prefab de Zombie<\/strong>, en el script Billboard.cs, arrastra tu Main Camera (el GameObject de tu c\u00e1mara principal en la escena) a la ranura Main Camera. Aseg\u00farate de que tu c\u00e1mara principal tenga el tag <strong>MainCamera<\/strong>.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>3. Sistema de Vida del Jugador (<\/strong><strong>PlayerHealth.cs<\/strong><strong> y UI)<\/strong><\/h3>\n\n\n\n<p><strong>A. Crea el Script <\/strong><strong>PlayerHealth.cs<\/strong><strong>:<\/strong>Crea un nuevo script llamado PlayerHealth.<\/p>\n\n\n\n<p>using_UnityEngine;<\/p>\n\n\n\n<p>using UnityEngine.UI; \/\/ Necesario para Slider<\/p>\n\n\n\n<p>using TMPro; \/\/ Necesario para TextMeshPro (si lo usas para mostrar vida num\u00e9rica)<\/p>\n\n\n\n<p>using_UnityEngine.SceneManagement; \/\/ Necesario para reiniciar la escena<\/p>\n\n\n\n<p>public class PlayerHealth : MonoBehaviour<\/p>\n\n\n\n<p>{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public float maxHealth = 100f;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;\/public float currentHealth;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public Slider healthBarSlider; \/\/ Referencia al Slider de la UI para la barra de vida<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;\/\/ public TextMeshProUGUI healthText; \/\/ Opcional: para mostrar la vida como n\u00famero<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public GameObject gameOverPanel; \/\/ Referencia al Panel de Game Over<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;\/public TextMeshProUGUI gameOverMessageText; \/\/ Mensaje de Game Over<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public Button restartButton; \/\/ Bot\u00f3n de reinicio<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;private WaveSpawner waveSpawner; \/\/ Para notificar que el jugador muri\u00f3 y detener oleadas<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp;void Awake() \/\/ Usar Awake para asegurar que se inicialice antes que otros scripts dependientes<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;currentHealth = maxHealth;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (healthBarSlider != null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;healthBarSlider.maxValue = maxHealth;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;healthBarSlider.value = currentHealth;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ if (healthText != null) healthText.text = currentHealth.ToString();<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (gameOverPanel != null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gameOverPanel.SetActive(false); \/\/ Asegurarse de que el panel de Game Over est\u00e9 oculto al inicio<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Encontrar el WaveSpawner para detener las oleadas al morir el jugador<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;waveSpawner = FindObjectOfType&lt;WaveSpawner&gt;();<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (waveSpawner == null)<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.LogWarning(&#8220;PlayerHealth: No se encontr\u00f3 WaveSpawner. Aseg\u00farate de que est\u00e9 en la escena si necesitas detener las oleadas al morir.&#8221;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Asignar la funci\u00f3n al bot\u00f3n de reinicio<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (restartButton != null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;restartButton.onClick.AddListener(RestartGame);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public void TakeDamage(float amount)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;currentHealth -= amount;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;currentHealth = Mathf.Max(currentHealth, 0); \/\/ Asegurarse de que la salud no baje de 0<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (healthBarSlider != null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;healthBarSlider.value = currentHealth;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ if (healthText != null) healthText.text = currentHealth.ToString();<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.Log($&#8221;Jugador recibi\u00f3 {amount} de da\u00f1o. Salud restante: {currentHealth}&#8221;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (currentHealth &lt;= 0)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Die();<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public void Heal(float amount)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;currentHealth += amount;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;currentHealth = Mathf.Min(currentHealth, maxHealth); \/\/ Asegurarse de que la salud no supere la m\u00e1xima<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (healthBarSlider != null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;healthBarSlider.value = currentHealth;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ if (healthText != null) healthText.text = currentHealth.ToString();<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.Log($&#8221;Jugador curado {amount}. Salud actual: {currentHealth}&#8221;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;void Die()<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.Log(&#8220;\u00a1El jugador ha muerto!&#8221;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Aqu\u00ed puedes detener el tiempo, deshabilitar el movimiento del jugador, etc.<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Time.timeScale = 0f; \/\/ Detener el tiempo del juego<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (gameOverPanel != null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gameOverPanel.SetActive(true);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (gameOverMessageText != null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gameOverMessageText.text = &#8220;\u00a1Has Perdido!&#8221;;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Opcional: Deshabilitar el script de movimiento y disparo del jugador<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PlayerShooting playerShooting = GetComponent&lt;PlayerShooting&gt;();<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (playerShooting != null) playerShooting.enabled = false;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Si tienes un script de movimiento de jugador, desact\u00edvalo tambi\u00e9n.<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Notificar al WaveSpawner que el juego ha terminado<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (waveSpawner != null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Puedes a\u00f1adir un m\u00e9todo en WaveSpawner para manejar el fin de juego,<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ por ahora, simplemente detendr\u00e1 el flujo de oleadas al no haber m\u00e1s jugador.<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public void RestartGame()<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Time.timeScale = 1f; \/\/ Reanudar el tiempo del juego antes de reiniciar la escena<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SceneManager.LoadScene(SceneManager.GetActiveScene().name); \/\/ Recarga la escena actual<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Paso a Paso: Implementando el Disparo (M1911 de Nokobot)<\/strong><\/h3>\n\n\n\n<p><strong>Asunci\u00f3n importante:<\/strong> Est\u00e1s utilizando el sistema de <strong>Input System (New)<\/strong> de Unity, ya que lo configuramos antes.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Fase 1: Configuraci\u00f3n del Arma en la Jerarqu\u00eda del Jugador<\/strong><\/h3>\n\n\n\n<p>Primero, necesitamos que el arma est\u00e9 visible y correctamente posicionada en la mano de tu personaje.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Localiza tu Prefab de Personaje:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>En la ventana Hierarchy, selecciona tu GameObject de personaje principal (probablemente Player o ThirdPersonController).<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>Encuentra el Hueso de la Mano Correcto:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>Expande la jerarqu\u00eda de tu personaje en el Hierarchy hasta encontrar el hueso de la mano derecha (o izquierda, seg\u00fan prefieras que dispare). Esto suele estar en una ruta similar a:\n<ul class=\"wp-block-list\">\n<li>Player &gt; PlayerArmature &gt; Root &gt; Hips &gt; Spine &gt; Spine1 &gt; Spine2 &gt; RightShoulder &gt; RightArm &gt; RightForeArm &gt; RightHand.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Selecciona el hueso <strong>RightHand<\/strong> (o LeftHand).<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>Posiciona el Arma en la Mano:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>En la ventana Project, busca tu prefab o modelo de la <strong>M1911<\/strong> del asset de Nokobot.<\/li>\n\n\n\n<li><strong>Arrastra el prefab\/modelo de la <\/strong><strong>M1911<\/strong><strong> desde la ventana <\/strong><strong>Project<\/strong><strong> y su\u00e9ltalo sobre el hueso <\/strong><strong>RightHand<\/strong><strong> que seleccionaste en la <\/strong><strong>Hierarchy<\/strong>. Esto har\u00e1 que la M1911 se convierta en un hijo de RightHand.<\/li>\n\n\n\n<li>Con la M1911 seleccionada en la Hierarchy, usa las herramientas de Move (W), Rotate (E) y Scale (R) para posicionar la M1911 en la mano de tu personaje. Ajusta su posici\u00f3n (Position), rotaci\u00f3n (Rotation) y tama\u00f1o (Scale) hasta que se vea natural en la mano.\n<ul class=\"wp-block-list\">\n<li><strong>Sugerencia:<\/strong> Puedes entrar en modo Play brevemente para ver c\u00f3mo se ve con la animaci\u00f3n de inactividad, y luego ajustar los valores en el Inspector. Los cambios en modo Play no se guardan, as\u00ed que anota los valores y luego apl\u00edcalos fuera del modo Play.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\">\n<li><strong>Crea un Punto de Disparo (FirePoint):<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>Dentro de la jerarqu\u00eda de tu M1911, haz clic derecho en el GameObject M1911 y selecciona Create Empty. Llama a este nuevo GameObject <strong>FirePoint<\/strong>.<\/li>\n\n\n\n<li>Mueve y posiciona este FirePoint exactamente en la <strong>punta del ca\u00f1\u00f3n<\/strong> de la M1911. Este ser\u00e1 el punto desde donde saldr\u00e1n tus rayos de disparo o balas. Es importante que est\u00e9 correctamente posicionado.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Fase 2: Script de Disparo (<\/strong><strong>WeaponController.cs<\/strong><strong>)<\/strong><\/h3>\n\n\n\n<p>Ahora, vamos a crear la l\u00f3gica de disparo.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Crea un Nuevo Script:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>En tu carpeta Assets\/Scripts (o donde guardes tus scripts), haz clic derecho Create &gt; C# Script.<\/li>\n\n\n\n<li>Llama al script <strong>WeaponController<\/strong>.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>Adjunta el Script a la M1911:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>Arrastra el script WeaponController que acabas de crear desde la ventana Project y su\u00e9ltalo sobre el GameObject <strong>M1911<\/strong> en tu Hierarchy.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p><strong>Abre el Script <\/strong><strong>WeaponController.cs<\/strong><strong> y Pega el C\u00f3digo:<\/strong><\/p>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXeBTf0DST1uu4hygrsndDlfZoaVbmoviEuEUIBw6w80UW1jjGu4ELRURuUZxCrKpm_VDx363f2GFUVJbHB3WCatVDqZUuDsevrK-X4vU_VU5z0rOkYpWyQzLGeKS9r8TBp_1T7rX8vxlfZzbjMdt5I?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"\"\/><figcaption class=\"wp-element-caption\">Scene &#8211; Personaje<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h6 class=\"wp-block-heading\">using UnityEngine;<\/h6>\n\n\n\n<p>using System.Collections; \/\/ Necesario para Coroutines<\/p>\n\n\n\n<p>\/\/ Aseg\u00farate de que este namespace coincida con el de tus Starter Assets si los tienes<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">namespace StarterAssets<\/h6>\n\n\n\n<p>{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;public class WeaponController : MonoBehaviour<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Header(&#8220;Weapon Settings&#8221;)]<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/public float Damage = 10f; \/\/ Da\u00f1o que hace el arma<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public float Range = 100f; \/\/ Alcance m\u00e1ximo del disparo<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public float FireRate = 0.1f; \/\/ Cadencia de disparo (segundos entre disparos)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Header(&#8220;References&#8221;)]<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/public Camera PlayerCamera; \/\/ La c\u00e1mara principal de tu jugador (generalmente CinemachineTarget o Main Camera)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public Transform FirePoint; \/\/ El punto desde donde saldr\u00e1 el rayo\/bala (el GameObject vac\u00edo que creaste)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/public GameObject MuzzleFlashEffect; \/\/ El GameObject del efecto de flash de la boca del ca\u00f1\u00f3n<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public Animator WeaponAnimator; \/\/ El Animator del arma (M1911)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private StarterAssetsInputs _input; \/\/ Referencia a tu script de entrada<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private float _nextTimeToFire = 0f; \/\/ Controla la cadencia de disparo<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void Start()<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Busca el componente StarterAssetsInputs en los padres o en el mismo objeto del personaje.<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Asume que StarterAssetsInputs est\u00e1 en el GameObject ra\u00edz del personaje.<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_input = GetComponentInParent&lt;StarterAssetsInputs&gt;();&nbsp;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (_input == null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.LogError(&#8220;WeaponController: StarterAssetsInputs script not found on parent!&#8221;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (PlayerCamera == null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Intentar encontrar la c\u00e1mara principal si no est\u00e1 asignada en el Inspector<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PlayerCamera = Camera.main;&nbsp;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (PlayerCamera == null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.LogError(&#8220;WeaponController: PlayerCamera not assigned and MainCamera not found!&#8221;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (FirePoint == null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.LogError(&#8220;WeaponController: FirePoint not assigned! Create an empty GameObject at the gun&#8217;s muzzle.&#8221;);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (MuzzleFlashEffect != null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MuzzleFlashEffect.SetActive(false); \/\/ Aseg\u00farate de que el flash est\u00e9 desactivado al inicio<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void Update()<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Si el jugador presiona el bot\u00f3n de disparo y ha pasado suficiente tiempo desde el \u00faltimo disparo<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (_input.shoot &amp;&amp; Time.time &gt;= _nextTimeToFire)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_nextTimeToFire = Time.time + FireRate; \/\/ Calcula cu\u00e1ndo se podr\u00e1 disparar de nuevo<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Shoot(); \/\/ Llama a la funci\u00f3n de disparo<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void Shoot()<\/h6>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ &#8212; 1. Animaci\u00f3n de Disparo &#8212;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (WeaponAnimator != null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Aseg\u00farate de tener un Trigger en tu Animator llamado &#8220;Fire&#8221; (o el que uses para disparar)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WeaponAnimator.SetTrigger(&#8220;Fire&#8221;);&nbsp;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ &#8212; 2. Efecto de Muzzle Flash &#8212;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (MuzzleFlashEffect != null)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StartCoroutine(MuzzleFlashRoutine()); \/\/ Inicia una Coroutine para activar y desactivar el flash<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ &#8212; 3. Detecci\u00f3n de Impacto (Raycasting) &#8212;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RaycastHit hit;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/*Dispara un rayo desde la c\u00e1mara o desde el FirePoint si quieres que sea m\u00e1s preciso<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Para 3ra persona, a menudo se usa la c\u00e1mara para simular la &#8220;mira&#8221; del jugador<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Si quieres que el rayo salga del arma en su direcci\u00f3n, usa FirePoint.forward<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/* Opci\u00f3n 1: Raycast desde el centro de la pantalla (m\u00e1s com\u00fan para ThirdPerson)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Esto simula que el jugador apunta con la mira<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ray ray = PlayerCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0));&nbsp;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (Physics.Raycast(ray, out hit, Range))<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.Log(&#8220;Hit: &#8221; + hit.collider.name);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Aqu\u00ed puedes a\u00f1adir l\u00f3gica para:<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/* &#8211; Instanciar un efecto de impacto (ej. un agujero de bala) en hit.point<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/* &#8211; Llamar a un m\u00e9todo de da\u00f1o en el objeto impactado (ej. hit.collider.GetComponent&lt;Health&gt;().TakeDamage(Damage);)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Opci\u00f3n 2: Raycast desde el FirePoint del arma (m\u00e1s preciso para el arma, pero menos para la mira del jugador)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/* Esto podr\u00eda no coincidir con el centro de la pantalla si no tienes un sistema de mira muy preciso<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (Physics.Raycast(FirePoint.position, FirePoint.forward, out hit, Range))<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; Debug.Log(&#8220;Hit (from gun): &#8221; + hit.collider.name);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Para visualizar el rayo en el editor *\/<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Debug.DrawRay(ray.origin, ray.direction * Range, Color.red, 1f);&nbsp;<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Coroutine para el efecto de flash de la boca del ca\u00f1\u00f3n<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IEnumerator MuzzleFlashRoutine()<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MuzzleFlashEffect.SetActive(true);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;yield return new WaitForSeconds(0.05f); \/\/ Duraci\u00f3n del flash (ajusta este valor)<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MuzzleFlashEffect.SetActive(false);<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>4: Configuraci\u00f3n del Action Map (Input System)<\/strong><\/h3>\n\n\n\n<p>Ahora que el script est\u00e1 listo, necesitamos configurar el Input System para reconocer el bot\u00f3n de disparo.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Abre tu <\/strong><strong>PlayerInput<\/strong><strong> Action Map:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>En la ventana Project, busca tu asset de Input Actions. Suele llamarse StarterAssets.inputactions o PlayerInputActions.<\/li>\n\n\n\n<li>Haz doble clic en \u00e9l para abrir la ventana <strong>Input Actions<\/strong><\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>A\u00f1ade una Nueva Acci\u00f3n de Disparo:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>En la columna de Action Maps, selecciona Player.<\/li>\n\n\n\n<li>En la columna de Actions, haz clic en el bot\u00f3n <strong>+<\/strong> (el signo de m\u00e1s).<\/li>\n\n\n\n<li>Nombra la nueva acci\u00f3n <strong>Shoot<\/strong>.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>Asigna un Bot\u00f3n a la Acci\u00f3n <\/strong><strong>Shoot<\/strong><strong>:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>Con la acci\u00f3n Shoot seleccionada, en la columna Properties (la m\u00e1s a la derecha), haz clic en el bot\u00f3n <strong>+<\/strong> debajo de No Bindings.<\/li>\n\n\n\n<li>Haz clic en <strong>Listen<\/strong>. Ahora, presiona el bot\u00f3n que quieres usar para disparar (por ejemplo, el <strong>bot\u00f3n izquierdo del mouse<\/strong>).<\/li>\n\n\n\n<li>Unity deber\u00eda detectar Mouse\/leftButton. Si es correcto, haz clic en Listen de nuevo para dejar de escuchar.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\">\n<li><strong>Guarda el Asset de Input Actions:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>Haz clic en el bot\u00f3n <strong>Save Asset<\/strong> en la parte superior derecha de la ventana Input Actions.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\"><\/ol>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\"><\/ol>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\"><\/ol>\n\n\n\n<ul class=\"wp-block-list\"><\/ul>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\"><\/ol>\n\n\n\n<ol class=\"wp-block-list\"><\/ol>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXf7i9imWh2theAfcTPGaguO_dpDGVcrspUU4-N4pzt0uRuF0p5fQn3In4E82l7riVTRRAbxuwltGSG8myrN58T_pSZ02w67UvBqdTZd__qBVoUev8Z-MT6ot_7qhuftG3BlRBoZF4yuxBLgT2tJLYI?key=jHAncPdtAn5ykZMkyaDMkw\" alt=\"\"\/><figcaption class=\"wp-element-caption\">window input actions<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Fase 5: Conectar Elementos en el Inspector<\/strong><\/h3>\n\n\n\n<p>Finalmente, conecta todas las referencias en el Inspector de tu M1911.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Selecciona tu GameObject <\/strong><strong>M1911<\/strong> en la Hierarchy.<\/li>\n<\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li>En su Inspector, busca el componente <strong>WeaponController<\/strong>.<\/li>\n<\/ol>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>Arrastra y asigna los siguientes campos:<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>Player Camera<\/strong>: Arrastra tu Main Camera (o el Cinemachine Virtual Camera Target) desde la Hierarchy hasta este campo.<\/li>\n\n\n\n<li><strong>Fire Point<\/strong>: Arrastra el GameObject FirePoint que creaste dentro de la M1911 hasta este campo.<\/li>\n\n\n\n<li><strong>Muzzle Flash Effect<\/strong>: Expande la jerarqu\u00eda de tu M1911 para encontrar el GameObject que contiene el efecto de flash (podr\u00eda llamarse &#8220;MuzzleFlash&#8221;, &#8220;Flash&#8221;, etc.). Arr\u00e1stralo a este campo.<\/li>\n\n\n\n<li><strong>Weapon Animator<\/strong>: Arrastra el GameObject M1911 (o el hijo que tenga el Animator si no es el padre) hasta este campo.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Fase 6: Configuraci\u00f3n del Animator del Arma<\/strong><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Selecciona tu GameObject <\/strong><strong>M1911<\/strong> en la Hierarchy.<\/li>\n<\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li>Abre la ventana <strong>Animator<\/strong> (Window > Animation > Animator).<\/li>\n<\/ol>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>Crea un <\/strong><strong>Trigger<\/strong><strong> para el disparo:<\/strong>\n<ul class=\"wp-block-list\">\n<li>En la ventana Animator, ve a la pesta\u00f1a <strong>Parameters<\/strong> (normalmente a la izquierda).<\/li>\n\n\n\n<li>Haz clic en el bot\u00f3n + y selecciona <strong>Trigger<\/strong>.<\/li>\n\n\n\n<li>N\u00f3mbralo <strong>Fire<\/strong> (debe coincidir exactamente con el nombre WeaponAnimator.SetTrigger(&#8220;Fire&#8221;); en el script).<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\">\n<li><strong>Configura la Transici\u00f3n a la Animaci\u00f3n de Disparo:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Arrastra tu clip de animaci\u00f3n de disparo (el que se llama Fire o similar) desde la ventana Project a la ventana Animator para crear un nuevo estado.<\/li>\n\n\n\n<li>Haz clic derecho en tu estado Any State (o tu estado de animaci\u00f3n base, como Idle) y selecciona Make Transition hacia tu nueva animaci\u00f3n de disparo.<\/li>\n\n\n\n<li>Haz clic en la flecha de transici\u00f3n. En el Inspector, en la secci\u00f3n Conditions, haz clic en + y selecciona tu Trigger <strong>Fire<\/strong>.<\/li>\n\n\n\n<li>Aseg\u00farate de que Has Exit Time est\u00e9 <strong>desactivado<\/strong> en la transici\u00f3n para que el disparo se reproduzca instant\u00e1neamente.<\/li>\n\n\n\n<li>Opcionalmente, puedes crear una transici\u00f3n de la animaci\u00f3n Fire de vuelta al estado Idle cuando la animaci\u00f3n de Fire termine (con Has Exit Time activado en esa transici\u00f3n).<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Parte 1: Crear la Mira (Crosshair) en la UI<\/strong><\/h3>\n\n\n\n<p>Primero, vamos a poner la imagen de la mira en el centro de tu pantalla.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Crea un Canvas para la UI:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>En la ventana Hierarchy, haz clic derecho.<\/li>\n\n\n\n<li>Selecciona UI > Canvas.<\/li>\n\n\n\n<li>Renombra el nuevo GameObject a UICrosshairCanvas.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>Configura el Canvas:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>Selecciona UICrosshairCanvas en la Hierarchy.<\/li>\n\n\n\n<li>En el Inspector, en el componente Canvas:\n<ul class=\"wp-block-list\">\n<li>Cambia Render Mode a Screen Space &#8211; Camera.<\/li>\n\n\n\n<li>Arrastra tu Main Camera (o la c\u00e1mara a la que est\u00e1 siguiendo Cinemachine, si es diferente) al campo <strong>Render Camera<\/strong>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>En el componente Canvas Scaler:\n<ul class=\"wp-block-list\">\n<li>Cambia UI Scale Mode a Scale With Screen Size.<\/li>\n\n\n\n<li>Pon Reference Resolution a 1920 x 1080 (o la resoluci\u00f3n base de tu juego).<\/li>\n\n\n\n<li>Pon Screen Match Mode a Match Width Or Height.<\/li>\n\n\n\n<li>Pon Match a 0.5 (para equilibrar ancho y alto).<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>A\u00f1ade la Imagen de la Mira (Crosshair Image):<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>Haz clic derecho en UICrosshairCanvas en la Hierarchy.<\/li>\n\n\n\n<li>Selecciona UI > Image.<\/li>\n\n\n\n<li>Renombra el nuevo GameObject a CrosshairImage.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\">\n<li><strong>Configura la Imagen de la Mira:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>Selecciona CrosshairImage en la Hierarchy.<\/li>\n\n\n\n<li>En el Inspector, en el componente Rect Transform:\n<ul class=\"wp-block-list\">\n<li>Haz clic en el cuadro de anclas (el que parece un cuadrado con dos flechas) y selecciona el ancla del <strong>centro<\/strong> (la que parece una cruz). Mant\u00e9n Alt presionado al hacer clic para tambi\u00e9n establecer la posici\u00f3n.<\/li>\n\n\n\n<li>Aseg\u00farate de que Pos X, Pos Y, Left, Right, Top, Bottom est\u00e9n todos en 0.<\/li>\n\n\n\n<li>Ajusta Width y Height a un tama\u00f1o peque\u00f1o, por ejemplo, 20 o 30.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>En el componente Image:\n<ul class=\"wp-block-list\">\n<li>En el campo <strong>Source Image<\/strong>, arrastra la textura de tu mira. Si no tienes una, puedes usar un sprite blanco temporalmente (crea uno con Assets > Create > Sprites > Square, luego cambia su color en el Inspector).<\/li>\n\n\n\n<li>Aseg\u00farate de que Color sea blanco (RGBA 255,255,255,255) por ahora.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Parte 2: Preparar a los Zombies (Capa y Script de Salud)<\/strong><\/h3>\n\n\n\n<p>Necesitamos que los zombies sean reconocibles para nuestro raycast y que puedan recibir da\u00f1o.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Crea una Capa (Layer) para los Zombies:<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>Selecciona uno de tus GameObjects de zombie en la Hierarchy.<\/li>\n\n\n\n<li>En el Inspector, en la parte superior, al lado de Layer, haz clic en el men\u00fa desplegable.<\/li>\n\n\n\n<li>Selecciona <strong>Add Layer&#8230;<\/strong>.<\/li>\n\n\n\n<li>En el primer espacio vac\u00edo (por ejemplo, User Layer 8 o User Layer 9), escribe <strong>Zombie<\/strong>.<\/li>\n\n\n\n<li>Vuelve a seleccionar tu GameObject de zombie en la Hierarchy.<\/li>\n\n\n\n<li>Cambia su Layer al reci\u00e9n creado Zombie.<\/li>\n\n\n\n<li><strong>IMPORTANTE:<\/strong> Si te pregunta Change Children? (\u00bfCambiar hijos?), selecciona <strong>Yes, change children<\/strong> para que todas las partes del modelo de tu zombie est\u00e9n en la misma capa.<\/li>\n\n\n\n<li>Repite esto para todos los GameObjects ra\u00edz de tus zombies en la escena.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>Crea un Script de Salud para los Zombies (<\/strong><strong>Health.cs<\/strong><strong>):<\/strong><strong><br><\/strong>\n<ul class=\"wp-block-list\">\n<li>En tu carpeta Scripts (o donde organices tus scripts), haz clic derecho.<\/li>\n\n\n\n<li>Selecciona Create > C# Script.<\/li>\n\n\n\n<li>N\u00f3mbralo Health.<\/li>\n\n\n\n<li>Abre el script Health.cs y pega el siguiente c\u00f3digo:<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusiones<\/h2>\n\n\n\n<p>Las herramientas utilizadas demuestran la potencia y versatilidad del ecosistema actual de desarrollo de videojuegos 3D. <strong>Mixamo<\/strong> se consolida como una plataforma fundamental para desarrolladores, ofreciendo una amplia biblioteca de personajes y animaciones de alta calidad que acelera significativamente el proceso de prototipado y desarrollo. Su capacidad de proporcionar modelos listos para usar elimina las barreras t\u00e9cnicas iniciales y permite a los desarrolladores concentrarse en la mec\u00e1nica del juego.<\/p>\n\n\n\n<p><strong>Blender<\/strong>, por su parte, confirma su posici\u00f3n como la herramienta de modelado 3D m\u00e1s completa y accesible del mercado. Su integraci\u00f3n con Facebuilder y las capacidades de edici\u00f3n de mallas permiten un nivel de personalizaci\u00f3n que seria costoso y complejo de lograr desde cero. La naturaleza open-source de Blender lo convierte en una opci\u00f3n especialmente atractiva para desarrolladores independientes y estudios con presupuestos limitados.<\/p>\n\n\n\n<p><strong>Unity<\/strong> demuestra ser mucho m\u00e1s que un motor de juegos; es una plataforma integral que proporciona herramientas sofisticadas como el sistema NavMesh, el Animator Controller y el sistema IK. Estas caracter\u00edsticas permiten implementar comportamientos complejos de IA y sistemas de animaci\u00f3n avanzados sin requerir programaci\u00f3n desde cero. La documentaci\u00f3n extensa y la comunidad activa de Unity facilitan la resoluci\u00f3n de problemas t\u00e9cnicos complejos.<\/p>\n\n\n\n<p>La sinergia entre estas tres herramientas crea un pipeline de desarrollo robusto y eficiente. Mixamo proporciona los assets base, Blender permite la personalizaci\u00f3n y optimizaci\u00f3n, y Unity ofrece la plataforma para dar vida a estos elementos con l\u00f3gica de juego sofisticada. Este enfoque demuestra que las herramientas modernas han democratizado el desarrollo de videojuegos, haciendo accesible la creaci\u00f3n de experiencias 3D de calidad profesional para desarrolladores de todos los niveles.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Referencias<\/h2>\n\n\n\n<pre class=\"wp-block-preformatted\">Autodesk Inc. (2023). Mixamo (Versi\u00f3n 1.0) [Plataforma de animaci\u00f3n 3D]. https:\/\/www.mixamo.com\/<br><br>Blender Foundation. (2023). Blender (Versi\u00f3n 4.0) [Software de modelado 3D]. https:\/\/www.blender.org\/<br><br>Unity Technologies. (2023). Unity (Versi\u00f3n 2023.3 LTS) [Motor de videojuegos]. https:\/\/unity.com\/<br><br>Unity Technologies. (2023). Unity NavMesh and Pathfinding. En Unity User Manual. https:\/\/docs.unity3d.com\/Manual\/nav-NavigationSystem.html<br><br>Unity Technologies. (2023). Unity Animation and Animators. En Unity User Manual. <br>https:\/\/docs.unity3d.com\/Manual\/AnimationOverview.html<br><br>Maty Dev. (2024, abril 18). Movimiento y animaciones en Unity 3D - Episodio 2 [Video]. YouTube. https:\/\/www.youtube.com\/watch?v=FC4IkQsEPfo<br><br>Maty Dev. (2024, abril 25). Exportar TU JUEGO En Unity Para ANDROID Correctamente [Video]. YouTube. https:\/\/www.youtube.com\/watch?v=foTtNekN9LM<br><br>Unity Technologies. (2024, septiembre 11). Starter Assets \u2013 ThirdPerson | Updates in new CharacterController package (versi\u00f3n 1.1.6) [Recurso de software]. Unity Asset Store. https:\/\/assetstore.unity.com\/packages\/essentials\/starter-assets-thirdperson-updates-in-new-charactercontroller-pa-196526<br><br><\/pre>\n\n\n\n<p><strong>Autor<\/strong>es:&nbsp;<a href=\"https:\/\/niixer.com\/?s=Diego+Gaitan+Camargo\">Diego Gait\u00e1n Camargo<\/a>, <a href=\"https:\/\/niixer.com\/?s=Juan+Camilo+Velasco+Vega\">Juan Camilo Velasco Vega<\/a><\/p>\n\n\n\n<p><strong>Editor:<\/strong>&nbsp;<a href=\"https:\/\/niixer.com\/?s=Carlos+Iv%C3%A1n+Pinz%C3%B3n+Romero\">Carlos Iv\u00e1n Pinz\u00f3n Romero<\/a><\/p>\n\n\n\n<p><strong>C\u00f3digo:<\/strong>&nbsp;<a href=\"https:\/\/niixer.com\/?s=UCMV-08\">UCMV-08<\/a><\/p>\n\n\n\n<p><strong>Universidad:<\/strong>&nbsp;<a href=\"https:\/\/niixer.com\/?s=universidad+central\">Universidad Central<\/a><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introducci\u00f3n Una gu\u00eda para el desarrollo de personajes 3D animados y la implementaci\u00f3n de sistemas de inteligencia artificial para videojuegos. El proceso abarca desde la creaci\u00f3n y personalizaci\u00f3n de personajes utilizando las plataformas Mixamo y Blender, hasta la programaci\u00f3n de comportamientos de IA avanzados en Unity. La gu\u00eda detalla elSeguir Leyendo<\/p>\n","protected":false},"author":1928,"featured_media":67421,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"colormag_page_container_layout":"default_layout","colormag_page_sidebar_layout":"default_layout","footnotes":""},"categories":[30],"tags":[473,1310,1324,1399,214,2627],"class_list":["post-67405","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-niixer","tag-blender","tag-blender-3d","tag-mixamo","tag-personajes","tag-unity","tag-video-juegos"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.2 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Personajes 3D, IA, Unity y Blender para crear Videojuegos<\/title>\n<meta name=\"description\" content=\"Una forma de desarrollar personajes 3D y Sistema de IA para la creaci\u00f3n de Videojuegos con Unity y Blender\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Personajes 3D, IA, Unity y Blender para crear Videojuegos\" \/>\n<meta property=\"og:description\" content=\"Una forma de desarrollar personajes 3D y Sistema de IA para la creaci\u00f3n de Videojuegos con Unity y Blender\" \/>\n<meta property=\"og:url\" content=\"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/\" \/>\n<meta property=\"og:site_name\" content=\"Portal de noticias de tecnolog\u00eda, Realidad Virtual, Aumentada y Mixta, Videojuegos\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/niixer\/\" \/>\n<meta property=\"article:published_time\" content=\"2025-05-24T12:10:30+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-05-31T11:06:13+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-521.png\" \/>\n\t<meta property=\"og:image:width\" content=\"975\" \/>\n\t<meta property=\"og:image:height\" content=\"604\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Diego Gaitan Camargo\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Diego Gaitan Camargo\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data2\" content=\"33 minutos\" \/>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Personajes 3D, IA, Unity y Blender para crear Videojuegos","description":"Una forma de desarrollar personajes 3D y Sistema de IA para la creaci\u00f3n de Videojuegos con Unity y Blender","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/","og_locale":"es_ES","og_type":"article","og_title":"Personajes 3D, IA, Unity y Blender para crear Videojuegos","og_description":"Una forma de desarrollar personajes 3D y Sistema de IA para la creaci\u00f3n de Videojuegos con Unity y Blender","og_url":"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/","og_site_name":"Portal de noticias de tecnolog\u00eda, Realidad Virtual, Aumentada y Mixta, Videojuegos","article_publisher":"https:\/\/www.facebook.com\/niixer\/","article_published_time":"2025-05-24T12:10:30+00:00","article_modified_time":"2025-05-31T11:06:13+00:00","og_image":[{"width":975,"height":604,"url":"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-521.png","type":"image\/png"}],"author":"Diego Gaitan Camargo","twitter_card":"summary_large_image","twitter_misc":{"Escrito por":"Diego Gaitan Camargo","Tiempo de lectura":"33 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/#article","isPartOf":{"@id":"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/"},"author":{"name":"Diego Gaitan Camargo","@id":"https:\/\/niixer.com\/#\/schema\/person\/1b245832dd915342822ba62a00e7b58b"},"headline":"Desarrollo de Personajes 3D y Sistema de IA para Videojuegos con Unity y Blender","datePublished":"2025-05-24T12:10:30+00:00","dateModified":"2025-05-31T11:06:13+00:00","mainEntityOfPage":{"@id":"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/"},"wordCount":8986,"publisher":{"@id":"https:\/\/niixer.com\/#organization"},"image":{"@id":"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/#primaryimage"},"thumbnailUrl":"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-521.png","keywords":["Blender","Blender 3D","Mixamo","Personajes","Unity","video juegos"],"articleSection":["Niixer"],"inLanguage":"es"},{"@type":"WebPage","@id":"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/","url":"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/","name":"Personajes 3D, IA, Unity y Blender para crear Videojuegos","isPartOf":{"@id":"https:\/\/niixer.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/#primaryimage"},"image":{"@id":"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/#primaryimage"},"thumbnailUrl":"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-521.png","datePublished":"2025-05-24T12:10:30+00:00","dateModified":"2025-05-31T11:06:13+00:00","description":"Una forma de desarrollar personajes 3D y Sistema de IA para la creaci\u00f3n de Videojuegos con Unity y Blender","breadcrumb":{"@id":"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/#primaryimage","url":"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-521.png","contentUrl":"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-521.png","width":975,"height":604,"caption":"Carga de personaje"},{"@type":"BreadcrumbList","@id":"https:\/\/niixer.com\/index.php\/2025\/05\/24\/desarrollo-de-personajes-3d-y-sistema-de-ia-para-videojuegos-con-unity-y-blender\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Portada","item":"https:\/\/niixer.com\/"},{"@type":"ListItem","position":2,"name":"Desarrollo de Personajes 3D y Sistema de IA para Videojuegos con Unity y Blender"}]},{"@type":"WebSite","@id":"https:\/\/niixer.com\/#website","url":"https:\/\/niixer.com\/","name":"Portal de noticias de tecnolog\u00eda, ciencia, Android, iOS, Realidad Virtual, Aumentada y Mixta, Videojuegos, computadores, todo lo mas reciente en tecnolog\u00eda","description":"Portal de noticias de tecnolog\u00eda","publisher":{"@id":"https:\/\/niixer.com\/#organization"},"alternateName":"Niixer","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/niixer.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/niixer.com\/#organization","name":"Niixer","alternateName":"Niixer.com","url":"https:\/\/niixer.com\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/niixer.com\/#\/schema\/logo\/image\/","url":"https:\/\/niixer.com\/wp-content\/uploads\/2022\/08\/logo-niixer-sin-fondo-1.png","contentUrl":"https:\/\/niixer.com\/wp-content\/uploads\/2022\/08\/logo-niixer-sin-fondo-1.png","width":140,"height":140,"caption":"Niixer"},"image":{"@id":"https:\/\/niixer.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/niixer\/","https:\/\/www.instagram.com\/niixer.tecnologia\/"]},{"@type":"Person","@id":"https:\/\/niixer.com\/#\/schema\/person\/1b245832dd915342822ba62a00e7b58b","name":"Diego Gaitan Camargo","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/secure.gravatar.com\/avatar\/1129c0a128fa6022efe91f89ea5a186e67fa0def3f541a9e0073372ddb96cf74?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1129c0a128fa6022efe91f89ea5a186e67fa0def3f541a9e0073372ddb96cf74?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1129c0a128fa6022efe91f89ea5a186e67fa0def3f541a9e0073372ddb96cf74?s=96&d=mm&r=g","caption":"Diego Gaitan Camargo"},"sameAs":["http:\/\/www.niixer.com"],"url":"https:\/\/niixer.com\/index.php\/author\/dgaitanc1\/"}]}},"jetpack_featured_media_url":"https:\/\/niixer.com\/wp-content\/uploads\/2025\/05\/image-521.png","_links":{"self":[{"href":"https:\/\/niixer.com\/index.php\/wp-json\/wp\/v2\/posts\/67405","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/niixer.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/niixer.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/niixer.com\/index.php\/wp-json\/wp\/v2\/users\/1928"}],"replies":[{"embeddable":true,"href":"https:\/\/niixer.com\/index.php\/wp-json\/wp\/v2\/comments?post=67405"}],"version-history":[{"count":38,"href":"https:\/\/niixer.com\/index.php\/wp-json\/wp\/v2\/posts\/67405\/revisions"}],"predecessor-version":[{"id":68136,"href":"https:\/\/niixer.com\/index.php\/wp-json\/wp\/v2\/posts\/67405\/revisions\/68136"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/niixer.com\/index.php\/wp-json\/wp\/v2\/media\/67421"}],"wp:attachment":[{"href":"https:\/\/niixer.com\/index.php\/wp-json\/wp\/v2\/media?parent=67405"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/niixer.com\/index.php\/wp-json\/wp\/v2\/categories?post=67405"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/niixer.com\/index.php\/wp-json\/wp\/v2\/tags?post=67405"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}