- Home /
How to instantiate and align sections of level in real-time
Hi,
I am trying to write a procedural level generation script which contains 5 different shaped sections which are placed into a public Transform array (Sections dragged into slots in Inspector, etc.) Each section has its pivot at one end (the front) and an object with tag 'helper' at the other end (this is the End-point of each section). The script looks through each section to find its 'helper' object (End-point) and then assigns this to the next Transform (Section) in the array (therefore, to its Start-point).
What I would like to be able to do now is to have say one starting section already in the scene, and then have the others generate after it in random order one after the other. Any help with this would be greatly appreciated! :)
The following function is my starting point. It receives a random number (ChosenIndex) and then goes onto select the section corresponding to that index. It will first create a new Transform (nextTrans) to the chosen section and then assign its position and rotation accordingly. This depends on whether we are adding onto the first (already existing) section in the scene, or ones we have added using the script.
However, running this seems to add the new section at the Start of the existing section (ie. on top) in the scene, not at its end-point. Having looked at the new section when the scene is running, it seems that its y-rotation is at 180 degrees, I'm not sure why this is the case.
Note,
ParkLotSectionList - the list of sections in the Parking Lot/available to add in the scene (added via Inspector)
EndpointPositionsList - the list of End-points of the sections in the Parking Lot, corresponding with their index (0 - 4) - (added via Inspector)
StartingSectionEndpoint - the End-point of the existing section in the scene (added via Inspector)
firstSection - simply a boolean to check which starting point to use
Thanks in advance.
//----
void SectionSelector (int ChosenIndex)
{
// Assign the chosen section to a new Transform, nextTrans
Transform nextTrans = ParkLotSectionList[ChosenIndex];
// Adding into the first section in the scene
if (firstSection)
{
nextTrans.position = StartingSectionEndpoint.position;
nextTrans.rotation = StartingSectionEndpoint.rotation;
Debug.Log("nextTrans.position = " + nextTrans.position);
firstSection = false;
}
// Otherwise, assign it the End-point values for the following sections
else
{
nextTrans.position = EndpointPositionsList[ChosenIndex].position;
nextTrans.rotation = EndpointPositionsList[ChosenIndex].rotation;
}
}
Hey - help me out - I get what you are trying to do, but I don't get what you are having a problem with. Your idea seems sound.
Sure thing whydoidoit, and good to hear I'm heading in the right direction :)
The game I am working on involves the Camera/Player constantly translating forward along the Z-axis. Now, rather than creating a level with a set path each time it is played, I am ins$$anonymous$$d trying to have its path generated randomly as the game is being played.
Just like Temple Run (I would presume), I would like the level to generate new sections that are bolted onto the end of current section in real-time. That is, say 1 - 2 sections ahead of the Player and just behind the fog layer) in front of him.
The level will be made up of five different types (Section1 - Section5), such as a straight, 45 deg left turn, 45 deg right turn, up, down, etc. Each of these is a Prefab with an End-point object tagged 'helper'.
To avoid any intersections with any currently instantiated sections in the scene (and also to decrease memory usage), I will have the sections just behind the Camera/Player destroyed as they're passed.
Well, that's the theory at least.
I'm currently having issues with generating the sections from the prefabs and aligning them one after the other. I'm starting off by having two sections in the scene to begin with. I would like to have one of the five sections in the array instantiate and bolt onto the one at the end (Section2 in my scene). I would then like another random section to generate and tack onto that section, and so on. Each prefab section is added to the tubeList array in the Inpector).
Hope that makes things clearer, any questions please ask - any help would be great :)
So it strikes me that you have a pivot point already - but I'm presu$$anonymous$$g that these prefabs need to be in boxes effectively (even if it is a 45 degree angle) - or there will be a split in the geometry from what I'm imagining.
I would have thought that you would define a standard block size and then plug them together like tiles. I suppose you could just attach to a centralised pivot point if the geometry extends to fit against the end of the previous section - but presumably that would be difficult.
Yes, the pivot is at the opposite end of the 'helper' End-point object. I should mention that currently, I'm working with different coloured straight sections only, but the curved sections will be in boxes (or cuboid volumes, as they are all tubes).
The idea of using a set block size sounds feasible too, maybe it's a better approach, not too sure. The pivot at the end was what sprung to $$anonymous$$d, but I'm open to any suggestions if you think they could be better for the job.
Well I think blocks would be easier to debug and visualize as you are program$$anonymous$$g and designing. I'm liking @Fattie's approach in his answer - the parking lot is a great idea and would really help performance.
Answer by Fattie · Jun 14, 2012 at 06:10 PM
Asimov -- can we cal you Isaac! -- :) -- I do not 100% understand the problem you're having (could you phrase it again more simply), but .....
Often this is the approach to take:
set up let's say 10 each of your different building units. Just have them sitting "in space" offscreen somewhere. We'll call that the "parking lot"
Each time you need a new one ......... just roll in the next one that is sitting in the "parking lot". All you do is change the position.
When the "parking lot" is empty of a particularly type, just suck back the oldest one form the scene.
(Alternately, if you wish, immediately "suck them back" once the plyer has passed or they are otherwise no longer needed.)
Note that you never have to instantiate (copy) anything ... you just literally loop through what you have, taking them out of the "parking lot" (or indeed, simply taking them from the "back" of the scene.
For example, I just literally did this this morning for a "stream of fast moving bullets" (I mean it's only 2 lines of code, no big deal) - and it's just what you can also do for "large chunks"
(Funnily enough, we had to do exactly what you describe in "the air" for a scene where you fly around endlessly in 3D with stuff.) Again this is I suppose a somewhat standard approach, and very easy.
I hope this helps in some way!
BTW when it is working beautifully, its great to watch the scene from a high meta-view in the editor as your colleague plays!
Hi Fattie,
I insist you call me Isaac! :D
The approach you mention sounds very promising for what I have in $$anonymous$$d. I think part of the problem was that I was trying to place the prefab in the scene (which is what I meant by instantiate), and then align it with the current section in the scene. The 'Parking Lot' idea makes sense as this means each section would already have a position.
Would the 'Parking Lot' have a script of its own which constantly checks to see if there's one of each section in the scene? Can this be achieved using a GameObject.Find() for each section (although would be expensive if placed in Update()) ?
So, if one is missing, Find one of the same in the 'currently used' array, if passed by the Player.
You'll have to bear with me WRT some of the code unfortunately, as I'm quite new to unity so still learning the infinitely long ropes :)
Specifically, I think I'm having the most trouble when thinking about how to structure this. Would I need an array to hold the five sections, or would they be ADDED to an array as they're added?
To clarify, what I have in $$anonymous$$d is something like;
Have some sections in the scene, find the end-point of the last one.
Randomly select a section type from the array/parking lot ?
Assign End-point of last section to the new section. Bolt it on.
Check Parking lot to see if one of each section. If any missing, move one of same type from currently placed. What happens if, for example, Section1 is missing from the Parking Lot and there are no Section1's that have been passed, instantiate another to Parking Lot, or avoid that Section for now?
Find End-point of last placed section.
Repeat steps 3 - 5
If you have any code to hand, that would be awesome, too!
BTW, do you have a link you the game you mention, if possible, as I'd be very interested to see this in action? :)
Eventually, I would like to do the same with the objects and enemy spawns within each section using empty objects placed inside - but that's for another day.
You'll need to learn how to use the List structure, and just keep a pointer to which one you "bring up next" !
Regarding your pivoit points and so on. I think you need to just make an empty object as a wrapper, and make THE ORIGIN OF THAT WRAPPER OBJECT the critical point you are talking about. Then when you "place" the overall object (the wrapper) that's exactly where it will land!
O$$anonymous$$ great, that makes sense.
Regarding making sure that all sections are always present in the Parking Lot. For my List of Transforms of size 5 (one of each type), how would you recommend that I go about maintaining the check that each type is always present in its slot?
Should do this with an explicit statement for each slot, like:
if (sectionList[0] != Section1 || sectionList[0] == null) { Find an 'expired' Section1 type in the scene, OR Instantiate another from prefab if not present in scene, Position in the Parking Lot }
just alwys use the oldest one! don't worry about the parking lot actually. they only START in the parking lot.
have a variable called "which one to use next". start it at zero.
every time ou have to place one, place the one whichOneToUseNext.
then, do these two lines of code
whichOneToUseNext += 1
if whichOneToUseNext >= 5, whichOneToUseNext = 0
THAT'S ALL YOU HAVE TO DO ! :) the rest is pure magic.
enjoy !
pls "tick" the answer if no better one comes along :) ask anything!
Thanks again for taking the time to reply. Glad you added the "ask anything" at the end! :)
Right now I have one Alignment script that also sends a random number between 0 and the array length (to select the next section). Passes that to the Parking Lot script with the idea that it would check if that section was present in the array and add it if it was. Unfortunately, when I remove that section to test the other side of the coin its an epic fail.
I'm not quite sure how to keep track of what sections are still in the array/List. Are the sections being removed from the List when 'used', or just the scene??
So you mean discard the parking lot idea entirely, as in, not have the sections just 'sit' somewhere in the scene and be positioned?
Can you possibly provide any pseudo-code to describe what the whole process would be? $$anonymous$$aybe from the point of just having a single section in the scene as the first End-point to add onto? Would this still make use of Lists if not using the Parking Lot idea, etc.
Really appreciate the advice, Thanks again!
Answer by FredericRP · Jun 19, 2012 at 10:40 AM
Here's a quick drawing to illustrate, as I understand, above descriptions. If you chose to use different block size, you should also get the "helper" position before runtime because searching in objects takes time : use a new Script to store that variable from the editor for instance and assign this script to each section game object you made. You'll then have a list of Section objects, and iterate through that list (or pick a random next one) to create your path.
List<Section> availableSections;
But beware if you move your camera only on the Z-axis as you said, and if your sections are not located one after another on the same axis (left bottom corner on the picture) : you'll have a path offscreen easily. Consider having a list of "potential candidates" for each section (block A can be followed by block B..)
Hi FredericRP - thanks for your reply!
The picture does help and is 'thereabouts' how I imagined the sections to be put together. The potential candidates is a good idea too. Funny you should mention having the 'helper' points in their own script to save time, I had something similar - I had them in their own array/List which would correspond (indexes 0 - 4) to the sections in their own array.
I just have a few questions regarding your description that I hope you can clear up;
Q1. In your version, are the 'unused' sections beginning life somewhere else 'out of camera view' and re-positioned (as in Fattie's version), or simply being instantiated from the prefabs?
For example, if we have say one of each sections behind the Player, we can choose to place one of these as the next one ahead of him as he moves. In this way, if we wanted to select randomly which section is to go next, then at first we could choose one from all 5 available, then as the Player moves, from the remaining 4 + the one he has just passed. So this should not be truly random if we are relying on what is available in the scene. This is not a major issue however, as the 'potential candidates' will change which section will follow which, anyway.
Q2. How do you keep track of which section was used last / which are available? Any chance of some code examples here?
Q3. The number of section types does not change, so would it not make more sense to add them to an Array rather than a List which can grow dynamically? Unless they can be manipulated in difference ways, of course.
Thanks again.
I've edited the code above to what I'm working on at the moment - maybe you know what's wrong?
ouch, there's not mail when a new comment is posted, but there is one for new answers :s A 1 year old question ! I'm sure you already answered yourself everything, but let's still answer, for everyone if that can be useful.
Q1. Yes, the unused sections should be instantiated at beginning and moved accordingly to the path that is built, and there shouldn't be more than 3 times the same section instantiated at the same time, but you still can have the same section (well, same prefab but not same object) multiple times.
Q2. That depends a lot on what you expect: if you focus on a random level generation, just stick to the potential candidates list and that's enough. As said in the Q1, you can instantiate the same section multiple times so you don't have to bother on which section is available or not.
Q3. For performance issue, an array can be better yes for a static length.