Como determinar se um jogador está ocioso
Nesta seção, você aprenderá a verificar se um jogador se moveu uma certa distância desde a última atualização da simulação. Se tiver, a posição atual do jogador é salva e verificada novamente. Se não tiver, o loop é interrompido e o método se completa. Esse método usa GetFortCharacter[], GetTransform() e Translation para obter a posição do jogador. Você pode saber mais sobre esses métodos nas páginas de referência da API.
Essa página inclui trechos de Verse que mostram como executar as mecânicas de jogo necessárias nesse modo de jogo. Siga as etapas a seguir e copie o script completo na etapa 6 deste tutorial.
Siga estas etapas para determinar se um jogador está ocioso.
-
Crie um método de extensão para a classe de agente chamada
AwaitStopMoving(). Assim, você está adicionando um método personalizado a uma classe já definida.~~~(verse) (PropAgent:agent).AwaitStopMoving(MinimumDistance:float)
:void= Logger.Print("Verificando se o agente se moveu menos que a distância mínima.") ~~~ -
Obtenha a posição inicial do jogador.
(PropAgent:agent).AwaitStopMoving(MinimumDistance:float)<suspends>:void= Logger.Print("Verificando se o agente se moveu menos que a distância mínima.") # Obtenha a posição inicial do agente a partir do personagem do agente na cena. if (Tracked := PropAgent.GetFortCharacter[]): var StartPosition:vector3 = Tracked.GetTransform().Translation -
Obtenha a próxima posição do jogador na próxima atualização da simulação.
~~~(verse) (PropAgent:agent).AwaitStopMoving(MinimumDistance:float)
:void= Logger.Print("Verificando se o agente se moveu menos que a distância mínima.") # Obtenha a posição inicial do agente a partir do personagem do agente na cena. if (Tracked := PropAgent.GetFortCharacter[]): var StartPosition:vector3 = Tracked.GetTransform().Translation Sleep(0.0) # Obtenha a posição do agente na próxima marcação do jogo. NewPosition := Tracked.GetTransform().Translation ~~~ -
Verifique se a distância entre a posição inicial e a posição mais recente está dentro do limiar aceitável, passado para a função como o parâmetro
MinimumDistance. ~~~(verse) (PropAgent:agent).AwaitStopMoving(MinimumDistance:float):void= Logger.Print("Verificando se o agente se moveu menos que a distância mínima.") # Obtenha a posição inicial do agente a partir do personagem do agente na cena. if (Tracked := PropAgent.GetFortCharacter[]): var StartPosition:vector3 = Tracked.GetTransform().Translation Sleep(0.0) # Obtenha a posição do agente na próxima marcação do jogo. NewPosition := Tracked.GetTransform().Translation # Se a distância da nova posição em relação à posição inicial for menor que "MinimumDistance", o agente não se moveu e interrompemos o loop. if (Distance(StartPosition, NewPosition) < MinimumDistance): Logger.Print("O agente se moveu uma distância menor que a mínima.") # Caso contrário, redefinimos "StartPosition" para garantir que o jogador se mova da nova posição. else: set StartPosition = NewPosition ~~~ -
Agora queremos que o loop seja verificado entre as posições inicial e a mais recente, e saia do loop quando a distância entre as posições estiver acima do limiar de
MinimumDistance.# Executa o loop até que o agente se mova uma distância menor que "MinimumDistance". (PropAgent:agent).AwaitStopMoving(MinimumDistance:float)<suspends>:void= Logger.Print("Verificando se o agente se moveu menos que a distância mínima.") # Obtenha a posição inicial do agente a partir do personagem do agente na cena. if (Tracked := PropAgent.GetFortCharacter[]): var StartPosition:vector3 = Tracked.GetTransform().Translation loop: Sleep(0.0) # Obtenha a posição do agente na próxima marcação do jogo. NewPosition := Tracked.GetTransform().Translation # Se a distância da nova posição em relação à posição inicial for menor que "MinimumDistance", o agente não se moveu e interrompemos o loop. if (Distance(StartPosition, NewPosition) < MinimumDistance): Logger.Print("O agente se moveu uma distância menor que a mínima.") break # Caso contrário, redefinimos "StartPosition" para garantir que o jogador se mova da nova posição. else: set StartPosition = NewPosition
Contagem regressiva até o batimento cardíaco
Siga estas etapas para esperar uma quantidade de tempo igual a HeartBeat.MoveTime - HeartBeat.WarningTime antes de exibir um aviso e o cronômetro de contagem regressiva até que o tempo da contagem regressiva termine, e depois retire o aviso e o texto de contagem regressiva.
-
Crie uma função chamada CountdownTimer(). ~~~(verse) # Atrasa até o momento de início de "HeartBeatWarningTime". Depois, faz a contagem regressiva de "HeartBeatWarningTime" e ativa o texto da contagem regressiva. Limpa o texto quando adiado. CountdownTimer(PropAgent:agent)
:void = Logger.Print("Iniciando contagem regressiva do batimento cardíaco.") ~~~ -
Primeiro, você precisa tentar obter
heartbeat_warning_uipara o jogador associado do mapa que configurou em heartbeat.verse. Se for efetivada, você precisará iniciar o adiamento entre o jogador parar e a exibição do cronômetro de contagem regressiva.~~~(verse) # Atrasa até o momento de início de "HeartBeatWarningTime". Depois, faz a contagem regressiva de "HeartBeatWarningTime" e ativa o texto da contagem regressiva. Limpa o texto quando adiado. CountdownTimer(PropAgent:agent)
:void= Logger.Print("Iniciando contagem regressiva do batimento cardíaco.") if (UIData := HeartBeat.WarningUI[PropAgent]): Sleep(HeartBeat.MoveTime - HeartBeat.WarningTime) # Suspende pela quantidade de tempo antes de o aviso ser exibido. Logger.Print("Iniciando aviso de batimento cardíaco.") else: Logger.Print("UIData não encontrado.") ~~~ -
Agora crie a variável que será exibida na tela e reduzida em um a cada segundo. Dê a ela o nome de
WarningTimeRemaining. Defina paraWarningTimede heartbeat.verse. ComoWarningTimeRemainingé uminteWarningTimeé umfloat, você precisará da funçãoCeil[]para criar umint.# Atrasa até o momento de início de "HeartBeatWarningTime". Depois, faz a contagem regressiva de "HeartBeatWarningTime" e ativa o texto da contagem regressiva. Limpa o texto quando adiado. CountdownTimer(PropAgent:agent)<suspends>:void= Logger.Print("Iniciando contagem regressiva do batimento cardíaco.") if (UIData := HeartBeat.WarningUI[PropAgent]): Sleep(HeartBeat.MoveTime - HeartBeat.WarningTime) # Suspende pela quantidade de tempo antes de o aviso ser exibido. Logger.Print("Iniciando aviso de batimento cardíaco.") var WarningTimeRemaining:int = 0 if (set WarningTimeRemaining = Ceil[HeartBeat.WarningTime]) {} else: Logger.Print("UIData não encontrado.") -
Antes de iniciar o loop de contagem regressiva, use a expressão
deferpara retirar o cronômetro de contagem regressiva da IU do jogador sempre que a funçãoCountdownTimer()for concluída. Ela só será concluída quando o cronômetro chegar ao fim ou quando o jogador começar a se mover novamente. Consulte Defer para saber mais.~~~(verse) # Atrasa até o momento de início de "HeartBeatWarningTime". Depois, faz a contagem regressiva de "HeartBeatWarningTime" e ativa o texto da contagem regressiva. Limpa o texto quando adiado. CountdownTimer(PropAgent:agent)
:void= Logger.Print("Iniciando contagem regressiva do batimento cardíaco.") if (UIData := HeartBeat.WarningUI[PropAgent]): Sleep(HeartBeat.MoveTime - HeartBeat.WarningTime) # Suspende pela quantidade de tempo antes de o aviso ser exibido. Logger.Print("Iniciando aviso de batimento cardíaco.") var WarningTimeRemaining:int = 0 if (set WarningTimeRemaining = Ceil[HeartBeat.WarningTime]) {} # Uma função "defer" acontece quando a função é concluída ou cancelada, como por exemplo, se perder uma corrida. # Então, nesse caso, o texto de aviso é limpo quando a contagem regressiva termina ou se o agente de adereço se move antes de a contagem regressiva terminar. defer: UIData.Text.SetText(HeartBeatWarningClear) # Define o texto de aviso para o tempo restante, espera um segundo e, depois, reduz o tempo restante. Se a contagem regressiva termina, interrompe o loop. UIData.Text.SetText(HeartBeatWarningMessage(WarningTimeRemaining)) else: Logger.Print("UIData não encontrado.") ~~~ -
Por fim, crie o loop que reduz o cronômetro da contagem regressiva. Use a função
SetText()para exibirHeartBeatWarningMessagecomWarningTimeRemaining. Depois, espere um segundo comSleep()antes de reduzir o tempo restante. SeWarningTimeRemainingfor 0 ou menos, então, a contagem regressiva termina e você pode interromper o loop.# Atrasa até o momento de início de "HeartBeatWarningTime". Depois, faz a contagem regressiva de "HeartBeatWarningTime" e ativa o texto da contagem regressiva. Limpa o texto quando adiado. CountdownTimer(PropAgent:agent)<suspends>:void= Logger.Print("Iniciando contagem regressiva do batimento cardíaco.") if (UIData := HeartBeat.WarningUI[PropAgent]): Sleep(HeartBeat.MoveTime - HeartBeat.WarningTime) # Suspende pela quantidade de tempo antes de o aviso ser exibido. Logger.Print("Iniciando aviso de batimento cardíaco.") var WarningTimeRemaining:int = 0 if (set WarningTimeRemaining = Ceil[HeartBeat.WarningTime]) {} # Uma função "defer" acontece quando a função é concluída ou cancelada, como por exemplo, se perder uma corrida. # Então, nesse caso, o texto de aviso é limpo quando a contagem regressiva termina ou se o agente de adereço se move antes de a contagem regressiva terminar. defer: UIData.Text.SetText(HeartBeatWarningClear) # Define o texto de aviso para o tempo restante, espera um segundo e, depois, reduz o tempo restante. Se a contagem regressiva termina, interrompe o loop. loop: Logger.Print("Batimento cardíaco em {WarningTimeRemaining} segundo(s).") UIData.Text.SetText(HeartBeatWarningMessage(WarningTimeRemaining)) Sleep(1.0) set WarningTimeRemaining -= 1 if (WarningTimeRemaining <= 0): break else: Logger.Print("UIData não encontrado.")
Como reproduzir efeitos em jogadores ociosos
Quando AwaitStopMoving() termina, você sabe que é hora de iniciar o cronômetro de contagem regressiva do jogador e depois seus efeitos de batimentos cardíacos. Mas assim que ele começar a se mover novamente, você deve cancelar o cronômetro ou o batimento cardíaco, o que estiver em execução. Para isso, você precisa de uma expressão race, onde as duas expressões de corrida são:
-
PropAgent.AwaitStartMoving(MinimumMoveDistance). -
blockem que há uma contagem regressiva antes da reprodução dos efeitos de contagem regressiva.
AwaitStartMoving() é necessária para vencer a corrida e interromper o cronômetro de contagem regressiva ou os efeitos de batimentos cardíacos.
A expressão block é usada para garantir que as duas funções dentro dela, CountdownTimer() e StartHeartbeart(), sejam executadas em sequência e não apostem uma corrida uma contra a outra. O cronômetro de contagem regressiva destina-se a avisar o jogador adereço que seus efeitos de batimentos cardíacos começarão depois que o cronômetro terminar, então não faria sentido começar o cronômetro e o batimento cardíaco ao mesmo tempo.
Siga as etapas abaixo para reproduzir os efeitos quando o jogador não tiver se movido por muito tempo.
- Crie um método de extensão chamado
AwaitStartMoving()em que a implementação é a mesma, exceto pelo seguinte:
-
Ele verifica se o jogador se moveu
MinimumDistanceou mais desde a última atualização da simulação. Em vez de menos queMinimumDistance, como emAwaitStopMoving(). -
Ele não redefine
StartPositiondepois de cada loop. SeStartPositiontiver sido redefinida no fim de todos os loops, o jogador teria que se mover pelo valor total deMinimumDistanceou mais no tempo necessário para executar a atualização da simulação, o que pode ser impossível.~~~(verse) # Executa o loop até que o agente se mova uma distância maior que "MinimumDistance". (PropAgent:agent).AwaitStartMoving(MinimumDistance:float)
:void= Logger.Print("Verificando se o agente se move mais que a distância mínima.") # Obtenha a posição inicial do agente a partir do personagem do agente na cena. if (Tracked := PropAgent.GetFortCharacter[]): StartPosition:vector3 = Tracked.GetTransform().Translation loop: Sleep(0.0) # Obtenha a posição do agente na próxima marcação do jogo. NewPosition := Tracked.GetTransform().Translation # Se a distância da nova posição em relação à posição inicial for maior ou igual a "MinimumDistance", o agente não se moveu e interrompemos o loop. if (Distance(StartPosition, NewPosition) >= MinimumDistance): Logger.Print("O agente se moveu uma distância maior ou igual à mínima.") break ~~~
-
Crie uma função chamada
RunPropGameLoop()que faz a reprodução do efeito de batimento cardíaco quando o jogador fica ocioso por muito tempo.~~~(verse) # Se o agente de adereço parar de se mover, então execute uma corrida ("race") para ver se ele se move além do valor de "MinimumMoveDistance", o cronômetro de batimento cardíaco termina ou o agente adereço é eliminado. RunPropGameLoop(PropAgent:agent)
:void = Logger.Print("Iniciando loop de jogo do agente adereço.") ~~~ -
Espere até que o agente adereço se mova uma distância menor que a mínima, depois avance.
# Se o agente de adereço parar de se mover, então execute uma corrida ("race") para ver se ele se move além do valor de "MinimumMoveDistance", o cronômetro de batimento cardíaco termina ou o agente adereço é eliminado. RunPropGameLoop(PropAgent:agent)<suspends>:void = Logger.Print("Iniciando loop de jogo do agente adereço.") # Execute o loop para sempre por meio do comportamento do adereço até que o agente adereço seja eliminado ou que o jogador saia da sessão. loop: # Espere até que o agente de adereço se mova uma distância menor que a mínima, depois avance. PropAgent.AwaitStopMoving(MinimumMoveDistance) Sleep(0.0) -
Adicione a expressão
racepara executar uma corrida entre a conclusão deAwaitStartMoving(), ou seja, o jogador começou a se mover, e uma expressãoblockcomCountdownTimer()e depoisStartHeartbeat()sendo executada.~~~(verse) # Se o agente de adereço parar de se mover, então execute uma corrida ("race") para ver se ele se move além do valor de "MinimumMoveDistance", o cronômetro de batimento cardíaco termina ou o agente adereço é eliminado. RunPropGameLoop(PropAgent:agent)
:void = Logger.Print("Iniciando loop de jogo do agente adereço.") # Execute o loop para sempre por meio do comportamento do adereço até que o agente de adereço seja eliminado ou que o jogador saia da sessão. loop: # Espere até que o agente de adereço se mova uma distância menor que a mínima, depois avance. PropAgent.AwaitStopMoving(MinimumMoveDistance) # Até que o agente adereço se mova além da distância mínima, faça a contagem regressiva para o batimento cardíaco e depois reproduza o batimento cardíaco indefinidamente. race: PropAgent.AwaitStartMoving(MinimumMoveDistance) block: CountdownTimer(PropAgent) PropAgent.StartHeartbeat() Sleep(0.0) # Quando a corrida terminar (o agente de adereço se mover), comece o loop novamente. ~~~