Eu estive pensando em um jogo RTS para vários jogadores. A parte que eu não consigo entender é manter o movimento da unidade sincronizado. Se eu mover a unidade A para localizar XY, tenho que comunicar isso de volta ao servidor que retransmite para o outro cliente.
Estou curioso para saber como seriam as comunicações. Você apenas comunicaria ao servidor que estou transferindo a unidade A para XY da JZ? Talvez você precise comunicar o movimento coord por coord em vez disso? Qual é a metodologia mais eficiente para comunicar o movimento de unidades de um cliente para outro?
EDITAR
Esta é uma pergunta publicada novamente por stackoverflow . Descobri que este site era provavelmente um lugar melhor para a pergunta.
Uma das melhores respostas desse post:
Presumo que você pretenda usar o paradigma de rede Cliente-Servidor? Nesse caso, você não pode confiar nos clientes para manipular o posicionamento real das unidades, você deve delegar essa tarefa ao servidor. Você pega a lista de comandos de cada cliente por tick e calcula o movimento de cada unidade, uma vez que isso tenha sido concluído. No próximo tick, você retransmitirá a posição de cada unidade relevante para cada cliente (em um mapa inteiro ou por visualização) e inicie o processo novamente.
Respostas:
Você não deseja sincronizar as posições de todas as unidades do servidor para cada cliente; isso ocupará muito mais largura de banda do que você precisa. Você também teria que lidar com posições de unidade de interpolação / extrapolação, etc. Quase nenhum RTS profissional usa cliente / servidor!
Em vez disso, você deseja enviar apenas os comandos dos jogadores. Em vez de mover as unidades imediatamente quando o jogador clicar, você enfileirará o comando de movimentação a ser feito em algum momento no futuro - geralmente apenas alguns quadros. Todo mundo envia seus comandos para todos. Alguns quadros depois, todos executam todos os comandos e, como o jogo é determinístico, todos veem o mesmo resultado.
A desvantagem é que todo jogador é tão lento quanto o jogador mais lento - se alguém fica para trás ao enviar comandos, todos precisam desacelerar e esperar que ele o alcance (em Starcraft 2, este é o "XXX está diminuindo a velocidade do jogo " diálogo).
De fato, há mais uma coisa que geralmente é feita: eliminar completamente o servidor . Todos os clientes enviam seus comandos para todos os outros clientes. Isso reduz o atraso (em vez de um comando sair de você -> servidor -> oponente, ele apenas vai de você -> oponente) e facilita a codificação, já que você não precisa mais codificar um servidor separado. Esse tipo de arquitetura é chamado ponto a ponto (P2P).
A desvantagem é que agora você precisa de uma maneira de resolver conflitos, mas como os comandos dos jogadores são independentes uns dos outros na maioria dos RTSs, isso geralmente não é um grande problema. Além disso, ele não escala bem - toda vez que você adiciona um novo jogador, todo jogador precisa enviar seus comandos. Você não fará um RTS MMO usando P2P.
Essa configuração (enviando apenas comandos usando P2P) é como a maioria dos RTS, incluindo Starcraft, C&C e AoE, funciona e é a única maneira pela qual o AoE poderia suportar 1500 unidades em uma conexão de 28.8kbps .
Aqui estão mais algumas dicas para escrever um P2P RTS:
rand()
,cos()
etc, mas praticamente toda a matemática de ponto flutuante está fora de questão (veja aqui , aqui e aqui ) ! Nesse caso, pode ser melhor usar o cliente-servidor.fonte
Eu criei um RTS em rede TCP, no qual eu próprio passei os comandos, e não os resultados dos comandos . Por exemplo, um jogador dá uma ordem de movimento. Se a ordem de movimentação for válida de acordo com esse cliente, ela será enviada ao servidor. O servidor envia de volta para todos os clientes que validam e executam.
Portanto, todas as máquinas clientes executam o jogo, o código do servidor aceita mensagens e as envia de volta a todos os clientes. Se um cliente der uma ordem de movimentação, ele não começará a executá-la até que seja recebido de volta do servidor.
O servidor envia também um número de 'tick' para executar o comando, que está alguns ticks à frente do tick 'atual'. Dessa forma, todos os comandos podem ser executados no mesmo 'tick' em todas as máquinas.
Um benefício desse método é que ele não depende de nenhuma máquina cliente individual para validar o comando. Se eu passar nos resultados da mudança, talvez seja possível cortá-la para mover minhas unidades mais rapidamente. Todos os clientes precisam executar o mesmo comando e, se uma máquina o executar de maneira diferente, será óbvio.
Não é necessário validar o comando do lado do cliente antes de enviá-lo ao servidor, mas, em teoria, ele economiza tráfego de rede. Usei o mesmo código de validação para informar à interface do usuário que a mudança era possível, portanto não foi necessário escrever código extra.
Quanto à aparência das mensagens. Eu não estava preocupado com a ultra eficiência, pois foi o meu primeiro jogo em rede. Eu passei comandos como strings. Os comandos seriam formatados assim:
"<player_id>:<command>:<parameters>"
Para um exemplo inventado, um comando de movimento pode ter esta aparência:
"3:move:522:100:200"
. Isso significa que o jogador3
desejamove
unir522
para (100
,200
).O servidor passa o comando para todos os clientes, incluindo aquele que o enviou, com um número carrapato grudado como este:
"153238:3:move:522:100:200"
.Todos os clientes executariam esse comando quando o tick 153238 for executado.
fonte