把啦啦队员换成杂技演员.杂技演员不是 pyramid ,而是以柱子形式直接堆叠在彼此的顶部,上下笔直地站在彼此的肩膀上.列号从左侧开始,最左侧的列指定为1,并随着向右移动而递增.
以下是安排杂技演员的规则:
In column 1, you stack 1 acrobat.
In column 2, you stack 2 acrobats.
In column 3, you stack 3 acrobats.
Etc...
这是9名杂技演员的样子:
9
5 8
2 4 7
0 1 3 6
现在想象一下,杂技演员非常强壮,可以偏离中心站立,所以只有一条腿在下面的人身上,相反的腿和相反的肩膀.它们都在相同的方向上偏移,使每一列都倾斜到一边.
每个堆叠的杂技演员都恰好是最下面一排杂技演员之间距离的一半,所以看起来他们就像是直接站在下面两个杂技演员的上面:
9
5 8
2 4 7
0 1 3 6
看起来眼熟吗? pyramid 不是真正的 pyramid ,它是一组倾斜的柱子!
因此,算法就是在每一列中保持正确的杂技演员数量,随着你向上移动,每一位杂技演员都向左偏移半列.每当你到达栏目的顶端,你就开始一个新的栏目,然后重复,直到你达到了所需的杂技演员数量.每个底部杂技演员在新的一列中的开始位置很容易计算,因为它只是 pyramid 原点(左下角)右侧的列号减一乘以水平偏移距离.
我不是Unity程序员,这是为C#WinForms编写的,但我确信您将能够理解算法和代码.
以下是该计划的核心部分:
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++;
}
}
这就是它在行动中的样子.每次啦啦队员的人数发生变化,下面的 pyramid 就会被重新绘制:
下面是整个C#WinForms程序:
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);
}
}