Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Movements and math curves

Discussion in 'Scripting' started by Willy-The-Kid, May 15, 2015.

  1. Willy-The-Kid

    Willy-The-Kid

    Joined:
    May 11, 2015
    Posts:
    32
    Hello friends.

    I'm want to create a spell system. Each spell as a path defined by a math curve.
    So for exemple, for a spell that go straight forward, i'll use a linear curve like

    Code (CSharp):
    1.  
    2. float posX = 0f;
    3. float posY = 0f;
    4. float posZ = speed * time;
    5.  
    For a spell that will draw a circle, I'll use a circle curve like this

    Code (CSharp):
    1.  
    2. floatposX = rayon * Mathf.Cos(time * speed);
    3. floatposY = 0f;
    4. floatposZ = rayon * Mathf.Sin(time * speed);
    5.  
    To get this system working, I get and set position based on world axis.

    At this point, my issue is that I don't know how to apply this curve move depending on the local orientation of my spell. For exemple, if my character looks at right when casting, the spell object will be created in this orientation, so a linear curve on that spell should make it going forward his local space, which is right on world space. Instead the spell always go up on world axis.


    This is a sample code

    Update on my spell object
    Code (CSharp):
    1.  
    2. public void Fire (LayersTypeslayerToIgnore, AttackDirectionsEnum direction, GameObjectlauncher)
    3.  {
    4. this.transform.position = launcher.transform.position;
    5. this.transform.rotation = launcher.transform.rotation;
    6.  
    7. switch (direction)
    8.  {
    9. caseAttackDirectionsEnum.Forward:
    10. this.gameObject.transform.Rotate(0,0,0);
    11. break;
    12. caseAttackDirectionsEnum.Diagonal_FR:
    13. this.gameObject.transform.Rotate(0,45,0);
    14. break;
    15. caseAttackDirectionsEnum.Right:
    16. this.gameObject.transform.Rotate(0, 90, 0);
    17. break;
    18. caseAttackDirectionsEnum.Diagonal_BR:
    19. this.gameObject.transform.Rotate(0,135,0);
    20. break;
    21. caseAttackDirectionsEnum.Backward:
    22. this.gameObject.transform.Rotate(0, 180, 0);
    23. break;
    24. caseAttackDirectionsEnum.Diagonal_BL:
    25. this.gameObject.transform.Rotate(0,225,0);
    26. break;
    27. caseAttackDirectionsEnum.Left:
    28. this.gameObject.transform.Rotate(0, 270, 0);
    29. break;
    30. caseAttackDirectionsEnum.Diagonal_FL:
    31. this.gameObject.transform.Rotate(0,315,0);
    32. break;
    33.  }
    34.  
    35. _startPos = this.transform.position;
    36. _startRot = this.transform.rotation;
    37.  }
    38.  
    39.  
    40. void Update ()
    41. {
    42. if (Time.time >= _channelingTime)
    43. {
    44.     CurveMove newMove = CurveHandler.GetPath(speed, pathType, Time.time - _channelingTime, rayon);
    45.  
    46.     this.transform.LookAt(_startPos + newMove.positionMove);
    47.     this.transform.position = _startPos + newMove.positionMove;
    48. }
    49. }


    Class that calculate the move based on curve
    Code (CSharp):
    1. private static CurveMove GetLinePath (float speed, float time)
    2.     {
    3.         float posX = 0f;
    4.         float posY = 0f;
    5.         float posZ = speed * time;
    6.  
    7.         float rotX = 0f;
    8.         float rotY = 0f;
    9.         float rotZ = 0f;
    10.  
    11.         return (new CurveMove(new Vector3(posX, posY, posZ), new Quaternion(rotX, rotY, rotZ, 0)));
    12.     }
    13.  
    14.     private static CurveMove GetCirclePath (float speed, float time, float rayon)
    15.     {
    16.         float posX = rayon * Mathf.Cos(time * speed);
    17.         float posY = 0f;
    18.         float posZ = rayon * Mathf.Sin(time * speed);
    19.        
    20.         float rotX = 0f;
    21.         float rotY = 0f;
    22.         float rotZ = 0f;
    23.        
    24.         return (new CurveMove(new Vector3(posX, posY, posZ), new Quaternion(rotX, rotY, rotZ, 0)));
    25.     }
    26.  
     
  2. shaderbytes

    shaderbytes

    Joined:
    Nov 11, 2010
    Posts:
    900
    use the forward vector of the players transform as a direction , transform.forward will give you the forward vector ie (0,0,1) in world space.
     
    Last edited: May 15, 2015
  3. Willy-The-Kid

    Willy-The-Kid

    Joined:
    May 11, 2015
    Posts:
    32
    Hello,

    Sorry for delay, I was away in vacations :)
    Thanks for your answer ! It does works well for a line path like this :

    Code (csharp):
    1. floatposX = (speed * time) * transform.forward.x;
    2. floatposY = (speed * time) * transform.forward.y;
    3. floatposZ = (speed * time) * transform.forward.z;
    But I have a bit of trouble using it on a circle path for exemple :

    Code (csharp):
    1. floatposX = rayon * Mathf.Cos(time * speed);
    2. floatposY = transform.forward.y;
    3. floatposZ = rayon * Mathf.Sin(time * speed);
    My issue here is that if I launch one fireball in a random position on the circle, instead of going on and following the circle from its starting point, it'll always go to a specific position and then start to follow the circle. This is logic as the position is calculated using time, I tried different ways to use transform.forward there without success.

    Any clue ?

    Thanks a lot.
     
  4. shaderbytes

    shaderbytes

    Joined:
    Nov 11, 2010
    Posts:
    900
    I dont know exactly what you are doing but Cos and Sin work with an Angle in Radians as input. When you create a fireball or whatever on a random point on a circle as you mentioned.. this points angle in relation to the circle needs to be understood as it is the starting point for your Cos and Sin calculations. You then increase/decrease the angle in a time step.
     
  5. Willy-The-Kid

    Willy-The-Kid

    Joined:
    May 11, 2015
    Posts:
    32
    you're right, to be correct my calculation should be taking in account Pi like this
    Code (CSharp):
    1.  
    2. float posX = rayon * Mathf.Cos(time * (2 * Mathf.PI / speed));
    3. float posY = forwardVector.y;
    4. float posZ = rayon * Mathf.Sin(time * (2 * Mathf.PI / speed));
    Let's try to explain it a bit more what is my issue.

    I try to create a fireball spell that will move to draw a circle.
    Using the formula I mentionned, I'm able to change the position of my fireball on the circle based on time elapsed since fireball as been launched and depending on the speed of the spell.

    Now let's imagine my character face the North and launch a fireball, the spell will start in front of him at setted Radius, let's say 5 units. As time is 0, angle is 0. On update, time and angle changed, so my fireball start to move on the circle path until it goes to 360, coming back to original position.

    Now if my character is facing south, the start position of my fireball should be 5 units in south direction (so based on degrees, 180 deg on the circle), but as time is 0 at this moment, the degree used is 0. Is that more clear?
     
  6. shaderbytes

    shaderbytes

    Joined:
    Nov 11, 2010
    Posts:
    900
    your modified code using PI does not factor in the angle anywhere. Your exact problem is that are using time as the angle. You should use the angle as the starting point and increment this angle using your time step and speed etc.. or if you can't win with this maths just parent the particle Object to the character and localize the values then you can use a constant starting point value.