- Home /
Classic Resident Evil-style room loading/level streaming?
Hi all,
I was wondering how one would go about implementing level streaming/room loading as in the classical Resident Evils (0, REmake, 1, 2, 3)
As most of you probably know, in RE if you're in a room then you're pretty much in isolation from actors/entities/objects in other rooms, so a zombie can't break in and attack. It's like there's a separate memory space for each room.
My guess is that when a player enters a room, they load the room with whatever tickable objects in it (zombies etc) and the background renders. When you exit the room, they check if the room should save anything (*), unload it and load the new room.
(*) Take for example the pictures with the crows room in RE1 (@24:15), if you mess up the puzzle and exit the room and re-enter, the puzzle would reset, but if you solve it correctly then exit/re-enter the puzzle had already been solved. I'd imagine there's a save that's done to the room upon player exit if the player solves the puzzle, and a load when the player enters.
I would like to achieve a very similar thing. I know that they probably couldn't load more due to hardware limitations, but most of the times I find myself seeking ways to achieve the results/outcomes of those limitations (Most the times those limitations end up playing a major role in enhancing the overall experience of the game they were implemented in (the fog in Silent Hill 1, the static backgrounds/cameras in RE etc)). I was wondering how one would go about implementing that in Unity. I thought about two approaches, but before I talk about them let me mention some of the prerequisites I want to meet in this system:
Each room is isolated, enemies in other rooms have no way of interacting with you/breaking in.
Fast loading times when entering rooms (I usually play the PC version of RE3 just because I can skip the door loading scenes...)
The ability to save room state upon exit if necessary (this is a room-dependent thing)
My thoughts/approaches (just theory, haven't tried them in practice yet):
A) Use a separate Unity Scene for each room.
Pros:
It easily ensures the room's isolation.
For saving/loading, I could keep track of the current loaded scene and use some of Unity's callbacks like OnLevelWasLoaded or OnDestroy/OnDisable & Awake/OnEnable in a per-scene manager behaviour.
Cons?
I'm not sure about loading times, I'm kinda worried that some rooms will have longer loading times than others...
There's gonna be a lot of small rooms, it could be an overkill to use a separate scene for each of them...
More scenes = more management + extra care needs to be taken cause from my experience scenes are fragile and could corrupt pretty easily which means I should not rely a lot on the editor to set my things up and go data-driven (which I'm already doing) and do the least amount of config to re-setup the scene if necessary.
B) Load a relatively big rooms chunk, e.g if I had a two story building, and the player's in the first floor, I'd load all the rooms in that floor - they're all in one scene. When player goes to the ground floor, I'd load the whole ground floor. Take for example the room in this video (the bg is pre-rendered btw :p) - I'd load it and all the rooms in it in one scene. But then to achieve room isolation I'd have to come up with a system that, for instance give each room an id, and keeps track of which room the player's currently in and deactivates all objects in the other rooms (I imagine the whole room would go under a GameObject for organization purposes and to make it easy to disable/enable rooms?) - Saving/loading wise, not much of a change. I'd still have to save/load things when player exits/enters a room or changes scene.
Here's an old map of that floor:
Pros:
Less scene management you could argue.
Faster loading times when traveling between rooms since they're already loaded.
Cons:
Room isolation is not as perfect. There could potentially be bugs where entities in other rooms might remain active, or don't initialize properly or Idk... But I don't think it's a huge deal I just haven't tried it yet...
Larger scene = harder to reconfigure/rewire if it gets corrupt.
My questions:
Are those two approaches decent? Which do you think is best and why?
A lot of the times we're in a tunneled vision and can't see outside of it, that's why we ask for others' opinions/thoughts: do you see something I don't in those two approaches? (in particular: potential bites, gotchas and caveats)
Can you think of a better approach?
Those were my 2 cents, can't wait to hear yours!
Thanks in advance for any help/ideas!
EDIT More on approach B: maybe each room would be a prefab?
This might be more suited to a forum discussion, but it's a good topic! :)
If I could live with the limitation that inter-room interactions are not possible or at least cumbersome to implement, I would go for the one-room-one-scene approach and keep it nice and orderly.
Yes you could argue it's a little bit argumentative but I think there's only a handful of ways to go about it i.e. not subjective enough to the point where everybody has his own opinion/approach :D
I'm leaning towards that approach too, it's more predictable and easier to reason about should the load times turn out to be fast. But one other thing to keep in $$anonymous$$d is that the artist then would have to handle me the rooms separately, maybe he'd have to re-think the way he's designing things, from thinking about levels into rooms, idk maybe it's not a big deal.
Answer by vexe · Jun 19, 2015 at 04:33 PM
Well I've gone with the scene per-room approach, seems good enough. Loading times are good, Unity 5 improved scene loading. I save selectively marked objects in the room to disk on exit, and load them on enter.
https://www.youtube.com/watch?v=z1ejB0oc-XM&feature=youtu.be
Answer by Eno-Khaon · Jun 16, 2015 at 04:09 AM
It's like there's a separate memory space for each room.
It's a little more straightforward than that. To borrow a note from the Wikipedia entry on the original Playstation:
RAM: 2 MB main, 1 MB video
There wasn't enough RAM in the system to hold any significant amount of 3D model and texture data in memory simultaneously. The rooms would've been loaded and unloaded in order for the game to function whatsoever, with as little overhead left over as possible.
As far as creating a representation of that system, however, you could create a Room class to hold data regarding the room's contents, their default state (if needed, such as puzzle rooms), their current state (enemy positions, if applicable), entrances/exits and more.
The player would then be able to transfer between "Rooms" and all the data from the room you're already in would be left behind. To actually process contents of a Room, define which objects can move without the player present (again, enemies?), then tell everything else to be immobilized. Why do that? Well, modern hardware is a bit powerful than a Playstation[citation needed][1]. You can define regions in each Room that tell your computer to load data for the adjacent Room you're approaching. Then, your rooms can connect seamlessly (and, if a room's not loaded yet for any reason, put the player in limbo until the room loads or, if it times out, send them back to where they just were when they tried to enter).
On the other hand, if you would prefer to change scenes for each Room you would use, you can make use of Application.LoadLevelAsync() to ready the scene ahead of time instead.
Edit: Yeah, my first portion of this does basically suggest using prefabs and loading them in on demand if you're going for lesser memory/video usage at a time.
Thanks for your answer!
Actually I incorrectly conveyed my thoughts with that statement. I did not mean that rooms would get loaded simultaneously in different memory spaces, ins$$anonymous$$d like you mentioned: the previous room gets unloaded, and whole current active room is loaded, since you're reloading things you'll probably end up storing in a different memory address, and so the new room sits in a space that has no relation with the previous one, so only one room is loaded in memory. Is what I meant :)
I'd have to find a way to easily tag/mark/tell actors (enemies) which room they belong in - an easy way to do it is to use child-parent relation. Have the room have its own GameObject (maybe with the Room.cs attached to it) and anything that belongs to it goes under it as child (enemies etc) - then a simple in-editor code that keeps an eye out for the children and adds them to a list if anything new is added. That way $$anonymous$$imal work is done.
LoadLevelAsync would definitely help reduce loading times if I went with the scenes approach yes.
Answer by skalev · Jun 16, 2015 at 03:57 AM
In our project we use the SECTR plugin to manage streaming chunks of levels.
https://www.assetstore.unity3d.com/en/#!/content/15356
Nathan, the creator is very helpful in supporting, and has added various features to the plugin to accommodate our project.
Yes, SECTR will work well with this kind of setup, as well as the more modern analog of airlocked strea$$anonymous$$g ala Dead Space or $$anonymous$$etroid Prime. SECTR gives you all the tools to prep your scenes, export them for strea$$anonymous$$g, and (un)load them at runtime. There are hooks for when rooms are loaded and unloaded, though you'd have to write the code to save and load puzzle object state yourself. Also, there's a built in door loader in SECTR, but if you wanted classic RE door animations, where the screen is black except for the door opening, you'd need to write that code yourself.
Thanks for the reply Nathan! SECTR seems definitely a good candidate solution. But the fact that there's no demo/free trial of it (try before buy) and that I'm a bit low on green makes it a less feasible option to me.
Gonna reopen the question for a bit longer see if anybody else has something else/more to say/add, I think I accepted too quick.