Skip to content

Complex UI (part 1)

alerdenisov edited this page Jan 20, 2017 · 6 revisions
Prev: Simple UI

How to make complex UI with ReUI

ReUI designed as components based UI framework such as React, Angular, Vue and etc from web-development. This means that we are focused on providing tools to reuse components much as possible. Let's make complex UI together to understand how it works.

Inventory UI

I prepared UI screen for next few pages. It's complex and real one screen from MMORPG project. Let's take a look on screen below:

As you can see here is a lot of elements. But a lot of them same. Lets divide whole UI to separate components:

  • Item grid — holds list of items slots in some rows and cols
  • Item slot — interactive place to show Item data
  • Panel — wraps content in nice looking gray box
  • Tabs group — display group of buttons in border and bunch of not so expected such as:
  • Render texture — shows render texture inside UI
  • Close button — custom button (shows as cross)
  • Header — header component
  • Key value line — shows two labels with opposite anchors and maybe much more (I'm too lazy to think too much, let's start building and decide in process)

Define first reusable component

Item slot is great point to start. First at all, change our bootstrap to show InGame window and declare simple one:

<?xml version="1.0" encoding="utf-8" ?>
<Root Name="In Game UI">
  <ItemSlot></ItemSlot>
</Root> 

<ItemSlot /> tag says ReUI to inject custom xml inside our hierarchy. ReUI will ask IContentProvider about xml with name ItemSlot and parse that. Sure, we should declare it before go, just for start make a red rectangle:

<?xml version="1.0" encoding="utf-8" ?>
<Root Name="Item slot">
  <!-- Color is rectangle component allow to be filled with some color -->
  <Color Color="#FF0000" Anchor="Stretch"></Color>
</Root> 

If you will play it nothing to appear, isn't? This is because our <ItemSlot /> have zero size. Change InGame.xml a little bit to resize our <ItemSlot /> and create few more.

<?xml version="1.0" encoding="utf-8" ?>
<Root Name="In Game UI">
  <ItemSlot Size="42, 42" Position="20, -20"></ItemSlot>
  <ItemSlot Size="42, 42" Position="20, -70"></ItemSlot>
  <ItemSlot Size="42, 42" Position="20, -120"></ItemSlot>
  <ItemSlot Size="60, 60" Position="20, -170"></ItemSlot>
</Root> 

Not so cool as we want, but already something. Time to change our ItemSlot.xml to shows nice looking rectangles.

Work with resources

Because ReUI know nothing about your content (and doesn't care) anything such as sprites is asking from IContentProvider and believe to obtain sometime in future. Then resource asked by <Image /> tag ReUI understand only UnityEngine.Sprite is fit as only UnityEngine.Font for <Text />. Detailed information can be found in IContentProvider section of docs.

In our case let's use simple ResourcesContentProvider and saves our sprites somewhere inside Resources folder as we did with fonts before.

Icons can be download from opengameart.org

Get down to change ItemSlot.xml:

<?xml version="1.0" encoding="utf-8" ?>
<Root Name="Item slot">
  <Image Resource="skin/slot-border"
         Anchor="Stretch" 
         Size="14,14" 
         Mode="Sliced"
         Pivot="MiddleCenter">
  </Image>
  <Image Resource="icons/axe" 
         Anchor="Stretch">
  </Image>
</Root> 

We added Anchor, Pivot, Mode, Size with unxpected values. It's a part of Anchoring in ReUI and uncover in special section... right now relax and have fun! Just take a look how gorgeous our UI already:

Using Lua to populate properties

How about different item icons? Here is Lua joins the battle! Go back to our InGame.xml and write a little bit Lua code:

<?xml version="1.0" encoding="utf-8" ?>
<Root Name="In Game UI">
  <ItemSlot Size="42, 42" Position="20, -20">
    return {
      icon = 'icons/coin',
      name = 'Gold',
      amount = '1k',
      properties = {
        { key = 'Amount', value = '1 543' }
      }
    }
  </ItemSlot>
  <ItemSlot Size="42, 42" Position="20, -70">
    return {
      icon = 'icons/scroll',
      name = 'Recal scroll',
      properties = {
        { key = 'Magery requirement', value = '60%' }
      }
    }
  </ItemSlot>
  <ItemSlot Size="42, 42" Position="20, -120">
    return {
      icon = 'icons/potionRed',
      name = 'Healing potion',
      amount = '32',
      properties = {
        { key = 'Exceptional', color = '#FFFF00' },
        { key = 'Health restore', value = '30' },
        { key = 'Coldown', value = '5 sec' }
      }
    }
  </ItemSlot>
  <ItemSlot Size="60, 60" Position="20, -170">
    return {
      icon = 'icons/axe',
      name = 'Battle axe',
      properties = {
        { key = 'Damage', value = '15—20' },
        { key = 'Damage Increase', value = '15%', color = '#00FFFF' },
        { key = 'Strength requirement', value = '70' }
      }
    }
  </ItemSlot>
</Root> 

Blah.. a lot of them. But what are you want? Here is game development. Sure nothing changes yet, we should handle received props in ItemSlot:

<?xml version="1.0" encoding="utf-8" ?>
<Root Name="Item slot">
  <OnProps>
    state.icon = props.icon
    state.amount = props.amount
  </OnProps>
  <Image Resource="skin/slot-border"
         Anchor="Stretch" 
         Size="14,14" 
         Mode="Sliced"
         Pivot="MiddleCenter">
  </Image>
  <Image Anchor="Stretch">
    <OnState>
      self:setResource(state.icon)
    </OnState>
  </Image>

  <Text Anchor="Stretch" 
        Margin="4,4" 
        FontSize="11" 
        Resource="fonts/marmelad" 
        Alignment="LowerRight">
    <OnState>
      self:setText(state.amount)
    </OnState>
  </Text>
</Root> 

There we go! Proper icons, amount and next is loop items