Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by OmegaVesko · Dec 22, 2013 at 07:37 PM · 2dperformanceoptimization

How do I optimize my usage of many GameObjects?

I'm currently prototyping a game using Unity's 2D tools, and I want the game to vaguely resemble Terraria. To this end, I want the scene to consist of a huge grid of tiles, much like Terraria.

Since the world needs to be destructible, and the player needs to collide with individual blocks, I'm making every tile a separate GameObject with a rigidbody2D and a box collider attached to it. Obviously this is very bad for performance, and the most I've managed at 60FPS was about 128x128 blocks.

Is there something I should be doing differently to get better performance? Is this sort of thing even possible in Unity? This isn't my first Unity project, but it is the first where I've attempted something on a scale as large as this.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
4
Best Answer

Answer by Statement · Dec 22, 2013 at 07:47 PM

Treat a chunk of tiles as one game object.

It would mean that you would be generating a mesh that cover multiple tiles.

If you generate both the graphical mesh and the collider mesh, then you get away with much less game objects (and you should do). To interact with the tiles, you will now have to rethink your code design to allow a different communication method since you no longer have a game object per tile and thus can't have scripts per tile.

This approach is very feasible and I've used it in various 3d voxel implementations, one of which is an experimental hobby project called Clayful (video 1) (video 2). A lot of people ask for source, but unfortunately I've binned them so please don't ask for source :) Just included the videos to reinforce your belief that it's doable and feasible.

If you have any concerns about this approach, post a comment onto my answer and I'll get back to you later.


Conceptually, think of a chunk as some managable sized grid of tiles. Like 8x8 or 16x16. I dont have a "best" value, get a feeling for it yourself. Basically you want to have as big of a chunk as you can, but not so big that the act of recreating the meshes becomes a bottleneck.

You would create a new Mesh and update it when you need to rebuild the map. Therefore, knowing the Mesh API is a must. After the mesh is created, you need to set the objects MeshFilter.sharedMesh property.

  • Note: You may be required to set sharedMesh to null and back if physics doesn't seem to update!

To support multiple textures and keep drawcalls down, I would suggest using an atlas so you can use a single material for every tile. This is a good technique but forces you to use a single material. If you want to support multiple types of materials, thats possible too but its extra work and I'll leave it to you to solve that problem.

I would recommend that you have a manager game object that you use to interact with the tiles and not communicate with the chunks directly. So you could think of having one game object for your map, and children to it are your chunks.

The "Map" (Manager) has a script on it that you use whenever you want to work with tiles, so you can do stuff like:

 map.SetTile(x, y, TileInfo.Brick);
 map.Rebuild();

Introduce Proxy classes if you want to be able to get a "Tile" object to work with so you don't have to mess around with the map all of the time. Here you could also define any behaviour you want to support. Alternatively you could make a higher level API for your Map if you prefer that but I think Tile proxy is cleaner personally.

  • Note: I don't know if "Proxy" is the correct word for the pattern here, but basically the class is intended to change the Map when you use a Tile, without ever having to know about the Map from your scripts!

Let's see how a Tile class could be made.

 // does not extend from MonoBehaviour
 public class Tile 
 {
     // These are intentionally set as read only
     public readonly Map map;
     public readonly int x;
     public readonly int y;

     public Tile(Map map, int x, int y) 
     {
         this.map = map;
         this.x = x;
         this.y = y;
     }

     // Just an example and everyone love explosions 
     public void Explode()
     {
         // alternatively also destroy neighbor tiles
         map.SetTile(x, y, TileInfo.Empty);
         map.Rebuild();
         // play audio
         // spawn particles at tile location
     }
 }

This object should be created by the Map like:

 public class Map : MonoBehaviour
 {
     // ...

     // Creates a proxy object, for convenience
     public Tile GetTile(int x, int y) 
     {
         return new Tile(this, x, y);
     }

     // ...
 }

If you really want to, you could also create a little system for adding components to your tiles too, using a howngrown system.

In the end, you could do stuff like:

 Tile foo = map.GetTile(4, 19);
 foo.Explode();

And my examples are very basic, you should probably cache Tile proxies you've created for instance so you don't keep creating new ones with every call to GetTile. Just giving you a skeleton idea to work with.

The idea is though that you have:

  • One Map, which is the entry point to working with tiles.

  • Several MapChunks, which the Map manages and are hidden from the rest of the code.
    Possibly has utility functions to regenerate the mesh.
    Each MapChunk also has a MeshCollider, a Renderer and a MeshFilter and represents n by n tiles.

  • A Tile class, which is an accessible and simple to use class for doing stuff with a Tile.
    As you saw, this is just for convenience and you may choose not to have it.

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image OmegaVesko · Dec 22, 2013 at 08:47 PM 0
Share

That seems feasible, thanks! I thought the solution would involve 'chunks' of some sort.

Could you give me some pointers on how to implement this? If I'm generating the world at runtime, how do I consolidate the generated tiles into a single chunk? Also, if they're a single GameObject, how would I interact with (or destroy) a single tile?

avatar image Statement · Dec 22, 2013 at 09:47 PM 0
Share

Updated answer.

avatar image MandL27 · Sep 17, 2016 at 06:13 PM 0
Share

Some questions about this: 1) If I already have a sprite sheet of all the images used in assembling the map, what steps should be taken to make that into something usable with a $$anonymous$$esh? 2) Ins$$anonymous$$d of altering the $$anonymous$$esh, can I have that created in the scene and then create/modify the Texture2D applied to it at runtime? 3) Extending from the above, if I have ~250 pickups placed in a single 28x31 grid, should each pickup be its own GameObject to completely avoid SetPixels() calls after creating the map?

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

20 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Sprites performance issue 0 Answers

Disable objects far away from player to make performance better 2 Answers

Increase Unity2D editor performance 0 Answers

2D Android game - bad performance after launch 1 Answer

gfx.waitforpresent took up to 40ms even without any gameobject running 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges