7DRL: Building an Engine — Line of Sight

NPCs don’t want to hit their allies while they are attacking you with ranged attacks. Some objects in the room can block them as well — and using the objects in the room to deal with larger swarms of enemies will be an important strategy in the actual game. Today we go over the line of sight algorithm.

As before, you can always test the latest state of the game engine by following this link to Trinket IO. I’d rather work with something that has the latest version of Pygame, or at least let me use a larger screen, but ya work with the tools ya have.

Playing with Line of Sight

I added some happy little trees to our test room. Based on the scale of the trees and the terrain, our adventurers are probably about 40 feet tall. Just saying.

In my last post, I wrote how each NPC has their own preferred positioning with respect to their target. Babus is the sprite closest to the bottom of the room and is currently representing the player. The templar is just northwest of them, and prefers to strike from melee range. The mog knight is partially hidden by a tree, and chooses to attack from the same row or column and currently cannot get into position to attack because of the tree and the templar. The archer is the Vierra to the right of the mog knight, and prefers an unobstructed view from 3-5 tiles away, and is also blocked by the trees.

Good job, Babus!

The line of sight algorithm is an addition to each Actor’s “good position” algorithm. Where the first implementation was just concerned with distance and position, we now draw an invisible line between the NPC and its target, and check every space it crosses to see if it’s on the list of “bad spaces” we make that contains blocking static items or NPCs that are in the way.

Here’s the Archer code:

    def good_pos(self, pos, player_pos, bad_spaces):
        dist = manhattan_distance(pos, player_pos)
        return self.line_of_sight(pos, player_pos, bad_spaces) and dist >= 3 and dist <= 5

I use a couple different distance algorithms, depending on how the NPC moves. The Archer seems to work best with the Manhattan distance, which is the sum of the absolute values of the differences between the X and Y coordinates of source and target.

This is another formula that came up a few times in Advent of Code.

I didn’t make any progress this weekend, as I was playing Horizon: Forbidden West. But next up is map making. Map making should be fun as I currently have no idea whatsoever how I want to approach it for this game engine. I’ve been wanting to try out the old D&D random dungeon generator because it seems like it would work well with what I’m trying to do here. It does guarantee all rooms will be connected, so that’s something.

Get something working, then refactor. I may iterate a few times on map creation. But I still have lighting to do, and items, and combat… SO MANY THINGS.