Closed RotX18 closed 2 years ago
Requirements for grid:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Class for every grid element
/// </summary>
public class GridElement : MonoBehaviour {
#region PRIVATE VARS
private int _id;
private float _posX;
private float _posY;
#endregion
#region PROPERTIES
public int ID {
get {
return _id;
}
set {
_id = value;
}
}
public float GridX {
get {
return _posX;
}
set {
_posX = value;
}
}
public float GridY {
get {
return _posY;
}
set {
_posY = value;
}
}
#endregion
}
Description:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Spawner for the grid that takes in a prefab and instantiates
/// it according to the given dimensions of the desired grid
/// </summary>
public class GridSpawner : MonoBehaviour
{
[Header("Object to be instantiated")]
public GameObject gridElement;
[Header("Grid size of lenX * lenY")]
public int lenX;
public int lenY;
[Header("X-axis spacing of spaceX, Y-axis spacing of spaceY")]
public float spaceX;
public float spaceY;
private void Start() {
for(int i = 0; i < lenY; i++){
//for each column
for(int j = 0; j < lenX; j++){
//for each row in each column
//instantiating each cube with space inbetween
Instantiate(gridElement, new Vector3(transform.position.x + j + (j * spaceX), transform.position.y + i + (i * spaceY), transform.position.z), Quaternion.identity);
}
}
}
}
Description:
[^spaceCalc]: [j + (j spaceX)] and [i + (i spaceY)] are due to the fact that we are instantiating relative to the spawner and NOT the previous cube; We are doing (iterationNumber) * (number of spaces between first and current cube)
Improvements made include:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Class for every grid element
/// </summary>
public class GridElement : MonoBehaviour {
#region PRIVATE VARS
private float _posX;
private float _posY;
private int _id;
#endregion
#region PROPERTIES
public float GridX {
get {
return _posX;
}
set {
_posX = value;
}
}
public float GridY {
get {
return _posY;
}
set {
_posY = value;
}
}
public int ID {
get {
return _id;
}
set {
_id = value;
}
}
#endregion
}
Edit:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Spawner for the grid that takes in a prefab and instantiates
/// it according to the given dimensions of the desired grid
/// </summary>
public class GridSpawner : MonoBehaviour
{
#region PUBLIC VARS
//grid element that will be instantiated
[Header("Object to be instantiated as elements of the grid")]
public GameObject gridElement;
//grid dimensions, lenX units by lenY units
[Header("Grid size of lenX * lenY")]
[Min(1)]
public int lenX;
[Min(1)]
public int lenY;
//spacing between each element along the X and Y axis
[Header("X-axis spacing of spaceX, Y-axis spacing of spaceY")]
[Min(0)]
public float spaceX;
[Min(0)]
public float spaceY;
#endregion
#region PRIVATE VARS
private GameObject _instantiatedObj;
#endregion
private void Start() {
for(int i = 0; i < lenY; i++){
//for each column
for(int j = 0; j < lenX; j++){
//for each row in each column
//instantiating each gridElement with space inbetween
_instantiatedObj = Instantiate(gridElement, new Vector3(transform.position.x + j + (j * spaceX), transform.position.y + i + (i * spaceY), transform.position.z), Quaternion.identity);
//setting the X and Y position for the instantiated ibject
_instantiatedObj.GetComponent<GridElement>().GridX = j;
_instantiatedObj.GetComponent<GridElement>().GridY = i;
//converting the gridX and gridY to strings, concatenating and converting value back to int and storing it as the ID
//eg. if one of the obj is at position (1, 2), its id would be 12
string idString = j.ToString() + i.ToString();
_instantiatedObj.GetComponent<GridElement>().ID = int.Parse(idString);
//setting the instantiated object as a child of the spawner
_instantiatedObj.transform.parent = gameObject.transform;
}
}
}
public GameObject FindElementByID(int id){
//getting all GridElement components from spawner's children
GridElement[] children;
children = gameObject.transform.GetComponentsInChildren<GridElement>();
//iterating through the children array to find first element that has the same id as the query id
foreach(GridElement ele in children){
if(ele.ID == id){
//returning gameObject if id matches
return ele.gameObject;
}
else{
continue;
}
}
//returning null if none of the elements in children have the same id
return null;
}
}
Edits:
Added:
Changed:
[^id]: Example: Given an element at position (12, 34), its ID will be "12" + "34" = 1234 [^searchFunction]: Could possibly be computationally expensive
For now, all objectives have been completed, may reopen this issue again should there be improvements/enhancements added to it
Demonstration of Grid System:
All objectives complete, issue can now be closed (closed with commit c34fe37cd9dad4fb723d5b40816fe89b8e4e4e87)
I copy-pasted the MouseInput.cs script into PlayerInput.cs as the naming was more appropriate
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// This script gets the game object under the mouse position and changes it to different colours
/// </summary>
public class PlayerInput : MonoBehaviour {
#region PUBLIC VARS
//seletion vars
public GameObject pointerOrigin;
//grid vars
public GameObject gridSpawnerObj;
public GridManager gridManager;
#endregion
#region PRIVATE VARS
//selection vars
private Ray _pointerRay;
private RaycastHit _hit;
private GameObject _hitObj;
//grid vars
private List<GridElement> _elements = new();
private Dictionary<int, GridElement> _correctEles = new();
private Dictionary<int, GridElement> _wrongEles = new();
#endregion
private void Start() {
_elements = gridSpawnerObj.GetComponent<GridSpawner>().AllElements;
//sorting the elements in the grid to correct elements and wrong elements
foreach(GridElement ele in _elements) {
if(ele.Correct) {
_correctEles.Add(ele.ID, ele);
}
else {
_wrongEles.Add(ele.ID, ele);
}
}
}
private void Update() {
if(OVRInput.GetDown(OVRInput.Button.SecondaryIndexTrigger)) {
//when the right trigger is pressed
if(_hitObj != null) {
//if the raycast hit is not null
if(_hitObj.GetComponent<GridElement>().Clickable) {
//if the element is clickable
_hitObj.GetComponent<GridElement>().Clicked = true;
//checking whether the element is correct
if(_hitObj.GetComponent<GridElement>().Correct) {
//if element is correct, set the colour to green
_hitObj.GetComponent<Renderer>().material.color = Color.green;
}
else {
//if element is not correct, reset all current colours
gridManager.ResetGrid();
}
}
}
}
}
private void FixedUpdate() {
//casting from the main camera to the point on screen where the mouse is
_pointerRay = new Ray(pointerOrigin.transform.position, pointerOrigin.transform.forward);
if(Physics.Raycast(_pointerRay, out _hit)) {
//if the point where the player click contains a gameobject
_hitObj = _hit.transform.gameObject;
}
else {
_hitObj = null;
}
}
}
Edits:
Demonstration of changes:
Feature has been implemented, branches can now be merged
This simply involved adding 4 lines of code, changes as follows:
//degrees to rotate the entire grid by
[Header("Initial rotation of the grid")]
public float rotX = 0;
public float rotY = 0;
public float rotZ = 0;
private void Awake(){
//rotating the grid after all elements have spawned
transform.Rotate(new Vector3(rotX, rotY, rotZ));
}
Edits:
With all rotations set to 0 (default)
With rotations set with random values
Enhancement complete, issue will now be closed
Implemented the new IPuzzle interface into the grid system for better streamlining of code
public class GridManager : MonoBehaviour, IPuzzle
{
private int _totalCorrects = 0;
private int _clickedCorrects = 0;
public bool Completed {
get;
set;
} = false;
public void OnComplete(){
//ADD COMPLETED EFFECTS HERE
Debug.Log("GRID HAS BEEN COMPLETED");
}
private void Start() {
foreach(GridElement ele in _elements){
if(ele.Correct){
//keeping count the total number of correct elements
_totalCorrects++;
}
}
}
private void Update() {
//completed check
if(_clickedCorrects == _totalCorrects){
//if the number of clicked correct elements = total number of correct elements
Completed = true;
}
}
public void ResetGrid() {
_clickedCorrects = 0;
}
}
Edits:
Did not account for whether the raycast hit object had a GridElement component.
Add a check to test whether the hit object contained a GridElement component
if(_hitObj.GetComponent<GridElement>() != null){
//if the hit object has a GridElement component
//CODE HERE
}
Description:
Fixed issue with Grid throwing NullReferenceError when pressing right trigger
Did not check whether corrects were clicked before incrementing ClickedCorrects
Account for whether the correct being clicked has been clicked prior via GridElement.Clicked
//checking whether the element is correct
if(_hitObj.GetComponent<GridElement>().Correct) {
//if element is correct, set the colour to green
_hitObj.GetComponent<Renderer>().material.color = Color.green;
if(!_hitObj.GetComponent<GridElement>().Clicked){
//if the current object has not yet been clicked prior
gridManager.ClickedCorrects++;
_hitObj.GetComponent<GridElement>().Clicked = true;
}
}
Edits:
Bug has been fixed
Previously, all correct elements in a given row could be clicked in any order, with the grid progressing as long as all correct elements within that row were clicked. With this change, that is no longer the case, now even if the clicked element within the row is correct, if it is not the next element in the sequence, it will reset the entire grid.
Changes can be found in GridInput.cs
private int _intendedCorrectIndex = 0;
//CORRECT ELEMENT CHECK IN Update(); Start line 62
//get current correct's index in gridManager
int currentCorrectIndex = Array.IndexOf(gridManager.correctElementIDs, gridSpawner.FindElementByID(_hitObj.GetComponent<GridElement>().ID).GetComponent<GridElement>().ID);
//CLICKED ELEMENT CHECK FOUND IN Update(); Start line 70
//comparing the current correct's index to the next correct in sequence
if(currentCorrectIndex == _intendedCorrectIndex){
//if the currentCorrectIndex is the same as the _intendedCorrectIndex, increment _intendedCorrectIndex
_intendedCorrectIndex++;
}
else{
//if the currentCorrectIndex is not the next one in sequence, reset
gridManager.ResetGrid();
_intendedCorrectIndex = 0;
}
Edits:
_instantiatedObj = Instantiate(gridElement, new Vector3(transform.position.x + j + (j * (spaceX -(1-gridElement.transform.localScale.x))), transform.position.y + i + (i * (spaceY - (1 - gridElement.transform.localScale.y))), transform.position.z), Quaternion.identity);
Objective: Create a dynamic way of instantiating a grid of objects
Grid system should:
From #39: