Difference between revisions of "User:Dem1se"

From Stardew Valley Wiki
Jump to navigation Jump to search
(Add Create UIs Section)
(Add supporting code for Create UIs section)
Line 33: Line 33:
 
## This method is called by Stardew Valley's draw code every render tick whenever your UI is actively displayed.
 
## This method is called by Stardew Valley's draw code every render tick whenever your UI is actively displayed.
 
## The latter statements draw '''over''' the earlier statment's output. So things like the cursor should always be drawn at last so they are on top of everything else.
 
## The latter statements draw '''over''' the earlier statment's output. So things like the cursor should always be drawn at last so they are on top of everything else.
 +
 +
===== The general code layout will look something like this: =====
 +
 +
<syntaxhighlight lang="c#">
 +
public class MyUserInterface : IClickableMenu
 +
{
 +
    // Some of the constants you'll use to relatively lay out all the UI elements
 +
    int UIWidth = 632;
 +
    int UIHeight = 600;
 +
    int XPos = (Game1.viewport.Width / 2) - (UIWidth / 2);
 +
    int YPos = (Game1.viewport.Height / 2) - UIHeight;
 +
   
 +
    // Declare all the UI elements
 +
    ClickableComponent TitleLabel;
 +
    ...
 +
 +
    public MyUserInterface()
 +
    {
 +
        base.initialize(XPos, YPos, UIWidth, UIHeight);
 +
 +
        // initialize and lay out all the declared UI components
 +
        TitleLabel = new ClickableComponent(new Rectangle(XPos + 200, YPos + 96, UIwidth - 400, 64), &quot;Some Title&quot;);
 +
        ...
 +
    }
 +
 +
    // The method invoked when the player left-clicks on the menu.
 +
    public override void receiveLeftClick(int x, int y, bool playSound = true)
 +
    {
 +
        if (TitleLabel.containsPoint(x, y))
 +
        {
 +
            // handle user clicking on the title. More practical use-case would be with buttons
 +
            ...
 +
        }
 +
    }
 +
 +
    ...
 +
 +
    // Render the UI that has been set up to the screen.
 +
    // Gets called automatically every render tick when this UI is active
 +
    public override void draw(SpriteBatch b)
 +
    {
 +
        //draw screen fade
 +
        b.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * 0.75f);
 +
 +
        // draw menu dialogue box
 +
        Game1.drawDialogueBox(XPos, YPos, UIWidth, UIHeight, false, true);
 +
 +
        // draw the TitleLabel
 +
        Utility.drawTextWithShadow(b, TitleLabel.name, Game1.dialogueFont, new Vector2(TitleLabel.bounds.X, TitleLabel.bounds.Y), Color.Black);
 +
        ...
 +
 +
        // draw cursor at last
 +
        drawMouse(b);
 +
    }
 +
}
 +
</syntaxhighlight>

Revision as of 06:48, 12 November 2021

Getting Started with Making UIs

Intro

What is this article?

This is a compilation of things that I've learnt making UI for my mods. This is just to help beginners to understand how making UIs works in Stardew Valley, since not everyone can read through codebases or find relatively simple ones to read in the first place.

This is about adding a new menu that the user can interact with in game, similar to the inventory menu, as opposed to modifying existing ones, but the basic ideas are the same.

How does adding UI work?

All the UIs in Stardew Valley are classes that derive from the IClickableMenu abstract class. So making your own UI is a matter of making your own class that derives from IClickableMenu, overriding the required methods and doing some other layout stuff.

After defining the UI, it is a matter of assigning an instance of that class to Game1.activeClickableMenu. We'll look at how to do both in detail below.

Creating UIs

Define your UI

The general steps you want to take are as follows:

  1. Create a new class (preferably in a new .cs file), that implements IClickableMenu
  2. Create constants / readonly fields that define the:-
    1. X, Y positions of the UI.
    2. Width and Height of the UI dialogue box.
  3. Declare all the UI elements that you going to be a part of your UI.
    1. Usually this means creating fields like, e.g., OkButton or Title, etc. of types ClickableTextureComponent and ClickableComponent (both of which are under the StartdewValley.Menus namespace).
  4. Initialize all the declared UI elements, either in constructor or in a method called by the constructor.
  5. Override method in the IClickableMenu abstract class, to add desired behaviour to the UI.
    1. Behaviour like handling clicks on the UI, reacting to cursor hovering over any element. Both of those are handled by the methods void receiveLeftClick(...) and void performHoverAction(...).
  6. Override the void draw(...) method to draw all the UI and UI elements you declared and set up, to the screen.
    1. This method is called by Stardew Valley's draw code every render tick whenever your UI is actively displayed.
    2. The latter statements draw over the earlier statment's output. So things like the cursor should always be drawn at last so they are on top of everything else.
The general code layout will look something like this:
public class MyUserInterface : IClickableMenu
{
    // Some of the constants you'll use to relatively lay out all the UI elements
    int UIWidth = 632;
    int UIHeight = 600;
    int XPos = (Game1.viewport.Width / 2) - (UIWidth / 2);
    int YPos = (Game1.viewport.Height / 2) - UIHeight;
    
    // Declare all the UI elements
    ClickableComponent TitleLabel;
    ...

    public MyUserInterface()
    {
        base.initialize(XPos, YPos, UIWidth, UIHeight);

        // initialize and lay out all the declared UI components
        TitleLabel = new ClickableComponent(new Rectangle(XPos + 200, YPos + 96, UIwidth - 400, 64), &quot;Some Title&quot;);
        ...
    }

    // The method invoked when the player left-clicks on the menu.
    public override void receiveLeftClick(int x, int y, bool playSound = true)
    {
        if (TitleLabel.containsPoint(x, y))
        {
            // handle user clicking on the title. More practical use-case would be with buttons
            ...
        }
    }

    ...

    // Render the UI that has been set up to the screen. 
    // Gets called automatically every render tick when this UI is active
    public override void draw(SpriteBatch b)
    {
        //draw screen fade
        b.Draw(Game1.fadeToBlackRect, Game1.graphics.GraphicsDevice.Viewport.Bounds, Color.Black * 0.75f);

        // draw menu dialogue box
        Game1.drawDialogueBox(XPos, YPos, UIWidth, UIHeight, false, true);

        // draw the TitleLabel
        Utility.drawTextWithShadow(b, TitleLabel.name, Game1.dialogueFont, new Vector2(TitleLabel.bounds.X, TitleLabel.bounds.Y), Color.Black);
        ...

        // draw cursor at last
        drawMouse(b);
    }
}