How do I implement tool tips?
The first consideration is how you determine you need to generate the tooltip. There are fundamentally input two paths; the Input System (input layers, $INPUT, etc) and GUI Mouse Events (gui controls intercept input directly). Assuming your mouse input layer(s) pass the events to the $INPUT system node (as done in the _input_mouse script), it already performs call to a shared function (in any of the class methods for the node that implement it) notifying the node of the event (enter/leave). If you do not, then you would implement something similar in your mouse input layers directly.
Data Store and Communication
There are many options for the storage and communication of the data displayed in a tooltip, which you choose depends on what your needs as well as the type of object. For game objects (inventory), storing the information required for your tooltips in the spec (assuming you are using the spec system to represent your game objects) itself probably makes sense and only storing any delta from the spec on the item.
Depending on the size and frequency of data on instances of area assets (i.e. on a rock or tree), you might choose to replicate an object that stores that information or write a file for each area containing the data for all instances to the repository.
You might even choose to create a new spec oracle that handles tooltip information for all of your objects whether game objects or instances of area assets, reducing what the server has to transmit down to a single spec key.
Things to be mindful of:
- When and how do you need to communicate for your tooltips?
- on demand (i.e. request information from server each time) not ideal if frequently needed
- on login and cached locally
- connection to a specific area (i.e. pulling data from a local cache for area 1234)
- Remote Calls
- Local Repository Cache
- Is your Tooltip Data shared in common by many objects?
- This favors a spec or similar mechanic approach
- How much data and how frequently does the data change?
- assuming tooltip data does not change during gameplay then pulling data from the local repository cache is probably a good idea whether using the spec system or a file you write out to the repository
- If the size of the data is small, sending it on demand may not be totally wrong (and it is easy...:) )
The generic editing GUI might serve as a template for how you would implement your Tooltip GUIControl class. It uses DOM Reflection and dynamic analysis of a node to construct the generic node property editor interface. While your tooltip mechanics would not necessarily need something this complex, it does demonstrate many of the fundamental techniques you can use to query the classes of a node and gather data from their class method scripts. The code for the control is found primarily in the _GUINodePropertyEditorClassMethods script, and has a lot of additional classes used to construct the various editing cells for particular field types.
While I have not completed full documentation on this control, you can find a lot of information related to its use on the Spec Editor Control documentation page Spec Oracle Editor#The Spec Editor Control
How do I bind a class to a GUI?
First your class must be properly constructed:
- It must be of archetype GUICONTROL
- It must inherit from the class GUIControl (or one of its children)
Once properly constructed, you can either specify the class at the time you create the control
Or you can modify the XML after the fact for a control that already exists. Using the HeroScript Editor, open up the GUI XML file for your control (cntrl-shift-G or using the Menu File->Open->GUI XML). Modify the XML to specify your class.
Compile and submit the GUI XML, and your control will now be created using your class and will receive the onControlBuild() event call.
Do HeroEngines GUI Labels support foreign characters?
Yes, provided you have set the Label to use a font that supports the characters.
Does HeroEngine have a C# like drag and drop interface to create a GUI?
Not quite identical, but it is modeled after C#'s UI. Creating a class is only necessary when you are building up your library of controls or need to implement specialized behavior for a control. For example, the Hero's Journey team has already built the basic controls for their game and I can create a new window based on their basic window.
While we do not have drag and drop for adding new controls(yet), you can select any existing control from the Organizer Panel's GUI XML tab and double-click it to add after first selecting the parent control of which you wish it to be a child. I did this by clicking in the center of this window, if you have the properties panel open you will see that the treeview highlights the control I selected (optionally you can select a control using the treeview).
Once I have selected the parent for my new control, I can double-click the control I want to add in the Organizer Panel's GUI XML tab to add it. I selected the control "HJ_Label" adding it to the client area control. Then I moved it to the center, setting the text property to say "Hello World".
This is of course a very simple example, for a game you almost always end up with a mix of dynamically generated UI and this more statically defined "prototype". Our UI is backed by HeroScript and you have (of course) the capability of dynamically generating and modifying the controls on the fly using the same scripting language you use to build the game.
Alternatively, HeroEngine supports a 3rd party UI solution called Scaleform GFx which (if you choose to license their technology) allows you to author your UI in Flash using the IDE of your choice and then use those Flash UIs in the game.
How do I build a GUI control that performs dynamic setup during the onControlBuild() method?
For complex controls that have dynamic setup via the onControlBuild() it is often useful to create game specific controls, with game specific classes (of archetype GUIControl and optionally leveraging the clean engine behaviors by inheriting from the corresponding classes). Allowing you to override the default implementations of the GUIControls included in the MMO Foundation Framework to achieve game specific behaviors. Hero's Journey does exactly this for many of its game GUIs, you can look at HJ_BaseWindowClassMethods in the Reference world as an example.
The quickest way to do this is working directly with the HeroScript Editor and the xml files (you can open them just like a script).
- Create a class MY_Window with an archetype GUIControl and a parent class of _GUIBaseWindow. There are methods in here you will want to override to create your own custom controls instead of the clean engine versions. In particular _allowWindowToScroll() creates the appropriate vertical and/or horizontal scroll bars during the build of the window control.
- Copy the structure of the clean engine _window gui prototype to serve as the template for your new window
- I would recommend you do this using the HeroScript Editor to open the xml file _cleanenginebasewindow.xml, copy lines 50-63 (the xml for the _window prototype).
- Create a new xml file (MY_Window.xml) using the HeroScript Editor, paste in the copied xml
- Copy the structure of the clean engine base scrollbar controls (_cleanenginebasescrollbar.xml), and paste it into a new MYBaseScrollbar.xml file
- For any of these controls you may want to override their behaviors, you will again create a MY_ class of archetype GUIControl and inherit from the clean engine class. Replace class='GUIPanel' with your new class='MY_GUIPanel' (for example) in the xml to have it use your game specific class for the control.
- Do a search and replace to change _scrollbar to MY_Scrollbar, repeat for each of the prototypes found in the xml you copied (in both files)
- Please note, it may be that you do not need to create game specific controls for all of the controls found in the _cleanenginebasescrollbar.xml file. It just depends on what you want to do.
- Compile and submit your xml files
- Once your controls are created, you can use the GUI Editor to modify their look/feel such as the textures they use.
This is of course represents a bit of work if you try to think about doing all of the controls at once, but over time you will build up a library of game specific GUIControls (such as MY_Scrollbar and MY_Window) that you can use when creating new GUI just like you have been doing using the clean engine controls up until this point.
You could of course use the GUI Editor to create each of your controls, but when working with a mass of controls I find working in the XML is faster. Please let me know if you need any clarifications or if you want to bounce what you intend to do with your GUI off one of our GUI experts. :)
When creating an inherited control can I delete existing elements?
The way inherited controls work is that you are allowed to modify the properties of existing elements and add new elements but you can not delete existing elements.
How do I create a custom GUI class?
There are basically two ways you might choose to do things in a more OO manner. The first is at the control level, and the second is handling it somewhere in a parent control. The basic technique remains the same for each:
- Create a new client class with an archetype of GUIControl (ex. GUICwiss)
- Add a parent class which has ultimately as a parent the class GUIControl
- Create a client class method script for your gui class (ex. GUICwissClassMethods )
The archetype GUIControl tells the engine to use an underlying "ghost" class to provide some very basic C++ functionality (for example, fowarding keyboard/mouse input). Additionally, new GUI control classes must have (ultimately) the class GUIControl as a parent (either by virtue of inheriting directly or from one of its children).
Events generated by C++ make calls into the class methods script for your GUIControl many examples of which you can find located in the class method script for the base control such as _GUIButton, GUIControlClassMethods, GUIRadioButton etc. The way we have implemented many of the basic controls is that they turn the generic input event (such as OnMouseClick()) into a more specific event that they forward up to their parents (for example _onButtonMouseClick()).
The advantage to the more specific events is that instead of making a new gui class for ever single control, you can instead make one for the ultimate parent (often a window/panel) which then handles the events for all of its children controls. These specific events are declared in the _GUIMethodCallbacksClassMethods Script.
Once you have created your class, you will need to create the XML (via the GUIEditor) for a new control that uses your class.
How do I automatically assign key focus to the chat window when the user types a specified character?
We do something similar to what you describe with our game chat window. Our command layer has defined the "enter" and "/" commands, which when caught by the HJInput_Command script use the external function SetKeyboardFocus() to give our game GUI chat window's text input box keyboard focus. So long as the game chat window has focus, keyboard commands are intercepted and interpreted by the GUI instead of the input system. A mouse click in the empty area of the render window will return focus to the game so that input is once again passed to the input system.
As long as a GUI control has focus, any events related to keyboard/mouse are passed to it instead of the input system (gui's can be made transparent to the mouse). I believe using a GUI Control like this will be preferable to you over attempting to use a command layer/the input system.
How do I delete controls from the GUI Editor?
Deleting controls in the GUI Editor is not the same as deleting the GUI Control Prototype that you created, this is the reason you still see your test control in the organizer. To delete the GUI Control Prototype, simply use the Script Editor to open the xml file for your GUI Control Prototype.
Once you have the file open, you can delete it by using the Delete Script Option located in the Tools menu.
In the case of xml files that contain multiple controls, you simply edit the xml directly to remove the specific GUI Control Prototype that you no longer need.