Jump to content

The Hankinator's UI library


thehankinator
 Share

Recommended Posts

The Hankinator's UI library

 

http://steamcommunity.com/sharedfiles/filedetails/?id=653673604

 

This is a rudimentary GUI library with the goal of simplicity but with flexibility. Only basic widgets are included, Label, Button, Checkbox and Combobox. This should satisfy the majority of GUI needs but if you come up with a good case to include others let me know. All widgets can be themed with images for beautification. THUI is built around groups of GUI elements. Every group has a name, this name is used to activate (make visible) when you need it to. Only one group can be active at a time. THUI contains helper functions so that you can ensure the GUI will scale and look similar on different resolutions. The easiest way to layout a menu system is to create a script for each group, then apply the scripts to pivots in your level. If you wish to design it so, you can use the flow graph to control how the user navigates between groups. It is fairly straight forward to create your own widgets that don't look so bland.

 

To kick things off, I am going to start with required changes to Main.lua, a simple example, pause screen, journal, and finally the API reference. When I was thinking about this post, I was thinking I'd have more to say about each example but now that I've gotten to it, the ideas are gone. Please ask if things need additional clarification. I've put a lot of thought into the design of this library so that it could be used in the majority of use cases but if I have forgotten something obvious, please let me know!

 

I publish updates to steam as I see fit but any development occurs on github first: https://github.com/airbrett/THUI

 

Main.lua modifications:

It should be pretty trivial to make the same modifications to App.lua but I like Main.lua best and I don't want to spend time talking about App.lua. There is an example Main.lua in the examples directory with all these changes.

 

1) First thing is first, import THUI at the top of the file and initialize some variables

import "Addons/THUI/THUI.lua"

paused = false
exit_game = false
 

 

2) Immediately after the context is created, initialize THUI

THUI:Initialize()
 

 

3) Change the while loop not to exit when we hit escape, this is for our pause menu example

while not exit_game do
 

 

4) Next we need to change the program flow to only update the time and the world when the game isn't paused.

if not paused then
--Update the app timing
Time:Update()

--Update the world
world:Update()
end
 

 

5) Immediately after world:Render(), we need to update THUI

THUI:Update()
 

 

Simple example:

This is a simple example of how to build a simple GUI screen with a label and a button.

self.group = THUI:CreateGroup("hello_world", self, THUI.AUTOSCALE, 0, 0, 1023, 767)

local title = THUI.Label:Create(512, 50, 0, 0, "Hello World!", THUI.JUSTIFY.CENTER, THUI.JUSTIFY.MIDDLE)
title.font_size = 24

local button1 = THUI.Button:Create(512, 300, 200, 50, "A button")

self.group:Add(title)
self.group:Add(button1)
 

 

Pause screen example:

This script will pause the game when the user hits the escape key. This example is utilizing the ANCHOR functionality to position all widgets to the left middle of the screen. It is pretty straight forward but the interesting parts we do in this order:

 

1) We create the group

2) Create a label for the title

3) Create a Resume button

4) Set the click callback for the resume button

5) Create an Exit button

6) Set the click callback for the exit button

7) Add all the widgets to the group

 

import "Addons/THUI/THUI.lua"

function Script:Start()
self.group = THUI:CreateGroup("pause_menu", self, THUI.AUTOSCALE, nil, nil, 1023, 767)

self.group.update = THUI:Callback(self.UpdateUI, self, nil)

local title = THUI.Label:Create(512, 50, 0, 0, "Paused!", THUI.CENTER, THUI.MIDDLE)
title.font_size = 24

local width = 200
local button1 = THUI.Button:Create(512, 300, width, 50, "Resume", THUI.CENTER, THUI.MIDDLE)

button1.click = THUI:Callback(self.ResumeButtonclicked, self)

local exitbutton = THUI.Button:Create(512, 400, width, 50, "Exit", THUI.CENTER, THUI.MIDDLE)
exitbutton.click = THUI:Callback(self.ExitButtonclicked, self)

self.group:Add(title)
self.group:Add(button1)
self.group:Add(exitbutton)
end

function Script:ResumeButtonclicked(button)
self:HideMenu()
end

function Script:ExitButtonclicked(button)
exit_game = true
end

function Script:UpdateWorld()
if window:KeyHit(Key.Escape) then
if not paused then
self:ShowMenu()
end
end
end

function Script:UpdateUI(group, arg)
if window:KeyHit(Key.Escape) then
if paused then
self:HideMenu()
end
end
end

function Script:ShowMenu()
THUI:PauseGame(true)
THUI:Show("pause_menu")
end

function Script:HideMenu()
THUI:PauseGame(false)
THUI:Hide("pause_menu")

--FPSPlayer.lua measures the distance from the middle of the screen to figure out how much
--the player is trying to look so we need to reset it when the user is done with the UI
local context = Context:GetCurrent()
Window:GetCurrent():SetMousePosition(Math:Round(context:GetWidth()/2), Math:Round(context:GetHeight()/2))
end
 

 

 

Journal example:

This is a little bit more complicated. But the first thing we need to do is create the journal menu itself. This is pretty simple but I will leave it to you to make the fancy things smile.png. In this script I create 10 buttons, each button is created with the active flag false so that it is greyed out. When the player picks up a journal entry, the button will be set to active and they can click on the button to view the entry. The Journal Entry script should be put on the object itself, like a piece of paper, cassette tape, or whatever.

 

Journal script:

import "Addons/THUI/THUI.lua"

function Script:Start()
Journal = self --global that entries can use to add themselves

self.pg = THUI:CreateGroup("journal", self, THUI.AUTOSCALE, nil, nil, 1023, 767)

local title = THUI.Label:Create(512, 50, 0, 0, "Journal", THUI.CENTER, THUI.MIDDLE)
title.font_size = 24

local button1 = THUI.Button:Create(50, 700, 200, 50, "Resume")

button1.click = THUI:Callback(self.ResumeButtonclicked, self)

self.pg:Add(title)
self.pg:Add(button1)

self.entries = {}
self.entry_buttons = {}

for i=1, 10 do
local b = THUI.Button:Create(512, 45 + 55 * i, 200, 50, "????", THUI.CENTER, THUI.MIDDLE)
b.active = false
b.click = THUI:Callback(self.EntryButtonclicked, self, i)
self.pg:Add(b)
self.entry_buttons[i] = b
end

self.journal_entry = THUI:CreateGroup("journal_entry", self)

end

function Script:UpdateWorld()
if window:KeyHit(Key.J) then
if not THUI:GamePaused() then
THUI:PauseGame(true)
THUI:Show(self.pg)
end
end
end

function Script:EntryButtonclicked(button, index)
THUI:Hide("journal")
THUI:Show(self.entries[index].grp.name)
end

function Script:ResumeButtonclicked(button)
THUI:PauseGame(false)
THUI:Hide(self.pg)

--FPSPlayer.lua measures the distance from the middle of the screen to figure out how much
--the player is trying to look so we need to reset it when the user is done with the UI
local context = Context:GetCurrent()
Window:GetCurrent():SetMousePosition(Math:Round(context:GetWidth()/2), Math:Round(context:GetHeight()/2))
end

function Script:AddJounalEntry(entry)
self.entries[entry.index] = entry

local b = self.entry_buttons[entry.index]
b.active = true
b.text = entry.title
end
 

 

Journal entry script:

import "Addons/THUI/THUI.lua"

Script.index = 3
Script.title = "Entry 3"

function Script:Start()
local text = {
"Day 45",
"",
"I have earned the Germans' trust.",
"They still do not realize I am a bear."
}

self.grp = THUI:CreateGroup("entry1", self, THUI.AUTOSCALE, nil, nil, 1023, 767)

local label = THUI.Label:Create(512, 10, 0, 0, self.title, THUI.CENTER, THUI.MIDDLE)
label.font_size = 24

self.grp:Add(label)

local y = 150
local leading = label.font:GetHeight() * 1.3
for i=0, #text do
label = THUI.Label:Create(512, y, 0, 0, text[i], THUI.CENTER, THUI.MIDDLE)
label.font_size = 24
self.grp:Add(label)
y = y + leading
end

local journal_button = THUI.Button:Create(100, 700, 200, 50, "Journal")
journal_button.click = THUI:Callback(self.JournalButtonclick, self, nil)

self.grp:Add(journal_button)
end

function Script:Use()
Journal:AddJounalEntry(self)

THUI:Show("entry1")
THUI:PauseGame(true)
self.entity:Hide()
end

function Script:JournalButtonclick(button, arg)
THUI:Hide("entry1")
THUI:Show("journal")
end
 
  • Upvote 4
Link to comment
Share on other sites

Reference:

This is where the majority if interesting text goes. If something up above doesn't make sense, it might be made clear in this section.

THUI

constants

THUI.ABSOLUTE
THUI.AUTOSCALE
THUI.ANCHOR

These values are using when creating a widget group, they will dictate the behavior of how the size and dimensions of the widgets will be modified (if at all) when added to the group.

 

THUI.LEFT --x axis
THUI.CENTER --x axis
THUI.RIGHT --x axis
THUI.MIDDLE --y axis
THUI.TOP --y axis
THUI.BOTTOM -- y axis

This is used for defining how a widget is positioned via the justify flags.

 

properties

THUI.default_fg_color --Foreground color used by widgets
THUI.default_bg_color --Background color used by widgets
THUI.default_inactive_color --Inactive color used by widgets
THUI.default_hover_color --Color used by widgets when mouse is hovering over them
THUI.default_mouse_down_color --Color used by widgets when mouse is hovering over them and the left mouse button is down

 

functions

THUI:Initialize()

Initializes THUI variables. Required for use.

 

THUI:CreateGroup(name, data, mode, anchorx, anchory, width, height)

  • name=the name of the group, this is the name you will use when you want to show this group
  • data=this is any data you want to be able to retrieve from the group at a later time (usually with LookUpByName())
  • mode=this can be THUI.AUTOSCALE, THUI.ABSOLUTE, or THUI.ANCHOR. THUI.AUTOSCALE will stretch all widgets in relation to the width and height specified. THUI.ABSOLUTE will make no adjustments to the widgets dimensions. THUI.ANCHOR will utilize anchorx, anchory, width and height parameters to move the widgets to the position specified.
  • anchorx=THUI.LEFT, THUI.CENTER, THUI.RIGHT used by THUI.AUTOSCALE
  • anchory=THUI.MIDDLE, THUI.TOP, THUI.BOTTOM used by THUI.AUTOSCALE
  • width=width of the widget group, this is used by THUI.AUTOSCALE and THUI.ANCHOR
  • height=height of the widget group, this is used by THUI.AUTOSCALE and THUI.ANCHOR
     
  • return=group table

This function creates a group to add widgets to.

 

THUI:Show(name)

  • name=group or name of group

If name is group, it will be shown. If name is a string, all groups with matching name will be shown.

 

THUI:Hide()

  • name=group or name of group

If name is group, it will be hidden. If name is a string, all groups with matching name will be hidden.

 

THUI:Update()

This function should be called from Main.lua every iteration. It will redraw any widgets and also fire off any callbacks that are ready to be fired

 

THUI:PauseGame(pause)

  • pause=true will pause, false will resume

Convenience function for pausing and resuming the game when Main.lua has required changes (see Main.lua in examples directory)

 

THUI:GamePaused()

Returns true if game is paused, false if not paused.

 

THUI:GetFont(path, size)

  • path=Path of the font
  • size=Size of the font

Returns a font from cache

 

THUI:MouseOverUI()

Returns true if the mouse is hovering over a widget, false otherwise

 

THUI:Callback(func, tbl, arg)

  • func=function to callback
  • tbl=table the function exists in, can be nil if func is a global function
  • arg=arg that should be used when calling the function, can be nil

 

This function creates a callback that is used by buttons to do a task.

 

Group

properties

group.update --function callback called every frame when group is active

 

functions

group:Add(widget)

  • widget=widget to add to the group

 

Adds a specified widget to the group. At this time the widget's position and dimensions are finalized depending on the group's mode.

 

Label

properties

label.text --Text to be displayed
label.font_path --Path to the font
label.font_size --Font size
label.img --Texture to be drawn instead of text

 

functions

THUI.Label:Create(x, y, width, height, text, justify_x, justify_y)

  • x=x position
  • y=y position
  • width=width, required when img property is set
  • height=height, required when img property set
  • justify_x=can be THUI.LEFT, THUI.CENTER or THUI.RIGHT
  • justify_y=can be THUI.MIDDLE, THUI.TOP, or THUI.BOTTOM
     
  • return=label table

 

Button

properties

button.text --Text to be displayed
button.font_path --Path to the font
button.font_size --Font size
button.active --This flag determines if the button is enabled or not.
button.visible --Hides or shows the button
button.click --Function callback for when button is clicked

 

button.fg_color --color used in idle state
button.bg_color --background color
button.hover_color --mouse hovering over widget
button.mouse_down_color --mouse hovering and mouse button down
button.inactive_color --active flag false

Colors used to draw the button when not themed with textures.

 

button.img_mouseup --idle state
button.img_hover --mouse hovering over widget
button.img_mouse_down --mouse hovering and mouse button down
button.img_inactive --active flag false

Textures to be rendered for different states of the button.

 

functions

THUI.Button:Create(x, y, width, height, text, justify_x, justify_y)

  • x=x position
  • y=y position
  • width=width
  • height=height
  • justify_x=can be THUI.LEFT, THUI.CENTER or THUI.RIGHT
  • justify_y=can be THUI.MIDDLE, THUI.TOP, or THUI.BOTTOM
     
  • return=button table

 

Checkbox

properties

checkbox.active --This flag determines if the checkbox is enabled or not.
checkbox.checked --Set to true if box is checked

 

inactive_color --active flag false
mouse_down_color --mouse hovering and mouse button down
hover_color --mouse hovering over widget
fg_color --color used in idle state
bg_color --background color

Colors used to draw the checkbox when not themed with textures.

 

checkbox.img_inactive --active flag false
checkbox.img_mouse_down --mouse hovering and mouse button down
checkbox.img_hover --mouse hovering over widget
checkbox.img_mouseup --idle state
checkbox.img_checked_inactive --active flag false while checked
checkbox.img_checked_mouse_down --mouse hovering and mouse button down while checked
checkbox.img_checked_hover --mouse hovering over widget while checked
checkbox.img_checked_mouseup --idle state while checked

Textures to be rendered for different states of the checkbox.

 

functions

THUI.CheckBox:Create(x, y, width, height, justify_x, justify_y)

  • x=x position
  • y=y position
  • width=width
  • height=height
  • justify_x=can be THUI.LEFT, THUI.CENTER or THUI.RIGHT
  • justify_y=can be THUI.MIDDLE, THUI.TOP, or THUI.BOTTOM
     
  • return=checkbox table

 

Combobox

The combobox isn't really a widget on it's own. It's a combination of 2 buttons and a label.

properties

combo.left_button --left button table, see button reference
combo.right_button --right button table, see button reference
combo.selected --The currently selected item in the list of values

functions

THUI.ComboBox:Create(x, y, width, height, values, selected, justify_x, justify_y)

  • x=x position
  • y=y position
  • width=width
  • height=height
  • values=table of possible values that can be selected
  • selected=the index of the default value to be selected
  • justify_x=can be THUI.LEFT, THUI.CENTER or THUI.RIGHT
  • justify_y=can be THUI.MIDDLE, THUI.TOP, or THUI.BOTTOM
     
  • return=combobox table

Edited by thehankinator
Link to comment
Share on other sites

What about windows/panels that contain these widgets and the pos/anchoring is relative to them vs the screen? Or maybe everything can be relative to the screen as long as you position elements that look like they are on top of a window/panel.

 

Just curious, why have the users call the THUI:Rel2Ab*() functions at all? As I'm using this, it seems a little tedious and not needed when you can call it behind the scenes for us and we can just pass in values since we would want these to be converted all the time wouldn't we? The entire point of using the lib would be because it handles screen/aspect for us right?

 

[EDIT]

This doesn't seem to work through different aspect ratios. I know you have the default width & height variables and I can set those, but it may be a good idea to have defaults for each aspect ratio maybe so the users of the lib don't have to worry about figuring out which aspect ratio they are in and then setting these 2 variables based on that? Just an idea. I love this library and am going to be using some ideas from it in our game and will probably modify it to do some of these things but just want to give feedback as much as I can as I'll be a big user of some of the functionality from it.

 

Some of the more rare screen resolutions don't seem to work that I can see. 1280x800 (8:5) works for sizing but positioning is off, even when I set my default w/h to 1280x800. I bring that up because that's what the LE game player allows players to set as. There are a few strange ones that I think would be troublesome. How would these be handled?

Link to comment
Share on other sites

What about windows/panels that contain these widgets and the pos/anchoring is relative to them vs the screen? Or maybe everything can be relative to the screen as long as you position elements that look like they are on top of a window/panel.

 

Just curious, why have the users call the THUI:Rel2Ab*() functions at all? As I'm using this, it seems a little tedious and not needed when you can call it behind the scenes for us and we can just pass in values since we would want these to be converted all the time wouldn't we? The entire point of using the lib would be because it handles screen/aspect for us right?

 

[EDIT]

This doesn't seem to work through different aspect ratios. I know you have the default width & height variables and I can set those, but it may be a good idea to have defaults for each aspect ratio maybe so the users of the lib don't have to worry about figuring out which aspect ratio they are in and then setting these 2 variables based on that? Just an idea. I love this library and am going to be using some ideas from it in our game and will probably modify it to do some of these things but just want to give feedback as much as I can as I'll be a big user of some of the functionality from it.

 

Some of the more rare screen resolutions don't seem to work that I can see. 1280x800 (8:5) works for sizing but positioning is off, even when I set my default w/h to 1280x800. I bring that up because that's what the LE game player allows players to set as. There are a few strange ones that I think would be troublesome. How would these be handled?

Hey Rick,

 

Thanks for looking at this. I completely forgot about anchoring, luckily I was add it in by adding a mode to the CreateGroup function. Also it allowed me to add a mode for what I am calling Autoscale. This will eliminate the ridiculous amount of Rel2Abs() calls since in autoscale they will be done by the group when they widget is added to it. I just thought of a problem and that is if the same widget gets added to two different groups, that could be a problem but also not a terrible limitation so I'll leave it in for now.

 

I'll have to take a look at why scaling/positioning are off at some of these different ratios.

 

The result of this change (which I'll be pushing to the workshop momentarily) is that CreateGroup now has a lot more arguments. The additional arguments are only for anchoring, as mode defaults to THUI.AUTOSCALE. To Anchor a group of widgets you would do something like the pause menu below. All the contents of the JUSTIFY table within THUI are now directly in THUI, so that could be code breaking if anyone is actually using this yet.

 


self.group = THUI:CreateGroup("pause_menu", self, THUI.ANCHOR, THUI.LEFT, THUI.MIDDLE, 200, 200)

local title_font = Font:Load("Fonts/arial.ttf", THUI:Rel2AbsY(32))
local title = THUI.Label:Create(100, 0, 0, 0, "Paused!", THUI.CENTER, THUI.TOP)
title.font = title_font

local button1 = THUI.Button:Create(0, 50, 200, 50, "Resume")

button1.click = THUI:Callback(self.ResumeButtonclicked, self)

local exitbutton = THUI.Button:Create(0, 150, 200, 50, "Exit")
exitbutton.click = THUI:Callback(self.ExitButtonclicked, self)

self.group:Add(title)
self.group:Add(button1)
self.group:Add(exitbutton)

Link to comment
Share on other sites

That looks a lot cleaner now.

 

The result of this change (which I'll be pushing to the workshop momentarily) is that CreateGroup now has a lot more arguments.

 

That's nothing compared to Win32 programming lol. Honestly it's not that bad and we only have to do it once per group which is not many compared to the controls we'd have potentially.

 

Let me know when it's updated and I'll check it out.

Link to comment
Share on other sites

I got to thinking more about it and I've never liked the default_width or default_height so I decided that if a group is going to scale it's widgets it should know it's size so it can scale up when the widget is added to it. I think this should make it more clear what's actually going on. I've updated the documentation to reflect these changes. I've probably got a couple copy/paste errors somewhere so if anyone spots something weird, please let me know.

 

I've pushed the update to steam. I've still not looked at why the positioning was wrong is different aspect ratios. Probably wont get a chance to look at that till tonight or tomorrow.

Link to comment
Share on other sites

I guess I don't get the changes you've made.

 

So if I pass 1024,767 to CreateGroup() it works, but buttons are stretched with a 16:9 ratio. If I change the values to CreateGroup() to 1919, 1079 then when I test with 1920x1080 the button's placement is not where it should be. It's way to the left.

 

self.group = THUI:CreateGroup("hello_world", self, THUI.AUTOSCALE, 0, 0, 1919, 1079)

local title = THUI.Label:Create(512, 50, 0, 0, "Hello World!", THUI.CENTER, THUI.MIDDLE)
title.font = Font:Load("Fonts/arial.ttf", THUI:Rel2AbsY(32,767))

local button1 = THUI.Button:Create(512, 300, 200, 50, "A button")
button1.font = title.font

self.group:Add(title)
self.group:Add(button1)
THUI:Activate("hello_world")

Link to comment
Share on other sites

If the group is 1024x767 units in measure, 512 is the center of the x axis so when the group is stretched out to the current resolution, it's in the middle. When you change the group to 1919x1079 units in measure the center is now around 960 of the x axis not 512, so it is on the left. When autoscale is used, the widget's position and dimensions are relative to the group's dimension. Does that make sense?

Link to comment
Share on other sites

I get it now. So I can code to a specific res and it'll scale for me no matter what res.

 

I've seen games that allow you to universally scale the UI too. Think something like that could be added? Like it auto scales and that would be 100% but then from the result of the autoscale we can provide 1 scale value which is a % from the 100% (normal autoscale)? That might be handy to give players some freedom.

 

http://cdn1.eveonline.com/www/newssystem/media/2783/3017/Esc_Scaling.png

 

http://cdn1.eveonline.com/www/newssystem/media/2783/3017/UI_Scaling_01.png

Link to comment
Share on other sites

  • 1 month later...
  • 2 weeks later...

I'm just not sure where I am going wrong, I have tried to replace the normal main.lua with the example one. I also have tried following the instructions on this page in an attempt to try and make a simple GUI Menu. When I press the esc key, nothing happens. Any help?

 

Would you post the code for your menu? I'll take a look.

Link to comment
Share on other sites

--Initialize Steamworks (optional)
Steamworks:Initialize()
--Set the application title
title="Game"
--Create a window
local windowstyle = window.Titlebar
if System:GetProperty("fullscreen")=="1" then windowstyle=windowstyle+window.FullScreen end
window=Window:Create(title,0,0,System:GetProperty("screenwidth","1024"),System:GetProperty("screenheight","768"),windowstyle)
window:HideMouse()
--Create the graphics context
context=Context:Create(window,0)
if context==nil then return end
--Create a world
world=World:Create()
world:SetLightQuality((System:GetProperty("lightquality","1")))
--Load a map
local mapfile = System:GetProperty("map","Maps/start.map")
if Map:Load(mapfile)==false then return end

while window:KeyDown(Key.Escape)==false do

--If window has been closed, end the program
if window:Closed() then break end

--Handle map change
if changemapname~=nil then

 --Clear all entities
 world:Clear()

 --Load the next map
 Time:Pause()
 if Map:Load("Maps/"..changemapname..".map")==false then return end
 Time:Resume()

 changemapname = nil
end

--Update the app timing
Time:Update()

--Update the world
world:Update()

--Render the world
world:Render()

--Render statistics
context:SetBlendMode(Blend.Alpha)
if DEBUG then
 context:SetColor(1,0,0,1)
 context:DrawText("Debug Mode",2,2)
 context:SetColor(1,1,1,1)
 context:DrawStats(2,22)
 context:SetBlendMode(Blend.Solid)
else
 --Toggle statistics on and off
 if (window:KeyHit(Key.F11)) then showstats = not showstats end
 if showstats then
  context:SetColor(1,1,1,1)
  context:DrawText("FPS: "..Math:Round(Time:UPS()),2,2)
 end
end

--Refresh the screen
context:Sync(true)

end

 

Here it is

Link to comment
Share on other sites

Sorry, posted the backup script by accident.This is the real one that I have been using (The Example one).

import "Addons/THUI/THUI.lua"
--Initialize Steamworks (optional)
Steamworks:Initialize()
--Set the application title
title="MyGame"
--Create a window
local windowstyle = window.Titlebar
if System:GetProperty("fullscreen")=="1" then windowstyle=windowstyle+window.FullScreen end
window=Window:Create(title,0,0,System:GetProperty("screenwidth","1024"),System:GetProperty("screenheight","768"),windowstyle)
window:HideMouse()
--Create the graphics context
context=Context:Create(window,0)
if context==nil then return end
THUI:Initialize()
--Create a world
world=World:Create()
world:SetLightQuality((System:GetProperty("lightquality","1")))
--Load a map
local mapfile = System:GetProperty("map","Maps/start.map")
if Map:Load(mapfile)==false then return end
paused = false
exit_game = false
while not exit_game do

--If window has been closed, end the program
if window:Closed() then break end

--Handle map change
if changemapname~=nil then

 --Clear all entities
 world:Clear()

 --Load the next map
 Time:Pause()
 if Map:Load("Maps/"..changemapname..".map")==false then return end
 Time:Resume()

 changemapname = nil
end

if not paused then
 --Update the app timing
 Time:Update()

 --Update the world
 world:Update()
end
--Render the world
world:Render()
THUI:Update()

--Render statistics
context:SetBlendMode(Blend.Alpha)
if DEBUG then
 context:SetColor(1,0,0,1)
 context:DrawText("Debug Mode",2,2)
 context:SetColor(1,1,1,1)
 context:DrawStats(2,22)
 context:SetBlendMode(Blend.Solid)
else
 --Toggle statistics on and off
 if (window:KeyHit(Key.F11)) then showstats = not showstats end
 if showstats then
  context:SetColor(1,1,1,1)
  context:DrawText("FPS: "..Math:Round(Time:UPS()),2,2)
 end
end

--Refresh the screen
context:Sync(true)

end
import "Addons/THUI/THUI.lua"
function Script:Start()
--Autoscale version
---[[
self.group = THUI:CreateGroup("pause_menu", self, THUI.AUTOSCALE, nil, nil, 1023, 767)
self.group.update = THUI:Callback(self.UpdateUI, self, nil)
local title_font = Font:Load("Fonts/arial.ttf", THUI:Rel2AbsY(32, 767))
local title = THUI.Label:Create(512, 50, 0, 0, "Paused!", THUI.CENTER, THUI.MIDDLE)
title.font = title_font
local width = 200
local button1 = THUI.Button:Create(512, 300, width, 50, "Resume", THUI.CENTER, THUI.MIDDLE)
button1.click = THUI:Callback(self.ResumeButtonclicked, self)

local exitbutton = THUI.Button:Create(512, 400, width, 50, "Exit", THUI.CENTER, THUI.MIDDLE)
exitbutton.click = THUI:Callback(self.ExitButtonclicked, self)
self.group:Add(title)
self.group:Add(button1)
self.group:Add(exitbutton)
--]]
--Anchored version
--[[
self.group = THUI:CreateGroup("pause_menu", self, THUI.ANCHOR, THUI.LEFT, THUI.MIDDLE, 200, 200)
local title_font = Font:Load("Fonts/arial.ttf", THUI:Rel2AbsY(32, 767))
local title = THUI.Label:Create(100, 0, 0, 0, "Paused!", THUI.CENTER, THUI.TOP)
title.font = title_font
local button1 = THUI.Button:Create(0, 50, 200, 50, "Resume")
button1.click = THUI:Callback(self.ResumeButtonclicked, self)

local exitbutton = THUI.Button:Create(0, 150, 200, 50, "Exit")
exitbutton.click = THUI:Callback(self.ExitButtonclicked, self)
self.group:Add(title)
self.group:Add(button1)
self.group:Add(exitbutton)
--]]
--Absolute version
--[[
self.group = THUI:CreateGroup("pause_menu", self, THUI.ABSOLUTE)
local title_font = Font:Load("Fonts/arial.ttf", THUI:Rel2AbsY(32, 767))
local title = THUI.Label:Create(400, 200, 0, 0, "Paused!", THUI.CENTER, THUI.TOP)
title.font = title_font
local button1 = THUI.Button:Create(300, 250, 200, 50, "Resume")
button1.click = THUI:Callback(self.ResumeButtonclicked, self)

local exitbutton = THUI.Button:Create(300, 350, 200, 50, "Exit")
exitbutton.click = THUI:Callback(self.ExitButtonclicked, self)
self.group:Add(title)
self.group:Add(button1)
self.group:Add(exitbutton)
--]]
end
function Script:ResumeButtonclicked(button)
self:HideMenu()
end
function Script:ExitButtonclicked(button)
exit_game = true
end
function Script:UpdateWorld()
if window:KeyHit(Key.Escape) then
 if not paused then
  self:ShowMenu()
 end
end
end
function Script:UpdateUI(group, arg)
if window:KeyHit(Key.Escape) then
 if paused then
  self:HideMenu()
 end
end
end
function Script:ShowMenu()
paused = true
Time:Pause()
THUI:Activate("pause_menu")
end
function Script:HideMenu()
paused = false
Time:Resume()
THUI:Deactivate()
--FPSPlayer.lua measures the distance from the middle of the screen to figure out how much
--the player is trying to look so we need to reset it when the user is done with the UI
local context = Context:GetCurrent()
Window:GetCurrent():SetMousePosition(Math:Round(context:GetWidth()/2), Math:Round(context:GetHeight()/2))
end

Link to comment
Share on other sites

Sorry, posted the backup script by accident.This is the real one that I have been using (The Example one).

Is that whole thing in your Main.lua? If so, you've got the pause screen script combined with the Main.lua script. The second portion (starting with the second "import" line to the end) should go in it's own script and be assigned to a pivot in your level.

Link to comment
Share on other sites

I was doing some edits to the pause menu to make it pop up once the player starts the game-and it does. Unfortunately I can't seem to it so once the player clicks on Resume the script goes back to normal. Heres a copy of my most succesful attempt

--The Hankinator's UI library
--For this script to work, you need to modify your Main.lua to
--only call Time:Update() and world:Update() when paused is false.
--Take a look at the Main.lua in the example's directory
import "Addons/THUI/THUI.lua"
Script.startPause = true

function Script:Start()
--Autoscale version
---[[
self.group = THUI:CreateGroup("pause2", self, THUI.AUTOSCALE, nil, nil, 1023, 767)
self.group.update = THUI:Callback(self.UpdateUI, self, nil)
local title_font = Font:Load("Fonts/arial.ttf", THUI:Rel2AbsY(32, 767))
local title = THUI.Label:Create(512, 50, 0, 0, "Parkour Game", THUI.CENTER, THUI.MIDDLE)
title.font = title_font
local width = 200
local button1 = THUI.Button:Create(512, 300, width, 50, "Play", THUI.CENTER, THUI.MIDDLE)
button1.click = THUI:Callback(self.ResumeButtonclicked, self)

local exitbutton = THUI.Button:Create(512, 400, width, 50, "Exit", THUI.CENTER, THUI.MIDDLE)
exitbutton.click = THUI:Callback(self.ExitButtonclicked, self)
self.group:Add(title)
self.group:Add(button1)
self.group:Add(exitbutton)
--]]
--Anchored version
--[[
self.group = THUI:CreateGroup("pause_menu", self, THUI.ANCHOR, THUI.LEFT, THUI.MIDDLE, 200, 200)
local title_font = Font:Load("Fonts/arial.ttf", THUI:Rel2AbsY(32, 767))
local title = THUI.Label:Create(100, 0, 0, 0, "Paused!", THUI.CENTER, THUI.TOP)
title.font = title_font
local button1 = THUI.Button:Create(0, 50, 200, 50, "Resume")
button1.click = THUI:Callback(self.ResumeButtonclicked, self)

local exitbutton = THUI.Button:Create(0, 150, 200, 50, "Exit")
exitbutton.click = THUI:Callback(self.ExitButtonclicked, self)
self.group:Add(title)
self.group:Add(button1)
self.group:Add(exitbutton)
--]]
--Absolute version
--[[
self.group = THUI:CreateGroup("pause_menu", self, THUI.ABSOLUTE)
local title_font = Font:Load("Fonts/arial.ttf", THUI:Rel2AbsY(32, 767))
local title = THUI.Label:Create(400, 200, 0, 0, "Paused!", THUI.CENTER, THUI.TOP)
title.font = title_font
local button1 = THUI.Button:Create(300, 250, 200, 50, "Resume")
button1.click = THUI:Callback(self.ResumeButtonclicked, self)

local exitbutton = THUI.Button:Create(300, 350, 200, 50, "Exit")
exitbutton.click = THUI:Callback(self.ExitButtonclicked, self)
self.group:Add(title)
self.group:Add(button1)
self.group:Add(exitbutton)
--]]
end
function Script:ResumeButtonclicked(button)
 if self.startPause==true then self.startPause = false
end
self:HideMenu()
end
function Script:ExitButtonclicked(button)
exit_game = true
end
function Script:UpdateWorld()
if window:KeyHit(Key.Escape) or self.startPause == true then
 if not paused then
  self:ShowMenu()
 end
end
end
function Script:UpdateUI(group, arg)
if window:KeyHit(Key.Escape) then
 if paused then
  self:HideMenu()
 end
end
end
function Script:ShowMenu()
paused = true
Time:Pause()
THUI:Activate("pause2")
end
function Script:HideMenu()
paused = false
Time:Resume()
THUI:Deactivate()
--FPSPlayer.lua measures the distance from the middle of the screen to figure out how much
--the player is trying to look so we need to reset it when the user is done with the UI
local context = Context:GetCurrent()
Window:GetCurrent():SetMousePosition(Math:Round(context:GetWidth()/2), Math:Round(context:GetHeight()/2))
end

Link to comment
Share on other sites

I was doing some edits to the pause menu to make it pop up once the player starts the game-and it does. Unfortunately I can't seem to it so once the player clicks on Resume the script goes back to normal. Heres a copy of my most succesful attempt

 

What are you trying to achieve? When I tried your script, the game starts paused with your menu up.

 

Something I noticed is that I placed

paused = false

in an unfortunate spot in Main.lua. I should have put it above loading the map. If you do that, to show the Pause menu when the game starts you can just put self:ShowMenu() at the end the Start() function in your script. The solution you have now is perfectly fine though.

Link to comment
Share on other sites

  • 4 weeks later...

Hi, I've been testing the Pause and Journal scripts following the provided instructions. I managed to get Pause to work fine but it seems that the Journal script creates a script error in Core.lua on Line 74 (attempt to index a nil value). For testing, do I simply attach JournalEntry.lua to a Model or am I missing something? I'm new to Leadwerks and Lua so please forgive any newb oversights.

Thanks!

Link to comment
Share on other sites

Hi, I've been testing the Pause and Journal scripts following the provided instructions. I managed to get Pause to work fine but it seems that the Journal script creates a script error in Core.lua on Line 74 (attempt to index a nil value). For testing, do I simply attach JournalEntry.lua to a Model or am I missing something? I'm new to Leadwerks and Lua so please forgive any newb oversights.

Thanks!

Do you have the Journal.lua script on a pivot in your scene?

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...