Hellhound Geschrieben 28. Februar 2017 Melden Share Geschrieben 28. Februar 2017 Hallo zusammen, ich bin mir nicht sicher, ob der Scripting-Thread der richtige Ort für das Thema ist oder ob es eigentlich eher zu dem Animationsbereich gehört ... In der Hoffnung das es skript baisert lösbar ist, poste ich es einmal hier. Ich schreibe aktuell für mich einen click to move basierten Avatar Controller und nutze den NavMeshAgent für die Steuerung/Wegfindung. Besonderheit hierbei ist, das ich die Rotation des NavMeshAgent deaktiviert habe um eine Punktrotation vor der eigentlichen Bewegung zum Zielpunkt durchzuführen. Ausgeführt wird das ganze in mehreren Schritten mit einer Coroutine für die Bewegung: Zunächst prüfe ob der Zielpunkt in einem größeren Winkel +/- 30 Grad zur Blickrichtung liegt. Ist dies der Fall wird durch eine weitere Coroutine zunächst die Bewegungsausführung unterbrochen, bis die Animation für die Rotation im Animator zu 75% abgeschlossen wurde. Anschließend setze ich am NavMeshAgent die Bewegunsrelevanten Daten Im letzten Schitt führe ich durch eine weitere Coroutine eine Korrektur der Rotation zum Zielpunkt durch, da diese i.d.R. durch das Blending nicht vollständig ist. Hier einmal der Code für die Bewegungsausrichtung getriggert durch ein separates Click-Skript: public IEnumerator Move(Vector3 target, float timeToWait){ this.targetDirection = target - animator.rootPosition; this.targetDirection.y = 0f; this.targetPosition = target; Vector3 rootDirection = this.transform.forward; Vector3 axisSign = Vector3.Cross(targetDirection, rootDirection); this.signedAngle = Vector3.Angle(rootDirection, targetDirection) * (axisSign.y >= 0 ? -1f : 1f); // block until rotation animation is complete if (signedAngle > 30f || signedAngle < -30f) { yield return StartCoroutine(OnCompleteRotationAnimation()); } this.navMesh.destination = target; this.navMesh.speed = this.walkSpeed; this.navMesh.acceleration = this.walkAcceleration; this.forward = 0.5f; this.signedAngle = 0f; this.hasValidDirection = true; // make sure we're rotating to face the proper direction this.useCustomRotation = true; while (Vector3.Angle(targetDirection, this.transform.forward) >= 0.25f) { Debug.DrawRay(this.transform.position, this.transform.forward * 5f, Color.blue); Debug.DrawRay(this.transform.position, targetDirection * 5, Color.red); yield return null; } this.useCustomRotation = false; } Und hier der eigentliche Update Code, bei dem ich lediglich die Animationen auf Basis der Entfernung und NavMesh Geschwindigkeit setze und prüfe, ob ich den Zielpunkt erreicht habe, in dem Fall wird die Navigation zurückgesetzt: void Update () { // Calculate our distance from target float distance = Vector3.Distance(targetPosition, navMesh.transform.position); /* Update our speed based on our distance from the target to slow down speed reaching target point position */ var speed = navMesh.desiredVelocity.magnitude * (distance >= 1.0f ? 1f : distance); animator.SetFloat(hashes.forward, speed, animationDampTime, Time.deltaTime); // only handle on active movement if (this.hasValidDirection) { this.Rotate(); if(distance < pathEndThreshold) { this.hasValidDirection = false; this.forward = 0f; this.signedAngle = 0f; this.navMesh.velocity = Vector3.zero; this.navMesh.speed = 0f; } // finally blend rotation value animator.SetFloat(hashes.angle, signedAngle, animationDampTime, Time.deltaTime); } } Das klappt auch soweit ganz gut, wie Ihr dem folgendem Video entnehmen könnt: https://vid.me/tVvC Für die Rotation selbst nutze ich einen Blend Tree mit diversen Mixamo Animationen unter Berüksichtigung des erforderlichen Rotationswinkels. Für die Animation selbst habe ich in dem Fall die RootMotion aktiviert. Aber genau die RootMotion scheint das Problem zu sein da die Animation scheinbar noch "nachläuft" nachdem der Agent gestoppt wurde und die RootMotion den Avatar über den Zielpunkt hinaus bewegt. Deaktiviere ich die RootMotion, dann stoppt der Avatar zwar am konkreten Zielpunkt. Zuckt aber merkwürdig bevor die eigentliche Rotationsanimation beginnt (ich habe keine Idee wo dies her kommt) zudem macht er i.d.R. auch noch einzelne Schritte obwohl er bereits steht, wie man es diesem Video entnehmen kann: https://vid.me/Ewb4 Ich habe auch schon versucht die OnAnimatorMove Methode zu verwenden und hier die aktuelle transform.position des Avatars auf den Wert der NavMesh.nextPosition zu setzen. Dies führt aber lediglich zum gleichen Effekt, wie bei der deaktivierten RootMotion. Ich bin mit meinem Latein inzwischen am Ende und finde zu diesem Thema auch nichts weiter im Netz. Daher bin ich äußerst dankbar für jede Hilfe, da mich dieses Problem schon gut 14 Tage beschäftigt. Gruß Hellhound Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Hellhound Geschrieben 2. März 2017 Autor Melden Share Geschrieben 2. März 2017 Inzwischen habe ich herausgefunden, dass wenn ich die Methode OnAnimatorMove mit folgendem Setting nutze und zudem am NavMeshAgent die updatePosition auf false setze, er sich korrekt zum Zielpunkt bewegt und auch das merkwürdige Zucken vor Bewegungsbeginn verschwindet: void OnAnimatorMove(){ transform.rotation = animator.rootRotation; transform.position = navMesh.nextPosition; } Allerdings sind nun Animation und NavMeshAgent nicht synchron, d.h. der Avatar läuft noch eine Weile, obwohl der Zielpunkt erreicht wurde und sowohl der Forward Wert für das Laufen als auch die NavMeshAgent.Velocity auf 0 gesetzt wurden. Hat jemand eine Idee wie ich das in den Griff bekomme? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.