Search Unity

Mesh rotation problem (picture included)

Discussion in 'Scripting' started by Lokken, Feb 11, 2012.

  1. Lokken

    Lokken

    Joined:
    Apr 23, 2009
    Posts:
    436
    Hello all

    I have this virus looking thing with tentacles that have various animations that show it 'swimming' along. The animations are all done with the same direction in mind.

    When a player clicks the virus move towards that location. I need to have the tentacles rotate around their up (y) axis so that they are 'pointing' in the direction of movement (the red dot) so that when their animations play, they do so in the correct direction.



    In this case, the red dot is the click location, and the tentacles need to be rotated around their y axis so that they are facing the black line.

    Any suggestions on how to do this?

    Thanks!

    L
     
  2. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    so why dont you rotate the virus in the direction of the mouseclick and simply play the animation?

    i'm not sure but i think for that you need make each tentacle an own game object parented to the body. then you can rotate it relative to local position and target direction to your liking and play its animation.
    but if it is all one object then you are stuck with the animations you made.
     
  3. Lokken

    Lokken

    Joined:
    Apr 23, 2009
    Posts:
    436
    Thanks for the response!

    There is functionality in place that enable the virus to attach to things. So I have it able to rotate while moving so it slowly starts to 'pull' what it has attached behind it as it moves in a direction.

    For movement though we don't want the virus to have a 'front'. So wherever the player taps, that becomes the 'front'. If that makes sense.

    Each tentacle is its own gameobject and it is indeed parented to the virus body. My difficulty is coming with how to determine the angle to rotate for each tentacle since they are all situated in different positions on the body of the virus.
     
  4. ivkoni

    ivkoni

    Joined:
    Jan 26, 2009
    Posts:
    978
  5. Lokken

    Lokken

    Joined:
    Apr 23, 2009
    Posts:
    436
    Those functions will rotate the tentacles around their z and x axis as well. We only want them to be rotated around their y. They wont necessarily be looking AT the click point, just in that direction (depending on where on the body of the virus they are.

    Think of the click point as defining the front. The tentacles need to keep their position but rotate around their up vector so that they 'face' the newly defined front and play the animation in the correct direction.

    I may not be explaining this very well or there may be a much easier way to do this that I am just missing.
     
  6. Lokken

    Lokken

    Joined:
    Apr 23, 2009
    Posts:
    436
    I am going to bump this, but not without a new question!

    This has to do with how Animation States work.

    My virus has many tentacles. They all consist of a parent gameobject and a child FBX prefab. The parent gameobject contains the tentacle script:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class Tentacle : MonoBehaviour {
    6.    
    7.     public Animation animationInfo;
    8.     public AnimationState attachDirect, attachLeft, attachLeftSR, attachRight, idle, swimFront, swimRear, swimSide;
    9.     public GameObject tentacleGO;
    10.     public SkinnedMeshRenderer tentacleMeshRenderer;
    11.     public Material defaultMat;
    12.     private string currentAnimation;
    13.     // Use this for initialization
    14.     void Start () {
    15.         tentacleGO      = gameObject;
    16.         animationInfo   = tentacleGO.transform.GetChild(0).gameObject.GetComponent("Animation") as Animation;
    17.         tentacleMeshRenderer = tentacleGO.transform.GetChild(0).GetChild(0).gameObject.GetComponent("SkinnedMeshRenderer") as SkinnedMeshRenderer;
    18.         attachDirect    = animationInfo.animation["Attach Direct"];
    19.         attachLeft      = animationInfo.animation["Attach Left"];
    20.         attachLeftSR    = animationInfo.animation["Attach Left SR"];
    21.         attachRight     = animationInfo.animation["Attach Right"];
    22.         idle            = animationInfo.animation["Idle"];
    23.         swimFront       = animationInfo.animation["Swim Front"];
    24.         swimRear        = animationInfo.animation["Swim Rear"];
    25.         swimSide        = animationInfo.animation["Swim Side"];
    26.         idle.wrapMode   = WrapMode.Loop;
    27.         idle.speed      = Random.Range(.3f, .7f);
    28.         currentAnimation = "Idle";
    29.         animationInfo.Play(currentAnimation);
    30.     }
    31.    
    32.     // Update is called once per frame
    33.     void Update () {
    34.     }
    35.     public void setAnimationToPlay(string animationToPlay)
    36.     {
    37.         currentAnimation = animationToPlay;
    38.     }
    39.     public string getCurrentAnimation()
    40.     {
    41.         return currentAnimation;
    42.     }
    43.     public void setToIdle()
    44.     {
    45.         idle.speed = Random.Range(.3f, .7f);
    46.         this.animationInfo.CrossFadeQueued("Idle", .3f,  QueueMode.CompleteOthers);
    47.     }
    48. }
    49.  
    Now, the random speed in the Start() function is to have them animating at slightly different rates so it looks more organic. That works, each tentacle is moving at a different rate when you start playing.

    However, in the virus script, when the player moves the virus I play certain animations for the tentacles depending on how close they are to the click point:

    Code (csharp):
    1.  
    2.     void animateTentacles()
    3.     {
    4.         for (int i = 0; i < tentacleArray.Length; i++)
    5.         {
    6.             Tentacle currentTentacle = tentacleArray[i];
    7.             float tempAngle = Vector3.Angle(direction, currentTentacle.tentacleGO.transform.position - virusGO.transform.position);
    8.             string animationToPlay = "Idle";
    9.             if (tempAngle <= 45)
    10.             {
    11.                 animationToPlay = "Swim Front";
    12.                 currentTentacle.tentacleMeshRenderer.material = GREEN;
    13.             }
    14.             else if (tempAngle > 45  tempAngle <= 135)
    15.             {
    16.                 animationToPlay = "Swim Side";
    17.                 currentTentacle.tentacleMeshRenderer.material = YELLOW;
    18.             }
    19.             else if (tempAngle > 135)
    20.             {
    21.                 animationToPlay = "Swim Rear";
    22.                 currentTentacle.tentacleMeshRenderer.material = RED;
    23.             }
    24.             currentTentacle.animationInfo.CrossFadeQueued(animationToPlay, .3f, QueueMode.PlayNow);
    25.             currentTentacle.setToIdle();
    26.         }
    27.     }
    28.  
    The animations work great (except for the problem of rotating the tentacles into the correct direction re: the original question of this thread). They blend great and play when I expect.

    My problem is coming when the tentacles get set back to the idle animation. They are all set to the default speed of 1 and obviously all play exactly in sync.

    As you can see I try to give the idle animation another random speed to mix it up whenever idle is re-started but nothing I do will make the animation play back at any rate other than 1.

    Does CrossFadeQueued() not apply state settings? I use Play() in the Start() function on each tentacle so that is the only difference that I can see. I am hoping I am just staring too long at the code and its something simple.

    I think this may tie into me just not understanding how Unity stores and uses animations.

    I have the following code attached to just one of my tentacles:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class AnimationController : MonoBehaviour {
    6.  
    7.     public Virus theVirus;
    8.     private AnimationEvent startMoving;
    9.     // Use this for initialization
    10.     void Start () {
    11.         startMoving = new AnimationEvent();
    12.         startMoving.time = .53f;
    13.         startMoving.functionName = "move";
    14.         this.animation["Swim Side"].clip.AddEvent(startMoving);
    15.     }
    16.    
    17.     // Update is called once per frame
    18.     void Update () {
    19.    
    20.     }
    21.     public void move(AnimationEvent en)
    22.     {
    23.         theVirus.movePlayer();
    24.     }
    25. }
    26.  
    The goal is to have the move functionality happen at a certain point in the animation. I only attach it to one of the tentacles because I don't want the move command being called once per tentacle. This actually works great, but I am getting an error in the console:

    Code (csharp):
    1. AnimationEvent 'move' has no receiver!
    2.  
    This is popping up for all of the other tentacles even though they do not have this script attached and thus shouldn't be having this event declared for them.

    L
     
  7. Lokken

    Lokken

    Joined:
    Apr 23, 2009
    Posts:
    436
    Bump.

    I have figured out the virus rotation (for the most part).

    I am still at a loss for why each Tentacle can have its idle animation at a different speed at run-time but when they return to the idle animation via CrossFadeQueued() its as if unity ignores my speed settings and plays them all at the same rate.

    The tentacles were made in the inspector by creating one and then using cntrl+D to duplicate them. Could this be why? I only have to attach a new shader or material to one and they all get it even though any prefab connection has been lost due to adding scripts to the FBX object.

    I am a bit stumped :(