# Space? > [!Info] Design Doc > ![[DESIGNS/SpaceGame/Space_GIF.gif]] ### Code ##### Metaphysics Controller ```cs using Unity.VisualScripting; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.Rendering.LookDev; using UnityEngine.SceneManagement; using UnityEngine.UI; //using static UnityEngine.Rendering.DebugUI; // AT START: Environment.y = 16; space panel off (onOff panel on); title panel on // Space Activate > Time Activate (Time On) > Subjectivity + Avatar falls public class MetaphysicsController : MonoBehaviour { [Header("UI")] // SPACE UI public GameObject spaceOnOff_Panel; public GameObject spaceInFinite_Panel; public Button[] spaceOnOff; // Off > On public Button[] spaceInFinite; // Finite > Infinite // TIME UI public GameObject timeOnOff_Panel; // includes title public GameObject timeInFinite_Panel; public Button[] timeOnOffArr; // Off > On public Button[] timeInFiniteArr; // Finite > Infinite // SUBJECT UI public GameObject subOnOff_Panel; // includes title public Button[] subOnOff_Arr; public GameObject agency_Panel; public Button[] agencyOnOff_Arr; public GameObject values_Panel; public Button[] valueOnOff_Arr; // SUBJECT UI [Header("Space")] public string loadingSceneName = "LoadingScene"; public GameObject environment; public GameObject borderL; public GameObject borderR; public float boundX_L; public float boundX_R; private bool spaceIsInfinite; [Header("Time")] private bool timeIs; public Sprite facelessSprite; public Sprite aliveSprite; public Sprite deadSprite; private bool timeStarted; private bool timeIsInfinite; [Header("Sun")] public GameObject sun; public Vector3 sunDirection = new Vector3(1, 1, 0); public Vector3 sunInitialPosition = new Vector3(-12, -25, 0); public float sunBoundX = 7; public float globalSpeed = 2f; [Header("Sky")] public SpriteRenderer skySR; public float skyLerpSpeed; public Color[] skyColour; private float skyT; [Header("Avatar")] public GameObject avatar; //public GameObject avatarBound_Left; //public GameObject avatarBound_Right; //public GameObject avatarPos; public float avatarSpeed = 4f; public float avatarJumpVelocity = 4f; public float stopBeforeBorder = 2f; public Rigidbody2D avatarRB; public SpriteRenderer avatarSR; private GameObject finiteDirection; [Header("Agency")] public GameObject[] jumpTriggers; public GameObject[] stopTriggers; public GameObject Controls_Panel; public bool hasJumped = false; private bool isSubject; private bool isAgent; [Header("Value")] public GameObject[] valuesArr; private ValueContr vScr; private void Start() { avatarSR = avatar.GetComponent<SpriteRenderer>(); } private void Update() { var kb = Keyboard.current; if (timeIs) MoveSkies(); if (timeIs && isSubject && !isAgent) { if (kb.aKey.isPressed || kb.leftArrowKey.isPressed) PlayerMoveLeft(); if (kb.dKey.isPressed || kb.rightArrowKey.isPressed) PlayerMoveRight(); if (kb.spaceKey.isPressed) PlayerJump(); } if (isAgent) AutomaticMovement(); if (spaceIsInfinite) WrapScreen(); //if (Input.GetKeyDown(KeyCode.A) || Input.GetKeyDown(KeyCode.LeftArrow)) // PlayerMoveLeft(); //if (Input.GetKeyDown(KeyCode.D) || Input.GetKeyDown(KeyCode.RightArrow)) // PlayerMoveRight(); } /// <summary> /// SPACE /// </summary> /// public void Space_On() { // Starts the scene spaceOnOff[1].interactable = false; spaceOnOff[0].interactable = true; spaceInFinite_Panel.SetActive(true); environment.AddComponent<Rigidbody2D>(); } public void Space_Off() { // Starts a coroutine that // Turns the scene spaceOnOff[0].interactable = false; spaceOnOff[1].interactable = true; SceneManager.LoadScene(loadingSceneName); } public void Space_Finite() { spaceIsInfinite = false; spaceInFinite[0].interactable = false; spaceInFinite[1].interactable = true; timeOnOff_Panel.SetActive(true); // Boundaries for agency-off (avatar is player-controlled) //borderL.SetActive(true); //borderR.SetActive(true); // ToDo // Constrains for agency: avatar jumps and stops, then jumps again } public void Space_Infinite() { spaceIsInfinite = true; spaceInFinite[1].interactable = false; spaceInFinite[0].interactable = true; timeOnOff_Panel.SetActive(true); } private void WrapScreen() // from Update { float avX = avatar.transform.position.x; if (avX >= boundX_R) avatar.transform.position = new Vector3 (boundX_L + 0.6f, avatar.transform.position.y, 0); else if (avX <= boundX_L) avatar.transform.position = new Vector3 (boundX_R - 0.6f, avatar.transform.position.y, 0); } /// <summary> /// TIME /// </summary> public void Time_On() { timeIs = true; // UI timeOnOffArr[1].interactable = false; timeOnOffArr[0].interactable = true; timeInFinite_Panel.SetActive(true); subOnOff_Panel.SetActive(true); Rigidbody2D envRB = environment.GetComponent<Rigidbody2D>(); //Destroy(envRB ); // Drops an avatar if (!timeStarted) { avatarRB.gravityScale = 1; timeStarted = true; } } public void Time_Off() { timeIs = false; // UI timeOnOffArr[0].interactable = false; timeOnOffArr[1].interactable = true; timeInFinite_Panel.SetActive(false); ResetSubject(); subOnOff_Panel.SetActive(false); // Turns an int to 0 // This int is a speed that movements in the scene are multuplied by // Removes the RigidBody && constrains the avatar } public void Time_Infinite() { timeIsInfinite = true; CheckValues(); // UI timeInFiniteArr[1].interactable= false; timeInFiniteArr[0].interactable = true; // Turns avatar alive if (isSubject) avatarSR.sprite = aliveSprite; } public void TimeFinite() { timeIsInfinite = false; CheckValues(); // UI timeInFiniteArr[1].interactable = true; timeInFiniteArr[0].interactable = false; // Kills the avatar if (isSubject) avatarSR.sprite = deadSprite; } /// <summary> /// SUBJECT /// </summary> public void SubjectOn() { isSubject = true; isAgent = true; avatar.GetComponent<AvatarHelper>().isAgent = true; foreach (GameObject trigger in jumpTriggers) trigger.SetActive(true); // UI subOnOff_Arr[0].interactable = true; subOnOff_Arr[1].interactable = false; // Give a face if (timeIsInfinite) avatarSR.sprite = aliveSprite; if (!timeIsInfinite) avatarSR.sprite = deadSprite; agency_Panel.SetActive(true); agencyOnOff_Arr[1].interactable = false; values_Panel.SetActive(true); valueOnOff_Arr[0].interactable = false; } public void SubjectOff() { isSubject = false; isAgent = true; // UI subOnOff_Arr[1].interactable = false; subOnOff_Arr[0].interactable = true; ResetSubject(); // turns OFF un-interactable } /// <summary> /// AGENCY /// </summary> /// public void Agency_On() { // Set the world's conditions isAgent = true; avatar.GetComponent<AvatarHelper>().isAgent = true; foreach (GameObject trigger in jumpTriggers) trigger.SetActive(true); foreach (GameObject trigger in stopTriggers) trigger.SetActive(true); // UI agencyOnOff_Arr[1].interactable = false; agencyOnOff_Arr[0].interactable = true; Controls_Panel.SetActive(false); // ToDo // Move left to right // If next to collider at the left foot -- move to x.1 before and jump (first up) } private void AutomaticMovement() // in Update on isAgent { if (spaceIsInfinite) { avatar.GetComponent<AvatarHelper>().isFiniteAutomatic = false; avatar.transform.position = Vector3.MoveTowards (avatar.transform.position, new Vector3(boundX_R + 10f, 0, 0), avatarSpeed * Time.deltaTime); } else if (!spaceIsInfinite) { avatar.GetComponent<AvatarHelper>().isFiniteAutomatic = true; //if (!agentDefinedDirection) //{ // // Decide where to go // //int directionIndex = Random.Range(0, 2); // //if (directionIndex == 0) finiteDirection = borderL; // //else finiteDirection = borderR; // finiteDirection = borderR; // agentDefinedDirection = true; //} //float avX = avatar.transform.position.x; //float directionX = finiteDirection.transform.position.x; //// To the RIGHT //avatar.transform.position = Vector3.MoveTowards // (avatar.transform.position, // new Vector3(directionX, 0, 0), // avatarSpeed * Time.deltaTime); //if ((directionX - avX) <= stopBeforeBorder) // finiteDirection = borderL; //else if ((directionX - avX) >= -stopBeforeBorder) // finiteDirection = borderR; } } public void Agency_Off() { isAgent = false; avatar.GetComponent<AvatarHelper>().isAgent = false; avatar.GetComponent<AvatarHelper>().isFiniteAutomatic = false; foreach (GameObject trigger in jumpTriggers) trigger.SetActive(false); foreach (GameObject trigger in stopTriggers) trigger.SetActive(false); // UI agencyOnOff_Arr[1].interactable = true; agencyOnOff_Arr[0].interactable = false; Controls_Panel.SetActive(true); } // From UI button and in Update for keyboard input public void PlayerMoveRight() { if (timeIs && !isAgent) { avatar.transform.Translate(Vector3.right * avatarSpeed * Time.deltaTime); //Controls_Panel.SetActive(false); } } public void PlayerMoveLeft() { if (timeIs && !isAgent) { avatar.transform.Translate(Vector3.left * avatarSpeed * Time.deltaTime); //Controls_Panel.SetActive(false); } } public void PlayerJump() { if (!hasJumped) { avatarRB.linearVelocity = new Vector3( avatarRB.linearVelocity.x, avatarJumpVelocity); hasJumped = true; } } // On Event triggers public void B_MoveRight() { InvokeRepeating("PlayerMoveRight", 0, 0.009f); } public void B_MoveLeft() { InvokeRepeating("PlayerMoveLeft", 0, 0.009f); } public void B_StopMovement() { CancelInvoke("PlayerMoveRight"); CancelInvoke("PlayerMoveLeft"); } /// <summary> /// VALUES /// </summary> public void Values_On() { // UI valueOnOff_Arr[0].interactable = true; valueOnOff_Arr[1].interactable = false; foreach (GameObject v in valuesArr) { v.SetActive(true); CheckValues(); } } public void Values_Off() { // UI valueOnOff_Arr[0].interactable = false; valueOnOff_Arr[1].interactable = true; // Remove values objects foreach (GameObject value in valuesArr) value.SetActive(false); } /// OBJECTS /// private void MoveSkies() { // SUN sun.transform.Translate(sunDirection * globalSpeed * Time.deltaTime); float sunCurX = sun.transform.position.x; float sunInitX = sunInitialPosition.x; if (sunCurX >= sunBoundX) { sun.transform.position = sunInitialPosition; sunCurX = sunInitX; } // SKY // Lerp between skyColour[0] & skyColour[1] with n speed skyT = Mathf.InverseLerp(sunInitX, sunBoundX, sunCurX); // 0..1 float cycle = 1f - Mathf.PingPong(skyT * 2f, 1f); // 1..0..1 skySR.color = Color.Lerp(skyColour[0], skyColour[1], cycle); // 0->1 using cycle } private void CheckValues() { if (valuesArr != null) { foreach (GameObject v in valuesArr) { if (timeIsInfinite) { vScr = v.GetComponent<ValueContr>(); vScr.avatarDead = false; } else if (!timeIsInfinite) { vScr = v.GetComponent<ValueContr>(); vScr.avatarDead = true; } } } } /// <summary> /// HELPERS /// </summary> private void ResetSubject() { subOnOff_Arr[0].interactable = false; subOnOff_Arr[1].interactable = true; foreach (Button b in agencyOnOff_Arr) b.interactable = true; foreach (Button b in valueOnOff_Arr) b.interactable = true; agency_Panel.SetActive(false); values_Panel.SetActive(false); Controls_Panel.SetActive(false); // Avatar isSubject = false; avatarSR.sprite = facelessSprite; isAgent = false; avatar.GetComponent<AvatarHelper>().isFiniteAutomatic = false; // ToDo // Remove values } } ``` ## Resource **Main palette reference**: https://www.color-hex.com/color-palette/71344 Blue (day sky): dde6f5 Blue (night sky): 8fa9d6 Red (dead avatar): D86A6A Lighter green (avatar): 80c395 Blue (darker -> lighter): `8fa9d6` -> `dde6f5` Purple (lighter): `d8a3d1` - [Values palette](https://coolors.co/palette/10002b-240046-3c096c-5a189a-7b2cbf-9d4edd-c77dff-e0aaff) - [Sun palette](https://coolors.co/palette/03071e-370617-6a040f-9d0208-d00000-dc2f02-e85d04-f48c06-faa307-ffba08) ## Logo ![[DESIGNS/SpaceGame/Space_Logo.png]]