0
\$\begingroup\$

I have a generic HTML5 Canvas GUI Button class and a Scene class. The Scene class has a method called createButton(), which will create a new Button with onclick parameter and store it in a list of buttons. I call createButton() for all UI buttons when initializing the Scene. Because buttons can appear and disappear very often during rendering, Scene would first deactivate all buttons (temporarily remove their onclick, onmouseover etc property) before each render frame. During rendering, the renderer would then activate the required buttons for that frame.

The problem is that part of the UI requires a variable number of buttons, and their onclick, onmouseover etc properties change frequently. An example is a buffs system. The UI will list all buffs as square sprites for the current unit selected, and mousing over each square will bring up a tooltip with some information on the buff. But the number of buffs is variable thus I won't know how many buttons to create at the start. What's the best way to solve this problem? P.S. My game is in Javascript, and I know I can use HTML buttons, but would like to make my game purely Canvas-based.

  1. Create buttons on-the-fly during rendering. Thus I will only have buttons when I require them. After the render frame these buttons would be useless and removed.
  2. Create a fixed set of buttons that I'm going to assume the number of buffs per unit won't exceed. During each render frame activate the buttons accordingly and set their onmouseover property.
  3. Assign a button to each Buff instance. This sounds wrong as the buff button is a part of the GUI which can only have one unit selected. Assigning a button to every single Buff in the game seems to be overkill. Also, I would need to change the button's position every render frame since its order in the unit's list of buffs matter.
  4. Any other solutions?

I'm actually quite for idea (1) but am worried about the memory/time issues of creating a new Button() object every render frame. But this is in Javascript where object creation is oh-so-common ({} mainly) due to automatic garbage collection. What is your take on this? Thanks!

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

1) is roughly what many games do. You don't need to create whole new objects each frame, but rather recycle a pool of the objects. You don't even need a Button object at all. If your buttons are in the usual kind of placement in most UIs, you can calculate the rectangle extents programatically during rendering. You simply need a DrawBuffButtons(list_of_buffs) function that draws each button in order, placing it appropriately. Your canvas mouse handler, upon a click or movement, can use a basic math expression to determine which button's bounds are hovered/clicked and set an integer appropriately (e.g. current_hover_index = index or use_buff(index) as appropriate). Absolutely no need for data, objects, or any runtime data to be kept arround. This is more generally known as an immediate mode GUI. There are potential issues with it, but it works for most in-game HUD stuff I've worked with (main menus and complex inventory screens and the like are another story).

If you want objects, just use a pool. Note that a fixed number of buttons probably works - do you really want to encourage or support units with 1000 buff buttons the user has to muck around with? Figure out what fits on your UI. Limit the buffs to that number. Now, the first button selects the first buff, second button the second buff, etc. No need to ever change event bindings. As the selected unit changes you just set the button names and enable/disable according to number in use.

Note that both approaches allow a little more intelligence in your buffs such as separating the different types (attack vs defense, hot-keyed vs open list, etc.) for the creation of a better UI, which you should concentrate on before worrying about architecture or performance issues you might not even ever have.

\$\endgroup\$
6
  • \$\begingroup\$ Your first approach is quite interesting but it still requires some form of position sharing between the renderer and the canvas mouse handler to do the calculations. I figure that if I need to share (x, y) coordinates and I have many other buttons placed, why not reuse the button code? That way my mouse handler can just do a loop through all the buttons to calculate current_hover_index. Your second approach sounds more like the (2) idea I have, initializing MAX_BUFFS buttons at the start and activating accordingly. You are right that event bindings do not need to change. :) \$\endgroup\$
    – Wakaka
    Oct 31, 2013 at 1:59
  • \$\begingroup\$ Also, I went to look into immediate mode GUI and found out that there is actually a huge debate out there about the favored mode here! To me, (1) sounds similar to immediate GUI, while (2) sounds like retained GUI. I have been doing (1) for quite some time, but since I'm creating a fresh set of buttons every frame, I would need to assign their event handlers, key shortcuts etc during rendering, which seems "ugly". Apparently this is a problem inherent with immediate GUIs. Now that I have read up a bit more, I'm leaning towards (2). Am I on the right train of thought here? \$\endgroup\$
    – Wakaka
    Oct 31, 2013 at 2:01
  • \$\begingroup\$ I think you're over-estimating how much data you need to retain. You don't need position sharing - you need a function. pos_x(index) { return 100 + 20 * index } sort of thing, but for both coordinates and the size. You don't need to bind event handles either - look a bit more closely at immediate mode GUIs frameworks, you usually just iterate over their callbacks more than once (draw, handle click, etc.). Too much to put in one comment. \$\endgroup\$ Oct 31, 2013 at 3:02
  • \$\begingroup\$ Oh, I see what you mean; you share the function instead. But doesn't that mean I need to call pos_x from both the renderer and the mouse handler? What if I need to check if a button exists? I need to perform the check on both the renderer and the mouse handler. In retained GUI it seems that I can just set the x,y,w,h values in the renderer if it exists and the button handler code will take care of the rest. I looked into Unity3D's GUI system - it appears that the OnGUI function handles the rendering AND logic and is called multiple times per frame; that's not a nice idea for a renderer... \$\endgroup\$
    – Wakaka
    Oct 31, 2013 at 5:23
  • \$\begingroup\$ @Wakaka: yup, you end up calling into it many times per frame. The idea is that you make it really fast so it doesn't matter. Given what a computer can do every per second on just a single core, you'd have to have some seriously wacky UI to run into any kind of real performance problem. Much, much bigger and heavier-weight games than yours have used immediate mode GUIs, not to mention massively bloatful Scaleform/Flash retained-mode GUIs. Do what you find easiest, not which you think is maybe most efficient. \$\endgroup\$ Oct 31, 2013 at 8:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .