Hello, I’m trying with the help of the uefn beta to make changes to the look, but I can’t get anything to work for me. Is there anyone who understands verse programming and can help me make changes to a verse file? It is from the official template, I don’t like how it does one function or I prefer another, but the beta AI is not helping me at all.
Hey @D3d how are you?
I could help you if you provide more details about what you want to do and which template are you trying to use. So I can check it for you and help with the modifications!
If you preffer to use Spanish you can, I speak Spanish as well! But please, be as detailed as you could and provide the code you are working on!
I’ll be waiting for your answer!
Vale, pues te comento. El sistema en la plantilla oficial de prop_hunt.verse de caza de elementos, me gustaría cambiar el sistema de reparto de equipos realizado con la forma “shufle” creo que se dice así, que hace que sea aleatorio la selección del cazador, y el resto son props. En el caso que en el verse config editables, se cambie el 1 hunter por cada 5 jugadores, eso no es ningun problema que se pueda escoger cantidad de cazadores. El problema es que el sistema original, puede repetir siempre que sea el mismo cazador cada ronda. Intento averiguar con el desarollador beta de verse, pero no hay manera de que funcione nada.
Mi idea era o bien que el cazador sea el que menos eliminaciones tenga, o que puedan votar quien quiere cazar, o cualquier otro sistema (no repita dos o tres rondas seguidas, etc)
Hola de nuevo @D3d !
Entiendo que lo que no debería pasar es que se repitan los cazadores en rondas sucesivas.
La forma que encontré de hacer esto es la siguiente:
(los comentarios del código van a estar en inglés para que sean útiles para la mayor cantidad de gente posible)
- Crear un map que use como key el Player/Agent y como value un logic (false/true) para llevar registro de quienes ya fueron elegidos como Hunters la ronda anterior.
Se crea de la siguiente manera:
var LastRoundHunters : [agent]logic = map{}
- Crear una función para inicializar ese map con todos los jugadores que existen actualmente en la Isla y ponerlos en false. Debes llamar esta función en el OnBegin:
OnBegin<override>()<suspends>:void =
# Initializer function called OnBegin
InitializeLastRoundHuntersMap()
# Store all current players and initialize them "false" in the map
InitializeLastRoundHuntersMap() : void =
# Iterate all the players that are currently on the Island
for ( Player : GetPlayspace().GetPlayers() ):
# Add each player one by one to the map with default value "false"
if ( set LastRoundHunters[ Player ] = false ):
- Crear una función para obtener todos los players que pueden ser seleccionados como Hunter en la próxima ronda (todos los players con value false en el map). Esta función deberías llamarla inmediatamente antes de setear la variable “NumberOfParticipants” dentro de la función “SetUpTeams” (adjunto una imagen luego del codigo):
# This function creates an array with all the players who were not hunters in the last round
GetPossibleHunters() : void =
# Creates an auxiliary array
var AuxArray : []agent = array{}
# Iterates the LastRoundHunters
for (Key -> WasHunter : LastRoundHunters):
# Check if the current player was a hunter in the last round
if (WasHunter = false):
# Adds the player to the list if it was not a hunter in the last round
if (AuxArray = AuxArray + array{Key}):
# Assign the values from the auxiliary array to our PossibleHunters array
if (PossibleHunters = AuxArray):
- Crear una función para obtener todos los players que NO fueron seleccionados como Hunters en la función anterior. Esta función la llamaremos en el siguiente punto:
# This functions returns an array with all the players who were not chosen as hunters for this round
GetPropPlayers( Participants:[]agent, StartingHunters:[]agent ) : []agent =
# Creates an auxiliary array
var AuxArray : []agent = array{}
# Iterates over all the participants
for ( Player : Participants ):
# Iterates over all the current hunters
for ( Hunter : StartingHunters ):
# Checks if the player will be a hunter this round
if ( Player = Hunter ):
else:
# Adds the player to the list if it will be not a hunter this round
if (AuxArray = AuxArray + array{Player}):
return AuxArray
- Modificar la función “SetUpTeams” para utilizar las funciones creadas anteriormente. Aquí cambiaremos varias partes, se detallan en el siguiente código:
# Shuffle the participants and then slice the array to get the starting hunter agents. The remaining participants are the starting prop agents.
# This is line "var RandomizedParticipants:[]agent = Shuffle(Participants)" is modified in the next one
var RandomizedParticipants:[]agent = Shuffle(PossibleHunters)
set StartingHunterAgents = RandomizedParticipants.Slice[0,NumberOfStartingHunters] or StartingHunterAgents
#This is line "set StartingPropAgents = RandomizedParticipants.Slice[NumberOfStartingHunters,RandomizedParticipants.Length] or StartingPropAgents" is modified in the next one
set StartingPropAgents = GetPropPlayers(Participants, StartingHunterAgents)
Con estas modificaciones, lo que debería pasar es que cada vez que se determinan los Hunters para la siguiente ronda se excluyen de la lista de selección todos los players que fueron Hunters la ronda anterior. Evitando que se repitan Hunters ronda tras ronda.
Adicionalmente, te dejo dos funciones mas para manejar las posibilidades de que entren nuevos jugadores a la isla (hay que agregarlos al map) y de que algunos jugadores se vayan de la isla (hay que quitarlos del map).
Estas funciones deberias llamarlas en el OnBegin luego de la función de inicialización que creaste en el punto 2:
OnBegin<override>()<suspends>:void =
GetPlayspace().PlayerAddedEvent().Subscribe( AddNewPlayerToLastRoundHuntersMap )
GetPlayspace().PlayerRemovedEvent().Subscribe( RemovePlayerFromLastRoundHuntersMap )
La funcón para agregar jugadores al map cuando se conectan a la Isla es:
# This function executes when a new player joins the Island and adds that player to the LastRoundHunters map
AddNewPlayerToLastRoundHuntersMap( Player : agent ) : void =
if ( set LastRoundHunters[ Player ] = false ):
La función para quitar jugadores del map cuando abandonan la Isla es:
# This function executes when a player leaves the Island and removes that player from the LastRoundHunters map
RemovePlayerFromLastRoundHuntersMap( Player : agent ) : void =
# Creates an auxiliary map to "copy" the LastRoundHunters map but with the player already removed
var AuxMap : [agent]logic = map{}
# Iterates over the LastRoundHunters map and stores all the player but the removed on the auxiliary map
for (Key -> Value : LastRoundHunters, Key <> Player):
set AuxMap = ConcatenateMaps(AuxMap, map{Key => Value})
# Finally, sets the LastRoundHunters with the updated values from the auxiliary map
set LastRoundHunters = AuxMap
Espero que esto te sea de utilidad para lo que necesitas! Dejame saber si funciona correctamente o si necesitas mas ayuda!
Vale, he conseguido terminar ahora con ayuda de la ia para entender un poco donde iba cada cosa, me aconsejo un var de esos iniciales pk me daba a entender que faltaría por añadir. Una vez todo puesto, mañana probaré con un amigo a ver como funciona.
Y por cierto, ya puestos… y añadir a todo esto eso nuevo que veo que se llama ronda infinita ??
O sea, añadir si se puede al código que en vez de finalizar ronda, cuando ganen cazadores o props, los reenvie a la sala de nuevo eespues de dar la victoria a uno o al otro, y que vuelva a empezar con el round start..
Lo que llaman ronda infinita.
Es muy lioso ??
Vale he podido hacer la prueba pero por ahora con bots (la opción de personalizado y he añadido 3 bots)
En total yo y 3 bots. Pero la prueba no ha funcionado. Aún lo he tengo que probar con otro player.
Pero con bots no funciona por este motivo:
- Iniciamos en la pre-sala, hace la cuenta atrás (ya de por si salimos todos con el pico (solo deberian salir cazadores), y cuando acaba el contador de ronda en 5..4..3..2.1… No cambia a ninguna clase, y no teletransporta a nadie. Es como si no nos metiera en la clase. Aparte que con el pico no consigo matar a ninguno, y veo a uno de ellos con el nombre en la cabeza como si ese fuera de mi equipo.
Puse armas en el team settings, y visualizar la tabla de puntuación. Yo soy teóricamente del equipo props, y llevo equipada el arma del team settings inventory del equipo props. (Pero no el de la clase) Imagino que los bots será lo mismo.
O sea, creo que no nos cambia la clase. Por eso falla al inicio.
Probaré con un player y te comentaré si sucede algo similar.
En la presa-la no teleporta a nadie. (No sé si será por lo de la clase)
Ah, y con los bots, durante 4 o 5 rondas, siempre salgo asi:
Como puedes ver, mismo equipo y sin clase. Asi ronda tras ronda. Se replica. Falta creo que lo de la clase.
Te añado 4 imagenes del codigo agregado, por si algo lo colocara mal, pues no me da errores.
Las marcadas con ### son las añadidas.
Hola nuevamente @D3d
Antes que nada, te pido disculpas por el error!
En la funcion GetPossibleHunters(), la ultima linea es “if (PossibleHunters = AuxArray):” pero deberia ser “set PossibleHunters = AuxArray”.
Con eso deberia funcionar perfectamente!
Adicionalmente, como sugerencia, te recomiendo que todas las funciones nuevas las pongas por debajo del “OnBegin”, ya que eso facilita mucho la lectura del codigo!
Por lo general se dejan todas las variables encima de OnBegin y todas las funciones debajo. Aunque no es una regla, es lo que suele hacerse para tener una lectura mas sencilla del codigo.
Saludos! Y espero que esta vez funcione correctamente!
Hice el cambio pero sigue igual, no hace nada como puse en las imagenes, no teleporta, no asigna random, nada.
Eso es muy extraño, de mi lado funciona.
Podrías enviarme una copia del codigo completo de ese device?
Por favor, enviala como texto entre “[code ] tu codigo [/code ]” (elimina los espacios y comillas).
De esta forma puedo revisarlo completo y ver los cambios que hiciste previamente.
Ten en cuenta que yo esoy usando el template de Prop Hunt sin modificaciones además de las que implementé yo mismo.
Espero tu respuesta!
Yo tambien estoy usando el template sin tocar nada mas :
using { /Fortnite.com/UI }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Colors }
using { /Verse.org/Random }
using { /Verse.org/Simulation }
log_prop_hunt_device := class(log_channel){}
prop_hunt := class(creative_device):
Logger:log = log{Channel:=log_prop_hunt_device}
@editable
PropTeam:prop_team = prop_team{}
@editable
HunterTeam:hunter_team = hunter_team{}
@editable
RoundSettings:round_settings_device = round_settings_device{}
@editable
LobbyTeleporter:teleporter_device = teleporter_device{}
@editable
WaitingForMorePlayers:waiting_for_more_players = waiting_for_more_players{}
@editable
HUDControllerWaiting:hud_controller_device = hud_controller_device{}
@editable
RoundTimer:round_timer = round_timer{}
@editable
GameMusic:radio_device = radio_device{}
@editable
StartTheHuntMessage:hud_message_device = hud_message_device{}
@editable
Cinematic:billboard_cinematic = billboard_cinematic{}
var LastRoundHunters : \[agent\]logic = map{} ###
var PossibleHunters : \[\]agent = array{} ###
OnBegin<override>()<suspends>:void =
Sleep(1.0)
InitializeLastRoundHuntersMap() ###
GetPlayspace().PlayerAddedEvent().Subscribe( AddNewPlayerToLastRoundHuntersMap ) ###
GetPlayspace().PlayerRemovedEvent().Subscribe( RemovePlayerFromLastRoundHuntersMap ) ###
Logger.Print("Round loaded.")
if (Cinematic.PlayAtStart?):
Cinematic.EnterCinematicModeForAll(GetPlayspace().GetPlayers())
Cinematic.CinematicCompleted.Await()
Cinematic.EndCinematicModeForAll(GetPlayspace().GetPlayers())
Logger.Print("Cinematic Completed.")
else:
Logger.Print("Cinematic Skipped.")
GameMusic.Play()
SetUpTeams()
race:
PropTeam.TeamEmptyEvent.Await()
HunterTeam.TeamEmptyEvent.Await()
RoundTimer.AwaitEnd()
Logger.Print("Round ending.")
EndRound()
InitializeLastRoundHuntersMap() : void = ###
for ( Player : GetPlayspace().GetPlayers() ): ###
if ( set LastRoundHunters\[ Player \] = false ): ###
GetPossibleHunters() : void = ###
var AuxArray : \[\]agent = array{} ###
for (Key -> WasHunter : LastRoundHunters): ###
if (WasHunter = false): ###
if (AuxArray = AuxArray + array{Key}): ###
set PossibleHunters = AuxArray ###
GetPropPlayers( Participants:\[\]agent, StartingHunters:\[\]agent ) : \[\]agent = ###
var AuxArray : \[\]agent = array{} ###
for ( Player : Participants ): ###
var IsHunter : logic = false ###
for ( Hunter : StartingHunters ): ###
if ( Player = Hunter ): ###
set IsHunter = true ###
if (IsHunter = false): ###
if (AuxArray = AuxArray + array{Player}): ###
return AuxArray ###
AddNewPlayerToLastRoundHuntersMap( Player : agent ) : void = ###
if ( set LastRoundHunters\[ Player \] = false ): ###
RemovePlayerFromLastRoundHuntersMap( Player : agent ) : void = ###
var AuxMap : \[agent\]logic = map{} ###
for (Key -> Value : LastRoundHunters, Key <> Player): ###
set AuxMap = ConcatenateMaps(AuxMap, map{Key => Value}) ###
set LastRoundHunters = AuxMap ###
SetUpTeams()<suspends>:void =
Logger.Print("Setting up teams.")
PropTeam.ScoreManager.SetScoreAward(PropTeam.ScorePerSecond)
PropTeam.TeamManager.TeamMemberEliminatedEvent.Subscribe(OnPropEliminated)
HunterTeam.WaitTimer.SuccessEvent.Subscribe(HuntersGo)
HunterTeam.WaitTimer.SetMaxDuration(HunterTeam.SpawnDelay)
HunterTeam.TeamManager.EnemyEliminatedEvent.Subscribe(OnHunterEliminated)
var StartingHunterAgents:\[\]agent = array{}
var StartingPropAgents:\[\]agent = array{}
var Participants:\[\]agent = GetPlayspace().GetParticipants()
HUDControllerWaiting.Enable()
set Participants = WaitingForMorePlayers.WaitForMinimumNumberOfParticipants(Participants)
Logger.Print("Round started.")
HUDControllerWaiting.Disable()
GetPlayspace().ParticipantAddedEvent().Subscribe(OnParticipantAdded)
GetPlayspace().ParticipantRemovedEvent().Subscribe(OnParticipantRemoved)
GetPossibleHunters() ###
NumberOfParticipants:float = 1.0 \* Participants.Length
if (NumberOfStartingHunters:int = Ceil\[NumberOfParticipants / Max(1.1, HunterTeam.HunterAgentPerNumberOfPlayers)\]):
var RandomizedParticipants:\[\]agent = Shuffle(PossibleHunters) ###
set StartingHunterAgents = RandomizedParticipants.Slice\[0,NumberOfStartingHunters\] or StartingHunterAgents ###
set StartingPropAgents = GetPropPlayers(Participants, StartingHunterAgents) ###
Logger.Print("Setting {StartingHunterAgents.Length} hunter agent(s).")
for (StartingHunterAgent : StartingHunterAgents):
HunterTeam.InitializeAgent(StartingHunterAgent)
HunterTeam.WaitTimer.Start()
Logger.Print("Setting {StartingPropAgents.Length} prop agent(s).")
LobbyTeleporter.Enable()
for (StartingPropAgent : StartingPropAgents):
PropTeam.InitializeAgent(StartingPropAgent)
PropTeam.HeartBeat.SetUpUI(StartingPropAgent)
LobbyTeleporter.Activate(StartingPropAgent)
LobbyTeleporter.Disable()
PropTeam.PropsRemainingTracker.SetTarget(PropTeam.Count())
PropTeam.UpdatePropsRemainingTracker()
HuntersGo(HunterInstigator:?agent):void =
spawn{ StartTheHunt() }
StartTheHunt()<suspends>:void =
Logger.Print("Teleporting hunter agent(s).")
LobbyTeleporter.Enable()
Sleep(0.5)
for (HunterAgent : HunterTeam.GetAgents\[\]):
LobbyTeleporter.Activate(HunterAgent)
StartTheHuntMessage.Show(HunterAgent)
Logger.Print("Starting prop(s) game logic.")
for (PropAgent : PropTeam.GetAgents\[\]):
spawn {PropTeam.RunPropGameLoop(PropAgent)}
StartTheHuntMessage.Show(PropAgent)
RoundTimer.Start()
PropTeam.ScoreTimer.Start()
OnParticipantAdded(Agent:agent):void =
Logger.Print("A participant joined the game.")
if (PropTeam.Count() > 0):
HunterTeam.InitializeAgent(Agent)
OnHunterEliminated(HunterAgent:agent):void =
Logger.Print("Hunter agent eliminated a prop agent.")
PropTeamSize := PropTeam.Count()
if (EliminationAward := Floor(HunterTeam.MaxEliminationScore / PropTeamSize)):
Logger.Print("Awarding {EliminationAward} points.")
HunterTeam.ScoreManager.SetScoreAward(EliminationAward)
HunterTeam.ScoreManager.Activate(HunterAgent)
OnPropEliminated(PropAgent:agent):void =
Logger.Print("Prop agent eliminated.")
spawn{ PropTeam.EliminateAgent(PropAgent) }
HunterTeam.InitializeAgent(PropAgent)
OnParticipantRemoved(Agent:agent):void =
Logger.Print("A participant left the game.")
if (PropTeam.FindOnTeam\[Agent\]):
Logger.Print("Participant was a Prop.")
spawn{ PropTeam.EliminateAgent(Agent) }
if (HunterTeam.FindOnTeam\[Agent\]):
Logger.Print("Participant was a Hunter.")
spawn{ HunterTeam.EliminateAgent(Agent) }
EndRound():void=
PropTeam.HeartBeat.DisableAll()
if (RoundEndInstigator := GetPlayspace().GetPlayers()\[0\]):
Logger.Print("Round ended.")
RoundSettings.EndRound(RoundEndInstigator)
############################### FIN CODE ###############################
Aunque veas diferencias con los
GetPossibleHunters() : void =
var AuxArray : []agent = array{}
for (Key -> WasHunter : LastRoundHunters):
if (WasHunter = false):
if (AuxArray = AuxArray + array{Key}):
if (PossibleHunters = AuxArray):
GetPropPlayers( Participants:[]agent, StartingHunters:[]agent ) : []agent =
var AuxArray : []agent = array{}
for ( Player : Participants ):
for ( Hunter : StartingHunters ):
if ( Player = Hunter ):
else:
if (AuxArray = AuxArray + array{Player}):
return AuxArray
Verás diferencia entre GetPossibleHunters y GetPropPlayers , pero aunque use este último, el tuyo tambien, ocurre lo mismo en la presala.
Tiene que ver algo el que haya modificado el islandsettings?
Hay algo mal colocado en orden?
Hola de nuevo @D3d !!
Estuve revisando el código linea por linea y el error es muy sencillo de solucionar.
En la funcion “InitializeLastRoundHuntersMap()” deberias reemplazar “GetPlayers()” por “GetParticipants()”
### Old Line
InitializeLastRoundHuntersMap() : void =
for ( Player : GetPlayspace().GetPlayers() ):
if ( set LastRoundHunters[ Player ] = false ):
### New Line
InitializeLastRoundHuntersMap() : void =
for ( Player : GetPlayspace().GetParticipants() ):
if ( set LastRoundHunters[ Player ] = false ):
Esto se debe a que “GetPlayers()” no reconoce los bots. Por ende, cuando agrega los players al map, solo te agrega a ti mismo mientras ignora a los que no sean usuarios reales.
Es una aclaración que pase por alto en mi primera version del codigo. Espero que esto lo solucione definitivamente!
Por otro lado, te recomiendo que la funcion “GetPropPlayers()” la utilices tal cual como te la envie, ya que de la forma en que la planteaste estas utilizando una variable extra (“var IsHunter : logic = false”) para comprobar el mismo resultado, lo que consume mas memoria en tu Isla.
Te pido disculpas por el error!
No solo ahora los bots no hacen nada y a mi no me teletransporta, si no que ya ni da armas ni nada. No entiendo nada. Te vuelvo a poner el codigo completo?
I get what you mean — Verse can be tricky, especially with UEFN still in beta. If you share the part of the Verse file or describe what function you want to change, I can help you figure out what’s going wrong or how to modify it the way you want.
Hola de nuevo @D3d
Estuve revisando todo nuevamente y encontre que dos de las funciones que te pase las copie de una version erronea del código. Te pido disculpas por eso.
Ademas de eso, tambien descubri que mi código tenía un error al pasar las rondas, ya que nunca actualizaba correctamente el map “[player]logic”.
Acaá te paso las funciones corregidas y la explicación de las nuevas:
- Función “GetPropPlayers”. En esta función agregué nuevamente la variable que habías implementado, llamada “IsHunter”, dado que es un buen método para evitar errores posteriores. Ademas, reemplazé el seteo del AuxArray por la sintaxtis correcta (estaba mal en el código que te envié en un principio). También agregué la linea “if ( set LastRoundHunters[ Player ] = false ):” previa al return, para que todos los jugadores que fueron elegidos como Prop para esta ronda puedan ser elegidos como Hunters en la próxima.
# This functions returns an array with all the players who were not chosen as hunters for this round
GetPropPlayers( Participants:[]agent, StartingHunters:[]agent )<suspends> : []agent =
# Creates an auxiliary array
var AuxArray : []agent = array{}
# Iterates over all the participants
for ( Player : Participants ):
var IsHunter : logic = false
# Iterates over all the current hunters
for ( Hunter : StartingHunters ):
# Checks if the player will be a hunter this round
if ( Player = Hunter ):
set IsHunter = true
# Adds the player to the list if it will be not a hunter this round
if (IsHunter = false):
set AuxArray = AuxArray + array{Player}
if ( set LastRoundHunters[ Player ] = false ):
return AuxArray
- Función “GetPossibleHunters”. Reemplazé el seteo del AuxArray por la sintaxtis correcta (estaba mal en el código que te envié en un principio).
# This functions creates an array with all the players who were not hunters in the last round
GetPossibleHunters() : void =
# Creates an auxiliary array
var AuxArray : []agent = array{}
# Iterates the LastRoundHunters
for (Key -> WasHunter : LastRoundHunters):
# Check if the current player was a hunter in the last round
if (WasHunter = false):
# Adds the player to the list if it was not a hunter in the last round
set AuxArray = AuxArray + array{Key}
# Assign the values from the auxiliary array to our PossibleHunters array
set PossibleHunters = AuxArray
- Agregue una función que actualiza el map LastRoundHunters con valor “true” a los agentes que fueron elegidos como Hunters para la ronda que está por iniciar.
# Sets value "true" for all the selected Hunters in the LastRoundHunters map
UpdateLastRoundHuntersMap( StartingHunters:[]agent ) : void =
for ( Hunter : StartingHunters ):
if ( set LastRoundHunters[ Hunter ] = true ):
Esta función debe llamarse inmediatamente despues de setear la variable “StartingHunterAgents” dentro de la función “SetUpTeams()” como se ve en la siguiente imagen:
Ahora si, con estos cambios debería funcionar correctamente.
Solo por si acaso, recuerda revisar que el device tenga asignados todos los elementos correspondientes en la Isla. A veces, cuando se realizan muchos cambios a un device, pueden desvincularse los elementos que necesita para funcionar.
Espero haber manejado todos los casos esta vez! Te pido disculpas nuevamente y quedo atento a tu respuesta!
En modo dinámico :
Con los player spawn en “all”
Con 4 bots y yo total 5 jugadores
Siempre sale el mismo bot como cazador, no hace rueda, siempre sale el mismo. Probado con 5-6 rondas.
Modificando island settings
Aparecer uniformemente
Plataformas equipo 1 - equipo 2.
Hace el random (el uniforme aleatorio de azules y rojos) pero si somos 4vs4 y agentes 1 de cada 2, siempre somos los dos en el mismo team. 2vs2 y hace cazadores contra props o props contra hunters pero siempre voy con el mismo bot.
Es como si no hiciera la rueda. (La rueda la hace el uniformemente)
He probado varias formas, y es raro, falla algo.
Te pongo el código nuevamente por si hice algo extraño…
using { /Fortnite.com/Devices }
using { /Fortnite.com/UI }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Colors }
using { /Verse.org/Random }
using { /Verse.org/Simulation }
log_prop_hunt_device := class(log_channel){}
prop_hunt := class(creative_device):
Logger:log = log{Channel:=log_prop_hunt_device}
@editable
PropTeam:prop_team = prop_team{}
@editable
HunterTeam:hunter_team = hunter_team{}
@editable
RoundSettings:round_settings_device = round_settings_device{}
@editable
LobbyTeleporter:teleporter_device = teleporter_device{}
@editable
WaitingForMorePlayers:waiting_for_more_players = waiting_for_more_players{}
@editable
HUDControllerWaiting:hud_controller_device = hud_controller_device{}
@editable
RoundTimer:round_timer = round_timer{}
@editable
GameMusic:radio_device = radio_device{}
@editable
StartTheHuntMessage:hud_message_device = hud_message_device{}
@editable
Cinematic:billboard_cinematic = billboard_cinematic{}
var LastRoundHunters : [agent]logic = map{} ###
var PossibleHunters : []agent = array{} ###
OnBegin<override>()<suspends>:void =
Sleep(1.0)
InitializeLastRoundHuntersMap() ###
GetPlayspace().PlayerAddedEvent().Subscribe( AddNewPlayerToLastRoundHuntersMap ) ###
GetPlayspace().PlayerRemovedEvent().Subscribe( RemovePlayerFromLastRoundHuntersMap ) ###
Logger.Print("Round loaded.")
if (Cinematic.PlayAtStart?):
Cinematic.EnterCinematicModeForAll(GetPlayspace().GetPlayers())
Cinematic.CinematicCompleted.Await()
Cinematic.EndCinematicModeForAll(GetPlayspace().GetPlayers())
Logger.Print("Cinematic Completed.")
else:
Logger.Print("Cinematic Skipped.")
GameMusic.Play()
SetUpTeams()
race:
PropTeam.TeamEmptyEvent.Await()
HunterTeam.TeamEmptyEvent.Await()
RoundTimer.AwaitEnd()
Logger.Print("Round ending.")
EndRound()
InitializeLastRoundHuntersMap() : void = ###
for ( Player : GetPlayspace().GetParticipants() ): ###
if ( set LastRoundHunters[ Player ] = false ): ###
GetPossibleHunters() : void = ###
var AuxArray : []agent = array{} ###
for (Key -> WasHunter : LastRoundHunters): ###
if (WasHunter = false): ###
set AuxArray = AuxArray + array{Key} ###
set PossibleHunters = AuxArray ###
GetPropPlayers( Participants:[]agent, StartingHunters:[]agent )<suspends> : []agent = ###
var AuxArray : []agent = array{} ###
for ( Player : Participants ): ###
var IsHunter : logic = false ###
for ( Hunter : StartingHunters ): ###
if ( Player = Hunter ): ###
set IsHunter = true ###
if (IsHunter = false): ###
set AuxArray = AuxArray + array{Player} ###
if ( set LastRoundHunters[ Player ] = false ): ###
return AuxArray
AddNewPlayerToLastRoundHuntersMap( Player : agent ) : void = ###
if ( set LastRoundHunters[ Player ] = false ): ###
RemovePlayerFromLastRoundHuntersMap( Player : agent ) : void = ###
var AuxMap : [agent]logic = map{} ###
for (Key -> Value : LastRoundHunters, Key <> Player): ###
set AuxMap = ConcatenateMaps(AuxMap, map{Key => Value}) ###
set LastRoundHunters = AuxMap ###
UpdateLastRoundHuntersMap( StartingHunters:[]agent ) : void =
for ( Hunter : StartingHunters ):
if ( set LastRoundHunters[ Hunter ] = true ):
SetUpTeams()<suspends>:void =
Logger.Print("Setting up teams.")
PropTeam.ScoreManager.SetScoreAward(PropTeam.ScorePerSecond)
PropTeam.TeamManager.TeamMemberEliminatedEvent.Subscribe(OnPropEliminated)
HunterTeam.WaitTimer.SuccessEvent.Subscribe(HuntersGo)
HunterTeam.WaitTimer.SetMaxDuration(HunterTeam.SpawnDelay)
HunterTeam.TeamManager.EnemyEliminatedEvent.Subscribe(OnHunterEliminated)
var StartingHunterAgents:[]agent = array{}
var StartingPropAgents:[]agent = array{}
var Participants:[]agent = GetPlayspace().GetParticipants()
HUDControllerWaiting.Enable()
set Participants = WaitingForMorePlayers.WaitForMinimumNumberOfParticipants(Participants)
Logger.Print("Round started.")
HUDControllerWaiting.Disable()
GetPlayspace().ParticipantAddedEvent().Subscribe(OnParticipantAdded)
GetPlayspace().ParticipantRemovedEvent().Subscribe(OnParticipantRemoved)
GetPossibleHunters() ###
NumberOfParticipants:float = 1.0 * Participants.Length
if (NumberOfStartingHunters:int = Ceil[NumberOfParticipants / Max(1.1, HunterTeam.HunterAgentPerNumberOfPlayers)]):
var RandomizedParticipants:[]agent = Shuffle(PossibleHunters) ###
set StartingHunterAgents = RandomizedParticipants.Slice[0,NumberOfStartingHunters] or StartingHunterAgents ###
set StartingPropAgents = GetPropPlayers(Participants, StartingHunterAgents) ###
UpdateLastRoundHuntersMap(StartingHunterAgents)
Logger.Print("Setting {StartingHunterAgents.Length} hunter agent(s).")
for (StartingHunterAgent : StartingHunterAgents):
HunterTeam.InitializeAgent(StartingHunterAgent)
HunterTeam.WaitTimer.Start()
Logger.Print("Setting {StartingPropAgents.Length} prop agent(s).")
LobbyTeleporter.Enable()
for (StartingPropAgent : StartingPropAgents):
PropTeam.InitializeAgent(StartingPropAgent)
PropTeam.HeartBeat.SetUpUI(StartingPropAgent)
LobbyTeleporter.Activate(StartingPropAgent)
LobbyTeleporter.Disable()
PropTeam.PropsRemainingTracker.SetTarget(PropTeam.Count())
PropTeam.UpdatePropsRemainingTracker()
HuntersGo(HunterInstigator:?agent):void =
spawn{ StartTheHunt() }
StartTheHunt()<suspends>:void =
Logger.Print("Teleporting hunter agent(s).")
LobbyTeleporter.Enable()
Sleep(0.5)
for (HunterAgent : HunterTeam.GetAgents[]):
LobbyTeleporter.Activate(HunterAgent)
StartTheHuntMessage.Show(HunterAgent)
Logger.Print("Starting prop(s) game logic.")
for (PropAgent : PropTeam.GetAgents[]):
spawn {PropTeam.RunPropGameLoop(PropAgent)}
StartTheHuntMessage.Show(PropAgent)
RoundTimer.Start()
PropTeam.ScoreTimer.Start()
OnParticipantAdded(Agent:agent):void =
Logger.Print("A participant joined the game.")
if (PropTeam.Count() > 0):
HunterTeam.InitializeAgent(Agent)
OnHunterEliminated(HunterAgent:agent):void =
Logger.Print("Hunter agent eliminated a prop agent.")
PropTeamSize := PropTeam.Count()
if (EliminationAward := Floor(HunterTeam.MaxEliminationScore / PropTeamSize)):
Logger.Print("Awarding {EliminationAward} points.")
HunterTeam.ScoreManager.SetScoreAward(EliminationAward)
HunterTeam.ScoreManager.Activate(HunterAgent)
OnPropEliminated(PropAgent:agent):void =
Logger.Print("Prop agent eliminated.")
spawn{ PropTeam.EliminateAgent(PropAgent) }
HunterTeam.InitializeAgent(PropAgent)
OnParticipantRemoved(Agent:agent):void =
Logger.Print("A participant left the game.")
if (PropTeam.FindOnTeam[Agent]):
Logger.Print("Participant was a Prop.")
spawn{ PropTeam.EliminateAgent(Agent) }
if (HunterTeam.FindOnTeam[Agent]):
Logger.Print("Participant was a Hunter.")
spawn{ HunterTeam.EliminateAgent(Agent) }
EndRound():void=
PropTeam.HeartBeat.DisableAll()
if (RoundEndInstigator := GetPlayspace().GetPlayers()[0]):
Logger.Print("Round ended.")
RoundSettings.EndRound(RoundEndInstigator)
Hola!
Te paso el código completo del device “prop_hunt.verse” tal cual como lo tengo yo funcionando.
Con el código armado de esta manera, y utilizando el template tal cual como viene por defecto, quien haya sido Hunter en una ronda NO puede ser hunter en la siguiente. Esto funciona sin importar la cantidad de hunters determinada por ronda (si se eligieron dos hunters en lugar de uno debido a la cantidad de players, esos dos players no podrán ser hunters en la siguiente).
Remarco nuevamente que este código personaliza funciona con el template sin modificaciones en otros devices ni en los island settings! Fue testeado con bots y con jugadores reales. Fue testeado con 5 players (1 hunter) y 6 Players (2 hunters) y funciona en todas las rondas.
Teniendo en cuenta que ahora los bots tienen todos el mismo nombre, qué método usas para identificar si es realmente el mismo bot el que sale en cada ronda?
# A tutorial for writing this script can be found at https://dev.epicgames.com/documentation/en-us/uefn/verse-prop-hunt-template-in-unreal-editor-for-fortnite
using { /Fortnite.com/Devices }
using { /Fortnite.com/UI }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Colors }
using { /Verse.org/Random }
using { /Verse.org/Simulation }
log_prop_hunt_device := class(log_channel){}
# This class contains the logic for starting and ending a round. It also handles events for participants joining and leaving when a round is in progress.
prop_hunt := class(creative_device):
Logger:log = log{Channel:=log_prop_hunt_device}
@editable # An instance of the prop_team class, used to manage the Prop team.
PropTeam:prop_team = prop_team{}
@editable # An instance of the hunter_team class, used to manage the Hunter team.
HunterTeam:hunter_team = hunter_team{}
@editable # The round manager device is used to end the round when the last prop agent is eliminated.
RoundSettings:round_settings_device = round_settings_device{}
@editable # The teleporter in the lobby area. This device is enabled and disabled to allow props and hunters out of the pre-game lobby.
LobbyTeleporter:teleporter_device = teleporter_device{}
@editable # The waiting for more players device. This device checks if there are enough participants to start the round.
WaitingForMorePlayers:waiting_for_more_players = waiting_for_more_players{}
@editable # This hud controller is used when a round is waiting to start.
# Set Priority to "Highest" for this device and have a second HUD controller set to < "Highest" to use during the round.
HUDControllerWaiting:hud_controller_device = hud_controller_device{}
@editable # The round timer device. This device keeps track of the time left in the round and is started within StartTheHunt().
RoundTimer:round_timer = round_timer{}
@editable # The device that controls the game music.
GameMusic:radio_device = radio_device{}
@editable # Message for when the hunter agents are set loose in the game.
StartTheHuntMessage:hud_message_device = hud_message_device{}
@editable # The Verse class that controls the opening cinematic.
Cinematic:billboard_cinematic = billboard_cinematic{}
var LastRoundHunters : [agent]logic = map{}
var PossibleHunters : []agent = array{}
# When the device is started in a running game, initialize subscriptions and launch the team setup. This runs at the start of every round.
OnBegin<override>()<suspends>:void =
Sleep(1.0)
Logger.Print("Round loaded.")
InitializeLastRoundHuntersMap()
GetPlayspace().PlayerAddedEvent().Subscribe( AddNewPlayerToLastRoundHuntersMap )
GetPlayspace().PlayerRemovedEvent().Subscribe( RemovePlayerFromLastRoundHuntersMap )
# Play the cinematic for each player at beginning if it is enabled
if (Cinematic.PlayAtStart?):
Cinematic.EnterCinematicModeForAll(GetPlayspace().GetPlayers())
Cinematic.CinematicCompleted.Await()
Cinematic.EndCinematicModeForAll(GetPlayspace().GetPlayers())
Logger.Print("Cinematic Completed.")
else:
Logger.Print("Cinematic Skipped.")
GameMusic.Play()
SetUpTeams()
race: # When there are no more prop or hunter agents (whichever happens first), or the round timer finishes, the round ends
PropTeam.TeamEmptyEvent.Await()
HunterTeam.TeamEmptyEvent.Await()
RoundTimer.AwaitEnd()
Logger.Print("Round ending.")
EndRound()
# Store all current players and initialize them "false" in the map
InitializeLastRoundHuntersMap() : void =
# Iterate all the players that are currently on the Island
for ( Player : GetPlayspace().GetParticipants() ):
# Add each player one by one to the map with default value "false"
if ( set LastRoundHunters[ Player ] = false ):
# This function executes when a new player joins the Island and adds that player to the LastRoundHunters map
AddNewPlayerToLastRoundHuntersMap( Player : agent ) : void =
if ( set LastRoundHunters[ Player ] = false ):
# This function executes when a player leaves the Island and removes that player from the LastRoundHunters map
RemovePlayerFromLastRoundHuntersMap( Player : agent ) : void =
# Creates an auxiliary map to "copy" the LastRoundHunters map but with the player already removed
var AuxMap : [agent]logic = map{}
# Iterates over the LastRoundHunters map and stores all the player but the removed on the auxiliary map
for (Key -> Value : LastRoundHunters, Key <> Player):
set AuxMap = ConcatenateMaps(AuxMap, map{Key => Value})
# Finally, sets the LastRoundHunters with the updated values from the auxiliary map
set LastRoundHunters = AuxMap
# This functions creates an array with all the players who were not hunters in the last round
GetPossibleHunters() : void =
# Creates an auxiliary array
var AuxArray : []agent = array{}
# Iterates the LastRoundHunters
for (Key -> WasHunter : LastRoundHunters):
# Check if the current player was a hunter in the last round
if (WasHunter = false):
# Adds the player to the list if it was not a hunter in the last round
set AuxArray = AuxArray + array{Key}
# Assign the values from the auxiliary array to our PossibleHunters array
set PossibleHunters = AuxArray
# This functions returns an array with all the players who were not chosen as hunters for this round
GetPropPlayers( Participants:[]agent, StartingHunters:[]agent )<suspends> : []agent =
# Creates an auxiliary array
var AuxArray : []agent = array{}
# Iterates over all the participants
for ( Player : Participants ):
var IsHunter : logic = false
# Iterates over all the current hunters
for ( Hunter : StartingHunters ):
# Checks if the player will be a hunter this round
if ( Player = Hunter ):
set IsHunter = true
# Adds the player to the list if it will be not a hunter this round
if (IsHunter = false):
set AuxArray = AuxArray + array{Player}
if ( set LastRoundHunters[ Player ] = false ):
return AuxArray
# Sets value "true" for all the selected Hunters in the LastRoundHunters map
UpdateLastRoundHuntersMap( StartingHunters:[]agent ) : void =
for ( Hunter : StartingHunters ):
if ( set LastRoundHunters[ Hunter ] = true ):
# When a round is started, subscribe to team devices, randomly pick the hunter agents, enable the hunter timer, set the prop agents, and teleport them into the game area.
SetUpTeams()<suspends>:void =
Logger.Print("Setting up teams.")
# Subscribe to the prop team score timer, set the score award, and subscribe to the prop team's eliminated event.
PropTeam.ScoreManager.SetScoreAward(PropTeam.ScorePerSecond)
PropTeam.TeamManager.TeamMemberEliminatedEvent.Subscribe(OnPropEliminated) # Occurs when a prop agent is eliminated.
# Subscribe to the hunter team's wait timer and set the duration. Also subscribe to the hunter team's elimination event.
HunterTeam.WaitTimer.SuccessEvent.Subscribe(HuntersGo)
HunterTeam.WaitTimer.SetMaxDuration(HunterTeam.SpawnDelay)
HunterTeam.TeamManager.EnemyEliminatedEvent.Subscribe(OnHunterEliminated) # Occurs when a hunter agent eliminates a prop agent.
# Initialize the starting hunter and prop agents arrays. Get the participants in the session.
var StartingHunterAgents:[]agent = array{}
var StartingPropAgents:[]agent = array{}
var Participants:[]agent = GetPlayspace().GetParticipants()
# Enable the HUD appropriate for the waiting for players state.
HUDControllerWaiting.Enable()
# Check if there are enough participants to start the round.
set Participants = WaitingForMorePlayers.WaitForMinimumNumberOfParticipants(Participants)
Logger.Print("Round started.")
# Disable the waiting HUD to use the next highest priority HUD.
HUDControllerWaiting.Disable()
# Now that the round has started, we need to handle participants being added or removed from the match. Subscribe to those events.
GetPlayspace().ParticipantAddedEvent().Subscribe(OnParticipantAdded)
GetPlayspace().ParticipantRemovedEvent().Subscribe(OnParticipantRemoved)
# Calls the function to obtain all the players that can be selected as hunters for this round
GetPossibleHunters()
# Calculate the number of starting hunter agents for the game based. 1 Hunter is selected per HunterAgentPerNumberOfPlayers participants.
NumberOfParticipants:float = 1.0 * Participants.Length # Converts Participants.Length to a float so it can be used in the next Ceil function.
if (NumberOfStartingHunters:int = Ceil[NumberOfParticipants / Max(1.1, HunterTeam.HunterAgentPerNumberOfPlayers)]):
# Shuffle the participants and then slice the array to get the starting hunter agents. The remaining participants are the starting prop agents.
# This is line "var RandomizedParticipants:[]agent = Shuffle(Participants)" is modified in the next one
var RandomizedParticipants:[]agent = Shuffle(PossibleHunters)
set StartingHunterAgents = RandomizedParticipants.Slice[0,NumberOfStartingHunters] or StartingHunterAgents
UpdateLastRoundHuntersMap(StartingHunterAgents)
#This is line "set StartingPropAgents = RandomizedParticipants.Slice[NumberOfStartingHunters,RandomizedParticipants.Length] or StartingPropAgents" is modified in the next one
set StartingPropAgents = GetPropPlayers(Participants, StartingHunterAgents)
# Iterate through the starting hunter agents and assign them to the hunter team. Then start the hunter wait timer.
Logger.Print("Setting {StartingHunterAgents.Length} hunter agent(s).")
for (StartingHunterAgent : StartingHunterAgents):
HunterTeam.InitializeAgent(StartingHunterAgent)
HunterTeam.WaitTimer.Start()
# Iterate through the starting prop agents and assign them to the prop team. Teleport them into the play area.
Logger.Print("Setting {StartingPropAgents.Length} prop agent(s).")
LobbyTeleporter.Enable()
for (StartingPropAgent : StartingPropAgents):
PropTeam.InitializeAgent(StartingPropAgent)
PropTeam.HeartBeat.SetUpUI(StartingPropAgent)
LobbyTeleporter.Activate(StartingPropAgent)
LobbyTeleporter.Disable()
# Set the props remaining tracker's Target and Value to the current number of props.
# In the future, we'll only update Value as props are eliminated.
PropTeam.PropsRemainingTracker.SetTarget(PropTeam.Count())
PropTeam.UpdatePropsRemainingTracker()
# When the hunter timer finishes, spawn the function that unleashes the hunter agents into the game and begins the round.
# HunterInstigator is needed for the event subscription but not used.
HuntersGo(HunterInstigator:?agent):void =
spawn{ StartTheHunt() }
# Enable the lobby teleporter, teleport all the hunter agents to the game area and then run the prop game loop for each prop agent.
StartTheHunt()<suspends>:void =
Logger.Print("Teleporting hunter agent(s).")
LobbyTeleporter.Enable()
Sleep(0.5) # Delaying half a second to give the teleporter time to enable.
for (HunterAgent : HunterTeam.GetAgents[]):
LobbyTeleporter.Activate(HunterAgent)
StartTheHuntMessage.Show(HunterAgent)
Logger.Print("Starting prop(s) game logic.")
for (PropAgent : PropTeam.GetAgents[]):
spawn {PropTeam.RunPropGameLoop(PropAgent)}
StartTheHuntMessage.Show(PropAgent)
# Signal that the round has started to start the round and scoring timers.
RoundTimer.Start()
PropTeam.ScoreTimer.Start()
# When a participant joins the match mid-round, make them a hunter if the round has started.
OnParticipantAdded(Agent:agent):void =
Logger.Print("A participant joined the game.")
if (PropTeam.Count() > 0): # if there are any prop agents, the round has started.
HunterTeam.InitializeAgent(Agent)
# When a hunter agent eliminates a prop agent, award score. The score is divided by the number of prop agents remaining.
OnHunterEliminated(HunterAgent:agent):void =
Logger.Print("Hunter agent eliminated a prop agent.")
PropTeamSize := PropTeam.Count()
if (EliminationAward := Floor(HunterTeam.MaxEliminationScore / PropTeamSize)):
Logger.Print("Awarding {EliminationAward} points.")
HunterTeam.ScoreManager.SetScoreAward(EliminationAward)
HunterTeam.ScoreManager.Activate(HunterAgent)
# When a prop agent is eliminated, remove the prop from the prop team, check for round end, and set them as a hunter.
OnPropEliminated(PropAgent:agent):void =
Logger.Print("Prop agent eliminated.")
spawn{ PropTeam.EliminateAgent(PropAgent) }
HunterTeam.InitializeAgent(PropAgent)
# When a participant leaves the match, check which team they were on and then check for round end.
OnParticipantRemoved(Agent:agent):void =
Logger.Print("A participant left the game.")
if (PropTeam.FindOnTeam[Agent]):
Logger.Print("Participant was a Prop.")
spawn{ PropTeam.EliminateAgent(Agent) }
if (HunterTeam.FindOnTeam[Agent]):
Logger.Print("Participant was a Hunter.")
spawn{ HunterTeam.EliminateAgent(Agent) }
# Cleans up the heart beat VFX and then ends the round.
EndRound():void=
PropTeam.HeartBeat.DisableAll()
# Get any player to use as an instigator to end the round.
if (RoundEndInstigator := GetPlayspace().GetPlayers()[0]):
Logger.Print("Round ended.")
RoundSettings.EndRound(RoundEndInstigator)
No entiendo muy bien a que te refieres cuando dices esto:
“Plataformas equipo 1 - equipo 2.
Hace el random (el uniforme aleatorio de azules y rojos) pero si somos 4vs4 y agentes 1 de cada 2, siempre somos los dos en el mismo team. 2vs2 y hace cazadores contra props o props contra hunters pero siempre voy con el mismo bot.
Es como si no hiciera la rueda. (La rueda la hace el uniformemente)
He probado varias formas, y es raro, falla algo.”
No encuentro como cambiar eso en el template. Hiciste alguna otra modificación además de la que estamos intentando implementar? Si hiciste mas modificaciones, es posible que alguna de ellas esté interfiriendo con el código del prop_hunt.verse
Si no hiciste ninguna modificación al template, siemplemente con reemplazar el código completo del device por el que dejo en este post debería ser suficiente para que funcione.
Lo pruebo cuando pueda y te diré algo, pues en breve podré utilizar mis otras dos cuentas para poder probar con 3 players en modo “versión privada”
Le di tu código a una IA y me dijo que cambiara 4 lineas de sitio y añadiera no se que (ya e pondré el que) y parece que tambien funciona, pero no hace cazador por ronda, si no una balanza, por ejemplo, si sales dos veces seguidas, la prioridad es mas baja en las siguientes). Probaré el tuyo en un template nuevo y te diré algo en cuanto pueda.
Por cierto, lo de ronda infinita la IA no se aclara. Si hacemos ese paso la plantilla será perfecta ![]()
Ah, lo que preguntabas por el bot, pues utilizando las puntuaciones y mostrando en la tabla de clasificación que se vea los equipos, cuando hace el round start 5.4.3…2. ya imagino que bot es cada uno, normalmente lo estoy probando así, 3 bots, yo y 1 de cada 5 agentes. Asi mas o menos se cual es cual ![]()
Vale, ya he testeado, lo de que no elija el hunter anterior si funciona, la única lógica es lo que faltaría que verás en la imagen, algunos cazaron muchas mas rondas que otros, en la lógica, habian dos bots que cazaban en una ronda si y otra no, y pocas veces me tocó a mi y al otro bot, creo que 2 para mí y otras 2 para uno de los otros bots, pues hicimos la puntuación, unos 100 puntos por ronda como prop escondido.
En total de 16 rondas, calculo que siendo los 4, cazaríamos un total de veces así:
No fueron consecutivas que eso estuvo genial!
- yo jugador 2 veces
- bot 1 unas 2.
- bot 2 unas 6 veces
- bot4 otras 6 veces.
Faltaría el balanceo y seria estupendito!









