Skip to content

antonworkgit/rect-orbit-movement-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Rect orbit movement

Проект сделан в рамках технического задания.

Задача - сделать 2D прототип, где персонаж может перемещаться вокруг прямоугольной платформы, плавно огибая углы. Грань платформы всегда является "землей" для персонажа и он не может с нее упасть. Также персонаж должен уметь прыгать.

Демонстрация:

showcase.mp4

Реализация

Для реализации перемещения были выбраны Unity Splines. Замкнутый сплайн используется как путь, по которому перемещается персонаж.

Точки генерируются по часовой стрелке:

points_clockwise
Реализация
{
if (cornerPoints < 2) throw new System.ArgumentOutOfRangeException(nameof(cornerPoints));
int pointsCount = Arcs * cornerPoints;
Vector2[] points = new Vector2[pointsCount];
float hx = size.x * 0.5f;
float hy = size.y * 0.5f;
// Base corners (no offset)
Vector2 tl = position + new Vector2(-hx, hy);
Vector2 tr = position + new Vector2(hx, hy);
Vector2 br = position + new Vector2(hx, -hy);
Vector2 bl = position + new Vector2(-hx, -hy);
float step = 1f / (cornerPoints - 1);
// Top-right (π/2 - 0)
for (int i = 0; i < cornerPoints; i++)
{
float angle = Mathf.Lerp(Mathf.PI / 2f, 0f, step * i);
points[i] = tr + new Vector2(
cornerRadius * Mathf.Cos(angle),
cornerRadius * Mathf.Sin(angle)
);
}
// Bottom-right (0 - −π/2)
for (int i = 0; i < cornerPoints; i++)
{
float angle = Mathf.Lerp(0f, -Mathf.PI / 2f, step * i);
points[cornerPoints + i] = br + new Vector2(
cornerRadius * Mathf.Cos(angle),
cornerRadius * Mathf.Sin(angle)
);
}
// Bottom-left (−π/2 - −π)
for (int i = 0; i < cornerPoints; i++)
{
float angle = Mathf.Lerp(-Mathf.PI / 2f, -Mathf.PI, step * i);
points[cornerPoints * 2 + i] = bl + new Vector2(
cornerRadius * Mathf.Cos(angle),
cornerRadius * Mathf.Sin(angle)
);
}
// Top-left (π - π/2)
for (int i = 0; i < cornerPoints; i++)
{
float angle = Mathf.Lerp(Mathf.PI, Mathf.PI / 2f, step * i);
points[cornerPoints * 3 + i] = tl + new Vector2(
cornerRadius * Mathf.Cos(angle),
cornerRadius * Mathf.Sin(angle)
);
}
return points;
}

Для удобства интерполяции в начало добавляется новая точка, которая будет центром пути (t=0)

Реализация
public OrbPath(Rect rect, PathSettings settings)
{
float cornerRadius = settings.CornerRadius;
int cornerPoints = settings.CornerPoints;
if (cornerRadius < 0) throw new System.ArgumentOutOfRangeException(nameof(cornerRadius));
if (cornerPoints < 2) throw new System.ArgumentOutOfRangeException(nameof(cornerPoints));
Vector2 position = rect.position;
Vector2 size = rect.size;
Vector2[] points = RoundedRectUtility.GetRoundRectPoints(position, size, cornerRadius, cornerPoints);
_spline = new Spline(points.Length + 1, closed: true);
// Extra point that will become 0t of a spline for easy evaluation
Vector2 startPoint = position + new Vector2(0f, size.y * 0.5f + settings.CornerRadius);
AddPoint(startPoint);
foreach (Vector2 point in points)
{
AddPoint(point);
}
_perimeter = _spline.GetLength();
}

В результате получается сплайн, выглядящий следующим образом:

path

Использование Splines позволяет реализовывать дополнительные настройки, а также работать со встроенным редактором.

Для данной задачи это одно из множества подходящих решений и, наверное, одно из самых удобных в движке Unity.

Более оптимизированым решением будет использование простой геометрии:

  1. Определить, к какому сегменту относится t или линейная позиция - к грани или дуге.
  2. Рассчитать точку на грани или дуге соответственно.

About

Move along a rect`s "orbit" with Unity Splines.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages