Jump to content
Sign in to follow this  
Packobilly

Build Setting no compila?

Recommended Posts

Buenas noches.

Ocurre algo que no me había pasado antes (concretamente en los tres proyectos anteriores :) ), y es que el proyecto global, con el cuál llevo ya meses, con todas sus escenas, etc. funciona perfectamente en el motor, pero al hacer el Buil Set para mac, el ejecutable no funciona como debería. Lo he compilado en modo dev para ver los errores y me da ciertos de ellos que no los da en la consola del motor. Es más, en Unity todo va como la seda y cada cosa cumple su función, pero al compilarlo, ocurre casi de todo.

Alguien lidió con este problema y tuvo final feliz?

Gracias.

Share this post


Link to post
Share on other sites

Podrias compartir los errores o el archivo de debug del compilado.

Esto puede deberse a que estas utilizando funciones que solo están disponible en una plataforma y/o el editor y por esta razón está generando errores el compilado.

  • Like 2

Share this post


Link to post
Share on other sites
Quote

Buenas tardes.

Tengo un objeto bala, que hace un spawn en el spawnpoint del player colocado a tal efecto.

Al probar el juego, y antes de morir el player, todo va bien; esto es, la bala se instancia en el sitio correcto, con su velocidad correcta, y desaparece al transcurrir el lifetime.

Una vez que el player muere, cambia el tag de player a untagged, para evitar que los enemigos sigan interaccionando con él; hago un fundido de pantalla y reaparece en el spawnpoint al comienzo del nivel, recuperando su tag de player de nuevo. Todo bien.

El problema es que ahora (tras el respawning), al disparar la bala queda paralizada en el aire, y en consola aparece el mensaje (tan común a veces, pero esta vez no doy con la tecla):

"NullReferenceException: Object reference not set to an instance of an object. Bullet_Manager. Update()...cs:25"

La línea 25 es la del  if (player.faceRight && !player.verticalLook)... y el caso es que si quito esta línea, el error me lo vuelve a dar (tras morir el player, claro) en el siguiente if.

Sé que está complicado, pero si alguien arrojase un atisbo de luz para continuar el proyecto, estaría eternamente agradecido.

Gracias de antemano!

 


public class Bullet_Manager : MonoBehaviour
{
    public float speed;
    public float lifeTime;
    Rigidbody2D rb;

    public GameObject impactPrefab;

    public int damageValue = 1;

    PlayerController player;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();

        player = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>();
  
        if (player.faceRight && !player.verticalLook)
        {
            rb.velocity = new Vector2(speed, rb.velocity.y);
        }

        else if (!player.faceRight && !player.verticalLook)
        {
            rb.velocity = new Vector2(-speed, rb.velocity.y);
            Vector3 bulletScale = transform.localScale;
            bulletScale.x *= -1;

            transform.localScale = bulletScale;
        }
        else if (player.faceRight && player.verticalLook || !player.faceRight && player.verticalLook)
        {
            rb.velocity = new Vector2(rb.velocity.x, speed);
            transform.Rotate(new Vector3(0f, 0f, 90f));
        }

        Destroy(gameObject, lifeTime);

    }

    private void OnTriggerEnter2D(Collider2D col)
    {
        Instantiate(impactPrefab, transform.position, Quaternion.identity);
        Destroy(gameObject);
    }

}

 

 

Este problema lo solucioné gracias a la ayuda de la buena gente que pulula por este foro. La bala cuando era instanciada se quedaba en el sitio donde se instanciaba, y aparecía el error de nullReferenceException...

Pues ahora, el proyecto va como la seda. Todo perfecto... hasta que lo compilo y me aparece ese mismo error en el ejecutable (modo dev), también en el Bullet_Manager,  rb.velocity = new Vector2(speed, rb.velocity.y); en el motor todo perfecto, y en la compilación falla. :(

Share this post


Link to post
Share on other sites

Para estas cosas es mejor trabajar con Singleton y estados.

1 - definir qué información nos es persistente, esto quiere decir la que reinicia cada vez que el jugador se genera (spawn), crear un clase con esta información para facilitar el reinicio.

public class PlayerInformation
{
	public int Score;
	public int Health;
}

2 - crear un singleton del componente que administra el jugador, de esta forma evitas utilizar funciones de búsquedas arbitrarias.

public class PlayerManager : MonoBehaviour
{
	public static PlayerManager Instance { get; private set; }
  	public PlayerInformation Information { get; private set; }

	private void Awake()
	{
		Instance = this;
	}
  
 	public void Respawn()
    {
      	Information = new PlayerInformation();
    }
}

3 - definir los estados del jugador.

public enum PlayerState
{
	Empty,
	Alive,
	Dead
}

Lo demás queda a imaginación --- 

El problema de referencias nulas en estos casos son por abordar mal ciertos patrones de diseños, intenta seguir algo como lo que te explique, y evita a toda costa destruir objetos, te diría que no lo hagas, olvídate de esa función por el momento. 

Edited by francoe1

Share this post


Link to post
Share on other sites

Gracias por contestar, Francoe1. Se me hace cuesta arriba todo esto. Crees que hay otra alternativa para solventar, o al menos, saber de dónde viene este error?

Share this post


Link to post
Share on other sites

Si, prueba crear un build en modo debug y conectar el Profiler con el dispositivo, de ese modo tendrías la información de la ejecución en el editor.

Si esto te suena complicado podrias eliminar el archivo de DEBUG.LOG del compilado y Abrirlo para que se escriba nuevamente el error, luego abres el LOG y tendrás una descripción específica del error mediante StackTrace.. 

También puede calibrar la sensibilidad del debug desde Player Setting en el editor de Unity antes de compilar.

 

Deberías verificar que todo lo que estés usando es compatible con la plataforma de destino, tenes que tener en cuenta que algo puede no funcionar después de compilar si se usó una directiva de compilación, como por ejemplo.

#IF UNITY_IOS
public Texture2D Textura
#ENDIF

Intenta seguir los pasos en orden.

Edited by francoe1

Share this post


Link to post
Share on other sites
Quote

Captura de pantalla 2020-02-10 a las 19.40.56.png

Hago el build en modo debug y con el Profiler conectado. Esto es lo que sale. La bala se instancia pero se queda quieta en el lugar donde aparece en la imagen (o sea, en el spawner); el error es el nullReference... apuntando a la línea 30 del script Bullet_Manager, en la cuál no veo nada fuera de lo común; y al consultar el log file, me abre la ventana de Data. Te dice algo?

Share this post


Link to post
Share on other sites

Remplaza únicamente el GameObject.Find por un reference estática a la instancia del jugador, cuánto menos cosas dejes al azar mejor funcionará. 

Share this post


Link to post
Share on other sites
11 hours ago, francoe1 said:

Remplaza únicamente el GameObject.Find por un reference estática a la instancia del jugador, cuánto menos cosas dejes al azar mejor funcionará. 

si, seguramente lo que falla es el "Find"

haz que la variable player sea "public" y asigna el objeto desde el editor

Share this post


Link to post
Share on other sites

En el PlayerController, declaré una public static PlayerController player;

En el Bullet_Manager, lo borré todo, dejando sólo el primer condicionante del primer modo de disparo,

por lo que el código original del Bullet_Manager que era así

Quote

 PlayerController player;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();

        player = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>();
  
        if (player.faceRight && !player.verticalLook)
        {
            rb.velocity = new Vector2(speed, rb.velocity.y);
        }

Quedó de esta manera, pues también le borré el FindObjectWithTag

Quote



    void Start()
    {
        rb = GetComponent<Rigidbody2D>();

        if (PlayerController.player.faceRight && !PlayerController.player.verticalLook)
        {
            rb.velocity = new Vector2(speed, rb.velocity.y);
        }

Y sigue realizando el mismo resultado. Incluso, al declarar la static en PlayerController y eliminar el FindObj del Bullet_Manager, en el motor la bala se instancia, pero no avanza; dando el consiguiente error, cosa que con el FindObjWTag no ocurre, pues todo va de lujo en el motor, no así en el build.

Otra prueba que he hecho, es dejar el Bullet_Manager solo con 

Quote

rb.velocity = new Vector2(speed, rb.velocity.y);

O sea, sin comprobar el faceRight ni el verticalLook. En este caso, el build no genera errores. (Aunque claro, la bala se instancia y ahí se queda, evidentemente; mismo resultado, pero sin errores).

 

Edited by Packobilly

Share this post


Link to post
Share on other sites

¿Podes subir fotos del error? o .log del build.

Podes estar teniendo un problema de orden de llamada, por esta razón existen 2 funciones de inicio, 1 que se llama Awake que vendría a "simular" el constructor de la clase para los componentes de Unity y otra la función Start que se llama después de Awake. 

Todas las asignaciones públicas estáticas se deben realizar en la función Awake , mientras que el resto permanecer en Start, de este modo cada vez que hagas referencia a X componente desde cualquier función que no sea Awake no vas a tener el error de orden de llamada.

Share this post


Link to post
Share on other sites

Los siguientes scripts creo yo que son los que están dando la murga:

PlayerController, desde donde controlo el mov del Player. (Claro).

ShootingManager, desde donde se controla el poder disparar o no, y desde donde se instancia la bala.

Estos dos primeros están dentro del Player.

Bullet_Manager, que está incluido en el objeto bala, y la dirige.

Pongo una foto del error en Build Dev con el error.

Estos scripts están originales. Los probé con el public static y de esta manera fallaba también en el motor, por lo que los volví a dejar con el FindObjWTag.

El error null Reference de la foto únicamente lo da cuando se pulsa disparo.

Gracias por el interés, y espero que se vea un rayo de luz en tanta oscuridad. :(

Quote


public class ShootingManager : MonoBehaviour {

    Animator myAnim;
    public float shootingRate;
    float count;

    public Transform bulletSpawner;
    public Transform verticalSpawner;
    public GameObject bulletPrefab;

    PlayerController controller;

    AudioSource myAudio;
    public AudioClip shootingSFX;

    void Start () 
    {
        myAnim = GetComponent<Animator>();
        controller = GetComponent<PlayerController>();
        myAudio = GetComponent<AudioSource>();
    }
    
    void Update () 
    {
        PlayerShooting();
    }

    void PlayerShooting()
    {
        if(Input.GetButton("Fire1") && GetComponent<AmmoManager>().haveAmmo && GetComponent<HealthManager>().canShoot && GetComponent<PlayerController>().canMove)
        {
            count += Time.deltaTime;

            if (count >= shootingRate)
            {
                if (!controller.verticalLook)
                {
                    Instantiate(bulletPrefab, bulletSpawner.position, Quaternion.identity);
                    myAnim.SetBool("shooting", true);
                    controller.moveSpeed = 50f;
                }
                else if (controller.verticalLook)
                {
                    controller.VerticalShooting();
                    myAnim.SetBool("verticalShooting", true);
                    myAnim.SetBool("shooting", false);
                    controller.moveSpeed = 0f;
                }

                myAudio.PlayOneShot(shootingSFX);
   
                GetComponent<AmmoManager>().UseAmmo();
                count = 0;
            }
        }
        else if(Input.GetButtonUp("Fire1"))
        {
            myAnim.SetBool("shooting", false);
            myAnim.SetBool("verticalShooting", false);
            controller.moveSpeed = 50f;
        }
    }
}
 

Quote


public class Bullet_Manager : MonoBehaviour
{
    public float speed;
    public float lifeTime;
    Rigidbody2D rb;

    public GameObject impactPrefab;

    public int damageValue = 1;

    PlayerController player;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();

        player = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>();

        if (player.faceRight && !player.verticalLook)
        {
            rb.velocity = new Vector2(speed, rb.velocity.y);
        }

        else if (!player.faceRight && !player.verticalLook)
        {
            rb.velocity = new Vector2(-speed, rb.velocity.y);
            Vector3 bulletScale = transform.localScale;
            bulletScale.x *= -1;

            transform.localScale = bulletScale;
        }
        else if (player.faceRight && player.verticalLook || !player.faceRight && player.verticalLook)
        {
            rb.velocity = new Vector2(rb.velocity.x, speed);
            transform.Rotate(new Vector3(0f, 0f, 90f));
        }
      
        Destroy(gameObject, lifeTime);
         
    }

    private void OnTriggerEnter2D(Collider2D col)
    {
        Instantiate(impactPrefab, transform.position, Quaternion.identity);
        Destroy(gameObject);
    }

}
 

Quote


public class PlayerController : MonoBehaviour
{
    Rigidbody2D rb;

    public float moveSpeed = 55f;

    public bool faceRight = true;

    Animator myAnim;

    public bool verticalLook;

    ShootingManager spawner;

    WallJump wallJump;

    ControlSalto controlSalto;

    AudioSource myAudio;
    public AudioClip steps;

    [HideInInspector]
    public bool canMove = true;

    void Start()
    {  
        rb = GetComponent<Rigidbody2D>();
        myAnim = GetComponent<Animator>();
        spawner = GetComponent<ShootingManager>();
        wallJump = GetComponent<WallJump>();
        controlSalto = GetComponent<ControlSalto>();
        myAudio = GameObject.FindGameObjectWithTag("pasos").GetComponent<AudioSource>();
    }

    private void FixedUpdate()
    {
       //float move = Input.GetAxisRaw("Horizontal") * moveSpeed * Time.deltaTime;

        if(controlSalto.isGrounded)
        {
            wallJump.onWall = false;
        }
    }

    void Update()
    {
        if (!wallJump.onWall && canMove)
        {
            PlayerMovement();
        }
    }

    void PlayerMovement()
    { 
    
            float move = Input.GetAxisRaw("Horizontal") * moveSpeed * Time.deltaTime;

            float vertical = Input.GetAxisRaw("Vertical");

            rb.velocity = new Vector2(move, rb.velocity.y);

            if (move > 0 && !faceRight || move < 0 && faceRight)
            {
                FlipPlayer();
            }
            else if (Mathf.Abs(move) <= 0 && vertical >= 0.1)
            {
                //myAnim.SetBool("verticalShooting", true);
                verticalLook = true;
            }

            else if (vertical <= 0)
            {
                myAnim.SetBool("verticalShooting", false);
                verticalLook = false;
            }

            myAnim.SetFloat("speed", Mathf.Abs(move));
    }
    

    void FlipPlayer()
    {
        faceRight = !faceRight;

        Vector3 curScale = transform.localScale;
        curScale.x *= -1;

        transform.localScale = curScale;
    }

    public void VerticalShooting()
    {
        if (Input.GetButton("Fire1") && verticalLook)
        {
            Instantiate(spawner.bulletPrefab, spawner.verticalSpawner.position, Quaternion.identity);
            moveSpeed = 0;
        }
    }

    public void Steps()
    {
        myAudio.PlayOneShot(steps);
    }

}
 

 

Error en Build Dev.png

Edited by Packobilly

Share this post


Link to post
Share on other sites

Te voy a dar por orden las cosas de deberías hacer.

1 - Adaptarse a utilizar los niveles de accesos como corresponde, si no especificas que x función es privada, pública, interna, protected, esto tiene razones de seguridad, pero tambien simplifica las cosas a la hora de leer código.

private void Update(){ }
private void Start(){ }

2 - Adaptarse a una nomenclatura "coding convention" esto hace que sea mucho más fácil programar y leer el código, las que te recomiendo serian las siguientes.

  • Todas las variables publicas, internas y protegidas deben empezar con mayúsculas.
  • Todas las variables privadas deben empezar con "m_"
  • Todos los parámetros de una función deben empezar con minúsculas.
  • Todas las variables dentro de una función deben empezar con minúsculas (como sus parámetros).

3 - Siempre que sea posible se debería omitir el uso de GetComponent, esto quiere decir que podes guardar referencias del componente en un campo para luego ser utilizado, esta tarea siempre que sea posible se debe realizar desde la función Awake(), es muy importante esto.

public class PlayerController : MonoBehaviour
{
    public static PlayerController Instance { get; private set; }
    private ShootingManager  m_shootingManager { get; set; }
    private AmmoManager m_ammoManager { get; set; }
    private HealthManager m_healthManager { get; set; }
    
    private void Awake()
    {
        Instance = this;
        m_shootingManager = GetComponent<ShootingManager>();
        m_ammoManager = GetComponent<AmmoManager>();
        m_healthManager = GetComponent<HealthManager>();
    }
}

4 - Intenta crear propiedades que agrupen cierto comportamiento lógico para evitar estar repitiendo código constantemente.

private bool m_availableShot 
{ 
    get 
    { 
        return m_ammoManager.haveAmmo && 
               m_healthManager.canShoot && 
               PlayerController.Instance.canMove;
    } 
}

5 - Evita usar static string, es mejor declararlos dentro de una constante

private const string _BUTTON_FIRE_1 = "Fire1";

 

 

Te dejo un código de ejemplo basado en lo que compartiste para que puedas evaluar y ver cómo mejorar el tuyo, no esta mal, pero está lejos de ser algo funcional. Ánimo!

public class PlayerController : MonoBehaviour
{
    public static PlayerController Instance { get; private set; }
    private ShootingManager  m_shootingManager { get; set; }
    private AmmoManager m_ammoManager { get; set; }
    private HealthManager m_healthManager { get; set; }
    
    private void Awake()
    {
        Instance = this;
        m_shootingManager = GetComponent<ShootingManager>();
        m_ammoManager = GetComponent<AmmoManager>();
        m_healthManager = GetComponent<HealthManager>();
    }
}

public class ShootingManager : MonoBehaviour
{
    private const string _BUTTON_FIRE_1 = "Fire1";
    
    public static ShootingManager Instance { get; private set; }
    private AmmoManager m_ammoManager { get; set; }
    private HealthManager m_healthManager { get; set; }
        
    [SerializeField]
    private BulletManager m_bulletPrefab = null;
    
    private bool m_availableShot 
    { 
        get 
        { 
            return m_ammoManager.haveAmmo && 
                   m_healthManager.canShoot && 
                   PlayerController.Instance.canMove;
        } 
    }
    
    private void Awake()
    {
        Instance = this;
        m_ammoManager = GetComponent<AmmoManager>();
        m_healthManager = GetComponent<HealthManager>();
    }
    
    private void Update()
    {
        if (Input.GetButton(_BUTTON_FIRE_1) && m_availableShot)
            OnShoot();
    }
    
    private void OnShoot()
    {
        BulletManager bullet = Instantiate(m_bulletPrefab, transform.position, transform.rotation);   
        bullet.Initialize();     
    }
}

public class BulletManager : MonoBehaviour
{
    [SerializeField]
    private float m_speed = 10;
    [SerializeField]
    private float m_lifeTime = 3;
    
    private Rigidbody2D m_rigidbody { get; set; }
    
    private void Awake()
    {
        m_rigidbody = GetComponent<Rigidbody2D>();
    }
    
    internal void Initialize()
    {
        player = PlayerController.Instance;
        //Logica del bullet.
    }
}

 

  • Like 1

Share this post


Link to post
Share on other sites

Cómo te lo has currado, tío!

Este finde me pondré a ver si lo depuro un poco guiándome por tus consejos.

Mil gracias, Francoe1. Ere un crack!

  • Like 1

Share this post


Link to post
Share on other sites

Francoe1, es un lujazo ver a Don Gonzalo usar su espada para disparar la llama de poder en el Build. El disparo funciona perfectamente. 

Aunque ahora tengo que lidiar con otros problemas más (casi todos los scripts están construidos con la misma lógica que éstos), los intentaré lidiar con los conocimientos y consejos que he aprendido con tu ayuda sobre public static, los get; set; y las instancias. A ver si puedo apañármelas.

Te estoy eternamente agradecido. 

Mil Gracias de nuevo.

PD.: No se descarte un próximo post con más quebraderos de cabeza!

Edited by Packobilly
  • Like 2

Share this post


Link to post
Share on other sites
Sign in to follow this  

×
×
  • Create New...