I spent the morning building a very basic login screen. It prompts the user for a username/password, and then does some basic debugging.
Features
- Verification - When the form is submitted it checks to make sure that a username and password have been entered and throws an error at the user if they didn’t enter either field.
- Points to Missing Field - if the user tries to submit the form without a password, it will set the cursor to the password field after giving the error message. Same with the username field.
- Tab Cycling - pressing the TAB key will cycle the cursor between the username and password box
- Submission - the form can be submitted by click in the Login button or hitting the ENTER key
- Layout Modification - every form element’s position is set relative to a simple Vec3 coordinate. Thus you can change the entire form positioning by changing the Vec3 variable coordinates (boxloc variable), or edit the coordinates of each individual element
Important Info
- This code does NOT include any kind of client-server authentication or networking code of any kind. It’s just a simple interface. I’m working on the networking bit next. All this will do right now is give you a really simple and easy-to-manipulate login screen that is very easy to change.
- It’s really easy to add a background image behind the login form with a DirectImage object to make it look somewhat nice.
- Additionally, the login box does not shift to the right as it appears in the screenshots below. That’s just my really bad pasting with Photoshop.
- No textures or other external files are needed. The interface runs entirely off built-in Panda code.
Preview:
Code:
import direct.directbase.DirectStart
from direct.showbase.DirectObject import DirectObject
from direct.gui.OnscreenText import OnscreenText
from direct.gui.DirectGui import *
from pandac.PandaModules import *
### client logic
# connect to patcher to see if update is available
# connect to login server
# send login credentials
class GameClient(DirectObject):
def __init__(self):
base.setBackgroundColor( 0, 0, 0 )
# sets the background color to black because the
# default grey color bugs me for some reason
self.loginScreen()
# draws the login screen
self.usernameBox['focus'] = 1
# sets the cursor to the username field by default
self.accept('tab', self.cycleLoginBox)
# enables the user to cycle through the text fields with the tab key
# this is a standard feature on most login forms
self.accept('enter', self.attemptLogin)
# submits the login form, or you can just click the Login button
def loginScreen(self):
# creates a basic login screen that asks for a username/password
boxloc = Vec3(0.0, 0.0, 0.0)
# all items in the login form will have a position relative to this
# this makes it easier to shift the entire form around once we have
# some graphics to display with it without having to change the
# positioning of every form element
# p is the position of the form element relative to the boxloc
# coordinates set above it is changed for every form element
p = boxloc + Vec3(-0.5, 0, 0.0)
self.textObject = OnscreenText(text = "Username:", pos = p, scale = 0.07,fg=(1, 1, 1, 1),align=TextNode.ALeft)
# "Username: " text that appears beside the username box
p = boxloc + Vec3(-0.1, 0.0, 0.0)
self.usernameBox = DirectEntry(text = "" , pos = p, scale=.05, initialText="", numLines = 1)
# Username textbox where you type in your username
p = boxloc + Vec3(-0.5, -0.1, 0.0)
self.textObject = OnscreenText(text = "Password:", pos = p, scale = 0.07,fg=(1, 1, 1, 1),align=TextNode.ALeft)
# "Password: " text that appears beside the password box
p = boxloc + Vec3(-0.1, 0, -0.1)
self.passwordBox = DirectEntry(text = "" , pos = p, scale=.05, initialText="", numLines = 1, obscured = 1)
# Password textbox where you type in your password
# Note - obscured = 1 denotes that all text entered will be replaced
# with a * like a standard password box
p = boxloc + Vec3(0, 0, -0.2)
self.loginButton = DirectButton(text = ("Login", "Login", "Login", "Login"), pos = p, scale = 0.075, command=self.attemptLogin)
# The 'Login' button that will trigger the attemptLogin function
# when clicked
p = boxloc + Vec3(-0.5, -0.4, 0)
self.statusText = OnscreenText(text = "", pos = p, scale = 0.05, fg = (1, 0, 0, 1), align=TextNode.ALeft)
# A simple text object that you can display an error/status messages
# to the user
def updateStatus(self, statustext):
self.statusText.setText(statustext)
# all this does is change the status text.
def attemptLogin(self):
# checks to make sure the user inputed a username and password:
# if they didn't it will spit out an error message
# if they did, it will try to connect to the login server
# (under construction)
if(self.usernameBox.get() == ""):
if(self.passwordBox.get() == ""):
self.updateStatus("ERROR: You must enter a username and password before logging in.")
else:
self.updateStatus("ERROR: You must specify a username")
self.passwordBox['focus'] = 0
self.usernameBox['focus'] = 1
elif(self.passwordBox.get() == ""):
self.updateStatus("ERROR: You must enter a password")
self.usernameBox['focus'] = 0
self.passwordBox['focus'] = 1
else:
self.updateStatus("Attempting to login...")
print "Attempting to connect to Server with credentials: (" + self.usernameBox.get() + ", " + self.passwordBox.get() + ")"
#
# this is where the networking code will get put in
#
def cycleLoginBox(self):
# function is triggered by the tab key so you can cycle between
# the two input fields like on most login screens
# IMPORTANT: When you change the focus to one of the text boxes,
# you have to unset the focus on the other textbox. If you do not
# do this Panda seems to get confused.
if(self.passwordBox['focus'] == 1):
self.passwordBox['focus'] = 0
self.usernameBox['focus'] = 1
elif(self.usernameBox['focus'] == 1):
self.usernameBox['focus'] = 0
self.passwordBox['focus'] = 1
Client = GameClient()
run()