Home > Software engineering >  Triangle Formation in Unity/C#
Triangle Formation in Unity/C#

Time:12-07

first of all, it is my first question and this is not a "Write my code" post. i need a hint from more experienced programmers or math enthusiasts.


I am trying to do pyramid tower formation in my game. I dont know if its about my math and how bad i am in programming or just my brain died while trying to figure out that. I have wrote several algorithms but nothing worked. I need my objects to position in a pyramid when i collect them. Second one next to first, then 3rd one on top of them. 4th one(index 3 in the pic) needs to go down again etc.. If i've collected 4 object; they should be positioned like 0-1-2-3 in the picture.


Here is what i am trying to implement:

enter image description here

I am nowhere close to this. I am just looping through my list and trying to figure out right now with some x-y offset calculations. I am not sure if i should do it manually with pre-filled Vector3 list.

public void SetFormation(int count)
{
    Vector3 pos = Vector3.zero;
    for (int i = count; i > 0; i--)
    {
        for (int j = 0; j < i; j  )
        {
            GameObject gM = Instantiate(prefab);
            gM.transform.SetParent(transform);
            gM.transform.position = new Vector3(pos.x, pos.y, 0);
            pos  = new Vector3(xOffset, 0, 0);
        }
        pos  = new Vector3(0, yOffset, 0);
    }
}

CodePudding user response:

Swap the cheerleaders out for acrobats. Instead of a pyramid, the acrobats stack directly on top of each other in columns, standing straight up and down on each others shoulders. The column numbers start on the left, with the leftmost column designated as 1, and increase as you move to the right.

Here are the rules for placing acrobats:

In column 1, you stack 1 acrobat.
In column 2, you stack 2 acrobats.
In column 3, you stack 3 acrobats.
Etc...

This is what it looks like for 9 acrobats:

      9
    5 8
  2 4 7
0 1 3 6

Now imagine the acrobats are insanely strong and can stand off-center so that only one leg is on the person below, opposite leg to opposite shoulder. They all get offset in the same direction, making each column lean to the side.

Each stacked acrobat is offset by exactly half the distance between the acrobats in the bottom row, so it looks like they are standing directly on top of the two acrobats underneath:

   9
  5 8
 2 4 7
0 1 3 6

Look familiar? The pyramid is not really a pyramid, it's a leaning collection of columns!

So the algorithm is simply to keep placing the correct number of acrobats in each column, offsetting each one to the left a half column as you go up. Whenever you reach the top of the column you start a new one and repeat until you've reached the requisite number of acrobats. The starting position of each bottom acrobat in a new column is easy enough to calculate, as it is simply the column number minus one, multiplied by the horizontal offset distance, to the right of the "origin" (bottom left) of the pyramid.

I'm not a Unity programmer, this is written for C# WinForms, but I'm pretty sure you'll be able to understand both the algorithm and the code.

Here's the core part of the program:

private int xOffset = 45;
private int yOffset = 45;
private int cheerleaderRadius = 15;

private int numCheerleaders = 1;

private void MainForm_Paint(object sender, PaintEventArgs e)
{
    // set origin at the bottom left of the form
    Point origin = new Point(cheerleaderRadius * 2, this.ClientRectangle.Height - (cheerleaderRadius*2));
           
    int currentCheerleader = 1;
    int currentColumnNumber = 1;
    int cheerleadersInCurrentColumn;
    while (currentCheerleader <= numCheerleaders)
    {
        cheerleadersInCurrentColumn = 1;
        Point position = new Point(origin.X   (currentColumnNumber - 1) * xOffset, origin.Y);
        while(cheerleadersInCurrentColumn<=currentColumnNumber && currentCheerleader<=numCheerleaders)
        {
            drawCheerleader(e.Graphics, position, (currentCheerleader - 1));
            position.Offset(-xOffset / 2, -yOffset);
            cheerleadersInCurrentColumn  ;
            currentCheerleader  ;
        }
        currentColumnNumber  ;
    }     
}

This is what it looks like in action. Each time the number of cheerleaders is changed, the pyramid below gets redrawn:

enter image description here

Here is the entire C# WinForms program:

public partial class MainForm : Form
{
    
    private int xOffset = 45;
    private int yOffset = 45;
    private int cheerleaderRadius = 15;

    private int numCheerleaders = 1;
    
    private StringFormat sf = new StringFormat();

    public MainForm()
    {
        InitializeComponent();
        sf.Alignment = StringAlignment.Center;
        sf.LineAlignment = StringAlignment.Center;
        this.Paint  = MainForm_Paint;
        this.SizeChanged  = MainForm_SizeChanged;
    }

    private void MainForm_SizeChanged(object sender, EventArgs e)
    {
        this.Invalidate();
    }

    private void numericUpDown1_ValueChanged(object sender, EventArgs e)
    {
        numCheerleaders = (int)numericUpDown1.Value;
        this.Invalidate();
    }

    private void MainForm_Paint(object sender, PaintEventArgs e)
    {
        // set origin at the bottom left of the form
        Point origin = new Point(cheerleaderRadius * 2, this.ClientRectangle.Height - (cheerleaderRadius*2));
               
        int currentCheerleader = 1;
        int currentColumnNumber = 1;
        int cheerleadersInCurrentColumn;
        while (currentCheerleader <= numCheerleaders)
        {
            cheerleadersInCurrentColumn = 1;
            Point position = new Point(origin.X   (currentColumnNumber - 1) * xOffset, origin.Y);
            while(cheerleadersInCurrentColumn<=currentColumnNumber && currentCheerleader<=numCheerleaders)
            {
                drawCheerleader(e.Graphics, position, (currentCheerleader - 1));
                position.Offset(-xOffset / 2, -yOffset);
                cheerleadersInCurrentColumn  ;
                currentCheerleader  ;
            }
            currentColumnNumber  ;
        }     
    }

    private void drawCheerleader(Graphics g, Point pos, int number)
    {
        RectangleF rc = new RectangleF(pos, new Size(1, 1));
        rc.Inflate(cheerleaderRadius, cheerleaderRadius);
        g.DrawEllipse(Pens.Black, rc);
        g.DrawString(number.ToString(), this.Font, Brushes.Black, rc, sf);
    }

}
  • Related