Search Unity

Player to enemy orbits

Discussion in 'Scripting' started by mvinc006, May 13, 2019.

  1. mvinc006

    mvinc006

    Joined:
    Jan 1, 2018
    Posts:
    91
    Hi All,

    I've been stuck on trying to get a Player ship to orbit around a moving enemy ship (and vice versa).

    The easiest way to visualize what I'm trying to achieve is exactly the same way EVE Online approaches a target, and then slowly rotates around a given radius.

    It's figuring out the math that I've proven to myself I'm just hopeless at.

    I did find some really good info, I found this https://www.reddit.com/r/Unity3D/comments/5ml43x/spaceship_orbiting_around_player_question/ which is an absolute gem, it does exactly what I want with one little problem...it will always rotate around the central world origin. The people in the thread didn't seem to have this issue.

    Unfortunately no amount of tinkering and learning Linear Algebra over the past month has helped me and I'm in a slump here. I know that using RotateAround will not solve my problem, as if the target moves, the ship just moves with it with no real re-orientation happening to re-circularize (almost as if its parented which its not).

    I don't expect any direct answers, but even some advice or mathmatical formulas i can look at which can help me achieve my desired goal, and hey if you post code that's awesome too!



    Code I'm currently using

    Code (CSharp):
    1. RequireComponent(typeof(Rigidbody))]
    2. public class Orbit : MonoBehaviour
    3. {
    4.     public enum OrbitalDirections
    5.     {
    6.         Prograde,
    7.         Retrograde,
    8.     }
    9.     public OrbitalDirections OrbitalDirection = OrbitalDirections.Prograde;
    10.  
    11.     public GameObject OrbitTarget = null;
    12.     public GameObject Marker = null;
    13.     private Rigidbody rigidBody;
    14.  
    15.     private float Azimuth = 0.0f;
    16.     private float Zenith = 0.0f;
    17.     public float Radius = 3.0f;
    18.  
    19.     public float TurnRate = 0.25f;
    20.     public float Velocity = 2.0f;
    21.  
    22.     // Use this for initialization
    23.     void Start()
    24.     {
    25.         if (OrbitTarget == null)
    26.             Debug.LogException(new System.Exception(this.name + ": Target Not Set"));
    27.         rigidBody = GetComponent<Rigidbody>();
    28.  
    29.     }
    30.  
    31.     // Update is called once per frame
    32.     void Update()
    33.     {
    34.         Azimuth = Mathf.Atan2(transform.position.z, transform.position.x);
    35.  
    36.         if (OrbitalDirection == OrbitalDirections.Prograde)
    37.             Azimuth += (Mathf.PI / 2.0f);
    38.         else
    39.             Azimuth -= (Mathf.PI / 2.0f);
    40.  
    41.         Zenith = Mathf.Acos(transform.position.y / Vector3.Distance(transform.position, Vector3.zero));
    42.  
    43.         Vector3 markerPosition = Vector3.zero;  // tried changing this to OrbitTarget.transform.position with no joy
    44.         markerPosition.x = Radius * Mathf.Cos(Azimuth) * Mathf.Sin(Zenith); // also tried *= with no joy
    45.         markerPosition.z = Radius * Mathf.Sin(Azimuth) * Mathf.Sin(Zenith);
    46.         markerPosition.y = Radius * Mathf.Cos(Zenith);
    47.  
    48.         if (Marker != null)
    49.             Marker.transform.position = markerPosition;
    50.  
    51.         transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(-1 * (transform.position - markerPosition).normalized), Time.deltaTime * TurnRate);
    52.         rigidBody.velocity = transform.forward * Velocity;
    53.     }
    54. }
    Edited: Clarified a bit more on what i've tried.
     
    Last edited: May 13, 2019
  2. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    While learning linear Algebra will give you a significant leg up in most methematical Problems in unity, you might get by without it. There's a neat Little trick you can do:
    When you want to enter 'orbit' mode, create a 'master' game object at the position of the ship you want to Orbit, and a second 'child' object at the position of your ship.
    Parent the Child that represents your ship to the first one (master). Now all you need to do is make the master follow the enemy ship (you could just parent it to the enemy), and rotate locally the master game object. This will cause the child to Orbit the master at the distance at the time you parented it.
    Make you ship follow the position of the second (child) game object, orbiting the enemy. You can even have your ship align correctly by copying the Rotation values (make sure to initially copy your ship's totation when you create the child object)
     
    Kurt-Dekker and mvinc006 like this.
  3. mvinc006

    mvinc006

    Joined:
    Jan 1, 2018
    Posts:
    91
    Thank you I appreciate it, I'll give this a go and come back with the results if it is my answer.
     
  4. mvinc006

    mvinc006

    Joined:
    Jan 1, 2018
    Posts:
    91
    Thank you very much the solution works perfectly for my needs, here is what i ended up going with.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class OrbitTest : MonoBehaviour
    6. {
    7.     public GameObject PrimaryTarget;    // hard coded via inspector for testing
    8.     public GameObject ChaseTarget;      // hard coded via inspector for testing
    9.     public float Velocity = 5f;
    10.     public float RevolutionSpeed = 20f;
    11.     public float Radius = 15f;
    12.  
    13.     private Vector3 Direction;
    14.  
    15.     private void Start()
    16.     {
    17.         if(PrimaryTarget==null)
    18.             Debug.LogException(new System.Exception(this.name + ": Primary Target Not Set"));
    19.    
    20.         ChaseTarget.transform.SetParent(PrimaryTarget.transform);           // Set the target we will chase (orbit) to be parented to the Primary Target
    21.         ChaseTarget.transform.rotation = PrimaryTarget.transform.rotation;  // Ensure rotation matches to prevent errors
    22.     }
    23.  
    24.     private void Update()
    25.     {
    26.         Vector3 Direction = (gameObject.transform.position - ChaseTarget.transform.position).normalized;    // Get direction from us to the chase target
    27.  
    28.         // As long as we are within Radius - Excecute orbital mode
    29.         if (Vector3.Distance(transform.position, ChaseTarget.transform.position) <= Radius)
    30.         {
    31.             ChaseTarget.transform.position = (ChaseTarget.transform.position - PrimaryTarget.transform.position).normalized * Radius + PrimaryTarget.transform.position;    // Some maths (probably don't need this anymore)
    32.             ChaseTarget.transform.RotateAround(PrimaryTarget.transform.position, Vector3.up, RevolutionSpeed * Time.deltaTime);     // Rotate around the Primary target, chase target is primarilly for direction facing purposes now
    33.         }
    34.         // If we are not within Radius - Exceute follow mode
    35.         else if (Vector3.Distance(transform.position, ChaseTarget.transform.position) > Radius)
    36.         {
    37.             ChaseTarget.transform.position = PrimaryTarget.transform.position - -Direction * Radius;    // Move the chasetarget back from our primary target by N units based on direction
    38.         }
    39.  
    40.         transform.LookAt(ChaseTarget.transform.position);   // change this to a Q Slerp later - it target moves sharply it doesn't look right
    41.         transform.position = Vector3.MoveTowards(transform.position, ChaseTarget.transform.position, Velocity * Time.deltaTime);    // can change to a more calculated approach later.
    42.     }
    43. }