ES/Introducción a la Programación de GUI: Difference between revisions

From Multi Theft Auto: Wiki
Jump to navigation Jump to search
No edit summary
 
(4 intermediate revisions by 3 users not shown)
Line 95: Line 95:


===Uso de la función anterior===
===Uso de la función anterior===
La función createLoginWindow ha sido completada, pero no hará nada hasta procesarlo. Es recomendable hacer todo el GUI cuando el resource del cliente se inicie, ocultarlo, y mostrarle al jugador cuando sea necesario. Por lo tanto, vamos a escribir un "event handler" para "[[onClientResourceStart]]" para crear la siguiente ventana:
La función createLoginWindow ha sido completada, pero no hará nada hasta procesarlo. Es recomendable hacer todo el GUI cuando el resource del cliente se inicie, ocultarlo, y mostrarle al jugador cuando sea necesario. Por lo tanto, vamos a escribir un "event handler" para "[[onClientResourceStart]]" para crear la ventana:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
-- attach the event handler to the root element of the resource
-- esto significa que se iniciará cuando el propio resource se inicie
-- this means it will only trigger when its own resource is started
addEventHandler("onClientResourceStart", getResourceRootElement(getThisResource()),  
addEventHandler("onClientResourceStart", getResourceRootElement(getThisResource()),  
function ()
function ()
Line 106: Line 105:
</syntaxhighlight>
</syntaxhighlight>


As this is a log in window, we now need to show the window when the player joins the game.  
Como en la ventana han de registrarse, la ventana se mostrará cuando el jugador entre al juego.  
This can be done using the same event, "[[onClientResourceStart]]", so we can modify the above code to include showing the window:
Para esto, se puede usar el mismo evento, "[[onClientResourceStart]]", con lo que podemos modificar el código anterior para mostrar la ventana:


'''Note that we are now writing more code for our existing 'onClientResourceStart' handler. This is not a new event handler and is meant to replace what you already have.'''  
'''Tenga en cuenta que ahora estamos escribiendo más código para nuestro actual 'onClientResourceStart'.Este no es un nuevo evento, está destinado a reemplazar el qué ya tienes.'''  
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
addEventHandler("onClientResourceStart", getResourceRootElement(getThisResource()),  
addEventHandler("onClientResourceStart", getResourceRootElement(getThisResource()),  
function ()
function ()
-- create the log in window and its components
-- crear el registro con sus componentes dentro de la ventana
createLoginWindow()
createLoginWindow()


-- output a brief welcome message to the player
-- emitir un mensaje de bienvenida al jugador
                 outputChatBox("Welcome to My MTA:SA Server, please log in.")
                 outputChatBox("Welcome to My MTA:SA Server, please log in.")


-- if the GUI was successfully created, then show the GUI to the player
-- si la interfaz gráfica de usuario se creó correctamente, a continuación, mostrar la interfaz gráfica de usuario para el jugador
        if (wdwLogin ~= nil) then
        if (wdwLogin ~= nil) then
guiSetVisible(wdwLogin, true)
guiSetVisible(wdwLogin, true)
else
else
-- if the GUI hasnt been properly created, tell the player
-- si la interfaz gráfica no se ha creado correctamente, se lo dirá al jugador
outputChatBox("An unexpected error has occurred and the log in GUI has not been created.")
outputChatBox("An unexpected error has occurred and the log in GUI has not been created.")
        end  
        end  


-- enable the players cursor (so they can select and click on the components)
-- mostrar el cursor al jugador ( para que pueda seleccionar y pulsar los botones )
        showCursor(true)
        showCursor(true)
-- set the input focus onto the GUI, allowing players (for example) to press 'T' without the chatbox opening
-- establecer el foco de entrada en la interfaz gráfica de usuario, permitiendo a los jugadores (por ejemplo) al pulsar 'T' sin que salga la apertura en el chat
        guiSetInputEnabled(true)
        guiSetInputEnabled(true)
end
end
Line 135: Line 134:
</syntaxhighlight>
</syntaxhighlight>


Note that we have a simple security check before making the window visible, so in the unlikely event that the window has not been created, meaning wdwLogin is not a valid element, we don't get an error and just inform the player what has happened.  
Tenga en cuenta que tenemos un sencillo "control de seguridad" antes de hacer la ventana visible, por lo que en el caso improbable de que la ventana no se haya creado, es decir wdwLogin no es un elemento válido, no se obtiene un error y simplemente se informa al jugador de lo que ha sucedido .
In the next step, we will create the button functionality for the log in button.
En el siguiente paso, vamos a crear la funcionalidad del botón para el botón "Iniciar sesión".


==Scripting the button==
==Scripteando el boton==
Now that we have created our GUI and shown it to the player, we need to make it work.  
Ahora que tenemos creado nuestro GUI and se lo hemos mostrado a un jugador, nesecitamos hacerlo funcionar.


===Detecting the click===
===Detectando el click===
When the player clicks on any part of the GUI, the event "[[onClientGUIClick]]" will be triggered for the GUI component you clicked on. This allows us to easily detect any clicks on the GUI elements we want to use.
Cuando un jugador clickea en alguna parte del GUI, el evento "[[onClientGUIClick]]" sera triggeado para el componente GUI que tu clickeaste. Esto nos permite detectar facilmente cualquier click en los elemento GUI que nosotros quisimos usar.  
For example, we can attach the event to the btnLogin button to catch any clicks on it:
Por ejemplo, podemos adjuntar el evento con el boton "btnLogin" para agarrar algun click en el:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
-- attach the event onClientGUIClick to btnLogin and set it to trigger the 'clientSubmitLogin' function
-- adjunta el evento onClientGUIClick a btnLogin y activa la funcion 'clientSubmitLogin'.
addEventHandler("onClientGUIClick", btnLogin, clientSubmitLogin, false)
addEventHandler("onClientGUIClick", btnLogin, clientSubmitLogin, false)
</syntaxhighlight>
</syntaxhighlight>
'''Note the final argument passed is "false". This indicates that the event will only trigger directly on btnLogin, not if the event has propagated up or down the tree. Setting this to "true" while attaching to gui elements will mean that clicking on any element in the same branch will trigger this event.'''
'''Que quede claro que el argumento final es pasado a "false". Esto indica que el evento solo se va a activar directamente en btnLogin, sino el evento se tiene que propagarse por todo los elementos. Ajusta esto a true mientras adjunta a los elementos GUI querra decir que algun click en cualquier elemento en el mismo se activara este evento.'''


This line of code can now be added inside the createLoginWindow function. It is a common mistake to try and attach events to non-existant GUI elements, so make sure you always attach your events '''after''' the gui element (in this case, the button) has been created:
Esta linea del codigo podra ahora ser añadida dentro de la funcion createLoginWindow. Esto es un error comun al intentar y adjuntar los eventos a algun elemento GUI inexistente, por lo tanto hacer que siempre el evento se adjunte '''despues''' the crear los elementos GUI (en este caso, el boton) ha sido creado:


'''Note that we are now writing more code for our existing 'createLoginWindow' function.'''  
'''Nota que ahora estamos escribiendo mas codigo para la existencia de la funcion 'createLoginWindow'
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function createLoginWindow()
function createLoginWindow()
-- create all our GUI elements
-- crea todos los elementos GUI
...
...


-- now add our onClientGUIClick event to the button we just created
-- Ahora añadimos nuevo evento onClientGUIClick al evento luego de ser creado.
addEventHandler("onClientGUIClick", btnLogin, clientSubmitLogin, false)
addEventHandler("onClientGUIClick", btnLogin, clientSubmitLogin, false)
</syntaxhighlight>
</syntaxhighlight>


===Managing the click===
===Administrar el clic===
Now that we can detect when the player clicks on the button, we need to write code to manage what happens when they do.
Ahora para detectar cuando le damos clic al boton, tenemos que escribir código para manejar lo que suceda cuando lo pulsen.
In our [[onClientGUIClick]] event handle, we told it to call the function clientSubmitLogin whenever btnLogin is clicked.
En nuestro controlador de evento [[onClientGUIClick]], le dijimos que llamara a la función clientSubmitLogin cada vez que se hace clic en btnLogin. Por lo tanto, ahora podemos utilizar la función clientSubmitLogin para controlar lo que ocurre cuando se hace clic en el botón:
Therefore, we can now use the function clientSubmitLogin to control what happens when the button is clicked:
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
-- create the function and define the 'button' and 'state' parameters
-- Crea la función y definir los parámetros 'Botón' y 'Estado'.
-- (these are passed automatically by onClientGUIClick)
-- (éstos pasan automáticamente por OnClientClick)
function clientSubmitLogin(button,state)
function clientSubmitLogin(button,state)
-- if our login button was clicked with the left mouse button, and the state of the mouse button is up
-- si nuestro botón "login" es clickeado con el botón izquierdo del ratón, y soltado el botón izquierdo.
if button == "left" and state == "up" then
if button == "left" and state == "up" then
-- move the input focus back onto the game (allowing players to move around, open the chatbox, etc)
-- move the input focus back onto the game (allowing players to move around, open the chatbox, etc)
guiSetInputEnabled(false)
guiSetInputEnabled(false)
-- hide the window and all the components
-- esconde la ventana y todos sus componentes
guiSetVisible(wdwLogin, false)
guiSetVisible(wdwLogin, false)
-- hide the mouse cursor
-- esconde el cursor del ratón
showCursor(false)
showCursor(false)
end
end
end
end
</syntaxhighlight>
</syntaxhighlight>
Now, when the button is clicked, the window will be hidden and all controls will be returned to the player. Next, we will tell the server to allow the player to spawn.
Ahora, cuando al botón le den clic, la ventana se debera esconder y todos los controles volveran. Despues, deberemos decirle al servidor que permita spawnear al jugador.


===Triggering the server===
===Triggering el server===
Triggering the server can be done using [[triggerServerEvent]]. This allows you to trigger a specified event on the server from the client. The same can be done in reverse using [[triggerClientEvent]].
La activación del server se puede hacer usando [[triggerServerEvent]]. Esto le permite activar un evento especificado en el servidor desde el cliente. El mismo se puede hacer a la inversa usando [[triggerClientEvent]]. Aquí, nosotros usamos la función [[triggerServerEvent]] para llamar a nuestro serverEvent personalizado, denominado "submitLogin", que a su vez controla el desove del jugador serverside.
Here, we use the [[triggerServerEvent]] function to call our own custom event on the server, named "submitLogin", which will then control the spawning of the player serverside.


'''Note that we are now writing more code for our existing 'clientSubmitLogin' function. This is not a new function and is meant to replace what you already have.'''  
'''Tenga en cuenta que ahora estamos escribiendo más código para nuestra función 'clientSubmitLogin' existente. Esto no es una nueva función y está destinado a reemplazar lo que ya tienes. '''
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function clientSubmitLogin(button,state)
function clientSubmitLogin(button,state)
if button == "left" and state == "up" then
if button == "left" and state == "up" then
-- get the text entered in the 'username' field
-- tomar el texto introducido en el campo 'username'
local username = guiGetText(edtUser)
local username = guiGetText(edtUser)
-- get the text entered in the 'password' field
-- tomar el texto introducido en el campo 'password'
local password = guiGetText(edtPass)
local password = guiGetText(edtPass)


-- if the username and password both exist
-- si el nombre de usuario y contraseña ambos existen
if username and password then
if username and password then
-- trigger the server event 'submitLogin' and pass the username and password to it
-- activar el server 'submitLogin' y pasar el nombre de usuario y contraseña a la misma.
triggerServerEvent("submitLogin", getRootElement(), username, password)
triggerServerEvent("submitLogin", getRootElement(), username, password)


-- hide the gui, hide the cursor and return control to the player
-- ocultar la gui, ocultar el cursor y devolver el control al player
guiSetInputEnabled(false)
guiSetInputEnabled(false)
guiSetVisible(wdwLogin, false)
guiSetVisible(wdwLogin, false)
showCursor(false)
showCursor(false)
else
else
-- otherwise, output a message to the player, do not trigger the server
-- de otro modo, presentar un mensaje para el jugador, no activar el server
-- and do not hide the gui
-- y no ocultar la gui
outputChatBox("Please enter a username and password.")
outputChatBox("Please enter a username and password.")
end
end
Line 214: Line 211:
</syntaxhighlight>
</syntaxhighlight>


===Creating the serverside event===
===Crear el evento serverside===
At this point we now have all the code needed on the client side, so open up your serverside 'script.lua' file (from the [[Scripting Introduction|Introduction to Scripting]]) or another suitable serverside file to work with.
En este punto, ahora tenemos todo el código necesario en el clienteside, por lo que abrimos el archivo 'script.lua' serverside (desde el [[Scripting Introduction|Introduction to Scripting]]) u otro archivo serverside adecuado para trabajar.


On the server side, recall that we are spawning the player as soon as they login.
En el lado del servidor, recordamos que estamos spawneando al jugador tan pronto como se loguea.
So, first of all, we will need to define the custom event that we used before on the client. This can be done using [[addEvent]] and [[addEventHandler]].
Así que, en primer lugar, tendremos que definir el evento personalizado que se utilizó antes en el cliente. Esto se puede hacer usando [[addEvent]] y [[AddEventHandler]].
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
-- create our loginHandler function, with username and password parameters (passed from the client gui)
-- create our loginHandler function, with username and password parameters (passed from the client gui)
Line 232: Line 229:


===Logging in===
===Logging in===
Now we have a function that is called through the custom event 'submitLogin', we can start to work on logging in and spawning the player, using our 'loginHandler' function:
Ahora tenemos una función que es llama a través del evento personalizado 'submitLogin', podemos empezar a trabajar en el on logging y el spawning del jugador, haciendo uso de nuestra funcion 'loginHandler':
<syntaxhighlight lang="lua">
<syntaxhighlight lang="lua">
function loginHandler(username,password)
function loginHandler(username,password)
-- check that the username and password are correct
-- compruebe que el nombre de usuario y la contraseña son correctos
if username == "user" and password == "apple" then
if username == "user" and password == "apple" then
-- the player has successfully logged in, so spawn them
-- el jugador se ah logueado satisfactoriamente, asi que debe spawnearlo
if (client) then
if (client) then
spawnPlayer(client, 1959.55, -1714.46, 10)
spawnPlayer(client, 1959.55, -1714.46, 10)
Line 245: Line 242:
end
end
else
else
-- if the username or password are not correct, output a message to the player
-- si el nombre de usuario o contraseña no es correcta, enviar un mensaje al player
outputChatBox("Invalid username and password. Please re-connect and try again.",client)
outputChatBox("Invalid username and password. Please re-connect and try again.",client)
         end
         end
Line 253: Line 250:
addEventHandler("submitLogin",root,loginHandler)
addEventHandler("submitLogin",root,loginHandler)
</syntaxhighlight>
</syntaxhighlight>
'''For the purposes of this tutorial, a very basic username and password system is shown. For a more comprehensive alternative, you can use the Account System or a MySQL database.'''
'''Para los fines de este tutorial, se muestra un sistema de nombre de usuario y una contraseña muy básico. Por una alternativa más completa, se puede utilizar el Sistema de cuentas o una base de datos MySQL.'''


Also note the use of the variable "client", it's an internal variable used by MTA to identify the player who triggered the event.  
También tenga en cuenta el uso dela variable "client", es una variable interna que utiliza MTA para identificar al jugador que provocó el evento.


 
Por último, no se olvide de incluir el nuevo archivo gui.lua en el meta.xml del recurso principal, y etiquetarlo como un script de cliente:
Finally, do not forget to include the new gui.lua file in the meta.xml of the main resource, and label it as a client script:
<syntaxhighlight lang="xml">
<syntaxhighlight lang="xml">
<script src="client/gui.lua" type="client" />
<script src="client/gui.lua" type="client" />
</syntaxhighlight>
</syntaxhighlight>


En este punto, ahora tenemos una ventana de base de inicio de sesión que comprueba el nombre de usuario y la contraseña del jugador cuando se hace clic en el botón de inicio de sesión. Si son correctos, el jugador se spawneara de forma automática.


At this point, we now have a basic login window that checks the player's username and password when the login button is clicked. If they are correct, the player is automatically spawned.
Para obtener más ayuda con la GUI, consulte la [[:Category:GUI_Tutorials|GUI tutorials]].
 
For further help with GUI, see the [[:Category:GUI_Tutorials|GUI tutorials]].


[[Category:GUI_Tutorials]]
[[Category:GUI_Tutorials]]

Latest revision as of 20:41, 7 April 2014

Una importante caracteristica de MTA:SA es la posibilidad de programar GUIs propias (Graphics User Interface que traducido seria, Interfaz Grafica del Usuario). Una GUI consiste en ventanas, botones, cajas de edición, entre otras cosas.... Estos pueden ser mostrados mientras el jugador esta en el juego, y es usado para tener interacción con el usuario en lugar de los típicos comandos.

Consola de Administración

Un tutorial para hacer una ventana de ingreso

En este tutorial nosotros haremos una simple ventana de ingreso, con dos cajas de edición y un botón. La ventana aparecerá cuando el jugador ingrese al juego, y cuando el botón sea apretado, el jugador aparecerá. El tutorial continuara el modo que hicimos en Introducción a LUA (Si tu continuaste de la pagina anterior, tendrás que remover o comentar la linea donde se encuentra la función spawnPlayer, porque estaremos reemplazando eso con una GUI alternativa en este tutorial). También daremos una mirada a lo que es la programación en el cliente.

Dibujando la ventana

Toda GUI se debe hacer en el cliente. Esto tambien es una buena practica para tener todos los archivos de cliente en carpetas separadas.

Busca el directorio /Tu servidor MTA/mods/deathmatch/resources/myserver/, y crea una carpeta llamada "cliente". En la carpeta cliente, crea un archivo de texto y llamalo "gui.lua".

En este archivo escribiremos una función que dibuje la ventana. Para crear la ventana usaremos guiCreateWindow:

function createLoginWindow()
	-- definimos las coordenadas X,Y donde se creara la ventana
	local X = 0.375
	local Y = 0.375
	-- definimos el tamaño de la ventana (El ancho y el alto)
	local Width = 0.25
	local Height = 0.25
	-- Creamos la ventana y la grabamos su valor de elemento en la variable 'wdwLogin'
	-- Apreta en el nombre de la función para leer su definición
	wdwLogin = guiCreateWindow(X, Y, Width, Height, "Porfavor ingrese", true)
end

Relativo y absoluto

Notese que el argumento final pasado a la función guiCreateWindow en el ejemplo de arriba es true. Esto indica que las coordenadas y las dimensiones de la ventana son relativas, queriendo decir que son un porcentaje del tamaño total de la pantalla. Queriendo decir que el lado izquierdo de la pantalla es 0 y el lado derecho es 1. Una posición X de 0.5, representaría el centro de la pantalla. Similarmente, si la parte de arriba de la pantalla es 0 y la de abajo es 1, entonces una posición en Y de 0.2 seria un 20% abajo de la pantalla. Este mismo principio se aplica al ancho y alto también. (Con un ancho de 0.5, quiere decir que la ventana tendrá un ancho de la mitad de la pantalla)

La alternativa a usar valores relativos es usar absolutos (Pasando false en vez de true a guiCreateWindow)). Los valores absolutos son calculados como el numero total de pixeles de la esquina superior-izquierda de su padre (Si no se especifica un elemento padre, entonces el padre seria la pantalla en si). Si asumimos una resolución de 1920x1200, El lado izquierdo empezaría con 0 pixeles y el lado derecho tendría 1920 pixeles, una posición X de 960 representaría el centro de la pantalla. Similarmente, si el lado superior de la pantalla empieza 0 pixeles y el lado inferior termina con 1920 pixeles, una posición Y de 20 seria 20 pixeles bajo el lado superior de la pantalla. El mismo principio se aplica al ancho y al alto. Tu puedes usar guiGetScreenSize y un poco de matemáticas para calcular algunas posiciones absolutas.

Las diferencias entre usar valores relativos y absolutos es un poco simple; Una GUI creada con valores absolutos siempre tendrá el mismo tamaño y posición, mientras que una GUI creada usando valores relativos siempre sera un porcentaje del tamaño de su padre.

El valor absoluto es generalmente mas fácil de mantener cuando se edita un código a mano, aunque tu opción del tipo depende de la situación para que lo estas usando.

Para propósitos de esta introducción usaremos valores relativos. (Aunque recomiendo usar absolutos)

Añadiendo los componentes

Ahora agregaremos las etiquetas de texto (Diciendo "Usuario:" y "Contraseña:", Cajas de edición (Para ingresar los datos) y un botón para ingresar.

Para crear el botón usaremos guiCreateButton, y para crear las cajas de edición usaremos guiCreateEdit:

Nota que estamos escribiendo mas codigo de nuestra existente función 'createLoginWindow'. Esto no es una nueva función y esta pensada a reemplazar la que tu ya tenias.

function createLoginWindow()
	local X = 0.375
	local Y = 0.375
	local Width = 0.25
	local Height = 0.25
	wdwLogin = guiCreateWindow(X, Y, Width, Height, "Porfavor Ingrese", true)
	
	-- definimos las coordenadas X,Y de nuestra primera etiqueta
	X = 0.0825
	Y = 0.2
	-- definimos el ancho y el alto de nuestra primera etiqueta
	Width = 0.25
	Height = 0.25
	-- Creamos la primera etiqueta, nota que el argumento final es 'wdwLogin' significando la ventana que creamos arriba es el padre de
	-- esta etiqueta (asique todos los valores de posición y tamaño son relativos a la posición de esa ventana)
	guiCreateLabel(X, Y, Width, Height, "Usuario", true, wdwLogin)
	-- alteramos el valor Y, para que la segunda etiqueta este un poco mas abajo de la primera
	Y = 0.5
	guiCreateLabel(X, Y, Width, Height, "Contraseña", true, wdwLogin)
	

	X = 0.415
	Y = 0.2
	Width = 0.5
	Height = 0.15
	edtUser = guiCreateEdit(X, Y, Width, Height, "", true, wdwLogin)
	Y = 0.5
	edtPass = guiCreateEdit(X, Y, Width, Height, "", true, wdwLogin)
	-- Ponemos el maximo de caracteres que se pueden escribir en las cajas a 50
	guiEditSetMaxLength(edtUser, 50)
	guiEditSetMaxLength(edtPass, 50)
	
	X = 0.415
	Y = 0.7
	Width = 0.25
	Height = 0.2
	btnLogin = guiCreateButton(X, Y, Width, Height, "Ingresar", true, wdwLogin)
	
	-- Hacer la ventana invisible
	guiSetVisible(wdwLogin, false)
end

Nota que todo componente GUI creado es un hijo de la ventana, esto se hace espeficicando el elemento padre (wdwLogin, en este caso) cuando se crea el componente.

Esto es muy util porque no solo hace pensar que todos sus componentes estan unidos a la ventana y que se van a mover con ella, sino que ademas todo cambio hecho a la ventana padre seran aplicados arbol abajo a todos sus elementos hijos. Por ejemplo, ahora podemos esconder todos los elementos GUI que creamos con solo esconder la ventana:

guiSetVisible(wdwLogin, false) --esconde todos los elementos GUI que hicimos para poderlos mostrar al jugador en el momento apropiado

Uso de la función anterior

La función createLoginWindow ha sido completada, pero no hará nada hasta procesarlo. Es recomendable hacer todo el GUI cuando el resource del cliente se inicie, ocultarlo, y mostrarle al jugador cuando sea necesario. Por lo tanto, vamos a escribir un "event handler" para "onClientResourceStart" para crear la ventana:

-- esto significa que se iniciará cuando el propio resource se inicie
addEventHandler("onClientResourceStart", getResourceRootElement(getThisResource()), 
	function ()
		createLoginWindow()
	end
)	

Como en la ventana han de registrarse, la ventana se mostrará cuando el jugador entre al juego. Para esto, se puede usar el mismo evento, "onClientResourceStart", con lo que podemos modificar el código anterior para mostrar la ventana:

Tenga en cuenta que ahora estamos escribiendo más código para nuestro actual 'onClientResourceStart'.Este no es un nuevo evento, está destinado a reemplazar el qué ya tienes.

addEventHandler("onClientResourceStart", getResourceRootElement(getThisResource()), 
	function ()
		-- crear el registro con sus componentes dentro de la ventana
		createLoginWindow()

		-- emitir un mensaje de bienvenida al jugador
                outputChatBox("Welcome to My MTA:SA Server, please log in.")

		-- si la interfaz gráfica de usuario se creó correctamente, a continuación, mostrar la interfaz gráfica de usuario para el jugador
	        if (wdwLogin ~= nil) then
			guiSetVisible(wdwLogin, true)
		else
			-- si la interfaz gráfica no se ha creado correctamente, se lo dirá al jugador
			outputChatBox("An unexpected error has occurred and the log in GUI has not been created.")
	        end 

		-- mostrar el cursor al jugador ( para que pueda seleccionar y pulsar los botones )
	        showCursor(true)
		-- establecer el foco de entrada en la interfaz gráfica de usuario, permitiendo a los jugadores (por ejemplo) al pulsar 'T' sin que salga la apertura en el chat
	        guiSetInputEnabled(true)
	end
)	

Tenga en cuenta que tenemos un sencillo "control de seguridad" antes de hacer la ventana visible, por lo que en el caso improbable de que la ventana no se haya creado, es decir wdwLogin no es un elemento válido, no se obtiene un error y simplemente se informa al jugador de lo que ha sucedido . En el siguiente paso, vamos a crear la funcionalidad del botón para el botón "Iniciar sesión".

Scripteando el boton

Ahora que tenemos creado nuestro GUI and se lo hemos mostrado a un jugador, nesecitamos hacerlo funcionar.

Detectando el click

Cuando un jugador clickea en alguna parte del GUI, el evento "onClientGUIClick" sera triggeado para el componente GUI que tu clickeaste. Esto nos permite detectar facilmente cualquier click en los elemento GUI que nosotros quisimos usar. Por ejemplo, podemos adjuntar el evento con el boton "btnLogin" para agarrar algun click en el:

-- adjunta el evento onClientGUIClick a btnLogin y activa la funcion 'clientSubmitLogin'.
addEventHandler("onClientGUIClick", btnLogin, clientSubmitLogin, false)

Que quede claro que el argumento final es pasado a "false". Esto indica que el evento solo se va a activar directamente en btnLogin, sino el evento se tiene que propagarse por todo los elementos. Ajusta esto a true mientras adjunta a los elementos GUI querra decir que algun click en cualquier elemento en el mismo se activara este evento.

Esta linea del codigo podra ahora ser añadida dentro de la funcion createLoginWindow. Esto es un error comun al intentar y adjuntar los eventos a algun elemento GUI inexistente, por lo tanto hacer que siempre el evento se adjunte despues the crear los elementos GUI (en este caso, el boton) ha sido creado:

Nota que ahora estamos escribiendo mas codigo para la existencia de la funcion 'createLoginWindow'

function createLoginWindow()
	-- crea todos los elementos GUI
	...

	-- Ahora añadimos nuevo evento onClientGUIClick al evento luego de ser creado.
	addEventHandler("onClientGUIClick", btnLogin, clientSubmitLogin, false)

Administrar el clic

Ahora para detectar cuando le damos clic al boton, tenemos que escribir código para manejar lo que suceda cuando lo pulsen. En nuestro controlador de evento onClientGUIClick, le dijimos que llamara a la función clientSubmitLogin cada vez que se hace clic en btnLogin. Por lo tanto, ahora podemos utilizar la función clientSubmitLogin para controlar lo que ocurre cuando se hace clic en el botón:

-- Crea la función y definir los parámetros 'Botón' y 'Estado'.
-- (éstos pasan automáticamente por OnClientClick)
function clientSubmitLogin(button,state)
	-- si nuestro botón "login" es clickeado con el botón izquierdo del ratón, y soltado el botón izquierdo.
	if button == "left" and state == "up" then
		-- move the input focus back onto the game (allowing players to move around, open the chatbox, etc)
		guiSetInputEnabled(false)
		-- esconde la ventana y todos sus componentes
		guiSetVisible(wdwLogin, false)
		-- esconde el cursor del ratón
		showCursor(false)
	end
end

Ahora, cuando al botón le den clic, la ventana se debera esconder y todos los controles volveran. Despues, deberemos decirle al servidor que permita spawnear al jugador.

Triggering el server

La activación del server se puede hacer usando triggerServerEvent. Esto le permite activar un evento especificado en el servidor desde el cliente. El mismo se puede hacer a la inversa usando triggerClientEvent. Aquí, nosotros usamos la función triggerServerEvent para llamar a nuestro serverEvent personalizado, denominado "submitLogin", que a su vez controla el desove del jugador serverside.

Tenga en cuenta que ahora estamos escribiendo más código para nuestra función 'clientSubmitLogin' existente. Esto no es una nueva función y está destinado a reemplazar lo que ya tienes.

function clientSubmitLogin(button,state)
	if button == "left" and state == "up" then
		-- tomar el texto introducido en el campo 'username'
		local username = guiGetText(edtUser)
		-- tomar el texto introducido en el campo 'password'
		local password = guiGetText(edtPass)

		-- si el nombre de usuario y contraseña ambos existen
		if username and password then
			-- activar el server 'submitLogin' y pasar el nombre de usuario y contraseña a la misma.
			triggerServerEvent("submitLogin", getRootElement(), username, password)

			-- ocultar la gui, ocultar el cursor y devolver el control al player
			guiSetInputEnabled(false)
			guiSetVisible(wdwLogin, false)
			showCursor(false)
		else
			-- de otro modo, presentar un mensaje para el jugador, no activar el server
			-- y no ocultar la gui
			outputChatBox("Please enter a username and password.")
		end
	end
end

Crear el evento serverside

En este punto, ahora tenemos todo el código necesario en el clienteside, por lo que abrimos el archivo 'script.lua' serverside (desde el Introduction to Scripting) u otro archivo serverside adecuado para trabajar.

En el lado del servidor, recordamos que estamos spawneando al jugador tan pronto como se loguea. Así que, en primer lugar, tendremos que definir el evento personalizado que se utilizó antes en el cliente. Esto se puede hacer usando addEvent y AddEventHandler.

-- create our loginHandler function, with username and password parameters (passed from the client gui)
function loginHandler(username,password)

end

-- define our custom event, and allow it to be triggered from the client ('true')
addEvent("submitLogin",true)
-- add an event handler so that when submitLogin is triggered, the function loginHandler is called
addEventHandler("submitLogin",root,loginHandler)

Logging in

Ahora tenemos una función que es llama a través del evento personalizado 'submitLogin', podemos empezar a trabajar en el on logging y el spawning del jugador, haciendo uso de nuestra funcion 'loginHandler':

function loginHandler(username,password)
	-- compruebe que el nombre de usuario y la contraseña son correctos
	if username == "user" and password == "apple" then
		-- el jugador se ah logueado satisfactoriamente, asi que debe spawnearlo
		if (client) then
			spawnPlayer(client, 1959.55, -1714.46, 10)
			fadeCamera(client, true)
                        setCameraTarget(client, client)
			outputChatBox("Welcome to My Server.", client)
		end
	else
		-- si el nombre de usuario o contraseña no es correcta, enviar un mensaje al player
		outputChatBox("Invalid username and password. Please re-connect and try again.",client)
        end			
end

addEvent("submitLogin",true)
addEventHandler("submitLogin",root,loginHandler)

Para los fines de este tutorial, se muestra un sistema de nombre de usuario y una contraseña muy básico. Por una alternativa más completa, se puede utilizar el Sistema de cuentas o una base de datos MySQL.

También tenga en cuenta el uso dela variable "client", es una variable interna que utiliza MTA para identificar al jugador que provocó el evento.

Por último, no se olvide de incluir el nuevo archivo gui.lua en el meta.xml del recurso principal, y etiquetarlo como un script de cliente:

<script src="client/gui.lua" type="client" />

En este punto, ahora tenemos una ventana de base de inicio de sesión que comprueba el nombre de usuario y la contraseña del jugador cuando se hace clic en el botón de inicio de sesión. Si son correctos, el jugador se spawneara de forma automática.

Para obtener más ayuda con la GUI, consulte la GUI tutorials.