Need help with creating a skill tree-adjusting the angle of the line underneath to point at skills

So what I’m trying to do is make a game with a skill tree, and I want to make lines in between each skill so the player knows which upgrades to get in which order, however unity doesn’t have a simple line drawing function for this. So I am using a rectangle to put one end under one skill and the other end under the other skill, and so I am doing this by taking the coordinates of both skills and adjusting the ends of the rectangle to it. However, I also need to tilt the rectangle to adjust to the two skills, because my skill tree isn’t just straight up, down, left and right. I need the angle of the rectangle to be adjusted to each set of skill images, no matter where each one is placed.

I will be making many different skill trees for many different classes, so I need the ability to be able to instantly load lots of lines, but I am also going to be designing each skill tree’s skills in specific ways for each one, so i need to make the skills myself then have the lines auto adjust to the skills.

So originally I had thought of just finding the angle opposite the hypotenuse, and using that to adjust the line, and it would’ve worked if the angle the hypotenuse was opposite of didn’t change. For instance (Triangle calculator, triangle solver SSS (side side side)), if I put in A(592,252), B(-184,252), and C(0,0), then the hypotenuse is straight down. But if I switch the coordinates, so A(592,252), B(0,0), and C(-184,252), then the hypotenuse is now top right, so the angle I need to get is different (angle B instead of angle C). So how do I know which angle to use and when? Or do I need to change the equation entirely?

Thanks

//Skill Tree------------

    public Dropdown mainClass;
    public Dropdown subClass;

    public GameObject originalSkillGO;
    public GameObject skillsFolder;
    public GameObject skillLine;
    public void MainClassChanged()
    {
        if (mainClass.options[mainClass.value].text == "Claymore") //More info https://answers.unity.com/questions/1082554/how-to-change-text-in-dropdown-menu-in-c-during-ru.html
        {
            subClass.options.Clear();
            subClass.options.Add(new Dropdown.OptionData() { text = "Miria" });
            subClass.options.Add(new Dropdown.OptionData() { text = "Clare" });
            subClass.options.Add(new Dropdown.OptionData() { text = "Ophelia" });
        }
    }
  

    public void SubClassChanged()
    {
        if(subClass.options[subClass.value].text == "Miria") //since each individual character will have their own seperately designed skill tree, I will need to make seperate ones (I can clean this up later)
        {
            //List of skills for each character below

            SkillTreeSkillButtons.Clear();
            //Also need to delete all gameobjects of skills and remake them every time you load a new character

            for (int i = 0; i < MiriaSkills.Count; i++)
            {
                GameObject newSkilLGO = (GameObject)Instantiate(originalSkillGO); //Creation of a new Skill, 
                newSkilLGO.name = "Skill";
                newSkilLGO.transform.parent = skillsFolder.transform;
                newSkilLGO.GetComponent<RectTransform>().localPosition = MiriaSkillsTransform[i];
                newSkilLGO.GetComponent<RectTransform>().localScale = new Vector3(.5f, .5f, .5f);
                SkillTreeSkillButtons.Add(newSkilLGO);

                SkillTreeSkillButtons[i].GetComponent<SkillTreeSkillSlot>().skill = MiriaSkills[i];
                SkillTreeSkillButtons[i].GetComponent<SkillTreeSkillSlot>().RefreshSkill();


            }

            for (int i = 0; i < SkillTreeSkillButtons.Count; i++)
            {
                GameObject newSkilLGO = (GameObject)Instantiate(originalSkillLine); //Creation of a new skill line, will finish up this section later
            }
        }
    }
    public List<GameObject> SkillTreeSkillButtons = new List<GameObject>(); //This is a list of the buttons that are created which will have the individual skill on that I can buy.
    public List<Skill> MiriaSkills = new List<Skill>(); //The Scriptable object of each individual skill (this will be attached to the skilltreeskillbutton game objects)
    public List<Vector3> MiriaSkillsTransform = new List<Vector3>() {}; //The coordinates of where I want each skill to go in the skill tree (designing myself)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class SkillTreeBGLine : MonoBehaviour
{
    public GameObject skill1;
    public GameObject skill2;


    Vector3 size;
    public void Move()
    {
        var skillOne = skill1.GetComponent<RectTransform>().localPosition; //Map Tab
        var skillTwo = skill2.GetComponent<RectTransform>().localPosition;


        size.x = (float)(Mathf.Abs((skillOne.x - skillTwo.x) /100f) + 1); // The Length
        size.y = .2f;
        size.z = 1f;




        this.GetComponent<RectTransform>().localScale = size; //width, height
        this.GetComponent<RectTransform>().localPosition = new Vector3(((skillOne.x + skillTwo.x) / 2), ((skillOne.y + skillTwo.y) / 2), 0f); //x,y,z

        var a = Mathf.Sqrt(Mathf.Pow(skillTwo.x - 0f, 2) + Mathf.Pow(skillTwo.y - 0f, 2));
        var b = Mathf.Sqrt(Mathf.Pow(skillTwo.x - skillOne.x, 2) + Mathf.Pow(skillTwo.y - skillOne.y, 2));
        var c = Mathf.Sqrt(Mathf.Pow(skillOne.x - 0f, 2) + Mathf.Pow(skillOne.y - 0f, 2));


        print("a" + a);
        print("b" + b);
        print("c" + c);


        this.GetComponent<RectTransform>().eulerAngles = new Vector3(0, 0, -1f * (Mathf.Acos((Mathf.Pow(a, 2) + Mathf.Pow(c, 2) - Mathf.Pow(b, 2)) / (2f * a * c))) * (180f / Mathf.PI));

        print("line angle" + (Mathf.Acos((Mathf.Pow(a, 2) + Mathf.Pow(c, 2) - Mathf.Pow(b, 2)) / (2f * a * c))) * (180f/Mathf.PI));


        //h = b * sin[arccos((a2 + b2 - c2) / (2ab))], B = arcsin (h / c)

    }

}

I feel your pain! Check into the Unity UI Extensions repo… there are many forks but this one seems to come up first in googling:

https://github.com/JohannesDeml/unity-ui-extensions

It might just be exactly what you need for connecting ad-hoc nodes.

1 Like

Okay so I had to leave for work right away, so I never really got time to search the UI Extensions, but at work I thought about it and figured it out! What I had to do was find the point that was closer to the y-axis, find the angle of that point, then find the outside angle of that point (so 90 degrees - the inside angle). Then I could set that angle to the outside angle. However, if the line was on the left side of the y axis, then I had to times it by -1, since the rotation is flipped opposite on the left side of the y axis.

This function also works with any two points. I plugged them in in the inspector, but you can skillOne and skillTwo to any two points you want. (I will be using those two points for my skill tree skills).

Here is the code below…

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class SkillTreeBGLine : MonoBehaviour
{
    public GameObject skill1;
    public GameObject skill2;


    Vector3 size;
    public void Move()
    {
        var skillOne = skill1.GetComponent<RectTransform>().localPosition; //These two points are your original two points that you want the line to connect to
        var skillTwo = skill2.GetComponent<RectTransform>().localPosition;


        size.x = (float)(Mathf.Abs((skillOne.x - skillTwo.x) / 100f) + 1); // Line settings -- The Length of the line
        size.y = .2f;
        size.z = 1f;


        this.GetComponent<RectTransform>().localScale = size; //width, height
        this.GetComponent<RectTransform>().localPosition = new Vector3(((skillOne.x + skillTwo.x) / 2), ((skillOne.y + skillTwo.y) / 2), 0f); //x,y,z

        var yAxisPoint = skillOne; //These variables have to be initialized outside the if statement, so these are just temporary settings, they may change in the if statement below
        var otherPoint = skillTwo;

        //Need an if statement for if the xs or ys are equal
        if (Mathf.Abs(skillOne.x) < Mathf.Abs(skillTwo.x)) //This determines which of the two points is closer to the yAxis
        {
            yAxisPoint = skillOne;
            otherPoint = skillTwo;
        } else
        {
            yAxisPoint = skillTwo;
            otherPoint = skillOne;
        }

        var rightAnglePoint = new Vector2(yAxisPoint.x, otherPoint.y);


        var hypotenuse = Mathf.Sqrt(Mathf.Pow(skillTwo.x - skillOne.x, 2) + Mathf.Pow(skillTwo.y - skillOne.y, 2));
        var adjacent = Mathf.Sqrt(Mathf.Pow(yAxisPoint.x - rightAnglePoint.x, 2) + Mathf.Pow(yAxisPoint.y - rightAnglePoint.y, 2));
        //var opposite = Mathf.Sqrt(Mathf.Pow(otherPoint.x - rightAnglePoint.x, 2) + Mathf.Pow(otherPoint.y - rightAnglePoint.x, 2));

        var pointInsideAngle = Mathf.Acos(adjacent / hypotenuse);
        pointInsideAngle = pointInsideAngle * (180f / Mathf.PI);

        var pointOutsideAngle = (90 - pointInsideAngle);

    
        if (otherPoint.x < 0) //The rotation needs to be flipped if the angle is being flipped towards the left side (negative side of x axis)
        {
            pointOutsideAngle = pointOutsideAngle * -1f;
        }
        if (otherPoint.y < 0) //The rotation needs to be flipped if the angle is being flipped towards the bottom side (negative side of y axis)
        {
            pointOutsideAngle = pointOutsideAngle * -1f;
        }else if (otherPoint.y < yAxisPoint.y)
        {
            pointOutsideAngle = pointOutsideAngle * -1f;
        }



        this.GetComponent<RectTransform>().eulerAngles = new Vector3(0, 0, pointOutsideAngle);

        //https://www.triangle-calculator.com/?what=vc This amazing website helped me a ton!
        //And this one too https://www.calculatorsoup.com/calculators/geometry-plane/distance-two-points.php

    }

}

Also just a reference image for my inspector, and I manually changed the rect transform to be pos x y and z by creating an empty object and adding the image and canvas renderer to it.

7247255--873182--Line Drawer.png