阶段暂存
This commit is contained in:
		| @ -16,7 +16,6 @@ void UBusyActorManagerSubSystem::OnWorldBeginPlay(UWorld& InWorld) { | ||||
| } | ||||
|  | ||||
| void UBusyActorManagerSubSystem::Deinitialize(){ | ||||
| 	// <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD>Luaʵ<61>ֵĺ<D6B5><C4BA><EFBFBD><EFBFBD>ܲ<EFBFBD><DCB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȳ<EFBFBD><C8B2>ṩ<EFBFBD><E1B9A9><EFBFBD>ٵ<EFBFBD>lua<75>ӿڰ<D3BF> | ||||
| 	Super::Deinitialize(); | ||||
| } | ||||
|  | ||||
| @ -26,7 +25,7 @@ FString UBusyActorManagerSubSystem::GetLuaFilePath_Implementation() const{ | ||||
|  | ||||
| bool UBusyActorManagerSubSystem::GetLevelBaseConfig(FBusyLevelBaseConfig& config){ | ||||
| 	FBusyLevelBaseConfig* Config; | ||||
| 	UDataTable *DataTable = UBusyGamePlayLibrary::GetGameDataTable("LevelBaseConfig"); | ||||
| 	UDataTable *DataTable = UBusyGameplayLibrary::GetGameDataTable("LevelBaseConfig"); | ||||
| 	if (!DataTable) return false; | ||||
|  | ||||
| 	Config = DataTable->FindRow<FBusyLevelBaseConfig>( | ||||
|  | ||||
| @ -11,7 +11,7 @@ static inline const UBusyDataAsset* GetGameAsset() { | ||||
|  | ||||
| template<typename RowStruct> | ||||
| static bool GetTableConfig(const FString& TableName, const FName& RowName, RowStruct& RowData) { | ||||
| 	UDataTable* Table = UBusyGamePlayLibrary::GetGameDataTable(TableName); | ||||
| 	UDataTable* Table = UBusyGameplayLibrary::GetGameDataTable(TableName); | ||||
| 	RowStruct* Config = Table->FindRow<RowStruct>( | ||||
| 		RowName, | ||||
| 		*FString::Printf(TEXT("GetTableConfig, %s"), *RowName.ToString()), | ||||
| @ -26,79 +26,59 @@ static bool GetTableConfig(const FString& TableName, const FName& RowName, RowSt | ||||
| 	} | ||||
| } | ||||
|  | ||||
| UDataTable* UBusyGamePlayLibrary::GetGameDataTable(const FString& TableName){ | ||||
| UDataTable* UBusyGameplayLibrary::GetGameDataTable(const FString& TableName){ | ||||
| 	const UBusyDataAsset* GameAsset = GetGameAsset(); | ||||
| 	if (!GameAsset) return nullptr; | ||||
| 	auto Table = (GameAsset->DataTableMapping.Find(TableName)); | ||||
| 	return Table ? Table->Get() : nullptr; | ||||
| } | ||||
|  | ||||
| UClass* UBusyGamePlayLibrary::GetGameClass(const FString& ClassName){ | ||||
| UClass* UBusyGameplayLibrary::GetGameClass(const FString& ClassName){ | ||||
| 	const UBusyDataAsset* GameAsset = GetGameAsset(); | ||||
| 	if (!GameAsset) return nullptr; | ||||
| 	auto Class = (GameAsset->ClassPathMapping.Find(ClassName)); | ||||
| 	return Class ? Class->Get() : nullptr; | ||||
| } | ||||
|  | ||||
| UClass* UBusyGamePlayLibrary::GetGameUIClass(const FString& ClassName){ | ||||
| UClass* UBusyGameplayLibrary::GetGameUIClass(const FString& ClassName){ | ||||
| 	const UBusyDataAsset* GameAsset = GetGameAsset(); | ||||
| 	if (!GameAsset) return nullptr; | ||||
| 	auto Class = (GameAsset->UIPathMapping.Find(ClassName)); | ||||
| 	return Class ? Class->Get() : nullptr; | ||||
| } | ||||
|  | ||||
| UWorld* UBusyGamePlayLibrary::K2_GetWorld(const UObject* obj){ | ||||
| 	return obj->GetWorld(); | ||||
| UWorld* UBusyGameplayLibrary::K2_GetWorld(const UObject* UObj){ | ||||
| 	return UObj->GetWorld(); | ||||
| } | ||||
|  | ||||
| bool UBusyGamePlayLibrary::GetLevelBaseConfig(const FName& RowName, FBusyLevelBaseConfig& RowData){ | ||||
| bool UBusyGameplayLibrary::GetLevelBaseConfig(const FName& RowName, FBusyLevelBaseConfig& RowData){ | ||||
| 	return GetTableConfig<FBusyLevelBaseConfig>(TEXT("LevelBaseConfig"), RowName, RowData); | ||||
| } | ||||
|  | ||||
| bool UBusyGamePlayLibrary::GetLevelItemConfig(const FName& RowName, FBusyLevelItemConfig& RowData){ | ||||
| bool UBusyGameplayLibrary::GetLevelItemConfig(const FName& RowName, FBusyLevelItemConfig& RowData){ | ||||
| 	return GetTableConfig<FBusyLevelItemConfig>(TEXT("LevelItems"), RowName, RowData); | ||||
| } | ||||
|  | ||||
| bool UBusyGamePlayLibrary::GetRoleConfig(const FName& RowName, FBusyRoleConfig& RowData){ | ||||
| bool UBusyGameplayLibrary::GetRoleConfig(const FName& RowName, FBusyRoleConfig& RowData){ | ||||
| 	return GetTableConfig<FBusyRoleConfig>(TEXT("RoleConfig"), RowName, RowData); | ||||
| } | ||||
|  | ||||
| bool UBusyGamePlayLibrary::GetItemResourceConfig(const FName& RowName, FBusyLevelItemResourceConfig& RowData){ | ||||
| bool UBusyGameplayLibrary::GetItemResourceConfig(const FName& RowName, FBusyLevelItemResourceConfig& RowData){ | ||||
| 	return GetTableConfig<FBusyLevelItemResourceConfig>(TEXT("LevelItemResource"), RowName, RowData); | ||||
| } | ||||
|  | ||||
| bool UBusyGamePlayLibrary::GetLevelItemDescription(const FName& RowName, FBusyLevelItemDescription& RowData){ | ||||
| bool UBusyGameplayLibrary::GetLevelItemDescription(const FName& RowName, FBusyLevelItemDescription& RowData){ | ||||
| 	return GetTableConfig<FBusyLevelItemDescription>(TEXT("LevelItemDesc"), RowName, RowData); | ||||
| } | ||||
|  | ||||
| bool UBusyGamePlayLibrary::GetHomelandItemDescription(const FName& RowName, FBusyHomelandItemDescription& RowData){ | ||||
| bool UBusyGameplayLibrary::GetHomelandItemDescription(const FName& RowName, FBusyHomelandItemDescription& RowData){ | ||||
| 	return GetTableConfig<FBusyHomelandItemDescription>(TEXT("HomelandItemDesc"), RowName, RowData); | ||||
| } | ||||
|  | ||||
| bool UBusyGamePlayLibrary::GetItemDescription(const FName& RowName, FBusyItemDescription& RowData){ | ||||
| bool UBusyGameplayLibrary::GetItemDescription(const FName& RowName, FBusyItemDescription& RowData){ | ||||
| 	return GetTableConfig<FBusyItemDescription>(TEXT("ItemDesc"), RowName, RowData); | ||||
| } | ||||
|  | ||||
| bool UBusyGamePlayLibrary::GetCookMaterialStateConfig(const FName& RowName, FBusyCookMaterialStateConfig& RowData){ | ||||
| bool UBusyGameplayLibrary::GetCookMaterialStateConfig(const FName& RowName, FBusyCookMaterialStateConfig& RowData){ | ||||
| 	return GetTableConfig<FBusyCookMaterialStateConfig>(TEXT("CookMaterialStateConfig"), RowName, RowData); | ||||
| } | ||||
|  | ||||
| FLuaBPVar UBusyGamePlayLibrary::CreateTextureBuffer(UObject* WorldContextObject){ | ||||
| 	auto DataTexture = UTexture2D::CreateTransient(512, 1, PF_R32_FLOAT); | ||||
| 	DataTexture->Filter = TF_Trilinear; | ||||
| 	DataTexture->AddressX = TA_Clamp; | ||||
| 	DataTexture->AddressY = TA_Clamp; | ||||
| 	DataTexture->UpdateResource(); | ||||
| 	return ULuaBlueprintLibrary::CreateVarFromObject(WorldContextObject, DataTexture); | ||||
| } | ||||
|  | ||||
| void UBusyGamePlayLibrary::UpdateTextureBuffer(UTexture2D *DataTexture, TArray<float> FloatData){ | ||||
| 	DataTexture->GetPlatformData()->Mips[0]; | ||||
| 	FTexture2DMipMap& Mip = DataTexture->GetPlatformData()->Mips[0]; | ||||
| 	void* Data = Mip.BulkData.Lock(LOCK_READ_WRITE); | ||||
|  | ||||
| 	FMemory::Memcpy(Data, FloatData.GetData(), FloatData.Num() * sizeof(float)); | ||||
|  | ||||
| 	Mip.BulkData.Unlock(); | ||||
| 	DataTexture->UpdateResource(); | ||||
| } | ||||
|  | ||||
| @ -14,9 +14,7 @@ ABusyPawnBase::ABusyPawnBase() | ||||
| 	SpineRenderComponent = CreateDefaultSubobject<USpineSkeletonRendererComponent>(TEXT("SpineRenderComponent")); | ||||
| 	SpineAnimationComponent = CreateDefaultSubobject<USpineSkeletonAnimationComponent>(TEXT("SpineAnimationComponent")); | ||||
| 	AbilitySystemComponent = CreateDefaultSubobject<UBusyAbilitySystemComponent>(TEXT("AbilitySystemComponent")); | ||||
| 	 | ||||
| 	MovementComponent = CreateDefaultSubobject<UBusyPawnMovement>(TEXT("MovementComponent")); | ||||
|  | ||||
| 	 | ||||
| 	RootComponent = RootScene; | ||||
| 	SpineRoot->SetupAttachment(RootScene); | ||||
| @ -24,20 +22,13 @@ ABusyPawnBase::ABusyPawnBase() | ||||
| 	SpineRenderComponent->SetupAttachment(SpineRoot); | ||||
|  | ||||
| 	SpineRoot->SetRelativeRotation(FRotator(0, 0, -90)); | ||||
|  | ||||
|  | ||||
| 	bReplicates = true; | ||||
| 	SetReplicatingMovement(true); | ||||
| 	NetUpdateFrequency = 60.0f; | ||||
| 	MovementComponent->SetIsReplicated(true); | ||||
| 	AbilitySystemComponent->SetIsReplicated(true); | ||||
| } | ||||
|  | ||||
| void ABusyPawnBase::BeginPlay() | ||||
| { | ||||
| 	Super::BeginPlay(); | ||||
| 	SpineAnimationComponent->SetSkin(DefaultSkinName); | ||||
| 	SpineAnimationComponent->SetAnimation(0, DefaultAnimationName, true); | ||||
| 	// SpineAnimationComponent->SetSkin(DefaultSkinName); | ||||
| 	// SpineAnimationComponent->SetAnimation(0, DefaultAnimationName, true); | ||||
| } | ||||
|  | ||||
| void ABusyPawnBase::UpdateMoveDirection_Implementation(const FVector2D& InDirection) | ||||
|  | ||||
							
								
								
									
										24
									
								
								Source/BusyRabbit/Private/Level/Actor/BusyStaticResource.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Source/BusyRabbit/Private/Level/Actor/BusyStaticResource.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| #include "Level/Actor/BusyStaticResource.h" | ||||
| #include "SpineSkeletonRendererComponent.h" | ||||
| #include "SpineSkeletonAnimationComponent.h" | ||||
|  | ||||
| ABusyStaticResource::ABusyStaticResource() | ||||
| { | ||||
| 	RootScene = CreateDefaultSubobject<USceneComponent>(TEXT("RootScene")); | ||||
| 	SpineRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SpineRoot")); | ||||
|  | ||||
| 	SpineRenderComponent = CreateDefaultSubobject<USpineSkeletonRendererComponent>("SpineRenderComponent"); | ||||
| 	SpineAnimationComponent = CreateDefaultSubobject<USpineSkeletonAnimationComponent>("SpineAnimationComponent"); | ||||
|  | ||||
| 	SetRootComponent(RootScene); | ||||
| 	SpineRoot->SetupAttachment(RootScene); | ||||
| 	SpineRenderComponent->SetupAttachment(SpineRoot); | ||||
| 	SpineRoot->SetRelativeRotation(FRotator(0, 0, -90)); | ||||
| } | ||||
|  | ||||
| void ABusyStaticResource::BeginPlay() | ||||
| { | ||||
| 	Super::BeginPlay(); | ||||
| 	SpineAnimationComponent->SetSkin("default"); | ||||
| 	SpineAnimationComponent->SetAnimation(0, "idle", true); | ||||
| } | ||||
| @ -30,14 +30,11 @@ FVector2D UBusyPawnMovement::GetMoveDirection()const | ||||
| 	return FVector2D(); | ||||
| } | ||||
|  | ||||
| #pragma optimize("",off) | ||||
| void UBusyPawnMovement::TickComponent(float DeltaTime, ELevelTick TickType, | ||||
| 							FActorComponentTickFunction* ThisTickFunction) | ||||
| { | ||||
| 	Super::TickComponent(DeltaTime, TickType, ThisTickFunction); | ||||
|  | ||||
| 	if (!GetOwner()->HasAuthority()) return; | ||||
| 	 | ||||
| 	AActor* Owner = GetOwner(); | ||||
| 	const IBusyMovable* Movable = Cast<IBusyMovable>(Owner); | ||||
| 	if (!Owner || !Movable) return; | ||||
| @ -66,11 +63,7 @@ void UBusyPawnMovement::TickComponent(float DeltaTime, ELevelTick TickType, | ||||
| 	if (!NewLocation.Equals(CurrentLocation)) | ||||
| 	{ | ||||
| 		Owner->SetActorLocation(NewLocation, true); | ||||
| 		Owner->ForceNetUpdate(); | ||||
| 	} | ||||
|  | ||||
| 	 | ||||
| 	// Movable->Execute_UpdateMoveDirection(Owner, GetMoveDirection()); | ||||
| 	Movable->Execute_UpdateMoveDirection(Owner, GetMoveDirection()); | ||||
| } | ||||
| #pragma optimize("",on) | ||||
|  | ||||
|  | ||||
| @ -32,7 +32,7 @@ void ABusyLevelItem::OnConstruction(const FTransform& Transform){ | ||||
| } | ||||
|  | ||||
| void ABusyLevelItem::BeginPlay(){ | ||||
| 	UClass* cls = UBusyGamePlayLibrary::GetGameUIClass("PickBar"); | ||||
| 	UClass* cls = UBusyGameplayLibrary::GetGameUIClass("PickBar"); | ||||
| 	if (cls != nullptr) { | ||||
| 		PickBar->SetWidgetClass(cls); | ||||
| 	} | ||||
| @ -81,7 +81,7 @@ void ABusyLevelItem::InitPickBar(){ | ||||
| } | ||||
|  | ||||
| void ABusyLevelItem::SetItemDisplay(const FName& ItemID){ | ||||
| 	UDataTable* Resource = UBusyGamePlayLibrary::GetGameDataTable(TEXT("LevelItemResource")); | ||||
| 	UDataTable* Resource = UBusyGameplayLibrary::GetGameDataTable(TEXT("LevelItemResource")); | ||||
|  | ||||
| 	// 查物品信息 | ||||
| 	FBusyLevelItemResourceConfig* ResourceConfig = Resource->FindRow<FBusyLevelItemResourceConfig>( | ||||
| @ -97,7 +97,7 @@ void ABusyLevelItem::SetItemDisplay(const FName& ItemID){ | ||||
|  | ||||
| void ABusyLevelItem::SetLevelItemID(const FName& ItemID){ | ||||
| 	// 取物品资源表 | ||||
| 	UDataTable* ConfigTable = UBusyGamePlayLibrary::GetGameDataTable(TEXT("LevelItems")); | ||||
| 	UDataTable* ConfigTable = UBusyGameplayLibrary::GetGameDataTable(TEXT("LevelItems")); | ||||
| 	// 查物品信息 | ||||
| 	FBusyLevelItemConfig* ItemConfig = ConfigTable->FindRow<FBusyLevelItemConfig>( | ||||
| 		ItemID, TEXT("ABusyLevelItem::SetLevelItemID"), true | ||||
|  | ||||
| @ -26,7 +26,7 @@ void ALevelItemReward::SetRewardID(const FName& CurrentRewardID){ | ||||
| 	bool bIsFind = false; | ||||
| 	FBusyLevelItemDescription Desc; | ||||
| 	if (CurrentRewardID.IsNone()) return; | ||||
| 	bIsFind = UBusyGamePlayLibrary::GetLevelItemDescription(CurrentRewardID, Desc); | ||||
| 	bIsFind = UBusyGameplayLibrary::GetLevelItemDescription(CurrentRewardID, Desc); | ||||
| 	if (!bIsFind) return; | ||||
| 	this->RewardID = CurrentRewardID; | ||||
| 	this->Sprite->SetFlipbook(Desc.LevelResource.LoadSynchronous()); | ||||
|  | ||||
| @ -2,10 +2,18 @@ | ||||
| #include "Level/Actor/BusyPlayerRole.h" | ||||
| #include "EnhancedInput/Public/EnhancedInputSubsystems.h" | ||||
| #include "Level/LevelPlayerState.h" | ||||
| #include "EnhancedInput/Public/EnhancedInputSubsystems.h" | ||||
| #include "EnhancedInput/Public/EnhancedInputComponent.h" | ||||
|  | ||||
|  | ||||
| inline static void BindEnhancedInputAction(UEnhancedInputComponent* EnhancedInput, const UInputAction* Action, UObject* Target, const FName& Callback) | ||||
| { | ||||
| 	if (Action) | ||||
| 	{ | ||||
| 		EnhancedInput->BindAction(Action, ETriggerEvent::Triggered, Target, Callback); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| ALevelPlayerController::ALevelPlayerController() | ||||
| { | ||||
| } | ||||
| @ -19,34 +27,74 @@ void ALevelPlayerController::BeginPlay() | ||||
| 	InputMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock); | ||||
| 	SetInputMode(InputMode); | ||||
|  | ||||
| 	// 注册输入 | ||||
| 	if (!HasAuthority()) | ||||
| 	if (RoamingCameraClass) | ||||
| 	{ | ||||
| 		const auto Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()); | ||||
| 		if (InputMapping && Subsystem) | ||||
| 		{ | ||||
| 			Subsystem->AddMappingContext(InputMapping, 0); | ||||
| 		} | ||||
| 		RoamingCameraActor = GetWorld()->SpawnActor<AActor>(RoamingCameraClass); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void ALevelPlayerController::SetupInputComponent() | ||||
| { | ||||
| 	Super::SetupInputComponent(); | ||||
| 	// 注册输入 | ||||
| 	if (!InputMapping || !InputComponent) return; | ||||
|  | ||||
| 	if (const auto Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer())) | ||||
| 	{ | ||||
| 		Subsystem->AddMappingContext(InputMapping, 0); | ||||
| 	} | ||||
|  | ||||
| 	UEnhancedInputComponent* EnhancedInput = CastChecked<UEnhancedInputComponent>(InputComponent); | ||||
| 	if (!EnhancedInput) return; | ||||
|  | ||||
| 	BindEnhancedInputAction(EnhancedInput, MoveAction, this, "OnMove"); | ||||
| 	BindEnhancedInputAction(EnhancedInput, CameraDetachAction, this, "OnCameraDetach"); | ||||
| 	BindEnhancedInputAction(EnhancedInput, PrimarySkillAction, this, "OnPrimarySkill"); | ||||
| 	BindEnhancedInputAction(EnhancedInput, UltimateSkillAction, this, "OnUltimateSkill"); | ||||
| } | ||||
|  | ||||
| void ALevelPlayerController::Tick(float DeltaTime) | ||||
| { | ||||
| 	Super::Tick(DeltaTime); | ||||
|  | ||||
| 	if (!bCameraDetached || !RoamingCameraActor) return; | ||||
|  | ||||
| 	AActor *ControlledRole = GetControlledRole(); | ||||
| 	const IBusyMovable *Movable = Cast<IBusyMovable>(GetControlledRole()); | ||||
| 	if (!Movable) return; | ||||
| 	 | ||||
| 	 | ||||
| 		if (UEnhancedInputComponent* EnhancedInput = CastChecked<UEnhancedInputComponent>(InputComponent)) { | ||||
| 			EnhancedInput->BindAction(TouchAction, ETriggerEvent::Triggered, this, FName("OnTouch")); | ||||
| 		} | ||||
| 	if (float CursorX, CursorY; GetMousePosition(CursorX, CursorY)) | ||||
| 	{ | ||||
|  | ||||
| 		// 获取视口大小 | ||||
| 		int32 ViewportSizeX, ViewportSizeY; | ||||
| 		GetViewportSize(ViewportSizeX, ViewportSizeY); | ||||
|      | ||||
| 		// 计算屏幕中心 | ||||
| 		const FVector2D ScreenCenter(ViewportSizeX / 2.0f, ViewportSizeY / 2.0f); | ||||
|  | ||||
| 		// 获取漫游相机位置 | ||||
| 		const FVector CurrentLocation = RoamingCameraActor->GetActorLocation(); | ||||
| 		 | ||||
| 		// 计算方向向量 | ||||
| 		FVector Direction(CursorX - ScreenCenter.X, CursorY - ScreenCenter.Y, 0); | ||||
|      | ||||
| 		// 归一化 | ||||
| 		Direction.Normalize(); | ||||
|  | ||||
| 		const float MoveSpeed = Movable->Execute_GetSpeed(ControlledRole); | ||||
| 		const FVector MoveDistance = Direction * DeltaTime * MoveSpeed * RoamingSpeedFactor; | ||||
|  | ||||
| 		// 更新漫游相机位置 | ||||
| 		RoamingCameraActor->SetActorLocation(CurrentLocation + MoveDistance); | ||||
| 	} | ||||
| 	 | ||||
| } | ||||
|  | ||||
| void ALevelPlayerController::SetRoleMoveTo_Implementation(const FVector2D& Location) | ||||
| { | ||||
| 	ABusyPlayerRole* ControlledRole = GetControlledRole(); | ||||
| 	if (!ControlledRole) return; | ||||
| 	ControlledRole->MovementComponent->MoveTo(Location); | ||||
| } | ||||
|  | ||||
| bool ALevelPlayerController::GetCursorPosition(FVector2D& Position) const | ||||
| { | ||||
| 	float CursorX = 0.f, CursorY = 0.f; | ||||
| 	if (GetMousePosition(CursorX, CursorY)) | ||||
| 	if (float CursorX, CursorY; GetMousePosition(CursorX, CursorY)) | ||||
| 	{ | ||||
| 		FVector WorldLocation, WorldDirection; | ||||
| 		if (DeprojectMousePositionToWorld(WorldLocation, WorldDirection)) | ||||
| @ -73,14 +121,50 @@ ABusyPlayerRole* ALevelPlayerController::GetControlledRole() const | ||||
|  | ||||
| void ALevelPlayerController::SwitchControlledRole(ABusyPlayerRole* Target) | ||||
| { | ||||
| 	this->SetViewTarget(Target); | ||||
| 	this->Possess(Target); | ||||
| } | ||||
|  | ||||
| void ALevelPlayerController::OnTouch(const FInputActionValue& Value) | ||||
| void ALevelPlayerController::OnMove(const FInputActionValue& Value) const | ||||
| { | ||||
| 	FVector2D Position; | ||||
| 	if (GetCursorPosition(Position)) | ||||
| 	AActor* ControlledRole = GetControlledRole(); | ||||
| 	if (!ControlledRole) return; | ||||
|  | ||||
| 	IBusyControllable *Controllable = Cast<IBusyControllable>(ControlledRole); | ||||
| 	if (!Controllable) return; | ||||
|  | ||||
| 	if (FVector2D Position; GetCursorPosition(Position)) | ||||
| 	{ | ||||
| 		SetRoleMoveTo(Position); | ||||
| 		Controllable->Execute_OnMove(ControlledRole, Position); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void ALevelPlayerController::OnPrimarySkill(const FInputActionValue& Value) const | ||||
| { | ||||
| } | ||||
|  | ||||
| void ALevelPlayerController::OnUltimateSkill(const FInputActionValue& Value) const | ||||
| { | ||||
| } | ||||
|  | ||||
| void ALevelPlayerController::OnCameraDetach(const FInputActionValue& Value) | ||||
| { | ||||
| 	if (!RoamingCameraActor) return; | ||||
| 	 | ||||
| 	AActor* ControlledRole = GetControlledRole(); | ||||
| 	if (!ControlledRole) return; | ||||
|  | ||||
| 	const FVector RoleLocation = ControlledRole->GetActorLocation(); | ||||
| 	RoamingCameraActor->SetActorLocation(RoleLocation); | ||||
| 	 | ||||
|  | ||||
| 	if (Value.GetMagnitude() > 0) | ||||
| 	{ | ||||
| 		bCameraDetached = true; | ||||
| 		SetViewTarget(RoamingCameraActor); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		bCameraDetached = false; | ||||
| 		SetViewTarget(ControlledRole); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| #include "Level/LevelPlayerState.h" | ||||
| #include "Net/UnrealNetwork.h" | ||||
| // #include "Net/UnrealNetwork.h" | ||||
| #include "Level/Actor/BusyPlayerRole.h" | ||||
|  | ||||
|  | ||||
| @ -11,24 +11,19 @@ void ALevelPlayerState::BeginPlay() | ||||
| 	Super::BeginPlay(); | ||||
|  | ||||
| } | ||||
|  | ||||
| void ALevelPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const | ||||
| { | ||||
| 	Super::GetLifetimeReplicatedProps(OutLifetimeProps); | ||||
|  | ||||
| 	DOREPLIFETIME(ALevelPlayerState, RoleRoster); | ||||
| 	DOREPLIFETIME(ALevelPlayerState, ControlledRoleIndex); | ||||
| } | ||||
| // | ||||
| // void ALevelPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const | ||||
| // { | ||||
| // 	Super::GetLifetimeReplicatedProps(OutLifetimeProps); | ||||
| // | ||||
| // 	DOREPLIFETIME(ALevelPlayerState, RoleRoster); | ||||
| // 	DOREPLIFETIME(ALevelPlayerState, ControlledRoleIndex); | ||||
| // } | ||||
|  | ||||
| AActor* ALevelPlayerState::CreateRoleRoster(class APlayerController* PlayerController) | ||||
| { | ||||
| 	if (!HasAuthority()) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	UWorld* World = PlayerController->GetWorld(); | ||||
| 	if (!World) | ||||
| 	if (!World || !PlayerController) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 	} | ||||
| @ -76,11 +71,3 @@ FVector2D ALevelPlayerState::GetSpawnLocation()const | ||||
| { | ||||
| 	return FVector2D::ZeroVector; | ||||
| } | ||||
|  | ||||
| void ALevelPlayerState::SetRoleRoster(const TArray<ABusyPlayerRole*>& Roster) | ||||
| { | ||||
| 	if (HasAuthority()) | ||||
| 	{ | ||||
| 		RoleRoster = Roster; | ||||
| 	} | ||||
| } | ||||
| @ -1,220 +0,0 @@ | ||||
| #include "Level/TerrainGenerator.h" | ||||
| #include "Math/UnrealMathUtility.h" | ||||
| #include "Math/RandomStream.h" | ||||
|  | ||||
| UTerrainGenerator::UTerrainGenerator() | ||||
| { | ||||
| 	NextHandle = 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| bool UTerrainGenerator::GenerateWithNodes(TArray<FGameplayTag>& Map, int32 Width, int32 Height, const TArray<int32>& ValidLeafNodes) | ||||
| { | ||||
| 	// 使用区域生长算法生成基础地图 | ||||
| 	RegionGrowing(Map, Width, Height, ValidLeafNodes); | ||||
| 	 | ||||
| 	// 应用柏林噪声进行平滑处理 | ||||
| 	ApplyPerlinNoiseSmoothing(Map, Width, Height); | ||||
| 	 | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void UTerrainGenerator::RegionGrowing(TArray<FGameplayTag>& Map, int32 Width, int32 Height,  | ||||
|                                       const TArray<int32>& ValidLeafNodes) const | ||||
| { | ||||
| 	if (ValidLeafNodes.Num() == 0) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	FRandomStream RandomStream(FMath::Rand()); | ||||
| 	 | ||||
| 	// 计算总权重 | ||||
| 	float TotalWeight = 0.0f; | ||||
| 	for (int32 Handle : ValidLeafNodes) | ||||
| 	{ | ||||
| 		if (const FTerrainNodeInfo* Node = TerrainNodes.Find(Handle)) | ||||
| 		{ | ||||
| 			TotalWeight += Node->Weight; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	if (TotalWeight <= 0.0f) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	// 创建权重分布 | ||||
| 	TArray<float> WeightDistribution; | ||||
| 	TArray<int32> HandleDistribution; | ||||
| 	float CurrentWeight = 0.0f; | ||||
| 	 | ||||
| 	for (int32 Handle : ValidLeafNodes) | ||||
| 	{ | ||||
| 		if (const FTerrainNodeInfo* Node = TerrainNodes.Find(Handle)) | ||||
| 		{ | ||||
| 			CurrentWeight += Node->Weight / TotalWeight; | ||||
| 			WeightDistribution.Add(CurrentWeight); | ||||
| 			HandleDistribution.Add(Handle); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	// 区域生长算法 | ||||
| 	TArray<int32> RegionSizes; | ||||
| 	RegionSizes.SetNum(ValidLeafNodes.Num()); | ||||
| 	 | ||||
| 	int32 TotalCells = Width * Height; | ||||
| 	for (int32 i = 0; i < ValidLeafNodes.Num(); i++) | ||||
| 	{ | ||||
| 		float Ratio = 0.0f; | ||||
| 		if (const FTerrainNodeInfo* Node = TerrainNodes.Find(ValidLeafNodes[i])) | ||||
| 		{ | ||||
| 			Ratio = Node->Weight / TotalWeight; | ||||
| 		} | ||||
| 		RegionSizes[i] = FMath::CeilToInt(TotalCells * Ratio); | ||||
| 	} | ||||
| 	 | ||||
| 	// 初始化地图为无效标签 | ||||
| 	FGameplayTag InvalidTag; | ||||
| 	for (int32 i = 0; i < Map.Num(); i++) | ||||
| 	{ | ||||
| 		Map[i] = InvalidTag; | ||||
| 	} | ||||
| 	 | ||||
| 	// 从随机点开始生长 | ||||
| 	for (int32 RegionIndex = 0; RegionIndex < ValidLeafNodes.Num(); RegionIndex++) | ||||
| 	{ | ||||
| 		int32 Handle = ValidLeafNodes[RegionIndex]; | ||||
| 		FGameplayTag TerrainTag = GetFinalTerrainTag(Handle); | ||||
| 		int32 TargetSize = RegionSizes[RegionIndex]; | ||||
| 		int32 CurrentSize = 0; | ||||
| 		 | ||||
| 		// 寻找起始点 | ||||
| 		int32 StartX, StartY; | ||||
| 		do | ||||
| 		{ | ||||
| 			StartX = RandomStream.RandRange(0, Width - 1); | ||||
| 			StartY = RandomStream.RandRange(0, Height - 1); | ||||
| 		} while (Map[StartY * Width + StartX].IsValid()); | ||||
| 		 | ||||
| 		// 使用队列进行区域生长 | ||||
| 		TQueue<FIntPoint> Queue; | ||||
| 		Queue.Enqueue(FIntPoint(StartX, StartY)); | ||||
| 		Map[StartY * Width + StartX] = TerrainTag; | ||||
| 		CurrentSize++; | ||||
| 		 | ||||
| 		while (!Queue.IsEmpty() && CurrentSize < TargetSize) | ||||
| 		{ | ||||
| 			FIntPoint CurrentPoint; | ||||
| 			Queue.Dequeue(CurrentPoint); | ||||
| 			 | ||||
| 			// 检查四个方向 | ||||
| 			TArray<FIntPoint> Directions = { | ||||
| 				FIntPoint(1, 0), FIntPoint(-1, 0), | ||||
| 				FIntPoint(0, 1), FIntPoint(0, -1) | ||||
| 			}; | ||||
| 			 | ||||
| 			for (const FIntPoint& Dir : Directions) | ||||
| 			{ | ||||
| 				FIntPoint Neighbor = CurrentPoint + Dir; | ||||
| 				 | ||||
| 				if (Neighbor.X >= 0 && Neighbor.X < Width &&  | ||||
| 					Neighbor.Y >= 0 && Neighbor.Y < Height) | ||||
| 				{ | ||||
| 					int32 Index = Neighbor.Y * Width + Neighbor.X; | ||||
| 					 | ||||
| 					if (!Map[Index].IsValid()) | ||||
| 					{ | ||||
| 						Map[Index] = TerrainTag; | ||||
| 						Queue.Enqueue(Neighbor); | ||||
| 						CurrentSize++; | ||||
| 						 | ||||
| 						if (CurrentSize >= TargetSize) | ||||
| 						{ | ||||
| 							break; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	// 填充剩余的空格 | ||||
| 	for (int32 i = 0; i < Map.Num(); i++) | ||||
| 	{ | ||||
| 		if (!Map[i].IsValid()) | ||||
| 		{ | ||||
| 			float RandValue = RandomStream.FRand(); | ||||
| 			for (int32 j = 0; j < WeightDistribution.Num(); j++) | ||||
| 			{ | ||||
| 				if (RandValue <= WeightDistribution[j]) | ||||
| 				{ | ||||
| 					Map[i] = GetFinalTerrainTag(HandleDistribution[j]); | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void UTerrainGenerator::ApplyPerlinNoiseSmoothing(TArray<FGameplayTag>& Map, int32 Width, int32 Height) const | ||||
| { | ||||
| 	FRandomStream RandomStream(FMath::Rand()); | ||||
| 	float NoiseScale = 0.1f; | ||||
| 	 | ||||
| 	for (int32 Y = 0; Y < Height; Y++) | ||||
| 	{ | ||||
| 		for (int32 X = 0; X < Width; X++) | ||||
| 		{ | ||||
| 			int32 Index = Y * Width + X; | ||||
| 			 | ||||
| 			// 计算柏林噪声值 | ||||
| 			float NoiseValue = FMath::PerlinNoise2D(FVector2D(X * NoiseScale, Y * NoiseScale)); | ||||
| 			NoiseValue = (NoiseValue + 1.0f) / 2.0f; // 映射到 0-1 | ||||
| 			 | ||||
| 			// 50%概率根据噪声调整地形 | ||||
| 			if (RandomStream.FRand() < 0.5f && NoiseValue > 0.7f) | ||||
| 			{ | ||||
| 				// 查找周围最多的地形 | ||||
| 				TMap<FGameplayTag, int32> NeighborCount; | ||||
| 				 | ||||
| 				for (int32 dy = -1; dy <= 1; dy++) | ||||
| 				{ | ||||
| 					for (int32 dx = -1; dx <= 1; dx++) | ||||
| 					{ | ||||
| 						if (dx == 0 && dy == 0) continue; | ||||
| 						 | ||||
| 						int32 NX = X + dx; | ||||
| 						int32 NY = Y + dy; | ||||
| 						 | ||||
| 						if (NX >= 0 && NX < Width && NY >= 0 && NY < Height) | ||||
| 						{ | ||||
| 							FGameplayTag NeighborTag = Map[NY * Width + NX]; | ||||
| 							NeighborCount.FindOrAdd(NeighborTag)++; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				 | ||||
| 				// 找到最多的邻居地形 | ||||
| 			FGameplayTag MostCommonTag; | ||||
| 				int32 MaxCount = 0; | ||||
| 				 | ||||
| 				for (const auto& Pair : NeighborCount) | ||||
| 				{ | ||||
| 					if (Pair.Value > MaxCount) | ||||
| 					{ | ||||
| 						MaxCount = Pair.Value; | ||||
| 						MostCommonTag = Pair.Key; | ||||
| 					} | ||||
| 				} | ||||
| 				 | ||||
| 				if (MaxCount > 0) | ||||
| 				{ | ||||
| 					Map[Index] = MostCommonTag; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -1,131 +0,0 @@ | ||||
| #include "Level/TerrainGeneratorBlueprintLibrary.h" | ||||
| #include "Level/TerrainGenerator.h" | ||||
| #include "GameplayTagsManager.h" | ||||
| #include "Engine/Engine.h" | ||||
|  | ||||
| UTerrainGenerator* UTerrainGeneratorBlueprintLibrary::CreateTerrainGenerator() | ||||
| { | ||||
| 	return NewObject<UTerrainGenerator>(); | ||||
| } | ||||
|  | ||||
| void UTerrainGeneratorBlueprintLibrary::SetupExampleTerrainConfig(UTerrainGeneratorBase* Generator) | ||||
| { | ||||
| 	if (!Generator) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	// 定义地形标签 | ||||
| 	FGameplayTag ForestTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Forest")); | ||||
| 	FGameplayTag GrasslandTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Grassland")); | ||||
| 	FGameplayTag WaterTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Water")); | ||||
| 	FGameplayTag SwampTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Swamp")); | ||||
| 	FGameplayTag LandTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Land")); | ||||
| 	 | ||||
| 	FGameplayTag SwampLandTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Swamp.Land")); | ||||
| 	FGameplayTag SwampWaterTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Swamp.Water")); | ||||
| 	FGameplayTag ShallowWaterTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Water.Shallow")); | ||||
| 	FGameplayTag DeepWaterTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Water.Deep")); | ||||
|  | ||||
| 	// 添加父地形 | ||||
| 	int32 ForestHandle = Generator->AddTerrain(ForestTag); | ||||
| 	int32 GrasslandHandle = Generator->AddTerrain(GrasslandTag); | ||||
| 	int32 WaterHandle = Generator->AddTerrain(WaterTag); | ||||
| 	int32 SwampHandle = Generator->AddTerrain(SwampTag); | ||||
| 	int32 LandHandle = Generator->AddTerrain(LandTag); | ||||
| 	 | ||||
| 	// 添加子地形 | ||||
| 	int32 SwampLandHandle = Generator->AddTerrain(SwampLandTag); | ||||
| 	int32 SwampWaterHandle = Generator->AddTerrain(SwampWaterTag); | ||||
| 	int32 ShallowWaterHandle = Generator->AddTerrain(ShallowWaterTag); | ||||
| 	int32 DeepWaterHandle = Generator->AddTerrain(DeepWaterTag); | ||||
| 	 | ||||
| 	// 绑定父子关系 | ||||
| 	Generator->BindChildTerrain(SwampHandle, {SwampLandHandle, SwampWaterHandle}); | ||||
| 	Generator->BindChildTerrain(WaterHandle, {ShallowWaterHandle, DeepWaterHandle}); | ||||
| 	 | ||||
| 	// 设置概率 | ||||
| 	Generator->SetProbability(ForestHandle, 0.8f);	  // 森林出现概率80% | ||||
| 	Generator->SetProbability(GrasslandHandle, 0.9f);   // 草地出现概率90% | ||||
| 	Generator->SetProbability(WaterHandle, 0.7f);	   // 水体出现概率70% | ||||
| 	Generator->SetProbability(SwampHandle, 0.6f);	   // 沼泽出现概率60% | ||||
| 	Generator->SetProbability(LandHandle, 1.0f);		// 土地总是出现 | ||||
| 	 | ||||
| 	// 设置权重 | ||||
| 	Generator->SetWeight(ForestHandle, 9.0f);		   // 森林权重9 | ||||
| 	Generator->SetWeight(GrasslandHandle, 5.0f);		// 草地权重5 | ||||
| 	Generator->SetWeight(LandHandle, 3.0f);			 // 土地权重3 | ||||
| 	 | ||||
| 	Generator->SetWeight(SwampLandHandle, 1.0f);		// 沼泽陆地权重1 | ||||
| 	Generator->SetWeight(SwampWaterHandle, 2.0f);	   // 沼泽水域权重2 | ||||
| 	 | ||||
| 	Generator->SetWeight(ShallowWaterHandle, 3.0f);	 // 浅水权重3 | ||||
| 	Generator->SetWeight(DeepWaterHandle, 1.0f);		// 深水权重1 | ||||
| 	 | ||||
| 	// 设置互斥关系 | ||||
| 	Generator->SetExclusive({ForestHandle, SwampWaterHandle}); // 森林和沼泽水域互斥 | ||||
| } | ||||
|  | ||||
| TArray<FGameplayTag> UTerrainGeneratorBlueprintLibrary::GenerateMap( | ||||
| 	UTerrainGenerator* Generator,  | ||||
| 	int32 Width,  | ||||
| 	int32 Height) | ||||
| { | ||||
| 	TArray<FGameplayTag> Result; | ||||
| 	 | ||||
| 	if (!Generator) | ||||
| 	{ | ||||
| 		return Result; | ||||
| 	} | ||||
|  | ||||
| 	// 直接返回一维地图数据 | ||||
| 	return Generator->GenerateMap(Width, Height); | ||||
| } | ||||
|  | ||||
| void UTerrainGeneratorBlueprintLibrary::GetMapDimensions( | ||||
| 	UTerrainGenerator* Generator, | ||||
| 	int32& Width, | ||||
| 	int32& Height) | ||||
| { | ||||
| 	Width = 256; | ||||
| 	Height = 256; | ||||
| 	 | ||||
| 	if (Generator) | ||||
| 	{ | ||||
| 		// 这里可以根据需要从生成器获取实际的尺寸信息 | ||||
| 		// 目前返回默认值 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| FString UTerrainGeneratorBlueprintLibrary::GetTerrainDisplayName(const FGameplayTag& TerrainTag) | ||||
| { | ||||
| 	if (!TerrainTag.IsValid()) | ||||
| 	{ | ||||
| 		return TEXT("无效地形"); | ||||
| 	} | ||||
|  | ||||
| 	FString TagName = TerrainTag.ToString(); | ||||
| 	 | ||||
| 	// 从标签中提取显示名称 | ||||
| 	if (TagName.StartsWith(TEXT("Terrain."))) | ||||
| 	{ | ||||
| 		TagName.RemoveFromStart(TEXT("Terrain.")); | ||||
| 	} | ||||
| 	 | ||||
| 	// 替换下划线为空格 | ||||
| 	TagName.ReplaceCharInline(TEXT('.'), TEXT(' ')); | ||||
| 	TagName.ReplaceCharInline(TEXT('_'), TEXT(' ')); | ||||
| 	 | ||||
| 	// 首字母大写 | ||||
| 	if (TagName.Len() > 0) | ||||
| 	{ | ||||
| 		TagName[0] = FChar::ToUpper(TagName[0]); | ||||
| 	} | ||||
| 	 | ||||
| 	return TagName; | ||||
| } | ||||
|  | ||||
| bool UTerrainGeneratorBlueprintLibrary::IsValidTerrainTag(const FGameplayTag& TerrainTag) | ||||
| { | ||||
| 	return TerrainTag.IsValid(); | ||||
| } | ||||
| @ -1,122 +0,0 @@ | ||||
| #include "Level/TerrainGenerator.h" | ||||
| #include "GameplayTagsManager.h" | ||||
| #include "Engine/Engine.h" | ||||
|  | ||||
| // 测试地形生成器功能 | ||||
| void TestTerrainGenerator() | ||||
| { | ||||
| 	// 创建地形生成器实例 | ||||
| 	UTerrainGenerator* Generator = NewObject<UTerrainGenerator>(); | ||||
| 	 | ||||
| 	// 定义地形标签 | ||||
| 	FGameplayTag ForestTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Forest")); | ||||
| 	FGameplayTag GrasslandTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Grassland")); | ||||
| 	FGameplayTag WaterTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Water")); | ||||
| 	FGameplayTag SwampTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Swamp")); | ||||
| 	FGameplayTag LandTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Land")); | ||||
| 	 | ||||
| 	FGameplayTag SwampLandTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Swamp.Land")); | ||||
| 	FGameplayTag SwampWaterTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Swamp.Water")); | ||||
| 	FGameplayTag ShallowWaterTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Water.Shallow")); | ||||
| 	FGameplayTag DeepWaterTag = FGameplayTag::RequestGameplayTag(TEXT("Terrain.Water.Deep")); | ||||
| 	 | ||||
| 	// 添加父地形 | ||||
| 	int32 ForestHandle = Generator->AddTerrain(ForestTag); | ||||
| 	int32 GrasslandHandle = Generator->AddTerrain(GrasslandTag); | ||||
| 	int32 WaterHandle = Generator->AddTerrain(WaterTag); | ||||
| 	int32 SwampHandle = Generator->AddTerrain(SwampTag); | ||||
| 	int32 LandHandle = Generator->AddTerrain(LandTag); | ||||
| 	 | ||||
| 	// 添加子地形 | ||||
| 	int32 SwampLandHandle = Generator->AddTerrain(SwampLandTag); | ||||
| 	int32 SwampWaterHandle = Generator->AddTerrain(SwampWaterTag); | ||||
| 	int32 ShallowWaterHandle = Generator->AddTerrain(ShallowWaterTag); | ||||
| 	int32 DeepWaterHandle = Generator->AddTerrain(DeepWaterTag); | ||||
| 	 | ||||
| 	// 绑定父子关系 | ||||
| 	Generator->BindChildTerrain(SwampHandle, {SwampLandHandle, SwampWaterHandle}); | ||||
| 	Generator->BindChildTerrain(WaterHandle, {ShallowWaterHandle, DeepWaterHandle}); | ||||
| 	 | ||||
| 	// 设置概率 | ||||
| 	Generator->SetProbability(ForestHandle, 1.0f); | ||||
| 	Generator->SetProbability(GrasslandHandle, 0.9f); | ||||
| 	Generator->SetProbability(WaterHandle, 0.7f); | ||||
| 	Generator->SetProbability(SwampHandle, 1.0f); // 设置为1.0确保沼泽总是出现 | ||||
| 	Generator->SetProbability(LandHandle, 1.0f); | ||||
| 	 | ||||
| 	// 设置权重 | ||||
| 	Generator->SetWeight(ForestHandle, 9.0f); | ||||
| 	Generator->SetWeight(GrasslandHandle, 5.0f); | ||||
| 	Generator->SetWeight(LandHandle, 3.0f); | ||||
| 	Generator->SetWeight(SwampHandle, 2.0f); // 为沼泽父节点设置权重 | ||||
| 	 | ||||
| 	Generator->SetWeight(SwampLandHandle, 1.0f); | ||||
| 	Generator->SetWeight(SwampWaterHandle, 2.0f); | ||||
| 	 | ||||
| 	Generator->SetWeight(ShallowWaterHandle, 3.0f); | ||||
| 	Generator->SetWeight(DeepWaterHandle, 1.0f); | ||||
| 	 | ||||
| 	// 设置互斥关系 | ||||
| 	Generator->SetExclusive({ForestHandle, SwampWaterHandle}); | ||||
| 	 | ||||
| 	// 生成地图 | ||||
| 	TArray<FGameplayTag> Map = Generator->GenerateMap(64, 64); | ||||
| 	 | ||||
| 	// 统计地形分布 | ||||
| 	TMap<FGameplayTag, int32> TerrainCount; | ||||
| 	for (const FGameplayTag& Tag : Map) | ||||
| 	{ | ||||
| 		TerrainCount.FindOrAdd(Tag)++; | ||||
| 	} | ||||
| 	 | ||||
| 	// 输出统计结果 | ||||
| 	UE_LOG(LogTemp, Log, TEXT("=== 地形生成统计 ===")); | ||||
| 	UE_LOG(LogTemp, Log, TEXT("地图大小: %dx%d"), 64, 64); | ||||
| 	UE_LOG(LogTemp, Log, TEXT("总格子数: %d"), Map.Num()); | ||||
| 	 | ||||
| 	for (const auto& Pair : TerrainCount) | ||||
| 	{ | ||||
| 		float Percentage = (float)Pair.Value / Map.Num() * 100.0f; | ||||
| 		UE_LOG(LogTemp, Log, TEXT("%s: %d (%.1f%%)"),  | ||||
| 			   *Pair.Key.ToString(), Pair.Value, Percentage); | ||||
| 	} | ||||
| 	 | ||||
| 	// 验证互斥关系 | ||||
| 	bool HasForest = TerrainCount.Contains(ForestTag); | ||||
| 	bool HasSwampWater = TerrainCount.Contains(SwampWaterTag); | ||||
| 	 | ||||
| 	if (HasForest && HasSwampWater) | ||||
| 	{ | ||||
| 		UE_LOG(LogTemp, Warning, TEXT("警告: 森林和沼泽水域同时出现,互斥关系可能未正确工作")); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		UE_LOG(LogTemp, Log, TEXT("互斥关系验证: 通过")); | ||||
| 	} | ||||
| 	 | ||||
| 	// 验证父子关系 | ||||
| 	bool HasSwamp = TerrainCount.Contains(SwampTag); | ||||
| 	bool HasSwampChildren = TerrainCount.Contains(SwampLandTag) || TerrainCount.Contains(SwampWaterTag); | ||||
| 	 | ||||
| 	if (HasSwamp && !HasSwampChildren) | ||||
| 	{ | ||||
| 		UE_LOG(LogTemp, Warning, TEXT("警告: 沼泽出现但没有子地形")); | ||||
| 	} | ||||
| 	else if (!HasSwamp && HasSwampChildren) | ||||
| 	{ | ||||
| 		UE_LOG(LogTemp, Warning, TEXT("警告: 沼泽子地形出现但沼泽未出现")); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		UE_LOG(LogTemp, Log, TEXT("父子关系验证: 通过")); | ||||
| 	} | ||||
| 	 | ||||
| 	UE_LOG(LogTemp, Log, TEXT("=== 测试完成 ===")); | ||||
| } | ||||
|  | ||||
| // 控制台命令用于测试 | ||||
| static FAutoConsoleCommand TestTerrainGeneratorCommand( | ||||
| 	TEXT("TestTerrainGenerator"), | ||||
| 	TEXT("测试地形生成器功能"), | ||||
| 	FConsoleCommandDelegate::CreateStatic(TestTerrainGenerator) | ||||
| ); | ||||
| @ -59,7 +59,7 @@ void ABusyRole::Tick(float InDeltaSeconds){ | ||||
| } | ||||
|  | ||||
| void ABusyRole::SetRole(const FName& Name){ | ||||
| 	UDataTable* Table = UBusyGamePlayLibrary::GetGameDataTable("RoleConfig"); | ||||
| 	UDataTable* Table = UBusyGameplayLibrary::GetGameDataTable("RoleConfig"); | ||||
| 	if (Table == nullptr) { | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| @ -62,15 +62,13 @@ void URoleAnimation::PlayPickAnimation(const FName& ItemName, ERoleMoveDirection | ||||
|  | ||||
|  | ||||
| bool URoleAnimation::GetOwnerRoleInfo(UPaperFlipbookComponent*& Sprite, FBusyRoleAnimationData*& AnimationData){ | ||||
| 	// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>owner | ||||
| 	ABusyRole* Role = Cast<ABusyRole>(this->GetOwner()); | ||||
| 	if (Role == nullptr) { | ||||
| 		UE_LOG(LogRoleAnimation, Error, TEXT("URoleAnimation::GetPaperFilpBookComponent, Can't get Role")); | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	// <20><><EFBFBD><EFBFBD>owner<65><72><EFBFBD><EFBFBD> | ||||
| 	UDataTable* DataTable = UBusyGamePlayLibrary::GetGameDataTable("RoleAnimation"); | ||||
| 	UDataTable* DataTable = UBusyGameplayLibrary::GetGameDataTable("RoleAnimation"); | ||||
| 	if (DataTable == nullptr) { | ||||
| 		UE_LOG(LogRoleAnimation, Error, TEXT("URoleAnimation::GetOwnerRoleInfo, Can't get Animation DataTable")) | ||||
| 		return false; | ||||
|  | ||||
| @ -18,7 +18,7 @@ | ||||
|  *  | ||||
|  */ | ||||
| UCLASS() | ||||
| class BUSYRABBIT_API UBusyGamePlayLibrary : public UBlueprintFunctionLibrary | ||||
| class BUSYRABBIT_API UBusyGameplayLibrary : public UBlueprintFunctionLibrary | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| @ -33,7 +33,7 @@ public: | ||||
| 	static UClass* GetGameUIClass(const FString& ClassName); | ||||
|  | ||||
| 	UFUNCTION(BlueprintPure) | ||||
| 	static UWorld* K2_GetWorld(const UObject* obj); | ||||
| 	static UWorld* K2_GetWorld(const UObject* UObj); | ||||
|  | ||||
| 	UFUNCTION(BlueprintPure) | ||||
| 	static bool GetLevelBaseConfig(const FName& RowName, FBusyLevelBaseConfig& RowData); | ||||
| @ -58,12 +58,5 @@ public: | ||||
|  | ||||
| 	UFUNCTION(BlueprintPure) | ||||
| 	static bool GetCookMaterialStateConfig(const FName& RowName, FBusyCookMaterialStateConfig& RowData); | ||||
| 	 | ||||
| 	UFUNCTION(BlueprintPure) | ||||
| 	static FLuaBPVar CreateTextureBuffer(UObject* WorldContextObject); | ||||
|  | ||||
| 	UFUNCTION(BlueprintCallable) | ||||
| 	static void UpdateTextureBuffer(UTexture2D* DataTexture, TArray<float> FloatData); | ||||
|  | ||||
|  | ||||
| }; | ||||
|  | ||||
| @ -1,9 +1,10 @@ | ||||
| #pragma once | ||||
| #include "BusyPawnBase.h" | ||||
| #include "Level/LevelPlayerController.h" | ||||
| #include "BusyPlayerRole.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class ABusyPlayerRole : public ABusyPawnBase | ||||
| class ABusyPlayerRole : public ABusyPawnBase, public IBusyControllable | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
| @ -12,21 +13,9 @@ public: | ||||
|  | ||||
| protected: | ||||
| 	/*--------------------相机相关--------------------------*/ | ||||
|  | ||||
|  | ||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) | ||||
| 	TObjectPtr<class USpringArmComponent> SpringArmComponent; | ||||
|  | ||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) | ||||
| 	TObjectPtr<class UCameraComponent> CameraComponent; | ||||
|  | ||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) | ||||
| 	TObjectPtr<class UBusyRoleMovement> Movement;  // 移动组件 | ||||
|  | ||||
| 	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) | ||||
| 	TObjectPtr<class UPW_AbilitySystemComponent> RoleAbility;	// 技能组件 | ||||
| 	 | ||||
| 	UPROPERTY(BlueprintReadWrite) | ||||
| 	TObjectPtr<class URoleAnimation> RoleAnimation; | ||||
| 	 | ||||
| }; | ||||
|  | ||||
							
								
								
									
										33
									
								
								Source/BusyRabbit/Public/Level/Actor/BusyStaticResource.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								Source/BusyRabbit/Public/Level/Actor/BusyStaticResource.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| #pragma once | ||||
| #include "LuaActor.h" | ||||
| #include "BusyStaticResource.generated.h" | ||||
|  | ||||
| class USpineSkeletonRendererComponent; | ||||
| class USpineSkeletonAnimationComponent; | ||||
|  | ||||
|  | ||||
| UCLASS(Blueprintable, BlueprintType) | ||||
| class ABusyStaticResource:public ALuaActor | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
| 	ABusyStaticResource(); | ||||
|  | ||||
| 	virtual void BeginPlay() override; | ||||
| 	 | ||||
| public: | ||||
| 	UPROPERTY(EditAnywhere) | ||||
| 	TObjectPtr<USceneComponent> RootScene;  //场景根组件 | ||||
|  | ||||
| 	/*----------------------------spine相关组件----------------------------*/ | ||||
| 	UPROPERTY(EditDefaultsOnly) | ||||
| 	TObjectPtr<USceneComponent> SpineRoot; | ||||
|  | ||||
| 	UPROPERTY(EditDefaultsOnly) | ||||
| 	TObjectPtr<USpineSkeletonRendererComponent> SpineRenderComponent; | ||||
|  | ||||
| 	UPROPERTY(EditAnywhere, BlueprintReadOnly) | ||||
| 	TObjectPtr<USpineSkeletonAnimationComponent> SpineAnimationComponent; | ||||
| 	/*-------------------------------------------------------------------*/ | ||||
| 	 | ||||
| }; | ||||
| @ -3,6 +3,33 @@ | ||||
| #include "LuaPlayerController.h" | ||||
| #include "LevelPlayerController.generated.h" | ||||
|  | ||||
|  | ||||
| UINTERFACE(MinimalAPI, Blueprintable) | ||||
| class UBusyControllable: public UInterface | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| }; | ||||
|  | ||||
|  | ||||
| class IBusyControllable | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
| 	// 角色移动 | ||||
| 	UFUNCTION(BlueprintNativeEvent, BlueprintCallable) | ||||
| 	void OnMove(const FVector2D& Location); | ||||
|  | ||||
| 	// 角色普通技能 | ||||
| 	UFUNCTION(BlueprintNativeEvent, BlueprintCallable) | ||||
| 	void OnPrimarySkill(); | ||||
|  | ||||
| 	// 角色大招 | ||||
| 	UFUNCTION(BlueprintNativeEvent, BlueprintCallable) | ||||
| 	void OnUltimateSkill(); | ||||
| }; | ||||
|  | ||||
|  | ||||
| struct FInputActionValue; | ||||
| class ABusyPlayerRole; | ||||
|  | ||||
| UCLASS() | ||||
| @ -14,37 +41,69 @@ public: | ||||
|  | ||||
| public: | ||||
| 	virtual void BeginPlay() override; | ||||
|  | ||||
|  | ||||
| public: // RPC相关 | ||||
| 	UFUNCTION(Server, Reliable) | ||||
| 	void SetRoleMoveTo(const FVector2D& Location); | ||||
| 	void SetRoleMoveTo_Implementation(const FVector2D& Location); | ||||
|  | ||||
| 	virtual void SetupInputComponent() override; | ||||
| 	virtual void Tick(float DeltaTime) override; | ||||
|  | ||||
| public: | ||||
| 	UFUNCTION(BlueprintCallable, Category = "Controller") | ||||
| 	bool GetCursorPosition(FVector2D& Position) const; | ||||
|  | ||||
| 	UFUNCTION(BlueprintCallable, Category = "Controller") | ||||
| 	void GetCursorHitResult(TArray<AActor*>& Results) const; | ||||
| 	ABusyPlayerRole* GetControlledRole() const; | ||||
|  | ||||
| 	UFUNCTION(BlueprintCallable, Category = "Controller") | ||||
| 	ABusyPlayerRole* GetControlledRole() const; | ||||
| 	void GetCursorHitResult(TArray<AActor*>& Results) const; | ||||
|  | ||||
| 	UFUNCTION(BlueprintCallable, Category = "Controller") | ||||
| 	void SwitchControlledRole(ABusyPlayerRole* Target); | ||||
|  | ||||
|  | ||||
| public: | ||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Roaming Camera") | ||||
| 	TSubclassOf<AActor> RoamingCameraClass; | ||||
|  | ||||
| 	// 漫游相机移动速度为角色移动速度 * 漫游速度系数 | ||||
| 	UPROPERTY(EditAnywhere, BlueprintReadWrite, DisplayName="漫游速度系数", Category = "Roaming Camera") | ||||
| 	float RoamingSpeedFactor = 3.0; | ||||
|  | ||||
| public: // 输入相关 | ||||
| 	UPROPERTY(EditDefaultsOnly, Category = "Input") | ||||
| 	TObjectPtr<class UInputMappingContext> InputMapping; | ||||
|  | ||||
| 	UPROPERTY(EditDefaultsOnly, Category = "Input") | ||||
| 	TObjectPtr<class UInputAction> TouchAction; | ||||
| 	TObjectPtr<class UInputAction> MoveAction;  // 鼠标右键移动 | ||||
| 	 | ||||
| 	UPROPERTY(EditDefaultsOnly, Category = "Input") | ||||
| 	TObjectPtr<class UInputAction> SelectAction;  // 鼠标左键选择 | ||||
|  | ||||
| 	UPROPERTY(EditDefaultsOnly, Category = "Input") | ||||
| 	TObjectPtr<class UInputAction> PrimarySkillAction;  // 基础技能 | ||||
|  | ||||
| 	UPROPERTY(EditDefaultsOnly, Category = "Input") | ||||
| 	TObjectPtr<class UInputAction> UltimateSkillAction;  // 大招 | ||||
|  | ||||
| 	UPROPERTY(EditDefaultsOnly, Category = "Input") | ||||
| 	TObjectPtr<class UInputAction> CameraDetachAction;  // 相机脱离 | ||||
|  | ||||
|  | ||||
| public: | ||||
| 	UFUNCTION() | ||||
| 	void OnMove(const FInputActionValue& Value)const; | ||||
|  | ||||
| 	UFUNCTION() | ||||
| 	void OnTouch(const FInputActionValue& Value); | ||||
| 	void OnPrimarySkill(const FInputActionValue& Value)const; | ||||
|  | ||||
| 	UFUNCTION() | ||||
| 	void OnUltimateSkill(const FInputActionValue& Value)const; | ||||
|  | ||||
| 	UFUNCTION() | ||||
| 	void OnCameraDetach(const FInputActionValue& Value); | ||||
|  | ||||
|  | ||||
| protected: | ||||
| 	UPROPERTY() | ||||
| 	AActor* RoamingCameraActor = nullptr; | ||||
|  | ||||
| private: | ||||
| 	bool bCameraDetached = false; | ||||
| }; | ||||
|  | ||||
| @ -15,7 +15,7 @@ class ALevelPlayerState : public ALuaPlayerState | ||||
| public: | ||||
| 	virtual void BeginPlay() override; | ||||
| 	 | ||||
| 	virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override; | ||||
| 	// virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override; | ||||
|  | ||||
| public: // 给蓝图初始化的接口 | ||||
| 	UFUNCTION(BlueprintCallable) | ||||
| @ -27,19 +27,6 @@ public: // 给蓝图的Get接口 | ||||
| 	ABusyPlayerRole* GetControlledRole() const; | ||||
|  | ||||
|  | ||||
|  | ||||
| public:  // 给蓝图的Set接口 | ||||
| 	UFUNCTION(BlueprintCallable) | ||||
| 	void SetRoleRoster(const TArray<ABusyPlayerRole*>& Roster); | ||||
| 	 | ||||
|  | ||||
| public: | ||||
|  | ||||
|  | ||||
| public: | ||||
| 	 | ||||
| 	 | ||||
|  | ||||
| protected: | ||||
| 	virtual FVector2D GetSpawnLocation()const; | ||||
|  | ||||
| @ -48,11 +35,10 @@ public: | ||||
| 	TArray<TSubclassOf<ABusyPlayerRole>> RoleClasses; | ||||
| 	 | ||||
| protected: | ||||
| 	UPROPERTY(Replicated, BlueprintReadOnly) | ||||
| 	UPROPERTY(BlueprintReadOnly) | ||||
| 	int ControlledRoleIndex = -1; | ||||
| 	 | ||||
| 	 | ||||
| 	UPROPERTY(Replicated, BlueprintReadOnly) | ||||
| 	UPROPERTY(BlueprintReadOnly) | ||||
| 	TArray<ABusyPlayerRole*> RoleRoster; | ||||
| }; | ||||
|  | ||||
|  | ||||
| @ -1,29 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "GameplayTagContainer.h" | ||||
| #include "Generator/TerrainGeneratorBase.h" | ||||
| #include "TerrainGenerator.generated.h" | ||||
|  | ||||
|  | ||||
|  | ||||
| UCLASS(BlueprintType, Blueprintable) | ||||
| class BUSYRABBIT_API UTerrainGenerator : public UTerrainGeneratorBase | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
| 	UTerrainGenerator(); | ||||
|  | ||||
| 	virtual bool GenerateWithNodes( | ||||
| 		TArray<FGameplayTag>& Map, int32 Width, int32 Height, | ||||
| 		const TArray<int32>& ValidLeafNodes | ||||
| 	)override; | ||||
|  | ||||
| private: | ||||
| 	void RegionGrowing(TArray<FGameplayTag>& Map, int32 Width, int32 Height,  | ||||
| 					  const TArray<int32>& ValidLeafNodes) const; | ||||
|  | ||||
| 	void ApplyPerlinNoiseSmoothing(TArray<FGameplayTag>& Map, int32 Width, int32 Height) const; | ||||
|  | ||||
| }; | ||||
| @ -1,46 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "Kismet/BlueprintFunctionLibrary.h" | ||||
| #include "GameplayTagContainer.h" | ||||
| #include "TerrainGeneratorBlueprintLibrary.generated.h" | ||||
|  | ||||
| // 蓝图函数库,方便在蓝图中使用地形生成<E7949F>? | ||||
| UCLASS() | ||||
| class BUSYRABBIT_API UTerrainGeneratorBlueprintLibrary : public UBlueprintFunctionLibrary | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
| 	// 创建地形生成器实<E599A8>? | ||||
| 	UFUNCTION(BlueprintCallable, Category = "Terrain Generator") | ||||
| 	static class UTerrainGenerator* CreateTerrainGenerator(); | ||||
|  | ||||
| 	// 快速设置示例地形配<E5BDA2>? | ||||
| 	UFUNCTION(BlueprintCallable, Category = "Terrain Generator") | ||||
| 	static void SetupExampleTerrainConfig(class UTerrainGeneratorBase* UTerrainGenerator); | ||||
|  | ||||
| 	// 生成地图并返回一维数组(蓝图不支持嵌套TArray<61>? | ||||
| 	UFUNCTION(BlueprintCallable, Category = "Terrain Generator") | ||||
| 	static TArray<FGameplayTag> GenerateMap( | ||||
| 		class UTerrainGenerator* Generator,  | ||||
| 		int32 Width = 256,  | ||||
| 		int32 Height = 256 | ||||
| 	); | ||||
|  | ||||
| 	// 获取地图尺寸信息(用于在蓝图中解析一维数组) | ||||
| 	UFUNCTION(BlueprintCallable, Category = "Terrain Generator") | ||||
| 	static void GetMapDimensions( | ||||
| 		class UTerrainGenerator* Generator, | ||||
| 		int32& Width, | ||||
| 		int32& Height | ||||
| 	); | ||||
|  | ||||
| 	// 获取地形标签的显示名<E7A4BA>? | ||||
| 	UFUNCTION(BlueprintCallable, Category = "Terrain Generator") | ||||
| 	static FString GetTerrainDisplayName(const FGameplayTag& TerrainTag); | ||||
|  | ||||
| 	// 检查地形标签是否有<E590A6>? | ||||
| 	UFUNCTION(BlueprintCallable, Category = "Terrain Generator") | ||||
| 	static bool IsValidTerrainTag(const FGameplayTag& TerrainTag); | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user