ECS em UI no cliente World of Tanks Blitz

Desenvolvimento de interface de usuårio usando arquitetura ECS (Entity-Component-System) em vez da herança tradicional

Este artigo Ă© uma continuação do discurso de Evgeny Zakharov na conferĂȘncia de verĂŁo C ++ RĂșssia, onde ele descreveu o desenvolvimento de uma interface de usuĂĄrio usando a arquitetura ECS (Entity-Component-System) em vez da herança tradicional e parte do dispositivo UI no World of Tanks Blitz. 

Em seu relatĂłrio, Eugene se detĂ©m em detalhes sobre quais princĂ­pios de criação de estruturas para IU sĂŁo usados ​​no mundo hoje e tambĂ©m diz como vocĂȘ pode fazer ECS e IU amigos e quais prĂłs e contras vocĂȘ pode obter disso como resultado.

Neste artigo, usando um pequeno exemplo de IU no World of Tanks Blitz, Eugene mostra qual Ă© a grande vantagem da arquitetura ECS na IU.

Antes de estudar o artigo, recomendamos assistir ao vĂ­deo da reportagem.

Implementando exibição de progresso radial

, , .. , 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