Błąd w Unity3D prawdopodobnie w skrypcie w C#

0

Witam, przy tworzeniu gry pojawił się błąd z którym nie mogę sobie poradzić, mogę dodać że jestem osobą początkującą w programowaniu i dla kogoś zaawansowanego może być to proste. Przejdę do szczegółów podczas odpalania gry w Unity3D wyskakuje błąd "NullReferenceException: Object reference not set to an instance of an object GameManager.SpawnujGracza() (at Assets/__Skrypty/Główne/GameManager.cs:21)

Tutaj dołączam skrypt z GameManager z voida SpawnujGracza

public void SpawnujGracza()
{
Vector3 pozycjaSpawnu = Vector3.zero;
Transform spawny = GameObject.Find("Mapa" + UnityEngine.SceneManagement.SceneManager.GetActiveScene().name + "/Spawny/" + Gracz.mojGracz.team.ToString()).transform;
pozycjaSpawnu = spawny.GetChild(Random.Range(0, spawny.childCount)).position;
GameObject mojGraczGO = PhotonNetwork.Instantiate("Gracz", pozycjaSpawnu, Quaternion.identity, 0);
mojGraczGO.GetComponent<FirstPersonController>().enabled = true;
mojGraczGO.transform.Find("TrzymaczKamery").gameObject.SetActive(true);
GetComponent<PhotonView>().RPC("SpawnujGraczaRPC", PhotonTargets.AllBuffered, Gracz.mojGracz.nick, mojGraczGO.GetComponent<PhotonView>().viewID);
}

Jak będzie coś potrzebne to będę doklejał w komentarzach, z góry dziękuję z pomoc :)

0

Twój błąd ma w komunikacie podaną linijkę. Więc jak załączasz tylko kod jednej metody, a nie całego pliku, to nie wiemy, o którą linijkę chodzi.

Poza tym kod wrzucamy na forum w odpowiednie znaczniki. I absolutnie nie myśl o tym, żeby wklejać kod do komentarzy. Po prostu edytuj posta.

Z reguły błąd NullReferenceException wyskakuje, kiedy chcesz się odnieść do zmiennej, która nie ma przypisanego żadnego obiektu. Np. w edytorze Unity nie przeciągnąłeś na dane publiczne pole skryptu przypisanego do obiektu.

Albo może Twój GameObject.Find nie znalazł obiektu o podanej nazwie... Tak nawiasem mówiąc, powinieneś unikać takich konstrukcji, bo są błędogenne. Zamiast szukać po łańcuchach można spokojnie referencję na dany obiekt zachować w skryptach. Poza tym find jest niewydajne, bo leci po całym drzewie obiektów.

0

Właśnie nie ma podanej linijki w komunikacie i dla tego mam z tym problem i dorzucam ss kodu żeby było bardziej przejrzyście niż kopiowanie całego.
Też dosyłam dodatkowy skrypt w którym jest użyte SpawnujGracza [Dodaje nową odp. ponieważ nie mam pola z możliwością edytowania w tamtym poście]
11.PNG
13.PNG
14.PNG

2
ZeuberO napisał(a):

Właśnie nie ma podanej linijki w komunikacie i dla tego mam z tym problem

Właśnie w komunikacie jest podana linijka...
screenshot-20190823023955.png

Jak na złość, akurat uciąłeś numerację linijek we właściwym zrzucie...

13.PNG

Jak klikniesz dwa razy na komunikat, to twoje IDE powinno skoczyć do linijki, której ten komunikat dotyczy...

Pewnie chodzi o ten Find. Nie znajduje obiektu o odpowiedniej nazwie, a chcesz z niego wyłuskać .transform (z nulla nie wyłuskasz).
Nad wadliwą linią napisz sobie Debug.Log(...); i w miejscu kropek wklej np. ten string poskładany z wielu części, i porównaj go sobie z nazwą obiektu, który szukasz... Możesz też wkleić cały kod ``GameObject.Find(...)``` pomijając transform (bo z nulla go i tak nie wyłuska) i zobaczysz, czy jest nullem, czy może poda Ci referencję do obiektu.

To co wypisujesz metodą Debug.Log(...), zobaczysz na konsoli, tam gdzie błędy.

Poczytaj: https://docs.unity3d.com/ScriptReference/GameObject.Find.html

Wcale nie musisz tam podawać nazwy sceny...

dorzucam ss kodu żeby było bardziej przejrzyście niż kopiowanie całego.

To nie jest przejrzyste... nie mogę zaznaczyć/skopiować tekstu, powiększyć wektorowo itp. Kolorowanie składni na 4p jest przejrzyste, tylko trzeba z niego skorzystać - wklejasz kod nie prosto w post, tylko pomiędzy odpowiednie oznaczenia.

screenshot-20190823023731.png
Zamiast przykładowego php napisz csharp.

[Dodaje nową odp. ponieważ nie mam pola z możliwością edytowania w tamtym poście]

No tak... nowi nie mają opcji edycji bodajże po jakimś czasie od publikacji...

0

Dodaję skrypt tak jak miał być.
Jak usunę .transform i Transform to program podpowiada żeby dodać publicznego lub prywatnego string spawny i po wykonaniu tej czynności GetChild ma problem bo nie pasuje do string. A z tym Debug.Log jeszcze zbytnio nie mam takiej wiedzy żeby to zrobić lub tego nie zrozumiałem :(
[Zacząłem przygodę 2 tyg temu i zaczynałem na CodeBloks i C++ Builder a tam nie używałem Debuga ]
{ Nie mogę edytować postów bo jestem nowy więc będę dodawał kolejne odpowiedzi }

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.Characters.FirstPerson;

public class GameManager : MonoBehaviour{
    void Start()    {        
    }
    void Update()    {        
    }
    public void SpawnujGracza()    {
        Vector3 pozycjaSpawnu = Vector3.zero;
        Transform spawny = GameObject.Find("Mapa" + UnityEngine.SceneManagement.SceneManager.GetActiveScene().name + "/Spawny/" + Gracz.mojGracz.team.ToString()).transform;
        pozycjaSpawnu = spawny.GetChild(Random.Range(0, spawny.childCount)).position;
        GameObject mojGraczGO =  PhotonNetwork.Instantiate("Gracz", pozycjaSpawnu, Quaternion.identity, 0);
        mojGraczGO.GetComponent<FirstPersonController>().enabled = true;
        mojGraczGO.transform.Find("TrzymaczKamery").gameObject.SetActive(true);
        GetComponent<PhotonView>().RPC("SpawnujGraczaRPC", PhotonTargets.AllBuffered, Gracz.mojGracz.nick, mojGraczGO.GetComponent<PhotonView>().viewID);
    }

    [PunRPC]
    void SpawnujGraczaRPC(string nick, int pvID, PhotonMessageInfo pmi)
    {
        GameObject nowyGraczGO = PhotonView.Find(pvID).gameObject;
        nowyGraczGO.name = "Gracz_" + nick;
        Gracz gracz = Gracz.ZnajdzGracza(pmi.sender);
        gracz.gameObject = nowyGraczGO;
    }
}

0

Jeśli dobrze policzyłem na screenie 21 linijka to jest ta:

 Transform spawny = GameObject.Find("Mapa" + UnityEngine.SceneManagement.SceneManager.GetActiveScene().name + "/Spawny/" + Gracz.mojGracz.team.ToString()).transform;

Tutaj tak naprawdę kilka rzeczy może być nullem:

  • Gracz
  • Gracz.mojGracz
  • Gracz.mojGracz.team
  • Możliwe że cały GameObject.Find zwrócił Ci nulla (i według mnie jest to najbardziej prawdopodobna opcja)

Ta ścieżka to jest w projekcie czy na scenie?

"Mapa" + UnityEngine.SceneManagement.SceneManager.GetActiveScene().name + "/Spawny/" + Gracz.mojGracz.team.ToString()
1

Musisz zrobić coś takiego...

 if( TutajNazwaObektu != null ) 
 { 

 }

Tam gdzie napisałem "TutajNazwaObiektu" to jest nazwa obiektu który powoduje wyjątek

Jeśli masz więcej pól lub obiektów które powodują wyjątek to zrób if'y zagnieżdżone czyli:

if( TutajNazwaObektu != null ) 
 { 
     if( TutajNazwaObektu != null ) 
     { 

     }
 }

Tutaj masz linka do filmiku o rozwiązaniu błędu w Unity3D:

https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=6&cad=rja&uact=8&ved=2ahUKEwizsNDtu5jkAhX_AxAIHUqcBGYQwqsBMAV6BAgJEAo&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DcNNoDGqLFOU&usg=AOvVaw0tuuf5yuY82DDWkXz6S6iE

A tutaj ogólnie w C#:

https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it

Mam nadzieję że pomogłem @Mondonno

:)

0
        Transform spawny = GameObject.Find("Mapa" + UnityEngine.SceneManagement.SceneManager.GetActiveScene().name + "/Spawny/" + Gracz.mojGracz.team.ToString()).transform;
        pozycjaSpawnu = spawny.GetChild(Random.Range(0, spawny.childCount)).position;

Jak już wspomniałem, wszelkie Find() możesz i powinieneś wyeliminować.
To co napisałeś nadaje się tylko do przeróbki. Czemu logikę wybierania losowej pozycji spawna zapisałeś w metodzie spawnującej?
Tutaj powinieneś tylko odnieść się w jakiś sposób do obiektu SpawnPoints (napisz nowy skrypt!) i poprosić o zwrócenie losowej pozycji/losowego Transforma.
Skrypt SpawnPoints powinieneś dodać jako komponent w edytorze do rodzica transformów ze SpawnPointami. Ostatecznie w Awake ten skrypt mógłby budować tablicę ze swoich dzieci, nawet przy użyciu GetChild...
Referencja do obiektu SpawnPoints powinna być umieszczona w jakimś singletonie. W ten sposób, bez żadnych Find() i szukania po nazwach obiektów, będziesz mógł dostać się do odpowiednich danych.
Możesz skryptu SpawnPoints użyć do przechowywania SpawnPointów wszystkich drużyn (tzn. jedna instancja komponentu na jedną drużynę).

ZeuberO napisał(a):

[Zacząłem przygodę 2 tyg temu i zaczynałem na CodeBloks i C++ Builder a tam nie używałem Debuga ]

Moim zdaniem skoro dopiero zaczynasz programować, nie powinieneś od razu rzucać się na taki projekt, zwłaszcza z rozgrywką sieciową.

Debug, o którym Ci napisałem, to zupełnie co innego niż Debug z Code::Blocks, czy C++ Buildera... Po prostu piszesz w odpowiednich miejscach Debug.Log(), żeby działająca gra mogła Ci wyświetlić jakieś dane w konsoli Unity. Czy to zawartość zmiennej, czy jakiś komunikat np. o tym, że dany kod się wykonuje.

0

Dziękuję wszystkim za pomoc, błąd znikną po zastosowaniu if od @Mondonno ale jak się włączy grę to sceny mają buga i się nie zmieniają. Posłucham się @Spine zrobię wszystko od nowa bardzie to uporządkuje i pozamieniam tego Find. Temat uważam za zakończony dziękuje wszystkim :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1