ECS dans l'interface utilisateur dans le client World of Tanks Blitz

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 – , , ( ) .




All Articles