Développement d'interface utilisateur utilisant l'architecture ECS (Entity-Component-System) au lieu de l'héritage traditionnel
Cet article est une continuation du discours d'Evgeny Zakharov lors de la conférence d'été C ++ en Russie, où il a décrit le développement d'une interface utilisateur utilisant l'architecture ECS (Entity-Component-System) au lieu de l'héritage traditionnel et une partie du dispositif d'interface utilisateur dans World of Tanks Blitz.
Dans son rapport, Eugene s'attarde en détail sur les principes de création de cadres pour l'interface utilisateur utilisés dans le monde aujourd'hui, et explique également comment se faire des amis ECS et UI, et quels avantages et inconvénients vous pouvez en tirer.
Dans cet article, en utilisant un petit exemple d'interface utilisateur dans World of Tanks Blitz, Eugene montre quel est le gros plus de l'architecture ECS dans l'interface utilisateur.
Avant d'étudier l'article, nous vous conseillons de visionner la vidéo du reportage.
Implémentation de l'affichage de la progression radiale
, , .. , 360 , - 100%. World of Tanks Blitz , , DLC .
, :
texture component;
texture component.
, . , : RadialProgressComponent.
, .
-, :
. : , ( ) "" .
texture- .
:
, texture- , .
:
, : RadialProgressComponent. ( ) 0.5:
:
, , , ( – RadialProgressSystem).
, ClipPolygonComponent – , - . RadialProgress- .
void RadialProgressSystem::RegisterControl(Control &control)
{
auto *pieClippable = control.GetComponent<RadialProgressComponent>();
if (pieClippable && control.GetComponent<TextureComponent>())
{
pieClippable->MarkAsDirty();
this->registeredControls.insert(&control);
}
}
, , TextureComponent RadialProgressComponent. , , – Process.
void RadialProgressSystem::UnregisterControl(Control &control)
{
this->registeredControls.erase(&control);
}
, , .
Progress , . "" dirty RadialProgressComponent. "" , RadialProgressComponent dirty true, false.
void RadialProgressSystem::Process(float elapsedTime)
{
for (Control *control : this->registeredControls)
{
auto *pieClippable = control->GetComponent<UIRadialProgressComponent>();
if (!pieClippable->IsDirty())
{
continue;
}
auto *polygon = control->GetComponent<ClipPolygonComponent>();
if (!polygon)
{
ReportError(control, "You need UIClipPolygonComponent for UIRadialProgressComponent");
continue;
}
auto *textureComponent = control->GetComponent<TextureComponent>();
if (textureComponent != nullptr && textureComponent->GetSprite() != nullptr)
{
Polygon2 &polygonData = polygon->GetPolygon();
polygonData.Clear();
const Vector2 imageSize = textureComponent->GetSprite()->GetSize();
const Vector2 pivot = CalcPivot(pieClippable);
const Vector2 center = imageSize * pivot;
const float progress = pieClippable->GetProgress();
float startAngle = pieClippable->GetNormalizedStartAngle();
float endAngle = pieClippable->GetNormalizedEndAngle();
const float currentAngle = Interpolation::Linear(startAngle, endAngle, 0, progress, 1);
const float width = pivot.x > 0 ? center.x : imageSize.x;
const float height = pivot.y > 0 ? center.y : imageSize.y;
const float initAngle = std::atan(width / height);
polygonData.AddPoint(center);
polygonData.AddPoint(CalcPointOnRectangle(startAngle, center, imageSize));
int direction = startAngle < endAngle ? 1 : -1;
float startOffset = direction > 0 ? 0 : PI_2 + pieClippable->GetAngleBias();
float squareAngle = startOffset + direction * initAngle;
const float directedStartAngle = direction * startAngle;
const float directedEndAngle = direction * endAngle;
const float directedCurrentAngle = direction * currentAngle;
float directedSqureAngle = direction * squareAngle;
const float doubledInitAngle = initAngle * 2.f;
Vector<Vector2> squares {
Vector2(imageSize.x, 0),
Vector2(imageSize.x, imageSize.y),
Vector2(0.f, imageSize.y),
Vector2(0.f, 0.f)
};
int i = 0;
while (directedSqureAngle < directedEndAngle)
{
if (directedSqureAngle < directedCurrentAngle && directedSqureAngle > directedStartAngle)
{
int squareIndex = direction > 0 ? i % 4 : 3 - i % 4;
polygonData.AddPoint(squares[squareIndex]);
}
i++;
int switcher = i % 2;
squareAngle += direction * (PI * switcher - Sign(switcher - 0.5f) * doubledInitAngle);
directedSqureAngle = direction * squareAngle;
}
polygonData.AddPoint(CalcPointOnRectangle(currentAngle, center, imageSize));
pieClippable->ResetDirty();
}
}
}
, RadialProgress-, , – , . :
, UI World of Tanks Blitz – . . ECS UI – , , ( ) .