Browse Source

Implemented new respawn logic: respawn location is the average loccation of players left on map, if any, or otherwise is the centre of the screen. Players will respawn in random open & unoccupied squares near this (within a radius of 1 if possible, widening the radius if there aren't enough open squares in that area).

Also made it so that players who fall behind the camera will lose a life & respawn, as intended.
master
s3607057 (Angus Niven) 5 years ago
parent
commit
c1309d9165
3 changed files with 137 additions and 16 deletions
  1. +3
    -3
      Assets/Scripts/Character.cs
  2. +133
    -12
      Assets/Scripts/GameMode/ColorGameMode/RacetrackGameMode.cs
  3. +1
    -1
      Assets/Scripts/Map Generation/MapManager.cs

+ 3
- 3
Assets/Scripts/Character.cs View File

@ -17,7 +17,7 @@ public class Character : MonoBehaviour
public bool isTuteLevel = false; public bool isTuteLevel = false;
public bool inWater = false; //Am I in the water? public bool inWater = false; //Am I in the water?
public bool inPit = false; //Did I fall into a pit?
public bool respawnNeeded = false; //Am I waiting on a respawn?
public bool onCrystal = false; public bool onCrystal = false;
public bool underRock = false; public bool underRock = false;
public bool stuck = false; //Am I still stuck? public bool stuck = false; //Am I still stuck?
@ -287,13 +287,13 @@ public class Character : MonoBehaviour
if (currentBlock != null) if (currentBlock != null)
{ {
this.transform.position = currentBlock.VisualPosition; this.transform.position = currentBlock.VisualPosition;
this.inPit = false;
this.respawnNeeded = false;
this._currentBlock = currentBlock; this._currentBlock = currentBlock;
Debug.Log("Moved " + this.name + " to " Debug.Log("Moved " + this.name + " to "
+ this.transform.position.x + ", " + this.transform.position.x + ", "
+ this.transform.position.y + ", " + this.transform.position.y + ", "
+ this.transform.position.z + ", " + this.transform.position.z + ", "
+ " inPit = " + inPit);
+ " respawnNeeded = " + respawnNeeded);
} }
else else
{ {

+ 133
- 12
Assets/Scripts/GameMode/ColorGameMode/RacetrackGameMode.cs View File

@ -18,6 +18,10 @@ public class RacetrackGameMode : GameMode
public Material OverlayMaterial; public Material OverlayMaterial;
public float scrollSpeed = 1.0f; //The rate at which the level will scroll past 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; } public int RoundCount { get; private set; }
private Dictionary<ClientData, List<Block>> BlocksOwned; private Dictionary<ClientData, List<Block>> BlocksOwned;
@ -39,19 +43,121 @@ public class RacetrackGameMode : GameMode
cameraCheck(allPlayers); cameraCheck(allPlayers);
//At the end of each round, any stuck players are freed to resume moving next round //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; player.character.stuck = false;
if (player.character.inPit && player.client.Lives > 0)
if (player.character.respawnNeeded && player.client.Lives > 0)
{ {
player.character.respawnCharacter(); player.character.respawnCharacter();
} }
}
}*/
RoundCount++; 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) void cameraCheck(PlayerData[] allPlayers)
{ {
//Get the average x-position of all players //Get the average x-position of all players
@ -60,14 +166,17 @@ public class RacetrackGameMode : GameMode
foreach (PlayerData player in allPlayers) foreach (PlayerData player in allPlayers)
{ {
if (player.client.Lives > 0)
if (!(player.character.respawnNeeded) && player.client.Lives > 0)
{ {
xAvg += player.character.transform.position.x; xAvg += player.character.transform.position.x;
livePlayerCount++; livePlayerCount++;
} }
} }
xAvg = xAvg / livePlayerCount;
if (livePlayerCount > 0)
{
xAvg = xAvg / livePlayerCount;
}
//Turn that position into a vector in viewport space //Turn that position into a vector in viewport space
Vector3 xAvgPos = new Vector3(xAvg, 0.0f, 0.0f); 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); 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 //We check for track sections we need to add/remove
mapManager.checkTrack(); 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 //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.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; 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 //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 //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.inWater = currentBlock.isWater;
character.inPit = currentBlock.isPit;
character.respawnNeeded = currentBlock.isPit;
character.onCrystal = currentBlock.isCrystals; character.onCrystal = currentBlock.isCrystals;
character.underRock = currentBlock.isRock; character.underRock = currentBlock.isRock;
if (didMove && (character.inWater || character.inPit))
if (didMove && (character.inWater || character.respawnNeeded))
{ {
character.stuck = 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);
} }
protected override void OnPlayerKilled(Character character, ClientData client) protected override void OnPlayerKilled(Character character, ClientData client)
{ {
if (character.inPit || character.onCrystal)
if (character.respawnNeeded || character.onCrystal)
{ {
character.lives -= 1; character.lives -= 1;
character.ClientLink.Lives = character.lives; character.ClientLink.Lives = character.lives;

+ 1
- 1
Assets/Scripts/Map Generation/MapManager.cs View File

@ -21,7 +21,7 @@ public class MapManager : ScriptableObject
public List<MapSection> activeSections; //The list of sections that have been placed on the map (and not removed) public List<MapSection> activeSections; //The list of sections that have been placed on the map (and not removed)
MapSection lastSection; //Which map-section was most recently added? MapSection lastSection; //Which map-section was most recently added?
float startX; //The x-position of the current start of the track
public float startX; //The x-position of the current start of the track
float startXinit = -16.0f; float startXinit = -16.0f;
float endX; //The x-position of the current end of the track float endX; //The x-position of the current end of the track
int totalSections; //How many sections have been added? Including ones that have been deleted int totalSections; //How many sections have been added? Including ones that have been deleted

Loading…
Cancel
Save