So I’m creating a Tower Defense game and I want to have different ways for towers to prioritize their targets (I’m using Python but looking for a generic design answer):
class TargetPriority(enum.Enum): LOW_HEALTH = 1 HIGH_HEALTH = 2 FIRST = 3 LAST = 4 CLOSEST = 5 class Tower(Entity): def __init__(self, *args, **kwargs, target_priority=TargetPriority.FIRST): super().__init__(*args, **kwargs) self.target_priority = target_priority def find_target(self, all_monsters): sort_functions = { TargetPriority.LOW_HEALTH: lambda monster: monster.health, TargetPriority.HIGH_HEALTH: lambda monster: -monster.health, TargetPriority.FIRST: ???, TargetPriority.LAST: ???, TargetPriority.CLOSEST: self.distance_to, } func = sort_functions[self.target_priority] return next(sorted(all_monsters, key=func), None)
As you can see, I’m not sure how to get the “first” or “last” monster from the wave of monsters. The way my monsters work right now is by getting a Checkpoint
object and once they reach the checkpoint, they call it’s check_in()
method to get new instructions:
class Monster(Entity): def __init__(self, *args, **kwargs, health, checkpoint): super().__init__(*args, **kwargs) self.health = health self.checkpoint = checkpoint def update(self, dt): travel = self.velocity / 1000 * dt remaining_distance = self.distance_to(self.checkpoint) if travel.length < remaining_distance: self.position += travel else: self.checkpoint.check_in(self)
The Checkpoint.check_in(monster)
method can invoke any callback given to the checkpoint, usually it just changes the monster’s checkpoint to the next checkpoint, but it can also do something else like take a life away from the player and remove the monster (the last checkpoint always does this). I can change the way these checkpoints work (or how the monsters move in general) if required by an “optimal” solution though.
Here are few things I’ve considered:
- I can’t use the order of the monsters in the
all_monsters
list because some towers may slow some monsters down, thus changing their order - For the same reason I can’t use any other kind of indexing
- I can’t use the monsters’ position on the map because there’s no way of knowing which way the monster is going or where the checkpoints are
- I can’t use the monsters’ distance to checkpoints because the monsters can be at different checkpoints already
So far the only actual solution I could come up with was to store a total_distance_travelled
for each monster, so in update()
I would have:
self.position += travel self.total_distance_travelled += travel.length
But there are two reasons why I hesitate:
- It’s not 100% fail proof: although not currently possible, what if I will have something like towers that teleport monsters back to their previous checkpoint?
- I’m adding an instance attribute just for the sole reason of towers being able to sort these monsters
Am I worrying too much, or is there a better solution that I’m just missing?