Estou procurando uma solução para o comportamento "Opções do botão direito".
Basicamente, todo e qualquer item de um jogo, quando clicado com o botão direito, pode exibir um conjunto de opções com base em qualquer objeto que seja.
Clique com o botão direito do mouse em exemplos para diferentes cenários :
Inventário: o capacete mostra as opções (Equipar, Usar, Soltar, Descrição)
Banco: capacete mostra opções (Take 1, Take X, Take All, Description)
Andar: capacete mostra opções (pegar, andar aqui, descrição)
Obviamente, cada opção de alguma forma aponta para um determinado método que faz o que diz. Isso faz parte do problema que estou tentando descobrir. Com tantas opções de potência para um único item, como eu teria minhas aulas projetadas de forma a não serem extremamente confusas?
- Pensei em herança, mas isso poderia ser muito longo e a cadeia poderia ser enorme.
- Pensei em usar interfaces, mas isso provavelmente me restringiria um pouco, já que eu não seria capaz de carregar dados de itens de um arquivo Xml e colocá-los em uma classe "Item" genérica.
Estou baseando meu resultado final desejado em um jogo chamado Runescape. Cada objeto pode ser clicado com o botão direito do jogo e, dependendo do que é e de onde está (inventário, piso, banco etc.) exibe um conjunto diferente de opções disponíveis para o jogador interagir.
Como eu iria conseguir isso? Que abordagem devo levar para antes de tudo, decidir quais opções DEVEM ser exibidas e, uma vez clicadas, como chamar o método correspondente.
Estou usando C # e Unity3D, mas os exemplos fornecidos não precisam estar relacionados a nenhum deles, pois estou atrás de um padrão em oposição ao código real.
Qualquer ajuda é muito apreciada e, se eu não tiver sido claro na minha pergunta ou nos resultados desejados, por favor, poste um comentário e eu o tratarei o mais rápido possível.
Aqui está o que eu tentei até agora:
- Na verdade, eu consegui implementar uma classe "Item" genérica que contém todos os valores para diferentes tipos de itens (ataque extra, defesa extra, custo etc ...). Essas variáveis são preenchidas por dados de um arquivo Xml.
- Pensei em colocar todos os métodos de interação possíveis dentro da classe Item, mas acho que essa é uma forma inacreditavelmente bagunçada e ruim. Eu provavelmente adotei a abordagem errada para implementar esse tipo de sistema usando apenas a classe e não subclassificando itens diferentes, mas é a única maneira de carregar os dados de um Xml e armazená-los na classe.
- A razão pela qual escolhi carregar todos os meus itens de um arquivo Xml é porque este jogo tem a possibilidade de mais de 40.000 itens. Se minha matemática estiver correta, uma classe para cada item é muitas.
fonte
Respostas:
Como em tudo no desenvolvimento de software, não há solução ideal. Somente a solução ideal para você e seu projeto. Aqui estão alguns que você poderia usar.
Opção 1: O modelo processual
O
antigométodoobsoleto davelha escola.Todos os itens são tipos de dados antigos simples, sem métodos, mas muitos atributos públicos que representam todas as propriedades que um item poderia ter, incluindo alguns sinalizadores booleanos
isEdible
,isEquipable
etc. , que determinam quais entradas do menu de contexto estão disponíveis para ele (talvez você também possa fique sem esses sinalizadores quando puder derivá-lo dos valores de outros atributos). Tenha em sua classe de jogador alguns métodosEat
,Equip
etc. , que pegam um item e que têm toda a lógica para processá-lo de acordo com os valores dos atributos.Opção 2: O modelo orientado a objetos
Esta é mais uma solução OOP-by-the-book que é baseada em herança e polimorfismo.
Tenha uma classe base
Item
da qual outros itensEdibleItem
, comoEquipableItem
etc. , sejam herdados. A classe base deve ter um método públicoGetContextMenuEntriesForBank
,GetContextMenuEntriesForFloor
etc. , que retorne uma lista deContextMenuEntry
. Cada classe herdada substituiria esses métodos para retornar as entradas do menu de contexto apropriadas para esse tipo de item. Também poderia chamar o mesmo método da classe base para obter algumas entradas padrão aplicáveis a qualquer tipo de item. AContextMenuEntry
seria uma classe com um métodoPerform
que chama o método relevante do item que o criou (você poderia usar um delegado para isso).Em relação aos problemas com a implementação desse padrão ao ler dados do arquivo XML: Primeiro examine o nó XML de cada item para determinar o tipo de item, depois use um código especializado para cada tipo para criar uma instância da subclasse apropriada.
Opção 3: O modelo baseado em componente
Esse padrão usa composição em vez de herança e está mais próximo de como o restante do Unity funciona. Dependendo de como você estrutura seu jogo, pode ser possível / benéfico usar o sistema de componentes do Unity para isso ... ou não, sua milhagem pode variar.
Cada objecto de classe
Item
teria uma lista de componentes comoEquipable
,Edible
,Sellable
,Drinkable
, etc. Um produto pode ter um ou nenhum de cada componente (por exemplo, um capacete de chocolate seria ambosEquipable
eEdible
, e quando não é uma trama-crítico item de missão tambémSellable
). A lógica de programação específica do componente é implementada nesse componente. Quando o usuário clica com o botão direito do mouse em um item, os componentes do item são iterados e as entradas do menu de contexto são adicionadas para cada componente existente. Quando o usuário seleciona uma dessas entradas, o componente que adicionou essa entrada processa a opção.Você pode representar isso no seu arquivo XML tendo um subnó para cada componente. Exemplo:
fonte
Então, Mike Hunt, sua pergunta me interessou tanto, que decidi implementar uma solução completa. Depois de três horas tentando coisas diferentes, acabei com esta solução passo a passo:
(Observe que esse código NÃO é muito bom, portanto aceitarei edições)
Criando painel de conteúdo
(Este painel será um contêiner para nossos botões do menu de contexto)
UI Panel
anchor
para o canto inferior esquerdowidth
para 300 (como desejar)Vertical Layout Group
e defina-oChild Alignment
para o centro superior,Child Force Expand
para a largura (não para a altura)Content Size Fitter
e definaVertical Fit
como Tamanho mínimo(Nesse momento, nosso painel diminuirá para uma linha. É normal. Este painel aceitará botões como filhos, alinhará-los verticalmente e se estenderá à altura do conteúdo resumido)
Criando botão de amostra
(Este botão será instanciado e personalizado para mostrar itens do menu de contexto)
anchor
para o canto superior esquerdoLayout Element
, definidoMin Height
como 30,Preferred Height
para 30Criando o script ContextMenu.cs
(Este script possui um método que cria e mostra o menu de contexto)
ContentPanel
pré - fabricada no slot correspondente e arraste o próprio Canvas para o slotCanvas
.Criando o script ItemController.cs
Cube
), Coloque-o para ficar visível para a câmera e anexe esse script a ele. Arraste e solte a casasampleButton
pré - fabricada no slot correspondente.Agora, tente executá-lo. Quando você clica com o botão direito do mouse no objeto, o menu de contexto deve aparecer, preenchido com a lista que criamos. Pressionar os botões imprimirá algum texto no console e o menu de contexto será destruído.
Possíveis melhorias:
Projeto de amostra (Unity Personal 5.2.0, VisualStudio Plugin): https://drive.google.com/file/d/0B7iGjyVbWvFwUnRQRVVaOGdDc2M/view?usp=sharing
fonte