How do I get a reference for each of the targets in the array so I can change their values?

I am trying to expand from the verse shooting gallery tutorial and wanted to use an array for the targets but I’m now a little lost. So i would like to know how I actually get the target reference and knock them down from the array rather than having to do a lots of repeating code if i want to add new targets.

using { /Fortnite.com/Devices }

using { /Verse.org/Simulation }

# A device that manages shooting range gameplay.

shooting_range_manager_device := class(creative_device):

@editable

GoodTrackTargets : \[\]shooting_range_target_track_device = array{}



@editable

BadTargets : \[\]shooting_range_target_device = array{}



@editable

Timer: timer_device = timer_device{}



@editable

ItemGranter: item_granter_device = item_granter_device{}



@editable

ScoreManager:score_manager_device = score_manager_device{}



@editable

SignalRemoteManager:signal_remote_manager_device = signal_remote_manager_device{}



@editable

StationaryTarget: shooting_range_target_device = shooting_range_target_device{}



\# @editable

\# GoodTarget1:shooting_range_target_track_device = shooting_range_target_track_device{}



\# @editable

\# GoodTarget2:shooting_range_target_track_device = shooting_range_target_track_device{}



\# @editable

\# GoodTarget3:shooting_range_target_track_device = shooting_range_target_track_device{}



\# @editable

\# GoodTarget4:shooting_range_target_track_device = shooting_range_target_track_device{}






@editable

BadTarget1:shooting_range_target_device = shooting_range_target_device{}



@editable

BadTarget2:shooting_range_target_device = shooting_range_target_device{}



@editable

BadTarget3:shooting_range_target_device = shooting_range_target_device{}



@editable

BadTarget4:shooting_range_target_device = shooting_range_target_device{}



@editable

BadTarget5:shooting_range_target_device = shooting_range_target_device{}



@editable

var GoodTargetScore:int = 100



@editable

var BadTargetScore:int = -100



@editable

var BullseyeGoodTargetScore: int = 250



@editable

var BullseyeBadTargetScore: int =-250




\# Runs when the device is started in a running game.

    \# 1. Update your Loop to use a single "Universal" function

OnBegin<override>()<suspends>:void=

    for (Target : GoodTrackTargets):

        \# We subscribe EVERY target to the same function

        Target.HitEvent.Subscribe(OnAnyTrackTargetHit)



    \# 2. This function now handles EVERY target in your array

    OnAnyTrackTrackHit(Result : shooting_range_target_track_hit_result):void=

        if (ShotDevice := Result.TargetDevice):

            AdjustScore(GoodTargetScore)

            ShotDevice.PopDown() # Only the one you shot pops down!

            Print("An array target was hit and popped down.")

    

    Print("--- Initializing Target Array ---")

        

        \# This loops through the array and gives us the position (X) 

        \# and the device (Target)

    for (X -> Target : GoodTrackTargets):

            Print("Target found at Index {X}")

            \# This will print the internal name of the device from UEFN

        

        Print("--- Total Targets: {GoodTrackTargets.Length} ---")



        if (TrackTargets := GoodTrackTargets\[0\]):

            TrackTargets.HitEvent.Subscribe(OnGoodTrackTargetsHit)



    \# for (Target :GoodTrackTargets):

    \#     Target.HitEvent.Subscribe(OnGoodTarget1Hit)

    \#     Target.BullseyeHitEvent.Subscribe(OnGoodTarget1HitBullseyeHitEvent)




    \# Subscribing to the StationaryTarget HitEvents.

    StationaryTarget.HitEvent.Subscribe(OnStationaryTargetHit)

    StationaryTarget.BullseyeHitEvent.Subscribe(OnStationaryBullseyeHit)

    #StationaryTarget.BullseyeHitEvent.Subscribe()



    \# Subscribing to the GoodTarget HitEvents.

    \# GoodTarget1.HitEvent.Subscribe(OnGoodTarget1Hit)

    \# GoodTarget1.BullseyeHitEvent.Subscribe(OnGoodTarget1HitBullseyeHitEvent)



    \# GoodTarget2.HitEvent.Subscribe(OnGoodTarget2Hit)

    \# GoodTarget2.BullseyeHitEvent.Subscribe(OnGoodTarget2HitBullseyeHitEvent)

    

    \# GoodTarget3.HitEvent.Subscribe(OnGoodTarget3Hit)

    \# GoodTarget3.BullseyeHitEvent.Subscribe(OnGoodTarget3HitBullseyeHitEvent)

    

    \# GoodTarget4.HitEvent.Subscribe(OnGoodTarget4Hit)

    \# GoodTarget4.BullseyeHitEvent.Subscribe(OnGoodTarget4HitBullseyeHitEvent)






    \# Subscribing to the BadTarget HitEvents.

    BadTarget1.HitEvent.Subscribe(OnBadTarget1Hit)

    BadTarget1.BullseyeHitEvent.Subscribe(OnBadTargetBullseye1Hit)



    BadTarget2.HitEvent.Subscribe(OnBadTarget2Hit)

    BadTarget2.BullseyeHitEvent.Subscribe(OnBadTargetBullseye2Hit) 



    BadTarget3.HitEvent.Subscribe(OnBadTarget3Hit)

    BadTarget3.BullseyeHitEvent.Subscribe(OnBadTargetBullseye3Hit)



    BadTarget4.HitEvent.Subscribe(OnBadTarget4Hit)

    BadTarget4.BullseyeHitEvent.Subscribe(OnBadTargetBullseye4Hit)



    BadTarget5.HitEvent.Subscribe(OnBadTarget5Hit)

    BadTarget5.BullseyeHitEvent.Subscribe(OnBadTargetBullseye5Hit)



\# A signal device trigger to stop movement of all targets



\# On starting timer make all the targets stationary

# 2. This function now handles EVERY target in your array

OnAnyTrackTrackHit(Result : shooting_range_target_track_hit_result):void=

    if (ShotDevice := Result.TargetDevice):

        AdjustScore(GoodTargetScore)

        ShotDevice.PopDown() # Only the one you shot pops down!

        Print("An array target was hit and popped down.")



\# A hit call back on the stationary target

OnStationaryTargetHit():void=

    AdjustScore(GoodTargetScore)

    #StationaryTarget



OnStationaryBullseyeHit():void=

    AdjustScore(BullseyeGoodTargetScore)



\# A hit callback that scores and pops down the first GoodTarget.

OnGoodTarget1Hit():void=

    AdjustScore(GoodTargetScore)

    Print("Target")

    #GoodTarget1.PopDown()



\# A Bullseye callback that scores and pops down the first GoodTarget.  

OnGoodTarget1HitBullseyeHitEvent():void=

    AdjustScore(BullseyeGoodTargetScore)

    Print("Bullseye")

    #GoodTarget1.PopDown()

    



\# A hit callback that scores and pops down the second GoodTarget.

OnGoodTarget2Hit():void=

    AdjustScore(GoodTargetScore)

    #GoodTarget2.PopDown()



\# A Bullseye callback that scores and pops down the second GoodTarget.  

OnGoodTarget2HitBullseyeHitEvent():void=

    AdjustScore(BullseyeGoodTargetScore)

    #GoodTarget2.PopDown()





\# A hit callback that scores and pops down the third GoodTarget.

OnGoodTarget3Hit():void=

    AdjustScore(GoodTargetScore)

    #GoodTarget3.PopDown()



\# A Bullseye callback that scores and pops down the third GoodTarget.      

OnGoodTarget3HitBullseyeHitEvent():void=

    AdjustScore(BullseyeGoodTargetScore)

    #GoodTarget3.PopDown()





\# A hit callback that scores and pops down the fourth GoodTarget.

OnGoodTarget4Hit():void=

    AdjustScore(GoodTargetScore)

    #GoodTarget4.PopDown()



\# A Bullseye callback that scores and pops down the fourth GoodTarget.    

OnGoodTarget4HitBullseyeHitEvent():void=

    AdjustScore(BullseyeGoodTargetScore)

    #GoodTarget4.PopDown()




\# A hit callback that scores and pops down the first BadTarget.

OnBadTarget1Hit():void=

    AdjustScore(BadTargetScore)

    BadTarget1.PopDown()



OnBadTargetBullseye1Hit():void=

    AdjustScore(BullseyeBadTargetScore)

    BadTarget1.PopDown()



\# A hit callback that scores and pops down the second BadTarget.

OnBadTarget2Hit():void=

    AdjustScore(BadTargetScore)

    BadTarget2.PopDown()

    

OnBadTargetBullseye2Hit():void=

    AdjustScore(BullseyeBadTargetScore)

    BadTarget2.PopDown()    



\# A hit callback that scores and pops down the third BadTarget.

OnBadTarget3Hit():void=

    AdjustScore(BadTargetScore)

    BadTarget3.PopDown()



OnBadTargetBullseye3Hit():void=

    AdjustScore(BullseyeBadTargetScore)

    BadTarget3.PopDown()   



\# A hit callback that scores and pops down the third BadTarget.

OnBadTarget4Hit():void=

    AdjustScore(BadTargetScore)

    BadTarget4.PopDown()



OnBadTargetBullseye4Hit():void=

    AdjustScore(BullseyeBadTargetScore)

    BadTarget4.PopDown()   




\# A hit callback that scores and pops down the third BadTarget.

OnBadTarget5Hit():void=

    AdjustScore(BadTargetScore)

    BadTarget5.PopDown()



OnBadTargetBullseye5Hit():void=

    AdjustScore(BullseyeBadTargetScore)

    BadTarget5.PopDown()   




\# Adjusts the player's score by the provided value.

AdjustScore(Value:int):void=

    ScoreManager.SetScoreAward(Value)



  \# Gets the first player in the playspace.

    if (Player:player = GetPlayspace().GetPlayers()\[0\]):

        \# Awards the points to the player.

        ScoreManager.Activate(Player)

        ItemGranter.GrantItem(Player)

Hello and welcome to the forums!
The targets on hit event and bullseye events don’t have a payload to use, so to solve this you could wrap them in a class that has that info and knows how to handle both of them. You can save any info and call anything you want in them. I provided a simple approach for this, you can expand on them. If you need some help, let me know. Cheers.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }

shooting_range_manager_device := class(creative_device):

    @editable
    GoodTrackTargets : []shooting_range_target_track_device = array{}

    @editable
    BadTargets : []shooting_range_target_device = array{}

    @editable
    Timer : timer_device = timer_device{}

    @editable
    ItemGranter : item_granter_device = item_granter_device{}

    @editable
    ScoreManager : score_manager_device = score_manager_device{}

    @editable
    SignalRemoteManager : signal_remote_manager_device = signal_remote_manager_device{}

    @editable
    StationaryTarget: shooting_range_target_device = shooting_range_target_device{}

    @editable
    var GoodTargetScore: int = 100

    @editable
    var BadTargetScore:int = -100

    @editable
    var BullseyeGoodTargetScore: int = 250

    @editable
    var BullseyeBadTargetScore: int =-250

    OnBegin<override>():void=
        for(GoodTarget : GoodTrackTargets):
            GoodHitWrapper := good_target_wrapper{
                Target := GoodTarget
                ShootingRange := Self
            }
            GoodTarget.HitEvent.Subscribe(GoodHitWrapper.HandleOnHitEvent)
            GoodTarget.BullseyeHitEvent.Subscribe(GoodHitWrapper.HandleBullsEye)

        for(BadTarget : BadTargets):
             BadHitWrapper := bad_target_wrapper{
                Target := BadTarget
                ShootingRange := Self
            }
            BadTarget.HitEvent.Subscribe(BadHitWrapper.HandleOnHitEvent)
            BadTarget.BullseyeHitEvent.Subscribe(BadHitWrapper.HandleBullsEye)

        #Jus as example this in case you want the results.
         for(GoodTarget : GoodTrackTargets):
            HitWrapperWithResult := hit_result_target_wrapper{
                ShootingRange := Self
                Target := GoodTarget
                NormalScore := GoodTargetScore
                BullseyeScore := BullseyeGoodTargetScore
                IsGood := true
            }
            GoodTarget.HitEvent.Subscribe(HitWrapperWithResult.HandleOnHitEvent)
            GoodTarget.BullseyeHitEvent.Subscribe(HitWrapperWithResult.HandleOnHitBullseye)


    AdjustScore(Value:int):void=
        ScoreManager.SetScoreAward(Value)
        if (Player:player = GetPlayspace().GetPlayers()[0]):
            ScoreManager.Activate(Player)
            ItemGranter.GrantItem(Player)


    HandleHit(HitResult:shooting_range_target_track_hit_result):void=
        #Handle your logic here if you want to centralize it with a custom hit result.
        #Some example of logic.
        if(HitResult.WasBullseye?):
            AdjustScore(HitResult.BullseyeScore)
        else:
            AdjustScore(HitResult.NormalScore)

        HitResult.Target.PopDown()

#A simple approach of good target wrapper
good_target_wrapper := class():
    Target : shooting_range_target_track_device
    ShootingRange : shooting_range_manager_device

    HandleOnHitEvent():void=
        ShootingRange.AdjustScore(ShootingRange.GoodTargetScore)
        Target.PopDown()
        Print("Good Target Hit")

    HandleBullsEye():void=
        ShootingRange.AdjustScore(ShootingRange.BullseyeGoodTargetScore)
        Target.PopDown()
        Print("Good Target Hit Bullseye")


#A simple approach of bad target wrapper
bad_target_wrapper := class():
    Target : shooting_range_target_device
    ShootingRange : shooting_range_manager_device

    HandleOnHitEvent():void=
        ShootingRange.AdjustScore(ShootingRange.BadTargetScore)
        Target.PopDown()
        Print("Bad Target Hit")

    HandleBullsEye():void=
        ShootingRange.AdjustScore(ShootingRange.BullseyeBadTargetScore)
        Target.PopDown()
        Print("Bad Target Hit Bullseye")



#Wrapper to create data based on hit events.
hit_result_target_wrapper := class():
    ShootingRange : shooting_range_manager_device
    Target : shooting_range_target_track_device
    NormalScore : int
    BullseyeScore : int
    IsGood : logic 
    
    HandleOnHitEvent():void=
        HitResult := shooting_range_target_track_hit_result{
            Target := Target
            WasBullseye := false
            IsGood := IsGood
            NormalScore := NormalScore
            BullseyeScore := BullseyeScore 
        }
        ShootingRange.HandleHit(HitResult)

    HandleOnHitBullseye():void=
        HitResult := shooting_range_target_track_hit_result{
            Target := Target
            WasBullseye := true
            IsGood := IsGood
            NormalScore := NormalScore
            BullseyeScore := BullseyeScore 
        }
        ShootingRange.HandleHit(HitResult)

#Data to be used in the shooting range.
shooting_range_target_track_hit_result := struct():
    Target : shooting_range_target_track_device
    NormalScore : int
    BullseyeScore : int
    WasBullseye : logic 
    IsGood : logic 
1 Like

First of all, thanks for the welcome.

It is very helpful to know a wrapper can be used for the purposes that I need and its ability to store information.

As I am new to learning the Verse programming language, is there any specific ways that you recommend I do so? I’ve been following the documentation but it still seems a little abstract at the moment.

Yeah the docs, I would say provide a first look, but not a full picture, of what’s really in them.

In my case, when learning for the first time, was googling a lot to find something that appears to be what I wanted then searching the docs and once I found the class name, going to the digest that contains it on UEFN. It could be Fornite, Unreal or Verse and search for the definitions that are available there because for me it’s easier to read and understand them on the digests, specially events and their payloads.

For solutions on problems, I would recommend learning on design patterns, no need to have them on the fly or know them on a heartbeat, just knowing some exist and then coming back to see what’s like a solution on other language, helps me to refresh memory and then implement something that works for what I need.

The code snippets, it’s a good place to see how people design different solutions and helps to dive in more depth in certain topics.

Of course doing the intro that Epic provides it’s also helpful, specially what you are doing of expanding on them and encountering problems it’s really good way to improve.
You can also download some samples of projects that Epic provides, in there you can also find coding in verse to certain topics.

1 Like