This recipe shows you how to use the concepts introduced in the previous recipes to create an actor that informs other actors of the passage of time within your game.
Actor
class called TimeOfDayHandler
.DECLARE_MULTICAST_DELEGATE_TwoParams(FOnTimeChangedSignature, int32, int32)
FOnTimeChangedSignatureOnTimeChanged;
UPROPERTY() int32 TimeScale; UPROPERTY() int32 Hours; UPROPERTY() int32 Minutes; UPROPERTY() float ElapsedSeconds;
TimeScale = 60; Hours = 0; Minutes = 0; ElapsedSeconds = 0;
Tick
, add the following code:ElapsedSeconds += (DeltaTime * TimeScale); if (ElapsedSeconds> 60) { ElapsedSeconds -= 60; Minutes++; if (Minutes > 60) { Minutes -= 60; Hours++; } OnTimeChanged.Broadcast(Hours, Minutes); }
Actor
class called Clock
.UPROPERTY() USceneComponent* RootSceneComponent; UPROPERTY() UStaticMeshComponent* ClockFace; UPROPERTY() USceneComponent* HourHandle; UPROPERTY() UStaticMeshComponent* HourHand; UPROPERTY() USceneComponent* MinuteHandle; UPROPERTY() UStaticMeshComponent* MinuteHand; UFUNCTION() void TimeChanged(int32 Hours, int32 Minutes); FDelegateHandleMyDelegateHandle;
RootSceneComponent = CreateDefaultSubobject<USceneComponent>("RootSceneComponent"); ClockFace = CreateDefaultSubobject<UStaticMeshComponent>("ClockFace"); HourHand = CreateDefaultSubobject<UStaticMeshComponent>("HourHand"); MinuteHand = CreateDefaultSubobject<UStaticMeshComponent>("MinuteHand"); HourHandle = CreateDefaultSubobject<USceneComponent>("HourHandle"); MinuteHandle = CreateDefaultSubobject<USceneComponent>("MinuteHandle"); auto MeshAsset = ConstructorHelpers::FObjectFinder<UStaticMesh>(TEXT("StaticMesh'/Engine/BasicShapes/Cylinder.Cylinder'")); if (MeshAsset.Object != nullptr) { ClockFace->SetStaticMesh(MeshAsset.Object); HourHand->SetStaticMesh(MeshAsset.Object); MinuteHand->SetStaticMesh(MeshAsset.Object); } RootComponent = RootSceneComponent; HourHand->AttachTo(HourHandle); MinuteHand->AttachTo(MinuteHandle); HourHandle->AttachTo(RootSceneComponent); MinuteHandle->AttachTo(RootSceneComponent); ClockFace->AttachTo(RootSceneComponent); ClockFace->SetRelativeTransform(FTransform(FRotator(90, 0, 0), FVector(10, 0, 0), FVector(2, 2, 0.1))); HourHand->SetRelativeTransform(FTransform(FRotator(0, 0, 0), FVector(0, 0, 25), FVector(0.1, 0.1, 0.5))); MinuteHand->SetRelativeTransform(FTransform(FRotator(0, 0, 0), FVector(0, 0, 50), FVector(0.1, 0.1, 1)));
BeginPlay
:TArray<AActor*>TimeOfDayHandlers; UGameplayStatics::GetAllActorsOfClass(GetWorld(), ATimeOfDayHandler::StaticClass(), TimeOfDayHandlers); if (TimeOfDayHandlers.Num() != 0) { auto TimeOfDayHandler = Cast<ATimeOfDayHandler>(TimeOfDayHandlers[0]); MyDelegateHandle = TimeOfDayHandler->OnTimeChanged.AddUObject(this, &AClock::TimeChanged); }
TimeChanged
as your event handler.void AClock::TimeChanged(int32 Hours, int32 Minutes) { HourHandle->SetRelativeRotation(FRotator( 0, 0,30 * Hours)); MinuteHandle->SetRelativeRotation(FRotator(0,0,6 * Minutes)); }
TimeOfDayHandler
and the AClock
into your level, and play to see that the hands on the clock are rotating:TimeOfDayHandler
contains a delegate which takes two parameters, hence the use of the TwoParams
variant of the macro.TimeScale
, which is an acceleration factor used to speed up time for testing purposes.Tick
function, we accumulate elapsed seconds based on the time elapsed since the last frame.Minutes
.Minutes
—if they go over 60, we subtract 60, and increment Hours
.Minutes
and Hours
were updated, we broadcast our delegate to let any object that has subscribed to the delegate know that the time has changed.Clock
actor uses a series of Scene components and Static meshes to build a mesh hierarchy that resembles a clock face.Clock
constructor, we parent the components in the hierarchy, and set their initial scale and rotations.BeginPlay
, the clock uses GetAllActorsOfClass()
to fetch all the time of day
handlers in the level.TimeOfDayHandler
in the level, the Clock
accesses the first one, and subscribes to its TimeChanged
event.TimeChanged
event fires, the clock rotates the hour and minute hands based on how many hours and minutes the time currently has.3.148.104.149