Hey there folks, I’ve looked over some other topics and Google-d a bit but found very generic answers, and the few specific ones were in java which I know next to nothing about. I’m new to 3D/Game programming and only know C# enough to do something like this.
I’m trying to create a large map where thousands of tiles get placed a player can interact with. (Think MC if it was flat or something similar, just not so extensive.) I’m currently using an IList array to store the details and make sure nothing overlaps, but once it gets past about 500 it locks up. I know this is a memory management issue but don’t know a better way to do this. If someone could give me some examples on how to generate so many tiles without lagging the engine out I would greatly appreciate it. Below is what I have so far.
public GameObject[] blocks;
IList usedCoords = new ArrayList (); // I know this isn't the best way, but I like using ILists, is there a better way than array?
for (int i = 0; i < 1000; iTries++) { // Once past about 550 the lag kicks in rather bad. No idea how to fix that.
int blockIndex = Random.Range (0, blocks.Length);
Vector3 v3 = new Vector3 (Random.Range (-20, 20), Random.Range (-9, 9), 0);
if (usedCoords.Contains (v3.ToString ()) != true) {
Instantiate (blocks [blockIndex], v3, transform.rotation);
//Debug.Log (v3);
usedCoords.Add (v3.ToString ());
i++;
} else {
}
I’m sure there’s a way to save all this data internally or to a file, and then only render what the player is closed to, but no idea how.
Hope the question isn’t too annoying, new around here. Thanks in advance to anyone who can help.
My guess is, you’re lagging at the line “if (usedCoords.Contains…”, because internally, it’s looping over the existing list and comparing EVERY vector to that new one.
Why do you want to place blocks randomly?
And frankly, if you know the exact number of object you’re going to have, use an array, not a list.
I assumed as much too. The reason is because I have about 10 different textures that all need to be placed randomly not in a particular order.
I don’t know the -exact- number, I just know how wide and how deep I want the map to be. Think of something like terraria where it’s a random world kinda thing. Blocks are placed randomly in no particular order.
In MineCraft or Terraria, block don’t exist until you encounter them. There’s a whole engine in background making sure the world is not bazillion of cubes.
In your case, if you want to have cubes;
private GameObject[,,] blocks = new GameObject[X_MAX, Y_MAX, Z_MAX];
// Your original prefab
private GameObject[] BlockType;
for (int x = 0; x < X_MAX; x++)
{
for (int y = 0; y < Y_MAX; y++)
{
for (int z = 0; z < Z_MAX; z++)
{
blocks[x,y,z] = Instanciate(BlockType[UnityEngine.Random(0, BlockType.Lenght)]);
}
}
}
I’m fine with using 2D bodies for what I’m doing, I don’t really need cubes I suppose.
As for what said; that’s what I don’t get. Reading though other code I’ve found online it acts like it’s created the info for what’s going to be there even before the player gets close. Once you leave the area and come back it’s the same, it’s just not visible or created. How do I manage to create a world that isn’t really there and only renders or exists when I player is close? I’m trying to create an area 500k square blocks in size, and obviously they can’t all be there at once but that info has to exist someplace,
That makes sense, but in what form? Is a good way to use an IList or array to hold the information then pull from it?
What structure would be good for what I’m doing (as I said this is all a bit new to me) to hold the info?
I was thinking create a file from an ilist or array of where everything would go, then when a player is within so many blocks
instantiate the GOs around them and remove those away.
There are different ways of doing this though, and I’m afraid using loops like For and If will just cause the same kind-of lag.
Why place the titles randomly when you can instead place a random title at each location instead? It’d likely be less computationally intense and you wouldn’t have to iterate over a list of strings which, as others have pointed out, will be very expensive as n grows sufficiently large where n is the size of the list.
Edit: Oh, you might not want the entire screen to be a title. Hmmm. Well, I’m not sure there.
As for:
You could, if C# permits, use a seedable pseudo-random generator. And the current location in the sequence could be represented by the current tile. From that you’d be able to save only the seed of the pseudo-random generator and be able to call upon the title by passing the title number to a function, the seed and return the random title. It’ll be the same title as before so you won’t need to save it.
That’s a solution for storing information about this random large title map. As for how you could only display what is visible I don’t know.
Edit: If you do want to store the data you could test the efficiency of a Dictionary vs a List and see if it holds for the data types you’d be using.
Here is a link to a possibly credible test of the look-up efficiency. Although this isn’t necessarily the same for initial creation. http://www.dotnetperls.com/dictionary-time
So if I get what you’re saying, instead of picking a random location to place a tile, select locations in order maybe, then place the random tiles that way?
That would be perfect, except I’ve only seen examples of said method in java and have no idea how to do it in C#.
That allows the data to be saved in a very simple way so that each tile has a place in the world but I wouldn’t have to reference
every gameobject as each one would be created and removed as needed. I could attach scripts for calculations such as if they’re able to be
removed and the speed at which that happens to prefabs and create some method for where the player’s sight radius is and just allow objects to be
enabled there.
I have no idea how to do such a thing, I would imagine that I could use simple foreach kind of loops to determine how many tiles would be close.
Does anyone have a code example of what I would need to do so I can get a better idea of how to build off it?
I have in C++ though, I wish I had that answer. It might be worth asking around but I’m not 100% certain that my suggestion may be what you need. I don’t want you to unnecessarily travel down an unfruitful path. It’s possible other’s might have suggestions that better solve the problem; especially so if C# does not provide any seedable pseudo-random classes.
Simple call Generate(x,y), and you can get random but reproducible results for any input. To get different results use the Generate(x,y,z) and use z to switch to a different layer of noise. You will get a result between 0 and 1 so just map that to your different textures however you want to.
Then you just have a certain number of blocks around the player that you have loaded (divide it into cells that are loaded/unloaded as a unit). When the player moves, you will have to load/unload cells around them. Ideally, you will not create or destroy blocks, but just move them around so you won’t hit the garbage collector.
If the player can make changes to the blocks, you will need to save these separately, and check it for each cell you load (and save it for each cell you unload).
That’s a bit of a brief overview of how I would approach the problem, but hopefully it is helpful.
That’s actually a great way to do it, I’ll have to look over that source to see how to use it with my system.
My problem is that the world isn’t 100% random, and that certain things will appear in certain places.
I suppose it’s a matter of generating them one set at a time and filling in the rest.
Also @Glader thanks for the info I did a bit more research into lists vs dictionaries and did some tests in VS
and found you were correct, once the count gets up a bit it’s a bit slower than a dictionary. Its functions are
convenient enough.