# 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]]