Sou um programador inexperiente que cria um jogo "tipo roguelike" na veia da FTL , usando Python (nenhum PyGame até o momento, pois ainda estou preocupado apenas com o texto).
Meu jogo conterá um grande número de armas (cerca de 50 para iniciantes) que produzem habilidades únicas. Estou lutando para entender como estruturar o código do objeto de uma maneira que seja poderosa (em termos de permitir que armas tenham efeitos radicalmente diferentes) e extensível (para que eu possa adicionar mais armas facilmente mais tarde, por exemplo, soltando-as em uma pasta )
Meu primeiro instinto foi ter uma classe BasicWeapon e armas diferentes herdadas dessa classe. No entanto, isso me parece problemático: ou eu tenho que tornar a classe BasicWeapon tão básica que é basicamente inútil (os únicos recursos que todas as armas têm em comum são nome e tipo (pistola, machado, etc.)) ou preciso prever todos os efeito único que eu vou criar e codificar isso no BasicWeapon.
O último é claramente impossível, mas o primeiro ainda pode ser trabalhado. No entanto, isso me deixa com a pergunta: onde coloco o código para armas individuais?
Crio plasmarifle.py, rocketlauncher.py, swarmofbees.py, etc etc, e os solto em uma pasta de onde o jogo pode importá-los?
Ou existe uma maneira de ter um arquivo no estilo de banco de dados (talvez algo tão simples quanto uma planilha do Excel) que de alguma forma contenha código único para cada arma - sem a necessidade de recorrer a eval / exec?
Em termos da última solução (banco de dados), acho que a questão fundamental com a qual estou lutando é que, embora compreenda que é desejável manter a separação entre código e dados, sinto que as armas desfocam a linha entre "código" e "dados" um pouco; eles representam a grande variedade de coisas semelhantes que podem ser encontradas no jogo; nesse sentido, são como dados, mas a maioria deles exigirá pelo menos algum código exclusivo não compartilhado com qualquer outro item; nesse sentido, eles são, naturalmente, código.
Uma solução parcial que encontrei em outras partes deste site sugere dar à classe BasicWeapon vários métodos vazios - on_round_start (), on_attack (), on_move () etc - e, em seguida, substituir esses métodos para cada arma. Na fase relevante do ciclo de combate, o jogo chamará o método apropriado para a arma de cada personagem, e apenas aqueles que possuem métodos definidos farão alguma coisa. Isso ajuda, mas ainda não me diz onde devo colocar o código e / ou os dados de cada arma.
Existe uma linguagem ou ferramenta diferente por aí que eu possa usar como uma espécie de quimera de meio dado e meio código? Estou massacrando completamente as boas práticas de programação?
Meu entendimento sobre OOP é superficial, na melhor das hipóteses, então eu apreciaria respostas que não são muito científicas em computação.
Edição: Vaughan Hilts deixou claro em seu post abaixo que o que eu estou falando essencialmente é sobre programação orientada a dados. A essência da minha pergunta é a seguinte: como posso implementar um design orientado a dados de forma que os dados possam conter scripts, permitindo que novas armas façam coisas novas sem alterar o código principal do programa?
fonte
Respostas:
Você deseja uma abordagem orientada a dados quase certamente, a menos que seu jogo seja completamente inesperado e / ou processual gerado para o núcleo.
Essencialmente, isso envolve armazenar informações sobre suas armas em uma linguagem de marcação ou formato de arquivo de sua escolha. XML e JSON são boas opções legíveis que podem ser usadas para tornar a edição bastante simples, sem a necessidade de editores complicados, se você está apenas tentando iniciar rapidamente. ( E o Python também pode analisar o XML com bastante facilidade! ) Você pode definir atributos como 'poder', 'defesa', 'custo' e 'estatísticas' relevantes. A maneira como você estrutura seus dados depende de você.
Se uma arma precisar adicionar um efeito de status, forneça um nó de efeito Status e especifique os efeitos de um efeito de status por meio de outro objeto controlado por dados. Isso tornará seu código menos dependente do jogo específico e tornará a edição e o teste triviais do jogo. Não ter que recompilar o tempo todo também é um bônus.
A leitura suplementar está disponível abaixo:
fonte
(Desculpe enviar a resposta em vez de um comentário, mas ainda não tenho representante.)
A resposta de Vaughan é ótima, mas eu gostaria de adicionar meus dois centavos.
Um dos principais motivos pelos quais você deseja usar XML ou JSON e analisá-lo em tempo de execução é alterar e experimentar novos valores sem precisar recompilar o código. Como o Python é interpretado e, na minha opinião, bastante legível, você pode ter os dados brutos em um arquivo com um dicionário e tudo organizado:
Dessa forma, basta importar o arquivo / módulo e usá-lo como um dicionário normal.
Se você deseja adicionar scripts, pode usar a natureza dinâmica das funções Python e de 1ª classe. Você poderia fazer algo assim:
Embora eu acredite que isso seria contra o design orientado a dados. Para ser 100% DDD, você teria informações (dados) especificando quais seriam as funções e o código que essa arma específica usaria. Dessa forma, você não quebra o DDD, pois não mistura dados com funcionalidade.
fonte
Design orientado a dados
Enviei algo como esta pergunta à revisão de código recentemente.
Após algumas sugestões e melhorias, o resultado foi um código simples que permitiria certa flexibilidade na criação de armas com base em um dicionário (ou JSON). Os dados são interpretados em tempo de execução e verificações simples são feitas pela
Weapon
própria classe, sem a necessidade de contar com um interpretador de script inteiro.O Design Orientado a Dados, apesar de o Python ser uma linguagem interpretada (os arquivos de origem e de dados podem ser editados sem a necessidade de recompilá-los), parece a coisa certa a fazer em casos como o que você apresentou. Esta pergunta entra em mais detalhes sobre o conceito, seus prós e contras. Há também uma boa apresentação na Universidade de Cornell sobre isso.
Comparado com outras linguagens, como C ++, que provavelmente usariam uma linguagem de script (como LUA) para lidar com interação e script de dados x mecanismos em geral, e com um determinado formato de dados (como XML) para armazenar os dados, o Python pode realmente fazer tudo por conta própria (considerando o padrão,
dict
mas tambémweakref
, o último especificamente para carregamento e armazenamento de recursos).Um desenvolvedor independente, no entanto, não pode levar ao extremo a abordagem orientada a dados, conforme sugerido neste artigo :
Talvez, com o Python, alguém possa se beneficiar do melhor da abordagem orientada a objetos e orientada a dados, visando produtividade e extensibilidade.
Processamento de amostra simples
No caso específico discutido na revisão de código, um dicionário armazenaria os "atributos estáticos" e a lógica a ser interpretada - caso a arma tenha algum comportamento condicional.
No exemplo abaixo, uma espada deve ter algumas habilidades e estatísticas nas mãos de personagens da classe 'antipaladin', e sem efeitos, com estatísticas mais baixas quando usadas por outros personagens):
Para fins de teste, criei classes
Player
e simplesWeapon
: a primeira a segurar / equipar a arma (chamando sua configuração de on_equip condicional) e a segunda como uma classe única que recuperaria os dados do dicionário, com base no nome do item passado como argumento durante aWeapon
inicialização. Eles não refletem o design adequado das classes de jogos, mas ainda podem ser úteis para testar os dados:Com algumas melhorias futuras, espero que isso me permita ter um sistema de criação dinâmico algum dia, processando componentes de armas em vez de armas inteiras ...
Teste
Como isso:
Deve imprimir:
Para um bardo
Para um antipaladin
fonte