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?