Worst-case scenario: the UEd Goblin wipes the map and burns down your house.
Legacy:Wizzie/OnJoinSpectatorCamera
From Unreal Wiki, The Unreal Engine Documentation Site
This is a codesnippet from my PlayerController. When a player joins the server, they'll have to choose a team in the teamselect menu. While they are choosing i change the camerlocation of the player to random locations of the map using current available actors as locations.
class pPlayerController extends PlayerController; ... ... ... auto state OnJoinSpectating { simulated function SetSpectatorCamera() { local int i; local array<Actor> ActorList; local Actor aActor; local float dist, bestdist; local vector CameraLocation, TargetLocation, best, tmp; local Vector hitloc, hitnormal; local float SearchTimelimit; // Get a list of current actors and skip those we don't want ForEach AllActors(class'Actor', aActor) { // Actor types we should'nt use if( Controller(aActor) != none || AntiPortalActor(aActor) != none || Emitter(aActor) != none || xEmitter(aActor) != none || BlockingVolume(aActor) != none || Info(aActor) != none || Inventory(aActor) != none || InventorySpot(aActor) != none || Note(aActor) != none || AmbientSound(aActor) != none || AIScript(aActor) != none || xWeatherEffect(aActor) != none || HUD(aActor) != none ) continue; ActorList[ActorList.Length] = aActor; } // Search for a good cameralocation for max 2 seconds, after that, take whatever location we got SearchTimeLimit = Level.TimeSeconds + 2; while( Level.TimeSeconds < SearchTimeLimit ) { // Pick a random actor to use as camera source aActor = ActorList[Rand(ActorList.Length)]; CameraLocation = aActor.location; // Using static meshes as cameralocation can give very strange camerapositions if( StaticMeshActor(aActor) != none ) continue; // Move out a randon number of units (atleast 256) from the light a random direction tmp = CameraLocation + VRand() * (rand(512) + 256); // Align new location to surrounding objects if( Trace( HitLoc, HitNormal, tmp, CameraLocation, true) != none ) CameraLocation = hitloc + hitnormal * 64; else CameraLocation = tmp; // Try avoiding placing the camera inside an visible actor i = 0; foreach RadiusActors( class'Actor', aActor, 64, CameraLocation ) if( aActor.bHidden == false ) i++; if( i > 0 ) continue; // Make sure the area surrounding the camera is clear to reduce clipping artifacts if( (Trace( HitLoc, HitNormal, CameraLocation+vect(64,0,0), CameraLocation+vect(-64,0,0), true) == none) && (Trace( HitLoc, HitNormal, CameraLocation+vect(0,64,0), CameraLocation+vect(0,-64,0), true) == none) && (Trace( HitLoc, HitNormal, CameraLocation+vect(0,0,64), CameraLocation+vect(0,0,-64), true) == none) ) break; } // Find a cameratarget location for(i=0; i < ActorList.Length; i++) { TargetLocation = ActorList[i].location; dist = VSize( CameraLocation - TargetLocation ); // Move the location out so we don't look straight at the actor tmp = TargetLocation + vrand() * rand(dist); // Don't push the new location through walls if( Trace(HitLoc,HitNormal, tmp, TargetLocation, false) != none ) TargetLocation = hitloc + HitNormal * 64; else TargetLocation = tmp; // Update new distance dist = VSize( CameraLocation - TargetLocation ); // Test this location and see if we found one with a better camera distance if( (bestdist <= 800) || ( (dist > 800) && (dist < bestdist) && (Trace(hitloc, hitnormal, TargetLocation, CameraLocation, false) == none )) ) { bestdist = dist; best = TargetLocation; } } SetLocation( CameraLocation ); SetRotation( rotator(best-CameraLocation) ); } function Timer() { SetSpectatorCamera(); } simulated function BeginState() { if( Level.NetMode != NM_DedicatedServer ) { SetTimer(6, true); SetSpectatorCamera(); // Initial cameraposition } } }