How to swap cubemap when game environment changes - c#

I'm a unity newbie and need a little help...
I have two different environments the user can choose from. I have generated a cubemap for each environment. When the user switches environments, I need to swap out the cubemap being reflected in the scene. Here's some ideas:
Create 2 materials for all of the assets and assign the material at runtime, when the scene changes. The problem I have with this is these are large scenes with tons of assets. How would I go about doing this without having to go through every single object in the scene.
Find a way to re-assign the cubemaps dynamically when the user switches environments. Maybe loop through all scene materials looking for the presence of one cubemap, then replace it with the other.
Seems like that's all I can come up with, and I'm leaning towards #2. Just curious if it would cause a performance hit. Anyone have a better suggestion?

Using concept #2 above...
// replaces the reflection cubemap for the selected environment (garage or gallery)
public void setReflectionMaps(Cubemap cubeMap)
{
// get all of the mesh renderers
var renderers = truckGO.GetComponentsInChildren<Renderer>();
foreach (Renderer r in renderers) {
// get the material for each renderer
Material mat = r.sharedMaterial;
// check if the material has a cubemap
if (mat.HasProperty("_ReflectionMap")) {
// replace existing cubemap
mat.SetTexture("_ReflectionMap",cubeMap);
}
}
}

Related

Order of FindObjectsOfType method in Unity

I'm using the Method FindObjectsOfType inside Unity and I want to know what the order Unity find objects?
I tried to change the order of my game objects inside the hierarchy and even change the name of my game objects to 1_name, 2_otherName and still the list seems random.
Do it really random or there is an order for the search? There is no documentation about the order in the Unity website.
If someone really want, this is my relevent script:
[SerializeField] List<AreaMeshHandler> areaMeshHandlers;
void Awake()
{
areaMeshHandlers = FindObjectsOfType<AreaMeshHandler>(true).ToList();
}
Short answer, by InstanceID. can be seen on each GameObject in debug mode.
Tested by running this code in a scene with multiple GameObjects (some in hierarchy)
foreach (Target t in FindObjectsOfType<Target>())
Debug.Log($"{t.name}: {t.GetInstanceID()}");

How to find a GameObjects Prefab during runtime with Unity version 2018.3

After updating to Unity 2018.3.0f2 I`m unable to find a GameObjects prefab while the game is running. In the previous versions i was simply using this line:
GameObject prefabObject =
PrefabUtility.GetCorrespondingObjectFromSource(gameObject);
But after the update this function only returns null, so I tried the new functions:
PrefabUtility.GetPrefabInstanceHandle
PrefabUtility.GetNearestPrefabInstanceRoot
PrefabUtility.GetOutermostPrefabInstanceRoot
but all of them return null but I`m sure that I am handing a prefab over as parameter. Any ideas what I am doing wrong here?
As soon as editor start playing (Application.isPlaying=true) prefab linkage with scene game objects will be broken (blue game objects turned into gray) and thus you cannot obtain prefab related information from it.
If you really need a scenario were you want to access such information on runtime, you should save it as Serialized variable in script component so that it will later available on runtime.
For example: this is a simplified contraption of what Mirror (Unity network plugin) is doing by issuing asset ID related stuff to help distinguish each prefab to spawn things in network on runtime.
[SerializeField] string m_AssetId;
void OnValidate() // Which will be called on build or editor play
{
#if UNITY_EDITOR
// Deposit UnityEditor API dependent into some field
m_AssetId = UnityEditor.AssetDatabase.GetAssetPath( gameObject );
#endif
}
Anyway, for running editor script, if you want to test or look for original prefab. UnityEditor.PrefabUtility is somewhat hard to find a full example of how to use them.
You can refer to my git repository on how to use them with examples.
https://github.com/wappenull/UnityPrefabTester

Unity 5 - Multiple Materials: Sprite Textures

I'm wondering if there's a way to use multiple textures on a single game object but only keep one active at a time. Maybe use of setActive(true/false)? I've been browsing around multiple forums and even Unity handbook but seen nothing relevant to what I'm trying to achieve.
Here's the deal. I'm pretty deep into programming at this point in my game. I have a LOT of scripts, layers, code, hp bars and children, etc.. attached to my 2D character which is nothing more than some 3D shapes I threw together (Because I REALLY SUCK at graphic design). Anyway, I created a texture and turned it into a material then put it on my character. Honestly, when I started this project, I planned on using this as a test only object. However, I learned the hard way that this was not such a good idea because transferring over chars after development is a horrible plan! Anyway, I created another material of the character facing different directions in hopes of using materials as my sprites animation.
Is this possible?
Define these variables. Just f.y.i. this is inside my movement script.
public Material rgtFace; // Is actually left facing .. derp
public Material lftFace; // Is actually right facing herp ...
public GameObject player;
if (Input.GetKeyDown(KeyCode.A)) {
GetComponent<Renderer>().material = rgtFace;
}
if (Input.GetKeyDown(KeyCode.D))
{
GetComponent<Renderer>().material = lftFace;
}
}
Messed around and found the solution! Very simple code! Anyway, this case is closed :)

Unity 2D: Destroy + Instantiate new GameObject vs Changing state and sprite

I am creating prefabs for farmland in my 2D game. Since I want all ground tiles to turn into farmable-land when hit with a hoe, I am worried about performance (Since there will be hundreds of these GameObjects in a scene).
Would the best thing be to Destroy the ground tile and Instantiate a farm tile in it's position, or would it be better to create a more generic Script that is attached to every Ground tile(?), which has states like:
GROUND, FARMABLE, PLANTED
, then depending on the state I change behaviour and set a sprite like: tile.GetComponent<Image>().sprite = Resources.Load<Sprite>(pathToSprite);
Maybe I'm missing a better option but these are the ones I can think of.
Destroyin and instantiating hundreds of game objects during runtime is a recipe for disaster, memory fragmentation and GC going wild which will kill performance.
The second solution is way better. Use an enum for all the possible states of a tile in your game logic, and then change the Sprite field of the Sprite Renderer component accordingly.
PSA: Don't use GetComponent and Resources.Load every time you need to change a sprite, get a reference to the Sprite Renderer component and to a Sprite[] array which contains all possible state images to use in Awake, and then use those references to change the sprite image when needed.
Edit: Answering your question in the comment.
Be sure that the Sprites are all in the Resources folder of your
project, they can be in a subfolder, i.e.: Resources/Sprites.
Check that the path string is correct, i.e. if the sprite asset is called Circle, and it's in the Resources/Sprites folder,
path must be "Sprites/Circle".
Code example:
public class MyClass : MonoBehaviour {
Sprite[] spritesArray = new Sprite[10];
void Awake() {
spritesArray[0] = Resources.Load<Sprite>("Sprites/Circle");
}
}
Try This:{ tile.GetComponent(/).sprite = Resources.Load(pathtosprite); }

Particle system behaviour different for game objects consisting of several gameobject components

I have a 2D game. I have game objects that are made of a singular shapes with colliders and some that are made out of several shapes and included in an empty game object to which I have added a character collider. All the game objects have particle systems added and the single shaped game objects work as expected and explode onCollision, the multi shaped objects do not.
The explosions work as expected when using Play On Awake and Looping to Test them, but they do not explode onCollision. I have tried putting the particle system on one of the shapes inside the outer game object and then it shows an error Missing Component System, trying to access particle system for x object, which makes sense.
Within each game Object C# class I have the following methods:
private void OnCollisionEnter(Collision coll)
{
Explode();
}
private void Explode()
{
var exp = GetComponent<ParticleSystem>();
exp.Play();
GetComponent<Renderer>().enabled = false;
Destroy(gameObject, exp.duration);
}
The bombs are set to a rate of 0, to go off in one burst.
I have tried searching and cannot find the missing information required when using particle systems in game objects that are made up from multiple 3D game object shapes.
What am I missing?
I sorted it out, there were a few issues created from not understanding what to do and creating hacks.
The first issue is the renderers were being created in the child objects, so it was better to get all the child objects and loop through these and then disable the renderer in each of these.
I also removed the character colliders, as this was not needed and used sphere colliders.
I then unchecked is kinematic,as this had been enabled to stop my gameobjects in the air from being kicked about, instead I added mass in the rigid body.
In the explode method I commented out removing the rendering visibility as this had interfered with the explosion:
private void Explode()
{
var exp = GetComponent<ParticleSystem>();
exp.Play();
//GetComponent<Renderer>().enabled = false;
Destroy(gameObject, exp.duration);
}
I also extended the particle system start lifetime to exceed the duration. To ensure the particles were visible when the object is destroyed.
I'm still needing to tweak the explosions, but this has made a huge dent for me.

Categories