Advice on repositioning sublevels (Level layout)

Hi, just wondering if anyone has advice on best practices when laying out a series of sublevels. Some specific questions:

  1. What is a good way of moving a bunch of levels at once. EG: I have 12 sublevels and I need to make sublevel 6 bigger (say make a building bigger). Is there a way to easily move levels 7-12 altogether?

  2. Does it matter where the world origin of a sublevel is located? Should they all reside at 0,0,0?

1 Like

How are the levels loaded?

I have a system ( bit of vector math ) that will line up any streaming levels seamlessly.

So are you streaming them, or are they all loaded at once, or…?

1 Like

Thanks, I will be level streaming for production but at the moment I’m testing play so loading all at once. I’m refining a greybox (vert slice) of a 2.5D puzzle platformer so my challenge atm is moving a large number of actors around as I refine gameplay.

I tried using Level Details > Viewport Edit to manage this, but it is a pita for more than one level at a time afaik. So I am now considering using Null parents (just empty actors) to group each sublevel’s contents. But, as this doesn’t move the sublevel origin I was unsure if this would be an issue, or if it matters.

Am curious about your system tho.

1 Like

Pita? ( typo I assume, but not quite sure what you mean ).

You can work with them all loaded in the levels window ( window → levels ), and then choose which level you are editing as you proceed. This method is fine, if you know upfront exactly how everything is going to connect. It doesn’t matter where things are positioned in their respective sub-levels, because when they are all connected, it makes sense.

I work by making the sublevels separately, and then connected them together using ‘load level instance’. That way, I can connect them in different ways if I want, both when editing ( construction script ), and at runtime.

1 Like

Sorry, pita is shorthand for ‘pain in the butt’. Having to move them one at a time is what I’m referring to.

Thanks a million for sharing your technique!!! I built a sublevel spawning editor widget and initial tests are successful.

One thing - I assume not, but is there any way to save changes made in editor to sublevels loaded this way into a persistent level?

1 Like

Glad to hear it’s progressing :slight_smile:

If you’re using the level editor, you can always save changes to that level

Tell me if you have any trouble getting things lined up with ‘load level instance’, and I’ll show you the code. ( It’s just a lot of pictures if you’re not interested :slight_smile: )

1 Like

I’d appreciate seeing your design.

When I load the levels using Load Level Instance (By Name) in an editor widget they do not show up in the levels window, so I can’t save them using the method you describe. Am I missing something?

1 Like

I do see them in the levels window, but marked as ‘transient’.

Anyway, it’s not a super easy way to work.

I will post the examples and math ( not too bad ) here in a little while… :slight_smile:

1 Like

Interesting. Mine shows only the persistent and the 1 level I added via the levels panel. Levels 2,3,4 are not shown. Its not a big deal, working on the sublevels seperately is better.

Thank you so much. I am very curious to see!

Also, sorry to hammer you with questions but I don’t get the attention of a wizard such as you all that often. Threads here lead me to believe it is not possible/advisable to get references to actors on sublevels loaded this way. I’m a bit confused by what the alternative would be, as I would prefer my playerstarts be set inside the sublevels (and also other actors - such as ones used for AI goals that I use ‘getallactorsofclass’ to get)

1 Like

I use sublevel player starts. You can give them an actor tag ( which you need because the system also makes dummy player starts ), and get to know when the level has loaded.

Storing actor refs is not a good idea. Maybe explain a bit what you’re doing there?

No worries :slight_smile:

1 Like

Ok, so here’s the problem:

I have an empty persistent. I load level A into it ( with no transform ), and I want to load level B in a certain position, ie, with a transform so that it fits. I don’t just want them loaded on top of each other.

So, I put a marker in level A, where I want level B to load. And I put a marker in level B, where I want level A to load. I need both markers, because I want to be able to load B into, or A into B ( depending on how the game goes ).

The marker BP is very simple. I just need to know where, and what rotation ( I only do Z rotation, although all 3 axis is possible )

You don’t need anything in the marker. But I have some text, so I can see what’s going on. And I have a collision volume, so that if someone tries to cross into level B, but it’s not ready, I can stop the player until it is.

Like I say, I will have the corresponding marker in level B, where I want A to load.

Now… I already have the math implied here. Because I have already specified a certain position and rotation that I want B loaded at. And I know the marker in B says where I want A. So, how do I turn that into some math that will give me the correct transform for level loading? That’s where the loader BP comes in.

I have the text again ( just for info ), and a collision volume. When the player overlaps here ( or when I press the button in the editor ) it will load B into A ( well, the persistent, but connected to A ). The only runtime code is

I’m saying, when the player overlaps, I load level B with this transform info. There are a few more layers, bear with me…

Why use the game instance? Because it persists between levels, so I can keep track of which levels are loaded, so I don’t load them twice, and can unload them when need be. You can see, I’m passing 3 things here

  1. A reference to the load point in this level
  2. The location and rotation of the load point in level B ( you have to give this info to the load BP, I have a bit of code to pass it through the save game in editor, but you can just copy/paste it )

I do the translation between levels in a function before I pass the info to the GI

That is the critical bit of maths.

The rest of the code in the loader BP is only to help me during edit, to load/unload other levels

Nearly there :slight_smile: Here’s what I have in the GI

I’m just checking if the level is loaded already. If not, I put it in the list and load it. Unloading is more simple

I think that’s everything. Read it a few times, and tell me how it goes… :slight_smile:

1 Like

Ok, beautiful. Thank you so much! I will take some time to digest this but it seems an elegant strategy.

Sorry, my spawn issue was related to sublevels not being loaded at runtime. I’d foolishly thought the editor widget was ‘permanently’ loading the sublevels into my persistent, but of course, it wasn’t… doh.

Thank you 1000 times for the help, I had not even remotely considered this method and I think it is going to seriously expedite my development.

1 Like

Great! :sunglasses:

Extra bit of code from the UnloadBP

and editor mode stuff from the marker

The save game function is a library call

image

Good luck :+1:

1 Like

To assist in rapid iterations for greyboxing, I constructed a simple system (based on your code) that aligns sublevels added to a persistent level (added via levels panel). It is near exactly what I was hoping for and is a MASSIVE time-saver over my old method. I’m also very happy to know that I also have a solid framework for when I get to the next step.

You’re a hero. Thanks again - this is all extremely helpful!!!

1 Like

Excellent! :sunglasses:

Yes, I spent hours painfully aligning levels at one point. It’s a real time saver :smiley:

1 Like

Just popping back in to say thank you again. No hyperbole, this is an absolute game-changer.

Between your method and @gOroQ’s snippet for generating extruded spline-based meshes
(Spline Extrude (GeneratedDynamicMeshActor) - Simple Example | Unreal engine Code Snippet) greyboxing a 2.5D platformer is technically a breeze.

2 Likes

Glad to hear it’s working out :smiley:

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.