Sprites como atores

12

Não tenho experiência em questões de desenvolvimento de jogos, mas como programador. No idioma Scala, você pode ter várias tarefas escaláveis ​​com atores, muito estáveis, pelo que ouvi. Você pode até ter centenas de milhares deles rodando ao mesmo tempo sem nenhum problema.

Então eu pensei, talvez você possa usá-los como uma classe base para 2D-Sprites, para romper com o ciclo do jogo que requer passar por todos os sprites e movê-los. Eles basicamente se moviam, orientados a eventos.

Isso faria sentido para um jogo? Tendo multitarefa assim? Afinal, ele será executado na JVM, embora isso não deva ser um problema hoje em dia.

EDITAR:

Depois de mexer um pouco, notei que há apenas uma vantagem real nessa idéia: Suporte Multicore. Um loop de jogo simples será executado apenas em um núcleo e funcionará com tudo sequencialmente.

Como os computadores modernos, mesmo em casa, hoje em dia têm dois ou mais núcleos embutidos, acho uma boa idéia permitir que programadores de jogos usem com eficiência os outros núcleos. Afinal, acho que geralmente o jogador terá apenas o jogo rodando em sua máquina de oito núcleos, então por que não?

A outra vantagem que vejo é que, no Scala, você pode ter RemoteActors, que pode ser tratado da mesma maneira, mas executado em outro computador. Portanto, talvez isso possa simplificar também os jogos em rede.

Pretendo incorporar isso no meu mecanismo Scala 2D o mais rápido possível.

Lanbo
fonte
Eu ficaria muito interessado em saber como isso acontece. Eu olhei para Scala algumas vezes, mas nunca mergulhei nisso antes.
Davy8
Muitos argumentam que, para suporte explícito com vários núcleos, é melhor você usar threads em vez de processos (e os modelos do Scala modelam processos). Isso ocorre porque você pode tirar proveito da memória compartilhada entre os threads. Obviamente, isso é propenso a erros de maneiras que o modelo do ator não é.
Kylotan
Os atores Scala são multiplexados em cima de um conjunto de encadeamentos, para que possam ser mais leves que os encadeamentos. Isso significa que eles podem manipular a memória compartilhada para se comunicar, desde que esteja sincronizada corretamente. Se você usar atores remotos, eles podem estar em processos diferentes, e a única maneira de se comunicar é enviar mensagens.
axel22

Respostas:

7

Não tentei, mas sou programador do Scala e diria que essa não é a melhor abordagem. Os sprites precisam ser animados de forma síncrona. Os atores não têm garantias de que serão executados de maneira justa - alguns sprites podem ser mais rápidos que outros, o que não é o que você deseja. Você pode querer usar uma barreira para sincronizá-los, mas então - por que usar atores. Se você confiar apenas na passagem de mensagens, implementar esse tipo de sincronização (implementar uma barreira para mais de 1.000 atores) é um exagero.

Outra questão é: para que você usaria a passagem de mensagens? Você precisa de seus sprites para se comunicar? Você pode enviar uma mensagem do ator principal, dizendo a cada sprite para passar para o próximo quadro, mas em termos de desempenho, são magnitudes e magnitudes mais do que invocar métodos diretamente e iterar através de um conjunto de sprites.

Parece-me que o que você precisa aqui é uma espécie de multitarefa muito leve e nenhuma mensagem sendo transmitida. Rolar em sua própria implementação do tipo ator, que garante justiça é provavelmente o melhor caminho a percorrer, se você quiser garantir isso, mas isso é muito trabalho para pouquíssimo ganho. Outra coisa a olhar é a programação reativa funcional e scala.react, acredito que seja uma correspondência melhor para este caso de uso.

Eu implementei um mecanismo de jogo isométrico 2d no Scala. Eu usei apenas um ator global para atualizar sprites visíveis que foram animados.

Você pode implementar sua lógica de jogo usando atores - por exemplo, para distribuir cálculos em diferentes partes do mapa do jogo para diferentes atores, para que eles atualizem o estado do jogo em paralelo - e obtenham um ganho de desempenho. Eu não usaria um único ator por objeto de jogo, e sim um ator por região. Se você for muito refinado, o desempenho será prejudicado.

Ainda assim, se eu fosse você, tentaria, apenas para ver o que acontece.

axel22
fonte
1

Então eu pensei, talvez você possa usá-los como uma classe base para 2D-Sprites, para romper com o ciclo do jogo que requer passar por todos os sprites e movê-los. Eles basicamente se moviam, orientados a eventos.

Qual seria o evento que os move?

Seria um evento que você emitisse uma vez por quadro?

E se sim, como isso mudou o sistema de alguma maneira prática?

Ao estudar originalmente a orientação a objetos no contexto de C ++, aprendi que algumas pessoas gostavam de pensar em uma declaração xyz.doThis(x)como o significado 'envie a mensagem doThis para xyz (com carga útil de x) e aguarde uma resposta imediata'. Quando visto neste nível, não há diferença intrínseca entre um sistema baseado em eventos ou mensagens e um procedimento normal.

Kylotan
fonte
Atores são uma solução multiencadeada. As comunicações não são síncronas. Os atores Scala (conceito de Erlang) permitem uma programação multi-core fácil.
Ellis
Você tem razão, mas a diferença aqui seria que o sprite baseado em ator não bloqueia o loop do jogo enquanto executa a ação, enquanto a abordagem por método espera até que xyz.doThis(x)seja feito. Eu acho que isso poderia até ajudar a tornar a lógica do jogo mais rápida, especialmente em sistemas com vários núcleos.
Lanbo 31/03
Isso facilita a distribuição da manipulação de entidades por vários núcleos, é verdade. Mas o custo disso é que você não pode se referir facilmente de um ator para outro sem mensagens adicionais ou dados extras enviados nas mensagens. Então você percebe rapidamente que a abordagem ingênua aqui não ajuda - você pode formular uma maneira baseada no ator de executar as atualizações?
Kylotan
Atualmente, estou experimentando algum tipo de atualização distribuída: meus atores são como nós em uma estrutura de árvore e a atualização da raiz atualiza os filhos por distribuição de mensagens. Além disso, a verdadeira vantagem será a rede: no Scala, um ator e um RemoteActor (ator em outro sistema) podem ser abordados da mesma maneira, pelas mesmas mensagens.
Lanbo
Sim, mas o problema não é o acionamento da atualização, é garantir que o destinatário da mensagem tenha todas as informações necessárias para agir sobre ela.
Kylotan
0

Essa é uma abordagem interessante para atualizar os objetos do jogo. Não conheço o Scala, mas digo: experimente e veja como fica e, melhor ainda, publique seus resultados!

As principais perguntas que me vêm à mente são: Como você gerencia com que frequência alguns objetos do jogo são atualizados em relação a outros? Você precisará se preocupar com os atores de sprite que executam muitos ciclos, de modo que o sistema de renderização não tenha tempo para desenhar um quadro a cada 1/60º | 30º | 24º de segundo?

Outra coisa a considerar é como isso afetará a resolução das interações entre jogadores e IA que dependem da ordem de uma sequência de eventos muito rápidos. Dependendo do tipo de jogo, este pode não provavelmente não vai importar muito.

michael.bartnett
fonte
O melhor dos atores da Scala é que eles são orientados por mensagens. Cada um deles tem uma própria mensagem / fila de eventos. Não tenho certeza se 'Draw' deve ser uma mensagem ou um método de chamada. Eu acho que será o último, para que um Sprite possa ser desenhado a qualquer momento, independentemente do estado da fila de eventos. E eles podem enviar mensagens uns aos outros para garantir que as coisas sejam feitas em uma determinada ordem.
Lanbo 12/03/11
Cuidado, acho que não seria útil ter cada sprite com um método ou evento Draw, exceto talvez como um sinalizador para alternar a visibilidade. Na fase de renderização de um loop do jogo, a ordem na qual os sprites são renderizados na tela tem um grande efeito no resultado. Se você tiver um sprite localizado na frente do outro (a dimensão está na direção do monitor), você quer que ele seja desenhado em segundo. Vejo os atores de Scala sendo úteis para a parte de atualização / lógica do ciclo do jogo.
michael.bartnett
Normalmente, você só tem um método de desenho lá; portanto, ao implementá-lo dessa maneira, não deve haver muita diferença na maneira normal de lidar com sprites.
Lanbo 12/03
Ah, tudo bem, eu não entendi o que você estava descrevendo. De alguma forma, eu estava imaginando sprites se processando quando e como quisessem. Deixe-nos saber como isso acaba!
22611 michael.bartnett
0

Bem, também não sou muito programador, mas não vejo nenhum problema em sua proposta. Eu nem pensei em uma maneira de desenvolver atores.

Pode ser um grande desafio, já que a IA precisa ser muito precisa, para evitar comportamentos inesperados, mas além disso, vejo que é uma proposta muito boa

Carlos Valenzuela
fonte
0

Se por sprite você quer dizer entidade do jogo , com certeza.

As entidades do jogo nunca devem se desenhar. Eles devem atualizar um identificador gráfico que descreve onde e como eles precisam ser desenhados. O sistema de renderização ou gráfico de cena ou o que quer que seja o desenho real. Existe uma placa gráfica, além disso, a placa gráfica deve ser sincronizada a cada 16ms. Uma configuração como essa simplesmente não funciona bem para processamento assíncrono distribuído.

O sistema de renderização deve ser um ator (ou possivelmente um casal, se você for complicado). Quando as entidades do jogo atualizam o identificador gráfico, ele envia mensagens para o sistema de renderização. O sistema de renderização pode tomar todos os tipos de decisões e / ou otimizações, por exemplo, renderização em lote, oclusão, suavização de tremores físicos, etc.

Não sou desenvolvedor de Scala, mas já fiz bastante com Erlang. Portanto, se parte da minha terminologia Scala estiver incorreta, por favor, perdoe-me.

deft_code
fonte