Gameplay.Gate.cs - robblofield/TomeboundDocs GitHub Wiki
A script which should be attached to every Gate GameObject, handles everything about sending the player characters and the Tome to the other side of the corresponding Gate. It takes form of the "Gameplay".
- EnterGate.cs
- Player.cs
- GameManager.cs
- GameObject Gate
- GameObject Gate with the same ID
- GameObject Player character and the Tome
- Use case
- Breakdown of code
- Using Statements
- Variables
- Start()
- checkObjectColliding()
- TeleportObject()
- Future Expansion
- Full Code Reference
It is mainly used for the GameObject Gate when it receives requests from nearby Player characters via EnterGate.cs. The script is not standalone and some functions must be executed from other scripts.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public bool isStartGate;
private Transform linkedGate;
private GameObject collidingObject;
private GameManager gameManager;
private bool hasUnlocked;
[Range(0, 2)] public int id;
bool isStartGate: A static boolean to set whether the Gate is a start or exit gate.
Transform linkedGate: A local transform data for the Gate that is linked with this one.
GameObject collidingObject: Stores local data for the object that is colliding with the Raycast from the Gate.
bool hasUnlocked: Represents whether the Gate is unlocked by the Tome and players can re-enter the Gate.
int id: The integer value ranged from 0 to 2 to look for the corresponding linkedGate.
GameObject[] gates = GameObject.FindGameObjectsWithTag("Gate");
foreach (GameObject gate in gates)
{
if (gate.GetComponent<Gate>().id == id)
{
if (gate.name != gameObject.name)
{
linkedGate = gate.transform;
break;
}
}
}
if (linkedGate == null)
{
Debug.Log("Linked Gate with id " + id + " not found");
}
gameManager = GameObject.FindObjectOfType<GameManager>().GetComponent<GameManager>();
Debug.Log(transform.parent.eulerAngles.y);
A function which is executed once at the start of the script. Mainly used for the initialization and finding linkedGate with the same ID.
Firstly, the array "gates" gets data of all GameObjects with the tag "Gate" within the Scene.
It uses foreach loops to look for the gate with the same ID, except for itself. The gate with same ID becomes the linkedGate and the for loop is stopped.
If it couldn't find the linkedGate, The debug message about not locating linkedGate with the same ID is displayed.
After that, it looks for the GameObject with the script GameManager.cs.
public Transform GetLinkedGate()
{
return linkedGate;
}
An accessor method which returns the transform data of the linkedGate.
private bool checkObjectColliding(Vector3 pos)
{
RaycastHit hit = new RaycastHit();
Debug.DrawRay(pos, Vector3.up * 1.25f, Color.green);
if (Physics.Raycast(pos, Vector3.up, out hit, 1.25f))
{
Debug.DrawRay(pos, Vector3.up * 1.25f, Color.blue);
collidingObject = hit.collider.gameObject;
return true;
}
return false;
}
A function which casts a ray upwards from the position set in the Vector3 parameter "pos".
It returns true if a ray collides with any collider and gets GameObject data as the variable collidingObject.
public void TeleportObject()
{
if (linkedGate != null)
{
if (checkObjectColliding(transform.position))
{
Vector3 teleportCoordinate = new Vector3(linkedGate.position.x, collidingObject.transform.position.y, linkedGate.position.z);
int addID;
if (!isStartGate)
{
addID = 1;
}
else
{
addID = -1;
}
if (!linkedGate.GetComponent<Gate>().checkObjectColliding(linkedGate.transform.position))
{
if (collidingObject.tag == "Player")
{
if (hasUnlocked || isStartGate)
{
collidingObject.transform.position = teleportCoordinate;
collidingObject.GetComponent<BaseObjectData>().floorID += addID;
// collidingObject.GetComponent<gridBasedMovement>().isGrabbingBook = false;
collidingObject.GetComponent<Action_Grab>().ReleaseObject();
}
else
{
gameManager.SetErrorMessage("You need to bring the tome to activate the Gate!");
}
}
if (collidingObject.tag == "Book")
{
if (isStartGate)
{
gameManager.SetErrorMessage("You can't send the Tome to previous floor!");
}
else
{
Tome tome = collidingObject.GetComponent<Tome>();
if (tome.isWizXHolding || tome.isWizYHolding)
{
// Debug.Log("Press Enter to Teleport Book and Player");
if (tome.isWizXHolding && tome.isWizYHolding)
{
// Debug.Log("Press Enter to Teleport Book and Both Players");
}
hasUnlocked = true;
if (!gameManager.invertTeleportation)
{
if (transform.parent.eulerAngles.y == 90)
{
if (tome.WizXDistance.x != 0 || tome.WizYDistance.x != 0)
{
teleportCoordinate += Vector3.right;
}
}
else if (transform.eulerAngles.y == 0)
{
if (tome.WizXDistance.z != 0 || tome.WizYDistance.z != 0)
{
teleportCoordinate += Vector3.down;
}
}
else if (transform.eulerAngles.y == 180)
{
if (tome.WizXDistance.z != 0 || tome.WizYDistance.z != 0)
{
teleportCoordinate += Vector3.up;
}
}
}
collidingObject.transform.position = teleportCoordinate;
collidingObject.GetComponent<BaseObjectData>().floorID += addID;
if (tome.isWizXHolding)
{
float origWizHeight = tome.WizX.position.y;
tome.WizX.position = teleportCoordinate - tome.WizXDistance;
tome.WizX.position = new Vector3(tome.WizX.position.x, origWizHeight, tome.WizX.position.z);
if (gameManager.invertTeleportation)
{
tome.WizX.eulerAngles += Vector3.up * 180;
}
tome.WizX.GetComponent<BaseObjectData>().floorID += addID;
}
if (tome.isWizYHolding)
{
float origWizHeight = tome.WizY.position.y;
tome.WizY.position = teleportCoordinate - tome.WizYDistance;
tome.WizY.position = new Vector3(tome.WizY.position.x, origWizHeight, tome.WizY.position.z);
if (gameManager.invertTeleportation)
{
tome.WizY.eulerAngles += Vector3.up * 180;
}
tome.WizY.GetComponent<BaseObjectData>().floorID += addID;
}
}
else
{
gameManager.SetErrorMessage("Either of players need to hold the tome to teleport it!");
}
}
}
}
else
{
gameManager.SetErrorMessage("Something is blocking the portal exit!");
}
}
}
}
A function that handles everything about sending colliding objects to the coordinates of the linkedGate.
if (linkedGate != null)
{
if (checkObjectColliding(transform.position))
{
The whole script won't function if the linkedGate is still missing and none of the objects collide with the Raycast in the checkObjectColliding().
Vector3 teleportCoordinate = new Vector3(linkedGate.position.x, collidingObject.transform.position.y, linkedGate.position.z);
int addID;
if (!isStartGate)
{
addID = 1;
}
else
{
addID = -1;
}
This section of the function is about initializing some important variables.
The Vector3 value teleportCoordinate will be the position of the colliding objects after the teleportation.
The integer addID becomes positive or negative of 1 depending on whether the Gate is the start or exit gate.
if (!linkedGate.GetComponent<Gate>().checkObjectColliding(linkedGate.transform.position))
{
if (collidingObject.tag == "Player")
{
if (hasUnlocked || isStartGate)
{
collidingObject.transform.position = teleportCoordinate;
collidingObject.GetComponent<BaseObjectData>().floorID += addID;
// collidingObject.GetComponent<gridBasedMovement>().isGrabbingBook = false;
collidingObject.GetComponent<Action_Grab>().ReleaseObject();
}
else
{
gameManager.SetErrorMessage("You need to bring the tome to activate the Gate!");
}
}
This and the next section of the function won't run if there's an obstacle on the other side of the gate.
If the tag of the collidingObject is "Player" and if the gate is unlocked or is a start gate, it sets the character's global position to the teleportCoordinate which is set at the start of the function.
The floor ID of the character is either incremented or decremented depending on whether the gate is the start or exit gate.
If the character is grabbing anything, they are forced to drop the object since they cannot bring the object to the other floor yet.
if (isStartGate)
{
gameManager.SetErrorMessage("You can't send the Tome to previous floor!");
}
else
{
Tome tome = collidingObject.GetComponent<Tome>();
if (tome.isWizXHolding || tome.isWizYHolding)
{
// Debug.Log("Press Enter to Teleport Book and Player");
if (tome.isWizXHolding && tome.isWizYHolding)
{
// Debug.Log("Press Enter to Teleport Book and Both Players");
}
hasUnlocked = true;
The Tome is unable to be teleported from the start gate because the players cannot send the Tome to the previous floor.
Also, the Tome needs to be carried by at least either of the player characters.
An error message will show up via GameManager.cs for not meeting those expectations.
if (!gameManager.invertTeleportation)
{
if (transform.parent.eulerAngles.y == 90)
{
if (tome.WizXDistance.x != 0 || tome.WizYDistance.x != 0)
{
teleportCoordinate += Vector3.right;
}
}
else if (transform.eulerAngles.y == 0)
{
if (tome.WizXDistance.z != 0 || tome.WizYDistance.z != 0)
{
teleportCoordinate += Vector3.down;
}
}
else if (transform.eulerAngles.y == 180)
{
if (tome.WizXDistance.z != 0 || tome.WizYDistance.z != 0)
{
teleportCoordinate += Vector3.up;
}
}
}
collidingObject.transform.position = teleportCoordinate;
collidingObject.GetComponent<BaseObjectData>().floorID += addID;
Setting a boolean invertTeleportation in the GameManager to true will invert the formation of the Tome and carrying characters when they are teleported (e.g. If the player character is at the left side of the Tome, it's at the right side after teleportation).
If invertTeleportation is false, and the carrying player character is behind the Tome, the Tome needs to be teleported at 1 tile further from the corresponding gate to fit the player character too.
If the Gate is on the right wall, the Tome moves by 1 step right. (There is no option for the left wall because the Tome cannot go back to previous floors)
If the Gate is on the top wall, the Tome moves by 1 step backwards, and 1 step forward if the Gate is on the bottom wall.
After everything, The Tome is sent to the world position of teleportCoordinate, and its floor ID is incremented.
if (tome.isWizXHolding)
{
float origWizHeight = tome.WizX.position.y;
tome.WizX.position = teleportCoordinate - tome.WizXDistance;
tome.WizX.position = new Vector3(tome.WizX.position.x, origWizHeight, tome.WizX.position.z);
if (gameManager.invertTeleportation)
{
tome.WizX.eulerAngles += Vector3.up * 180;
}
tome.WizX.GetComponent<BaseObjectData>().floorID += addID;
}
if (tome.isWizYHolding)
{
float origWizHeight = tome.WizY.position.y;
tome.WizY.position = teleportCoordinate - tome.WizYDistance;
tome.WizY.position = new Vector3(tome.WizY.position.x, origWizHeight, tome.WizY.position.z);
if (gameManager.invertTeleportation)
{
tome.WizY.eulerAngles += Vector3.up * 180;
}
tome.WizY.GetComponent<BaseObjectData>().floorID += addID;
}
The player characters who are carrying the Tome need to be teleported altogether.
Their teleportCoordinate is subtracted by the vector distance between the player and the Tome, except for the y-axis of the position which remains the same.
If the invertTeleportation is true, they also rotate in 180 degrees.
Finally, the floor ID of them is also incremented by 1.
}
else
{
gameManager.SetErrorMessage("Either of players need to hold the tome to teleport it!");
}
}
}
}
else
{
gameManager.SetErrorMessage("Something is blocking the portal exit!");
}
}
}
}
}
The rest of the function requests GameManager.cs to generate error messages when something goes wrong and needs a brief description of the error.
In this current build, only the player character and Tome can use the Gate. However, if there's an idea to add enemies who can travel through floors, the script will be compatible with NPC characters as well. Furthermore, the variables or functions to handle animation and effects of the Gate will be added in the Gate.cs. Finally, when the Tome is carried by both player characters, the player should have the option to select which player character to be teleported or left on the floor.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Gate : MonoBehaviour
{
public bool isStartGate;
private Transform linkedGate;
private GameObject collidingObject;
private GameManager gameManager;
private bool hasUnlocked;
[Range(0, 2)] public int id;
void Start()
{
GameObject[] gates = GameObject.FindGameObjectsWithTag("Gate");
foreach (GameObject gate in gates)
{
if (gate.GetComponent<Gate>().id == id)
{
if (gate.name != gameObject.name)
{
linkedGate = gate.transform;
break;
}
}
}
if (linkedGate == null)
{
Debug.Log("Linked Gate with id " + id + " not found");
}
gameManager = GameObject.FindObjectOfType<GameManager>().GetComponent<GameManager>();
Debug.Log(transform.parent.eulerAngles.y);
}
public Transform GetLinkedGate()
{
return linkedGate;
}
private bool checkObjectColliding(Vector3 pos)
{
RaycastHit hit = new RaycastHit();
Debug.DrawRay(pos, Vector3.up * 1.25f, Color.green);
if (Physics.Raycast(pos, Vector3.up, out hit, 1.25f))
{
Debug.DrawRay(pos, Vector3.up * 1.25f, Color.blue);
collidingObject = hit.collider.gameObject;
return true;
}
return false;
}
public void TeleportObject()
{
if (linkedGate != null)
{
if (checkObjectColliding(transform.position))
{
Vector3 teleportCoordinate = new Vector3(linkedGate.position.x, collidingObject.transform.position.y, linkedGate.position.z);
int addID;
if (!isStartGate)
{
addID = 1;
}
else
{
addID = -1;
}
if (!linkedGate.GetComponent<Gate>().checkObjectColliding(linkedGate.transform.position))
{
if (collidingObject.tag == "Player")
{
if (hasUnlocked || isStartGate)
{
collidingObject.transform.position = teleportCoordinate;
collidingObject.GetComponent<BaseObjectData>().floorID += addID;
// collidingObject.GetComponent<gridBasedMovement>().isGrabbingBook = false;
collidingObject.GetComponent<Action_Grab>().ReleaseObject();
}
else
{
gameManager.SetErrorMessage("You need to bring the tome to activate the Gate!");
}
}
if (collidingObject.tag == "Book")
{
if (isStartGate)
{
gameManager.SetErrorMessage("You can't send the Tome to previous floor!");
}
else
{
Tome tome = collidingObject.GetComponent<Tome>();
if (tome.isWizXHolding || tome.isWizYHolding)
{
// Debug.Log("Press Enter to Teleport Book and Player");
if (tome.isWizXHolding && tome.isWizYHolding)
{
// Debug.Log("Press Enter to Teleport Book and Both Players");
}
hasUnlocked = true;
if (!gameManager.invertTeleportation)
{
if (transform.parent.eulerAngles.y == 90)
{
if (tome.WizXDistance.x != 0 || tome.WizYDistance.x != 0)
{
teleportCoordinate += Vector3.right;
}
}
else if (transform.eulerAngles.y == 0)
{
if (tome.WizXDistance.z != 0 || tome.WizYDistance.z != 0)
{
teleportCoordinate += Vector3.down;
}
}
else if (transform.eulerAngles.y == 180)
{
if (tome.WizXDistance.z != 0 || tome.WizYDistance.z != 0)
{
teleportCoordinate += Vector3.up;
}
}
}
collidingObject.transform.position = teleportCoordinate;
collidingObject.GetComponent<BaseObjectData>().floorID += addID;
if (tome.isWizXHolding)
{
float origWizHeight = tome.WizX.position.y;
tome.WizX.position = teleportCoordinate - tome.WizXDistance;
tome.WizX.position = new Vector3(tome.WizX.position.x, origWizHeight, tome.WizX.position.z);
if (gameManager.invertTeleportation)
{
tome.WizX.eulerAngles += Vector3.up * 180;
}
tome.WizX.GetComponent<BaseObjectData>().floorID += addID;
}
if (tome.isWizYHolding)
{
float origWizHeight = tome.WizY.position.y;
tome.WizY.position = teleportCoordinate - tome.WizYDistance;
tome.WizY.position = new Vector3(tome.WizY.position.x, origWizHeight, tome.WizY.position.z);
if (gameManager.invertTeleportation)
{
tome.WizY.eulerAngles += Vector3.up * 180;
}
tome.WizY.GetComponent<BaseObjectData>().floorID += addID;
}
}
else
{
gameManager.SetErrorMessage("Either of players need to hold the tome to teleport it!");
}
}
}
}
else
{
gameManager.SetErrorMessage("Something is blocking the portal exit!");
}
}
}
}
}