I have a character that I spawn from a dynamically created player start onto a dynamically created floor. Right now, the character cannot move across the floor normally. I can see that the movement events are firing, and the character can jump properly. This means that I can do a tiny bunny-hop to move around on the floor. It’s almost as if the friction on the floor or character capsule is infinite.
The character can move correctly on the mesh that I spawn dynamically if it is statically placed in a level from the editor. The dynamic generation only currently occurs when the map is determined to be a dynamic map and occurs in the GameMode’s PreInitializeComponents method.
I’m fairly confident that I am missing some small setting that will let the movement occur normally, but I am clearly missing it.
I would appreciate any help you could provide into why the character is stuck on the floor to get it moving on the dynamically created floor.
I am using the latest version of the engine, 4.7.5. I also tried this in 4.7.3 before 4.7.5 was released.
For your convenience, the relevant pieces of code are below.
The Player Start Spawn
void ADungeonBuilder::SpawnStart(UWorld* world, ARoom* room)
{
FVector roomExtent = room->Boundary->GetUnscaledBoxExtent();
//TODO: Make Random in the room
FActorSpawnParameters spawnParameters;
spawnParameters.Owner = this;
spawnParameters.Instigator = Instigator;
FVector spawnLocation(-600, -600, -600);
FRotator spawnRotation(FRotator::ZeroRotator);
PlayerStart = Cast<APlayerStart>(world->SpawnActor<AActor>(APlayerStart::StaticClass(), spawnLocation, spawnRotation, spawnParameters));
PlayerStart->AttachRootComponentToActor(room);
PlaceExitVolume(world, room);
}
The room tile method. (where all floor tiles are placed in the world)
void ADungeonBuilder::TileFloor(ARoom* room)
{
UStaticMesh* floorMesh = LoadFloorMesh();
UMaterial* floorMaterial = LoadFloorMaterial();
FVector meshExtent = floorMesh->GetBounds().BoxExtent;
FVector roomExtent = room->Boundary->GetUnscaledBoxExtent();
//TODO: Handle case where room is smaller than mesh
uint32 tilesWide = roomExtent.X / meshExtent.X;
uint32 tilesDeep = roomExtent.Y / meshExtent.Y;
float startX = -roomExtent.X;
float startY = -roomExtent.Y;
float startZ = -roomExtent.Z + meshExtent.Z;
float slideX = meshExtent.X * 2;
float slideY = meshExtent.Y * 2;
for (uint32 deepRank = 0; deepRank < tilesDeep; ++deepRank)
{
for (uint32 wideRank = 0; wideRank < tilesWide; ++wideRank)
{
FVector nextCenter(startX + slideX*wideRank,
startY + slideY*deepRank,
startZ);
UStaticMeshComponent* floorComponent = LoadComponent(floorMesh);
floorComponent->SetMaterial(0, floorMaterial);
floorComponent->SetWorldLocation(nextCenter);
floorComponent->RegisterComponentWithWorld(GetWorld());
floorComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
floorComponent->AttachTo(room->GetRootComponent());
room->Floor.Add(floorComponent);
}
}
}
The floor mesh loader
UStaticMesh* ADungeonBuilder::LoadFloorMesh()
{
TCHAR* floorName = TEXT("/Game/Architecture/Floor_400x400.Floor_400x400");
UStaticMesh* floorMesh = LoadObject<UStaticMesh>(NULL, floorName, NULL, LOAD_None, NULL);
return floorMesh;
}
The Component Loader
UStaticMeshComponent* ADungeonBuilder::LoadComponent(UStaticMesh* mesh)
{
UStaticMeshComponent* floorComponent = ConstructObject<UStaticMeshComponent>(UStaticMeshComponent::StaticClass());
floorComponent->SetStaticMesh(mesh);
floorComponent->SetMobility(EComponentMobility::Movable);
floorComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
floorComponent->bCanEverAffectNavigation = true;
floorComponent->bCastDynamicShadow = true;
return floorComponent;
}
The Material Loader
UMaterial* ADungeonBuilder::LoadFloorMaterial()
{
TCHAR* floorMaterialName = TEXT("/Game/Materials/M_CobbleStone_Smooth.M_CobbleStone_Smooth");
UMaterial* floorMaterial = LoadObject<UMaterial>(NULL, floorMaterialName, NULL, LOAD_None, NULL);
return floorMaterial;
}
Edit: Included the engine version.