Jump to content
Unity Insider Forum
Sign in to follow this  
Blissm

"Animator is not playing an AnimatorController"

Recommended Posts

Heyho, ich hab's geschafft..!

...oder auch nicht. 😅

Aber der Reihe nach.. Bei meinem Projekt Mega Bliss Bros. habe ich schon seit längerer Zeit versucht eine Charakter-Auswahl im Titel-Menü zu integrieren, und nach vielen Versuchen und vielem Lernen hab ich es jetzt auch tatsächlich geschafft. Jedoch wartete dort natürlich gleich schon der nächste Fehler auf mich.. 😬

Nämlich kann ich zwar mit jedem der Charaktere spielen und auch von Level zu Level weiter springen, aber wenn der Charakter stirbt will er einfach nicht mehr respawnen. Es hängt dann in Dauerschleife in der Todes-Animation fest anstatt dass es den Animator triggert zu respawnen. 🤷‍♂️

Animator is not playing an AnimatorController
UnityEngine.Animator:SetTrigger(String)
CharacterController2D:Respawn(Vector3) (at Assets/Scripts/CharacterController2D.cs:306)
GameManager:ResetGame() (at Assets/Scripts/GameManager.cs:192)
<KillPlayer>c__Iterator0:MoveNext() (at Assets/Scripts/CharacterController2D.cs:267)
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

Das ist was mit die Konsole dazu ausspuckt. Das Auswählen der Charaktere funktioniert ßber die PlayerPrefs mit SetInt und GetInt. Jeder Charakter hat den Character-Controller Skript mit individuellen Anpassungen, jeder ist als "Player" getaggt und ihr gemeinsames Parent hat den Character-Selection Skript. Die Spielfigur wird durch den "Player"-Tag erkannt.

Ausschnitt aus dem Character-Controller Skript:

// (...)
    
    // public function to apply damage to the player
	public void ApplyDamage (int damage) {
		if (playerCanMove) {
			playerHealth -= damage;

			if (playerHealth <= 0) { // player is now dead, so start dying
				PlaySound(deathSFX);
				StartCoroutine (KillPlayer ());
			}
		}
	}

	// public function to kill the player when they have a fall death
	public void FallDeath () {
		if (playerCanMove) {
			playerHealth = 0;
			PlaySound(fallSFX);
			StartCoroutine (KillPlayer ());
		}
	}

	// coroutine to kill the player
	IEnumerator KillPlayer()
	{
		if (playerCanMove)
		{
			// freeze the player
			FreezeMotion();

			// play the death animation
			_animator.SetTrigger("Death");
			
			// After waiting tell the GameManager to reset the game
			yield return new WaitForSeconds(2.0f);

			if (GameManager.gm) // if the gameManager is available, tell it to reset the game
				GameManager.gm.ResetGame();
			else // otherwise, just reload the current level
				SceneManager.LoadScene(SceneManager.GetActiveScene().name);
		}
	}
    
// (...)

	// public function to respawn the player at the appropriate location
	public void Respawn(Vector3 spawnloc) {
		UnFreezeMotion();
		playerHealth = 1;
		_transform.parent = null;
		_transform.position = spawnloc;
		_animator.SetTrigger("Respawn");
	}
    
// (...)

Ausschnitt aus dem Game-Manager Skript:

// (...)    

	Vector3 _spawnLocation;
    
// (...)


        // set things up here
    void Awake () {
		// setup reference to game manager
		if (gm == null)
			gm = this.GetComponent<GameManager>();

		// setup all the variables, the UI, and provide errors if things not setup properly.
		setupDefaults();
       
    }

// (...)

    	// setup all the variables, the UI, and provide errors if things not setup properly.
	void setupDefaults() {
		// setup reference to player
		if (_player == null)
			_player = GameObject.FindGameObjectWithTag("Player");
		
// (...)

        // get current scene
        _scene = SceneManager.GetActiveScene();

		// get initial _spawnLocation based on initial position of player
		_spawnLocation = _player.transform.position;

// (...)

		// get the UI ready for the game
		refreshGUI();
	}

// (...)

        // public function to remove player life and reset game accordingly
    public void ResetGame() {
		// remove life and update GUI
		lives--;
		refreshGUI();

		if (lives<=0) { // no more lives
			// save the current player prefs before going to GameOver
			PlayerPrefManager.SavePlayerState(score,highscore,lives);

			// load the gameOver screen
			SceneManager.LoadScene(levelAfterGameOver);
		} else { // tell the player to respawn
			_player.GetComponent<CharacterController2D>().Respawn(_spawnLocation);
		}
	}

Hoffe die Ausschnitte sind brauchbar. 😅 Aber da es mit einem einzelnen Charakter ja einwandfrei funktioniert hat, denke ich dass die anderen Sachen irrelevant sind. Jedenfalls komme ich hier nicht weiter, aber vielleicht habt ihr ja eine Idee..?

Share this post


Link to post
Share on other sites

Ich denke wir brauchen noch mehr Informationen um zu helfen, bei den aktuell gezeigten Codeteilen fällt mir nichts auf.

Die Fehlermeldung besagt, daß am aktuellen GameObjekt zwar ein Animator hängt aber dieser keinen Controller hat und daher der Aufruf:

_animator.SetTrigger("Respawn");

ins Leere geht.

Dein Problem liegt aber vermutlich woanders. Ich denke das das GameObjekt (mit dem entsprechend ausgewählten Spieler) für den Respawn-Prozeß nicht richtig konfiguriert ist.

Share this post


Link to post
Share on other sites

Hmmm, also während diese Meldung kommt wird mir im Animator selbst angezeigt was er macht. Scheint alles normal, abgesehen von dem Respawn. Das seltsame ist dass es funktioniert wenn der Charakter der gespielt wird voher in der Szene schon aktiv ist, aber wiederum nicht wenn auch nur ein weiterer aktiv ist, oder garkeiner.

Und ich hab festgestellt dass wenn dieser eine Charakter aktiv ist, ich aber einen anderen im Menß anwähle zum spielen, ich diesen zwar auch spielen kann, aber bei einem Tod der zuvor aktivierte respawnt anstelle des Charakters den ich gerade gespielt habe. (Er ist jedoch inaktiv, weil durch den Int ja der andere aktiviert ist. Ich merk es nur daran, dass er den Parent verlässt.) 

Heißt das dass das Spiel einfach nach dem falschen Controller sucht..? Aber was kann ich da machen? 🤔 Sollte ich vielleicht den Parent respawnen, anstelle des Charakters selbst? (Andererseits hat der mit dem Animator ja nix zu tun..) 😅

Achja.. und _animator.SetTrigger("Victory"); funktioniert ganz normal. Das find ich auch äußerst kurios in Anbetracht dessen das behauptet wird da wäre kein Controller.

Ich schau mal ob ich noch was zum zeigen finden kann, aber eigentlich hab ich alles zum Thema Animator und Respawn oben schon drin.. 🤷‍♂️

Share this post


Link to post
Share on other sites

Ich vermute mal du hast nur einen Animator aber mehrere Spieler. Beim Respawn  hängt der Character-Controller dann vermutlich an einem Spieler der keinen gßltigen Animation-Controller hat (und daher kann er die Respawn-Animation nicht ausfßhren und wirft diese Fehlermeldung). Das sind aber alles nur Vermutungen, da ich die Objekt-Hierarchie in deinem Game nicht kenne.

Ändere deinen Quellcode mal wie folgt ab und klicke auf die geworfene Fehlermeldung, dann sollte er das entsprechende GO anspringen welches den Fehler verursacht (alle Ausführungen werden an dieser Stelle unterbrochen, damit du dir die Situation in Ruhe anschauen kannst):
 

	// public function to respawn the player at the appropriate location
	public void Respawn(Vector3 spawnloc) {
		UnFreezeMotion();
		playerHealth = 1;
		_transform.parent = null;
		_transform.position = spawnloc;

                if (_animator.runtimeAnimatorController==null) {
                   Debug.Log("Animation-Controller ist nicht korrekt gesetzt! (Klick mich)", gameObject);
                   Debug.Break();
                } else {
		   _animator.SetTrigger("Respawn");
                }
	}


 

Share this post


Link to post
Share on other sites

Ändert leider nix. Kommt nur die gleiche Fehlermeldung wie vorher. Es hat auch jeder Charakter seinen ganz persönlichen Animation-Controller.

2.thumb.PNG.2873a305fa356f97d7531413d2276868.PNG

1.PNG.df0afc8584d42c8b6074bd6ea7ab8aae.PNG

Share this post


Link to post
Share on other sites

Wenn er in den Debug nicht reinläuft, dann setz den Debug mal so:

// public function to respawn the player at the appropriate location
	public void Respawn(Vector3 spawnloc) {
		UnFreezeMotion();
		playerHealth = 1;
		_transform.parent = null;
		_transform.position = spawnloc;

 	   _animator.SetTrigger("Respawn");
       Debug.Log("Animation-Controller ist nicht korrekt gesetzt! (Klick mich)", gameObject);
       Debug.Break();
	}

Kann es sein, daß der Charakter deaktviert wurde und im Skript dann versucht wird auf einen inaktiven Controller zuzugreifen?

Wenn die FM kommt und du in den Debug.Break() reinläufst schau dir mal das Objekt an indem du dann auf die Logausgabe klickst...

PS:
Warum nimmt er im Respawn den Parent zu "Player" weg, dass macht irgendwie keinen Sinn, da alle Charaktere unter "Player" liegen sollten?
Wenn ich die Technik so sehe, dann sollte immer 1 GO (= der Charakter) unter dem Player aktiv sein.

In der Charakterauswahl werden dann nur die GOs unter dem "Player"-GO aktiviert oder deaktivert, also so, dass immer ein GO unter "Player" aktiv ist.

Share this post


Link to post
Share on other sites

Huuuch, auf einmal kommt jetzt doch ne andere Fehlermeldung (ohne dass ich jetzt nochmal was geändert hätte 🤨) anstatt der voherigen, nämlich:

NullReferenceException: Object reference not set to an instance of an object
GameManager.ResetGame () (at Assets/Scripts/GameManager.cs:192)
CharacterController2D+<KillPlayer>c__Iterator0.MoveNext () (at Assets/Scripts/CharacterController2D.cs:267)
UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) (at C:/buildslave/unity/build/Runtime/Export/Coroutines.cs:17)

Aach, welche der beiden Meldungen kommt hängt davon ab, ob ich die Charaktere alle an oder aus hab. Wenn sie alle aktiviert sind zum Start dann kommt das mit dem Animator.

Share this post


Link to post
Share on other sites
	_player.GetComponent<CharacterController2D>().Respawn(_spawnLocation);

Dein GameManager muss eine Referenz auf 1 aktives GO (=Character) unter "Player" haben ansonsten geht dieser Aufruf da schief.

Zu jeder Zeit sollte unter "Player" 1 aktives GO sein (= der aktive Charakter) wenn das nicht so ist läuft etwas schief.

Geh am besten mal auf deinen GameManager und mach den aktiven Spieler (= Variable "_player") dort "public" damit du siehst, welcher Charakter gerade aktiv sein sollte.

Share this post


Link to post
Share on other sites

Er nimmt nich den parent von "Player" weg sondern den parent vom Charakter, also das "Player"-Objekt.

Das hier ist der komplette Selection-Script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// based primary on a quick tutorial by "N3K EN"

public class CharacterSelection : MonoBehaviour {

    private GameObject[] characterList;
    private int indexx;

    private void Start()
    {
        indexx = PlayerPrefs.GetInt("CharacterSelected");

        characterList = new GameObject[transform.childCount];

 // TEST       characterList[1].SetActive(true);        TEST //

        // Fill the array with our characters
        for (int i = 0; i < transform.childCount; i++)
            characterList[i] = transform.GetChild(i).gameObject;
        
        // Toggle off their renderer
        foreach (GameObject go in characterList)
            go.SetActive(false);

        // Toggle on the selected character
        if (characterList[indexx])
            characterList[indexx].SetActive(true);
    }

        public void ChangeCharacter(int index)
        {
            indexx = index;
            PlayerPrefs.SetInt("CharacterSelected", index);
            int myPrefsValue = PlayerPrefs.GetInt("CharacterSelected");
        }

Beim laden der Scene wird der entsprechende Charakter je nach int aktiviert, was auch funktioniert.

Share this post


Link to post
Share on other sites
vor 1 Minute schrieb Blissm:

Er nimmt nich den parent von "Player" weg sondern den parent vom Charakter, also das "Player"-Objekt.

Das hier ist der komplette Selection-Script:

Beim laden der Scene wird der entsprechende Charakter je nach int aktiviert, was auch funktioniert.

Mein ich ja macht keinen Sinn, wozu?

Share this post


Link to post
Share on other sites

Was in der CharacterSelection fehlt ist das Aktualisieren des GameManagers, der halt eine Referenz auf den aktiven Charakter und die wird oben nicht neu gesetzt!

Poste mal den Quellcode vom GameManager vor allen wo er die Referenzen setzt.

Und geh mal auf deinen GameManager-Code und mach den aktiven Spieler (= Variable "_player") dort "public" damit du siehst, welcher Charakter gerade aktiv ist, dieser sollte dem Charakter entsprechen den du ausgewählt hast.

Share this post


Link to post
Share on other sites

Hmm, stimmt.. 🤔 Das mit dem herausnehmen kapier ich auch nicht.. 😂 sieht jedenfalls so hier aus:3.thumb.png.074c46a5c4e06eb8b1488a0c8687f819.png

 

Share this post


Link to post
Share on other sites

Der Inspector steht noch auf "June" so sieht man nix.
Macht fĂźr mich jedenfalls kein Sinn den C (Charakter) vom Parent zu lĂśsen.
Glaub aber das Problem liegt eher am GameManager.... siehe Kommentare oben

Sowas fehlt meiner Meinung nach (ist nur eine fiktive Methode da ich die GameManager-Klasse nicht kenne):

    // Toggle on the selected character
        if (characterList[indexx]) {
           characterList[indexx].SetActive(true);
           GameManager.gm.SetActivePlayer(characterList[indexx]);
           // oder GameManager.gm._player = characterList[indexx];
        }

 

Share this post


Link to post
Share on other sites

"June" war dort gerade der Charakter den ich gespielt habe, der nicht respawnen wollte. Stattdessen ist der Charakter "Pulli" rausgesprungen. 🤷‍♂️

Das mit dem GameManager schau ich mir jetzt nochmal an.

Share this post


Link to post
Share on other sites

Tatsache, im Inspector hat er Pulli drin. Wenn ich zu Beginn jedoch jeden Charakter inaktiv habe, bleibt das Feld leer. Der GameManager sucht den Spieler nach Tag, weil ich mir nicht besser zu helfen wusste. 😅

Share this post


Link to post
Share on other sites

Ist es eigentlich normal dass der GameManager Skript inaktiv wird, sobald man auf Play drßckt..? Oder ist das nur wegen des Fehlers? 4.PNG.bba6f36c6032e5c50a933e01a10c4866.PNG

Share this post


Link to post
Share on other sites

Eine Exception, die in einem MonoBehaviour-Event (Start, Update, ...) fliegt (und nicht gefangen wird), sorgt in der Tat dafĂźr, dass die Komponente deaktiviert wird.

Share this post


Link to post
Share on other sites

Hier eine Änderung für deinen GameManager. Dabei musst du danach alle deine Charaktere den GameManager in dem neuen Array zuweisen!

Sollte dein GameManager ßber die Szenen hinweg aber nicht persistent sein, dann ist es aber ggf. nicht die optimalste LÜsung, da du dann hier in jeder Szene diese Referenzen neu setzen mßsstest... (sollte der GameManager in jeder neuen Szene neu erzeugt werden, dann mßsstest du doch wieder ßber den Childs des GOs "Player" gehen)

 public GameObject[] characters; // Hier alle Charaktere zuweisen im Inspector

 void setupDefaults()
    {
        int selected = PlayerPrefs.GetInt("CharacterSelected", 0);
        // Alle Charaktere deaktiveren
        foreach (GameObject character in characters) {
           character.SetActive(false);
        }
        
        // Gewählten Charakter aktivieren (startet bei 0!)
        characters[selected].SetActive(true);

        // setup reference to player
        _player = characters[selected];

	//if (_player == null) _player = GameObject.FindGameObjectWithTag("Player");

 }

 

Share this post


Link to post
Share on other sites

Soo, hab das jetzt mal ausprobiert. Funktioniert jetzt einwandfrei~ 😇 Danke schonmal für die groooße Hilfe!

Aber ja, ich muss es bei jeder Szene einzeln angeben. Beim GameManager trag ich nämlich unter anderem auch immer den Level ein der als nächstes geladen werden soll.

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...