[Tutorial] El lнmite de los TextDraws
#1

El lнmite de los TextDraws
[*] Introducciуn
Buenas chavales, decidн hacer este pequeсo tutorial sobre el lнmite de los TextDraws porque veo un montуn de filterscripts usбndolos de mala manera.
Y sin mencionar todas las dudas que tienen sobre ellos los usuarios mбs nuevos en PAWN.

Aclaro que no explicarй sus funciones, sino cуmo se alcanza el lнmite y quй tipo de TextDraw usar en diferentes situaciones.

No se preocupen si no entienden ciertas cosas a primera vista, porque al final de todo explico todo de forma mбs detallada.
Tambiйn menciono que si no sabes como funcionan las matrices, es posible que se te complique un poquito mбs, aunque yo lo explicarй lo mejor que pueda.


[*] Tipos
En la versiуn actual del SA-MP hay dos tipos de TextDraws, vamos a ver cуmo era antes y cуmo es ahora.
  • Antes de SA-MP 0.3e

    [1] Global:
    Hasta antes del reciente SA-MP 0.3e existнa solo un tipo de TextDraw: el global
    Global quiere decir que es igual para todo el mundo en todo momento, el contenido (texto) de este es igual para todos los jugadores.
    PHP код:
    new
        
    Text:tuto_gTextDraw //Aquн se guarda la ID del TextDraw que creamos a continuaciуn.
    ;
    public 
    OnGameModeInit() {
        
    tuto_gTextDraw TextDrawCreate(240.0580.0"Hola!");
        
    /*
        Igual que en el caso de los jugadores, el primer TextDraw creado recibe la ID 0.
        Si el lнmite de los TextDraws globales es 2048, entonces ya tenemos 1/2048.
        Podemos crear 2047 TextDraws mбs iguales a este.
        */
        
    return 1;

    Posiblemente esa es la forma mбs fбcil de crear un TextDraw. Si todos fueran creados de esa manera podrнamos poner 2048 sin problema.
    Pero el verdadero problema es que el texto de ellos serб igual para todo el mundo, y por eso si nosotros queremos hacer un TextDraw que indique el dinero del jugador no podemos usar este tipo ya que cada jugador tendrнa su cantidad de dinero y necesitamos un TextDraw para cada jugador.

    Imaginense que todos los jugadores tienen 100$ siempre, podrнamos usar este TextDraw porque el valor es el mismo para todos. Pero al tener diferentes cantidades de dinero, no podemos usar un solo TextDraw teniendo varios jugadores en el servidor, para eso necesitamos los TextDraws por jugador.


    [2] Global por jugador:
    Aun asн, se inventу una manera de usar los TextDraws globales para crear TextDraws por jugador, o sea que cada jugador tenнa su propio TextDraw global con su propio contenido.

    їEn quй consiste?
    Pues se declara una matriz (el TAG Text se incluye) usando un determinado valor para las celdas de esta, pero la mayorнa de los scripters usan el famoso MAX_PLAYERS que tiene un valor de 500 por defecto.

    Luego hay dos formas de crearlos, todos a la vez usando un bucle for (por ejemplo) en OnGameModeInit
    PHP код:
    new
        
    Text:tuto_gTPJ[MAX_PLAYERS]
    ;
    public 
    OnGameModeInit() {
        for (new 
    xMAX_PLAYERSx++) {
            
    tuto_gTPJ[x] = TextDrawCreate(240.0580.0"100$");
        }
        return 
    1;
    }
    public 
    OnPlayerSpawn(playerid) {
        new
            
    name[MAX_PLAYER_NAME]
        ;
        
    GetPlayerName(playeridnameMAX_PLAYER_NAME);
        
    format(nameMAX_PLAYER_NAME"%s"name);
        
        
    TextDrawSetString(tuto_gTPJ[playerid], name);
        
    TextDrawShowForPlayer(playeridtuto_gTPJ[playerid]);
        
    /*
        Cogemos la celda que coincide con playerid, y el valor que contiene es la ID del TextDraw.
        Luego se lo mostramos, їpero cuбl mostramos si tenemos 500?
        La ID que tenemos almacenada en la celda con el mismo valor que playerid.
        */
        
    return 1;

    Como ven usamos MAX_PLAYERS, creamos 500 TextDraws de golpe. Ya estariamos usando 500/2048. Pero el error es que nosotros tendemos a pensar que solo es un TextDraw lo que hicimos ya que solo tenemos una variable (es una matriz con 500 celdas), pero son 500 ya que el bucle for se ejecuto 500 veces y llamу 500 veces el TextDrawCreate.


    Tambiйn podemos crearlos cuando un jugador se conecte en OnPlayerConnect, si usamos este tipo de TextDraw yo recomendarнa esta forma, ya que no se crean todos a la vez, y creamos uno cuando un jugador entra.
    PHP код:
    new
        
    Text:tuto_gTPJ[MAX_PLAYERS]
        
    /*
        La matriz se declara con 500 celdas, pero no usamos un bucle para crear los TextDraws
        a la vez, sino que las celdas se quedan vacias. Y cuando un jugador se conecta
        se crea un TextDraw y en la celda que coincide con playerid se guarda la
        ID que justу se creo en OnPlayerConnect.
        */
    ;
    public 
    OnPlayerConnect(playerid) {
        
    tuto_gTPJ[playerid] = TextDrawCreate(240.0580.0"100$");
        
    /*
        Usando la matriz tuto_gTPJ guardamos la ID del TextDraw en la celda que corresponde a playerid.
        */
        
    return 1;
    }
    public 
    OnPlayerDisconnect(playerid) {
        
    TextDrawDestroy(tuto_gTPJ[playerid]);
        
    /*
        Aquн lo destruimos cuando el jugador sale, asн restamos un TextDraw
        y liberamos un slot mбs para TextDraws
        */
        
    return 1;

    їCuбl es el truco?
    No hay ningъn truco, es algo de lуgica. Veamos:

    1є. Se crea una matriz con el tamaсo de MAX_PLAYERS (por ejemplo).
    2є. Cuando un jugador entra se crea un TextDraw y se guarda la ID en la celda correspondiente a playerid, o bien usamos el bucle en OnGameModeInit.
    3є. Modificamos ese TextDraw identificando la celda correspondiente con playerid.

    їQuй contiene la celda que corresponde a playerid?
    Contiene un valor, y es la ID de un TextDraw.
    Cada celda tiene una ID diferente, si usamos MAX_PLAYERS para declarar la matriz tendrнamos 500 celdas, y cada una tendrнa una ID diferente lo que quiere decir que tenemos 500 TextDraws (dependiendo de la tйcnica que usemos para crearlos).

    Da le sensaciуn que el jugador tiene su propio TextDraw, pero en realidad es uno global que solo lo usamos para un determinado jugador.

    Quote:

    Aquн se suele cometer el mayor error, al usar MAX_PLAYERS, como ya sabemos que tiene un valor de 500 al usar el bucle for ya crearнamos 500 TextDraws a la vez, aunque nosotros solo tengamos 100 slots.
    Si usamos 100 slots y usamos MAX_PLAYERS solo usaremos 100 TextDraws y los otros 400 solo estarбn ahн ocupando espacio, asн alcanzaremos mбs rбpido el lнmite.
    La mejor forma de crear este tipo de TextDraw es en OnPlayerConnect ya que solo se crea uno para el jugador cuando se conecta y se destruye cuando sale.

  • Desde SA-MP 0.3e
    En la ъltima versiуn publicada de manera oficial, 0.3e, se aсadiу un nuevo tipo: el TextDraw por jugador.

    Es exactamente lo mismo que un TextDraw global, pero solo se crea para un jugador. Lo bueno es que podemos crear 256 TextDraws de este tipo para cada jugador, y segъn mis experiencias parece que no tienen nada que ver con el otro lнmite de 2048.

    Eso sн, las funciones son diferentes en cuanto a los nombres, pero es muy pequeсa la diferencia. Y ahora hay que agregar un parбmetro mбs.

    їCуmo se crean y quй debemos usar?
    Aun se necesita una matriz pero esta vez funciona totalmente diferente, segъn la wiki puede que haya mezclas de IDs y que se muestre a un jugador un TextDraw incorrecto, y al parecer se arregla usando una matriz (array).
    PHP код:
    new
        
    PlayerText:tuto_gTD[MAX_PLAYERS]
    ;
    public 
    OnPlayerConnect(playerid) {
        
    tuto_gTD[playerid] = CreatePlayerTextDraw(playerid240.0580.0"Hola!");
        return 
    1;

    Estos TextDraws no tienen que ver nada con el lнmite de los TextDraw globales, aquн por ejemplo hemos creado uno. Y ya va 1/256.
    ****** me dijo que podemos crear 256 TextDraws de este tipo para cada jugador.

    Lo ideal es crearlos en OnPlayerConnect, tambiйn menciono que se destruyen automбticamente cuando un jugador se desconecta. Asн que es mala idea crearlos en OnGameModeInit.

    їPor quй se necesita una matriz en estos TextDraws?
    Porque cada jugador podrб tener 256 TextDraws de este tipo, y las IDs de los TextDraws para todos los jugadores irбn del 0 al 255. A veces el orden de creaciуn de los TextDraws es alterado y puede que en una variable se guarden dos valores distintos, cosa que no es posible. Por eso necesitamos matrices, para que no lleguen a mezclarse.

    Un ejemplo muy claro:
    PHP код:
    new
        
    PlayerText:A,
        
    PlayerText:B
    ;
    public 
    OnPlayerConnect(playerid) {
        if (
    IsPlayerAdmin(playerid)) {
            
    CreatePlayerTextDraw(playerid0.00.0"A"); //Este TextDraw tendrб la ID 0 si el jugador es admin.
        
    }
        
    CreatePlayerTextDraw(playerid0.00.0"B");
        
    /*
        Pero la ID del B dependerб de la condiciуn de mбs arriba, ї0 o 1?
        Si el jugador no es admin tendrб la ID 0, pero si lo es tendrб la ID 1.
        Imaginen que tenemos dos jugadores, uno admin y otro no.
        Entra el admin y el orden de sus TextDraws es A (ID 0) y B (ID 1), entra el segundo y solo tiene B (ID 0).
        Entonces en la variable A se guardarб la ID 0 del TextDraw A del jugador con admin,
        pero en la variable B se guardarб la ID 0 del jugador sin admin mбs la ID 1 del jugador con admin.
        Entonces tendrнamos dos valores distintos en una sola variable, cosa que no es posible,
        por eso se llegarб a la pйrdida de informaciуn, y la mezcla.
        */
        
    return 1;

    Otro mбs:
    PHP код:
    #include <a_samp>
    new
        
    PlayerText:A,
        
    PlayerText:B,
        
    PlayerText:C
    ;
    public 
    OnPlayerConnect(playerid) {
        if (
    playerid == 0) {
            
    CreatePlayerTextDraw(playerid0.00.0"A"); //A - ID 0
            
    CreatePlayerTextDraw(playerid0.00.0"B"); //B - ID 1
            
    CreatePlayerTextDraw(playerid0.00.0"C"); //C - ID 2
        
    } else if (playerid == 1) {
            
    CreatePlayerTextDraw(playerid0.00.0"C"); //C - ID 0
            
    CreatePlayerTextDraw(playerid0.00.0"A"); //A - ID 1
            
    CreatePlayerTextDraw(playerid0.00.0"B"); //B - ID 2
        
    }
        return 
    1;

    Bien, se conectan dos jugadores, el primer jugador tiene los TextDraws en el siguiente orden: A B C, y el segundo en este: C A B. Hasta ahн todo bien. Ahora el TextDraw A tiene la ID 0 para el jugador ID 0, pero para el jugador ID 1 es la ID 1. Y lуgicamente no se pueden almacenar diferentes IDs en una sola variable, se necesita una matriz. Mбs claro que el agua.

    Para facilitar el entendimiento, son similares a los objetos por jugador (Player Objects) y los globales como los objetos normales.

    No me adentro mбs en este tipo, como dije solo iba a hablar sobre los lнmites.

[*] Cuando usarlos
  • Globales
    Deberнan usarse en Textos que siempre son iguales para todos, fondos, contadores (siempre y cuando la cuenta sea igual para todo el mundo), etc.
    PHP код:
    // ---------------------[Mostrar Web en TextDraw]--------------------------- //
    #include <a_samp>
    new
        
    Text:tuto_gTD,
    ;
    public 
    OnGameModeInit(playerid) {
        
    tuto_gTD TextDrawCreate(240.0580.0"www.sa-mp.com");
        return 
    1;
    }
    public 
    OnPlayerSpawn(playerid) {
        
    TextDrawShowForPlayer(playeridtuto_gTD);
        return 
    1;
    }
    public 
    OnPlayerDeath(playeridkilleridreason) {
        
    TextDrawHideForPlayer(playeridtuto_gTD);
        return 
    1;

  • Por jugador
    Para mostrar estadнsticas, barras animadas, y cosas que pueden tener diferentes valores entre los jugadores: dinero, score, etc.
    PHP код:
    // ---------------------[Mostrar dinero en TextDraw]--------------------------- //
    #include <a_samp>
    new
        
    bool:tuto_gSpawned                             [MAX_PLAYERS],
        
    PlayerText:tuto_gTD                            [MAX_PLAYERS]
    ;
    public 
    OnPlayerConnect(playerid) {
        
    tuto_gSpawned[playerid] = false;
        
    tuto_gTD[playerid] = CreatePlayerTextDraw(playerid240.0580.0"Hola!");
        return 
    1;
    }
    public 
    OnPlayerSpawn(playerid) {
        
    tuto_gSpawned[playerid] = true;
        
    PlayerTextDrawShow(playeridtuto_gTD[playerid]);
        return 
    1;
    }
    public 
    OnPlayerDeath(playeridkilleridreason) {
        
    tuto_gSpawned[playerid] = false;
        
    PlayerTextDrawHide(playeridtuto_gTD[playerid]);
        return 
    1;
    }
    public 
    OnPlayerUpdate(playerid) {
        if (
    tuto_gSpawned[playerid]) {
            new
                
    cadena[50]
            ;
            
    format(cadena50,
                
    "~w~%d~g~~h~$",
                
    GetPlayerMoney(playerid)
            );
            
    PlayerTextDrawSetString(playeridtuto_gTD[playerid], cadena);
            
    PlayerTextDrawShow(playeridtuto_gTD[playerid]);
        }
        return 
    1;

[*] Consejos de optimizaciуn
Algunas cosas que me han servido a la hora de usar TextDraws:
  • Si son TextDraws de decoraciуn y son iguales para todo el mundo nunca uses TextDraws por jugador.
  • No olviden de destruir los TextDraws por jugador si los crean en OnPlayerConnect basбndose en los TextDraws globales, vean mi ejemplo.
  • Cuando usemos los TextDraws globales para crear TextDraws por jugador, en vez de usar MAX_PLAYERS con 500 como valor, deberнamos definirlo de nuevo con el nъmero de slots que usamos:
    PHP код:
    #include <a_samp>
    //---
    #undef  MAX_PLAYERS
    #define MAX_PLAYERS                                            (100)
    //---
    //Otros includes. 
  • Si ya usan la 0.3e recomendarнa no usar mбs los TextDraws globales para crear TextDraws por jugador, algunas personas dicen que tienen problemas con ellos, yo personalmente no he tenido ninguno.
  • Deben saber que los TextDraws de los filterscripts, includes, etc. se juntan todos para alcanzar el lнmite. Quiero decir que si tienes 1 FS no puedes tener 4096 TextDraws (2048 del FS + 2048 del GM).
[*] Lнmites actuales

GlobalesPor Jugador
2048256 (Como dije, cada jugador puede tener 256 de este tipo)

[*] Fin
Es esto seсores.
Menciono que toda la informaciуn estб basada en mis propias experiencias y la wiki.

Una pequeсa cosa del lнmite del nuevo tipo de TextDraw de la 0.3e, me la confirmу ****** porque tenнa una duda.

Tambiйn doy las gracias a MrDeath537 (que al parecer ya no estб en el foro), que me lo explicу a mi cuando yo no lo entendнa.

Cualquier duda, aporte de informaciуn, algъn fallo que haya cometido en el tutorial, si quieren que explique mejor una cosa especifica, o quieren algъn tutorial de alguna otra cosa, etc. comenten.

ЎSaludos, y lo siento si hay faltas de ortografнa!
Reply
#2

Pequeсo tutorial >.< xDD
Muy bueno irinel.
Reply
#3

Buena explicaciуn
En el sistema de velocнmetro que publique trate de implementar un sistema de slots para los TD, normalmente yo tengo definido MAX_JUGADORES (los que necesito), para disminuir la variable que se crea, si de igual manera no los usare, pero decidн no ponerlo en la primera versiуn para hacerlo mas fбcil de entender.
Lo que no he probado es si funcione por ejemplo:
Код:
#define MAX_JUGADORES  GetMaxPlayers()
Reply
#4

Ja, esta de 10 no sabia eso que se creaban 500 Text de Golpe o.O, Muy bueno. Una consulta, eso quiere decir que es preferentemente mejor, crearlos en "OnPlayerConnect"?

Segun lo que entendi.
Reply
#5

Quote:
Originally Posted by CrossOv3r
Посмотреть сообщение
Ja, esta de 10 no sabia eso que se creaban 500 Text de Golpe o.O, Muy bueno. Una consulta, eso quiere decir que es preferentemente mejor, crearlos en "OnPlayerConnect"?

Segun lo que entendi.
MAX_PLAYERS esta valorado en 500 en a_samp

lo que quiere decir que al crear una variable con [MAX_PLAYERS] lo que en realidad estas haciendo es
crear una variable [500] celdas eso quiere decir que se crearan 500 textdraw.

osea si tienes un server de 50 slot y creaste 500 textdraw estarнas inutilizando 450 textdraw(celdas) que lo ъnico que te crearan es lag y acaparamiento en la memoria.
Reply
#6

Los PlayerTextDraws no necesitan array, ya lo comprobe y si no me crees, podйs comprobarlo con un amigo tuyo.
Reply
#7

Quote:
Originally Posted by CaptainMactavish
Посмотреть сообщение
Los PlayerTextDraws no necesitan array, ya lo comprobe y si no me crees, podйs comprobarlo con un amigo tuyo.
Raro, ya que en la SA:MP wiki aparecen con array... pero probarй a ver..
Reply
#8

y si no necesitan array como lo eliminas?
Perdona mi ignorancia
Reply
#9

Quote:
Originally Posted by enigma513
Посмотреть сообщение
y si no necesitan array como lo eliminas?
Perdona mi ignorancia
Se eliminan solos cuando un jugador se desconecta, pero si lo quieres destruir por tu cuenta: PlayerTextDrawDestroy(playerid, PlayerText:text);
No hay problema man, me imagino que para eso es un tutorial.

EDIT: Oh, justo ahora entendн tu comentario. Sн, esa es otra de las preguntas que indica que hay que usar una matriz.
__________________________________________________ __
Quote:
Originally Posted by enigma513
Посмотреть сообщение
Buena explicaciуn
En el sistema de velocнmetro que publique trate de implementar un sistema de slots para los TD, normalmente yo tengo definido MAX_JUGADORES (los que necesito), para disminuir la variable que se crea, si de igual manera no los usare, pero decidн no ponerlo en la primera versiуn para hacerlo mas fбcil de entender.
Lo que no he probado es si funcione por ejemplo:
Код:
#define MAX_JUGADORES  GetMaxPlayers()
Podrнa funcionar pero yo no lo recomiendo para usar en un GM.
Harнa mбs lentos los bucles que usen MAX_PLAYERS, ya que GetMaxPlayers serб llamado en el bucle tantas veces como el valor que devuelve. Desde luego es mejor un valor constante.
__________________________________________________ __
Quote:
Originally Posted by CaptainMactavish
Посмотреть сообщение
Los PlayerTextDraws no necesitan array, ya lo comprobe y si no me crees, podйs comprobarlo con un amigo tuyo.
Sн que se necesitan, y te voy a decir por quй.
Al crear un TextDraw por jugador con las nuevas funciones de la 0.3e, el TextDraw recibe una ID para cada jugador.
Y sн se pueden mezclar cuando haya mбs jugadores, aunque a veces parezca que funcione, llegarб un momento en el que se buggearan si no usas la matriz.

Tomemos el siguiente script como ejemplo:
pawn Код:
#include <a_samp>

new
    PlayerText:A,
    PlayerText:B,
    PlayerText:C
;

public OnPlayerConnect(playerid) {
    if (playerid == 0) {
        A = CreatePlayerTextDraw(playerid, 0.0, 0.0, "A"); //A - ID 0
        B = CreatePlayerTextDraw(playerid, 0.0, 0.0, "B"); //B - ID 1
        C = CreatePlayerTextDraw(playerid, 0.0, 0.0, "C"); //C - ID 2
    } else if (playerid == 1) {
        C = CreatePlayerTextDraw(playerid, 0.0, 0.0, "C"); //C - ID 0
        A = CreatePlayerTextDraw(playerid, 0.0, 0.0, "A"); //A - ID 1
        B = CreatePlayerTextDraw(playerid, 0.0, 0.0, "B"); //B - ID 2
    }
    return 1;
}
Bien, se conectan dos jugadores, el primer jugador tiene los TextDraws en el siguiente orden: A B C, y el segundo en este: C A B. Hasta ahн todo bien. Ahora el TextDraw A tiene la ID 0 para el jugador ID 0, pero para el jugador ID 1 es la ID 1. Y lуgicamente no se pueden almacenar diferentes IDs en una sola variable, se necesita una matriz. Mбs claro que el agua.

Yб se que en el ejemplo el TextDraw C lo puse en primer lugar para el jugador ID 1 pero es solo un ejemplo para que entiendas lo que sucede cuando hay mбs jugadores en el servidor entrando y saliendo.
Reply
#10

Muy buen tutorial explica bastante bien cuando deberian utilizarse los textdraws.

OFF-TOPIC:
Quote:
Originally Posted by enigma513
Посмотреть сообщение
Buena explicaciуn
En el sistema de velocнmetro que publique trate de implementar un sistema de slots para los TD, normalmente yo tengo definido MAX_JUGADORES (los que necesito), para disminuir la variable que se crea, si de igual manera no los usare, pero decidн no ponerlo en la primera versiуn para hacerlo mas fбcil de entender.
Lo que no he probado es si funcione por ejemplo:
Код:
#define MAX_JUGADORES  GetMaxPlayers()
En general cuando se crea un tutorial, se tiende a utilizar todo lo mas estandarizado posible. Lo mejor para realizar un bucle entre los jugadores es foreach, pero si no lo quieres utilizar y deseas utilizar GetMaxPlayers para hacerlo mas rapido, lo mejor es que lo realizes asi:
pawn Код:
for(new i, j=GetMaxPlayers(); i<j; i++)
{
    if(!IsPlayerConnected(i))
        continue;
    //Aqui tu codigo
}
Reply


Forum Jump:


Users browsing this thread: 4 Guest(s)