Search Unity

UnityException: Transform child out of bounds PlayerScript.CreateAtStart (Int32 amount) (at Assets/W

Discussion in 'Scripting' started by incenseman, Jan 13, 2018.

  1. incenseman

    incenseman

    Joined:
    Nov 20, 2012
    Posts:
    90
    I cannot find anything on the forums that talk about this error specifically. I have tried changing some things but it does not fix this issue.

    CodeUnityException: Transform child out of bounds
    PlayerScript.CreateAtStart (Int32 amount) (at Assets/Walls/Scripts/PlayerScript.cs:297)
    PlayerScript.Start () (at Assets/Walls/Scripts/PlayerScript.cs:66)"

    Here is my script.

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine.UI;
    5. using UnityEngine.SceneManagement;
    6.  
    7. public class PlayerScript : MonoBehaviour {
    8.  
    9.     //this script controls most functions of the game
    10.     //handle game start animation
    11.     //it generates tiles and closes tiles
    12.     //calculates score
    13.     //decides when player dies
    14.  
    15.  
    16.     public GameObject xTilePrefab;
    17.     public GameObject yTilePrefab;
    18.  
    19.     public Transform contactPoint;
    20.     public LayerMask whatIsGround;
    21.     public GameObject ps;    //particle system for coin
    22.     public GameObject cam;    //main camera refrence
    23.     public float speed  ;    //ball speed
    24.  
    25.     public bool onXTile ;     //on which tile ball is
    26.     public bool onYTile ;
    27.     public bool generateTile;    //when to generate tile
    28.  
    29.     public Text scoreText;    //refrence for UI element
    30.     public GameObject startObj;
    31.     public Animator anim;        //UI animator
    32.     public Animator scoreAnim;    //when game ends because of zero score
    33.  
    34.     //for storing active X and Y tiles
    35.     public List<GameObject> currentTileX;
    36.     public List<GameObject> currentTileY;
    37.  
    38.     //storing inactive X and Y tiles
    39.  
    40.     public List<GameObject> recycledTileX ;
    41.     public     List<GameObject> recycledTileY ;
    42.  
    43.     //list of all audio assets
    44.     public AudioClip [] audios;
    45.  
    46.  
    47.     Vector3 dir ;
    48.     bool camMoved;
    49.     public int score;
    50.     bool restart;
    51.     bool gmStarted;
    52.     float tileGenerateSpeed;
    53.     List<GameObject> closeAnimX;
    54.     List <GameObject> closeAnimY;
    55.  
    56.  
    57.  
    58.     void Awake(){
    59.         CreateTiles (30);
    60.  
    61.     }
    62.  
    63.     void Start () {
    64.  
    65.         gmStarted = false;
    66.         CreateAtStart (10);
    67.         generateTile = true;
    68.         scoreText.text = "SCORE : " + score;
    69.         restart = true;
    70.  
    71.         closeAnimX = new List<GameObject>();
    72.         closeAnimY = new List<GameObject>();
    73.  
    74.  
    75.  
    76.     }
    77.  
    78.  
    79.     void FixedUpdate(){
    80.      
    81.         if (currentTileY.Count != 0 && currentTileX.Count != 0 && IsGrounded()&& !camMoved) {
    82.             CamFollow ();
    83.         }
    84.  
    85.         //translating ball
    86.         transform.Translate (dir * speed * Time .deltaTime);
    87.     }
    88.  
    89.     void Update () {
    90.  
    91.         //handeling mouse click and checking player is on ground(tile) or not
    92.             OnClickMouse ();
    93.             IsGrounded ();
    94.  
    95.         //if player is not on any tile or score gets zero
    96.         if (!IsGrounded () && restart || score < 0 && restart ) {
    97.             if(score < 0)
    98.                 scoreAnim.SetTrigger("Score0");
    99.          
    100.             StartCoroutine(PlayerDead());
    101.             restart = false;
    102.         }
    103.  
    104.     }
    105.     IEnumerator PlayerDead(){
    106.  
    107.         //managing sound
    108.         GetComponent<AudioSource> ().volume = 1;
    109.         GetComponent<AudioSource> ().pitch = 1;
    110.  
    111.         GetComponent<AudioSource>().clip = audios[5];
    112.         GetComponent<AudioSource>().Play();
    113.  
    114.         //when player is dead, restart the game after 2 seconds
    115.  
    116.         yield return new WaitForSeconds (2);
    117.  
    118.  
    119.         if (PlayerPrefs.GetInt ("GamePlayed", 0) >PlayerPrefs.GetInt("AD",30)) {
    120.  
    121.         }
    122.         //reload current scene
    123.         SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    124.  
    125.     }
    126.  
    127.     //changes ball speed when it touchs blocker on the tile
    128.     //reduces score every time it collides blocker
    129.     //decides on which tile ball is
    130.  
    131.     void OnTriggerEnter(Collider other){
    132.  
    133.  
    134.         if (other.CompareTag ("Block")) {
    135.  
    136.             //if ball trigers blocker, it changes ball direction and generates a number of new tiles which will be generaated
    137.             dir = -dir;
    138.             int randomTileNumber = Random.Range (5, 9);
    139.             ActivateTiles (randomTileNumber);
    140.  
    141.             //reducing score by 1
    142.             score--;
    143.  
    144.             if(score >= 0){
    145.             scoreText.text  = "SCORE : " + score;
    146.                 GetComponent<AudioSource> ().volume = 1;
    147.                 GetComponent<AudioSource> ().pitch = 1;
    148.  
    149.                 GetComponent<AudioSource>().clip = audios[1];
    150.                 GetComponent<AudioSource>().Play();
    151.             }
    152.  
    153.             //calculating on which tile ball is
    154.  
    155.         } else if (other.CompareTag ("XTile")) {
    156.             onYTile = false;
    157.             onXTile = true;
    158.         } else if (other.CompareTag ("YTile")) {
    159.             onXTile = false;
    160.             onYTile = true;
    161.         } else if (other.CompareTag ("Coin")) {
    162.  
    163.             score += 2;
    164.             Instantiate(ps,other.transform.position,other.transform.rotation);
    165.             other.gameObject.SetActive (false);
    166.             scoreText.text = "SCORE : " + score;
    167.             GetComponent<AudioSource> ().pitch = 1;
    168.  
    169.             GetComponent<AudioSource> ().volume = .5f;
    170.             GetComponent<AudioSource>().clip = audios[3];
    171.             GetComponent<AudioSource>().Play();
    172.         }
    173.     }
    174.  
    175.  
    176.     //handles mouse click, increases score by 5 on every click, changes direction of ball on mouse click
    177.  
    178.     void OnClickMouse(){
    179.  
    180.  
    181.         if (Input.GetMouseButtonDown (0) && IsGrounded() && score >= 0) {
    182.          
    183.  
    184.             if (!gmStarted) {
    185.              
    186.                 //handeling first click of game
    187.  
    188.                 GetComponent<Rigidbody> ().isKinematic = false;
    189.                 anim.SetTrigger ("GameStarted");
    190.  
    191.                 if (!anim.GetCurrentAnimatorStateInfo (0).IsName ("GameStarted"))
    192.              
    193.                 scoreText.gameObject.SetActive (true);
    194.                 gmStarted = true;
    195.                 GetComponent<AudioSource> ().pitch = 1;
    196.                 GetComponent<AudioSource> ().volume = 1;
    197.                 GetComponent<AudioSource> ().clip = audios [0];
    198.                 GetComponent<AudioSource> ().Play ();
    199.      
    200.             } else {
    201.                 GetComponent<AudioSource> ().pitch = 1.35f;
    202.                 GetComponent<AudioSource> ().volume = 1;
    203.                 GetComponent<AudioSource>().clip = audios[1];
    204.                 GetComponent<AudioSource>().Play();
    205.             }
    206.      
    207.  
    208.                 score += 5;
    209.              
    210.             scoreText.text = "SCORE : " + score;
    211.             generateTile = true;
    212.  
    213.             //changing ball direction on every click
    214.  
    215.             if (dir == Vector3.right || dir == -Vector3.right) {
    216.                 dir = Vector3.forward;
    217.             } else if (dir == Vector3.forward || -dir == Vector3.forward) {
    218.                 dir = -Vector3.right;
    219.             }else{
    220.                 dir = -Vector3.right;
    221.             }
    222.         }
    223.     }
    224.  
    225.     //hadels camera to follow the ball smoothly
    226.  
    227.     void CamFollow(){
    228.         GameObject tmp = null;
    229.  
    230.         if (onYTile && currentTileX.Count != 0) {
    231.  
    232.             //if ball is on Y Tile, giving a target to camera to follow
    233.             //you can try to change the target
    234.  
    235.             tmp = currentTileX[currentTileX.Count -1];
    236.  
    237.         }else if (onXTile && currentTileY.Count != 0) {
    238.  
    239.             tmp = currentTileY[currentTileY.Count - 1];
    240.  
    241.         }
    242.         Vector3 point = cam.GetComponent<Camera>().WorldToViewportPoint(tmp.transform.position);
    243.         Vector3 delta = tmp.transform.position - cam.GetComponent<Camera>().ViewportToWorldPoint(new Vector3(0.5f, 0.5f, point.z));
    244.         Vector3 destination = cam.transform.position + delta;
    245.         Vector3 velocity = Vector3.zero;
    246.         cam.transform.position =  Vector3.SmoothDamp(cam.transform.position, destination,ref velocity, .35f);
    247.  
    248.     }
    249.      
    250.     private bool IsGrounded(){
    251.  
    252.         //making a sphere at bottom of the ball and checking its collision to the tile
    253.  
    254.         Collider [] colliders = Physics.OverlapSphere (contactPoint.position, .3f, whatIsGround);
    255.         for(int i = 0; i<colliders.Length; i++){
    256.             if(colliders.gameObject != gameObject){
    257.  
    258.                 return true;
    259.             }
    260.         }
    261.  
    262.         return false;
    263.  
    264.     }
    265.  
    266.      
    267.     public void CreateTiles(int amount){
    268.  
    269.         //renaming all new tiles which we are going to generate
    270.  
    271.         for (int i = 0; i < amount; i++) {
    272.             recycledTileX.Add (Instantiate (xTilePrefab));
    273.  
    274.             //renaming last element of array
    275.             recycledTileX [recycledTileX.Count - 1].name = ("xTile");
    276.             recycledTileX [recycledTileX.Count - 1].SetActive (false);
    277.             recycledTileY.Add (Instantiate (yTilePrefab));
    278.             recycledTileY [recycledTileY.Count - 1].name = ("yTile");      
    279.             recycledTileY [recycledTileY.Count - 1].SetActive (false);
    280.         }
    281.     }
    282.  
    283.     void ManageSpeed(){
    284.         //generating new speed for ball, when it collides to blocker
    285.         //deviding by 4 so that we can get more variations in speed
    286.         speed = Random .Range (16, 44)/4;
    287.     }
    288.  
    289.     void CreateAtStart(int amount){
    290.         //this function creates given amount of tile when game starts
    291.  
    292.         for (int i = 0; i < amount ; i++){
    293.             GameObject tmp = recycledTileX[recycledTileX.Count-1];
    294.             recycledTileX.Remove(tmp );
    295.  
    296.  
    297.             tmp.transform.position = currentTileX[currentTileX.Count - 1].transform.GetChild(0).transform.GetChild (1).transform.position;
    298.             currentTileX .Add( tmp);
    299.  
    300.             int spawnPickUp = Random.Range (0, 10);
    301.  
    302.             if (spawnPickUp == 0) {
    303.                 currentTileX[currentTileX.Count - 1]. transform.GetChild(2).gameObject.SetActive(true);
    304.             }
    305.  
    306.             if(i == amount -1){
    307.                 tmp.transform.GetChild (1).gameObject.SetActive(true);
    308.             }
    309.         }
    310.         tileGenerateSpeed = .3f;
    311.         StartCoroutine(TileWakeUp());
    312.     }
    313.  
    314.     //this function genaarates new tiles when ball is on X tile or on Y tile
    315.     //plays animations for tile opening and closing
    316.     //hanles seperately, when it is on X or Y tile
    317.     //decides where to keep new blocker on tile
    318.  
    319.     public void ActivateTiles(int amount){
    320.         //if tile amount which we generated is not enough
    321.  
    322.         if (recycledTileX.Count < 15 || recycledTileY.Count < 15 ) {
    323.             CreateTiles(10);
    324.             Debug.Log ("generating extra 10 tiles");
    325.         }
    326.  
    327.         //when ball is on Y tile and ball is colliding to Y tile blocker first time
    328.  
    329.         if(onYTile && generateTile){
    330.  
    331.             //generating a new speed for ball
    332.             ManageSpeed();
    333.             if(currentTileX.Count != 0){
    334.                 if(currentTileX.Count != 0){
    335.                 for(int i = 0; i < currentTileX.Count; i++){
    336.  
    337.                         //deactivating previous tiles (X tiles because ball is on Y tile now)
    338.  
    339.                     if(currentTileX[currentTileX.Count - 1-i].transform.GetChild(1).gameObject.activeSelf){
    340.                         currentTileX[currentTileX.Count - 1-i].transform.GetChild(1).gameObject.SetActive(false);
    341.                     }
    342.                         //running tile close animation
    343.  
    344.                         closeAnimX.Add (currentTileX [currentTileX.Count - i - 1]);
    345.                 }
    346.  
    347.             }
    348.                 StartCoroutine (DeactivateXTile ());
    349.  
    350.                 //clearing currentTileX so that we can keep new X tiles in it
    351.                 currentTileX.Clear();
    352.             }
    353.             // choosing a random tile to activate blocker on tile
    354.  
    355.             int randomBlockNumber = Random.Range(0, currentTileY.Count -3);
    356.             int randomTileNumber = Random.Range(randomBlockNumber + 1, currentTileY.Count -1);
    357.  
    358.             //setting a random blocker active on tile
    359.             currentTileY[randomBlockNumber].transform.GetChild (1).gameObject.SetActive (true);
    360.             GameObject tmp = recycledTileX[recycledTileX.Count - 1];
    361.             recycledTileX.Remove (tmp);
    362.          
    363.             //setting a random Y tile position to  new X tile
    364.  
    365.             tmp.transform.position = currentTileY[randomTileNumber].transform.GetChild (0).transform.GetChild (1).transform.position;
    366.  
    367.             //adding that X tile to currentTileX
    368.             currentTileX.Add(tmp);
    369.  
    370.             for(int i = 0; i < amount; i++){
    371.                 tmp = recycledTileX[recycledTileX.Count - 1];
    372.                 recycledTileX.Remove (tmp);
    373.              
    374.                 //genarating new X tiles on next to last tile position
    375.  
    376.                 tmp.transform.position = currentTileX[currentTileX.Count - 1].transform.GetChild (0).transform.GetChild (1).transform.position;
    377.      
    378.                 currentTileX.Add(tmp);
    379.              
    380.                 if(i == amount-1){
    381.                     tmp.transform.GetChild (1).gameObject.SetActive (true);
    382.                 }
    383.  
    384.                 int spawnPickUp = Random.Range (0, 10);
    385.                 //setting a coin active if random number matches to zero for every tiles
    386.  
    387.                 if (spawnPickUp == 0) {
    388.                     currentTileX[currentTileX.Count - 1]. transform.GetChild(2).gameObject.SetActive(true);
    389.                 }
    390.             }
    391.             //running tile open animation
    392.  
    393.             StartCoroutine (WakeUpWOnY());
    394.             generateTile = false;
    395.             camMoved = false;
    396.         }
    397.  
    398.         //same as above, just at place of Y tile ball is on X tile
    399.  
    400.         if(onXTile && generateTile){
    401.  
    402.             //when ball is on X tile and ball is colliding to Y tile blocker first time
    403.             if(currentTileY.Count != 0){
    404.                 //generating a new speed for ball
    405.                 ManageSpeed();
    406.  
    407.                 for(int i = 0; i < currentTileY.Count; i++){
    408.  
    409.                     if(currentTileY.Count != 0){
    410.                     if(currentTileY[currentTileY.Count - 1-i].transform.GetChild(1).gameObject.activeSelf){
    411.                  
    412.                             //deactivating previous tiles (Y tiles because ball is on X tile now)
    413.                             currentTileY[currentTileY.Count - 1-i].transform.GetChild(1).gameObject.SetActive(false);
    414.                 }
    415.  
    416.              
    417.                         closeAnimY.Add (currentTileY [currentTileY.Count - i - 1]);
    418.                     }
    419.                 }
    420.                 StartCoroutine (DeactivateYTile ());
    421.  
    422.                 //clearing currentTileY so that we can keep new Y tiles in it
    423.                 currentTileY.Clear();
    424.             }
    425.  
    426.             // choosing a random tile to activate blocker on tile
    427.             int randomBlockNumber = Random.Range(0, currentTileX.Count -3);
    428.             int randomTileNumber = Random.Range(randomBlockNumber +1 , currentTileX.Count -1);
    429.             //setting a random blocker active on tile
    430.  
    431.             currentTileX[randomBlockNumber].transform.GetChild (1).gameObject.SetActive (true);
    432.             GameObject tmp = recycledTileY[recycledTileY.Count - 1];
    433.             recycledTileY.Remove (tmp);
    434.  
    435.             //setting a random X tile position to  new Y tile
    436.  
    437.             tmp.transform.position = currentTileX[randomTileNumber].transform.GetChild (0).transform.GetChild (0).transform.position;
    438.  
    439.             //adding that Y tile to currentTileY
    440.             currentTileY.Add(tmp);
    441.  
    442.             for(int i = 0; i < amount; i++){
    443.                 tmp = recycledTileY[recycledTileY.Count - 1];
    444.                 recycledTileY.Remove (tmp);
    445.          
    446.                 //genarating new X tiles on next to last tile position
    447.                 tmp.transform.position = currentTileY[currentTileY.Count - 1].transform.GetChild (0).transform.GetChild (0).transform.position;
    448.          
    449.                 currentTileY.Add(tmp);
    450.  
    451.                 if(i == amount-1){
    452.                     tmp.transform.GetChild (1).gameObject.SetActive (true);
    453.                 }
    454.                 int spawnPickUp = Random.Range (0, 10);
    455.              
    456.                 if (spawnPickUp == 0) {
    457.                     currentTileY[currentTileY.Count - 1]. transform.GetChild(2).gameObject.SetActive(true);
    458.                 }
    459.             }
    460.             tileGenerateSpeed = .3f;
    461.             StartCoroutine (WakeUpWOnX());
    462.             generateTile = false;
    463.             camMoved = false;
    464.         }
    465.     }
    466.  
    467.     IEnumerator DeactivateXTile(){
    468.         tileGenerateSpeed = .3f;
    469.  
    470.         //closing every tile by playing CloseTile animation
    471.  
    472.         if (closeAnimX.Count != 0) {
    473.             foreach(GameObject tile in closeAnimX) {
    474.  
    475.                 tile .GetComponent<Animator> ().SetTrigger ("CloseTile");
    476.  
    477.                 if (tileGenerateSpeed > .15f) {
    478.                     tileGenerateSpeed -= .1f;
    479.                     yield return new WaitForSeconds (tileGenerateSpeed);
    480.  
    481.                 } else{
    482.                     yield return new WaitForSeconds (tileGenerateSpeed);
    483.                 }
    484.                 recycledTileX.Add (tile);
    485.             }
    486.  
    487.  
    488.             closeAnimX.Clear ();
    489.         }
    490.     }
    491.     IEnumerator DeactivateYTile(){
    492.         tileGenerateSpeed = .3f;
    493.         if (closeAnimY.Count != 0) {
    494.  
    495.             //closing every tile by playing CloseTile animation
    496.  
    497.             foreach(GameObject tile in closeAnimY) {
    498.  
    499.                 tile .GetComponent<Animator> ().SetTrigger ("CloseTile");
    500.  
    501.                 if (tileGenerateSpeed > .15f) {
    502.                     tileGenerateSpeed -= .1f;
    503.                     yield return new WaitForSeconds (tileGenerateSpeed);
    504.  
    505.                 } else{
    506.                     yield return new WaitForSeconds (tileGenerateSpeed);
    507.                 }
    508.                 recycledTileY.Add (tile);
    509.             }
    510.  
    511.             closeAnimY.Clear ();
    512.         }
    513.     }
    514.  
    515.     IEnumerator WakeUpWOnX(){
    516.         //playing OpenTile animation for Y tile
    517.  
    518.         foreach (GameObject tile in currentTileY) {
    519.             tile.SetActive (true);
    520.                 tile.GetComponent<Animator>().SetTrigger ("OpenTile");
    521.  
    522.      
    523.         if (tileGenerateSpeed > .15f) {
    524.             tileGenerateSpeed -= .1f;
    525.             yield return new WaitForSeconds (tileGenerateSpeed);
    526.         } else{
    527.             yield return new WaitForSeconds (tileGenerateSpeed);
    528.         }
    529.  
    530.         }
    531.     }
    532.     IEnumerator WakeUpWOnY(){
    533.  
    534.         //playing OpenTile animation for X tile
    535.         foreach (GameObject tile in currentTileX) {
    536.             tile.SetActive (true);
    537.             tile.GetComponent<Animator>().SetTrigger ("OpenTile");
    538.      
    539.             if (tileGenerateSpeed > .15f) {
    540.                 tileGenerateSpeed -= .1f;
    541.                 yield return new WaitForSeconds (tileGenerateSpeed);
    542.             } else{
    543.                 yield return new WaitForSeconds (tileGenerateSpeed);
    544.             }
    545.          
    546.         }
    547.     }
    548.     IEnumerator TileWakeUp(){
    549.  
    550.         // handles tile open animation when game starts
    551.  
    552.         foreach (GameObject tile in currentTileX) {
    553.             tile.SetActive (true);
    554.      
    555.             tile.GetComponent<Animator>().SetTrigger ("OpenTile");
    556.  
    557.  
    558.  
    559.             if (tileGenerateSpeed > .15f) {
    560.                 tileGenerateSpeed -= .1f;
    561.                 yield return new WaitForSeconds (tileGenerateSpeed);
    562.             } else{
    563.                 yield return new WaitForSeconds (tileGenerateSpeed);
    564.             }
    565.          
    566.         }
    567.     }
    568.  
    569.  
    570.  
    571.  
    572.  
    573. }
    574.  
    575.  
     
    Last edited: Jan 13, 2018
  2. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Well, first off.. wow, glad I had this link still open in another tab!
    Please read this page for how to insert code properly on the forums: https://forum.unity.com/threads/using-code-tags-properly.143875/

    Next, please specify which line has the error based on the line # that will show up when you paste your code properly.
    Next, please do not paste 5,000 lines of code if 50 are sufficient. :) :)
     
  3. incenseman

    incenseman

    Joined:
    Nov 20, 2012
    Posts:
    90
    I will try to keep that in mind
    added the code tag
    As for the number of lines, I do not know what lines are causing the problem. Therefore logic demands that I post the entire script. If I post the wrong lines then I would not get the help I seek.
    I seldom post because I seldom need help.
    If anyone has any information on this I would be grateful.
     
    Last edited: Jan 13, 2018
  4. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Okay, I would check that those transform children exist? There's always a child, then at least 2 children on that child?
     
  5. incenseman

    incenseman

    Joined:
    Nov 20, 2012
    Posts:
    90
    I have checked for duplicate children and for children that are not where they should be.
    It all seems to be the way I last opened it in an older version of unity.
    I upgraded to the latest version and this is what I got when I opened it next.
     
  6. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Not sure what could be wrong. You can check each transform (instead of that long line of code) to ensure they're all valid & where it breaks?
     
  7. incenseman

    incenseman

    Joined:
    Nov 20, 2012
    Posts:
    90
    I am not sure what has changed from old version to new version of unity. Since it did work before, and now does not, I am lead to believe that something has changed with unity as I did not alter the script initially. That puts me at a disadvantage. For instance, I cannot seem to find a statement that is shorter than this one that does the same thing.
    Code (csharp):
    1.  
    2. [LIST=1]
    3. [*]tmp.transform.position = currentTileX[currentTileX.Count - 1].transform.GetChild(0).transform.GetChild (1).transform.position;
    4. [*]            currentTileX .Add( tmp);
    5. [/LIST]
    6.  
    I also cannot seem figure out an alternate for this statement.
    Code (csharp):
    1.  
    2. void CreateAtStart(int amount)
    3.  
    I can usually figure things out given time but this has really got me stumped. Because I do not devote a lot of time to working with it as I work much of the time. Short on time and understanding of this particular process. I have a feeling that I may need to simply start from scratch. Was just hoping to actually finish a game. Hobbies can be a cruel mistress. :)
     
    Last edited: Jan 13, 2018