void AZombieCharacter::Attack()
{
//This function is used only when it's permitted by the zombie's animation instance
//It creates a raycast in a sphere shape and checks for possible hits
//If the hits contain our player it makes sure it applies damage to him
//Setting up the start and end location of the raycast
FVector StartLocation = GetMesh()->GetSocketLocation(FName("MeleeStartSocket"));
FVector EndLocation = GetMesh()->GetSocketLocation(FName("MeleeEndSocket"));
//Raycasting in a sphere to detect collisions
TArray<FHitResult> HitResults;
//Setting up the shape of the raycast
FCollisionShape CollisionShape;
CollisionShape.ShapeType = ECollisionShape::Sphere;
CollisionShape.SetSphere(AttackRaycastRadius);
//Object query parameters
FCollisionObjectQueryParams ObjectQueryParams;
ObjectQueryParams.AllDynamicObjects;
//Handling ignored actors
FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(this);
UWorld* World = GetWorld();
if (World && ZAnimInstance->bEligibleForAttack)
{
//Raycasting...
bool bHit = World->SweepMultiByObjectType(HitResults, StartLocation, EndLocation, FQuat::Identity, ObjectQueryParams, CollisionShape, QueryParams);
//Raycast visualization
/*FVector Center = ((EndLocation - StartLocation) / 2) + StartLocation;
DrawDebugSphere(World, Center, AttackRaycastRadius, 20, FColor::Green, false, 2.f);*/
//Checking for possible hits
if (bHit)
{
for (auto It = HitResults.CreateIterator(); It; It++)
{
ARoguelikeChar* Char = Cast<ARoguelikeChar>(It->GetActor());
if (Char && ZAnimInstance && GetCharacterMovement())
{
//Calling the attack function from character
Char->TakeDamageFromZombie(Damage);
//Closing the flag which checks for the attack function
ZAnimInstance->bEligibleForAttack = false;
//Updating with new movement speed
GetCharacterMovement()->MaxWalkSpeed = InitialMaxWalkSpeed;
ZAnimInstance->Speed = InitialMaxWalkSpeed;
break;
}
}
}
}
}
void UChildActorComponent::CreateChildActor()
{
// Kill spawned actor if we have one
DestroyChildActor();
// This is no longer needed
if (CachedInstanceData)
{
delete CachedInstanceData;
CachedInstanceData = nullptr;
}
// If we have a class to spawn.
if(ChildActorClass != nullptr)
{
UWorld* World = GetWorld();
if(World != nullptr)
{
// Before we spawn let's try and prevent cyclic disaster
bool bSpawn = true;
AActor* Actor = GetOwner();
while (Actor && bSpawn)
{
if (Actor->GetClass() == ChildActorClass)
{
bSpawn = false;
UE_LOG(LogChildActorComponent, Error, TEXT("Found cycle in child actor component '%s'. Not spawning Actor of class '%s' to break."), *GetPathName(), *ChildActorClass->GetName());
}
Actor = Actor->ParentComponentActor.Get();
}
if (bSpawn)
{
FActorSpawnParameters Params;
Params.bNoCollisionFail = true;
Params.bDeferConstruction = true; // We defer construction so that we set ParentComponentActor prior to component registration so they appear selected
Params.bAllowDuringConstructionScript = true;
Params.OverrideLevel = GetOwner()->GetLevel();
Params.Name = ChildActorName;
if (!HasAllFlags(RF_Transactional))
{
Params.ObjectFlags &= ~RF_Transactional;
}
// Spawn actor of desired class
FVector Location = GetComponentLocation();
FRotator Rotation = GetComponentRotation();
ChildActor = World->SpawnActor(ChildActorClass, &Location, &Rotation, Params);
// If spawn was successful,
if(ChildActor != nullptr)
{
ChildActorName = ChildActor->GetFName();
// Remember which actor spawned it (for selection in editor etc)
ChildActor->ParentComponentActor = GetOwner();
ChildActor->AttachRootComponentTo(this);
// Parts that we deferred from SpawnActor
ChildActor->FinishSpawning(ComponentToWorld);
}
}
}
}
}
UWorld* NUTNet::CreateUnitTestWorld(bool bHookTick/*=true*/)
{
UWorld* ReturnVal = NULL;
// Unfortunately, this hack is needed, to avoid a crash when running as commandlet
// NOTE: Sometimes, depending upon build settings, PRIVATE_GIsRunningCommandlet is a define instead of a global
#ifndef PRIVATE_GIsRunningCommandlet
bool bIsCommandlet = PRIVATE_GIsRunningCommandlet;
PRIVATE_GIsRunningCommandlet = false;
#endif
ReturnVal = UWorld::CreateWorld(EWorldType::None, false);
#ifndef PRIVATE_GIsRunningCommandlet
PRIVATE_GIsRunningCommandlet = bIsCommandlet;
#endif
if (ReturnVal != NULL)
{
UnitTestWorlds.Add(ReturnVal);
// Hook the new worlds 'tick' event, so that we can capture logging
if (bHookTick)
{
FWorldTickHook* TickHook = new FWorldTickHook(ReturnVal);
ActiveTickHooks.Add(TickHook);
TickHook->Init();
}
// Hack-mark the world as having begun play (when it has not)
ReturnVal->bBegunPlay = true;
// Hack-mark the world as having initialized actors (to allow RPC hooks)
ReturnVal->bActorsInitialized = true;
// Enable pause, using the PlayerController of the primary world (unless we're in the editor)
if (!GIsEditor)
{
AWorldSettings* CurSettings = ReturnVal->GetWorldSettings();
if (CurSettings != NULL)
{
ULocalPlayer* PrimLocPlayer = GEngine->GetFirstGamePlayer(NUTUtil::GetPrimaryWorld());
APlayerController* PrimPC = (PrimLocPlayer != NULL ? PrimLocPlayer->PlayerController : NULL);
APlayerState* PrimState = (PrimPC != NULL ? PrimPC->PlayerState : NULL);
if (PrimState != NULL)
{
CurSettings->Pauser = PrimState;
}
}
}
// Create a blank world context, to prevent crashes
FWorldContext& CurContext = GEngine->CreateNewWorldContext(EWorldType::None);
CurContext.SetCurrentWorld(ReturnVal);
}
return ReturnVal;
}
void UChildActorComponent::CreateChildActor()
{
// Kill spawned actor if we have one
DestroyChildActor();
// If we have a class to spawn.
if(ChildActorClass != nullptr)
{
UWorld* World = GetWorld();
if(World != nullptr)
{
// Before we spawn let's try and prevent cyclic disaster
bool bSpawn = true;
AActor* MyOwner = GetOwner();
AActor* Actor = MyOwner;
while (Actor && bSpawn)
{
if (Actor->GetClass() == ChildActorClass)
{
bSpawn = false;
UE_LOG(LogChildActorComponent, Error, TEXT("Found cycle in child actor component '%s'. Not spawning Actor of class '%s' to break."), *GetPathName(), *ChildActorClass->GetName());
}
if (UChildActorComponent* ParentComponent = Actor->GetParentComponent())
{
Actor = ParentComponent->GetOwner();
}
else
{
Actor = nullptr;
}
}
if (bSpawn)
{
FActorSpawnParameters Params;
Params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
Params.bDeferConstruction = true; // We defer construction so that we set ParentComponent prior to component registration so they appear selected
Params.bAllowDuringConstructionScript = true;
Params.OverrideLevel = (MyOwner ? MyOwner->GetLevel() : nullptr);
Params.Name = ChildActorName;
if (!HasAllFlags(RF_Transactional))
{
Params.ObjectFlags &= ~RF_Transactional;
}
// Spawn actor of desired class
FVector Location = GetComponentLocation();
FRotator Rotation = GetComponentRotation();
ChildActor = World->SpawnActor(ChildActorClass, &Location, &Rotation, Params);
// If spawn was successful,
if(ChildActor != nullptr)
{
ChildActorName = ChildActor->GetFName();
// Remember which component spawned it (for selection in editor etc)
FActorParentComponentSetter::Set(ChildActor, this);
// Parts that we deferred from SpawnActor
const FComponentInstanceDataCache* ComponentInstanceData = (CachedInstanceData ? CachedInstanceData->ComponentInstanceData : nullptr);
ChildActor->FinishSpawning(ComponentToWorld, false, ComponentInstanceData);
ChildActor->AttachRootComponentTo(this, NAME_None, EAttachLocation::SnapToTarget);
}
}
}
}
// This is no longer needed
if (CachedInstanceData)
{
delete CachedInstanceData;
CachedInstanceData = nullptr;
}
}
void UParticleModuleCollision::Update(FParticleEmitterInstance* Owner, int32 Offset, float DeltaTime)
{
SCOPE_CYCLE_COUNTER(STAT_ParticleCollisionTime);
check(Owner);
check(Owner->Component);
UWorld* World = Owner->Component->GetWorld();
if (Owner->ActiveParticles == 0 || (bDropDetail && World && World->bDropDetail))
{
return;
}
//Gets the owning actor of the component. Can be NULL if the component is spawned with the World as an Outer, e.g. in UGameplayStatics::SpawnEmitterAtLocation().
AActor* Actor = Owner->Component->GetOwner();
UParticleLODLevel* LODLevel = Owner->SpriteTemplate->GetCurrentLODLevel(Owner);
check(LODLevel);
const int32 MeshRotationOffset = Owner->GetMeshRotationOffset();
const bool bMeshRotationActive = Owner->IsMeshRotationActive();
const FTransform& OwnerTM = Owner->Component->GetAsyncComponentToWorld();
const FVector ParentScale = OwnerTM.GetScale3D();
FParticleEventInstancePayload* EventPayload = NULL;
if (LODLevel->EventGenerator)
{
EventPayload = (FParticleEventInstancePayload*)(Owner->GetModuleInstanceData(LODLevel->EventGenerator));
if (EventPayload &&
(EventPayload->bCollisionEventsPresent == false) &&
(EventPayload->bDeathEventsPresent == false))
{
EventPayload = NULL;
}
}
FParticleCollisionInstancePayload* CollisionInstPayload = (FParticleCollisionInstancePayload*)(Owner->GetModuleInstanceData(this));
const TArray<FVector>& PlayerLocations = Owner->Component->GetPlayerLocations();
TArray<float> PlayerLODDistanceFactor = Owner->Component->GetPlayerLODDistanceFactor(); //Make a copy because we need to square it later
const int32 PlayerCount = PlayerLocations.Num();
if (World->IsGameWorld())
{
bool bIgnoreAllCollision = false;
// LOD collision based on visibility
// This is at the 'emitter instance' level as it will be true or false for the whole instance...
if (bCollideOnlyIfVisible && ((World->TimeSeconds - Owner->Component->LastRenderTime) > 0.1f))
{
// no collision if not recently rendered
bIgnoreAllCollision = true;
}
else
{
// If the MaxCollisionDistance is greater than WORLD_MAX, they obviously want the check disabled...
if (MaxCollisionDistance < WORLD_MAX)
{
// If we have at least a few particles, do a simple check vs. the bounds
if (Owner->ActiveParticles > 7)
{
if (CollisionInstPayload->CurrentLODBoundsCheckCount == 0)
{
FBox BoundingBox;
BoundingBox.Init();
if (Owner->Component->Template && Owner->Component->Template->bUseFixedRelativeBoundingBox)
{
BoundingBox = Owner->Component->Template->FixedRelativeBoundingBox.TransformBy(OwnerTM);
}
else
{
// A frame behind, but shouldn't be an issue...
BoundingBox = Owner->Component->GetAsyncBounds().GetBox();
}
// see if any player is within the extended bounds...
bIgnoreAllCollision = true;
// Check for the system itself beyond beyond the bounds
// LOD collision by distance
bool bCloseEnough = false;
for (int32 PlyrIdx = 0; PlyrIdx < PlayerCount; PlyrIdx++)
{
// Invert the LOD distance factor here because we are using it to *expand* the
// bounds rather than shorten the distance checked as it is usually used for.
float InvDistanceFactor = 1.0f / PlayerLODDistanceFactor[PlyrIdx];
FBox CheckBounds = BoundingBox;
float BoxExpansionValue = MaxCollisionDistance * InvDistanceFactor;
BoxExpansionValue += BoxExpansionValue * 0.075f;
// Expand it by the max collision distance (and a little bit extra)
CheckBounds = CheckBounds.ExpandBy(BoxExpansionValue);
if (CheckBounds.IsInside(PlayerLocations[PlyrIdx]))
{
// If one is close enough, that's all it takes!
bCloseEnough = true;
break;
}
}
if (bCloseEnough == true)
{
bIgnoreAllCollision = false;
}
//.........这里部分代码省略.........
//.........这里部分代码省略.........
// Save info about actor to reattach
FAttachedActorInfo Info;
Info.AttachedActor = AttachedActor;
Info.AttachedToSocket = EachRoot->AttachSocketName;
Info.bSetRelativeTransform = false;
AttachedActorInfos.Add(Info);
// Now detach it
AttachedActor->Modify();
EachRoot->DetachFromParent(true);
}
}
}
if (bUseRootComponentProperties && RootComponent != nullptr)
{
// Do not need to detach if root component is not going away
if (RootComponent->AttachParent != NULL && RootComponent->bCreatedByConstructionScript)
{
Parent = RootComponent->AttachParent->GetOwner();
// Root component should never be attached to another component in the same actor!
if (Parent == this)
{
UE_LOG(LogActor, Warning, TEXT("RerunConstructionScripts: RootComponent (%s) attached to another component in this Actor (%s)."), *RootComponent->GetPathName(), *Parent->GetPathName());
Parent = NULL;
}
ParentComponent = RootComponent->AttachParent;
SocketName = RootComponent->AttachSocketName;
//detach it to remove any scaling
RootComponent->DetachFromParent(true);
}
OldTransform = RootComponent->ComponentToWorld;
OldTransform.SetTranslation(RootComponent->GetComponentLocation()); // take into account any custom location
}
// Destroy existing components
DestroyConstructedComponents();
// Reset random streams
ResetPropertiesForConstruction();
// Exchange net roles before running construction scripts
UWorld *OwningWorld = GetWorld();
if (OwningWorld && !OwningWorld->IsServer())
{
ExchangeNetRoles(true);
}
// Run the construction scripts
ExecuteConstruction(OldTransform, InstanceDataCache);
if(Parent)
{
USceneComponent* ChildRoot = GetRootComponent();
if (ParentComponent == NULL)
{
ParentComponent = Parent->GetRootComponent();
}
if (ChildRoot != NULL && ParentComponent != NULL)
{
ChildRoot->AttachTo(ParentComponent, SocketName, EAttachLocation::KeepWorldPosition);
}
}
// If we had attached children reattach them now - unless they are already attached
for(FAttachedActorInfo& Info : AttachedActorInfos)
{
// If this actor is no longer attached to anything, reattach
if (!Info.AttachedActor->IsPendingKill() && Info.AttachedActor->GetAttachParentActor() == NULL)
{
USceneComponent* ChildRoot = Info.AttachedActor->GetRootComponent();
if (ChildRoot && ChildRoot->AttachParent != RootComponent)
{
ChildRoot->AttachTo(RootComponent, Info.AttachedToSocket, EAttachLocation::KeepWorldPosition);
if (Info.bSetRelativeTransform)
{
ChildRoot->SetRelativeTransform(Info.RelativeTransform);
}
ChildRoot->UpdateComponentToWorld();
}
}
}
// Restore the undo buffer
GUndo = CurrentTransaction;
#if WITH_EDITOR
if (ActorTransactionAnnotation)
{
CurrentTransactionAnnotation = NULL;
}
else
#endif
{
delete InstanceDataCache;
}
}
}
void UMaterialParameterCollection::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
// If the array counts have changed, an element has been added or removed, and we need to update the uniform buffer layout,
// Which also requires recompiling any referencing materials
if (ScalarParameters.Num() != PreviousScalarParameters.Num()
|| VectorParameters.Num() != PreviousVectorParameters.Num())
{
// Limit the count of parameters to fit within uniform buffer limits
const uint32 MaxScalarParameters = 1024;
if (ScalarParameters.Num() > MaxScalarParameters)
{
ScalarParameters.RemoveAt(MaxScalarParameters, ScalarParameters.Num() - MaxScalarParameters);
}
const uint32 MaxVectorParameters = 1024;
if (VectorParameters.Num() > MaxVectorParameters)
{
VectorParameters.RemoveAt(MaxVectorParameters, VectorParameters.Num() - MaxVectorParameters);
}
// Generate a new Id so that unloaded materials that reference this collection will update correctly on load
StateId = FGuid::NewGuid();
// Update the uniform buffer layout
CreateBufferStruct();
// Recreate each instance of this collection
for (TObjectIterator<UWorld> It; It; ++It)
{
UWorld* CurrentWorld = *It;
CurrentWorld->AddParameterCollectionInstance(this, false);
}
// Build set of changed parameter names
TSet<FName> ParameterNames;
for (const FCollectionVectorParameter& Param : PreviousVectorParameters)
{
ParameterNames.Add(Param.ParameterName);
}
for (const FCollectionScalarParameter& Param : PreviousScalarParameters)
{
ParameterNames.Add(Param.ParameterName);
}
for (const FCollectionVectorParameter& Param : VectorParameters)
{
ParameterNames.Remove(Param.ParameterName);
}
for (const FCollectionScalarParameter& Param : ScalarParameters)
{
ParameterNames.Remove(Param.ParameterName);
}
// Create a material update context so we can safely update materials using this parameter collection.
{
FMaterialUpdateContext UpdateContext;
// Go through all materials in memory and recompile them if they use this material parameter collection
for (TObjectIterator<UMaterial> It; It; ++It)
{
UMaterial* CurrentMaterial = *It;
bool bRecompile = false;
// Preview materials often use expressions for rendering that are not in their Expressions array,
// And therefore their MaterialParameterCollectionInfos are not up to date.
if (CurrentMaterial->bIsPreviewMaterial)
{
bRecompile = true;
}
else
{
for (int32 FunctionIndex = 0; FunctionIndex < CurrentMaterial->MaterialParameterCollectionInfos.Num() && !bRecompile; FunctionIndex++)
{
if (CurrentMaterial->MaterialParameterCollectionInfos[FunctionIndex].ParameterCollection == this)
{
TArray<UMaterialExpressionCollectionParameter*> CollectionParameters;
CurrentMaterial->GetAllExpressionsInMaterialAndFunctionsOfType(CollectionParameters);
for (UMaterialExpressionCollectionParameter* CollectionParameter : CollectionParameters)
{
if (ParameterNames.Contains(CollectionParameter->ParameterName))
{
bRecompile = true;
break;
}
}
}
}
}
if (bRecompile)
{
UpdateContext.AddMaterial(CurrentMaterial);
// Propagate the change to this material
CurrentMaterial->PreEditChange(NULL);
//.........这里部分代码省略.........
请发表评论