Portal SAMP
[Ajuda] Qual método mais eficiente? - Versão de Impressão

+- Portal SAMP (https://portalsamp.com)
+-- Fórum: SA-MP (https://portalsamp.com/forumdisplay.php?fid=5)
+--- Fórum: Área de suporte (https://portalsamp.com/forumdisplay.php?fid=6)
+--- Tópico: [Ajuda] Qual método mais eficiente? (/showthread.php?tid=3407)



Qual método mais eficiente? - tylerthecreator - 09/03/2023

Galera, dúvida básica. 

Qual melhor método de criar o famoso "carregando" para jogadores mobiles não caírem no limbo? 

Sei que existe a forma mais simples do SetPlayerPosEx, que coloca um timer congelando e ao final, descongelar. 
Mas haveria outra forma mais eficaz? Dessa forma, ainda alguns jogadores sofrem com esse problema e acabam caindo com os objetos carregando.
Se aumentar bastante o timer, até que resolve, mas deixar os caras carregando por 5/7 segundos acho muito. Quebra demais a dinâmica. 

Tentei o " Streamer_UpdateEx(playerid, X, Y, Z, GetPlayerVirtualWorld(playerid), GetPlayerInterior(playerid)); ", mas não funcionou mt bem.


RE: Qual método mais eficiente? - strelo - 09/03/2023

Uma alternativa ao uso do timer congelante é o uso de threads para carregar os recursos do jogo em segundo plano, permitindo que o jogo continue a funcionar enquanto os recursos são carregados. Aqui está um exemplo de como isso pode ser:

Código:
// Define uma variável global para controlar a thread
new g_ThreadRunning = false;

// Função da thread para carregar os recursos do jogo
forward thread_LoadResources();

// Função para mostrar a mensagem de carregamento na tela do jogador
forward ShowLoadingScreen(playerid);

public OnPlayerConnect(playerid)
{
    // Inicia a thread para carregar os recursos do jogo
    g_ThreadRunning = true;
    thread thread_LoadResources();
}

public OnPlayerSpawn(playerid)
{
    // Mostra a tela de carregamento enquanto a thread estiver em execução
    while(g_ThreadRunning)
    {
        ShowLoadingScreen(playerid);
        Sleep(1000);
    }
}

public thread_LoadResources()
{
    // Carrega os recursos do jogo aqui, por exemplo:
    LoadMyTextures();
    LoadMyModels();
    LoadMySounds();
   
    // Marca a thread como concluída
    g_ThreadRunning = false;
}

public ShowLoadingScreen(playerid)
{
    // Mostra a mensagem de carregamento na tela do jogador aqui, por exemplo:
    SendClientMessage(playerid, 0xFFFFFFFF, "Carregando...");
}


Neste exemplo, a função thread_LoadResources() é chamada quando o jogador se conecta ao servidor, e carrega os recursos do jogo em segundo plano. Enquanto a thread estiver em execução, a variável g_ThreadRunning é definida como verdadeira e a função OnPlayerSpawn() é executada para mostrar a tela de carregamento para o jogador. A função ShowLoadingScreen() é chamada a cada segundo para atualizar a mensagem de carregamento na tela do jogador. Quando a thread de carregamento de recursos for concluída, a variável g_ThreadRunning é definida como falsa e a tela de carregamento é removida.

Espero que isso ajude a resolver o problema de carregamento em seu jogo. Se tiver alguma dúvida, sinta-se à vontade para perguntar!


RE: Qual método mais eficiente? - tylerthecreator - 09/03/2023

(09/03/2023 18:23)strelo Escreveu: Uma alternativa ao uso do timer congelante é o uso de threads para carregar os recursos do jogo em segundo plano, permitindo que o jogo continue a funcionar enquanto os recursos são carregados. Aqui está um exemplo de como isso pode ser:

Código:
// Define uma variável global para controlar a thread
new g_ThreadRunning = false;

// Função da thread para carregar os recursos do jogo
forward thread_LoadResources();

// Função para mostrar a mensagem de carregamento na tela do jogador
forward ShowLoadingScreen(playerid);

public OnPlayerConnect(playerid)
{
    // Inicia a thread para carregar os recursos do jogo
    g_ThreadRunning = true;
    thread thread_LoadResources();
}

public OnPlayerSpawn(playerid)
{
    // Mostra a tela de carregamento enquanto a thread estiver em execução
    while(g_ThreadRunning)
    {
        ShowLoadingScreen(playerid);
        Sleep(1000);
    }
}

public thread_LoadResources()
{
    // Carrega os recursos do jogo aqui, por exemplo:
    LoadMyTextures();
    LoadMyModels();
    LoadMySounds();
   
    // Marca a thread como concluída
    g_ThreadRunning = false;
}

public ShowLoadingScreen(playerid)
{
    // Mostra a mensagem de carregamento na tela do jogador aqui, por exemplo:
    SendClientMessage(playerid, 0xFFFFFFFF, "Carregando...");
}


Neste exemplo, a função thread_LoadResources() é chamada quando o jogador se conecta ao servidor, e carrega os recursos do jogo em segundo plano. Enquanto a thread estiver em execução, a variável g_ThreadRunning é definida como verdadeira e a função OnPlayerSpawn() é executada para mostrar a tela de carregamento para o jogador. A função ShowLoadingScreen() é chamada a cada segundo para atualizar a mensagem de carregamento na tela do jogador. Quando a thread de carregamento de recursos for concluída, a variável g_ThreadRunning é definida como falsa e a tela de carregamento é removida.

Espero que isso ajude a resolver o problema de carregamento em seu jogo. Se tiver alguma dúvida, sinta-se à vontade para perguntar!

Mas tipo, geralmente os interiores personalizados de objetos são no céu e muito distantes das cidades. Existe a possibilidade de carregar em segundo plano objetos streamer de longe? E caso seja possível, não causaria lag? 

E outro detalhe, por eles serem no céu(interiores), se não carregar os objetos na hora, os jogadores caem e morrem. O tal do "limbo"


RE: Qual método mais eficiente? - xbruno1000x - 09/03/2023

Uma possibilidade seria criar o chão dos interiores com CreateObject. CreateObject não necessita tempo de carregamento.


RE: Qual método mais eficiente? - tylerthecreator - 10/03/2023

(09/03/2023 23:42)xbruno1000x Escreveu: Uma possibilidade seria criar o chão dos interiores com CreateObject. CreateObject não necessita tempo de carregamento.

Interessante, Bruno. Testarei dessa forma, tomara que dê certo.


RE: Qual método mais eficiente? - strelo - 10/03/2023

(09/03/2023 22:10)tylerthecreator Escreveu:
(09/03/2023 18:23)strelo Escreveu: Uma alternativa ao uso do timer congelante é o uso de threads para carregar os recursos do jogo em segundo plano, permitindo que o jogo continue a funcionar enquanto os recursos são carregados. Aqui está um exemplo de como isso pode ser:

Código:
// Define uma variável global para controlar a thread
new g_ThreadRunning = false;

// Função da thread para carregar os recursos do jogo
forward thread_LoadResources();

// Função para mostrar a mensagem de carregamento na tela do jogador
forward ShowLoadingScreen(playerid);

public OnPlayerConnect(playerid)
{
    // Inicia a thread para carregar os recursos do jogo
    g_ThreadRunning = true;
    thread thread_LoadResources();
}

public OnPlayerSpawn(playerid)
{
    // Mostra a tela de carregamento enquanto a thread estiver em execução
    while(g_ThreadRunning)
    {
        ShowLoadingScreen(playerid);
        Sleep(1000);
    }
}

public thread_LoadResources()
{
    // Carrega os recursos do jogo aqui, por exemplo:
    LoadMyTextures();
    LoadMyModels();
    LoadMySounds();
   
    // Marca a thread como concluída
    g_ThreadRunning = false;
}

public ShowLoadingScreen(playerid)
{
    // Mostra a mensagem de carregamento na tela do jogador aqui, por exemplo:
    SendClientMessage(playerid, 0xFFFFFFFF, "Carregando...");
}


Neste exemplo, a função thread_LoadResources() é chamada quando o jogador se conecta ao servidor, e carrega os recursos do jogo em segundo plano. Enquanto a thread estiver em execução, a variável g_ThreadRunning é definida como verdadeira e a função OnPlayerSpawn() é executada para mostrar a tela de carregamento para o jogador. A função ShowLoadingScreen() é chamada a cada segundo para atualizar a mensagem de carregamento na tela do jogador. Quando a thread de carregamento de recursos for concluída, a variável g_ThreadRunning é definida como falsa e a tela de carregamento é removida.

Espero que isso ajude a resolver o problema de carregamento em seu jogo. Se tiver alguma dúvida, sinta-se à vontade para perguntar!

Mas tipo, geralmente os interiores personalizados de objetos são no céu e muito distantes das cidades. Existe a possibilidade de carregar em segundo plano objetos streamer de longe? E caso seja possível, não causaria lag? 

E outro detalhe, por eles serem no céu(interiores), se não carregar os objetos na hora, os jogadores caem e morrem. O tal do "limbo"

Sim, é possível carregar objetos streamer de longe em segundo plano usando threads, mas pode haver um risco de lag se houver muitos objetos sendo carregados simultaneamente. Portanto, é importante usar um número limitado de threads para carregar os objetos.

 Para lidar com interiores personalizados no céu e evitar que os jogadores caiam no "limbo", você pode considerar o uso de teleportes para permitir que os jogadores se movam para o interior apenas quando o carregamento estiver concluído. Isso pode ser feito em conjunto com o uso de threads para carregar os objetos em segundo plano. 

Aqui está um exemplo de como isso pode ser feito:
Código:
// Define uma variável global para controlar a thread
new g_ThreadRunning = false;

// Função da thread para carregar os objetos do interior
forward thread_LoadInteriorObjects(int interiorid);

// Função para mostrar a mensagem de carregamento na tela do jogador
forward ShowLoadingScreen(playerid);

public OnPlayerConnect(playerid)
{
    // Inicia a thread para carregar os objetos do interior em segundo plano
    g_ThreadRunning = true;
    thread thread_LoadInteriorObjects(interiorid);
}

public OnPlayerInteriorChange(playerid, interiorid, oldinteriorid)
{
    // Verifica se o jogador está entrando no interior personalizado
    if(interiorid == MEU_INTERIOR_PERSONALIZADO)
    {
        // Mostra a tela de carregamento enquanto a thread estiver em execução
        while(g_ThreadRunning)
        {
            ShowLoadingScreen(playerid);
            Sleep(1000);
        }
       
        // Teleporta o jogador para o interior personalizado
        SetPlayerPos(playerid, MEU_INTERIOR_PERSONALIZADO_X, MEU_INTERIOR_PERSONALIZADO_Y, MEU_INTERIOR_PERSONALIZADO_Z);
       
        // Marca a thread como concluída
        g_ThreadRunning = false;
    }
}

public thread_LoadInteriorObjects(int interiorid)
{
    // Carrega os objetos do interior personalizado aqui, por exemplo:
    LoadMyInteriorObjects(interiorid);
   
    // Marca a thread como concluída
    g_ThreadRunning = false;
}

public ShowLoadingScreen(playerid)
{
    // Mostra a mensagem de carregamento na tela do jogador aqui, por exemplo:
    SendClientMessage(playerid, 0xFFFFFFFF, "Carregando...");
}

Neste exemplo, a função thread_LoadInteriorObjects() é chamada quando o jogador se conecta ao servidor e começa a carregar os objetos do interior personalizado em segundo plano. Quando o jogador entra no interior personalizado, a função OnPlayerInteriorChange() é chamada e verifica se o jogador está entrando no interior personalizado. Se for o caso, a função mostra a tela de carregamento até que a thread de carregamento de objetos seja concluída. Em seguida, o jogador é teleportado para o interior personalizado e a tela de carregamento é removida.

Lembre-se de que, para evitar o risco de lag, é importante usar um número limitado de threads para carregar os objetos. Além disso, você pode usar técnicas de otimização, como culling e LOD (nível de detalhe), para reduzir o número de objetos que precisam ser carregados.


RE: Qual método mais eficiente? - Dr Editor - 10/03/2023

Existe uma forma de resolver e do meu ponto de vista não tem opção melhor e mais simples que essa: TogglePlayerControllable
Com essa função o jogador congela mesmo no ar, ou seja, num ambiente onde demora para carregar você consegue controlar exatamente quando deve descongelar para garantir que não caia no limbo.


RE: Qual método mais eficiente? - Device-Black - 14/03/2023

Isso sempre funcionou para mim:
Código PHP:
#define UPDATE_TIME    (1500) // Tempo que o jogador deve ser congelado

TeleportarJogador(playeridFloat:xFloat:yFloat:zFloat:angleworldidinteriorid)
{
    
SetPlayerPos(playeridxyz);
    
SetPlayerFacingAngle(playeridangle);
    
SetPlayerInterior(playeridinteriorid);
    
SetPlayerVirtualWorld(playeridworldid);
    
    
// quanto mais especifico, melhor o resultado
    
Streamer_UpdateEx(playeridxyzworldidinterioridSTREAMER_TYPE_OBJECTUPDATE_TIME);