Development Style, what's best for Unity? Help

I’m going to give a very basic example here, but I really need to know this before I move forward professionally.

Design 1:

A character instantiates bullet prefabs and in a master “Game” GameObject, there is a script containing lists of projectiles that all projectiles are added to. There is a for loop that iterates over the array and tells every projectile to move forward, and after traveling for a few seconds they are destroyed. Something like…

GameObject tempVar = Destroy(Instantiate(prefab_reference), 5.0f);
game_projectiles.add(tempVar);

foreach(GameObject projectile in game_projectiles)
{
if(projectile == null)
{
game_projectiles.remove(projectiles); // I know that might not work on an iteration object, but you get the idea
}
projectile.transform.position += projectile.transform.forward;
}

Design 2:

A player instantiates a bullet prefab where each prefab contains a script that will be moving it forward for some duration and then remove it from the scene.

Please someone tell me which is better. Is it best to have each GameObject controlled by it’s own script (like 100 bullets running bullet scripts) or have all game objects added to lists to be managed by a master script (like 100 bullets added to a list and controlled by a for loop) ? I would like to know which is best for unity performance wise. It seems obvious to me with my experience so far that the fewer scripts running the better, but maybe there’s some background thread manager that handles better if each prefab handles itself instead of having minor pauses from moving every prefab in a loop that covers them all?

I’ve only been using Unity for around a year now but I’ve found that the more “Update” methods you have, the slower it will be - even if those Update methods are empty. Simply removing the Update method will improve performance.

I’d go with option 1.

Common sense prevails :smile:

I thought maybe there was some kind of thread handler with a master Update function that allocated space for every update function that we implement. So every time we instantiate something with a script it would be added to the master Update thread. I guess that’s a little bit of a pipe dream.

Well, thank you. I really needed to make a decision because option 2 would have been way easier now that I’m doing network stuff, but I’ll stick with option 1. It feels so misleading that so many tutorials make use of option 2 haha. Can anyone address that? Maybe someone who’s been using unity longer can clarify? I’ve also been using it for about a year.

There’s no reason option 2 couldn’t work with a little work though - What about using a Constant Force component? (that way you don’t need to set the transform every frame). And maybe there is some secret optimization/handler I don’t know about :slight_smile:

And now I have to question it again, thanks a lot lol.

For the time being I’ll just keep my games small and with option 1 since it is the more difficult 1. If it is ever answered (please within the next few hours / days!) it’ll be easier to make the switch from option 1 to option 2 than to go from the more intuitive option 2 to option 1.

Besides tutorials, even unity demo projects have prefabs with scripts all over the place!

I think I might do a hybrid option 3, in which all prefabs contain the functionality they need in script components, but no update function - they are called by a main world-update thread. Now the question is… will the existence of a 1000 prefabs with 1000 script components be significantly more overhead / performance hit / whatever than 1000 prefabs being referenced and manipulated by 1 script in a main thread. Something like a think script. Is it better to have

for(int i = 0;i < game_objects.Length;i++)
{
game_objects*.think();*
}
where each prefab has it’s own think script attached
or…
think(game_objects);
where think in the second case is defined in the world script in the second case, and the prefab is nothing more than models and animations.
Damn… even option 3 is unclear… fudge. If I’m going to be making “The World” from .hack//, the battles are going to be rather small, but for future projects I definitely need to know this lol. I know the performance in option 3 will be better than 2 (most likely), but is 1 still superior? Endless questions…
Option 1 (of the 3 now) got me to use 4000 animated models in an alien defense game in my project last semester.

Sorry :slight_smile:

In my experience, having more gameObjects with Update scripts is slower - but there may be some way around this problem that I don’t know about… Wouldn’t think so though.

Here’s what I’d try: (note - I haven’t tested this, so I don’t guarantee it’s the best/fastest approach but I’d expect it to work well based on my experience with Unity so far)

1 - Have a BulletManager script which maintains references to each of the bullets and does the spawning/disposing of bullets
2 - Use a Bullet script for each bullet, but do not use an Update method. The OnBulletStart method (which is called by BulletManager) sets the velocity of the ConstantForce component attached to the bullet, and calculates how long (in seconds) it will take to reach the required position. Use a coroutine to WaitForSeconds(x) then trigger BulletManager.DestroyBullet().

The BulletManager can pool bullets - so you reuse inactive bullets rather than instantiating new ones (which can hurt performance as well).

If you are worried about the performance of many projectiles, I would focus on object pooling before worrying about the updates.

Agreed. Watch a tutorial on Object Pooling here: https://www.youtube.com/watch?v=9-zDOJllPZ8

Will do. Thanks to everyone.

My primary concern at the moment is Network stuff and I am VERY new (like 2 days in). I’ve got a players instantiated on my machine and my second machine seeing each other move and being controlled correctly, but when I disconnected Network.DestroyPlayerObjects(NetworkPlayer) doesn’t cleanup the prefabs on anyone’s view (the clients or the server which I use the editor for to get a good scene view).

I want a way to get an ID for each player who joins and track all the objects created by some player with that ID. So far NetworkPlayer.guid is not helping. I managed to get the name of a player prefab to be the guid of the connecting player, but when I try to destroy it, it seems to just not destroy it. That is with my own attempts and with Network.DestroyPlayerObjects.

The only tutorial I’ve managed to find and follow is Gamer to Game Developer, but I’m stuck on destroying certain objects when a player disconnects and identifying specific players when they connect initially.

void OnPlayerDisconnect(NetworkPlayer player)
{
Network.RemoveRPCs(player);
Network.DestroyPlayerObjects(player);
}

I don’t know if the functionality of this has changed since 3.4 when the tutorial was made, but it’s not working for me. The Network.Instantiate call elsewhere has a group value of 0. If that’s related, please let me know. And someone please point me to a more up to date and complete multiplayer tutorial… I have learned quite a bit from what I’ve done so far but if I don’t get good style now I’ll probably damage my skills that will take time to undo.

Halp

Just did a quick test around my “Updates are bad” statement - A couple of hundred bullet components makes absolutely no difference according to the stats gizmo, it’s not until I start getting into the thousands that performance starts to be affected.
5,000 bullets: Without Update=0.8ms, With Update=4.1ms

So, I’d agree with the others in this case - focus more on object pooling :slight_smile:

For your network issue, is that your actual code? Try renaming OnPlayerDisconnect to “OnPlayerDisconnected”

I just reread that last line of yours, going back and forth between my code and what you posted until my eyes bled. YES. DAMNIT.

No wonder literally nothing worked (my attempts to do it manually, the built in stuff, etc)… the event to execute anything wasn’t being called ._.

Thanks for the other stuff. I’ll most likely go with Option 1 which from what I understand will be similar to object pooling. I’m never going to be working with more than like 12 monsters and 4-8 player network objects. I’m a hitscan kind of fellow when it comes to projectiles. That or a spread of bullets would be a single prefab and the distance of the player to the center of the spread would be more damage. I do everything I can to emulate actual calculations to optimize things.

But yea, thanks. Also, do you (or anyone else) have an opinion on the following?

Destroy(Instantiate(Resources.load(“someFolder/somePrefab”), location, position), 5.0f);

I used that in an RPC to have some placed objects disappear after 5 seconds, and it worked. The RPC created the objects on all devices and they were deleted after 5 seconds. I’ve been using that as my main way to have things like projectiles in a game so I don’t need to track time or distance traveled on all of them. Although I guess the engine is doing that with the second Destroy() parameter… but hopefully in a good way. I may test that myself later, but for now it just looks awesome.

–edit

Yep, it works now like it did in the tutorial. I guess next is to experiment with RPCs and immediately try to build a LAN multiplayer ARPG diablo clone. Any recommendations on when to use which RPC mode and when I should just Network.Instantiate something?

The tutorial I followed only showed Network.Instantiate for players and a regular instantiate called via RPC for things like projectiles. Should I do that Network.Instantiate for a specific kind of object? Should I be using RPC calls for specific kinds of objects?

I know enough practical information for the difference between a buffered and not buffered RPC call. I saw All for projectiles, AllBuffered for things like player movement. Is that information still the correct way to go about it? I could swear on some forum I saw a bunch of people say “Never use Network.Instantiate, always implement everything with RPC calls”. But that was back when Network.Destroy existed and Network.DestroyPlayerObjects did not.

Last question… if I want to make a change to the world permanent, is there a way to change ownership of an instantiated object so that it won’t be deleted by Network.DestroyPlayerObjects?

The important part of object pooling is to never use Instantiate() and Destroy() at all. That requires Unity to invoke the garbage collector, and because of licensing complications Unity’s GC is a bit dated. When it has to clean up objects like this (especially things like bullets that are constantly created and destroyed), you will periodically get frame rate stuttering. It becomes important with Unity to avoid any runtime allocations or deallocations of memory.

It’s not a difficult fix. Just create a pool of objects at runtime, deactivate them all, replace Instantiate() with Spawn() that grabs/initializes a deactivated object, and replace Destroy() with Despawn() that deactivates the object and adds it back to the list.

There’s lots of tutorials about this already, and a few assets on the store if you want a drag-and-drop solution.

@CaptainScience

Having lists of active and inactive objects is better that instantiating and destroying others in a short amount of time, got it. I might save the practice for future projects since for now I’m going to have a max of like…

8-12 monsters
4-8 players
1-4 prefab that has a particle effect on it per monster player for doing special effects
Gear on the players

I’ll rarely be instantiating objects in this game, and it’ll never be more than like 30 at once (in total including the floor, nearby objects, players, monsters, effects, etc). I’ll definitely keep that in mind for games where I would otherwise use rapid instantiation. I bet that works better on multiplayer games as well.

Thanks.