@ -18,6 +18,10 @@ public class RacetrackGameMode : GameMode
public Material OverlayMaterial ;
public float scrollSpeed = 1.0f ; //The rate at which the level will scroll past
[SerializeField]
[Tooltip("Layers to ignore when checking for blocks")]
public LayerMask Ignore ;
public int RoundCount { get ; private set ; }
private Dictionary < ClientData , List < Block > > BlocksOwned ;
@ -39,19 +43,121 @@ public class RacetrackGameMode : GameMode
cameraCheck ( allPlayers ) ;
//At the end of each round, any stuck players are freed to resume moving next round
foreach ( PlayerData player in allPlayers )
respawnPlayers ( allPlayers ) ;
/ * foreach ( PlayerData player in allPlayers )
{
player . character . stuck = false ;
if ( player . character . inPit & & player . client . Lives > 0 )
if ( player . character . respawnNeeded & & player . client . Lives > 0 )
{
player . character . respawnCharacter ( ) ;
}
}
} * /
RoundCount + + ;
}
void respawnPlayers ( PlayerData [ ] allPlayers )
{
//First step: determine if anyone is waiting to respawn
List < PlayerData > respawningPlayers = new List < PlayerData > ( ) ;
List < PlayerData > survivingPlayers = new List < PlayerData > ( ) ;
foreach ( PlayerData player in allPlayers )
{
if ( player . client . Lives > 0 )
{
if ( player . character . respawnNeeded )
{
respawningPlayers . Add ( player ) ;
}
else
{
survivingPlayers . Add ( player ) ;
}
}
}
//If nobody needs a respawn, we stop here. Otherwise, we carry on
if ( respawningPlayers . Count > 0 )
{
//Next step: figure out the appropriate respawn point
//If there are any players left, it will be the average of their positions
//Otherwise, it will be as close to the centre of the screen as possible
Vector3 respawnLocation = new Vector3 ( 0.0f , - 0.5f , 0.0f ) ;
if ( survivingPlayers . Count > 0 ) //If any players are not currently waiting to respawn, we get the average of their locations
{
//We list the positions of all the surviving players
List < Vector3 > survivingPlayerLocations = new List < Vector3 > ( ) ;
foreach ( PlayerData player in survivingPlayers )
{
survivingPlayerLocations . Add ( player . character . transform . position ) ;
}
foreach ( Vector3 vec in survivingPlayerLocations )
{
respawnLocation + = vec ;
}
respawnLocation = respawnLocation / survivingPlayers . Count ;
}
else //Otherwise, we go for the middle of the screen
{
//We start in the middle of the track, at the back, and scroll forward until we're past the centre of the camera's view
respawnLocation . x = mapManager . startX ;
Vector3 respawnLocationVP = Camera . main . WorldToViewportPoint ( respawnLocation ) ;
while ( respawnLocationVP . x > 0.5f | | respawnLocationVP . y > 0.5f )
{
respawnLocation . x + = 1.0f ;
respawnLocationVP = Camera . main . WorldToViewportPoint ( respawnLocation ) ;
}
}
//Now we randomly pick blocks in the vicinity of this point to respawn players on
//Valid blocks are those within x & +/-1 from the chosen location
//If we don't find enough open, unoccupied blocks within that radius, then we widen it
int radius = 0 ;
List < Block > respawnBlocks ;
do
{
respawnBlocks = new List < Block > ( ) ;
radius + + ;
for ( int i = - 1 * radius ; i < = radius ; i + + )
{
for ( int j = - 1 * radius ; j < = radius ; j + + )
{
Block currentBlock ;
Vector3 currentPos = new Vector3 ( respawnLocation . x + i , respawnLocation . y , respawnLocation . z ) ;
if ( Block . isBlockAtPosition ( currentPos , 1 , ~ Ignore , out currentBlock ) //Does a block exist here?
& & currentBlock . is_Walkable //Are we allowed on this block?
& & ! ( currentBlock . isWater ) & & ! ( currentBlock . isPit ) //Don't respawn on top of instant traps
& & currentBlock . CurrentPlayer = = null ) //Block must be unoccupied
{
respawnBlocks . Add ( currentBlock ) ;
}
}
}
} while ( respawnBlocks . Count < respawningPlayers . Count ) ;
foreach ( PlayerData player in respawningPlayers )
{
//We randomly pick a block for them to respawn on
Block respawnBlock = respawnBlocks [ ( int ) Random . Range ( 0.0f , ( float ) respawnBlocks . Count ) ] ;
Vector3 respawnLocationPlayer = respawnBlock . transform . position ;
player . character . respawnCharacter ( respawnLocationPlayer ) ;
respawnBlocks . Remove ( respawnBlock ) ; //Then we remove it from the list for the next player
}
}
}
void cameraCheck ( PlayerData [ ] allPlayers )
{
//Get the average x-position of all players
@ -60,14 +166,17 @@ public class RacetrackGameMode : GameMode
foreach ( PlayerData player in allPlayers )
{
if ( player . client . Lives > 0 )
if ( ! ( player . character . respawnNeeded ) & & player . client . Lives > 0 )
{
xAvg + = player . character . transform . position . x ;
livePlayerCount + + ;
}
}
xAvg = xAvg / livePlayerCount ;
if ( livePlayerCount > 0 )
{
xAvg = xAvg / livePlayerCount ;
}
//Turn that position into a vector in viewport space
Vector3 xAvgPos = new Vector3 ( xAvg , 0.0f , 0.0f ) ;
@ -107,6 +216,18 @@ public class RacetrackGameMode : GameMode
playerVP = Camera . main . WorldToViewportPoint ( playerAhead . character . transform . position ) ;
} /**/
//If anyone is out of view at this point, they are dead and need to respawn
foreach ( PlayerData player in allPlayers )
{
if ( player . client . Lives > 0 & & ! ( player . character . respawnNeeded ) )
{
playerVP = Camera . main . WorldToViewportPoint ( player . character . transform . position ) ;
if ( playerVP . x < 0.0f | | playerVP . y < 0.0f )
{
player . character . respawnNeeded = true ;
}
}
}
//We check for track sections we need to add/remove
mapManager . checkTrack ( ) ;
@ -158,14 +279,14 @@ public class RacetrackGameMode : GameMode
//If a character has fallen in the water or into a pit, we mark that fact, and they lose the rest of their turn
character . inWater = currentBlock . isWater ;
character . inPit = currentBlock . isPit ;
character . respawnNeeded = currentBlock . isPit ;
if ( character . inWater = = true | | character . inPit = = true )
if ( character . inWater = = true | | character . respawnNeeded = = true )
{
character . stuck = true ;
}
Debug . Log ( "inWater = " + character . inWater + ", inPit = " + character . inPit + ", stuck = " + character . stuck ) ; * /
Debug . Log ( "inWater = " + character . inWater + ", respawnNeeded = " + character . respawnNeeded + ", stuck = " + character . stuck ) ; * /
//Commented out because we don't do this in the racetrack mode
@ -251,20 +372,20 @@ public class RacetrackGameMode : GameMode
{
//If a character has fallen in the water or into a pit, we mark that fact, and they lose the rest of their turn
character . inWater = currentBlock . isWater ;
character . inPit = currentBlock . isPit ;
character . respawnNeeded = currentBlock . isPit ;
character . onCrystal = currentBlock . isCrystals ;
character . underRock = currentBlock . isRock ;
if ( didMove & & ( character . inWater | | character . inPit ) )
if ( didMove & & ( character . inWater | | character . respawnNeeded ) )
{
character . stuck = true ;
}
//Debug.Log("inWater = " + character.inWater + ", inPit = " + character.inPit + ", stuck = " + character.stuck);
//Debug.Log("inWater = " + character.inWater + ", respawnNeeded = " + character.respawnNeeded + ", stuck = " + character.stuck);
}
protected override void OnPlayerKilled ( Character character , ClientData client )
{
if ( character . inPit | | character . onCrystal )
if ( character . respawnNeeded | | character . onCrystal )
{
character . lives - = 1 ;
character . ClientLink . Lives = character . lives ;