La recolección de pociones en Unity es más clara y mantenible cuando el objeto jugador se referencia una sola vez y se notifica con métodos específicos. Aquí verás cómo vincular el PlayerController desde el script Collectable, llamar a los métodos de curación y maná, y preparar las pociones en escena con diferencias visuales claras. Todo con C# y buenas prácticas para evitar errores comunes.
¿Qué solucionamos al recoger pociones en Unity?
Al recoger una poción, ya no se notifica al game manager (como con las monedas en el switch), sino directamente al PlayerController. Como el jugador no es un singleton, se accede por nombre con GameObject.Find y luego con GetComponent para invocar los métodos correctos. Además, se evita el error de declarar la variable del jugador dentro de cada caso del switch.
Objetivo: notificar al jugador al tomar pociones de vida o de maná.
Cambio clave: de game manager a PlayerController en la lógica de recolección.
Problema detectado: variable duplicada dentro del switch marcándose en rojo.
Solución: mover la referencia del jugador fuera del switch e inicializarla una sola vez.
¿Por qué no usar un singleton para PlayerController?
Porque el PlayerController no es un singleton. Se accede al objeto con nombre en escena usando GameObject.Find("Player") y, desde ahí, al componente del jugador. Es directo y suficiente para esta necesidad.
¿Cómo evitar el conflicto dentro del switch?
El switch no delimita ámbitos como un if/else. Declarar la misma variable en dos casos distintos puede generar conflicto. Se declara una sola referencia al jugador fuera del switch (incluso como campo privado) y se inicializa en Start. Así desaparecen los errores y el código queda más limpio.
¿Cómo notificar al jugador con GameObject.find y getcomponent?
Primero se localiza el objeto jugador por nombre y, después, se llama al componente para aplicar el efecto de la poción. Las llamadas son directas y expresivas: CollectHealth para vida y CollectMana para maná, pasando this.value como cantidad.
// Búsqueda inicial (ejemplo local):GameObject player = GameObject.Find("Player");// Notificar recolección de poción de vida:player.GetComponent<PlayerController>().CollectHealth(this.value);// Notificar recolección de poción de maná:player.GetComponent<PlayerController>().CollectMana(this.value);
¿Dónde inicializar la referencia al player?
Mejor en Start, una sola vez. Así evitas repetir código en cada caso del switch y eliminas el error por duplicidad.
// En Collectable:privateGameObject player;voidStart(){// Ojo: GameObject con G mayúscula es la clase de Unity.// gameObject con g minúscula es la instancia asociada al script. player = GameObject.Find("Player");}// Luego, cuando corresponda:player.GetComponent<PlayerController>().CollectHealth(this.value);player.GetComponent<PlayerController>().CollectMana(this.value);
Clave: una sola referencia compartida en la clase evita declarar variables dentro del switch y simplifica las llamadas.
¿Qué diferencia hay entre GameObject y gameObject?
GameObject (mayúscula): la clase de Unity para buscar y manipular objetos en escena.
gameObject (minúscula): la instancia del objeto al que está asociado el script actual.
¿Cómo configurar y diferenciar las pociones en escena?
Se parte de un único asset de poción en Sprites. Se arrastra a la escena, se le añade el scriptCollectable, y se configura su tipo y valor. Luego se duplica para la versión de maná, se tiñe el color para distinguirlas y se añade un Circle Collider a cada una para que puedan recolectarse.
¿Qué valores y tipos asignar en el inspector?
Asignar el script Collectable al objeto poción.
Elegir tipo: poción de vida para la primera. Valor: 100 puntos (mitad de 200 de vida total).
Duplicar el objeto (Command D o Control D).
Configurar la segunda como poción de maná. Valor: 15 puntos de maná.
¿Cómo distinguir visualmente las pociones con el sprite renderer?
Usar el sprite renderer y su tinte de color.
Para vida: seleccionar rojo con el cuentagotas.
Para maná: seleccionar azul.
Si el color queda muy intenso, bajar la tonalidad. Elegir un tono más suave para no confundirse con el fondo.
¿Qué colisionador usar para activar la recolección?
Añadir un circle collider a cada poción.
Ajustar el tamaño al área deseada de recolección.
Probar en Play: ambas pociones deben recolectarse al tocarlas. Es un buen indicio de que la lógica funciona.
¿Quieres seguir afinando esta mecánica o te quedan dudas sobre la referencia al jugador o la configuración del sprite renderer? Comparte tus preguntas y casos en los comentarios.
!usa ctrl + m
Cambié los colores de las pociones usando Krita
dupliqué las pociones, luego ctrl + m para que aparezca la ventana de filtros y ajusté el Hue
Grazie lml
Yo me tome la libertad de crear una nueva poción para el mana, que opinan?? 😀
.
Otra alternativa para que dentro del switch no entren en conflicto variables de igual nombre: agrega llaves. { }
privatevoidCollect(){ hasBeenCollected =true;switch(itemType){caseItemType.Coin:{GameView.sharedInstance.coins+=this.value;break;}caseItemType.HealthPotion:{GameObject player =GameObject.Find("Player"); player.GetComponent<PlayerController>().RecoverHp(this.value);break;}caseItemType.ManaPotion:{GameObject player =GameObject.Find("Player"); player.GetComponent<PlayerController>().RecoverMp(this.value);break;}}}
Nótese que los dos puntos ' : ' siguen ahí, y que las llaves se sitúan después de ellos.
Yo he decidido crear una tercera, la deadPotion, la idea es que al tomarla el personaje muere, aunque no logro hacerla funcionar, dejaré la pregunta en la otra sección.
Por qué recoge las pociones? No debería estar el circle collider como isTrigger?
Porque el Capsule Collider del Player is Trigger.
Correcto debe de estar seleccionado:
Lo hizo con la moneda. Con las posiones no lo hizo y me parece raro que le funcionase;La logica consite en que al momento de Ontrigger detecte la biñeta del jugador, oculte el GameOdjet por medio de la desactivacion del Sprite Render y el Mismo Circle Collider 2D
No entiendo porque dice que playerController no tiene sharedInstance si le habiamos implementado singleton con el antes.
Tengo 2 preguntas:
1 - En vez de acceder al PlayerController inicializando una variable usando el "GetComponent<PlayerControlller>" no es más facil ir a Player controller y establecer un SINGLETON?
2- Por otro lado, luego de crear el objeto player. Por que lo inicializa en el start? A mi el código me funciona sin hacerlo. Cual sería el objetivo? No es redundante?
He creado una tercera poción, deadPotion, la idea es que al tomarla el personaje muere, pero no logro hacerla funcionar.
El problema es que al darle play, el personaje muere inmediatamente :c
Tal vez ven el error?
Lo he solucionado, al parecer esta línea ocasionaba el error.
Cambie los colores usando photoshop. Para el que no tenga, puede usar Photopea que es online y gratuito.
Dejo los sprites de las pociones por si le sirve a alguien
Me parece extraño que se declare los puntos de vida y maná en el PlayerController y las monedas en el GameManager, ya que se declaro un método CollectObject() que recibiria distintos tipos de objetos Collectable
yo lo entiendo así, la vida y el mana son atributos propios del player pero las monedas no son propios de este sino que le pertenecen a el. como contigo tu energía, (animo) conocimientos, etc. pero tu celular tus dinero esta contigo pero no son parte de ti.
ademas el método collectobject se ocupa de interactuar con el objeto para que el cambio se haga donde corresponda.