An important project I struck out on this semester was the creation of a component-based UI system portable to other platforms. I wanted to create something that scaled nicely and allowed artists to create beautiful layouts without having to write a line of code. This worked out very well and has become one of the standout systems in my framework.
There were several important points I wanted to hit on with my UI system. I wanted the system to be flexible enough to be portable to any other backend. That is, I wanted something that didn't rely on platform-specific code to work. While obviously the actual rendering is handled on a per-platform basis, the API had to abstract this out. Additionally, I wanted to achieve some level of resolution-independence, particularly for mobile platforms. Positions needed to be specified such that things could be anchored to the sides of the screen without writing code manually positioning it relative to screen size. All this was intended to decrease the amount of time I spent re-implementing common structures across UI forms and create something that made it easier for designers and artists to create content without an engineer.
My objectives, for the most part, were met. I created a coordinate system composed of two parts - screen-relative and pixel offset - that allowed things to be positioned and sized uniformly across multiple devices and screen resolutions. Retrieving the absolute position on the screen is as easy as multiplying the screen position by the UI size and adding on the pixel offset. This made, for example, corners much easier to deal with.
I implemented a UI stack system which allowed forms to animate in a generic manner as well block touches to lower forms, which made the creation of message boxes much simpler. Forms are depth-sorted, and elements from top forms can block touches to lower forms, allowing touchable elements to occlude deeper elements and prevent unwanted touches. The animation system gives a generic way of making opening and closing animations for forms, allowing elements to slide, scale, and fade in a customizable manner. This added a nice layer of polish to the game, particularly when we added easing functions.
Additionally, I created several common controls, including buttons, checkboxes, and radio buttons. Finally, I implemented a slick tweening system, which allows each individual element to be rotated, positioned, scaled, rotated, faded, and color-shifted at will with very little code. This is built on top of one of my existing value tweening systems and required a bit more work to implement without using expensive lambdas, considering that tweens of certain types were not allowed to overlap - I couldn't, for example, have two position tweens running on the same element without unwanted behavior. Finishing this system added a nice layer of polish, giving us flashing UI elements, arrows that scale, buttons that pop up, and selection icons that shift around the map instead of teleporting. The visual benefits of this system are immediately obvious and well worth the effort to implement.
After finishing this project, I've concluded that having a dedicated UI system helps cut down on redundant development time. I created a system early on that made creating forms a five-minute process instead of a thirty-minute process, and while creating the system took time, the effort was worth it. It also gave my Production game much more visual polish. Another important lesson was that building this system does not necessarily mean that artists and designers will actively work with it. I did not spend enough time introducing it to the people it was intended for, which led to me spending more time than I would like on the layouts instead of dedicated UI people.
No comments:
Post a Comment