Difference between revisions of "User:Dem1se"
(Add first two sections of additional info) |
(Add next two sections of Additional Info) |
||
Line 144: | Line 144: | ||
int XPos = (Game1.viewport.Width / 2) - (UIWidth / 2); | int XPos = (Game1.viewport.Width / 2) - (UIWidth / 2); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | === Decompiling the Game === | ||
+ | |||
+ | Use dotPeek (''free'') or ILSpy to [[Modding:Modder_Guide/Get_Started#How_do_I_decompile_the_game_code.3F | decompile the game ]] and view what are the available UI/Graphics classes in the game, to either modify or use within your UI. You'll have to look inside of <code>StardewValley.Menus</code> namespace mostly. | ||
+ | |||
+ | === Available UI Components === | ||
+ | |||
+ | The best way to find the complete list of all the UI / graphics components you can use in your UI is to decompile Stardew Valley yourself and looking at what's available. I'll still list a few fundamental types that every UI will use, and might even find to be enough usually: | ||
+ | |||
+ | {| class="wikitable" | ||
+ | ! '''Component Name''' | ||
+ | ! '''Uses''' | ||
+ | ! '''Namespace''' | ||
+ | |- | ||
+ | | ClickableTextureComponent | ||
+ | | Can be used to display any texture asset, including any image. Commonly used for buttons, images, etc. | ||
+ | | StardewValley.Menus | ||
+ | |- | ||
+ | | ClickableComponent | ||
+ | | Commonly used to draw text labels. Base of ClickableTextureComponent. | ||
+ | | StardewValley.Menus | ||
+ | |- | ||
+ | | TextBox | ||
+ | | Typical textbox. Used to get text inputs from users | ||
+ | | StardewValley.Menus | ||
+ | |- | ||
+ | | SpriteText | ||
+ | | While not a drawable component by itself, contains useful methods to draw TextScrolls to screen like <code>#drawStringWithScrollCenteredAt()</code> | ||
+ | | StardewValley.BellsAndWhistles | ||
+ | |} |
Revision as of 06:51, 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:
- Create a new class (preferably in a new .cs file), that implements
IClickableMenu
- Create constants / readonly fields that define the:-
- X, Y positions of the UI.
- Width and Height of the UI dialogue box.
- Declare all the UI elements that you going to be a part of your UI.
- Usually this means creating fields like, e.g., OkButton or Title, etc. of types
ClickableTextureComponent
andClickableComponent
(both of which are under theStartdewValley.Menus
namespace).
- Usually this means creating fields like, e.g., OkButton or Title, etc. of types
- Initialize all the declared UI elements, either in constructor or in a method called by the constructor.
- Override method in the
IClickableMenu
abstract class, to add desired behaviour to the UI.- Behaviour like handling clicks on the UI, reacting to cursor hovering over any element. Both of those are handled by the methods
void receiveLeftClick(...)
andvoid performHoverAction(...)
.
- Behaviour like handling clicks on the UI, reacting to cursor hovering over any element. Both of those are handled by the methods
- Override the
void draw(...)
method to draw all the UI and UI elements you declared and set up, to the screen.- 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 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), "Some Title");
...
}
// 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);
}
}
Displaying your UI
Game1.activeClickableMenu
stores the currently active UI, and has the value null
when no UI is active. It also can be assigned to, to display any IClickableMenu
UI that you want.
- Choose what event you want to activate your UI.
- This can be a simple button press on most cases, or a specfic game state like a time of the day, etc.
- Add the activation logic in your
Mod
subclass, where you bind to events and define handlers.
public class ModEntry : Mod
{
public override void Entry(IModHelper helper)
{
// bind the event handler
helper.Events.Input.ButtonPressed += OnButtonPressed;
...
}
void OnButtonPressed(object sender, ButtonPressedEventArgs ev)
{
// Don't process button presses if player hasn't loaded a save,
// is in another menu, or isn't free. I'd recommended you ignore these cases too.
if (!Context.IsWorldReady) return;
if (Game1.activeClickableMenu != null || (!Context.IsPlayerFree)) return;
// Display our UI if user presses F10
if (ev.Button == SButton.F10)
Game1.activeClickableMenu = new MyUserInterface();
...
}
}
Important Info
The Screen Positions
The number literals used in the UI element initializations and to define the UI dialog's contants are pixel values that represent the UI's positions in the screen.
The top-left corner of the screen is (0, 0) and increases across to the right and downwards.
Accounting for Scaling
Stardew valley video settings has an option to increase or decrease the UI scale which causes all the UI in the game to appear larger or smaller. This needs to be accounted for if you want your UI to be centered properly on the screen without being offset to either side.
This can be done by dividing with the UI Scale option.
// Scaling accounted for
int XPos = (int)(Game1.viewport.Width * Game1.options.zoomLevel * (1 / Game1.options.uiScale)) / 2 - (UIWidth / 2);
// Scaling unaccounted
int XPos = (Game1.viewport.Width / 2) - (UIWidth / 2);
Decompiling the Game
Use dotPeek (free) or ILSpy to decompile the game and view what are the available UI/Graphics classes in the game, to either modify or use within your UI. You'll have to look inside of StardewValley.Menus
namespace mostly.
Available UI Components
The best way to find the complete list of all the UI / graphics components you can use in your UI is to decompile Stardew Valley yourself and looking at what's available. I'll still list a few fundamental types that every UI will use, and might even find to be enough usually:
Component Name | Uses | Namespace |
---|---|---|
ClickableTextureComponent | Can be used to display any texture asset, including any image. Commonly used for buttons, images, etc. | StardewValley.Menus |
ClickableComponent | Commonly used to draw text labels. Base of ClickableTextureComponent. | StardewValley.Menus |
TextBox | Typical textbox. Used to get text inputs from users | StardewValley.Menus |
SpriteText | While not a drawable component by itself, contains useful methods to draw TextScrolls to screen like #drawStringWithScrollCenteredAt()
|
StardewValley.BellsAndWhistles |