0
\$\begingroup\$

I'm trying to make a set of tiles on the floor of my 3d world visible only when the Player is nearby them. This will work as single tile prefabs. Just not if I set them within an empty parent gameobject... which is what I really need, ideally, for the sake of game performance.

Once I put them inside the empty parent gameobject, OnTrigger stops working or even registering (debug.log doesn't show anything).

Does anyone know the correct way to access and switch the MeshRenderer on/off via OnTrigger (or OnCollision might be even better... I've tried and same issue) when I have a LevelManager that loads all my game objects at runtime? The Level Manager instantiates a prefab (clone), which has an empty gameobject that's holding the tiles as children?

Code I've tried and that's not working so far:

public class CubeVis : MonoBehaviour
{

    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {



    }

    private void OnTriggerEnter(Collider other)
    {
        Debug.Log("hit");
        if (other.gameObject.CompareTag("Cube"))
        {
            Debug.Log("hittt");
            //other.gameObject.GetComponentInParent<MeshRenderer>().enabled = true;
           // other.gameObject.GetComponentInChildren<MeshRenderer>().enabled = true;
            //other.gameObject.GetComponent<MeshRenderer>().enabled = true;


        }
    }

Inspector/Hierarchy info as requested:

enter image description here

The parent GameObject is loaded via World and Level Manager scripts

enter image description here

enter image description here

enter image description here

enter image description here

\$\endgroup\$
  • \$\begingroup\$ Can you show us the inspector and hierarchy setup of these tiles? \$\endgroup\$ – DMGregory Sep 8 '18 at 11:41
  • \$\begingroup\$ I don't see your cube object in the hierarchy. Is it spawned at runtime? If so, can you show us the spawning logic and what the hierarchy looks like when your cube is present & ready to be triggered? I also notice you have a Rigidbody on your cube object. Does it move? \$\endgroup\$ – DMGregory Sep 8 '18 at 12:59
  • \$\begingroup\$ I have given an answer, but a clearer description would be great. Especially of how your scene is setup, how objects (prefabs?) are loaded at runtime, and how the prefabs are structured. Are you perhaps losing some references in the prefabs? Are the objects you want to enable the same as the trigger you enter? \$\endgroup\$ – Morten Andersen Sep 8 '18 at 13:50
  • \$\begingroup\$ I don't think it's an issue with the object spawning but I'll upload an image of the hierarchy at runtime next. I can get the code to work with a single cube tile object and OnTriggerEnter/Exit to turn the meshrenderer on and off (i.e. make a cube tile that has been spawned at runtime via my WorldManager initially invisible, then visible when the Player collides with it, then invisible again when the Player leaves the trigger zone). \$\endgroup\$ – user117610 Sep 8 '18 at 13:55
  • \$\begingroup\$ I just can't get it to perform the same operation when I put the same cube tile object into an empty gameobject and try to access the meshrenderer component that way... because ideally I'd like to be able to put all the cube tiles I will need for the path the Player needs to follow under one prefab rather than have to instantiate each indi \$\endgroup\$ – user117610 Sep 8 '18 at 13:55
0
\$\begingroup\$

Based your newest comments, here's another suggestion for a solution to your problem.

The idea is that you use a OverlapSphere to find all colliders on a specific layer within a certain range. Then you can use the dot product between the direction the player is looking, and the direction towards the collider. Finally you sort these by the distance to the player (may not be necessary, do a test), and enable the mesh renderer.

TileManager.cs

Attach the script to the player, and assign a tag and layer to your tiles. See the screenshots.

using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class TileManager : MonoBehaviour
{
    public string tileTag;
    public LayerMask tileLayer;
    public float maxDistance = 50.0f;
    public int maxVisibleTiles = 3;

    private List<MeshRenderer> tileMeshRenderers = new List<MeshRenderer>();

    private void Start()
    {
        // find all game objects with the specified tag,
        // and save their mesh renderer in a list for later
        var tiles = GameObject.FindGameObjectsWithTag(tileTag);
        foreach (var tile in tiles)
        {
            tileMeshRenderers.Add(tile.transform.GetComponent<MeshRenderer>());
        }
    }

    private void Update()
    {
        // disable all mesh renderers
        foreach (var meshRenderer in tileMeshRenderers)
        {
            meshRenderer.enabled = false;
        }

        // find tiles within range
        var hits = Physics.OverlapSphere(transform.position, maxDistance, tileLayer);
        var visibleHits = new List<Collider>();

        // filter the hits
        foreach (var collider in hits)
        {
            // use dot product to check if the collider's pivot is within a 180 degree fov
            if (Vector3.Dot(transform.forward, collider.transform.position - transform.position) > 0)
            {
                visibleHits.Add(collider);
            }
        }

        // order the hits by the distance to the camera
        visibleHits = visibleHits.OrderBy(x => (x.transform.position - transform.position).sqrMagnitude).ToList();

        // enable the 3 closests mesh renderers
        var indices = visibleHits.Count > maxVisibleTiles ? maxVisibleTiles : visibleHits.Count;
        for (int i = 0; i < indices; i++)
        {
            visibleHits[i].GetComponent<MeshRenderer>().enabled = true;
        }
    }
}

Preview Player Tile

\$\endgroup\$
  • \$\begingroup\$ Thanks for taking the time to put that together. If I can't find a way to get the mesh renderers enabled, I'll have a go with this code. I'll need to find a way to modify it though because the tiles have invisible walls next to them to keep the player on a straight path... if I enable all the meshrenderers in a nearby range, the walls will be visible. It's important that they not be so that the player can see the landmarks around them. \$\endgroup\$ – user117610 Sep 8 '18 at 23:07
  • \$\begingroup\$ If you NEVER need to see the walls, but just use them for collision or triggering, then you can just remove the MeshRenderer component. But is what you want, that when a trigger is hit, all its children's mesh renderer should be enabled? Can you perhaps make a simplified version of your scene along with the minimum amount of code, and share that unity project here? It might be easier to understand, if I could see your scene... Sorry for not getting it ;) \$\endgroup\$ – Morten Andersen Sep 9 '18 at 18:40
1
\$\begingroup\$

Your description was a little confusing, but I gather that you want to enable one or more MeshRenderer components, when the player enters a trigger.

  1. First of all, make sure your player game object has a RigidBody and a Collider. Then assign some tag to your player - in my example I've used the Player tag.

  2. Then, your trigger object needs a Collider that has IsTrigger enabled (which I think you've done). There's no need to set a tag on the trigger box.

  3. Assign the sample script TriggerSample.cs to your trigger object, not the player. If the player now enters the trigger object, the MeshRenderer on the trigger object is enabled.

  4. If you want to enable other game objects in your scene, you can drag them into the array ObjectToEnableOnTrigger in the inspector on the trigger object.

I have attached screenshots of the scene hierarchy, the player (the slim cube) and the trigger object (the big cube).

TriggerSample.cs

using UnityEngine;


public class TriggerSample : MonoBehaviour
{
    // array of MeshRenderers - assign them in the inspector
    public MeshRenderer[] ObjectsToEnableOnTrigger;

    // place this on the object you want to enable
    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Player"))
        {
            // enable the MeshRenderer on THIS game object
            // this is the same as transform.GetComponent<>()
            // it is good practice to check for null
            var thisRenderer = GetComponent<MeshRenderer>();
            if (thisRenderer != null)
            {
                thisRenderer.enabled = true;
            }

            // this will enable all the MeshRenderers assigned in the inspector
            foreach (var meshRenderer in ObjectsToEnableOnTrigger)
            {
                meshRenderer.enabled = true;
            }
        }
    }
}

Preview

Hierarchy

Player

Trigger

\$\endgroup\$
  • \$\begingroup\$ I only want to have a single tile at a time visible to the player... i.e. the one nearest the player then have it return to being invisible once the player leaves the Trigger/Collider zone. All other need to remain invisible until the player approaches them. \$\endgroup\$ – user117610 Sep 8 '18 at 13:48
  • \$\begingroup\$ Then you probably want to add OnTriggerExit and just disable all the MeshRenderers again. \$\endgroup\$ – Morten Andersen Sep 8 '18 at 13:51
  • \$\begingroup\$ That works when I do it for a single cube tile object that isn't held under an empty gameobject parent... when I make the empty gameobject the parent of the cube tile, none of the collisions happen anymore. I think it's because I'm not correctly calling the meshrenderer under the parent empty gameobject but I don't know what code to use to correct that. \$\endgroup\$ – user117610 Sep 8 '18 at 13:58
  • \$\begingroup\$ To clarify, I need only the cube tiles directly in front of the player to display at any given time. So, ideally I'm trying to get the 3 cube tiles in front on my player to be visible when they are triggering them and none of the others until they are approached (i.e. only the 3 cube tiles near the player to be visible at any given moment). \$\endgroup\$ – user117610 Sep 8 '18 at 14:05
  • \$\begingroup\$ Can you post a screenshot of your game? Just to understand you correctly - do you only want the 3 closest tiles in front of the player to visible? Or just whatever 3 tiles are closest, even if they are behind the player? Is this a 2D or a 3D game? \$\endgroup\$ – Morten Andersen Sep 8 '18 at 14:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.