How do I create a Class selection UI, that will gray out a class once it has been chosen?

Here is the flow of what I would like to create.


@Conan_Reis

Assuming that I understood what you are going for, here is some general logic with some magic functions that I am assuming are provided to keep things simple. [This is off the top of my head so there might be a parser error or two…]

If you don’t care about the number of players - i.e. the number of players matches the number of classes:

var AgentDPS : ?agent = false
var AgentTank : ?agent = false
var AgentHealer : ?agent = false

# Wait for class selection
sync:
    block: # Could organize blocks as functions
        ShowButtonDPS()
        set AgentDPS = DPSButton.InteractedWithEvent.Await()
        HideButtonDPS()
    block:
        ShowButtonTank()
        set AgentTank = TankButton.InteractedWithEvent.Await()
        HideButtonTank()
    block:
        ShowButtonHealer()
        set AgentHealer = HealerButton.InteractedWithEvent.Await()
        HideButtonHealer()

Afterwards, each of AgentDPS, AgentTank and AgentHealer will be set with the agent/player that pressed the specific button.

Or if you do care about the number of players - i.e. the number of players could be more or less than the number of classes:

var ClassCount := 0
ClassesNeeded := GetNumberPlayers() # Magic function
var AgentDPS : ?agent = false
var AgentTank : ?agent = false
var AgentHealer : ?agent = false

# Wait for class selection
AllPlayersHaveClasses := event(){}
race:
    # Race 1: Wait until all players have classes
    block:
        AllPlayersHaveClasses.Await()
        # Hide any buttons remaining
        # This could also be done using `defer` in the button blocks
        HideAllButtons()
    # Race 2: If there are more players than classes then sync will complete
    sync:
        block: # Could organize blocks as functions since they are similar
            ShowButtonDPS()
            set AgentDPS = DPSButton.InteractedWithEvent.Await()
            HideButtonDPS()
            set ClassCount = ClassCount + 1
            if (ClassCount = ClassesNeeded):
                AllPlayersHaveClasses.Signal()
        block:
            ShowButtonTank()
            set AgentTank = TankButton.InteractedWithEvent.Await()
            HideButtonTank()
            set ClassCount = ClassCount + 1
            if (ClassCount = ClassesNeeded):
                AllPlayersHaveClasses.Signal()
        block:
            ShowButtonHealer()
            set AgentHealer = HealerButton.InteractedWithEvent.Await()
            HideButtonHealer()
            set ClassCount = ClassCount + 1
            if (ClassCount = ClassesNeeded):
                AllPlayersHaveClasses.Signal()

Afterwards, each of AgentDPS, AgentTank and AgentHealer may be set with the agent/player that pressed the specific button - depending on the number of players.

Or something similar.
Does that logic make sense?

[If you need to know how to implement the magic functions that I didn’t provide the bodies for - I can figure that out though it will take more time to get back to you… :grin:]

:thinking:
I just realized that the above logic doesn’t prevent a player that already selected a class from choosing another class.

I can update with that logic too if needed…

Yes, that would be helpful. We are currently working on doing just that with the teams as well.

For example: When team A has 4 players, the TeamAButton becomes grayed out for all other players in real-time. This is what we have thus far (WIP)

VS_HUD_TeamSelect.verse (7.2 KB)

@Conan_Reis

Updated logic that prevents a classed player from selecting another class.

Helper code:

    #############################################
    # Member variables

    @editable
    ButtonDPS : button_device = button_device{}

    @editable
    ButtonTank : button_device = button_device{}

    @editable
    ButtonHealer : button_device = button_device{}

    var AgentDPS : ?fort_character = false
    var AgentTank : ?fort_character = false
    var AgentHealer : ?fort_character = false
    var ClassedAgents : []fort_character = array{}

    #############################################
    # Enables button, waits for press, disables button, returns character that pressed
    WaitForClassButton(ClassButton : button_device)<suspends>:?fort_character=
        ClassButton.Enable()
        defer:
            # Disable button whenever this function exits
            ClassButton.Disable()
        loop:
            Agent := ClassButton.InteractedWithEvent.Await()
            if:
                # Is this agent a fort_character?
                FortCharacter := Agent.GetFortCharacter[]
                # Does this character already have a class?
                not ClassedAgents.Find[FortCharacter]
            then:
                set ClassedAgents = Concatenate(ClassedAgents, array{FortCharacter})
                return option{FortCharacter}

Simple logic to wait for just the 3 classes with three players

    #############################################
    # Wait for classes to be set by players pressing class buttons
    # Called by OnBegin() or something similar
    ChooseClasses()<suspends>:void=
        # Wait for class selection
        sync:
            set AgentDPS    = WaitForClassButton(ButtonDPS)
            set AgentTank   = WaitForClassButton(ButtonTank)
            set AgentHealer = WaitForClassButton(ButtonHealer)

Logic that allows any number of players:

    #############################################
    # Wait for classes to be set by any number of players pressing class buttons
    # Called by OnBegin() or something similar
    ChooseClassesVariablePlayers()<suspends>:void=
        # Signaled when all players have class set
        AllPlayersHaveClasses := event(){}
        # Wait for class selection
        race:
            # Race 1: Wait until all players have classes
            AllPlayersHaveClasses.Await()
            # Race 2: If there are more players than classes then sync will complete
            sync:
                block: # Could organize blocks as functions
                    set AgentDPS = WaitForClassButton(ButtonDPS)
                    if (ClassedAgents = GetNumberPlayers()):
                        AllPlayersHaveClasses.Signal()
                block:
                    set AgentTank   = WaitForClassButton(ButtonTank)
                    if (ClassedAgents = GetNumberPlayers()):
                        AllPlayersHaveClasses.Signal()
                block:
                    set AgentHealer = WaitForClassButton(ButtonHealer)
                    if (ClassedAgents = GetNumberPlayers()):
                        AllPlayersHaveClasses.Signal()

    #############################################
    # Magic function for simplicity
    GetNumberPlayers()<computes> : int = 3

I just adapted the original code rather than your supplied code. Hopefully this makes sense?

@Conan_Reis this will be helpful for sure. Bits and pieces make sense in my artist brain. So much learning. LOVE IT! :smiley:

A few differences though, such as UI buttons not button devices. See the video, it’s better than a block of text.

VS_HUD_ClassSelect.verse (7.9 KB)

Something I didn’t mention in the video about the team select screen. Just like the class select, we want to limit the number of players (four on each team). Though it should be easy enough to address that by reusing the code from the class select code.

1 Like