Vale a pena implementar a mecânica / regras do jogo separadamente do código principal?


25

Não tenho certeza se ele se encaixa no escopo desta comunidade ou deve ir para Stackoverflow.

Vamos supor que eu queira que meu jogo seja facilmente extensível em sua essência, ou seja, eu quero que muitas pessoas, mesmo sem um conhecimento decente de programação, sejam capazes de não apenas ajustar as regras existentes, mas até adicionar mecânicas de jogo totalmente novas. Eu não sou um bom programador, mas estou pronto para aprender, só preciso de algumas instruções e garantia de que isso pode ser feito.

O que eu pensei é se é possível / viável implementar de algum modo a mecânica do jogo separadamente do código do utilitário principal? Quero dizer, para jogos de mesa, temos aqueles livros de regras que não contêm algoritmos reais de todas as ações, mas descrevem alguns protocolos e limites, referenciando fortemente o contexto de cada um desses itens. É possível fazer algo semelhante ao jogo para PC, como descrever todas as regras em um nível muito alto, facilmente legível (e alterável) por uma linguagem de programação humana, que é então "consumida" e analisada pelo código do utilitário em um instância de trabalho da mecânica de jogos?

Parece realmente que preciso escrever minha própria linguagem e um compilador))) o que não poderei fazer, é claro. Mas pode haver uma abordagem mais fácil para o problema?

FYI: minha linguagem de escolha para o código do utilitário será Python 3.x


Como você é inexperiente e trabalha como desenvolvedor único, sugiro que você não tente implementar tudo sozinho. O uso das bibliotecas SDL2 pode ser muito útil para você em muitas áreas e elas têm ligações Python para que você possa trabalhar na linguagem com a qual se sinta confortável. Para alcançar o que você está buscando, o design da sua arquitetura deve ser feito com muito, muito cuidado e eu anteciparia pelo menos uma reescrita completa, mesmo para uma equipe experiente. Além disso, o Python não é realmente muito mais fácil de aprender do que qualquer outro idioma e, na minha opinião, tem grandes dificuldades no nível intermediário.
ttbek

O conceito que você está procurando é comum fora do desenvolvedor de jogos. Há uma coleção de ferramentas de software chamadas mecanismos de regras de negócios que devem fazer exatamente isso. No game dev, você também pode aproveitar essas ferramentas. O GameplayKit da Apple, por exemplo, incluiu as classes GKRuleSystem e GKRule para uma finalidade semelhante. Levaria algum esforço para estender para permitir a edição externa disso, mas poderia ser estruturado de maneira a alterar o comportamento sem recompilação do seu código.
Sandy Chapman

Respostas:


34

De um modo geral, a facilidade com que qualquer sistema pode ser estendido depende do grau em que seus subsistemas estão acoplados de maneira firme ou vaga . Normalmente, quanto mais fracamente acoplados são os subsistemas, mais fácil é modificá-los à medida que são isolados e não necessariamente exigem uma compreensão completa do sistema como um todo.

Porém, nada é gratuito - esse sistema normalmente requer mais recursos (várias combinações de tempo, dinheiro e habilidade) para ser construído. O grau de extensibilidade que você descreveu me parece estar diretamente em desacordo com o nível de habilidade que você atribuiu a si mesmo. Isso pode ser feito, mas criar software como você descreveu é uma tarefa muito desafiadora.

As coisas mais próximas que eu conheço são Vassal (que é muito mais programático do que você descreveu), ou fazer um mod para o Tabletop Simulator (que depende principalmente da interação humana para interpretar e aplicar as regras do jogo).


Conselhos sólidos. Eu tento manter meu código o mais flexível possível para facilitar a extensibilidade, mas você sempre terá casos em que é muito mais fácil codificar / associar algo. Mesmo como desenvolvedor profissional, não é uma tarefa fácil e, definitivamente, não é amigável para iniciantes.
precisa saber é o seguinte

O TTS agora suporta Lua e a aplicação de regras não depende totalmente das interações humanas agora.
Ave

17

O que eu pensei é se é possível / viável implementar de algum modo a mecânica do jogo separadamente do código do utilitário principal?

Isso é absolutamente possível. Uma maneira usada frequentemente em jogos é o script Lua .

Do artigo vinculado:

Lua foi originalmente projetado em 1993 como uma linguagem para estender aplicativos de software para atender à crescente demanda de customização da época.

Muitos jogos usam Lua. (Eu vincularia, mas a reputação de novos usuários está limitando minha contagem de links.)

Os scripts Lua podem ser compilados em tempo de execução. Isso significa que eles podem (por exemplo) ser arquivos de texto no diretório "scripts" do seu jogo, facilmente editáveis ​​por um modder. Seu jogo os carrega e os executa.

Eu vi scripts Lua definir as propriedades das unidades do jogo. Aqui está um exemplo aleatório da TA Spring.

Mas você deseja "descrever todas as regras". Isso é possível em teoria, pois Lua é uma linguagem completa, mas o problema é que você precisa ser suficientemente presciente para que o código principal do jogo saiba procurar scripts para estender seu comportamento.

Por exemplo, você pode desenvolver um jogo de cartas que saiba procurar cards em um diretório "scripts / cards". Isso é ótimo para adicionar novos cartões ou editar os existentes. Mas se você quiser expandir seu jogo mais tarde para incluir miniaturas em uma grade, terá que editar o código principal - nenhuma quantidade de mexer com Lua o levará lá por conta própria.

Observe: eu trago o Lua porque sei que ele é comumente usado tanto em jogos quanto em software para personalização. Não estou sugerindo que seja a única solução, nem a melhor para as necessidades do interlocutor.


7
Esta resposta implica que Lua é a única linguagem de script usada dessa maneira. Existem muitas outras linguagens de script que podem ser incorporadas nos mecanismos de jogos. Alguns mecanismos também seguem seu próprio caminho e implementam sua própria linguagem de script específica de domínio. Normalmente, eu não recomendaria isso (porque construir uma linguagem é uma tonelada de trabalho), mas isso deve ser mencionado.
Philipp

3

Há um continuum de abordagens e se alguma delas vale a pena, dependerá exatamente do que você está tentando fazer. Especificamente, quanto controle você deseja oferecer ao tweaker?

No extremo extremo do controle, você pode simplesmente deixar o tweaker modificar o código de todo o jogo. Nesse ponto, você essencialmente publicaria o código do utilitário e pelo menos um exemplo de como usá-lo. Um tweaker pode usar tanto ou pouco código quanto quiser.

Uma abordagem que ofereça um pouco menos de controle seria "congelar" seu código de utilidade (digamos, compilando-o de antemão) e deixar apenas os tweakers preencherem funções específicas (retornos de chamada), restringindo o que eles podem fazer. Dependendo do que você deseja fazer, essa abordagem pode assumir várias formas. Um método comum seria colocar toda a parte da exibição no código utilitário / principal e toda a mecânica na parte ajustável. Ou você pode manter algumas mecânicas na parte "congelada" porque é improvável que os jogadores as alterem ou torná-las mutáveis ​​é muito complicado.

Na extremidade de baixo controle do continuum, apenas os tweakers alteram os valores dentro de um intervalo fixo. Um arquivo de dados que permite selecionar as cores das coisas dentro do jogo seria um exemplo. No entanto, você pode usar essa abordagem e ainda oferecer muita personalização. Seria possível definir uma seleção de funções e permitir que os tweakers os compusessem para criar os retornos de chamada da abordagem anterior, mas não permitindo que eles definissem novos. Ou talvez você pule a parte da composição e apenas ofereça uma seleção finita.

Os detalhes de todas essas abordagens e qual deles se encaixa no seu caso de uso depende de que tipo de jogo básico você deseja fazer e de quanto controle deseja abandonar. Observe que os jogos comerciais geralmente usam apenas o segundo e o terceiro método, porque o primeiro permite que os jogadores façam jogos totalmente separados, o que introduz problemas complicados de licenciamento. Observe que, como essas abordagens formam um continuum, a segunda abordagem também pode introduzir esses problemas.


Tornar o código-fonte aberto é meu objetivo, na verdade. O que vejo como um problema é como implementar essa extensibilidade da maneira mais fácil, para que outros jogadores do jogo (que é um jogo MP, btw) possam criar suas próprias extensões do conjunto básico de regras e compartilhá-las com cada outro, de alguma forma, evitando conflitos ao mesmo tempo. Portanto, se um usuário desenvolver alguma extensão substituindo certas regras e outro desenvolver extensão diferente, como garantir que o terceiro usuário que deseja usar os dois em seus jogos não tenha problemas de compatibilidade? Além de forçá-los a colaborar fortemente.
tis

..e implementá-lo de forma que não exija modificação de nenhum código de utilitário e, portanto, muito conhecimento sobre programação.
tis

11
Eu não acho que haveria uma maneira de evitar problemas de compatibilidade (mesmo definir a cor de algo pode causar isso!) Acho que a melhor coisa a fazer é detectar um possível problema de compatibilidade e oferecer uma maneira agradável aos usuários responder. Dependendo do design da interface do código do utilitário e das extensões em questão, pode haver uma maneira de solicitar retornos de chamada etc. que produz o resultado desejado. Então, novamente, pode não haver. Alertar o usuário que pode haver problemas e por que parece uma experiência melhor do que as coisas quebrando sem explicação.
precisa saber é o seguinte

2

É absolutamente possível separar as regras do sistema do código que as aplica. Prefiro estruturar meu código dessa maneira para projetos complexos, pois facilita a adição de novas regras ou a alteração posterior das regras sem introduzir erros no sistema subjacente. E os erros em um mecanismo de regras são encontrados mais rapidamente do que os erros em um sistema em que as regras e outros códigos são misturados muito alto, porque o mesmo mecanismo de regras é usado repetidamente por todas as regras.

Se vale a pena, depende da complexidade do sistema. Como se eu não me importasse com o Pac-Man, mas não conseguia imaginar escrever Dwarf Fortress de outra maneira.


Obrigado, @Robyn. Algum conselho de leitura para alguém que não sabe nem como abordar esse design corretamente? Existem alguns padrões de design bem estabelecidos para esses aplicativos? Algum livro que cobre o assunto?
tis

Sem livros, desculpe. Mas a idéia básica de um mecanismo de regras simples: crie uma classe Rule que possua uma propriedade para todas as informações necessárias para descrever uma regra. Se algumas dessas propriedades mantiverem funções lambda, você poderá atribuir comportamentos complexos a elas. Faça uma classe que instancia uma lista de regras, para que todas as suas regras estejam em um só lugar. Faça outra classe que tenha um método que use uma lista de Regras como entrada e as aplique ao sistema.
22617 Robyn

2

É definitivamente viável. Se vale a pena, depende de seus objetivos.

Você não precisa inventar sua própria linguagem ou escrever um compilador para fazer isso funcionar.

Se você deseja que seu jogo seja facilmente extensível, provavelmente é uma boa ideia.

Provavelmente, é mais trabalhoso para você, pelo menos a curto prazo, criar sistemas compreensíveis e facilitar a modificação.

Um jogo que faz isso é o Rimworld (não tenho afiliação) e você pode ver e aprender como eles fizeram, basicamente colocando muitos dados e mecânicos de jogos em arquivos XML que estão nas pastas do jogo para qualquer um ver e modificar. O núcleo / mecanismo do jogo foi criado usando o Unity.

Há também a possibilidade de estender o jogo ainda mais / mais profundamente por meio da codificação real, eu sei menos sobre isso, mas você pode aprender olhando no fórum de mods.

A possibilidade de modificar torna o jogo mais interessante para muitas pessoas e acho que contribuiu muito para o seu sucesso. Ele também permite que os desenvolvedores tragam qualquer conteúdo modificado que desejem para o jogo principal e, de certa forma, que acelere o desenvolvimento e melhore o jogo, pois eles recebem assistência de muitas pessoas e podem decidir aceitar coisas com base em o que é popular, o que parece funcionar etc.

E, é claro, especialmente para um pequeno estúdio independente, eles têm centenas de pessoas criando idéias e testando-as para elas, o que é muito trabalho que elas não poderiam fazer por si mesmas, nem provavelmente contratam pessoas para fazer.


Embora eu possa ver como os dados do jogo podem ser definidos com o xml, não consigo imaginar como você pode usá-los para definir regras / mecânica do jogo. Você poderia fornecer algum exemplo / artigo sobre o assunto, talvez?
tis

As regras do @tis são apenas outro tipo de dados. Se meu mecanismo tiver "Se A do B", eu posso carregar A e B de um arquivo XML, agora os usuários podem colocar regras bastante arbitrárias, um bit adicional que pode ajudar é fornecer uma lista com todos os possíveis As e Bs que você suporta per se , por exemplo, "Se status statustype move a velocidade 100", "Se status statustype e time> x then status statustype" Portanto, em seu design, pense em quais tipos de regras você deseja permitir em quais tipos de objetos (status, hora, velocidade) e com que tipos de composição permitir (e / ou etc ...). Se o status estiver subaquático e o tempo for> 5, saúde -10.
ttbek

1

Você pode querer examinar o Design Orientado a Objetos . Python tem um bom suporte para isso.

Livros grossos são escritos sobre isso, o que pode ser assustador quando você é novo, mas os princípios principais são bastante fáceis.

O ponto principal é apenas que você identifica com que tipo de objetos está trabalhando. Você não diz que tipo de jogo está pensando, mas coisas como Jogador, Monstro, Item, Equipamento, Arma, Armadura e outros são objetos típicos.

Se você deseja diferentes tipos de jogos, provavelmente desejará um objeto de Jogo que cuide da condição de vitória e tal. Talvez um objeto Map também?

Às vezes, não está claro se algo merece ser um objeto ou não, por exemplo, danos. Se você não danificar um objeto, o código será mais simples, mas torná-lo um objeto facilita a personalização.

Subclassificação: Armas e Armaduras são Equipamentos. Equipamentos são itens. Provavelmente existem outros tipos de itens. Você provavelmente achará útil definir um Combatente de classe do qual jogadores e monstros sejam subclasses.

A idéia é que, por exemplo, as armas terão muitas coisas em comum com todos os outros tipos de itens, elas terão peso, tamanho e outras propriedades assim.

Portanto, a subclasse fornece uma maneira de dizer que "as armas são como outros itens, mas além disso você pode manejá-los, eles afetam o dano que você causa, etc. etc."

A subclasse também permite que seus criadores de mods digam "Meu novo tipo de arma é exatamente como as armas padrão, exceto que ..."

Então você tem que decidir qual objeto é responsável por quê. Isso não é tão fácil quanto parece e você deve pensar um pouco sobre isso. Fazer escolhas erradas não afetará muito o jogo básico, mas dificultará a personalização.

Contanto que você esteja apenas mexendo sozinho, você pode mudar as coisas, mas no momento em que lança algo ao público, fazer alterações se torna muito mais difícil! As pessoas farão mods que dependem das coisas serem exatamente como são agora. Até insetos. As pessoas escreverão mods que dependem de bugs que permanecem no código. Se você mudar as coisas, esses mods irão quebrar e lynch mobs aparecerão em sua casa.

Por exemplo:

Um jogador empunhando uma arma ataca um monstro usando várias armaduras. Isso ocorre em um modo de jogo específico e em um determinado mapa.

Ambos os Combatentes podem ter Habilidades como Golpe Crítico e Esquiva.

Agora, qual objeto é responsável por quê?

Não existe uma resposta certa para isso. Depende muito do tipo de personalização que você deseja permitir.

Se você nunca chamar um objeto (por exemplo, o Mapa), esse objeto não poderá alterar o ataque de forma alguma.

Depois de tomar todas essas decisões, documente-as . Escreva um "Manual do Modders" que lista exatamente quais métodos modáveis ​​cada objeto possui, quais parâmetros eles usam, quais devem retornar e assim por diante ...

Boa sorte!


Sua opinião é muito apreciada e você se esforça muito, por isso definitivamente vale um +1, mas estou ciente da OOP, em geral (embora não tenha experiência nela). Meus problemas atuais são com a abordagem de design mais geral que devo adotar. Meu jogo não é tão grande quanto o D&D em escala, mas ainda assim é MUITO profundo em sua mecânica. Isso significa muito complexo, misturado em diferentes níveis de regras. O que eu gostaria de permitir que os usuários estendessem significativamente, não apenas ajustando alguns valores. Pode ser que não há solução fácil, na verdade ..
tis

@tis A chave para isso é tomar a decisão correta sobre o que realmente são os objetos no seu modelo OO do jogo. O lugar "óbvio" para começar é com os "substantivos", como arma, armadura, etc., não é o único caminho, e pode levar a uma confusão de códigos não personalizáveis. Se uma regra diz "você só atira em alguns monstros com balas de prata em um cemitério à meia-noite", onde você aplica essa regra no código? Na classe Gun (ou Bullet), na classe Monster, na classe Fighter do usuário de armas, na classe Churchyard ou na classe Time? A melhor resposta pode ser "nenhuma das anteriores" ...
alephzero

... e repensar todo o design em termos de uma classe Rules (que provavelmente é realmente um banco de dados) e uma classe de Resolução de Conflitos. Agora, outras regras como "se você não tem balas, ainda pode usar sua arma como um taco" e "se Alice lança um feitiço que protege parcialmente (mas não completamente) Bob contra ferimentos de bala, enquanto Charlie está tentando atirar em Bob, então .... "tem um único e" óbvio "local a ser implementado no código. Você pode achar que sua classe original de armas agora faz muito pouco, exceto produz alguns efeitos audiovisuais - e nem isso, se for um jogo baseado em texto!
alephzero

1

Uma maneira simples de obter algum suporte básico para isso seria separar a maioria dos valores numéricos em um ou mais arquivos de texto separados para permitir que indivíduos interessados ​​os ajustem no esquecimento.

Por exemplo, você mencionou jogos de mesa; se você teve um jogo baseado em D&D, pode ter um weapon_damagearquivo contendo linhas como Battleaxe: 1d12. O código do seu utilitário leria esse arquivo e, sempre que um dano fosse causado pelo Battleaxeseu, o generate a number from 1-12, 1 time(s)acrescentaria. Ajustar a linha para ler Battleaxe: 4d6o generate a number from 1-6, 4 time(s)adicionaria. Da mesma forma, você pode ter uma pasta Creaturese, dentro, um arquivo para cada criatura, incluindo linhas como AC: 12; adicionar novos arquivos a essa pasta criaria novas criaturas. Poderia até ser feito para classes de personagens, tipos de terreno, muitas coisas.

Esse estilo de personalização sem código ainda pode ser muito poderoso e abranger muitas partes do seu jogo. No entanto, isso realmente não permite que um usuário faça alterações que você não especificou explicitamente. Por exemplo, você pode permitir Sneak Attack: [damage]que seja dada a qualquer Criatura ou Classe para adicionar [damage]a qualquer ataque que atenda às condições de um Ataque Furtivo. Você pode até fornecer maneiras de alterar quais são as condições, como "sempre que você atacar furtivamente" ou "sempre que estiver flanqueando" ou "sempre que tiver vantagem". No entanto, se um usuário decidir que deseja que os ataques furtivos sejam "Quando você faz um teste de ataque, também pode fazer furtividade contra a percepção do alvo. Se ambos os testes forem bem-sucedidos, adicione o dano de Ataque furtivo"

Se você deseja que um usuário possa adicionar um comportamento completamente novo ao jogo sem precisar de habilidades de codificação no mesmo nível que o desenvolvedor, então, como as pessoas mencionaram, você está procurando essencialmente criar um mecanismo de jogo ou uma linguagem de programação separada. Para modificações que não exigem conhecimento de codificação, os arquivos de dados baseados em texto e as estruturas de pastas ainda podem fornecer muitas opções. Se você quiser que os usuários modifiquem mais do que isso, precisará solicitar que eles aprendam ou conheçam uma linguagem de programação.


Sim, eu preciso permitir que eles adicionem novas mecânicas também, apenas ajustar alguns valores não serve. Eu também pensei que isso pode precisar de uma linguagem separada, apenas pensei que talvez já exista uma que eu possa empregar no meu código utilitário Python.
tis

@tis Você já considerou o que a Wikipedia tem sobre o assunto ainda? pt.wikipedia.org/wiki/Logic_programming
ttbek 23/09/17

0

[Sou desenvolvedor de software há décadas, mas sem experiência em desenvolvimento de jogos, talvez a indústria de jogos adote abordagens diferentes, talvez por boas razões ...]

Sua abordagem faz absolutamente sentido para mim. O núcleo fornece as funcionalidades básicas em que a mecânica e as regras se baseiam, por isso é uma API que deve ser usada pelos componentes de nível superior.

E ao projetar uma API, minha orientação favorita é criar a linguagem na qual você deseja expressar seu código de nível superior (é claro, sem as limitações de sintaxe da sua linguagem de programação).

Portanto, uma boa abordagem seria escrever algumas regras e mecânicas hipotéticas da maneira que você gostaria que fossem expressas (com a sintaxe do Python, é claro), descobrindo assim o que você deseja que a API principal forneça às regras e mecânicas camadas.

E, é claro, eu recomendo dar uma olhada nas instalações de script dos jogos existentes para ter uma idéia do que eles fazem.

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.