Hello Guest

Author Topic: OtterSauceGui - A GUI Library for Otter  (Read 3878 times)

0 Members and 1 Guest are viewing this topic.

Fatesauce

  • Member
  • Posts: 26
    • View Profile
OtterSauceGui - A GUI Library for Otter
« on: July 25, 2015, 04:05:27 AM »
OtterSauceGui - Alpha v0.01

Quick Introduction

OtterSauceGui is a graphical user interface library for use with Otter.  If you’re like me, sometimes you want some flashy mouse input, or text input for your games.  This is what the OtterSauceGui aims to provide.

Download the library at the end of the post!

Installation Instructions

Import the OtterSauceGui project into your games solution in the same way you do with Otter.  OtterSauceGui depends on Otter, so make sure you add a reference to Otter in the OtterSauceGui project.

To use it in your game, add a reference to OtterSauceGui in your game project.



The Long Version

Forward

This project is a massive but enlightening challenge for me for 3 reasons: Inexperience with Otter, inexperience with C#, and to top it off, I have never ever attempted to create a gui library in any form before.

In spite of it all, I NEEDED a functional gui for the game prototypes I had in mind.  Enter OtterSauceGui.

This library is an intensive work in progress, there are a lot of features I haven’t implemented yet, as I want to fix the logic before making it flashy and large.  There are bugs, possibly bugs that I haven’t discovered yet.  And of course there is polish.  At the moment this shiny piece of furniture needs a few coats of varnish.

The main reason I release this library at such an early stage, is so hopefully developers use the library and give feedback on bugs they discover, features they really need, or some of the stuff they have been able to do with it.

Please test, use, and reply with any feedback!

I will keep this post updated as changes occur.


Tutorial

About the Classes

GuiManager
At the core of OtterSauceGui is a class called the GuiManager.  GuiManager extends from Otters Entity class, and is in charge of maintaining and displaying your gui components, called “Widjets”.  (Apparently widjets is spelt wrong, but i’m rolling with my way for now....unless people rage).

The GuiManager object is the first thing you will create in your Scene when you are building your gui.  Once created, you add “Widjets” to the GuiManager instance, and finally, add the GuiManager to the Scene to be rendered in all its glory.

Widjet
The second most important class in the library.  This is the base class from which all other Widjets are built upon.  Widjet extends from Otters Component class.  Components are added to Entities, In the same sort of way that Entities are added to Scenes.  Widjet is a base class, so its not recommended to instance this class directly.  If you wish to create your own widjet using this class, just extend from it and build from there.

GuiPointer
This class is super simple, so simple it probably doesn’t need to be in the library.  But its something I plan to use a lot of, so here it is!  GuiPointer is not a widjet, it is an Entity.  You do not add it to your GuiManager object (it won’t let you), you add it to your Scene. 

All this Entity does is follow around your mouse cursor.  Thats it.  Its purpose? To easily allow you to use a custom and graphical mouse cursor in your game!

GuiButton
The main and most used widjet in the library.  GuiButton extends from Widjet.  It is a component, which is added to your GuiManager object.  GuiButton has 4 different ways of functioning: As a normal clicky button, as a button you can hold down, as a toggled “on/off? button, or as a radio button, which is grouped with other radio buttons.

GuiTextBox
This widjet, (also extends Widjet...go figure), is used to provide players with single line text input.  Input can be moderated, allowing users to only use certain characters.  Input can be set from within the program, and retrieved.

And that’s it so far.  As the library evolves, there will undoubtedly be more added.

Getting Started

Step One: Create your game and have a Scene ready to add a gui too.  I’m going to assume you know how to do this, if not, check out the other Otter tutorials!

Step Two: Declare the objects you need for your gui to function in your Scene.

Theres a few ways to do this. Im going to show you the most basic.
We need at least 4 things in our Scene for our gui to work:

A Surface to render the gui on.  This way your gui wont be affected by the games camera when it moves around the Scene (there are exceptions to this, explained after the tutorial).

A GuiManager object.  This is the core of your gui.  Without it, things become somewhat more awkward.

At least one “Widjet”.  Either a GuiButton or GuiTextBox, to add to the GuiManager object.

A visible mouse cursor.  If you haven’t already, add this line to your code before you call game.Start();

Code: [Select]
game.MouseVisible = true;
Where “game” is whatever you named your game object.

You should end up with something like this:

Code: [Select]
//creates the surface for the gui.  I recommend setting it to the same size as your game window.
Surface guiSurface = new Surface(800, 600);

//Create the gui manager object and pass it your game object, and the surface you just created.
GuiManager testGui = new GuiManager(game, guiSurface);

//Create the button object, set its x/y position on guiSurface, and set its width and height.
GuiButton testButton = new GuiButton(10, 10, 400, 50);

Step Three: Prepare our widjet.

Next we have to prepare our testButton somwhere in the Scenes constructor, or in the Begin() method:

Code: [Select]
//Set the text to display on the button.  pass it the string to display, the path to your desired font file (use “” for default Otter font), and the size of the font.
testButton.SetText("This is a Button!", "", 40);

//Subscribe to the testButtons “OnClickEvent”, so we can make our game do something when the user clicks.  You will get a red line/error here likely, but thats ok. Read on!
testButton.OnClickEvent += new EventHandler(testButton_OnClickEvent);

//Add the widjet to your GuiManager
testGui.AddWidjet(testButton);

Ok so if your unfamiliar with events and EventHandlers, allow me to explain! The line of code we entered above:

Code: [Select]
testButton.OnClickEvent += new EventHandler(testButton_OnClickEvent);
is telling our testButton object, “when the button is clicked, inform this method so we can respond to it”.  The method the OnClickEvent is going to notify is what we are going to create next.

The way events work, is that you “subscribe” methods to them, so when the event is invoked, it calls all the methods subscribed to it, basically.  EventHandler is a delegate, part of the C# language, that tells us what parameters we need to include in the subscribing method.  So lets create the method!

Create a method in your Scene:

Code: [Select]
//The parameters are the minimum required by all events, and are defined by EventHandler.  Without them, you cant subscribe this method to the event.
public void testButton_OnClickEvent(object sender, EventArgs e)
{

}

This is the method that will be executed every time the testButton is clicked.  So this is where you add all your own crazy game logic basically.

And thats it!  The testButton is ready.

Step Four:  Add the GuiManager to the Scene.

A note about this: Don’t use Add(testGui); in the Scenes constructor.  This may cause a runtime error when your game starts depending on when you first initialised the Scene, due to information not being available when GuiManager needs it. 

Instead, add this to your Scene:

Code: [Select]
public override void Begin()
{
base.Begin();
}

The Scene calls this method when the Scene first begins, not when the Scene is first initialised (ie: when the Constructor is called).

Now we can add our testGui!

Code: [Select]
public override void Begin()
{
base.Begin();

Add(testGui);
}

As a matter of opinion, I believe it to be a bit cleaner/better practice, for any entities the Scene requires to be added in the Begin method and not the constructor.

Now we should be ready to go! ....Or are we?  If you run your game now....no gui.

Step Five: Rendering the Surface.

Before we render our surface, we have to tell it how to respond to camera movement.  Add this code to your constructor after the surface object is created:

Code: [Select]
//This will stop our gui moving with the camera!
guiSurface.Scroll = 0f;

The surface we created for our gui wont render itself, so we have to tell it to render in the Scenes Render loop.  Add this to your Scene:

Code: [Select]
public override void Render()
{
base.Render();

guiSurface.Render();
}

Now run the game!  You should see a plain looking white box with a bit of writing on it.



Extra Information

About Surfaces

In the tutorial, we created a single Surface.  This only works If you plan on doing very little with your camera, aside from moving it left right up down. If you want to zoom the camera, you may find it zooms the gui as well.  The way around this is to use a second surface.  Add your gui to one surface, and add all your game entities to your second surface.  If you have graphics added directly to the Scene (not in an entity), then things will look weird....put those graphics in an entity.  Instead of calling the Scenes camera now, you call the Surfaces camera.  Check out the Demo project for an example.

About Widjet Graphics

I haven’t spent alot of time on making options available to developers for widjet graphics, primarily because I want to get the logic right first, THEN plaster the widjets with ways of making them look cool.  I encourage you to experiment and see what you come up with.

Possible Ways to Create Guis

Gui code can take up a crap tonne of space once you have a good handful of widjets, or more than one gui (one game prototype i have has 4 guis for one scene).  A possible option would be put all the code into a single class and make calls to it.  Or you could create a class that extends GuiManager.  Put all the widjet code in the constructor, then in the scene, all you are doing is creating the object for the class (passing it the game/surface), and Adding it to the Scene in the Begin method.  Keep it nice n tidy.

Version Log

Alpha v0.01
First public release!
-GuiTextBox has a bug triggered by the OSD screen capture software, when using OpenGL for rendering.  It makes all the Text graphics on screen behave strangely.  Aside from this it works great.
-Limited means of natively setting up graphics for widjets.
-No major faults found with the button logic (yet).
-Its the first release so theres probably a bunch of things undiscovered.  Give OtterSauceGui a play and see what kind of damage you can do!


Downloads

In Google Drive, click the "Download" button at the top of the screen.

Download the Demo project: https://drive.google.com/file/d/0B53B5lQltax0UWpvRjYxcndueEU/view?usp=sharing

Download the Library: https://drive.google.com/file/d/0B53B5lQltax0NW81eFN0NnZxZ1U/view?usp=sharing
« Last Edit: July 26, 2015, 01:36:53 PM by Fatesauce »

Fatesauce

  • Member
  • Posts: 26
    • View Profile
Re: OtterSauceGui - A GUI Library for Otter
« Reply #1 on: July 25, 2015, 08:20:33 PM »
An example of creating a gui by creating a class that extends GuiManager:

Instance the new class in your Scenes constructor, then Add it to the Scene in the Scenes "Begin" method.  Create your Widjets in the Constructor of your new GuiManager class, not the Added method, otherwise grouping doesnt work properly.

Code: [Select]

class MainMenuGui : GuiManager
    {
        GuiButton btnSinglePlayer, btnMultiPlayer, btnOptions, btnQuit;

        public MainMenuGui(Game game, Surface s)
            : base(game,s)
        {
            btnSinglePlayer = new GuiButton(Global.game.HalfWidth - 150, Global.game.HalfHeight - 150, 300, 50);
            btnSinglePlayer.SetText("Single Player", "", 32);
            btnSinglePlayer.SetSpriteMap("../../TestGraphics/MenuButtons1.png");
            btnSinglePlayer.OnClickEvent += new EventHandler(btnSinglePlayer_OnClickEvent);
            AddWidjet(btnSinglePlayer);

            btnMultiPlayer = new GuiButton(Global.game.HalfWidth - 150, Global.game.HalfHeight - 80, 300, 50);
            btnMultiPlayer.SetText("Multi Player", "", 32);
            btnMultiPlayer.SetSpriteMap("../../TestGraphics/MenuButtons1.png");
            btnMultiPlayer.OnClickEvent += new EventHandler(btnMultiPlayer_OnClickEvent);
            AddWidjet(btnMultiPlayer);

            btnOptions = new GuiButton(Global.game.HalfWidth - 150, Global.game.HalfHeight - 10, 300, 50);
            btnOptions.SetText("Options", "", 32);
            btnOptions.SetSpriteMap("../../TestGraphics/MenuButtons1.png");
            btnOptions.OnClickEvent += new EventHandler(btnOptions_OnClickEvent);
            AddWidjet(btnOptions);

            btnQuit = new GuiButton(Global.game.HalfWidth - 150, Global.game.HalfHeight + 100, 300, 50);
            btnQuit.SetText("Quit", "", 32);
            btnQuit.SetSpriteMap("../../TestGraphics/MenuButtons1.png");
            btnQuit.OnClickEvent += new EventHandler(btnQuit_OnClickEvent);
            AddWidjet(btnQuit);
        }

        public void btnSinglePlayer_OnClickEvent(object sender, EventArgs e)
        {
            Global.game.RemoveScene();
            Global.game.AddScene(Global.gameScene);
        }

        public void btnMultiPlayer_OnClickEvent(object sender, EventArgs e)
        {
            //TODO
        }

        public void btnOptions_OnClickEvent(object sender, EventArgs e)
        {
            RemoveSelf();
            Global.menuScene.StartOptionsGui();
        }

        public void btnQuit_OnClickEvent(object sender, EventArgs e)
        {
            Global.game.Close();
        }
    }


Fatesauce

  • Member
  • Posts: 26
    • View Profile
Re: OtterSauceGui - A GUI Library for Otter
« Reply #2 on: July 26, 2015, 01:41:12 PM »
About the GuiTextBox bug.
After alot of testing, the cause of the bug was actually the screen capture software I was using called "OSD", with its rendering set to OpenGL.  If I was using OSD with DirectX3D 11, the bug would not happen.  Nor will it happen while OSD is not running.  So the issue lies with some sort of OpenGL conflict.  As far as the OtterSauce goes, the text boxes should be safe to use without your game being broken at run time.

I updated the original post to reflect my findings.