Skip to main content

Selecting Random Enemies

Overview

note

See LV_SelectRandomActors in the example map for an implementation.

Loot Tables are very effective, but sometimes you may want to associate data with distributions that can't be placed in data tables (e.g., the data was sourced at runtime). For this, we may use the same design as loot tables but associate our data instead of Data Table Row Handles.

Suppose we have a lightning spell which bounces between enemies randomly, with closer enemies more likely to be selected. We can't use a loot table for this because of two reasons:

  • The amount of items (enemies) is based on runtime data.
  • The weights of each item (enemy) are based on runtime data.

Suppose we are casting this spell with three viable targets for the next bounce:

Table A (Possible Targets)
IndexDistanceEnemy Reference
0100BP_Enemy_0
1400BP_Enemy_1
2500BP_Enemy_2
note

Suppose the 'enemy references' are references to spawned actors in the level. This is the data we need to actually target the enemy.

We need to convert this into a discrete distribution, but we can't use the distance values as weights directly because we want closer enemies to be more likely. Instead, we can subtract the weights from the maximum radius of the spell:

Array B (Target Weights)
IndexWeight
0500
1200
2100

Each enemy's weight was set at 600 (maximum range of the spell) - distance to that enemy. We can construct a distribution out of this array:

Distribution C (Unlimited)
IndexWeightProbability
050062.5%
120025%
210012.5%
tip

You could use a discrete distribution, Sum Array, Sum Tree, or Alias Table. The structs will be much faster on performance (albeit less user-friendly).

Finally, we still have an array of actor references which we want to associate to this distribution:

Array D (Actor References)
IndexActor Reference
0BP_Enemy_0
1BP_Enemy_1
2BP_Enemy_2

By 'associate', we mean each item in the distribution has a corresponding item in the array. You could also view the distribution/array as columns in a table, with each index being a row. As such, it's important to ensure the distribution and array are the same size.

When we sample from the distribution, we'll receive the index of the enemy we picked. Then we can select that enemy's reference from the array.

info

When using this method, we have to ensure the size of the distribution matches the size of the data we're associating (in this case, enemy references). Otherwise the sampled indices may be invalid.