EventoObtenha 50% de desconto no seu ingresso para MongoDB.local Londres em outubro 2. Use o código WEB50Saiba mais >>
Desenvolvedor MongoDB
Central de desenvolvedor do MongoDBchevron-right
Idiomaschevron-right
JavaScriptchevron-right

Crie um jogo de desenho multijogador com Phaser e MongoDB

Nic Raboy14 min read • Published Jan 12, 2022 • Updated Apr 02, 2024
RealmJavaScript
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Artigo
star-empty
star-empty
star-empty
star-empty
star-empty
Quando se trata de MongoDB, um setor frequentemente ignorado em que ele funciona extraordinariamente bem é o de jogos. Ele funciona muito bem em jogos por causa de seu desempenho, mas, mais importante, por sua capacidade de armazenar quaisquer dados complexos que o jogo lance sobre ele.
Digamos que você queira criar um jogo de desenho como Pictionary. Eu sei o que você está pensando: por que eu iria querer criar um jogo Pictionary com integração com MongoDB? Bem, e se você quisesse poder jogar com amigos remotamente? Neste cenário, você poderia armazenar suas pinceladas no MongoDB e carregá-las no dispositivo do seu amigo. Essas pinceladas podem ser praticamente qualquer coisa. Elas podem ser imagens, dados vetoriais ou algo totalmente diferente.
Um jogo de desenho é apenas um dos muitos jogos possíveis que combinariam bem com o MongoDB.
Neste tutorial, vamos criar um jogo de desenho usando o Phaser. Os dados serão armazenados e sincronizados com o MongoDB e ficarão visíveis no dispositivo de todos os outros, seja desktop ou celular.
Veja a seguinte imagem animada como exemplo:
Phaser com MongoDB em desktop e celular
No exemplo acima, tenho meu Macbook e meu dispositivo iOS na tela. Estou desenhando no meu dispositivo iOS, à direita, e depois que as pinceladas são consideradas concluídas, elas são enviadas ao MongoDB e aos outros clientes, como o MacBook. É por isso que os traços não estão disponíveis instantaneamente, pois estão em andamento.

Os requisitos do tutorial

Existem alguns requisitos que devem ser atendidos antes de iniciar este tutorial:
O trabalho pesado deste exemplo será com Faser, MongoDB Atlase MongoDB Realm.
O MongoDB Atlas tem uma camada para sempre GRÁTIS que pode ser configurada no MongoDB Cloud.
Não há necessidade de conta ou downloads necessários quando se trata de criar jogos Phaser. Esses jogos são compatíveis com a web e o celular.

Desenhar com Faser, HTML e JavaScript simples

Quando se trata do Phaser, você pode fazer tudo em um único arquivo HTML. Esse arquivo deve ser servido em vez de ser aberto no sistema de arquivos local, mas nada de extravagante precisa ser feito com o projeto.
Vamos começar criando um projeto em algum lugar do seu computador com um arquivoindex.html e um arquivogame.js . Vamos adicionar um código padrão ao nosso index.html antes de adicionar nossa lógica de jogo ao arquivogame.js.
Dentro do arquivo index.html, adicione o seguinte:
No HTML acima, adicionamos scripts para Phaser e MongoDB Realm. Também definimos um elemento de container HTML <div>, como visto pelo IDgame, para manter nosso jogo quando chegar a hora.
Poderemos adicionar toda a nossa lógica Faser e MongoDB à <script> tag não utilizada , mas é aqui que faz sentido ter a maior parte de nossa lógica no arquivojogo.js.
Abra o arquivogame.js e inclua o seguinte código padrão:
A classeGameacima é responsável pela renderização e pelas interações entre o usuário e o jogo, e pelas interações entre o jogo e o banco de dados. Por enquanto, não vamos nos preocupar com nosso banco de dados.
Dentro do método constructor, pegamos as informações fornecidas pelo usuário para configurar o Phaser. Alguns dos campos de configuração têm valores padrão, caso o usuário decida não fornecê-los ao instanciar a classe. Esses dados virão do desenvolvedor e não do jogador. No que diz respeito àscenas, o initScene será responsável pela inicialização das variáveis do jogo, o createScene será responsável pela sincronização com o servidor quando o jogo for carregado pela primeira vez e o updateScene será responsável pelas interações contínuas com o jogo.
Antes de pularmos para cada uma das funções, vamos voltar ao arquivoindex.html e instanciar nossa classe. Isso pode ser feito na tag<script>que existe atualmente:
No código acima, estamos definindo que nosso jogo deve ser renderizado no elemento HTML com o IDgame. Também estamos dizendo que ele deve ter a largura e a altura totais que estão disponíveis para nós no navegador. Essa largura e altura totais funcionam tanto para computadores quanto para dispositivos móveis.
Agora podemos dar uma olhada em cada uma das nossas cenas no arquivogame.js, começando com a funçãoinitScene :
Por enquanto, a função initScenepermanecerá curta. Isso ocorre porque ainda não vamos nos preocupar em inicializar nenhuma informação do banco de dados. Quando se trata destrokes, ela representará coleções independentes de pontos. Uma pincelada é apenas uma série de pontos conectados, portanto, queremos mantê-los. Precisamos ser capazes de determinar quando uma pincelada começa e termina, portanto, podemos usar isDrawing para determinar se levantamos o cursor ou o lápis.
Agora vamos dar uma olhada na funçãocreateScene:
Como com o initScene, essa função mudará à medida que adicionamos a funcionalidade do banco de dados. Por enquanto, estamos inicializando a camada de gráficos em nossa cenário e definindo o tamanho da linha e a cor que devem ser renderizadas. Este é um jogo simples, então todas as linhas terão 4 pixels de tamanho e a cor verde.
Isso nos leva à mais extravagante das cenas. Vamos dar uma olhada na funçãoupdateScene:
A função updateSceneé responsável por renderizar continuamente as coisas na tela. Ela é executada constantemente, ao contrário dacreateScene, que é executada apenas uma vez. Ao atualizar, queremos verificar se estamos desenhando ou não.
Se o activePointer não estiver inativo, significa que não estamos desenhando. Se não estivermos desenhando, provavelmente queremos indicar isso com a variávelisDrawing. Essa condição ficará mais avançada quando começarmos a adicionar a lógica do banco de dados.
Se o activePointer estiver para baixo, significa que estamos desenhando. No Phaser, para desenhar uma linha, precisamos de um ponto de partida e, em seguida, de uma série de pontos que possam ser renderizados como um caminho. Se estivermos iniciando a pincelada, provavelmente deveremos criar um novo caminho. Como definimos nossa linha como 4 pixels, se quisermos que a linha seja desenhada no centro do nosso cursor, precisaremos usar metade do tamanho para a posição x e y.
Como nunca estamos limpando a tela, não precisamos desenhar o caminho, a menos que o ponteiro esteja ativo. Quando o ponteiro estiver ativo, o que quer que tenha sido desenhado anteriormente permanecerá na tela. Isso nos economiza alguns recursos de processamento.
Estamos quase em um ponto em que podemos testar nosso jogo offline!
As cenários são bons, embora não tenhamos adicionado lógica MongoDB a eles. Precisamos realmente criar o jogo para que as imagens possam ser usadas. No arquivorole.js, atualize a seguinte função:
O código acima usará a configuração do Faser que definimos no métodoconstructor e iniciará a configuraçãodefault. A partir de agora, não estamos passando nenhum dado para nossas cenários, mas passaremos no futuro.
Com a funçãocreateGame disponível, precisamos utilizá-la. No arquivoindex.html, adicione a seguinte linha ao seu bloco <script>abaixo da instanciação do objetogame :
Você conseguiu! Você tem um jogo com uma tela preta em que pode desenhar linhas com o cursor. No momento, você só pode ter um jogo e as imagens que desenhar não serão salvas nem sincronizadas em lugar algum. Vamos chegar a isso a seguir!
Lembre-se de que, se quiser experimentar o jogo, precisa servi-lo ou hospede-o. Você não pode simplesmente abrir o arquivoindex.html do seu sistema de arquivos. Se você não quiser configurar a hospedagem localmente, consulte o Realm para hospedagem do.

Configuração do MongoDB Atlas e MongoDB Realm para persistência e sincronização de dados

Então, qual é o objetivo da próxima etapa deste tutorial?
No momento, não podemos traçar linhas na tela. Funciona muito bem, mas só podemos ter um único jogo e, se atualizarmos, essas linhas desaparecem. Além disso, se quisermos que um amigo veja nossa imagem, ele não poderá ver.
Então, vamos fazer o seguinte com o MongoDB Atlas e MongoDB Realm:
  • Crie documentos para a pessoa que está desenhando e armazene as Pinceladas.
  • Fique atento às alterações no documento e renderize-as na tela.
Em vez de Go em nosso código, vamos preparar as coisas para o Atlas e o Realm primeiro. Precisamos preparar um banco de dados e uma collection, bem como as regras de dados para quem pode acessar e manipular os dados.
Supondo que você já tenha criado um Atlas cluster, crie um banco de dadosmongo-draws com uma coleçãogame. Não vamos adicionar nenhum documento manualmente, mas quando começarmos a adicioná-los, eles ficarão assim:
A matrizstrokes será preenchida a partir de qualquer que o Phaser determine ser um caminho, conforme criado na parte anterior deste tutorial. O _id representará uma sala de jogos e o owner_id representará o anfitrião ou proprietário dessa sala em particular. Essencialmente, o plano é que apenas o anfitrião possa adicionar novas pinceladas em uma sala de jogos enquanto os outros participantes assistem.
Antes de começarmos a criar as regras de acesso aos dados, queremos descobrir quem pode participar. Para simplificar este exemplo, não nos preocuparemos com contas, portanto, a autenticação anônima será tudo de que precisamos.
Autenticação anônima do MongoDB Realm
Você pode habilitar a autenticação anônima clicando na guia Fornecedores na áreaUsuários do painel do Realm.
Com a autenticação anônima habilitada, agora podemos definir as regras de leitura e gravação de nossos documentos.
Regras para proprietários e não proprietários do MongoDB Realm
Na áreaRegras do painel Realm, você vai querer criar duas regras para a collection dojogo. A primeira regra, para o proprietário do documento, você deseja conceder a ele a capacidade de leitura e escrita. Para não proprietários, como queremos que eles assistam ao jogo, daremos acesso de leitura. Durante o processo de criação de regras, certifique-se de especificar que o owner_id do documento deve ser mapeado para o proprietário do documento.
Para mais informações, as regras devem ser semelhantes a estas:
Regras para proprietários e não proprietários do MongoDB Realm
MongoDB Atlas e Realm estão prontos para serem usados em nosso jogo. Não se lembre de implementar suas alterações no Realm, caso ainda não o tenha feito.
Abra o arquivo game.js do projeto e adicione o seguinte ao constructor método:
Queremos configurar como planejamos usar o MongoDB Realm quando instanciarmos nossa Game classe . Isso significa que precisamos alterar ligeiramente o que estamos fazendo noarquivo index.html :
Você notará que temos três novos campos de configuração para serem inseridos em nossa configuração do Realm.
Os camposdatabaseName e collectionNamedevem corresponder ao nome do seu banco de dados e coleção. O realmAppId pode ser encontrado no painel do Realm na web, no canto superior esquerdo da tela.
Antes de tentarmos criar ou entrar em um jogo existente, precisamos nos autenticar no MongoDB Realm. No arquivogame.js, atualize a seguinte função:
Lembre-se, estamos fazendo autenticação anônima, então nada muito sofisticado. Não vamos tentar autenticar com esta função ainda.
Então agora o que precisamos fazer é descobrir como criar um novo documento de sala de jogos ou usar um que já existe. Já temos uma funçãocreateGame, mas precisaremos melhorá-la para incluir a funcionalidade de banco de dados. Dentro da funçãocreateGame do arquivorole.js, altere para o seguinte:
Lembre-se, anteriormente estávamos apenas criando um jogo e iniciando a coleção de cenas. Agora estamos criando um novo documento com base no ID do jogo e no ID do proprietário passados e, em seguida, passando algumas dessas informações para a própria cena.
Então, por que estamos passando essas informações?
Devido à forma como o JavaScript define o escopo das variáveis, não temos acesso às variáveis de nível de classe de dentro de nossas cenários. Para contornar isso, estamos passando essas variáveis para a cena quando a iniciamos. As informações importantes para o local incluem a ID do proprietário do documento para que possamos descobrir quem deve ser capaz de extrair, as informações da collection para que possamos acessar os dados, a ID do jogo para sabermos quais dados acessar e, em seguida, inicial informações para dados de traçado.
Pudemos atualizar o arquivoindex.html para usar a nova funçãocreateGame, mas sabemos que vamos querer criar ou participar, não apenas criar. Com isso em mente, vamos atualizar outra função no arquivojogo.js:
Em vez de inserir um novo documento, estamos tentando encontrar um com base no ID do jogo fornecido. Se nenhum dado retornar, significa que não existe nenhum jogo. No entanto, se um jogo existir, inicializaremos a cena do jogo com as informações armazenadas.
Com as funçõesjoinGame e createGame disponíveis, vamos atualizar uma função wrapper para eliminar parte do trabalho.
Na funçãojoinOrCreateGame, primeiro fazemos a autenticação no MongoDB Realm. Após a autenticação, tentamos entrar em um jogo. Se a participação não for bem-sucedida porque não existe nenhum documento, tentaremos criar um jogo.
Então, vamos atualizar o arquivoindex.html para usar nossa funçãojoinOrCreateGame em vez de nossa funçãocreateGame:
Como estamos trabalhando com documentos do jogo, vamos atualizar a initScene função no arquivogame.js . Aquele para o qual estamos passando as informações do jogo quando criamos ou juntamos:
Tudo bem, então temos um mecanismo para criar e ingressar em jogos. Embora possamos fazer melhor. É provável que não queiramos codificar o ID do jogo ao tentar entrar ou criar um jogo. Vamos adicionar mais alguns elementos HTML para nos ajudar.
Abra o index.html e faça com que ele fique assim:
O código acima tem um pouco mais acontecendo agora, mas não se esqueça de usar suas próprias IDs de aplicativo, nomes de banco de dados e coleções. Você provavelmente começará notando a seguinte marcação:
Nem tudo era absolutamente necessário, mas dá ao nosso jogo uma aparência melhor. Essenciais agora temos um campo de entrada. Quando o campo de entrada é enviado, seja com uma pressão de tecla ou um clique, a funçãojoinOrCreateGame é chamada O keyCode == 13 representa que a tecla Enter foi pressionada. A função não é chamada diretamente, mas as funções do wrapper a chamam. O ID do jogo é extraído da entrada e os componentes HTML são transformados com base nas informações sobre o jogo.
Para resumir o que acontece, o usuário envia um ID de jogo. O ID do jogo flutua no topo da cenário do jogo, assim como informações sobre se você é o proprietário do jogo ou não.
A marcação parece pior do que é.
Agora que podemos criar ou participar de jogos tanto de uma perspectiva de experiência do usuário quanto de uma perspectiva lógica, precisamos mudar o que acontece quando se trata de interagir com o próprio jogo. Precisamos ser capazes de armazenar nossas pinceladas no MongoDB. Para fazer isso, vamos revisitar a funçãoupdateScene:
Lembre-se de que, desta vez, temos acesso ao ID do jogo e às informações do ID do proprietário. Foi passado para a frente quando crivamos ou ingressamos em um jogo.
Quando se trata de desenhar de verdade, nada vai mudar. No entanto, quando não estamos desenhando, queremos atualizar o documento do jogo para aprimorar nossos novos traços. O Phaser facilita a conversão de nossas informações de linha em JSON, que é inserido facilmente no MongoDB. Lembra quando eu disse que aceitar dados flexíveis era um grande benefício para os jogos?
Então, estamos enviando essas traçadas para o MongoDB. Precisamos ser capazes de carregá-los do MongoDB.
Vamos atualizar nossa funçãocreateScene :
Quando a funçãocreateScene é executada, estamos pegando a matrizstrokes que foi fornecida pelas funções createGamee joinGame e fazendo um loop sobre ela. Lembre-se, na funçãoupdateScene, estamos armazenando o caminho exato. Isso significa que podemos carregar o caminho exato e desenhá-lo.
Isso é ótimo, mas os usuários do outro lado só verão as pinceladas quando iniciarem o jogo pela primeira vez. Precisamos fazer com que elas recebam novas pinceladas à medida que são inseridas em nosso documento. Podemos fazer isso com fluxos de mudanças no Realm.
Vamos atualizar nossa createScene função mais uma vez:
Agora estamos observando nossa collection em busca de documentos que tenham um campo_idque corresponda ao nosso game ID. Lembre-se de que estamos em um jogo, não precisamos observar documentos que não sejam do nosso jogo. Quando um novo documento chega, podemos examinar os campos atualizados e renderizar os novos traços na cena.
Então, por que não estamos usando path como em todas as outras áreas do código?
Você não sabe quando novos abas vão chegar. Se você estiver usando a mesma variável global entre a tela de tiragem ativa e o change stream, há uma possibilidade de que os traçados sejam mesclados, dadas determinadas condições de corrida. É mais fácil deixar o fluxo de alterações seguir seu próprio caminho.
Neste momento, supondo que seu cluster esteja disponível e as configurações tenham sido feitas corretamente, qualquer desenho que você fizer será adicionado ao MongoDB e essencialmente sincronizado com outros computadores e dispositivos que observam o documento.

Conclusão

Você acabou de ver como fazer um jogo de desenho simples com Phaser e MongoDB. Dada a natureza do Phaser, este jogo é compatível com desktops e dispositivos móveis e, dada a natureza do MongoDB e do Realm, qualquer coisa que você adicionar ao jogo também será sincronizada entre dispositivos e plataformas.
Este é apenas um dos muitos exemplos de jogos possíveis que poderiam usar o MongoDB, e esses aplicativos interativos nem precisam ser um jogo. Você pode estar criando o próximo aplicativo do Photoshop e deseja que cada pincelada, cada camada, etc., seja sincronizada com o MongoDB. O que você pode fazer é ilimitado.

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Artigo
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Início rápido

Instâncias sem servidor do MongoDB Atlas: início rápido


Aug 13, 2024 | 4 min read
Início rápido

Aggregation Framework com Node.js 3.3.2 Tutorial


Aug 22, 2023 | 9 min read
Tutorial

Trabalhando com MongoDB Charts e o novo SDK para JavaScript


Apr 02, 2024 | 10 min read
Tutorial

Como distribuir um aplicativo no Kubernetes com o MongoDB Atlas Operator


Aug 30, 2024 | 9 min read
Sumário