Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How to set properties of an object that was created at runtime, at runtime...

Discussion in 'Scripting' started by charleshking, May 9, 2014.

  1. charleshking

    charleshking

    Joined:
    May 9, 2014
    Posts:
    3
    Please forgive the noobishness here: I'm new to Unity, C# and, indeed OOP in general, and I've experimented myself into a corner.

    I'm planning on playing with concepts like using perlin noise to generate a kind of pseudo-landscape of tiles and, later, using A* pathfinding to send some kind of entity navigating around it.

    For now, I've written a component (attached to an empty game object), which creates a grid of 'tiles'. I've also created a 'tile' class which consists of a flattened cube, with a plane on top, and various parameters which I hope to use later.

    What I'm stuck on, is how to access things like the colors of individual instances of the 'tile', or indeed parameters that I have set such as 'cost', and how to modify them at runtime (for example how to raise a 'tile' in the y axis, based on Mathf.perlinNoise, or to change the color of the 'plane' primitive in the tile object based on some other runtime-calculated value...

    Any guidance gratefully accepted!

    Grid.cs, attached to an empty gameObject

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. namespace Assets.Code
    6. {
    7.         public class Grid : MonoBehaviour
    8.         {
    9.                
    10.                 public Vector2 perlinOrigin = new Vector2 (24.2f, 11.8f);
    11.                 public float perlinPlaneScale = 1.65f;
    12.                 public float perlinHeightScale = 1.65f;
    13.                 public static int worldX = 50;
    14.                 public static int worldZ = 50;
    15.                 public static float gridScaleX = 2.2f;
    16.                 public static float gridScaleZ = 2.2f;
    17.                 public static Vector3 tileScale = new Vector3 (2.0f, 0.5f, 2.0f);
    18.                 Tile[,] worldGrid = new Tile[worldX, worldZ];
    19.  
    20.                 // Use this for initialization
    21.                 void Start ()
    22.                 {  
    23.                         for (int gridX = 0; gridX < worldX; gridX ++) {
    24.                                 for (int gridZ = 0; gridZ < worldZ; gridZ ++) {
    25.  
    26.                                         worldGrid [gridX, gridZ] = new Tile (new Vector2 (gridX, gridZ), tileScale, new Vector3 ((float)gridX * gridScaleX, 0f, (float)gridZ * gridScaleZ), Tile.GREY, Tile.WHITE, 1, true);
    27.  
    28.  
    29.                                 }
    30.                         }
    31.  
    32.                 }
    33.    
    34.                 // Update is called once per frame
    35.                 void Update ()
    36.                 {
    37.                         if (Input.GetKeyDown (KeyCode.W)) {
    38.                 gameObject.renderer.material.color = Color.red;
    39.                 Debug.Log ("Go Red!");
    40.                         }
    41.                         if (Input.GetKeyDown (KeyCode.X)) {
    42.                                 gameObject.renderer.material.color = Color.blue;
    43.                                 Debug.Log ("Go Blue!");
    44.                         }
    45.                         if (Input.GetKeyDown (KeyCode.C)) {
    46.                                 gameObject.renderer.material.color = Color.white;
    47.                                 Debug.Log ("Go White!");
    48.                         }
    49.                    
    50.                         if (Input.GetKeyDown (KeyCode.V)) {
    51.                                 gameObject.renderer.material.color = RandomColor ();
    52.                                 Debug.Log ("Go BANANAAANAAAAAS!");
    53.                         }
    54.  
    55.                 }
    56.  
    57.                 Color RandomColor ()
    58.                 {
    59.                         Random.seed = 54654;
    60.                         return new Color (Random.value, Random.value, Random.value);
    61.                 }
    62.  
    63.         }
    64. }
    65.  
    And the Tile class, Tile.cs

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. namespace Assets.Code
    6. {
    7.         public class Tile
    8.         {
    9.  
    10.                 public Vector2 ID;
    11.                 public int cost = 0;
    12.                 public bool walkable;
    13.  
    14.                 //tile colours
    15.                 public static Vector4 BLACK = new Vector4 (0.0f, 0.0f, 0.0f, 1);
    16.                 public static Vector4 WHITE = new Vector4 (1f, 1f, 1f, 1f);
    17.                 public static Vector4 GREY = new Vector4 (0.7f, 0.7f, 0.7f, 1f);
    18.                 public static Vector4 MEH = new Vector4 (0.624f, 0.124f, 0.354f, 0.02f);
    19.  
    20.                 public Tile (Vector2 ID, Vector3 scale, Vector3 position, Vector4 tileColor, Vector4 faceColor, int cost = 10, bool walkable = true)
    21.                 {
    22.                         GameObject tileBody = GameObject.CreatePrimitive (PrimitiveType.Cube);
    23.                         GameObject tileFace = GameObject.CreatePrimitive (PrimitiveType.Plane);
    24.                         tileBody.transform.localScale = scale;
    25.                         tileBody.transform.localPosition = position;
    26.                         tileBody.renderer.material.color = tileColor;
    27.                         tileFace.transform.localScale = scale / 11.0f;
    28.                         tileFace.transform.localPosition = new Vector3 (position [0], position [1]+0.26f, position [2]);
    29.                         tileFace.renderer.material.color = faceColor;
    30.  
    31.  
    32.                         //Debug.Log ("Tile() - " + ID + ", scale: " + scale + ", colour: " + tileColor + ", cost: " + cost);
    33.                 }
    34.  
    35.                 void ChangeColor (Vector4 tileColor, Vector4 faceColor) {
    36.             //this.tileBody.renderer.material.color = tileColor;
    37.             //this.tileFace.renderer.material.color = faceColor
    38.  
    39.                 }
    40.  
    41.         }
    42. }
    43.  
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    Well your Tile class is creating GameObjects (and isn't a part of a GameObject) on which you're setting these values. They exist in the world, but you haven't stored a reference to them.

    In your Tile class you should store a reference to that GameObject so you can get at it. This way if you have a reference to the Tile, you have a reference to its corresponding GameObject.

    Of course, if you wanted to fully embrace the component design pattern that Unity implements. I'd say that 'Tile' should actually be a component, and you create GameObjects and attach the Tile component to it. Then by default the Tile will have a reference to the gameObject, because all components have a reference to the GameObject it's attached to.

    This would mean though that your two primitives you created would need some association as well. I'd parent them in the GameObject this Tile component would be attached too. In which case we'd still need to store a reference to them on the Tile class... because they are separate GameObjects. Nice part here though is that if you move the parent GameObject that Tile is attached to, both child game objects get moved with it.
     
  3. novashot

    novashot

    Joined:
    Dec 12, 2009
    Posts:
    373
    can't you just say:
    Code (csharp):
    1.  
    2.  worldGrid [gridX, gridZ].cost = /*whatever*/;
    3.  worldGrid [gridX, gridZ].walkable = false;
    4.  
    since you are already storing the tile in the worldGrid array?
     
  4. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,398
    That's not really a good idea. You should use a quad, or better yet a Sprite. However, creating all of them results in an enormous number of separate objects (50 * 50 = 2500), which is also not the best idea.

    Another thing, use Color or Color32 for colors, not Vector4. Black, white, and grey are already built-in values for Color (but not "meh", which I have to say is a shocking oversight on Unity's part ;) ).

    --Eric
     
  5. charleshking

    charleshking

    Joined:
    May 9, 2014
    Posts:
    3
    That seems to make sense - how would I 'store a reference' to the gameObjects that I create, though? Like I said, noobish :)

    Are you suggesting that I create a gameObject for each 'tile', and then child objects for the cube and it's 'topping' (which will likely be a sprite or a quad, as Eric5h5 suggested, ... or even a texture.)? How would that look in code? Would it give me 'Tile' objects in my inspector, instead of a list of 'cubes' and 'planes', which is what I currently get?

    Thanks for the heads-up about quads/sprites and color32.

    I see that I'm generating a fair few objects, but if I'm ultimately planning on having a procedurally generated tile landscape on which I can then perform operations (like changing heights/colours/properties) at the individual tile level, what would be a better approach? (I'd actually hoped for rather larger terrains, 250x250 tiles for example.

    Cheers

    Charlie
     
  6. charleshking

    charleshking

    Joined:
    May 9, 2014
    Posts:
    3
    Just as a follow up.

    I've parked what I've been doing for the time being, and I'm going to go through this tutorial that I found: http://studentgamedev.blogspot.no/p/unity3d-c-voxel-and-procedural-mesh.html

    It seems to be well pitched to cover some of the subjects that I've hit here, as well as addressing Eric5h5's remarks about not generating thousands of seperate objects: the tutorial covers how to batch-convert many 'virtual' voxel objects into a mesh that only renders the visible surfaces...

    ...but it approached that rather complex concept from a suitable distance so as not to make the learning curve too steep.

    I'll let you know how I get on :)