Game Development Community

Implementing several scenewindows

by Ricardo Vladimiro · in Torque Game Builder · 03/26/2007 (10:31 am) · 11 replies

Hi everyone

As discussed on a previous thread (http://www.garagegames.com/mg/forums/result.thread.php?qt=59332) we are creating our own GUI elements. It is mentioned by Thomas in that thread that there are advantages in using overlaid scene windows.

I've searched the forums and found some info, but I'm still a bit puzzled on how to implement it and I have some doubts about it. First the generic ones:

First step is to create a new scene window. I did that in GUI Builder. Assigned it a name and I believe that's pretty much it. Now the questions:

1. If the scene window is rendering, what's scenegraph I get from sceneWindow2d.getSceneGraph() and what's it's purpose since I have to "tell" my objects which scenegraph they are on. This scenewindow vs scenegraph puzzles me. I can't seem to understand who does what.

2. How do know in which scenewindow I'm putting my objects? By the scenegraph I get from the above function?

3. How do I tell the engine which scene window to render first? Or better yet, in which order should the engine draw the several scene windows.

4. If I use the editor, how do I know in which scene window I'm putting the objects? How can I change it within the editor, since if I change it outside, the moment I save a level it will revert to any state the editor is using?

5. If using several scene windows allows me to decide the rendering order, does this mean I have 32 layers per scene window?

Ufff, so many doubts. Hope someone can help me out in this. Thanks in advance.

#1
03/26/2007 (11:08 am)
1) You can more or less view the 'window' literally as a 'window', and the 'graph' as the scenery on the other side of the window -- you can Zoom the 'window' ... and, you can even move it around -- the window more or less is relative to the camera, for most intents and purposes ... the graph is the overall area you have to work with -- your objects are drawn to the graph, but the window is how you see them ... you can't see through walls, so anything thats not in the 'window' is not 'visible' -- ie; window == camera, graph == scene

2) you could do an equivalency check, look through the windows and check to see if the objects graph is the same graph contained in the current window of the loop --

3) the engine will most likely render the windows in the order they were created -- I don't think there's any other way to force the rendering ... using the "send to back" and "bring to front" in the GUI builder would be about the only way I'd see forcing the rendering order --

4) SceneGraps have a loadLevel function -- so if you want Objects 1-10 to load in the background scene, and objects 11-20 to load in the foreground scene ... you would probably want to do one of the following:

* Put the objects in seperate level files
* Give all objects a "sceneWindow" field, which identifies the name of the Window to place them in, and then create a generic "t2dSceneObject::onLevelLoaded()" function that looks for this, and if found, removes the object from the scenegraph it is in, and put it in the appropriate scenegraph.

5) yes -- you have 32 layers per scenegraph ...




NOTE: Using multiple scenegraphs to compensate for the 32 layer restriction in TGB is -NOT- the right way to do things -- this is just an FYI for anyone who reads this and goes "Ohhhh ... theres an idea!" ...
#2
03/26/2007 (11:16 am)
Just a few more theory notes:

A SceneGraph is where you put objects. A SceneWindow is one camera's perspective on one SceneGraph.

You mention a few times "how do I know which SceneWindow I am putting my objects in?"--and I think that's the basic concept you may be missing--you never put objects in a SceneWindow, you put them in a SceneGraph--and if the SceneWindow has those objects within it's camera range, then it will display them.

The basic idea here is the following (rough, I'm doing this from memory for theory discussion purposes):

1) Create a SceneGraph (for discussion purposes call it GameSceneGraph)that contains your primary game objects, and create a SceneGraph that contains your GUI objects. Additionally, create a SceneWindow with the appropriate camera controls for this game.

2) Create a SceneGraph that contains your GUI objects (maybe GUISceneGraph), and a SceneWindow that shows them properly. This SceneWindow should have a transparent background (or no background I think will work), and should be positioned to overlay where your GameSceneGraph's primary SceneWindow is on screen.

3) Use your GUISceneGraph objects to display your Gui style information.
#3
03/26/2007 (11:21 am)
Oh, another side-note -- a single scenegraph can be shared across multiple scenewindows -- this can be seen in the 'TGB Split-Screen Starter Kit' resource I released a few months back -- everything is drawn to a single scenegraph, but two scene windows use this graph ... allowing for player 1 and player 2 to be in the same 'world', but have different views of it --
#4
03/26/2007 (1:23 pm)
More thoughts/comments.

Scene windows are rendered in the order they were created. So the first window is at the "bottom" of the rendering stack, next window on top of that, etc. .

If you are using mouse events on multiple windows and your windows overlay each other, the topmost window gets the mouse events.

Stephen is correct about the transparency, if you do not specify a background the window is transparent and you can see the objects behind it.

You can create new scenewindows on the fly and attach them to the canvas for more flexibility in your scripts.

To determine which window you are addressing I name the window object when I create it. The default in TGB is sceneWindow2d and I can create a new window named sceneWindowGUI then I can do a sceneWindowGUI.loadlevel("/pathtofile/guilevel.t2d") and load a GUI window that overlays my main window.
#5
03/26/2007 (3:26 pm)
Guys, you are fantastic!

Upon reading this, I went to check several script files in the common directory and I sorted a plan. Since we have levels and menus separated in level files and any menu will always appear on top of any level, then I can create a scene window on the fly (to get the mouse events "locked") and a scene graph in it. That will give us full freedom regarding layers, mouse events, level loading (menu or not) and so on.

Basically, we'll stack scene windows and scene graphs:

1. gameWindow
2. optionsWindow
3......

Did I get it right?

Then, when the scene windows are not needed, we'll just delete it and with it, scenegraphs, objects, etc, right?
#6
03/26/2007 (3:29 pm)
Err ... sounds about right ... :)
#7
03/27/2007 (10:18 am)
Can't say the first attempt was successful. To be sure everything worked has planed, I created everything in the level editor and then copied the new scenegraph from the level file to a function. Cleared all the objects from the level file so I would have no duplicates.

So I ended up with this:

$hud = new t2dSceneGraph()
	{
		canSaveDynamicFields = "1";
		scenePhysicsFPSActive = "0";
		scenePhysicsTargetFPS = "120";
		scenePhysicsLimitFPS = "0.5";
		scenePhysicsMaxIterations = "1";
		UseLayerSorting = "1";
		layerSortMode0 = "Normal";
		layerSortMode1 = "Normal";
		layerSortMode2 = "Normal";
		layerSortMode3 = "Normal";
		layerSortMode4 = "Normal";
		layerSortMode5 = "Normal";
		layerSortMode6 = "Normal";
		layerSortMode7 = "Normal";
		layerSortMode8 = "Normal";
		layerSortMode9 = "Normal";
		layerSortMode10 = "Normal";
		layerSortMode11 = "Normal";
		layerSortMode12 = "Normal";
		layerSortMode13 = "Normal";
		layerSortMode14 = "Normal";
		layerSortMode15 = "Normal";
		layerSortMode16 = "Normal";
		layerSortMode17 = "Normal";
		layerSortMode18 = "Normal";
		layerSortMode19 = "Normal";
		layerSortMode20 = "Normal";
		layerSortMode21 = "Normal";
		layerSortMode22 = "Normal";
		layerSortMode23 = "Normal";
		layerSortMode24 = "Normal";
		layerSortMode25 = "Normal";
		layerSortMode26 = "Normal";
		layerSortMode27 = "Normal";
		layerSortMode28 = "Normal";
		layerSortMode29 = "Normal";
		layerSortMode30 = "Normal";
		layerSortMode31 = "Normal";
			cameraPosition = "400 300";
			cameraSize = "800 600";

		new t2dStaticSprite() {
			imageMap = "mainMenuButtons";
			frame = "3";
			canSaveDynamicFields = "1";
			superclass = "menuElement";
			class = "Button";
			UseMouseEvents = "1";
			position = "739.000 566.500";
			size = "92.000 57.000";
				call = "returnToMain";
				down = "11";
				inactive = "15";
				mountID = "2";
				Normal = "3";
				over = "7";
				state = "3";
		};
		new t2dStaticSprite() {
			imageMap = "progressBar";
			frame = "0";
			canSaveDynamicFields = "1";
			position = "50.000 300.000";
			size = "44.000 471.000";
			Layer = "1";
				mountID = "3";
		};
		new t2dStaticSprite() {
			imageMap = "cloudLeft";
			frame = "0";
			canSaveDynamicFields = "1";
			position = "128.000 535.000";
			size = "256.000 128.000";
			Layer = "2";
			BlendColor = "1 1 1 0.784314";
				mountID = "4";
		};
		new t2dStaticSprite() {
			imageMap = "cloudRight";
			frame = "0";
			canSaveDynamicFields = "1";
			position = "672.000 535.000";
			size = "256.000 128.000";
			Layer = "2";
			BlendColor = "1 1 1 0.784314";
				mountID = "5";
		};
		new t2dStaticSprite() {
			imageMap = "globe";
			frame = "0";
			canSaveDynamicFields = "1";
			position = "736.000 534.000";
			size = "128.000 128.000";
			Layer = "3";
				mountID = "6";
		};
		new t2dStaticSprite() {
			imageMap = "cloudRight";
			frame = "0";
			canSaveDynamicFields = "1";
			position = "128.000 64.000";
			size = "256.000 128.000";
			FlipX = "1";
			FlipY = "1";
			Layer = "2";
			BlendColor = "1 1 1 0.784314";
				mountID = "7";
		};
		new t2dStaticSprite() {
			imageMap = "cloudLeft";
			frame = "0";
			canSaveDynamicFields = "1";
			position = "671.000 64.000";
			size = "256.000 128.000";
			FlipX = "1";
			FlipY = "1";
			BlendColor = "1 1 1 0.784314";
				mountID = "8";
		};
		new t2dStaticSprite() {
			imageMap = "progress";
			frame = "0";
			canSaveDynamicFields = "1";
			position = "49.000 94.000";
			size = "70.000 40.000";
			Layer = "1";
				mountID = "9";
		};
	};
}

This function is called from a sceneWindow2D::onLevelLoaded callback. The result is nothing but a load of errors on the console. I have no backgrounds right now, so I can't assume the graphics are hidden behind the background.

Those errors point to scenegraph functions (pickPoints getSceneTime, etc), from a class to which this scenegraph does not belong. More weird, if I quit the level and return to the editor, the errors continue.

I did not create a new sceneWindow because this has to have the mouse events. I think it will be easier to work with diferent scenewindows and simple load levels.

Reading the documentation provided me some hope... sceneWindow2D::setSceneGraph, which I used promptly, only to eliminate my original scenegraph and see this one.

I believe the question is: how to add the scenegraph on top of the other? Any hints?
#8
03/27/2007 (12:32 pm)
Ricardo, a single scene window can only have a single scene graph ... therefore, to utilize multiple scene graphs, you must have multiple scene windows
#9
03/28/2007 (1:10 am)
Ah! Ok then. In that case, menus are doable and nice, but hud system will have to be a addLevel of some sort. Since I would have the mouse events on the top scene window. It's a shame, this could be a nice idea.

Thank you for the help.
#10
03/28/2007 (9:36 am)
Ricardo, depending on your overall requirements, you could build a single mainScreen GUI that has multiple scenewindows, the scene windows do not have to be the full size of the screen ... so if you need a scene window in your HUD for any reason, you could easily do this, and still have mouse events triggered in the playing field ...

I have something similiar planned, for the Dungeon Builder ... the UI, as seen in one of James Rozee posts ... will actually be 3 scene windows (so far) ... one scene window will be sized to fit into the viewable 'dungeon crawl' area where the dungeon is actually pseudo-rendered ... another scene window will be attached to the 'hud' to show a tile-layer that represents a flat version of the map ... and a third scene window will be used to display the character portraits and what not (to allow for particle effects on user-driven events, etc)

None of these scene windows will overlap ...
#11
03/28/2007 (10:14 am)
I see what you mean, but considering the actual hud and game board, and considering that there's a layer scheme implemented since the beggining of the project, it's more pratical in this specific case to simply create levels with the backgrounds, one level with the hud, and then simply add levels.

This allows us to have one background level per area, one hud for the whole game and one level file per level where the variables that are important to the gameplay of the level are dynamic fields of the scenegraph that is loaded. This allows to have background and hud with 2 lines of script, no matter if there are 1 or 1.000.000 levels.

I did this to test what was discussed in the thread. The main objective of more scene windows is the options menu exactly to take the the mouse events off the scene window where the game is running. What I was trying to achieve before understanding that there's a 1 to 1 relation between scene window and scene graph, was to "win" extra layers without worrying with what's background, foreground or hud. Think about it, if it worked was a no brainer layer management process. :)

Still, all of this was an important lesson that may prove very useful in the future and saved us several days of work once we start to do the level design.