Usamos os seguintes sistemas para suportar tanto os sistemas de jogabilidade fundamentais quanto quaisquer objetivos dos requisitos de design principais .
Gerente de Uso
UseManager forneceu uma API simples para aplicar um objeto capturado em algo, como uma peça de roupa em camadas em um manequim.A principal função para esta API é UseManager.AddUse (tags, objetivos alvo, distância, onSuccess, onNothingEquipped, onWrongEquipped, dados extras), que vincula um conjunto de tags a objetivos alvo .Quando um jogador tem um objeto com uma das tags e clica em um objetivo, a função de chamada de retorno de sucesso é chamada.Outras funções de chamada nos permitiram mostrar informações visuais extras aos jogadores se um clique for feito sem um item capturado ou com o tipo de item errado.
Podemos remover o "uso" com UseManager.RemoveUse, que geralmente era útil quando uma missão era terminada ou um item específico era "usado".Além disso, poderíamos adicionar ou remover alvos com AddUseTargets e RemoveUseTargets .
Destaques
Quando um jogador estava perto de um item de interesse, como um selo, queríamos que esse item se destacasse de seus arredores.Para implementar isso, criamos um LocalScript chamado HighlightItems que usa uma esfera centrada ao redor do jogador para detectar toques com outras malhas, conectando-se aos eventos Touched e TouchEnded.A função getHighlight verifica várias etiquetas em uma malha tocada ou seus pais usando uma função de auxílio GetTaggedObjectUpHierarchy .Se qualquer destaque não for necessário, poderíamos removê-lo forçadamente usando uma tag Sem Destaque .No entanto, se for necessário, mas não se encaixar totalmente em várias outras etiquetas, poderíamos forçá-lo usando a etiqueta Importante .
Esta utiliza uma nova característica do motor que desenha um contorno de um objeto e/ou preenche o interior do objeto com uma cor definida; para mais informações sobre como usar esta funcionalidade, veja Destaque de Objetos. Highlights e o cursor do mouse OnItemIndicator sistemas trabalham juntos, então Highlights não apenas determinam se uma malha precisa de destaque, mas também fornecem um tipo de malha para OnItemIndicator .
HighlightItemsFunc é usado para se comunicar com outros sistemas de clientes.Por exemplo, Gerenciador de Eventos usa-o com um comando Ativar para ativar ou desativar um em determinadas cenas, e Indicador de Item usa para perguntar sobre o tipo de objeto que é.Para detectar quando um item não está mais presente, como quando uma sala corrompida é destruída, nós nos conectamos a CollectionService.GetInstanceRemovedSignal.
Lore e Bolhas de Pensamento
Lore e Bolhas de Pensamento são 2 sistemas semelhantes.Lore usa um ScreenGui como um contêiner de UI na tela com um filho Frame para controlar o redimensionamento e o redimensionamento de seus filhos TextLabels e ImageLabels , e a Lore aguarda que o jogador clique em qualquer lugar na tela para removê-la.Da mesma forma, bolhas de pensamento usam um BillboardGui com uma criança TextLabel para objetos não-lore, e exibe diálogo no espaço 3D perto do objeto por um período de tempo especificado e período de espera sem o texto ocupar toda a tela.Para mais informações sobre o design por trás desses sistemas, veja Lore e Bolhas de Pensamento.
Lore é implementado no Gerente de Lore LocalScript .Quando clicado ou tocado, ele dispara um raio usando uma função de auxílio utils.RaycastAlongPointingDir e usa um grupo Sem Colisão de Jogador .Se uma malha sob o clique ou um dos pais tiver uma etiqueta Lore ou ThoughtBubble , exibimos a interface.O texto, legenda e imagem são definidos pelos atributos LoreText, LoreCaption e LoreImage no Objeto.
Observe que usamos Camera.ViewportPointToRay ou Camera.ScreenPointToRay para construir o raio, dependendo se foi chamado de um não toque ou toque.As coordenadas estão em sistemas de coordenadas um pouco diferentes.Para o mouse, obtemos deles a partir de Class.UserInputService.InputEnded``:Connect para o MouseButton1, e para dispositivos de toque, obtemos deles a partir de Class.UserInputService.TouchTapInWorld``:Connect .
Bolhas de pensamento são semelhantes em geral, usando um raycast para verificar se uma malha ou seus pais têm uma etiqueta Bolha de pensamento .Também usa o atributo Texto de Pensamento para texto e uma etiqueta bolha de pensamento para apontar para um objeto de espaço reservado usado para posicionar a UI no mundo.Bolhas de pensamento que usam o mesmo objeto posicional, mas têm textos diferentes têm diferentes tempos de espera.
Casos especiais
Lore tem alguns casos especiais, um deles é os selos corrompidos.Quando um jogador clica em um selo corrompido, ele exibe a interface de usuário de lore e aguarda um clique para iniciar uma missão, o que afeta o fluxo do jogo.Isso é tratado pelo GameStateClient que usa um bindable LoreManagerFunc para solicitar a interface de usuário lore.Um retorno de chamada é fornecido ao sistema Lore por GameStateClient para saber quando o lore é "fechado" pelo jogador.Outro caso especial é quando Bolhas de Pensamento e Sabedoria tags estão no mesmo Objeto.Neste caso, para evitar uma sobreposição de texto de sabedoria e bolha de pensamento, executamos a bolha de pensamento após o fechamento da sabedoria. Gerente de Lore também lida com um caso especial mostrando uma pequena cutscene ao clicar em portas desativadas que estão trancadas até que o jogador pegue o selo da sala.
Indicador de Item OnItemIndicator
Queremos mostrar diferentes ícones no centro da tela quando o jogador estiver olhando para itens de interesse específico.O script do cliente OnItemindicator faz um raycast ao longo da câmera Class.CFrame.LookVector e analisa os resultados.Com base nos resultados, ela define uma imagem no OnItemIndicator2 ScreenGui .
Quando nenhum item de interesse é atingido, o ícone padrão é um pequeno ponto.Podemos definir qualquer ícone adicionando um atributo OnItemIndicator de corda a uma malha específica, usando os nomes de onItemIndicatorImages , como Mão, Olho ou PortaAtualmenteBloqueada.O atributo é necessário apenas em casos raros, e a maior parte do tempo outras tags ou sistemas existentes fornecem o tipo de ícone.Para mais detalhes, veja a função Update .
Tipos verificam alguns em uma ordem de prioridade.Após a Sobrepor/substituirde OnItemIndicator, verificamos se é possível pegá-la ou se é um arquivo para o ícone "mão" através de utils.CanGrabModel(model) ou utils.GetTaggedObjectUpHierarchy("Drawer2", model).Depois disso, chamamos HighlightManager que determina o status de destaque, os tipos de itens e qual ícone usar.Por exemplo:
highlightItemsFunc:Invoke({"GetType", curInst})
As tags Lore e ThoughtBubble são verificadas mais tarde ao verificar as tags.Para as portas, temos 2 ícones diferentes: PortaAtualmenteFechada e PortaSempreTrancada . DoorManager define um atributo verdadeiro ou falso DoorEnabled para portas que podem ser abertas ou fechadas, e usamos a presença e o valor do atributo.Objetos que se parecem com portas, mas não se abrem, têm a tag PortaTrancada .
Gerente de Portas
O Gerenciador de Portas utiliza uma tag Porta e para gerenciar a abertura e fechamento de portas.A porta tem gatilhos frontais e traseiros que conectamos com toque e eventos touchEnded .Criamos pré-adolescentes para abrir e fechar uma porta dos lados frontal e traseiro.Mantemos um mapa jogadoresNear (de jogadores que tocam os gatilhos, separadamente para os lados frontal e traseiro.
Cada porta tem um sistema de estado simples, DoorState (Fechada, Abrindo, Aberta, Fechando), com pré-adolescentes usados para transições.Podemos habilitar ou desabilitar a capacidade de uma porta de abrir ou fechar de sistemas externos chamando DoorManager.EnableDoor, que define um atributo DoorEnabled.
Animador Master
O Animador Master joga imagens animadas (atlas de textura), que usávamos para animar telas de TV.Para rolar por imagens, precisávamos saber um conjunto de parâmetros: número de linhas e colunas, número total de quadros, períodos, dimensões de imagem e um conjunto de IDs de imagem.O sistema nos permitiu animar através de várias imagens, cada uma possivelmente dividida em linhas e colunas de subimagens.Podemos fornecer esses dados através de atributos ou valores, mas nesta experiência, usamos scripts de ajuda.UpdateImageAnimations(dT) cálcula qual imagem ou subimagem precisávamos mostrar usando tempo e parâmetros.Se precisássemos mudar para uma nova imagem, definimos Imagem.Se precisarmos alterar qualquer subimagem, definimos ImageRectOffset.
Um objeto com um animado SurfaceGui teria um Animador ModuleScript, com o principal objetivo de fornecer uma função Animator.GetParams que retorna todos os parâmetros.Isso ajuda o MasterAnimator LocalScript que usa a tag Animação de Imagem e CollectionService para reunir tais objetos e encontrar o Animador ModuleScript sob eles.Então usa o pcall para exigir Animador ModuleScript e chamar GetParams nele.
Animações de Espaço Local
As Animações de Espaço Local usam uma etiqueta LocalSpaceRotation para girar principalmente objetos "cosméticos" com uma velocidade de rotação dada e um atraso ao redor do eixo X, Y ou Z.Usamos isso para objetos distantes com os quais os jogadores não interagiriam ou para objetos menores que não afetam muito a simulação.Parâmetros definidos através dos valores Speed, Delay e Axis.Para detalhes de implementação, veja Rotating Cloud Meshes.
Gerenciador de Lanterna de Cabeça
O Gerenciador de Lanterna de Cabeça lida quando os usuários selecionam o on-screen para ativar ou desativar o holofote sobre a cabeça deles, dispara comentários para o servidor usando o Evento de Lanterna e lida com sons de ativação e desativação de placas.Quando um personagem é adicionado, ou seu Head é alterado, a função giveCharacterHeadlamp clona a lâmpada modelo , e posiciona a lâmpada usando alguns deslocamentos e rotações da FaceFrontAttachment .
Gerente de Assentos
Não queremos que os jogadores se sentem automaticamente quando estão perto de um objeto em que podem se sentar.Em vez disso, queremos exigir que os usuários cliquem perto de um assento para se sentar.O script Gerenciador de Assentos adiciona ClickDetectors com base em uma etiqueta de assento e chama seat:Sit(humanoid) quando clicado.Ao teletransportar jogadores entre o estado normal e corrupto de uma sala, não podemos ter jogadores sentados porque CFrame a coordenação de mudança não seria capaz de funcionar, então o Gerenciador de Assentos tem uma funcionalidade para desativar ou habilitar assentos alguns segundos antes e depois do teleportar.
Gerenciador de Drawer
O script Gerenciador de Caixas usa uma tag Caixa2 e para lidar com cliques em caixas para abrí-las ou fechá-las, e tocar qualquer áudio correspondente.A ação de abertura e fechamento é feita definindo TargetPosition para um PrismaticConstraint .
Volume de Morte
Em algumas áreas da área principal de jogabilidade, como as faíscas elétricas e a água perto do início da estrada que leva à casa, um jogador pode ter seu conjunto definido para quando entrar em um volume com a tag KillVolume .O script KillVolumes usa Touched:Connect para determinar quando um jogador entra em um volume, então reduz sua saúde para 0.
Reaparecimento de Missão de Jogador
O script PlayerMissionRespawn usa uma tag RespawnVolume e CollectionService para lidar com volumes que fazem os jogadores respawnarem quando tocados.Colocamos esses volumes sob salas corrompidas, pois muitas missões têm lacunas ou plataformas móveis nas quais o jogador poderia cair.Quando tocado, o script reproduz uma pequena Teleport_Jump cutscene e invoca GameStateFunc com GameEvents.PlayerRespawn comando.
Ao processar GameEvents.PlayerRespawn, o script pode usar RespawnPositions, se a configuração da missão o fornecer.Caso não, ele usa TeleportPositions para a missão específica.Não temos um sistema de "checkpoint", então CalcClosestTeleportPos apenas seleciona os pontos mais próximos de Respawn ou Teleport a partir de onde o jogador atingiu o RespawnVolume, usando a única distância horizontal, "2D".
Sistemas de auxílio pequenos
Gerente de Piano
O script PianoManager usa uma tag Piano e para adicionar e tocar um dos sons de piano quando clicado no teclado.
Suporte de Ritual
O salão onde os jogadores colocam selos tem uma contrapartida complicada que sofre mudanças à medida que cada selo é colocado em sua localização definida.Por exemplo, dependendo do número de selos colocados, eventos específicos jogam para ativar/desativar luzes e feixes, alterar a transparência de certos objetos, etc.O Suporte de Ritual é um pequeno wrapper sobre chamadas para esses eventos, fornecendo parâmetros ao evento, como o que "Objetoraiz" deve ser jogado, dependendo de qual selo específico foi colocado.
Gerenciador Restaurável
Alguns objetos pegáveis são importantes para o jogabilidade, como focas, e não queríamos que eles se perdessem se um jogador os deixasse em algum lugar.Se um objeto tiver uma tag Recuperável , o script Gerenciador Recuperável lembra sua transformação quando é adicionado ao sistema de recuperação.Quando um jogador solta tal Objeto, o sistema de agarramento chama restorableManager.StartTracking .Se o objeto não for recuperado novamente em cinco segundos, o script Gerenciador Recuperável o posiciona na transformação original e redefine o tempo de rastreamento.
Portais
Em algumas missões, teletransportamos os jogadores a uma curta distância dentro de uma missão, como respawnar jogadores que caem de uma plataforma girante.Para simplificar a configuração desse tipo de teletransporte, que chamamos de "Portais" no script, uma função de auxílio ProcessPortal em DemoUtils é usada.Por exemplo, se P1 for a peça que define o gatilho inicial e P2 for a peça que define a transformação do jogador de destino, o seguinte trecho de código poderia definir tal funcionalidade do portal:
P1.Touched:Connect(function(otherPart) utils.ProcessPortal(otherPart, P2) end)
Portal de Processamento lida com a verificação de que outra parte é humana, teletransportando o jogador através de uma mudança de coordenada CFrame e invocando uma pequena cutscene para esconder a transição usando um evento Teleport_Jump em Gerenciador de Eventos.
Scripts de configuração
Temos vários scripts de configuração, definição de dados e funcionalidade comum: DemoConfig . Definições de missões. Enumerações para estados de jogo, eventos para comunicações cliente-servidor. Configurações Globais de Demo .Desenvolvemos em um local, mas liberamos (e teste de jogo) em outros.O script verifica o placeID e habilita/desabilita várias funções de truques e de depuração. DemoUtils .Várias funções de utilidade.Lidando com transformações.Definindo visibilidade, ancorada ou outras propriedades.Verificando um ponto em uma caixa.Encontrando objetos na hierarquia pelo nome "embolado".Gerenciando TempStorage (que pode ser usado para mover temporariamente modelos "em algum lugar distante" e trazê-los de volta mais tarde).Ajuda de detectores de cliques.Agarando suporte.Suporte para verificar tags (especialmente ao longo da hierarquia).Conectando gatilhos a Gerenciador de Eventos. AudioUtils . Algumas funções para tocar sons aleatórios pesados de um configurar. GrabUtil . Funções de auxílio para agarrar.