//============================================================================= // Copyright 1998-2013 Epic Games, Inc. All Rights Reserved. //============================================================================= class FracturedStaticMeshPart extends FracturedStaticMeshActor native(Mesh) notplaceable; /** This part will be destroyed if it gets further than BaseFracturedMeshActor's radius * DestroyPartRadiusFactor from BaseFracturedMeshActor. */ var float DestroyPartRadiusFactor; /** Base FracturedStaticMeshActor that this part was spawned off of. */ var transient FracturedStaticMeshActor BaseFracturedMeshActor; /** Indicates whether this part has already been recycled and just needs to be initialized to be used again. */ var bool bHasBeenRecycled; /** Last time that this pieces was spawned. */ var float LastSpawnTime; /** Used to know index within pool in FractureManager, so we replace it in the free pool. */ var int PartPoolIndex; /** Additional gravity scaling for fracture pieces*/ var float FracPartGravScale; /** If TRUE, check when piece goes to sleep, and then change its RBChannel. */ var bool bChangeRBChannelWhenAsleep; /** If bChangeRBChannelWhenAsleep is TRUE, RBChannel to switch to when asleep. */ var ERBCollisionChannel AsleepRBChannel; /** Used to store preview frames velocity, to look for sudden velocity changes. */ var vector OldVelocity; /** If oldvel dot newvel < -DestroyVelChangeThresh, destroy piece. */ var float CurrentVibrationLevel; /** Indicates that this part consists of more than 1 chunk - and should explode upon impact. */ var bool bCompositeThatExplodesOnImpact; /** Time since last physics impact sound */ var float LastImpactSoundTime; /** Revive part, set physics to PHYS_RigidBody, enabled collision etc */ simulated native function Initialize(); /** Reset state of this part - clear mesh reference, put in PHYS_None, disable collision etc */ simulated native function RecyclePart(bool bAddToFreePool); cpptext { virtual void TickSpecial(FLOAT DeltaSeconds); virtual FLOAT GetGravityZ(); virtual void OnRigidBodyCollision(const FRigidBodyCollisionInfo& MyInfo, const FRigidBodyCollisionInfo& OtherInfo, const FCollisionImpactData& RigidCollisionData); #if WITH_NOVODEX virtual void ModifyNxActorDesc(NxActorDesc& ActorDesc, UPrimitiveComponent* PrimComp, const class NxGroupsMask& GroupsMask, UINT MatIndex); virtual void PostInitRigidBody(NxActor* nActor, NxActorDesc& ActorDesc, UPrimitiveComponent* PrimComp); #endif // WITH_NOVODEX #if WITH_PHYSX virtual void ModifyPxActor(PxActor* nActor, UPrimitiveComponent* PrimComp, UPhysicalMaterial* PhysMat); #endif //WITH_PHYSX }; /** Used so weapons etc move parts. */ simulated event TakeDamage(int Damage, Controller EventInstigator, vector HitLocation, vector Momentum, class DamageType, optional TraceHitInfo HitInfo, optional Actor DamageCauser) { Super.TakeDamage(Damage, EventInstigator, HitLocation, Momentum, DamageType, HitInfo, DamageCauser); FracturedStaticMeshComponent.AddImpulse(Normal(momentum) * damageType.default.KDamageImpulse, HitLocation); } /** Try to clean up this part if its not seen or it's parent has been removed. If it is seen, keep trying until it isn't. */ simulated function TryToCleanUp() { if(BaseFracturedMeshActor == None || WorldInfo.TimeSeconds - BaseFracturedMeshActor.SkinnedComponent.LastRenderTime > 1.0) { RecyclePart(TRUE); } else { SetTimer( 2.0, FALSE, nameof(TryToCleanUp) ); } } simulated event FellOutOfWorld(class dmgType) { RecyclePart(TRUE); } simulated event Explode() { // Explode is called from OnRigidBodyCollision, which can be fired off multiple times for the same actor, so we must prevent re-entrance if (!bHasBeenRecycled) { super.Explode(); RecyclePart(TRUE); } } /** For broken off pieces, we only want to spawn more parts if its a shatterable composite. */ simulated event BreakOffPartsInRadius(vector Origin, float Radius, float RBStrength, bool bWantPhysChunksAndParticles) { if(bCompositeThatExplodesOnImpact) { super.BreakOffPartsInRadius(Origin, Radius, RBStrength, bWantPhysChunksAndParticles); } } `if(`__TW_PHYSICS_) simulated event Reset() { RecyclePart( true ); } `endif defaultproperties { `if(`__TW_LIGHTING_MODIFICATIONS_) // Light environment is not in components list to begin with `else Components.Remove(LightEnvironment0) `endif Components.Remove(FracturedSkinnedComponent0) SkinnedComponent=none Begin Object Name=FracturedStaticMeshComponent0 bCastDynamicShadow=FALSE bForceDirectLightMap=FALSE bAllowApproximateOcclusion=TRUE BlockRigidBody=TRUE bAcceptsStaticDecals=FALSE bAcceptsDynamicDecals=FALSE bSkipRBGeomCreation=TRUE // ModifyNxActorDesc fills in geometry BlockNonZeroExtent=FALSE BlockZeroExtent=FALSE RBChannel=RBCC_FracturedMeshPart RBCollideWithChannels=(Default=TRUE,GameplayPhysics=TRUE,EffectPhysics=TRUE,FracturedMeshPart=TRUE) bUseVisibleVertsForBounds=TRUE bUseDynamicIndexBuffer=FALSE bUseDynamicIBWithHiddenFragments=FALSE bUseSkinnedRendering=TRUE bInitialVisibilityValue=FALSE bUsePrecomputedShadows=FALSE `if(`__TW_PHYSICS_) bNotifyRigidBodyCollision=true `endif End Object DestroyPartRadiusFactor=10; bNoDelete=FALSE bMovable=TRUE bWorldGeometry=FALSE bPathColliding=FALSE TickGroup=TG_PostAsyncWork bNetInitialRotation=true bCollideActors=TRUE bBlockActors=FALSE bNoEncroachCheck=TRUE Physics=PHYS_RigidBody RemoteRole=ROLE_None LifeSpan=15.0 FracPartGravScale=2.0 bChangeRBChannelWhenAsleep=FALSE AsleepRBChannel=RBCC_GameplayPhysics }