Antes de começar a escrever qualquer código Verse para o Quebra-cabeça de luzes marcadas, é uma boa ideia pensar na melhor maneira de realizar o que você deseja fazer. Esta seção mostra como abordar a criação de uma mecânica de quebra-cabeças. Ao final desta etapa, você terá o pseudocódigo que representa o algoritmo para criar esse quebra-cabeça. A próxima etapa mostrará como implementar esse algoritmo no Verse e no UEFN.
Identificar objetivos, requisitos e restrições
O primeiro passo é identificar seus objetivos, requisitos e restrições. Os requisitos geralmente vêm da divisão de objetivos mais amplos em partes menores.
| Objetivos |
|
| Requisitos |
|
| Restrições |
|
Dividir o problema
Agora que você entende o que deseja e com o que está trabalhando, divida o problema em problemas menores que podem ser mais fáceis de raciocinar. Fazer perguntas pode ajudar a resolver um problema maior:
- Como o jogador pode interagir com o quebra-cabeça?
- Como você usa as tags de jogabilidade para encontrar as luzes?
- Como você define as condições iniciais e as soluções que podem ser modificadas no editor?
- Como você combina o estado do jogo armazenado em uma estrutura em Verse com os elementos visuais do jogo?
- Como a interação do jogador pode atualizar um conjunto específico de luzes?
- Como você desabilita a interação do jogador depois que o quebra-cabeça for resolvido?
Em seguida, identifique possíveis dependências entre esses problemas menores. Nesse caso, parece que os problemas são independentes, mas vale a pena considerar:
- As perguntas 1, 5 e 6 têm vinculação fraca.
- Para as perguntas 1 e 6, como o jogador interage com o quebra-cabeça não pode determinar como a interação é desativada depois que o quebra-cabeça é resolvido.
- Para as perguntas 1 e 5, uma única interação ativa várias luzes ao mesmo tempo. Isso informará a estrutura de dados a ser usada para o mapeamento de interação para luzes.
- A pergunta 2 é uma consideração de design importante. O funcionamento da API das tags de jogabilidade pode afetar a forma como as luzes são controladas no código. Isso tem ramificações para as perguntas 4 e 5 porque você precisará alterar o estado das luzes do jogo e, portanto, deve encontrar uma maneira comum de fazer isso.
- As perguntas 3 e 4 provavelmente devem convergir para uma única solução para a estrutura de dados subjacente para os estados inicial, atual e de solução.
Idealizar soluções potenciais
Agora que o problema foi dividido em problemas menores, concentre-se em responder às perguntas relacionadas aos problemas menores:
1. Como o jogador pode interagir com o quebra-cabeça?
Existem várias soluções para estas perguntas. Geralmente, você pode usar qualquer dispositivo com o qual o jogador pode interagir e pode ser usado em Verse para detectar a interação. O conjunto de ferramentas do Modo Criativo tem muitos dispositivos que atendem a esses requisitos, como dispositivos Gatilho, dispositivos Botão, mas também dispositivos Quadrado que Muda de Cor e dispositivos Gatilho de Percepção.
Esse exemplo usará o dispositivo de botão e seu InteractedWithEvent, que é despachado todas as vezes que o jogador interage com o botão, desde que o botão esteja ativado. Para obter mais informações sobre eventos, consulte Como programar interações entre dispositivos.
2. Como você usa as tags de jogabilidade para encontrar as luzes?
Com as tags de jogabilidade, você pode recuperar grupos de atores aos quais foi atribuída uma tag personalizada que você define em seu código Verse.
Você pode usar a função GetCreativeObjectsWithTag() para obter uma matriz de todos os atores que foram atribuídos à sua tag personalizada. O resultado da função é uma matriz de todos os objetos que implementam creative_object_interface. O customizable_light_device é a representação no Verse de um dispositivo Luz Personalizável, e é uma classe que implementa creative_object_interface.
Não há ordem garantida para a lista de dispositivos retornada por GetCreativeObjectsWithTag(), e a chamada de função pode demorar para retornar todos os dispositivos, especialmente se houver muitos dispositivos no nível, por isso é uma boa ideia armazenar as luzes para acesso rápido mais tarde. Isso é chamado de cache e geralmente pode melhorar o desempenho. Como as luzes são uma coleção do mesmo tipo, você pode usar uma matriz para armazená-las juntas.
Isso significa que é possível:
- Crie uma nova tag chamada
puzzle_light. - Marque todas as luzes para o quebra-cabeça com a tag
puzzle_light. - Chame
GetCreativeObjectsWithTag(puzzle_light)para obter todos os atores que têm a tagpuzzle_light. - Determine quais dos resultados da chamada de função são
customizable_light_device. - Salve a lista de objetos
customizable_light_deviceem uma matriz, para que possa acessá-los mais tarde.
3. Como você define as condições iniciais e as soluções que podem ser modificadas no editor?
Uma luz tem apenas dois estados: acesa ou apagada. Você pode usar o tipo logic no Verse para representar o estado aceso/apagado de uma luz, já que os valores do tipo logic só podem ser true ou false. Como existem várias luzes, você também pode usar um array aqui para armazenar todos os valores logic e fazer com que a posição do array, ou índice, para um estado de luz corresponda ao índice da luz à qual está associado.
Esse array de valores logic pode ser usado para definir o estado inicial das luzes do quebra-cabeça e também conter o estado atual das luzes durante o jogo. Você pode expor esse array ao editor com o atributo @editable. As luzes no início do jogo podem ser acesas ou apagadas para combinar visualmente com o estado armazenado no array.
A solução do quebra-cabeça deve corresponder ao tipo usado para armazenar o estado atual das luzes, para que você possa verificar se o quebra-cabeça foi resolvido comparando os dois. Isso significa que você terá dois arrays logic editáveis, um representando a condição atual das luzes e outro representando a solução do quebra-cabeça. Isso significa que você pode alterar o estado inicial das luzes do quebra-cabeça e a solução do quebra-cabeça do editor e, assim, reutilizar o quebra-cabeça com diferentes configurações.
4. Como você combina o estado do jogo armazenado em uma estrutura em Verse com os elementos visuais do jogo?
Você pode ativar ou desativar um customizable_light_device no jogo usando as funções TurnOn() e TurnOff(). Portanto, sempre que você atualizar o estado atual das luzes conforme representado pelo array lógico, também deve chamar TurnOn() e TurnOff() para combinar os elementos visuais do jogo com o estado do jogo.
5. Como a interação do jogador pode atualizar um conjunto específico de luzes?
Desde a primeira pergunta, você já determinou que o jogador vai interagir com o quebra-cabeça usando o Dispositivo de Botão. Você pode inscrever um manipulador de eventos para InteractedWithEvent do Botão, que mudará as luzes quando o jogador interagir com o Dispositivo de Botão. Como existem vários botões para o jogador usar, você pode usar um array novamente aqui para mantê-los juntos.
Agora, você precisa identificar como mapear cada evento de botão separado para o conjunto de luzes que ele deve alternar.
Como a ordem das luzes no array customize_light_device será a mesma ordem do array lógico para representar o estado das luzes, você pode criar um mapeamento entre um botão e os índices das luzes que ele afetará. Esse mapeamento pode ser representado em um array, em que a ordem dos elementos corresponde à ordem dos botões e os elementos são arrays de índices.
Você pode tornar o array editável para alterar o mapeamento de botões para luzes no editor e reutilizar o quebra-cabeça sem alterar o código propriamente dito.
6. Como você desativa a interação do jogador depois que o quebra-cabeça é resolvido?
Você já sabe que o jogador está interagindo com o quebra-cabeça usando o Dispositivo de Botão, que é detectado por meio de InteractedWithEvent.
Depois que o quebra-cabeça é resolvido, como o dispositivo de quebra-cabeça pode parar de receber informações do jogador para que o jogador não possa mais alterar o quebra-cabeça?
Existem pelo menos três maneiras de fazer isso:
- Desabilite os botões do jogo quando o quebra-cabeça for resolvido.
- Adicione um campo
logicatagged_lights_puzzleque é modificado quando o quebra-cabeça é resolvido. Sempre que o estado do jogo é atualizado, esse campologicdeve ser verificado primeiro para garantir que o quebra-cabeça ainda não tenha sido resolvido. - Cancele a inscrição nos botões
InteractedWithEventquando o quebra-cabeça for resolvido para que os manipuladores de eventos não sejam mais chamados.
A terceira opção é a melhor porque é uma solução simples e eficiente. Você não precisa criar novos campos para verificar a execução de código condicional. O conceito de cancelar a inscrição de um evento de dispositivo também é reutilizável em outras situações. Em geral, é uma boa prática se inscrever em um evento quando você deseja ser notificado sobre ele e cancelar a inscrição quando não precisa mais dele. Os detalhes de implementação para cancelar a assinatura são explicados posteriormente neste tutorial.
Combinar as soluções e planejar com pseudocódigo
Agora que você tem soluções para os problemas menores, combine-os para resolver o problema original. Formalize o algoritmo para construir a solução usando um pseudocódigo.
O que acontece quando o jogo começa? As luzes são preparadas. Você se inscreve nos Botões InteractedWithEvent, encontra todos os dispositivos com a tag puzzle_light e os armazena em cache. Você também acende/apaga as luzes do jogo com base no LightState inicial.
OnBegin:
O resultado de GetCreativeObjectsWithTag(puzzle_light) é armazenado na variável FoundDevices
para cada dispositivo em FoundDevices:
se o Dispositivo for um dispositivo de luz personalizável:
Armazene a Luz
if ShouldLightBeOn?:
Acender a luz
else:
Apagar a luz
para cada Botão:
Inscreva-se no Botão InteractedWithEvent usando o manipulador OnButtonInteractedWith
Uma versão em pseudocódigo de OnButtonInteractedWith pode ser assim, em que InteractedButtonIndex significa o índice para o array button_device que corresponde ao Botão com o qual o jogador interagiu. Você verá como receber essas informações dentro do manipulador de eventos posteriormente no tutorial.
OnButtonInteractedWith:
Obtenha as luzes associadas ao botão com o qual se interagiu usando a matriz ButtonsToLights e armazene na variável Lights
# Alternar luzes
para cada Luz em Luzes:
if IsLightOn?:
Definir o estado de Luz do jogo como apagada
Apagar a luz
else:
Definir o estado de Luz do jogo como acesa
Acender a luz
if IsPuzzleSolved():
Habilitar Gerador de Itens
para cada Botão:
Cancelar inscrição no Botão InteractedWithEvent
~~~
O pseudocódigo para `IsPuzzleSolved` verifica se o estado atual das luzes corresponde à solução. Se o estado atual não corresponder à solução, a verificação falhará e o bloco `if IsPuzzleSolved` do pseudocódigo acima não será executado. Se o estado atual corresponder à solução, a verificação será bem-sucedida, e o bloco `if IsPuzzleSolved` será executado.
~~~(verse)
IsPuzzleSolved:
para cada Luz:
se IsLightOn não for igual a IsLightOnInSolution
falhar e retornar
sucesso
Você terminou de desenvolver seu algoritmo!
Próxima etapa
Na próxima etapa deste tutorial, você adaptará esse algoritmo à linguagem de programação Verse e testará seu projeto para ver essas etapas em ação.