Disable objects far away from player to make performance better

Hello guys, I am making a plataformer game and I was thinking, if the object (like an enemy) is too far away from the screen, there is no necessity to it execute any function like animate or move.

I am planning to create a game level that the player will need more than 6 minutes to go until the end. Therefore will be a lot of objects (scenario objects, enemies, traps, etc). So anyone know a good way to disable an object until the player enters in the object’s action radius.

For now, I am thinking to make a general script that uses a circle trigger collider, while the player is not inside of it, it will get all the components from the object(except this script component) and its children and disable then. What do you think? Thanks ;).

Maybe you can go the other way round. Instantiate the objects when player comes closer and destroy them when the player got away

Adding fog?

MarkusB: I was thinking in this too, but if I go closer enough to the enemy spawn and run away from it, the problem of extra processing will persist.

qiqete: My plataformer game is 2d, the camera range isn’t too large to need to use fog :stuck_out_tongue:

Split level in parts and activate / deactivate parts with triggers?

And if you run away, you destroy the object. You come closer again, you instantiate it new

LOL huge performance increase there…

You can create a huge collider around your player. Once enemies/objects come within range, you can instantiate them. So you could use a simple place holder such as a cube or a transform, once the collision happens, instantiate the enemy on that spot. You could pass in a prefab to the script on to this spawner object so it automatically spawns the correct prefab.

TheHoboCoder: I am thinking this as a last alternative, split the level in minor levels.

Meltdown: This idea is like what MarkusB said, maybe this can be a good idea. I am thinking about also let one script on each other object that only activates the others components of the object while it’s inside of the huge collider. Something like:

function OnTriggerEnter (other : Collider)
{
var sm : ScriptManager = other.gameObject.GetComponent( ScriptManager );
if( sm != null )
sm.setObjectsFunctional(true); // this function make all the components of this object and its children active
}
function OnTriggerExit (other : Collider)
{
var sm : ScriptManager = other.gameObject.GetComponent( ScriptManager );
if( sm != null )
sm.setObjectsFunctional(false); // this function disable all the components of this object and its children except the ScriptManger
}

What do you think?

This was a stupid post - removed - my official verdict is below haha!

You could add a script to the player, where he has a radius of the distance he can see objects.
In this case, if an object enters the radius, the script activate the object or render, whatever it is. When it comes out, turns off.

That’s help?

Well I think that the graphic part isn`t THE problem, since I can use the camera’s farClipPlane and etc. I am more bothered with the script processing like AI with objects that are too far away.

And about the cullDistances, what I read in the docs, it’s something like the farClipPlane, I don’t get how to use it instead of circle trigger colliders, can you give me a little example jsipich?

I would just do a

if(Vector3.distance( playTransform.position, thisEnemyTransform.position) > whatevs)
{

}

in the update loop

1 Like

eem I read somewhere that is better to let the unity’s trigger collider make the detection work than use square distance or other thing to do this. Anyone heard this too?

1 Like

I am stupid. I am facepalming myself as I type this.

I don’t know why but I read your post as “hiding” the entire object from view and not just “disabling” what that object (enemy, etc) does.

Yes - triggers would be the route I would use. I would create a bool that would turn the functions of the object on/off based on whether or not that trigger was collided.

Using an FPS like Resistance 2 for the PS3 as an example, the team created AI that would function differently based on distance from the player.

The closer you got to the enemy - the more advanced AI routines would run. Also - the AI routines would change based on wether or not that enemy was within view of the players FOV, as well.

This way enemies could still be “active” at further distances but not directly engaging the player. This was how they created massive battles with tons of enemies - the distance to the player was the driving factor for how advanced the AI routines were. This gave the “illusion” of pressure on the player.

1 Like

Use this method, from what I know that’s the common practics of doing it. just don’t do at level junks, use it per object. Once the user enters the trigger, just enable the renderer + all scripts

Have you tried using the built in Monobehaviour events?

(I’ve found that these are called when the object goes in out of the camera frustum, not the screen)

I think that some objects like torches need to be activated some seconds before become visible, otherwise you can see a torch turning on of the nothing, like something supernatural :stuck_out_tongue:

Well guys, I am trying to implement to trigger active area. But I am with a problem, when I want to get the scripts components I can only get the object itself, for example when i run this code with the dog enemy, it shows only “DogTop” on the debug log instead to show the 7 scrips that it has. Can some1 gimme a hand, i think that the problem could be in the lines 39-79 in the ProcessController.js

ProcessCoontroller (attach in everything that want to enable/disable):

#pragma strict



private var canProcess : boolean = true;

private var topParent : GameObject = null;



function Start()

{

	// Getting the root from this object

	topParent = transform.root.gameObject;

	setProcessing( false );

}



function setProcessing ( b : boolean ) 

{

	// Checking if need to change something

	if( canProcess == b )

		return;

	

	// JavaScript script is a MonoBehaviour, C# and boo need to make it explicitly

	var scripts : MonoBehaviour[] = topParent.GetComponents.<MonoBehaviour>( );

	

	

	// Changing all scripts from the object

	for( var script : MonoBehaviour in scripts )

	{

		Debug.Log( script.name + "top" );

		if( script.name != "ProcessController" )

		{

			script.enabled = b;

		}

	}

	

	// Getting all the children and doing the same

	for( var i : int = 0; i < topParent.transform.GetChildCount(); i++ )

	{

	    var t : Transform = topParent.transform.GetChild(i);

	    

	    var go : GameObject = t.gameObject;

	    

	    var scriptsChild : MonoBehaviour[] = go.GetComponents.<MonoBehaviour>( );

	   

		// Changing all scripts from the object

		for( var scriptChild : MonoBehaviour in scriptsChild )

		{

			Debug.Log( scriptChild.name + "child" );

			if( scriptChild.name != "ProcessController" )

			{

				scriptChild.enabled = b;

			}

		}

	}

	

	canProcess = b;

}

TriggerDetector (attach to some child with a trigger collider in the player):

function OnTriggerEnter (other : Collider) 
{
	var processControl : ProcessController = other.gameObject.GetComponent( ProcessController );
	if(  processControl != null )
	{
		processControl.setProcessing(true);
	}
}

function OnTriggerExit (other : Collider) 
{
	var processControl : ProcessController = other.gameObject.GetComponent( ProcessController );
	if( processControl != null )
	{
		processControl.setProcessing(false);
	}
}

Just use GetComponentsInChildren Method to get all scripts in the active object and all of it’s children.

It’s best to do this in Awake() and cache it in a member variable, so it doesn’t have big performance impact during the gameplay.

public class Blah : MonoBehaviour {
    private MonoBehaviour[] scripts;

    public void Awake() {
         scripts = GetComponentsInChildren<MonoBehaviour>();
    }
    
    // P.S. It's a pretty bad idea to call an variable 'b'
    public void SetProcessing(bool enable) {
        foreach(MonoBehaviour script in scripts) {
            script.enabled = enable;
        }
    }
}
1 Like

Oh thank you Tseng, I made this changes in my code, but now I am getting all the object and children objects names instead of the their scripts names, do you have any idea what is wrong?

#pragma strict

#pragma downcast



private var canProcess : boolean = true;

private var scripts : MonoBehaviour[]; 



function Start()

{

	var topParent : GameObject = transform.root.gameObject;



	// Getting the scripts

	scripts = topParent.GetComponentsInChildren.<MonoBehaviour>( );

	

	// Set it to false

	setProcessing( false );

}



function setProcessing ( bool : boolean ) 

{

	// Checking if need to change something

	if( canProcess == bool )

		return;

		

	// Changing all scripts from the object

	for( var script : MonoBehaviour in scripts )

	{

		Debug.Log( script.name + "top" );

		if( script.name != "ProcessController" )

		{

			script.enabled = bool;

		}

	}

	canProcess = bool;

}