[UE4] RichTextBlock에서 타자기 연출

13009 단어 C++위 4

어드벤처 게임에서 텍스트를 한 글자씩 표시하게 하는 것입니다.
문자 하나만 표시하면 TextBlock으로 충분하지만 문자 색상을 변경하거나 장식을 추가하기 위해 RichTextBlock을 사용하고 싶습니다. 하지만 구문 분석이라든지 어떻게 하는 거야? 라고 이야기가 됩니다.

RichTextBlock 시리즈



[UE4] RichTextBlock에서 루비 흔들기
[UE4] RichTextBlock에서 자체 태그 정의

RichTextBlock 정보 (가볍게)



UMG 리치 텍스트 블록 - 언리얼 엔진 4 문서

고배는 고양이이다. 이름은 아직 없다.

자주 사용하는 기능으로서는 텍스트중의 부분적인 색변이군요. 색상뿐만 아니라 글꼴 스타일 및 기타 장식도 설정할 수 있습니다. 폰트 설정의 부분 변경을 할 수 없거나, 중첩 구조(문자라든지)로 할 수 없거나 하는 것은 어떻게든 하고 싶은 곳입니다만, 조사해 보면 그것은 더 유연하게 확장 할 수 있도록 설계되었습니다 (구현을 읽는 재미). 그 근처는 또 다음번에도.

한 문자씩 표시



자주 있는 구현이라면, FString::Len() 로 문자수를 취득해 텍스트 치환하는 등이 있다고 생각합니다.

고배는
하지만, 예를 들면 5 문자째까지의 잘라내면 이렇게 되어 버립니다군요.
구문 부분도 잡히기 때문에, 성형 후의 문자수를 취득할 필요가 있습니다.

구문 분석 클래스 확장



구문 분석의 구현은 FDefaultRichTextMarkupParser 로 되어 있어 URichTextBlock::CreateMarkupParser 로부터 확장을 할 수 있게 되어 있습니다. 우선은 URichTextBlock 상속의 UMyRichTextBlock 를 작성합니다.

MyRichTextBlock.cpp
TSharedPtr<IRichTextMarkupParser> UMyRichTextBlock::CreateMarkupParser()
{
    // 後で MarkupParserInstance にアクセスするために SharedPtr をメンバ変数に保存する
    RichTextMarkupParser = MakeShareable( new FMyDefaultRichTextMarkupParser() );
    return RichTextMarkupParser;
}

void UMyRichTextBlock::SetCharacterCount( int32 NewCount )
{
    if ( RichTextMarkupParser.IsValid() )
    {
        // 後述の MyDefaultRichTextMarkupParser へ表示位置を渡す
        RichTextMarkupParser->SetDisplayCharacterCount( NewCount );
        if ( MyRichTextBlock.IsValid() )
        {
            // 解析処理を再実行
            MyRichTextBlock->Refresh();
        }
    }
}

여기에서는 FDefaultRichTextMarkupParser를 복제한 FMyDefaultRichTextMarkupParser를 만들고 확장합니다.

MyRichTextMarkupProcessing.cpp
void FMyDefaultRichTextMarkupParser::Process(
    TArray<FTextLineParseResults>& Results, const FString& Input, FString& Output )
{
    // エンジン側実装の構文解析処理
    TArray<FTextRange> LineRanges;
    FTextRange::CalculateLineRangesFromString( Input, LineRanges );
    ParseLineRanges( Input, LineRanges, Results );
    HandleEscapeSequences( Input, Results, Output );

    // 整形後の文字列をさらに整形する処理を追加
    bHiddenCharacters = HiddenCharacters( Results, DisplayString, Output );
}

void FMyDefaultRichTextMarkupParser::SetDisplayCharacterCount( int32 NewCount )
{
    // 表示位置を指定する
    DisplayCharacterCount = NewCount;
}

bool FMyDefaultRichTextMarkupParser::HiddenCharacters(
    const TArray<FTextLineParseResults>& LineParseResultsArray,
    FString& OutDisplayString, FString& InOutConcatenatedLines ) const
{
    bool bFoundToReplace = false;
    OutDisplayString.Empty();

    if ( !InOutConcatenatedLines.IsEmpty() && DisplayCharacterCount != INDEX_NONE )
    {
        int32 CharIndex = 0;
        for ( const FTextLineParseResults& LineParseResult : LineParseResultsArray )
        {
            for ( const FTextRunParseResults& RunParseResult : LineParseResult.Runs )
            {
                FTextRange TargetRange =
                    RunParseResult.ContentRange.IsEmpty() ?
                    RunParseResult.OriginalRange : RunParseResult.ContentRange;

                // 整形後の文字列を保存する
                OutDisplayString += InOutConcatenatedLines.Mid(
                    TargetRange.BeginIndex, TargetRange.EndIndex - TargetRange.BeginIndex );

                bool bFoundInRunParseResult = false;
                for ( int32 i = 0; i < TargetRange.Len(); ++i )
                {
                    int32 TargetIndex = TargetRange.BeginIndex + i;
                    if ( ensure( InOutConcatenatedLines.IsValidIndex( TargetIndex ) ) )
                    {
                        if ( CharIndex++ < DisplayCharacterCount )
                        {
                            // 表示文字であれば何もしない
                            continue;
                        }

                        // 表示位置まで到達していない文字列は空白に置換する
                        InOutConcatenatedLines[TargetIndex] = *TEXT( "\u0020" );
                        bFoundInRunParseResult = true;
                    }
                }

                bFoundToReplace |= bFoundInRunParseResult;
            }
        }
    }

    return bFoundToReplace;
}

타자기로 숨기는 부분을 공백으로 바꿉니다.
텍스트 내의 공백은 레이아웃 측에서 좋은 느낌으로 처리해 줍니다. 좋은 느낌으로.

블루프린트로 적당히 처리를 작성




Tick에서 DeltaTime을 더하여 표시 간격 시간으로 나눕니다.

좋은 웹페이지 즐겨찾기