Jump to content
Unity Insider Forum

Follower soll Collectables einsammeln


Garzec

Recommended Posts

Guten Abend,

ich versuche die Libelle Sparx aus Spyro nachzubauen, wer nicht weiß, wer das ist hier ein Video

Nähert sich Spyro (der Drache) Kristallen, so fliegt Sparx (die Libelle) zu den Kristallen und lässt diese zum Spieler fliegen. Die Logik, dass ein Kristall zum Spieler fliegt habe ich bereits, sagen wir einfach mal die Methode heißt bei mir 

collectable.StartMovingToPlayer();

So nun hat der Follower einen Rigidbody, damit die Items von seinem Trigger erfasst werden. Da diese Items alle von der abstracten Klasse "Collectable" erben, kann ich im Trigger prüfen, ob das Objekt ein Collectable ist und kann die benötigten Methoden des Items aufrufen.

    private List<Collectable> collectablesToCollect = new List<Collectable>(); // alle gefundenen Collectables
    private bool isCollecting = false; // sammelt der Follower aktuell schon ein Collectable ein?
    private float movementSpeed = 10; // Sammelgeschwindigkeit

    private void Update()
    {
        if (CollectablesInRange()) // Irgendwelche Collectables in Reichweite?
        {
            if (!isCollecting) // Aktuell noch nicht am Einsammeln?
                MoveToCollectable(); // Dann das Item einsammeln
        }
    }

    private void OnTriggerEnter(Collider col)
    {
        Collectable collectable = col.GetComponent<Collectable>();

        if (collectable != null) // ist das gefundene Objekt ein Collectable?
        {
            if (!collectable.GetMovementState()) // Ist das Item noch nicht "aktiviert"?
                collectablesToCollect.Add(collectable); // Dann der Liste zum Einsammeln hinzufügen
        }
    }

    private void OnTriggerExit(Collider col)
    {
        Collectable collectable = col.GetComponent<Collectable>();

        if (collectable != null)
            collectablesToCollect.Remove(collectable); // Item aus der Liste entfernen
    }

    private void MoveToCollectable()
    {
        isCollecting = true; // Sammelprozess aktivieren

            Collectable collectable = collectablesToCollect.First(); // das erste Objekt der Liste nehmen
            Vector3 defaultPosition = transform.position; // Die Ursprungsposition des Followers

        CollectionMovement(transform.position, collectable.GetCollectablePosition()); // Follower zum Item bewegen

        collectable.StartMovingToPlayer(); // Item zum Spieler bewegen

        CollectionMovement(transform.position, defaultPosition); // Follower zurück bewegen

            collectablesToCollect.Remove(collectable); // eingesammeltes Collectable aus der Liste entfernen

            isCollecting = false; // Sammelprozess beenden

            if (CollectablesInRange()) // Noch ein weiteres Item in der Liste?
                MoveToCollectable(); // Weiter sammeln
    }
      
          private IEnumerator CollectionMovement(Vector3 startPos, Vector3 endPos)
    {
        transform.position = Vector3.MoveTowards(startPos, endPos, movementSpeed * Time.deltaTime);
        yield return null;
    }

    private bool CollectablesInRange() // Befinden sich irgendwelche Objekte in Reichweite / in der Liste?
    {
        return collectablesToCollect.Count > 0;
    }

Bewege ich mich mit dem Follower zu einem Collectable, so bewegt sich dieses problemlos auf den Spieler zu und wird eingesammelt. Mein Follower bewegt sich aber nicht zum Collectable hin und wieder zurück.

Ich gehe davon aus, dass ich die Routine

Vector3.MoveTowards()

so steuern muss, dass der restliche Code erst danach ausgeführt wird. Wie mache ich denn sowas am geschicktesten?

Vielleicht gibt es auch Verbesserungsvorschläge für den Code?

Link zu diesem Kommentar
Auf anderen Seiten teilen

So, ich habs dann mit der freundlichen Hilfe von @Sascha hinbekommen, sollte es jemanden interessieren, sieht der aktuell funktionierende Code so aus

 

private Transform player;
    private List<Collectable> collectablesToCollect = new List<Collectable>();
    private bool isCollecting = false;
    private float movementSpeed = 10;
    private Vector3 currentPosition;

    private void Start()
    {
        player = Globals.GetPlayerObject().transform;
    }

    private void Update()
    {
        if (CollectablesInRange())
            MoveToCollectable();
        else
            FollowPlayer();
    }

    private void OnTriggerEnter(Collider col)
    {
        Collectable collectable = col.GetComponent<Collectable>();

        if (collectable != null)
        {
            if (!collectable.GetMovementState())
                collectablesToCollect.Add(collectable);
        }
    }

    private void OnTriggerExit(Collider col)
    {
        Collectable collectable = col.GetComponent<Collectable>();

        if (collectable != null)
            collectablesToCollect.Remove(collectable);
    }

    private void MoveToCollectable()
    {
        Collectable collectable = collectablesToCollect.First();
        StartCoroutine(CollectionMovement(collectable));
    }

    private IEnumerator CollectionMovement(Collectable collectable)
    {
        if (isCollecting)
            yield break;

        isCollecting = true;

        yield return StartCoroutine(MoveToPoint(collectable.GetCollectablePosition()));

        if (collectable != null)
            collectable.StartMovingToPlayer();

        yield return StartCoroutine(MoveToPoint(currentPosition));

        collectablesToCollect.Remove(collectable);

        if (CollectablesInRange())
            MoveToCollectable();

        isCollecting = false;
    }

    private IEnumerator MoveToPoint(Vector3 targetPosition)
    {
        while (transform.position != targetPosition)
        {
            transform.position = Vector3.MoveTowards(transform.position, targetPosition, movementSpeed * Time.deltaTime);
            yield return null;
        }
    }

    private void FollowPlayer()
    {
        // TEST
        Vector3 playerPos = player.position;
        currentPosition = new Vector3(playerPos.x, playerPos.y + 2, playerPos.z);
        transform.position = currentPosition;
        // TEST
    }

    private bool CollectablesInRange()
    {
        return collectablesToCollect.Count > 0;
    }

Wobei ich die schrittweise Bewegung, also dass der Follower einen Schritt nach dem anderen abarbeitet, mithilfe von den beiden Enumeratoren löse. Dadurch kann der Follower zum Item hinlaufen, ihn einsammeln und wieder zurücklaufen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Join the conversation

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

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung jetzt entfernen

  Only 75 emoji are allowed.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Clear editor

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

Lädt...
×
×
  • Neu erstellen...