UnlockTree
UnlockTree in UIToolbox shows cards that unlock in order: a tech tree, a skill tree, a talent tree, research or a quest chain. Each child UnlockNode is a card at a column and a row. It names the ids of the cards that it requires. The tree computes the state of each card and draws a line from each requirement to its card.
Video tutorial: Skill tree. All videos: Video tutorials.
<tb:UnlockTree name="tech" column-width="160" row-height="76">
<tb:UnlockNode id="agriculture" title="Agriculture" cost="40 science" column="0" row="1" />
<tb:UnlockNode id="pottery" title="Pottery" cost="60 science" requires="agriculture" column="1" row="0" />
<tb:UnlockNode id="writing" title="Writing" cost="100 science" requires="pottery" column="2" row="0" />
<tb:UnlockNode id="mathematics" title="Mathematics" requires="writing, wheel" column="3" row="1" />
</tb:UnlockTree>
var tree = root.Q<UnlockTree>("tech");
tree.UnlockRequested += node =>
{
if (science < CostOf(node)) return;
science -= CostOf(node);
tree.Unlock(node.Id);
};
tree.Unlocked += node => Debug.Log(node.Title + " is done");
In the UI Builder, the tree shows a dashed cell at each column and row, labeled "Column 2, Row 1", with one free column and row past the last card. Set column and row on a card to the numbers of the cell where it goes. The cells do not show in Play mode or in a build.
States
| State | When | Look |
|---|---|---|
Locked |
A requirement is not unlocked. | Dim. A click plays the error sound and does nothing. |
Available |
All requirements are unlocked. | Accent border. A click or Submit raises UnlockRequested. |
Unlocked |
Unlock or SetUnlocked unlocked it. |
Green border and a check mark. The cost does not show. |
Hidden |
A secret card that is locked. |
It does not show, and its lines do not show. |
Blocked |
A card on another path is unlocked: one that it excludes, or one that excludes it. |
Faint, with a red border. A click plays the error sound. Its tooltip names the card that closed it. |
- A card with
requires="a, b"needs all ofaandb. - A card with
requires-any="a, b"needs one ofaandb. It can haverequirestoo. - A card with no requirements is
Availableat the start. - A card with
excludes="a"and the cardaare two paths: when one unlocks, the other isBlocked. One side is enough. - Each line has the state of its two cards:
Unlockedwhen the two are unlocked,Availablewhen only the requirement is unlocked,Hiddenwhen one is hidden,Blockedwhen one is blocked, elseLocked. The more complete lines draw on top.
Paths that exclude each other
A choice closes the other path. Give one of the two cards excludes:
<tb:UnlockNode id="guild" title="Join the guild" requires="blade" column="4" row="0" />
<tb:UnlockNode id="thieves" title="Join the thieves" requires="blade" excludes="guild" column="4" row="2" />
<tb:UnlockNode id="ending" title="Face the dragon" requires-any="guild, thieves" column="5" row="1" />
When the guild unlocks, the thieves card is Blocked, and BlockedBy(node) returns the guild card. A secret card on the closed path stays Hidden.
Unlock
A click, Enter or the gamepad submit on a card raises NodeClicked. When the card is Available and CanUnlock allows it, UnlockRequested comes next. The tree does not unlock the card itself: the game checks the cost and calls Unlock(id). A research can wait, so the game can unlock the card later.
With unlock-on-click="true", the click unlocks the card after UnlockRequested. Use CanUnlock to stop a click when the player cannot pay:
tree.CanUnlock = node => CostOf(node) <= points;
tree.Unlocked += node =>
{
points -= CostOf(node);
tree.Refresh(); // CanUnlock has new answers
};
An Available card that CanUnlock does not allow gets the class tb-unlock-node--denied: its cost is red, and a click plays the error sound. Call Refresh() when the answer of CanUnlock changes.
Save and load
saved = string.Join(",", tree.GetUnlockedIds());
tree.SetUnlocked(saved.Split(','));
SetUnlocked does not check the requirements and raises no Unlocked event. StateChanged comes for each card that changes. Ids that are not in the tree are ignored.
API
UnlockTree
| Member | Description |
|---|---|
column-width, row-height |
The distance in pixels from one column or row to the next. Defaults 200 and 100. |
padding |
The space in pixels around the cards. Default 16. |
direction |
Horizontal (default): the lines go from the right side of a requirement to the left side of the card. Vertical: from the bottom to the top. |
link-shape |
Elbow (default): lines at right angles, with the turn half way. Straight: one line. A card that is not after its requirement gets a straight line. |
unlock-on-click |
A click on an available card unlocks it. Default false. |
show-tooltips |
Sets the tooltip of each card: its description, and for a locked card the requirements that are missing. Default true. |
AddNode(node), AddNode(id, title, column, row, params requires) |
Adds a card from code. |
RemoveNode(id), GetNode(id), Nodes |
The cards. |
GetState(id) |
The state of a card. Locked for an unknown id. |
Unlock(id) |
Unlocks an Available card and raises Unlocked. False for a card that is not available. It does not ask CanUnlock. |
Reset() |
Locks all cards. |
GetUnlockedIds(), SetUnlocked(ids) |
Save and load. |
MissingRequirements(node) |
The ids that the card still needs. |
BlockedBy(node) |
The unlocked card that blocks the card, or null. |
CanUnlock |
Optional. False stops the click on an available card. |
Refresh() |
Places the cards, makes the lines and computes the states again. |
Links |
The lines, each an UnlockLink with From, To, IsAnyOf and State. |
ScrollView |
The scroll view around the cards. |
NodeClicked, UnlockRequested, Unlocked, StateChanged |
The events. StateChanged gives the card and its state before. |
UnlockNode
| Attribute | Description |
|---|---|
id |
The id that other cards name in requires, and that the save holds. |
title |
The bold text of the card. |
description |
The text of the tooltip. Rich text tags work. |
cost |
The muted text under the title, such as "60 science". It does not show on an unlocked card. |
icon |
The picture at the left of the card. |
column, row |
The place of the card, from 0. A fraction such as 2.5 places the card between two rows. |
requires, requires-any |
The ids of the requirements, split by commas. |
excludes |
The ids of the cards on another path, split by commas. When one of the two unlocks, the other is Blocked. |
secret |
A locked secret card is Hidden. Its title shows as "?" in the tooltips of other cards. |
progress |
The part of the research that is done, from 0 to 1, as a bar at the bottom of the card. |
The card is a Button, so it gets the button sound. State and IsUnlocked give its state in code.
Keyboard and gamepad
The arrow keys and the gamepad move the focus to the nearest visible card in that direction. The tree scrolls to the focused card. Enter or the gamepad submit clicks the card. A drag on the background of the tree pans it.
Styling
| Class | Element |
|---|---|
tb-unlock-tree |
The tree (grows; background, border). |
tb-unlock-tree__scroll, __canvas, __links, __nodes |
The scroll view, the canvas that is as large as the cards, and the layers of the lines and the cards. |
tb-unlock-tree__link |
A line, with --locked, --available, --unlocked, --hidden, --blocked and --any. |
tb-unlock-tree__editor-grid, __editor-cell |
The layer and the cells of the column and row grid in the UI Builder. |
tb-unlock-tree--panning |
The tree while a drag pans it. |
tb-unlock-node |
A card (168px wide). |
tb-unlock-node__icon, __body, __title, __cost, __check, __progress, __progress-fill |
The parts of a card. |
tb-unlock-node--locked, --available, --unlocked, --hidden, --blocked, --denied |
The state of a card. |
| Variable | On | Description |
|---|---|---|
--tb-unlock-link-color |
tb-unlock-tree__link |
The color of the line. |
--tb-unlock-link-width |
tb-unlock-tree__link |
The width of the line in pixels. |
--tb-unlock-link-dash |
tb-unlock-tree__link |
The length of a dash in pixels. 0 draws a solid line. Locked lines are dashed. |
The card is a Button, so its rules need two classes to beat the button rule of the workspace:
.unity-button.tb-unlock-node { width: 140px; }
.tb-unlock-tree__link--available { --tb-unlock-link-color: #f0c040; }
The UnlockTreeDemo scene shows a tech tree with a research queue, a skill tree with points and a quest chain.