Unity C# group project for Ravensbourne University consisting of an entire class of Year 2 Game developers and Programmers (46 students) from February to March 2024
As this project was for a large group module, we had a total of 8 programmers working together to produce all the features and mechanics. While primarily i focused on developing the shadergraph i also devised one of the key mobility mechanics used in the game, the grapple hook.
This is the primary portion for my grapple hook script. When the player enters the grapple anchor's radius it enables the use of the hook, and when the player activates the hook it creates a spring joint between the player and the anchor to use the physics engine to control the movement, with the feel of the rope being dialed in using the behaviour variables. I also used a line renderer to create the hook visually and set the start and end points to the player and the anchor
//using late update to render the rope so that it does not lag behind the physics of the rope private void LateUpdate() { DrawRope(); } private void GrappleBegin() { if(grappleAnchor != Vector3.zero) //if the grapple point is not "Reset" { //Adds a springJoint component and connects it to the desired grappleAnchor joint = gameObject.AddComponent(); joint.autoConfigureConnectedAnchor = false; joint.connectedAnchor = grappleAnchor; //gets the distance between the player and the grapple-point float dist = Vector3.Distance(gameObject.transform.position, grappleAnchor); //distance the player can vary from grapple point joint.maxDistance = dist * ropeMaxScale; //smaller scale, the less it can stretch joint.minDistance = dist * ropeMinScale; //smaller scale, the less it can pull you in //setting the Variables for rope's behaviour joint.spring = ropeSpringyness; joint.damper = ropeDampen; joint.massScale = ropeMass; //amount of points the line render can render too for the rope lr.positionCount = 2; isGrappling = true; }
public class GrappleAnchor : MonoBehaviour { private GameObject enteredPlayer; //ref to the player that enters the area private GrappleHook hook; //ref to the GrappleHook script on the player private void OnTriggerEnter(Collider other) { //if the object that entered the area is a player and there isnt already a player inside the array if (other.tag == "Player" && enteredPlayer == null) { enteredPlayer = other.gameObject; hook = enteredPlayer.GetComponent(); //tells the player's grapple hook the location of the anchor and enables the hook hook.EnterGrappleRadius(gameObject.transform.position); } } private void OnTriggerExit(Collider other) { //to prevent issues if theres multiple players, only the player who initially entered can trigger the exit script if(other.tag == "Player" && other.gameObject == enteredPlayer) { //triggers the exit function in the player's script hook.ExitGrappleRadius(); //clears the references hook = null; enteredPlayer = null; } } }
The entire script for the anchor points. This script only stores references the player when they're within the trigger,
sending the location of the anchor to the player so that their grapple hook script can handle the physics of the game.
Its a simple and easy method for other developers to be able to quickly understand when it comes to building the levels.
For this project i was also responsible for creating a checkpoint and saving system for the game, so that players could keep their progress when they die or close the game
This was the first time i had experimented with saving systems, so for the most part i focused on saving essential data as a class in a text document.
The class contains the index number for the last checkpoint they were at, whether this is a fresh save-file and the amount of health the player has.
When the level is loaded, the SaveManager checks whether it is loading a new save file or a pre-existing one and spawns the player at the corresponding checkpoint/spawnpoint
and the player's data is saved every time they pass a new checkpoint to keep up with their progress. Whenever the player dies they are also respawned at the same checkpoint they would when
the game is launched based on their save-file.
using System.Collections; using System.Collections.Generic; using Unity.VisualScripting; using UnityEngine; using UnityEngine.SceneManagement; public class PlayerSettings { public int lastSavedPosition; //index of the last checkpoint the player hit public int playerHealth; public bool isNewGame = true; //initialised to true so that fresh saveData is always considered a new game. } public class SaveManager : MonoBehaviour { [SerializeField] private GameObject[] checkPoints; //list of checkpoints in the scene private GameObject player, //reference to the player startPos; //first child of GameManager, where the player spawns when they have no save data/saved checkpoints private PlayerSettings saveData = new PlayerSettings(); //creates a saveData type initialised to default settings private int currentCheckPoint; //current checkPoint the player is at in the level void Awake() { startPos = gameObject.transform.GetChild(0).gameObject; //gets the startPos from child player = GameObject.FindGameObjectWithTag("Player"); //gets a reference to the player in the scene LoadFromJson(); //runs the load function to check if there is save data and to set the player's position } private void Update() { //if the player wants to load the save if (Input.GetKeyDown(KeyCode.L)) { //reload the scene to re-run the "loadFromJson()" in awake SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex); } /if the player wants to clear a save if (Input.GetKeyDown(KeyCode.C)) / { //Creates a new PlayerSettings & Overwrites pre-existing save with new one saveData = new PlayerSettings(); SaveToJson(); } } //Saves the game data to a .json file private void SaveToJson() { //converts the saveData to a .json formatted string and saves it to the desired path string savDat = JsonUtility.ToJson(saveData); string filePath = Application.persistentDataPath + "/PlayerData.json"; Debug.Log(filePath); System.IO.File.WriteAllText(filePath, savDat); //writes the data to the file } private void LoadFromJson() { //locates the filepath of the saveData and saves it to a temporary string variable string filepath = Application.persistentDataPath + "/PlayerData.json"; string savDat = System.IO.File.ReadAllText(filepath); if(JsonUtility.FromJson(savDat) != null) { //converts from .json to PlayerSettings class and saves in in the saveData saveData = JsonUtility.FromJson (savDat); //checks if the loading save is from a new game if (!saveData.isNewGame) { //sets the players position to the last checkpoint player.transform.position = checkPoints[saveData.lastSavedPosition].transform.position; } else { //sends player to the start position player.transform.position = startPos.transform.position; } } else //if no saveData could be found, treats the game as loading from a fresh save { player.transform.position = startPos.transform.position; } } public void HitCheckPoint(GameObject checkPoint) { //compares index of checkpoints against the checkpoint the player hit for(int i = 0; i < checkPoints.Length; i++) { if (checkPoints[i].gameObject == checkPoint) { //sets the file's index number to the checkpoint the player hit saveData.lastSavedPosition = i; saveData.isNewGame = false; //saves the game SaveToJson(); } } } }