Noticias

¡RECUERDA QUE SI ERES UN NUEVO USUARIO, DEBES PRESENTARTE PARA PODER PUBLICAR MENSAJES! | TENEMOS CANAL OFICIAL DE TELEGRAM: t.me/unity3dspain

Problema on trasform enemigo(Resuelto)

Iniciado por ramunda, Septiembre 21, 2018, 02:57:03 PM

Tema anterior - Siguiente tema
Septiembre 21, 2018, 02:57:03 PM Ultima modificación: Septiembre 22, 2018, 03:42:43 PM por ramunda
Buenas tardes, llevo dos dias rompiendome la cabeza de este problema, veran;
 
Tengo un enemigo que me persigue a distgancia x me ataca a distancia x...eso va perfecto, a la hora de activar un simple canvas que es una imagen de sangre en la pantalla solo lo activa el primer enemigo los demas pasan de activar nada.
 
Creo que el problema puede ser en el transform(ahora lo vereis en el script), lo mismo me pasa al activar audios etc solo uno lo hace los demas aunque aga prefab no funciona.
 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
 
public class enemigoataca2 : MonoBehaviour
{
    public Transform player;
    public float velocidadenemigo;  
    public float distance;
    public AudioSource pega;
    public AudioSource camina;
    public AudioSource espadahit;
   
 
    void Start()
    {
        player = GameObject.FindGameObjectWithTag("player").transform;
        pega.enabled = false;
        camina.enabled = false;
        espadahit.enabled = false;
       
 
    }
    void Update()
    {
        distance = Vector3.Distance(transform.position, player.position);
        if (distance <= 30)
        {
            camina.enabled = true;
            pega.enabled = false;
            GetComponent<Animation>().CrossFade("Walk");
            GetComponent<walkmesh2>().enabled = false;
            GetComponent<UnityEngine.AI.NavMeshAgent>().SetDestination(player.transform.position);
           
        }
        if (distance <= 3)///AQUI DEBERIA ACTIVAR EL CANVAS SANGRE/AUDIO LO QUE SEA
        {
           GetComponent<Animation>().CrossFade("2H_skeleton_specal_attack_A");
            ManagerScript.manager.Vida -= 5f * Time.deltaTime;
            ManagerScript.manager.activasangre = true;
            pega.enabled = true;
            // player.GetComponent<Animation>().Play("Cover_sword_hit");
            espadahit.enabled = true;
        }
        else
        {
           
            espadahit.enabled = false;
            // player.GetComponent<Animation>().CrossFade("Run");
            ManagerScript.manager.activasangre = false;
        }
       
     
        if (distance >= 25)
        {
            camina.enabled = false;
            GetComponent<walkmesh2>().enabled = true;
        }
    }
}

 
Donde le digo que si la distancia es-= 3 es donde deberia activarlo.
 
y creo que el problema viene de : player = GameObject.FindGameObjectWithTag("player").transform;
 
que solo calcula la distancia de el player en un solo enemigo.
 
 
 
Agradeceria una idea gracias!!!
 
 
 
 

Si el script lo tiene cada enemigo está bien, calcula la distancia entre ese enemigo y el player, yo creo que el problema está en la condición de salida, dejas la asignación
 
Cita de: ramunda date=1537534623ManagerScript.manager.activasangre = false;
   


en manos del script del enemigo, sería mejor que lo gestionaras dentro del ManagerScript, de esta forma puedes controlar cuando se desactiva, por ejemplo;
 
Puedes hacer que se desactive después de X segundos con una corrutina:
 

...
public void ActivarSangre ()
{
if(!activo)
   StartCoroutine ("CorrutinaSangre");
}
private IEnumerator CorrutinaSangre ()
{
activo = true;
//Activas el UI.
yield return new WaitForSeconds(tiempoDeEspera);
//Desactivas el UI.
activo = false;
}
...

 
De esta forma cada vez que entre un enemigo en el rango llama la función.
 
También puedes crear una variable con la distancia y pasarla al ManagerScript cuando no haya ninguno cerca dejas de mostrar la distancia... de todas formas intenta hacer que sea el ManagerScript el que se encargue de cambiar a false la variable...
 
Imagina que matas al enemigo, la distancia en el último frame será menos de 3, pero en el siguiente frame no entra en la condición porque ya no existe el objeto y no se llama su Update.

Gracias juanmma_teso, lo que me dices tiene mucho sentido, pero el problema es que en la coorutina no puedo saber cuento tiempo el enemigo estara en la distancia de <3 en frente de el player, se puede tirar un mimuto como 3 segundos, si estipulo en tiempo se parara.
 
igualmente lo he provado...y algo he echo mal porque no funciona , se activa la sangre al empezar el juego luego se va y el enemigo al pegarme no se activa :(
 
 
 
:(
 
la parte de el enemigo simplemente la he dejado asi:
 

if (distance <= 3)
        {
                GetComponent<Animation>().CrossFade("2H_skeleton_specal_attack_A");
                ManagerScript.manager.Vida -= 5f * Time.deltaTime;
                ManagerScript.manager.activasangre = true;
                pega.enabled = true;
                espadahit.enabled = true;
          }

 
y el manager asi con la coorutina que me sijeristes:
 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using UnityEngine.UI;
public class ManagerScript : MonoBehaviour
{
    public static ManagerScript manager;
    public float Vida;
    public float Mana;
    public float Manamaximo = 100f;
    public float manaReg;
    public GameObject player;
    public GameObject sangre;
    public bool activasangre;
    private float tiempoDeEspera = 5f;
    public float experiencia = 0f;
    public Text exptext;
    //public bool activamusicabatalla;
    //public AudioSource batalla;
    public GameObject playermuerto;
 
    void Awake()
    {
        if (manager == null)
        {
            DontDestroyOnLoad(gameObject);
            manager = this;
        }
        else if (manager != this)
        {
            Destroy(gameObject);
        }
    }
    void Start()
    {
        activasangre =false;
    }
 
    void Update()
    {
        exptext.text = "Experiencia: " + experiencia.ToString();
        if (activasangre = true)
        {  
            StartCoroutine("CorrutinaSangre");
        }
        else if (activasangre = false)
        {
            sangre.SetActive(false);
        }
               
            if (Mana <= Manamaximo)
        {
            StartCoroutine(RegainHealthOverTime());
           
        }
        if (Vida <= 0)
        {
            player.SetActive(false);
            playermuerto.SetActive(true);
        }
    }
    IEnumerator RegainHealthOverTime()
    {
        while (Mana < Manamaximo)
        {
            manaregen();
            yield return new WaitForSeconds(5);
        }
    }
    public void manaregen()
    {
        Mana += manaReg*Time.deltaTime;
    }
    private IEnumerator CorrutinaSangre()
    {
        sangre.SetActive(true);
        yield return new WaitForSeconds(tiempoDeEspera);
        sangre.SetActive(false);
    }
}

 
pero la he liado y nada va a cordes.
 
 

Pensalo así, que tiene que ver el comportamiento de ataque de un enemigo con la sangre que se muestra en pantalla ? ---> absolutamente nada:
 


  •    Enemigo: Provoca un daño, avisa al objetivo (Player) que debe reducir su salud


  •    Player: Recibe el msj, reduce su salud


  •    UI Manager: "Nota" que le bajo la salud a alguien, al player, entonces hace lo que debe hacer (mostrar la sangre)


Si seguis el camino de poner if, tocar condiciones, probar esto y aquello hasta que algo aislado te funcione estás metiendote en otro nuevo problema si las condiciones cambian a futuro, por eso necesitas un sistema algo más estable (nada complicado), con objetos con tareas bien definidas.
 
Dicho todo esto, seguramente sea un "problema de static", osea por comodidad optaste por hacer una static (sea un singleton o una variable) y accederla de cualquier lado, cosa que está en principio mal para manejar este aspecto (por esta razón en programación el alcance y accesibilidad de variables es de suma importancia). Si ves lo siguiente:
 

if (distance <= 3){
...
ManagerScript.manager.activasangre = true;
    ...
}
else{
...
ManagerScript.manager.activasangre = false;
}

 
... Si esto lo evaluas para los tantos enemigos que tengan este script, uno dice true y el otro lo contradice con false y si le sumás el orden en el que los scripts se ejecutan estás dejando todo a la suerte. Lo mejor sería separar un poco los tantos como te comentaba arriba.
 
Ojo quizás sea cualquier otra cosa pero esa parte es la que más me llama la atención.
 
Lo que te propuso @juanma_teso debería funcionar, tenés que definirla en tu manager(supongo) y nada más tenés que dispararla desde el enemigo, que el enemigo llame al método público, el manager maneja si debe correrlo o no.
 
Igual hay cosas como :
 

if (activasangre = true)
{  
StartCoroutine("CorrutinaSangre");
}
else if (activasangre = false)
{
sangre.SetActive(false);
}

 
ojo que = no es lo mismo que == , y si estás evaluando un true y no se da no tenés que ver si es falso, usá solo un else.
 
Saludos
 
 

Gracias   @lightbug
 
Desgraciadamente sigue sin funcionar, pero despues de vuestra ayuda intentare enfocarlo de otra manera.
 
Muchas gracias
 
 

La cosa debe ir por aquí...
 

if (activasangre = true)
        {  
            StartCoroutine("CorrutinaSangre");
        }
else if (activasangre = false)
        {
            sangre.SetActive(false);
        }

 
...debería ser...
 

if (activasangre == true)
        {  
            StartCoroutine("CorrutinaSangre");
        }
else if (activasangre == false)
        {
            sangre.SetActive(false);
        }

 
...aunque mejor así:
 

if (activasangre)
        {  
            StartCoroutine("CorrutinaSangre");
        }
else    {
            sangre.SetActive(false);
        }

 
Creo. 

A ver no... lo que yo puse es: "si no está activo":
 

if(!activo)
es lo mismo que
if(activo==false)

 
es decir que si la sangre no está activa, corremos la corrutina, dentro de la corrutina asignamos true a "activo" para que no se vuelva a llamar la corrutina si está activa o si otro enemigo la ha llamado antes... una vez termina la corrutina, es la propia corrutina quien cambia "activo" a false cuando han pasado dos segundos.
 
Ahora bien, esto era una solución, lo mejor es efectivamente hacer un evento cuando cambie la vida... peeeero en la programación hay muchas maneras conseguir lo mismo; intentemos creando un número entero, éste es el número de enemigos dentro del rango.
 

... Script enemigo.
if(distancia <=3)
   ManagerScript.manager.AgregarEnemigo();
...
... Script Manager.
int numeroEnemigos = 0;
public void AgregarEnemigo()
{
numeroEnemigos++;
}
void LateUpdate ()
{
Vida -= numeroEnemigos * 5f * Time.deltaTime;
sangre.SetActive(numeroEnemigos > 0);
numeroEnemigos = 0;
}

 
Así no cambias mucho lo que tienes, pero te recomiendo mucho que empieces a averiguar cómo funcionan los eventos, de esta forma no estás llamando constantemente el "SetActive" o asignando un valor a numeroEnemigos.

Septiembre 22, 2018, 03:40:03 PM #7 Ultima modificación: Septiembre 22, 2018, 03:41:30 PM por ramunda
@debug
Cita de: ramunda date=1537623603@debug
   


mil gracias a los 3 , ya salio algo entre todas las posibles opciones!!! soys geniales! mil gracias por la ayuda y por el tiempo prestado!!!
 
Un abrazo!!
 
 
 
 

Si está resuelto, marca la mejor respuesta, plis.

Etiquetas: