# -*- indent-tabs-mode: t -*-
# Soya 3D tutorial
# Copyright (C) 2005 Javier Correa Villanueva (jbcorrea@puc.cl)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# widget-1: Widget system : a game presentation
# WARNING :
# soya.widget is now deprecated, you should rather consider using soya.pudding instead.
#!/usr/bin/env python -O
import sys, os, os.path
import soya
import soya.sdlconst
import soya.widget as widget
soya.init()
soya.path.append(os.path.join(os.path.dirname(sys.argv[0]), "data"))
# Some fonts
big_font = soya.Font(os.path.join(soya.DATADIR, "FreeSans.ttf"), 40, 60)
medium_font=widget.default_font
small_font = soya.Font(os.path.join(soya.DATADIR, "FreeSans.ttf"), 10, 15)
# This class is to get an input widget
# When you press RETURN key, it will call action with the text introduced as parameter
class Input(widget.Label):
def __init__(self, master = None, text = "", action=None,align = 0, color = (1.0, 1.0, 1.0, 1.0), font = None, resize_style = None):
self.action=action
widget.Label.__init__(self,master,text,align,color,font,resize_style)
def widget_begin_round(self):
for event in soya.MAIN_LOOP.events:
self.process_event(event)
def process_event(self,event):
if event[0]==soya.sdlconst.KEYDOWN :
if event[1]==soya.sdlconst.K_RETURN or event[1]==soya.sdlconst.K_KP_ENTER:
if self.action:
self.action(self.text)
else:
pass
elif event[1]==soya.sdlconst.K_DELETE or event[1]==soya.sdlconst.K_BACKSPACE:
if len(self.text)>0:
length=len(self.text)
temp_text=self.text[0:length-1]
self.text=temp_text
elif event[1]<256 and chr(event[1]).isalnum():
last_character=event[1]
# Now check is shift is pressed, i had to use numbers instead of
# macros, my soya isntalation didn't have macros for shift modification
if event[2]==1 or event[2]==2:
last_character-=32
temp_text=self.text
temp_text=temp_text+chr(last_character)
self.text=temp_text
# Password input, same as normal input, but display only * when character are introduced
class PasswordInput(widget.Label):
def __init__(self, master = None, text = "", action=None,align = 0, color = (1.0, 1.0, 1.0, 1.0), font = None, resize_style = None):
self.action=action
self.real_text=""
widget.Label.__init__(self,master,text,align,color,font,resize_style)
def widget_begin_round(self):
for event in soya.MAIN_LOOP.events:
self.process_event(event)
def process_event(self,event):
if event[0]==soya.sdlconst.KEYDOWN :
if event[1]==soya.sdlconst.K_RETURN or event[1]==soya.sdlconst.K_KP_ENTER:
if self.action:
self.action(self.real_text)
else:
pass
elif event[1]==soya.sdlconst.K_DELETE or event[1]==soya.sdlconst.K_BACKSPACE:
if len(self.text)>0:
length=len(self.text)
temp_text=self.text[0:length-1]
self.text=temp_text
temp_text=self.real_text[0:length-1]
self.real_text=temp_text
elif event[1]<256 and chr(event[1]).isalnum():
last_character=event[1]
if event[2]==1 or event[2]==2:
last_character-=32
self.text+='*'
self.real_text=self.real_text+chr(last_character)
# Widget with a few effects, fade and move
# It may be very ineficient
class EffectWidget:
# Change the init so if read a hash with the information to change
def __init__(self,fade_speed=0.05,up_speed=1.5,down_speed=1.5,left_speed=1.5,right_speed=1.5):
# Variables for fading effect
self.fadein=None
self.fadeout=None
self.faded=1
self.fade_speed=fade_speed
# Variable for moving
self.move_up=None
self.move_down=None
self.move_right=None
self.move_left=None
self.up_speed=up_speed
self.down_speed=down_speed
self.right_speed=right_speed
self.left_speed=left_speed
# The distance to move
self.up_distance=50
self.down_distance=50
self.left_distance=50
self.right_distance=50
# The traveled so far
self.up_travel=0
self.down_travel=0
self.left_travel=0
self.right_travel=0
def fadeIn(self):
self.fadein=1
self.fadeout=None
def fadeOut(self):
self.fadeout=1
self.fadein=None
def startUp(self):
self.move_up=1
self.move_down=None
def stopUp(self):
self.move_up=None
def startDown(self):
self.move_down=1
self.move_up=None
def stopDown(self):
self.move_down=None
def startLeft(self):
self.move_left=1
self.move_right=None
def stopLeft(self):
self.move_left=None
def startRight(self):
self.move_right=1
self.move_left=None
def stopRight(self):
self.move_right=None
def resetMove(self):
# Variable for moving
self.move_up=None
self.move_down=None
self.move_right=None
self.move_left=None
# The traveled so far
self.up_travel=0
self.down_travel=0
self.left_travel=0
self.right_travel=0
def doMove(self,proportion):
# Implementation of moving animation
if self.move_up:
if self.up_travel>self.up_distance:
self.move_up=None
self.up_travel=0
else:
self.top-=self.up_speed*proportion
self.up_travel+=self.up_speed*proportion
if self.move_down:
if self.down_travel>self.down_distance:
self.move_down=None
self.down_travel=0
else:
self.top+=self.down_speed*proportion
self.down_travel+=self.down_speed*proportion
if self.move_left:
if self.left_travel>self.left_distance:
self.move_left=None
self.left_travel=0
else:
self.top-=self.left_speed*proportion
self.left_travel+=self.left_speed*proportion
if self.move_right:
if self.right_travel>self.right_distance:
self.move_right=None
self.right_travel=0
else:
self.top+=self.right_speed*proportion
self.right_travel+=self.right_speed*proportion
# A choice wich is fadable also
class EffectChoice(EffectWidget,widget.ChoiceList):
def __init__(self, master = None, choices = [], font = None, color = (1.0, 0.5, 0.5,0.0),highlight = (1.0, 1.0, 0.0, 0.0), cancel = None,align=1,fade_speed=0.05):
widget.ChoiceList.__init__(self,master,choices,font,color,highlight,cancel,align)
EffectWidget.__init__(self,fade_speed)
def widget_begin_round(self):
if not self.faded:
widget.ChoiceList.widget_begin_round(self)
for event in soya.MAIN_LOOP.events:
self.process_event(event)
def widget_advance_time(self,proportion):
# Implementation of fadinf animation
if self.fadeout:
r1,g1,b1,a=self.color
r2,g2,b2,a2=self.highlight
a-=self.fade_speed*proportion
if a<0:
self.master.remove(self)
self.fadeout=None
self.faded=1
self.color=(r1,g1,b1,a)
self.highlight=(r2,g2,b2,a)
elif self.fadein:
if self.faded:
self.faded=None
r1,g1,b1,a=self.color
r2,g2,b2,a2=self.highlight
a+=self.fade_speed*proportion
if a<1:
self.color=(r1,g1,b1,a)
self.highlight=(r2,g2,b2,a)
else:
self.fadein=None
self.faded=None
self.doMove(proportion)
# A fadable label
class EffectLabel(EffectWidget,widget.Label):
def __init__(self, master = None, text = "", align = 0, color = (1.0, 1.0, 1.0, 0.0), font = None,resize_style = None,fade_speed=0.05):
widget.Label.__init__(self,master,text,align,color,font,resize_style)
EffectWidget.__init__(self,fade_speed)
def widget_advance_time(self,proportion):
if self.fadeout:
r,g,b,a=self.get_color()
a-=self.fade_speed*proportion
if a<0:
self.master.remove(self)
self.faded=1
self.fadeout=None
self.set_color((r,g,b,a))
elif self.fadein:
r,g,b,a=self.get_color()
a+=self.fade_speed*proportion
if a<1:
self.set_color((r,g,b,a))
else:
self.faded=None
self.fadein=None
self.doMove(proportion)
# The configuration screen
class ConfigureScreen(widget.Group):
def __init__(self,caller,background):
widget.Group.__init__(self)
self.caller=caller
self.state=0
if not background:
material=soya.Material()
#material.texture=soya.Image.get('back.png')
background=widget.Image(None,material)
background.resize_style=soya.widget.WIDGET_RESIZE_MAXIMIZE
self.add(background)
self.configureLabel=EffectLabel(self,'Configuration',1)
self.configureLabel.resize_style=soya.widget.WIDGET_RESIZE_MAXIMIZE
self.configureLabel.resize(0,-50,640,480)
self.configureLabel.resize_style=None
# The initial options of the game
optionResolution=widget.Choice('Change Resolution',self.changeResolution)
optionFullscreen=widget.Choice('Togle Fullscreen',self.goFullscreen)
optionServer=widget.Choice('Change Server',self.changeServer)
optionBack=widget.Choice('Back',self.goBack)
# The menu itself
self.optionsMenu=EffectChoice(self,[optionResolution,optionFullscreen,optionServer,optionBack])
self.optionsMenu.resize_style=soya.widget.WIDGET_RESIZE_MAXIMIZE
# Show the menu
self.configureLabel.fadeIn()
self.configureLabel.startDown()
self.optionsMenu.fadeIn()
def widget_begin_round(self):
widget.Group.widget_begin_round(self)
if self.state==10:
if self.configureLabel.faded:
self.master.add(self.caller)
self.master.remove(self)
self.add(self.configureLabel)
self.add(self.optionsMenu)
self.configureLabel.fadeIn()
self.configureLabel.startDown()
self.optionsMenu.fadeIn()
self.state=0
def changeResolution(self):
pass
def goFullscreen(self):
pass
def changeServer(self):
pass
def goBack(self):
self.state=10
self.configureLabel.fadeOut()
self.configureLabel.startUp()
self.optionsMenu.fadeOut()
class LoginScreen(widget.Group):
def __init__(self,background=None):
widget.Group.__init__(self)
if not background:
material=soya.Material()
#material.texture=soya.Image.get('back.png')
background=widget.Image(None,material)
background.resize_style=soya.widget.WIDGET_RESIZE_MAXIMIZE
self.add(background)
# The state on the login process
self.state=0
self.configScreen=ConfigureScreen(self,background)
# This will be the title of the game, always present
self.gameName=EffectLabel(self,"The Name of the Game",1,(.3,.3,1.0,0.0),big_font)
self.gameName.resize_style=soya.widget.WIDGET_RESIZE_MAXIMIZE
# The initial options of the game
optionLogin=widget.Choice('Login',self.startLogin)
optionConfig=widget.Choice('Configure',self.doConfiguration)
optionQuit=widget.Choice('Quit',self.quitGame)
# The menu itself
self.optionsMenu=EffectChoice(self,[optionLogin,optionConfig,optionQuit])
self.optionsMenu.resize_style=soya.widget.WIDGET_RESIZE_MAXIMIZE
# A label saying "Enter username" and user input
self.userLabel=EffectLabel(None,'Username:',1)
self.userLabel.resize_style=soya.widget.WIDGET_RESIZE_MAXIMIZE
self.userLabel.resize(0,100,640,100)
self.userLabel.resize_style=None
self.userInput=Input(None,"",self.setUser,1)
self.userInput.resize_style=soya.widget.WIDGET_RESIZE_MAXIMIZE
self.userInput.resize(0,200,640,100)
self.userInput.resize_style=None
# The password label and input
self.passLabel=EffectLabel(None,'Password:',1)
self.passLabel.resize_style=soya.widget.WIDGET_RESIZE_MAXIMIZE
self.passLabel.resize(0,100,640,100)
self.passLabel.resize_style=None
self.passInput=PasswordInput(None,"",self.doLogin,1)
self.passInput.resize_style=soya.widget.WIDGET_RESIZE_MAXIMIZE
self.passInput.resize(0,200,640,100)
self.passInput.resize_style=None
# Everything set, let's show the menu
self.optionsMenu.fadeIn()
self.gameName.fadeIn()
def widget_begin_round(self):
widget.Group.widget_begin_round(self)
if self.state==1:
if self.optionsMenu.faded:
self.optionsMenu.resetMove()
self.gameName.resetMove()
self.state=2
elif self.state==2:
self.add(self.userLabel)
self.add(self.userInput)
self.userLabel.fadeIn()
self.state=3
elif self.state==4:
if self.userLabel.faded:
self.state=5
elif self.state==5:
self.add(self.passLabel)
self.add(self.passInput)
self.passLabel.fadeIn()
self.state=6
elif self.state==10:
if self.optionsMenu.faded:
self.optionsMenu.resetMove()
self.gameName.resetMove()
self.master.add(self.configScreen)
self.master.remove(self)
# Set fadeIn, so the next time we add this widget to the root, it will fade in
self.add(self.optionsMenu)
self.add(self.gameName)
self.optionsMenu.fadeIn()
self.gameName.fadeIn()
self.state=0
def startLogin(self):
self.optionsMenu.fadeOut()
self.optionsMenu.startDown()
self.state=1
def mainMenu(self):
self.add(self.optionsMenu)
self.optionsMenu.fadeIn()
self.state=0
def setUser(self,text):
self.userLabel.fadeOut()
self.remove(self.userInput)
self.state=4
def doLogin(self,text):
self.passLabel.fadeOut()
self.remove(self.passInput)
print 'The End'
self.mainMenu()
def doConfiguration(self):
self.optionsMenu.fadeOut()
self.optionsMenu.startUp()
self.gameName.fadeOut()
self.gameName.startDown()
self.state=10
def quitGame(self):
sys.exit()
scene = soya.World()
root=soya.widget.Group()
soya.set_root_widget(root)
root.add(LoginScreen())
soya.MainLoop(scene).main_loop()
Tutorials : basic-1 - basic-2 - basic-3 - basic-4 - basic-5 - basic-6 - basic-loadingfile-1 - basic-savingfile-cerealizer-1 - basic-savingfile-pickle-1 - blender-auto-exporter-1 - bsp-game_skel - character-animation-1 - character-animation-2 - character-animation-shadow-cellshading-1 - deform-1 - facecutter-1 - fullscreen-1 - game_skel-1 - game_skel-2 - game_skel-3 - game_skel-4 - game_skel-5 - gui-1 - gui-2 - gui-background-1 - label3D-1 - modeling-1 - modeling-2 - modeling-3 - modeling-cellshading-1 - modeling-env-mapping-1 - modeling-material-1 - modeling-material-2 - modeling-shadow-1 - modeling-smoothlit-1 - modeling-solid-model-1 - modeling-transparency-1 - mouse-1 - multiple-cameras-1 - nested-world-1 - ode-collision-1-base - ode-collision-2-base - ode-collision-3-mass_influence - ode-collision-4-pushable - ode-collision-5-hit_func - ode-collision-6-hit_func-2-other - ode-collision-7-hit_func-3-contacts - ode-collision-8-terrain - ode-collision-9-box - ode-gravity - ode-join - ode-mass - ode-test - particle-1 - portal-1 - pudding-1 - pudding-2 - pudding-buttonbar-1 - pudding-buttonbar-2 - pudding-console-1 - pudding-console-2 - pudding-game_skel-5 - pudding-image-1 - pudding-image-slicing-1 - pudding-input-1 - pudding-listbox-1 - pudding-menu-1 - pudding-meter-1 - pudding-svgelements-1 - pudding-z-index-1 - ray-1 - raypicking-1 - raypicking-2 - raypicking-3 - shader-1 - shader-2 - shader-3 - shader-4 - sound-1 - soya-with-tk-1 - speed-1 - state-1 - static-shadows-1 - terrain-1 - terrain-2 - test - traveling-camera-1 - widget-1 - widget-background-1