[RESOLVED] T2DSceneObjects as HUD elements
by Ron Barbosa · in Torque X 2D · 04/21/2010 (9:01 pm) · 28 replies
Hey all...I'm using some plain old scene objects to make up the gauges and meters of my HUD. Can anyone recommend a good way to keep them in a static position on the screen (IE always in the upper left corner)?
I tried mounting them to the player, but I can't set the offset in TXB.
Any help would be appreciated...thanks!
--RB
I tried mounting them to the player, but I can't set the offset in TXB.
Any help would be appreciated...thanks!
--RB
#2
I guess I was hoping for some "trick" that was built into the engine for this type of thing.
Thanks again!
--RB
04/22/2010 (4:01 am)
Thanks, William. I guess I'll write a HUD component that tracks the camera's original size (my camera changes size) and scales/positions the HUD components as a function of the current position and the original size.I guess I was hoping for some "trick" that was built into the engine for this type of thing.
Thanks again!
--RB
#3
You can then load a scene and put it in the new scene view (i.e. set the sceneview's camera to the the hud scene camera).
IMPORTANT: make sure that all the objects in the scene for the hud have the correct scenegraph set or they will just get added to the main scene like before! (if you're using the modded version of the engine from the SVN then you should be fine so long as you have renamed the scenegraphs for any scenes already loaded before you loaded the hud scene - otherwise you will need to loop through the scene objects and set their scenegraph to the right one). Also make sure the scene's camera has the right scenegraph reference too.
04/22/2010 (5:17 am)
You can achieve this with multiple GUISceneview instances. Each view can have it's own camera. To add an extra scene view to the canvas simply set the scene view's folder...myHudView.Folder = GUICanvas.Instance;
You can then load a scene and put it in the new scene view (i.e. set the sceneview's camera to the the hud scene camera).
IMPORTANT: make sure that all the objects in the scene for the hud have the correct scenegraph set or they will just get added to the main scene like before! (if you're using the modded version of the engine from the SVN then you should be fine so long as you have renamed the scenegraphs for any scenes already loaded before you loaded the hud scene - otherwise you will need to loop through the scene objects and set their scenegraph to the right one). Also make sure the scene's camera has the right scenegraph reference too.
#4
=P
Have you just been ripping into the engine or do have some magic tome of tutorials that you aren't sharing with the class? ;)
Thanks again...I'll give this a shot...although I'll admit I'm not 100% sure how all of this works or how to implement it.
I'll dig through it, though...thanks.
--RB
04/22/2010 (5:34 am)
@Duncan...you're about as knowledgeable as anyone I've seen around here when it comes to the TX products...out of curiosity...where do you get this information?=P
Have you just been ripping into the engine or do have some magic tome of tutorials that you aren't sharing with the class? ;)
Thanks again...I'll give this a shot...although I'll admit I'm not 100% sure how all of this works or how to implement it.
I'll dig through it, though...thanks.
--RB
#5
GUICanvas and GUISceneview: the GUICanvas is a Folder so you can add as many sceneviews to it as you like. Torque defaults to just one active sceneview, but you can add more. Each sceneview should reference a camera. And each sceneview's camera should reference a scenegraph. So each sceneview will draw the objects in that scenegraph using that camera. (technically you could even render the same scenegraph twice in different sceneviews - e.g. for a splitscreen feature).
Much fun is to be had with multiple sceneviews and scenes :)
04/22/2010 (6:05 am)
lol :) No I don't have any hidden tomes. I used to be in professional game dev full time though before I turned freelance. And I do have a substantial in-house framework that extends Torque X. A side effect of developing that was a greater knowledge of the engine.GUICanvas and GUISceneview: the GUICanvas is a Folder so you can add as many sceneviews to it as you like. Torque defaults to just one active sceneview, but you can add more. Each sceneview should reference a camera. And each sceneview's camera should reference a scenegraph. So each sceneview will draw the objects in that scenegraph using that camera. (technically you could even render the same scenegraph twice in different sceneviews - e.g. for a splitscreen feature).
Much fun is to be had with multiple sceneviews and scenes :)
#6
To add your hud sceneview you would do the following:
Also note that if a sceneview is not on the canvas then, of course, it won't be rendered. Useful if you want to 'hide' a sceneview, but not delete it or it's contents.
04/22/2010 (6:13 am)
Here's a little class I use to manage sceneview layering more intuitively.using System;
using System.Collections.Generic;
using System.Text;
using GarageGames.Torque.GUI;
using GarageGames.Torque.Core;
namespace A.Namespace
{
/// <summary>
/// Provides methods to insert GUISceneView instances in a controlled layered way on the
/// GUICanvas.
///
/// NOTE: if comparing this with the what GUICanvas calls 'front' and 'back' be warned that
/// GUICanvas is referring to positions in a list and not positions as they appear on a display
/// (the exact opposite infact).
/// </summary>
public class SceneViewLayering
{
public enum EnumAbsolutePosition { Front, Back };
public static void InsertInfrontOf(GUISceneview viewToInsert, GUISceneview viewToInsertInfrontOf)
{
viewToInsert.Folder = GUICanvas.Instance;
if (viewToInsertInfrontOf != null)
{
GUICanvas.Instance.ReOrder(viewToInsertInfrontOf, viewToInsert);
}
}
public static void InsertBehind(GUISceneview viewToInsert, GUISceneview viewToInsertBehind)
{
viewToInsert.Folder = GUICanvas.Instance;
GUICanvas.Instance.ReOrder(viewToInsert, viewToInsertBehind);
}
public static void InsertInfrontOf(GUISceneview viewToInsert, EnumAbsolutePosition positionToInsertInfrontOf)
{
InsertInfrontOf(viewToInsert, GetViewAt(positionToInsertInfrontOf));
}
public static void InsertBehind(GUISceneview viewToInsert, EnumAbsolutePosition positionToInsertBehind)
{
InsertBehind(viewToInsert, GetViewAt(positionToInsertBehind));
}
public static void Remove(GUISceneview view)
{
view.Folder = TorqueObjectDatabase.Instance.RootFolder;
}
protected static GUISceneview GetViewAt(EnumAbsolutePosition position)
{
if (GUICanvas.Instance.GetNumObjects() == 0) return null;
switch (position)
{
case EnumAbsolutePosition.Front:
return GUICanvas.Instance.GetObject(GUICanvas.Instance.GetNumObjects() - 1) as GUISceneview;
case EnumAbsolutePosition.Back:
return GUICanvas.Instance.GetObject(0) as GUISceneview;
default:
Assert.Fatal(false, "Unrecognized position: " + position);
return null;
}
}
}
}To add your hud sceneview you would do the following:
SceneViewLayering.InsertInfrontOf(myHudView, SceneViewLayering.EnumAbsolutePosition.Front);
Also note that if a sceneview is not on the canvas then, of course, it won't be rendered. Useful if you want to 'hide' a sceneview, but not delete it or it's contents.
#7
Or do you have the HUD in its own .txscene file?
Sorry...for the ignorance...I've been so wrapped up in getting MY code to work for my prototype, that I haven't really taken many opportunities to open up the TX code and really dig into it.
Just as a side note...I am in fact running the modified TX from the online svn repo. I'm mostly up to date, but I have not yet picked up the async scene loader.
Thanks again!
--RB
04/22/2010 (6:21 am)
And all of the sceneviews are part of the same .txscene file? Is that how this works? So I'd be building out my HUD in each level file (which is fine...if not ideal).Or do you have the HUD in its own .txscene file?
Sorry...for the ignorance...I've been so wrapped up in getting MY code to work for my prototype, that I haven't really taken many opportunities to open up the TX code and really dig into it.
Just as a side note...I am in fact running the modified TX from the online svn repo. I'm mostly up to date, but I have not yet picked up the async scene loader.
Thanks again!
--RB
#8
e.g.
1. Load level scene
2. Load hud scene
3. Create a sceneview for the hud
4. Set the hud view to use the hud scene (see prev posts)
5. Add the hud view to the canvas
Creating a new sceneview is as simple as:
04/22/2010 (6:53 am)
I would put the hud in its own .txscene file. e.g.
1. Load level scene
2. Load hud scene
3. Create a sceneview for the hud
4. Set the hud view to use the hud scene (see prev posts)
5. Add the hud view to the canvas
Creating a new sceneview is as simple as:
GUISceneview myHudView = new GUISceneview(); myHudView.Name = "HudView"; myHudView.Style = new GUIStyle();
#9
Thanks for the clarification. Presumably all objects in both the HUD scene and the level scene are accessible to one another.
So as I perform my tick processing that manages the levels in my gauges, my player object (which holds the meter value) can query the object database for the gauge object (by name or whatever) and set the meter value (even though the gauge is defined in a different .txscene file).
Good information and guidance...this is gonna help me out hugely!
Thanks again!
--RB
04/22/2010 (7:02 am)
I see...that's much more elegant than the solution I thought I would have to implement.Thanks for the clarification. Presumably all objects in both the HUD scene and the level scene are accessible to one another.
So as I perform my tick processing that manages the levels in my gauges, my player object (which holds the meter value) can query the object database for the gauge object (by name or whatever) and set the meter value (even though the gauge is defined in a different .txscene file).
Good information and guidance...this is gonna help me out hugely!
Thanks again!
--RB
#10
04/22/2010 (8:18 am)
Yes, the database allows you to access objects as you normally would regardless of which scenegraph or sceneview they are in.
#11
mount to camera:
create component with input for vector2 (this will be the offset of the hud element).
_sceneObject.position = bla bla bla camera.position + whatever u called the vector2 offset from the component.
...maybe add the display layer you want, to be entered into the component as well.
not the most elegant. but damn if its not easy to manage. :P
04/22/2010 (3:46 pm)
...or there's the easy and dirty method.mount to camera:
create component with input for vector2 (this will be the offset of the hud element).
_sceneObject.position = bla bla bla camera.position + whatever u called the vector2 offset from the component.
...maybe add the display layer you want, to be entered into the component as well.
not the most elegant. but damn if its not easy to manage. :P
#12
04/22/2010 (4:28 pm)
Ron's camera also changes size, which complicates things a bit more. Once you get the hang of working with multiple sceneviews though, it's actually a lot simpler than it sounds :)
#13
At any rate...I've resolved most of the items on my weekend "to-do" list for my game, and it's not even Friday night yet...so I'm ahead of myself so far. I think I'll take the time to learn to use the multiple sceneviews this weekend.
Thanks for the help, gents!
--RB
04/23/2010 (4:45 am)
@Steve...I'm all for "easy if not elegant," but Duncan's right. My camera will change size, and I think it's a worthwhile exercise to learn how to work with multiple sceneviews.At any rate...I've resolved most of the items on my weekend "to-do" list for my game, and it's not even Friday night yet...so I'm ahead of myself so far. I think I'll take the time to learn to use the multiple sceneviews this weekend.
Thanks for the help, gents!
--RB
#14
I did have a couple of concerns. First, there is a bug in TXB that does not save the camera name to the .txscene file. So I think I will always have a conflict in the Torque object DB while searching for my camera since both the play scene and the HUD scene will both have a camera called "Camera" is this a correct assumption?
I've verified that if I do this:
Immediately after loading my HUD, then immediately again after loading my scene, I get 2 different camera objects (each with the respective settings of the HUD and play cameras.
Secondly...I can see my HUD...but the play field is blank.
I think I may have a problem with the sequence I'm using to load the level and HUD. You recommended level first, HUD later...but that triggers an assertion failure in my current setup (because my level has direct references to objects that I have now moved to my HUD scene).
Let me play around with that...but if you have any guidance for the camera name thing, that would be great.
[EDIT] I think it may be that the screen clearing color for my HUD needs to be set to something other than black. I need a transparent clearing color (I think). Let me find where that gets set.
Thanks
--RB
04/24/2010 (7:58 am)
@Duncan...if you're still following this thread, I'm working on using multiple scene views. Haven't gotten it down yet, but I've made some "progress."I did have a couple of concerns. First, there is a bug in TXB that does not save the camera name to the .txscene file. So I think I will always have a conflict in the Torque object DB while searching for my camera since both the play scene and the HUD scene will both have a camera called "Camera" is this a correct assumption?
I've verified that if I do this:
camera = TorqueObjectDatabase.Instance.FindObject<T2DSceneCamera>("Camera");Immediately after loading my HUD, then immediately again after loading my scene, I get 2 different camera objects (each with the respective settings of the HUD and play cameras.
Secondly...I can see my HUD...but the play field is blank.
I think I may have a problem with the sequence I'm using to load the level and HUD. You recommended level first, HUD later...but that triggers an assertion failure in my current setup (because my level has direct references to objects that I have now moved to my HUD scene).
Let me play around with that...but if you have any guidance for the camera name thing, that would be great.
[EDIT] I think it may be that the screen clearing color for my HUD needs to be set to something other than black. I need a transparent clearing color (I think). Let me find where that gets set.
Thanks
--RB
#15
You can get the camera for a scene directly via the scene data object that SceneLoader.Load() returns. And while you're there you can get the scenegraph too (as you noted, querying the database is less than helpful when the objects have default naming applied by tx).
Do that for each level you load into a new sceneview and things should be alot better. Also don't forget to add the sceneviews to the canvas (see prev posts).
04/24/2010 (8:10 am)
Order of loading the scenes doesn't matter for the sceneview thing. Sounds like you either don't have a second scene view set up or the camera is not set on it properly or the scenegraph is not set on the camera properly. That kind of thing - just a little missing link.You can get the camera for a scene directly via the scene data object that SceneLoader.Load() returns. And while you're there you can get the scenegraph too (as you noted, querying the database is less than helpful when the objects have default naming applied by tx).
TorqueSceneData sceneData = Game.Instance.SceneLoader.Load(mylevel);
T2DSceneGraph sceneGraph = (T2DSceneGraph)sceneData.SceneData.Find(delegate(object obj) { return obj is T2DSceneGraph; });
T2DSceneCamera camera = T2DSceneCamera)sceneData.SceneData.Find(delegate(object obj) { return obj is T2DSceneCamera; });
camera.SceneGraph = sceneGraph;
mySceneView.Camera = camera;Do that for each level you load into a new sceneview and things should be alot better. Also don't forget to add the sceneviews to the canvas (see prev posts).
#16
I don't normally worry about setting the sceneGraph and Camera (I guess TX does that by default). So if I'm reading you correctly, because I have more than one loaded scene, I need to manually set the sceneGraph and Camera for each?
Thanks again for all your help here.
--RB
04/24/2010 (8:19 am)
Thanks again, Duncan. I think I may have oversimplified it just a bit. Here's my BeginRun method:protected override void BeginRun()
{
base.BeginRun();
GuiPlay playGUI = new GuiPlay();
GUICanvas.Instance.SetContentControl(playGUI);
// Set up the HUD
TorqueSceneData hud = SceneLoader.Load(@"data\levels\hud.txscene");
GUISceneview hudSceneView = new GUISceneview();
hudSceneView.Name = "HudView";
hudSceneView.Style = new GUIStyle();
hudSceneView.SceneData = hud;
// Load the scene data
Game.Instance.SceneLoader.Load(@"data\levels\levelData.txscene");
// Set the camera up
T2DSceneCamera camera = TorqueObjectDatabase.Instance.FindObject<T2DSceneCamera>("Camera");
camera.FarDistance = 5000.0f;
// Attach the HUD
hudSceneView.Folder = GUICanvas.Instance;
// Mount the camera to the player
T2DSceneObject player = TorqueObjectDatabase.Instance.FindObject<T2DSceneObject>("mainPlayer");
// Ensure that both exist
if (player != null && camera != null)
{
camera.Mount(player, "", false);
camera.TrackMountRotation = false;
}
}I don't normally worry about setting the sceneGraph and Camera (I guess TX does that by default). So if I'm reading you correctly, because I have more than one loaded scene, I need to manually set the sceneGraph and Camera for each?
Thanks again for all your help here.
--RB
#17
FYI: you don't need to to put hudSceneView.SceneData = hud; (this is an async loading thing that you don't need to bother with here)
04/24/2010 (9:28 am)
Yes, that's right - you need to set up the scenegraph/camera/sceneview stuff yourself, for each scene file that you load. It's best to make sure all the details are in place than rely to tx to guess right. Try the following modified version:protected override void BeginRun()
{
base.BeginRun();
GuiPlay playGUI = new GuiPlay();
GUICanvas.Instance.SetContentControl(playGUI);
// Set up the HUD
TorqueSceneData hud = SceneLoader.Load(@"data\levels\hud.txscene");
GUISceneview hudSceneView = new GUISceneview();
hudSceneView.Name = "HudView";
hudSceneView.Style = new GUIStyle();
T2DSceneGraph hudSceneGraph = (T2DSceneGraph)hud.SceneData.Find(delegate(object obj) { return obj is T2DSceneGraph; });
T2DSceneCamera hudCamera = (T2DSceneCamera)hud.SceneData.Find(delegate(object obj) { return obj is T2DSceneCamera; });
hudCamera.SceneGraph = hudSceneGraph;
hudSceneView.Camera = hudCamera;
// Load the scene data
TorqueSceneData playSceneData = Game.Instance.SceneLoader.Load(@"data\levels\levelData.txscene");
T2DSceneGraph playSceneGraph = (T2DSceneGraph)playSceneData.SceneData.Find(delegate(object obj) { return obj is T2DSceneGraph; });
T2DSceneCamera playCamera = (T2DSceneCamera)playSceneData.SceneData.Find(delegate(object obj) { return obj is T2DSceneCamera; });
playCamera.SceneGraph = playSceneGraph;
playGUI.Camera = playCamera;
// Set the camera up
playCamera.FarDistance = 5000.0f;
hudCamera.FarDistance = 5000.0f;
// Attach the HUD
hudSceneView.Folder = GUICanvas.Instance;
// Mount the camera to the player
T2DSceneObject player = TorqueObjectDatabase.Instance.FindObject<T2DSceneObject>("mainPlayer");
// Ensure that both exist
if (player != null && playCamera != null)
{
playCamera.Mount(player, "", false);
playCamera.TrackMountRotation = false;
}
}FYI: you don't need to to put hudSceneView.SceneData = hud; (this is an async loading thing that you don't need to bother with here)
#18
The last artifact that I'm not sure how to manage is comes from lines 5 & 6 above.
This is part of the out-of-the-box T2D Starter Project with GUI. They create a small text overlay with Score, Health, etc. This is appearing BEHIND my main scene data.
Once I can resolve that, I'll be done. Not sure how this plays in, because it's not a txscene file, so it doesn't have a scene view or camera (to my knowledge).
[EDIT] We must have posted at the same time. My updated versions looks nearly identical to your edits. In my updated version I had attached "playGUI" to the HUD camera. Now I have it attached to the level camera and all is right with the world! Thanks again!
--RB
04/24/2010 (9:28 am)
OK...99.9% of the way there by manually managing the scene graphs and cameras. Thanks, Duncan.The last artifact that I'm not sure how to manage is comes from lines 5 & 6 above.
This is part of the out-of-the-box T2D Starter Project with GUI. They create a small text overlay with Score, Health, etc. This is appearing BEHIND my main scene data.
Once I can resolve that, I'll be done. Not sure how this plays in, because it's not a txscene file, so it doesn't have a scene view or camera (to my knowledge).
[EDIT] We must have posted at the same time. My updated versions looks nearly identical to your edits. In my updated version I had attached "playGUI" to the HUD camera. Now I have it attached to the level camera and all is right with the world! Thanks again!
--RB
#19
The thing to bear in mind is that there is no special treatment for the hud or the gameplay level scene. They are both just scene files being loaded and put in sceneviews. So mostly you just do the same thing for both. Unless you need something different, such as the Hud using a GuiPlay sceneview instead of a vanilla sceneview, it's pretty much all boiler plate stuff.
04/24/2010 (9:52 am)
Try this:protected override void BeginRun()
{
base.BeginRun();
// Set up the HUD
TorqueSceneData hud = SceneLoader.Load(@"data\levels\hud.txscene");
GuiPlay hudSceneView = new GuiPlay();
hudSceneView.Name = "HudView";
hudSceneView.Style = new GUIStyle();
T2DSceneGraph hudSceneGraph = (T2DSceneGraph)hud.SceneData.Find(delegate(object obj) { return obj is T2DSceneGraph; });
T2DSceneCamera hudCamera = (T2DSceneCamera)hud.SceneData.Find(delegate(object obj) { return obj is T2DSceneCamera; });
hudCamera.SceneGraph = hudSceneGraph;
hudSceneView.Camera = hudCamera;
// Setup the level
TorqueSceneData levelSceneData = Game.Instance.SceneLoader.Load(@"data\levels\levelData.txscene");
GUISceneview levelSceneView = new GUISceneview();
levelSceneView.Name = "LevelView";
levelSceneView.Style = new GUIStyle();
T2DSceneGraph levelSceneGraph = (T2DSceneGraph)levelSceneData.SceneData.Find(delegate(object obj) { return obj is T2DSceneGraph; });
T2DSceneCamera levelCamera = (T2DSceneCamera)levelSceneData.SceneData.Find(delegate(object obj) { return obj is T2DSceneCamera; });
levelCamera.SceneGraph = levelSceneGraph;
levelSceneView.Camera = levelCamera;
// Set the cameras up
levelCamera.FarDistance = 5000.0f;
hudCamera.FarDistance = 5000.0f;
// Add the HUD and the level to the canvas
levelSceneView.Folder = GUICanvas.Instance;
hudSceneView.Folder = GUICanvas.Instance;
// Mount the camera to the player
T2DSceneObject player = TorqueObjectDatabase.Instance.FindObject<T2DSceneObject>("mainPlayer");
// Ensure that both exist
if (player != null && levelCamera != null)
{
levelCamera.Mount(player, "", false);
levelCamera.TrackMountRotation = false;
}
}The thing to bear in mind is that there is no special treatment for the hud or the gameplay level scene. They are both just scene files being loaded and put in sceneviews. So mostly you just do the same thing for both. Unless you need something different, such as the Hud using a GuiPlay sceneview instead of a vanilla sceneview, it's pretty much all boiler plate stuff.
#20
You're awesome, Duncan...thanks for your help. It's working fine now.
--RB
04/24/2010 (10:00 am)
Save the sequence of some of the steps...this version looks exactly like mine.You're awesome, Duncan...thanks for your help. It's working fine now.
--RB
Torque Owner William McDonald
Suckerfree Games