Como armazenar e exibir com eficiência um mapa de blocos na Web?


9

Sobre

Na verdade, essas são duas perguntas em uma. Antes de tudo, estou procurando uma maneira de armazenar com eficiência grandes quantidades de dados do bloco. O outro aspecto lida com a consulta do conjunto de dados e a exibição de blocos. Deixe-me dar-lhe alguns antecedentes primeiro.

Estamos criando um jogo de tycoon multiplayer baseado em navegador usando a biblioteca CraftyJS para renderizá-lo no Canvas. No fundo da GUI, estamos rodando o Yii Framework em PHP e tudo se conecta a um gerador de mapas aleatórios e mecanismo de jogo em Python.

É assim que o primeiro mapa aproximado é exibido : http://i.imgur.com/khAXtl.png

Armazenando os dados do mapa

O mundo do jogo é gerado aleatoriamente cada vez que o jogo é iniciado. O tamanho é de 100x100 peças hexagonais para cada jogador. Isso significa que, para um jogo com três jogadores, existem 90.000 peças criadas. Atualmente, apenas crio uma matriz JavaScript a partir da qual renderizo o mapa.

Isso funciona bem para renderização, mas para qualquer tipo de interação com o mapa, precisamos armazenar qual jogador possui o ladrilho, que tipo de estrutura é construída sobre ele, qual é o preço atual e assim por diante. No começo, pelo menos para o protótipo, queríamos usar o MySQL, mas após alguns testes, não é exatamente tão rápido quanto eu gostaria. Talvez um armazenamento de objetos como o MongoDB seja mais adequado para armazenar dados de bloco em vez de uma tabela SQL. Ou talvez algo mais?

Exibindo o mapa

Outro problema que vejo está se movendo pelo mapa. Atualmente, estou criando entidades Crafty para cada bloco, mesmo que não esteja na janela de exibição. Isso é lento, porque, embora o Crafty renderize apenas os da janela de exibição, ele armazena e possivelmente itera através de todos os blocos em cada evento de renderização. O que eu tenho atualmente é um mapa gerado desenhado que é muito lento para carregar e gagueja quando você se move, agora eu gostaria de torná-lo jogável.

Minha primeira ideia foi carregar o subconjunto de blocos exibido na janela de exibição. Mas quando um jogador moveria a janela de visualização para uma área em branco, eu precisaria consultar o servidor e aguardar a resposta, somente então o mapa poderá ser renderizado. Isso seria bom em um aplicativo nativo, mas é lento em um jogo na web.

A maneira de obter um bom desempenho no mapa pode ser pré-carregar um subconjunto maior de blocos em uma matriz javascript e usá-lo como cache. O jogador teria algumas telas "armazenadas em cache" e, quando ele move a janela de visualização, eu carregava mais blocos no "cache" do JS.

Estou indo na direção certa? Gostaria muito de obter mais informações de alguém que fez algo semelhante. Eu sou novo no desenvolvimento de jogos, mas tenho passado por muitas fontes nas últimas duas semanas.


11
Estou surpreso que você tenha identificado o MySQL como um gargalo. O que você testou para chegar à conclusão de que está atrasando as coisas?
Bmmzack #

@bummzack Se ele tem uma linha por ladrilho, mal consigo ver como as coisas não podem ser lentas.
Aaaaaaaaaaaa

11
@eBusiness Consultar alguns milhares de linhas de um banco de dados não deve ser realmente um problema. Ainda deve estar na faixa de alguns milissegundos. Também não seriam 90'000 linhas, mas 30'000 linhas para 3 jogadores (100x100 por jogador).
Bmmzack #

Desculpe pela matemática confusa, também há o dobro do espaço entre os jogadores, além da zona do jogador, para que eles fiquem a uma distância igual um do outro, o que o torna 90k. Consultar não é um problema. Selecionar 90 mil peças e construir um mapa é. Mas não é uma boa maneira de fazer isso. Serializaremos os dados do mapa e utilizarei a consulta dos blocos no banco de dados quando informações detalhadas forem solicitadas.
elemento

Respostas:


2

Jogabilidade
Antes de mais nada, gostaria de perguntar: você realmente precisa de 10000 peças por jogador? Embora eu não saiba que tipo de jogo você está criando, geralmente é verdade que mapas grandes produzem jogos longos. O maior mapa da Civilização 5 é 10240 blocos, e isso apenas funciona porque você não precisa jogar em mais do que uma fração dele.

Banco de dados
Você não deve tentar executar um jogo como esse em um banco de dados, é necessário manter os dados na memória do aplicativo. Você pode usar um banco de dados para fazer backup do jogo. Para um backup completo, salve uma serialização dos dados do jogo e, em seguida, você poderá incrementá-lo salvando as ordens dadas e, em seguida, execute-as novamente se o backup precisar ser usado.

Armazenamento JavaScript
Quanto ao cliente, eu diria que é melhor você manter o mapa inteiro carregado, pelo menos se você ficar com os gazilhões de blocos, ter tudo isso em uma bela árvore de objetos pode ser um pouco demais, então você provavelmente deve manter os dados em um formato codificado "semi-binário". As strings funcionam excelente para esse tipo de coisa; alternativamente, você pode armazenar com segurança números inteiros não assinados até 53 bits em um float de 64 bits, encher muitos deles em uma matriz e acho que você verá uma pegada de memória bastante modesta.

Visualização JavaScript
Embora eu não diga que você não deve necessariamente usar canvas, na verdade você não precisa disso para coisas como esta. Configure tudo como um monte de elementos img e altere a propriedade src para exibir diferentes partes do mapa.

Dica profissional
A propósito, às vezes é mais fácil compartilhar a semente usada para gerá-la do que compartilhar o mapa inteiro.


+1, mas infelizmente um aplicativo Web escrito em PHP geralmente não tem como manter o estado do jogo na memória.
bummzack

@bummzack, Ahh, certo, acho que de alguma forma pulei a palavra PHP e acabei de ler Python. Em seguida, uma mudança na estrutura de back-end pode estar em ordem. O Node.js pode ser uma opção.
Aaaaaaaaaaaa

Estou construindo um magnata do transporte competitivo, pense no OpenTTD, um mapa do tamanho de 512x512 (262k) não é tão grande para alguns jogadores. Sei que é ambicioso, mas se o mapa não for tão grande, o jogo terminará muito cedo. Por ser um jogo multiplayer, preciso sincronizar as alterações no mapa entre os jogadores. Meu primeiro instinto foi usar apenas os conceitos que eu conheço no desenvolvimento da web e usar uma base de dados. Não precisa ser super em tempo real. Vou com a visualização JS, porque gostaria de ter coisas dinâmicas no mapa.
elemento

Considere minha resposta como alguns indicadores, no final, você terá que descobrir o desempenho por conta própria, é um problema sério e talvez seja necessário fazer alguns compromissos.
Aaaaaaaaaaaa

Eu concordo, sua resposta me deu muita comida para pensar. Tentarei encontrar uma maneira de manter os dados do mapa serializados na memória e manter o banco de dados como um backup. Mas então eu tenho que descobrir como compartilhar as mudanças entre os jogadores. Voltarei ao que for apresentado depois de fazer alguns testes adicionais.
elemento

1

O MySQL não é lento. Provavelmente você está executando consultas ingênuas ou possui índices abaixo do ideal. Abordagens NoSQL como o MongoDB podem ser mais rápidas, talvez não. Seu padrão de acesso e escolha de consulta é o que realmente importa aqui. É possível dar conselhos sobre como melhorar o desempenho, mas não sem ver o que você já está fazendo.

A maneira de obter um bom desempenho no mapa pode ser pré-carregar um subconjunto maior de blocos em uma matriz javascript e usá-lo como cache.

Sim, claro. Não há muito a acrescentar aqui - o cliente solicita blocos do servidor, portanto, você só precisa garantir que os solicitados cubram uma área maior que a tela.

Termo aditivo:

estamos rodando o Yii Framework no PHP e tudo se conecta a um gerador de mapas aleatórios e mecanismo de jogo Python.

Se você é competente com o Python, aconselho que você evite o intermediário do PHP. Se você rodar o jogo como um processo Python, poderá manter os dados do bloco na memória com muito mais facilidade e reduzir significativamente os acessos ao MySQL. Ajuda que o Python também seja uma linguagem muito mais saudável do que o PHP.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.