I’m not quite sure how to implement this. I have a game similar to the Roguelike Tutorial game (when you move, food decreases, except I’ve replaced food with health and also oxygen). My game randomly generates levels using the BoardCreator/Manager scripts, and I want oxygen to work like food did, so every space you move, it decreases. However, I only want oxygen to appear in the higher, harder levels. But I’m not sure how to do this. The if statement obviously (e.g. if level 6 or higher, make oxygen true), but I don’t know how to do it. Do I need a for loop as well? I’ll post the relevant scripts so you can see what’s going on.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
namespace Completed
{
//Player inherits from MovingObject, our base class for objects that can move, Enemy also inherits from this.
public class Player : MovingObject
{
public float restartLevelDelay = 1f; //Delay time in seconds to restart level.
public int pointsPerTuna = 10; //Number of points to add to player food points when picking up a food object.
public int pointsPerPotion = 20; //Number of points to add to player food points when picking up a soda object.
public int pointsPerOxygen = 10;
private bool weapon = false;
private bool key = false;
public int wallDamage = 1; //How much damage a player does to a wall when chopping it.
public Text oxygenText;
private int oxygen = 100;
public Text healthText;
public int health = 100;
public AudioClip moveSound1;
public AudioClip moveSound2;
public AudioClip eatSound1;
public AudioClip eatSound2;
public AudioClip drinkSound1;
public AudioClip drinkSound2;
public AudioClip gameOverSound;
private Animator animator; //Used to store a reference to the Player's animator component.
private bool oxygenLevel = false; //Oxygen is made a boolean so it can be set to true on harder levels
//Start overrides the Start function of MovingObject
protected override void Start()
{
//Get a component reference to the Player's animator component
animator = GetComponent<Animator>();
//Get the current food point total stored in GameManager.instance between levels.
oxygen = GameManager.instance.playerFoodPoints;
//oxygenText.text = "Oxygen: " + oxygen;
//Call the Start function of the MovingObject base class.
base.Start();
}
//This function is called when the behaviour becomes disabled or inactive.
private void OnDisable()
{
//When Player object is disabled, store the current local food total in the GameManager so it can be re-loaded in next level.
GameManager.instance.playerFoodPoints = health;
}
private void Update()
{
//If it's not the player's turn, exit the function.
if (!GameManager.instance.playersTurn) return;
int horizontal = 0; //Used to store the horizontal move direction.
int vertical = 0; //Used to store the vertical move direction.
//Get input from the input manager, round it to an integer and store in horizontal to set x axis move direction
horizontal = (int)(Input.GetAxisRaw("Horizontal"));
//Get input from the input manager, round it to an integer and store in vertical to set y axis move direction
vertical = (int)(Input.GetAxisRaw("Vertical"));
//Check if moving horizontally, if so set vertical to zero.
if (horizontal != 0)
{
vertical = 0;
}
//Check if we have a non-zero value for horizontal or vertical
if (horizontal != 0 || vertical != 0)
{
//Call AttemptMove passing in the generic parameter Wall, since that is what Player may interact with if they encounter one (by attacking it)
//Pass in horizontal and vertical as parameters to specify the direction to move Player in.
AttemptMove<Wall>(horizontal, vertical);
}
}
//AttemptMove overrides the AttemptMove function in the base class MovingObject
//AttemptMove takes a generic parameter T which for Player will be of the type Wall, it also takes integers for x and y direction to move in.
protected override void AttemptMove<T>(int xDir, int yDir)
{
//Every time player moves, subtract from food points total.
//oxygen--;
//oxygenText.text = "Oxygen: " + oxygen;
//Call the AttemptMove method of the base class, passing in the component T (in this case Wall) and x and y direction to move.
base.AttemptMove<T>(xDir, yDir);
//Hit allows us to reference the result of the Linecast done in Move.
RaycastHit2D hit;
//If Move returns true, meaning Player was able to move into an empty space.
if (Move(xDir, yDir, out hit))
{
//Call RandomizeSfx of SoundManager to play the move sound, passing in two audio clips to choose from.
// SoundManager.instance.RandomizeSfx(moveSound1,moveSound2);
}
//Since the player has moved and lost food points, check if the game has ended.
CheckIfGameOver();
//Set the playersTurn boolean of GameManager to false now that players turn is over.
GameManager.instance.playersTurn = false;
}
//OnCantMove overrides the abstract function OnCantMove in MovingObject.
//It takes a generic parameter T which in the case of Player is a Wall which the player can attack and destroy.
protected override void OnCantMove<T>(T component)
{
//Set hitWall to equal the component passed in as a parameter.
Wall hitWall = component as Wall;
//Call the DamageWall function of the Wall we are hitting.
hitWall.DamageWall(wallDamage);
//Set the attack trigger of the player's animation controller in order to play the player's attack animation.
animator.SetTrigger("playerChop");
}
//OnTriggerEnter2D is sent when another object enters a trigger collider attached to this object (2D physics only).
private void OnTriggerEnter2D(Collider2D other)
{
//Check if the tag of the trigger collided with is Exit.
if (other.tag == "Exit")
{
//Invoke the Restart function to start the next level with a delay of restartLevelDelay (default 1 second).
Invoke("Restart", restartLevelDelay);
//Disable the player object since level is over.
enabled = false;
}
//Check if the tag of the trigger collided with is Food.
else if (other.tag == "Food")
{
//Add pointsPerTuna to the players current health total.
health += pointsPerTuna;
healthText.text = "+" + pointsPerTuna + " Health: " + health;
SoundManager.instance.RandomizeSfx(eatSound1,eatSound2);
//Disable the tuna object the player collided with.
other.gameObject.SetActive(false);
}
//Check if the tag of the trigger collided with is Potion.
else if (other.tag == "Potion")
{
//Add pointsPerPotion to players health points total
health += pointsPerPotion;
healthText.text = "+" + pointsPerPotion + " Health: " + health;
SoundManager.instance.RandomizeSfx(drinkSound1,drinkSound2);
//Disable the potion object the player collided with.
other.gameObject.SetActive(false);
}
//Check if the tag of the trigger collided with is Oxygen.
else if (other.tag == "Oxygen")
{
//Add pointsPerOxygen to players oxygen points total
oxygen += pointsPerOxygen;
oxygenText.text = "+" + pointsPerOxygen + " Oxygen: " + oxygen;
SoundManager.instance.RandomizeSfx(drinkSound1,drinkSound2);
//Disable the oxygen object the player collided with.
other.gameObject.SetActive(false);
}
}
//Restart reloads the scene when called.
private void Restart()
{
//Load the last scene loaded, in this case Main, the only scene in the game.
Application.LoadLevel(Application.loadedLevel);
}
//LoseFood is called when an enemy attacks the player.
//It takes a parameter loss which specifies how many points to lose.
public void LoseFood(int loss)
{
//Set the trigger for the player animator to transition to the playerHit animation.
animator.SetTrigger("playerHit");
//Subtract lost food points from the players total.
health -= loss;
healthText.text = "-" + loss + " Health: " + health;
//Check to see if game has ended.
CheckIfGameOver();
}
//CheckIfGameOver checks if the player is out of food points and if so, ends the game.
private void CheckIfGameOver()
{
//Check if oxygen or health is equal to or less than zero.
if (oxygen <= 0 || health <= 0)
{
//Call the GameOver function of GameManager.
SoundManager.instance.PlaySingle(gameOverSound);
SoundManager.instance.musicSource.Stop();
GameManager.instance.GameOver();
}
}
//If the level is 6 or higher, make the oxygen boolean true
public void Oxygen(){
if(){
oxygenLevel = true;
}
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random; //Tells Random to use the Unity Engine random number generator.
namespace Completed
{
public class BoardCreator : MonoBehaviour
{
// The type of tile that will be laid in a specific position.
public enum TileType
{
Wall, Floor,
}
// Using Serializable allows us to embed a class with sub properties in the inspector.
[Serializable]
public class Count
{
public int minimum; //Minimum value for our Count class.
public int maximum; //Maximum value for our Count class.
//Assignment constructor.
public Count(int min, int max)
{
minimum = min;
maximum = max;
}
}
public int columns = 100; // The number of columns on the board (how wide it will be).
public int rows = 100; // The number of rows on the board (how tall it will be).
public IntRange numRooms = new IntRange(15, 20); // The range of the number of rooms there can be.
public IntRange roomWidth = new IntRange(3, 10); // The range of widths rooms can have.
public IntRange roomHeight = new IntRange(3, 10); // The range of heights rooms can have.
public IntRange corridorLength = new IntRange(6, 10); // The range of lengths corridors between rooms can have.
public IntRange numEnemies = new IntRange(1, 5); //Lower and upper limit for our random number of food items per level.
public Count foodCount = new Count(1, 5); //Lower and upper limit for our random number of food items per level.
public GameObject[] floorTiles; // An array of floor tile prefabs.
public GameObject[] objectTiles; // An array of food tile prefabs.
public GameObject[] enemyTiles; // Array of enemy prefabs.
public GameObject[] weaponTiles; // Array of weapon prefabs.
public GameObject[] computerTiles; // Array of weapon prefabs.
public GameObject[] wallTiles; // An array of wall tile prefabs.
public GameObject[] outerWallTiles; // An array of outer wall tile prefabs.
public GameObject player;
public GameObject exit;
private TileType[][] tiles; // A jagged array of tile types representing the board, like a grid.
private Room[] rooms; // All the rooms that are created for this board.
private Corridor[] corridors; // All the corridors that connect the rooms.
private GameObject boardHolder; // GameObject that acts as a container for all other tiles.
private List<Vector3> gridPositions = new List<Vector3>(); //A list of possible locations to place tiles.
public void levelStart(int level)
{
Spawner();
}
public void Spawner()
{
// Create the board holder.
boardHolder = new GameObject("BoardHolder");
SetupTilesArray();
CreateRoomsAndCorridors();
SetTilesValuesForRooms();
SetTilesValuesForCorridors();
InstantiateTiles();
InstantiateOuterWalls();
CreateEnemies();
CreateWeapons();
CreateObjects();
CreateComputers ();
}
void CreateEnemies()
{
//spawn between 1-5 enemies
int randomEnemies = Random.Range(1, 5);
Vector3 enemySpawn = Vector3.zero;
for (int i = 0; i < randomEnemies; i++)
{
enemySpawn.x = Random.Range(1, 30);
enemySpawn.y = Random.Range(1, 30);
while (tiles[(int)(enemySpawn.x)][(int)(enemySpawn.y)] == TileType.Wall)
{
enemySpawn.x = Random.Range(1, 30);
enemySpawn.y = Random.Range(1, 30);
}
Instantiate(enemyTiles[UnityEngine.Random.Range(0, enemyTiles.Length)], enemySpawn, Quaternion.identity);
}
}
void CreateWeapons()
{
//spawn between 1-5 objects
int randomWeapons = Random.Range(1, 5);
Vector3 weaponSpawn = Vector3.zero;
for (int i = 0; i < randomWeapons; i++)
{
weaponSpawn.x = Random.Range(1, 30);
weaponSpawn.y = Random.Range(1, 30);
while (tiles[(int)(weaponSpawn.x)][(int)(weaponSpawn.y)] == TileType.Wall)
{
weaponSpawn.x = Random.Range(1, 30);
weaponSpawn.y = Random.Range(1, 30);
}
Instantiate(objectTiles[UnityEngine.Random.Range(0, weaponTiles.Length)], weaponSpawn, Quaternion.identity);
}
}
void CreateObjects()
{
//spawn between 1-5 objects
int randomObjects = Random.Range(1, 5);
Vector3 objectSpawn = Vector3.zero;
for (int i = 0; i < randomObjects; i++)
{
objectSpawn.x = Random.Range(1, 30);
objectSpawn.y = Random.Range(1, 30);
while (tiles[(int)(objectSpawn.x)][(int)(objectSpawn.y)] == TileType.Wall)
{
objectSpawn.x = Random.Range(1, 30);
objectSpawn.y = Random.Range(1, 30);
}
Instantiate(objectTiles[UnityEngine.Random.Range(0, objectTiles.Length)], objectSpawn, Quaternion.identity);
}
}
void CreateComputers()
{
//spawn between 1-5 objects
int randomObjects = Random.Range(1, 5);
Vector3 computerSpawn = Vector3.zero;
for (int i = 0; i < randomObjects; i++)
{
computerSpawn.x = Random.Range(1, 30);
computerSpawn.y = Random.Range(1, 30);
while (tiles[(int)(computerSpawn.x)][(int)(computerSpawn.y)] == TileType.Wall)
{
computerSpawn.x = Random.Range(1, 30);
computerSpawn.y = Random.Range(1, 30);
}
Instantiate(computerTiles[UnityEngine.Random.Range(0, computerTiles.Length)], computerSpawn, Quaternion.identity);
}
}
void SetupTilesArray()
{
// Set the tiles jagged array to the correct width.
tiles = new TileType[columns][];
// Go through all the tile arrays...
for (int i = 0; i < tiles.Length; i++)
{
// ... and set each tile array is the correct height.
tiles[i] = new TileType[rows];
}
}
void CreateRoomsAndCorridors()
{
// Create the rooms array with a random size.
rooms = new Room[numRooms.Random];
// There should be one less corridor than there is rooms.
corridors = new Corridor[rooms.Length - 1];
// Create the first room and corridor.
rooms[0] = new Room();
corridors[0] = new Corridor();
// Setup the first room, there is no previous corridor so we do not use one.
rooms[0].SetupRoom(roomWidth, roomHeight, columns, rows);
// Setup the first corridor using the first room.
corridors[0].SetupCorridor(rooms[0], corridorLength, roomWidth, roomHeight, columns, rows, true);
for (int i = 1; i < rooms.Length; i++)
{
// Create a room.
rooms[i] = new Room();
// Setup the room based on the previous corridor.
rooms[i].SetupRoom(roomWidth, roomHeight, columns, rows, corridors[i - 1]);
// If we haven't reached the end of the corridors array...
if (i < corridors.Length)
{
// ... create a corridor.
corridors[i] = new Corridor();
// Setup the corridor based on the room that was just created.
corridors[i].SetupCorridor(rooms[i], corridorLength, roomWidth, roomHeight, columns, rows, false);
}
//For positioning the player in a room
if (i == Math.Floor(rooms.Length * .5f))
{
Vector3 playerPos = new Vector3(rooms[i].xPos, rooms[i].yPos, 0);
Instantiate(player, playerPos, Quaternion.identity);
}
//For positioning the next level in a room
if (i == Math.Floor(rooms.Length * .10f))
{
Vector3 exitPos = new Vector3(rooms[i].xPos, rooms[i].yPos, 0);
Instantiate(exit, exitPos, Quaternion.identity);
}
}
}
void SetTilesValuesForRooms()
{
// Go through all the rooms...
for (int i = 0; i < rooms.Length; i++)
{
Room currentRoom = rooms[i];
// ... and for each room go through it's width.
for (int j = 0; j < currentRoom.roomWidth; j++)
{
int xCoord = currentRoom.xPos + j;
// For each horizontal tile, go up vertically through the room's height.
for (int k = 0; k < currentRoom.roomHeight; k++)
{
int yCoord = currentRoom.yPos + k;
// The coordinates in the jagged array are based on the room's position and it's width and height.
tiles[xCoord][yCoord] = TileType.Floor;
}
}
}
}
void SetTilesValuesForCorridors()
{
// Go through every corridor...
for (int i = 0; i < corridors.Length; i++)
{
Corridor currentCorridor = corridors[i];
// and go through it's length.
for (int j = 0; j < currentCorridor.corridorLength; j++)
{
// Start the coordinates at the start of the corridor.
int xCoord = currentCorridor.startXPos;
int yCoord = currentCorridor.startYPos;
// Depending on the direction, add or subtract from the appropriate
// coordinate based on how far through the length the loop is.
switch (currentCorridor.direction)
{
case Direction.North:
yCoord += j;
break;
case Direction.East:
xCoord += j;
break;
case Direction.South:
yCoord -= j;
break;
case Direction.West:
xCoord -= j;
break;
}
// Set the tile at these coordinates to Floor.
tiles[xCoord][yCoord] = TileType.Floor;
}
}
}
void InstantiateTiles()
{
// Go through all the tiles in the jagged array...
for (int i = 0; i < tiles.Length; i++)
{
for (int j = 0; j < tiles[i].Length; j++)
{
// ... and instantiate a floor tile for it.
InstantiateFromArray(floorTiles, i, j);
// If the tile type is Wall...
if (tiles[i][j] == TileType.Wall)
{
// ... instantiate a wall over the top.
InstantiateFromArray(wallTiles, i, j);
}
}
}
}
void InstantiateOuterWalls()
{
// The outer walls are one unit left, right, up and down from the board.
float leftEdgeX = -1f;
float rightEdgeX = columns + 0f;
float bottomEdgeY = -1f;
float topEdgeY = rows + 0f;
// Instantiate both vertical walls (one on each side).
InstantiateVerticalOuterWall(leftEdgeX, bottomEdgeY, topEdgeY);
InstantiateVerticalOuterWall(rightEdgeX, bottomEdgeY, topEdgeY);
// Instantiate both horizontal walls, these are one in left and right from the outer walls.
InstantiateHorizontalOuterWall(leftEdgeX + 1f, rightEdgeX - 1f, bottomEdgeY);
InstantiateHorizontalOuterWall(leftEdgeX + 1f, rightEdgeX - 1f, topEdgeY);
}
void InstantiateVerticalOuterWall(float xCoord, float startingY, float endingY)
{
// Start the loop at the starting value for Y.
float currentY = startingY;
// While the value for Y is less than the end value...
while (currentY <= endingY)
{
// ... instantiate an outer wall tile at the x coordinate and the current y coordinate.
InstantiateFromArray(outerWallTiles, xCoord, currentY);
currentY++;
}
}
void InstantiateHorizontalOuterWall(float startingX, float endingX, float yCoord)
{
// Start the loop at the starting value for X.
float currentX = startingX;
// While the value for X is less than the end value...
while (currentX <= endingX)
{
// ... instantiate an outer wall tile at the y coordinate and the current x coordinate.
InstantiateFromArray(outerWallTiles, currentX, yCoord);
currentX++;
}
}
void InstantiateFromArray(GameObject[] prefabs, float xCoord, float yCoord)
{
// Create a random index for the array.
int randomIndex = Random.Range(0, prefabs.Length);
// The position to be instantiated at is based on the coordinates.
Vector3 position = new Vector3(xCoord, yCoord, 0f);
// Create an instance of the prefab from the random index of the array.
GameObject tileInstance = Instantiate(prefabs[randomIndex], position, Quaternion.identity) as GameObject;
// Set the tile's parent to the board holder.
tileInstance.transform.parent = boardHolder.transform;
}
}
}
using System;
using System.Collections.Generic; //Allows us to use Lists.
using Random = UnityEngine.Random; //Tells Random to use the Unity Engine random number generator.
namespace Completed
{
public class BoardManager : MonoBehaviour
{
// Using Serializable allows us to embed a class with sub properties in the inspector.
[Serializable]
public class Count
{
public int minimum; //Minimum value for our Count class.
public int maximum; //Maximum value for our Count class.
//Assignment constructor.
public Count(int min, int max)
{
minimum = min;
maximum = max;
}
}
public int columns = 8; //Number of columns in our game board.
public int rows = 8; //Number of rows in our game board.
public Count wallCount = new Count(5, 9); //Lower and upper limit for our random number of walls per level.
public Count foodCount = new Count(1, 5); //Lower and upper limit for our random number of food items per level.
public GameObject exit; //Prefab to spawn for exit.
public GameObject[] floorTiles; //Array of floor prefabs.
public GameObject[] wallTiles; //Array of wall prefabs.
public GameObject[] foodTiles; //Array of food prefabs.
public GameObject[] enemyTiles; //Array of enemy prefabs.
public GameObject[] outerWallTiles; //Array of outer tile prefabs.
private Transform boardHolder; //A variable to store a reference to the transform of our Board object.
private List<Vector3> gridPositions = new List<Vector3>(); //A list of possible locations to place tiles.
//Clears our list gridPositions and prepares it to generate a new board.
void InitialiseList()
{
//Clear our list gridPositions.
gridPositions.Clear();
//Loop through x axis (columns).
for (int x = 1; x < columns - 1; x++)
{
//Within each column, loop through y axis (rows).
for (int y = 1; y < rows - 1; y++)
{
//At each index add a new Vector3 to our list with the x and y coordinates of that position.
gridPositions.Add(new Vector3(x, y, 0f));
}
}
}
//Sets up the outer walls and floor (background) of the game board.
void BoardSetup()
{
//Instantiate Board and set boardHolder to its transform.
boardHolder = new GameObject("Board").transform;
//Loop along x axis, starting from -1 (to fill corner) with floor or outerwall edge tiles.
for (int x = -1; x < columns + 1; x++)
{
//Loop along y axis, starting from -1 to place floor or outerwall tiles.
for (int y = -1; y < rows + 1; y++)
{
//Choose a random tile from our array of floor tile prefabs and prepare to instantiate it.
GameObject toInstantiate = floorTiles[Random.Range(0, floorTiles.Length)];
//Check if we current position is at board edge, if so choose a random outer wall prefab from our array of outer wall tiles.
if (x == -1 || x == columns || y == -1 || y == rows)
toInstantiate = outerWallTiles[Random.Range(0, outerWallTiles.Length)];
//Instantiate the GameObject instance using the prefab chosen for toInstantiate at the Vector3 corresponding to current grid position in loop, cast it to GameObject.
GameObject instance =
Instantiate(toInstantiate, new Vector3(x, y, 0f), Quaternion.identity) as GameObject;
//Set the parent of our newly instantiated object instance to boardHolder, this is just organizational to avoid cluttering hierarchy.
instance.transform.SetParent(boardHolder);
}
}
}
//RandomPosition returns a random position from our list gridPositions.
Vector3 RandomPosition()
{
//Declare an integer randomIndex, set it's value to a random number between 0 and the count of items in our List gridPositions.
int randomIndex = Random.Range(0, gridPositions.Count);
//Declare a variable of type Vector3 called randomPosition, set it's value to the entry at randomIndex from our List gridPositions.
Vector3 randomPosition = gridPositions[randomIndex];
//Remove the entry at randomIndex from the list so that it can't be re-used.
gridPositions.RemoveAt(randomIndex);
//Return the randomly selected Vector3 position.
return randomPosition;
}
//LayoutObjectAtRandom accepts an array of game objects to choose from along with a minimum and maximum range for the number of objects to create.
void LayoutObjectAtRandom(GameObject[] tileArray, int minimum, int maximum)
{
//Choose a random number of objects to instantiate within the minimum and maximum limits
int objectCount = Random.Range(minimum, maximum + 1);
//Instantiate objects until the randomly chosen limit objectCount is reached
for (int i = 0; i < objectCount; i++)
{
//Choose a position for randomPosition by getting a random position from our list of available Vector3s stored in gridPosition
Vector3 randomPosition = RandomPosition();
//Choose a random tile from tileArray and assign it to tileChoice
GameObject tileChoice = tileArray[Random.Range(0, tileArray.Length)];
//Instantiate tileChoice at the position returned by RandomPosition with no change in rotation
Instantiate(tileChoice, randomPosition, Quaternion.identity);
}
}
//SetupScene initializes our level and calls the previous functions to lay out the game board
public void SetupScene(int level)
{
//Creates the outer walls and floor.
BoardSetup();
//Reset our list of gridpositions.
InitialiseList();
//Instantiate a random number of wall tiles based on minimum and maximum, at randomized positions.
LayoutObjectAtRandom(wallTiles, wallCount.minimum, wallCount.maximum);
//Instantiate a random number of food tiles based on minimum and maximum, at randomized positions.
LayoutObjectAtRandom(foodTiles, foodCount.minimum, foodCount.maximum);
//Determine number of enemies based on current level number, based on a logarithmic progression
int enemyCount = (int)Mathf.Log(level, 2f);
//Instantiate a random number of enemies based on minimum and maximum, at randomized positions.
LayoutObjectAtRandom(enemyTiles, enemyCount, enemyCount);
//Instantiate the exit tile in the upper right hand corner of our game board
Instantiate(exit, new Vector3(columns - 1, rows - 1, 0f), Quaternion.identity);
}
}
}