【UE4】Montage NextSection problem record

This article uses UE4.26 and the GAS system to record a problem with the Montage Next Section.

1. Problem background and performance

1.1 Problem background

  In UE4, sometimes you need to modify the connection relationship of Section while playing Montage (for the meaning and usage of Montage and Section, please refer here ). For example, sometimes you want to follow the 1st paragraph to the 2nd paragraph, and sometimes you want to follow the 3rd paragraph. segment, you can use to UGameplayAbility::MontageSetNextSectionNameset the next segment of the first segment, and then you can achieve the effect of continuing playback directly from the segment after the end of the first segment.

  If you don't want the current segment to finish playing, but jump directly to the next segment, from the interface point of view, there is no interface with such a function as " JumpToNextSection ", only an interface such as " MontageJumpToSection ", so an interface such as " GetNextSection " is needed. Which is the next Section to the current Section.

1.2 Problem manifestation

  The problem performance can be summarized in one sentence: inconsistent FAnimMontageInstance::GetNextSection()with FAnimMontageInstance::GetNextSectionIDthe results.

FName FAnimMontageInstance::GetNextSection() const
{
    
    
	if (Montage)
	{
    
    
		float CurrentPosition;
		const int32 CurrentSectionIndex = Montage->GetAnimCompositeSectionIndexFromPos(Position, CurrentPosition);
		if (Montage->IsValidSectionIndex(CurrentSectionIndex))
		{
    
    
			FCompositeSection& CurrentSection = Montage->GetAnimCompositeSection(CurrentSectionIndex);
			return CurrentSection.NextSectionName;
		}
	}
	return NAME_None;
}

int32 FAnimMontageInstance::GetNextSectionID(int32 const & CurrentSectionID) const
{
    
    
	return NextSections.IsValidIndex(CurrentSectionID) ? NextSections[CurrentSectionID] : INDEX_NONE;
}

  The two functions are shown above:

  1. GetNextSectionThe current Section is calculated through Position, and then the NextSection is obtained through the variable FCompositeSectionin the type NextSectionName.
  2. Instead GetNextSectionID, the ID of NextSection is obtained through the NextSection array and the ID of the current Section.

  After getting the ID of NextSection through the second method, you can get the Name of NextSection:

FName FAnimMontageInstance::GetSectionNameFromID(int32 const & SectionID) const
{
    
    
	if (Montage && Montage->IsValidSectionIndex(SectionID))
	{
    
    
		FCompositeSection const & CurrentSection = Montage->GetAnimCompositeSection(SectionID);
		return CurrentSection.SectionName;
	}
	return NAME_None;
}

  Judging from the function names, the difference between the two should only be the return name and ID (when the current Section ID is passed as a parameter GetNextSectionID), but because two completely different ways are used to obtain NextSection (one is FCompositeSectiona member variable, the other is NextSectionsan array), actual results may vary.

1.3 Problem recurrence

  Configure a Montage as shown below:
Insert image description here

  There are four Sections, and the next section of each section is the subsequent Section.
  Each segment is configured with a "PrintString" animation notification, which is used to output a configured string. Each segment is configured with the corresponding "2", "3", and "4".
  Run the game and play this Montage. You can see that four are output in order, no problem:

LogAbilitySystem: Error: Print String 1
LogAbilitySystem: Error: Print String 2
LogAbilitySystem: Error: Print String 3
LogAbilitySystem: Error: Print String 4

  Configure an animation notification in the first paragraph. When the notification is triggered, perform the operations of " SetNextSection " and " GetNextSection " (for testing, although you can jump directly),
Insert image description here

  code show as below:

ACharacter* const Character = Cast<ACharacter>(GetOwningActorFromActorInfo());
if (!Character)
{
    
    
	return;
}

UAbilitySystemComponent* const ASC = GetAbilitySystemComponentFromActorInfo_Checked();
if (!ASC)
{
    
    
	return;
}

UAnimInstance* const AnimInstance = Character->GetMesh()->GetAnimInstance();
if (!AnimInstance)
{
    
    
	return;
}

FAnimMontageInstance* const AnimMontageInstance = AnimInstance->GetActiveInstanceForMontage(ASC->GetCurrentMontage());
if (!AnimMontageInstance)
{
    
    
	return;
}

MontageSetNextSectionName("1", "3");

FName const CurSection = AnimMontageInstance->GetCurrentSection();
FName const NextSection1 = AnimMontageInstance->GetNextSection();
FName const NextSection2 = 
	AnimMontageInstance->GetSectionNameFromID(AnimMontageInstance->GetNextSectionID(ASC->GetCurrentMontageSectionID()));
UE_LOG(LogAbilitySystem, Error, 
	TEXT("CurSection is %s; NextSection1 is %s; NextSection2 is %s;"), 
	*CurSection.ToString(), 
	*NextSection1.ToString(), 
	*NextSection2.ToString());

  The point is actually that MontageSetNextSectionName("1", "3");the next paragraph after setting the "1" paragraph is the "3" paragraph instead of the default "2" paragraph.

  The three methods of MontageSetNextSectionName("1", "3");and AnimInstance->Montage_SetNextSection("1", "3", ASC->GetCurrentMontage());and AnimMontageInstance->SetNextSectionName("1", "3");are the same.

  Then Get NextSection in two different ways, the results are as follows:

LogAbilitySystem: Error: CurSection is 1; NextSection1 is 2; NextSection2 is 3;
LogAbilitySystem: Error: Print String 1
LogAbilitySystem: Error: Print String 3
LogAbilitySystem: Error: Print String 4

  From the actual animation performance and output, we can see that the NextSection setting is effective. The end of paragraph "1" is followed by paragraph "3", but the default paragraph "2" is obtained through AnimMontageInstance->GetCurrentSection().

2. Cause of the problem

UGameplayAbility::MontageSetNextSectionName(FName FromSectionName, FName ToSectionName)

  The function above will eventually be adjusted to the following:

bool FAnimMontageInstance::SetNextSectionID(int32 const & SectionID, int32 const & NewNextSectionID)

  The above function only modifies the member variables PrevSectionsand NextSectionsthese two arrays, and does not actually modify the NextSection of the Section on the Montage, as shown in the following figure:
Insert image description here

  Modifying this is equivalent to modifying the configuration of the resource, and it should not be modified itself. Therefore, I personally feel that FAnimMontageInstance::GetNextSection()there is a problem with the writing of this function. It should return the NextSection on the Montage Instance instead of the unadjusted configuration of the resource itself.

Guess you like

Origin blog.csdn.net/Bob__yuan/article/details/117357991