# How do I implement unit selection in this program?

I'm trying to implement unit selection on a large, scrollable surface.

# Arbitrary values for window size
self.w, self.h = 1600, 900

# Game world surface, everything gets blitted to this, which is then drawn to the screen:
self.mapSurf = pygame.Surface((3600, 3600))


The general process looks like this:

# draw the floor first
for e in self.map_layout.fixed_list:
if e.type == 1:
self.mapSurf.blit(self.map_sprite_list['floor_red'], e.rect)
# then draw the walls
for e in self.map_layout.fixed_list:
if e.type == 2:
self.mapSurf.blit(self.map_sprite_list['wall'], e.rect)
# add agents (units) to the mapSurf
for a in self.agent_list:
self.mapSurf.blit(self.map_sprite_list['proto_unit'], a.pos)
# draw everything to screen
self.screen.blit(self.mapSurf, self.mapSurfRect)


I have a method for getting the coordinates of a click on the screen. And tried to use this to select units.

def mouseUp(self, button, pos):

# select agent
if button==1:
for a in self.agent_list:
if a.pos.get_distance(vec2d(pos)) < 24:
self.selected.append(a)


The problem is that the value pos does not correspond to the mapSurf, but rather to the self.screen surface, so when comparing a.pos to the pygame event.pos returned from mouseUp, this function can only return coordinates within the window size, and I can't select agents which are spawned outside of the top left area of mapSurf.

What would be the general method of selecting units I need to implement to fix this program?

For some more details, here are three relevant links, all of which describe different aspects of how my program was built:

Trying to make a python map editor

Collision detection performance problem

Pygame performance issue for many images

• I don't think your rendering approach is efficient or scalable. Consider only drawing the displayed area, rather than rendering to a larger area and copying a rectangle. It'll be more efficient (especially in memory) and give opportunity for bigger worlds and more objects (with suitable optimisations) in the future. – MarkR Jan 15 '13 at 14:25
• @MarkR I have considered that, but don't yet know how to go about implementing it. Would you care to elaborate on how it might be done, and post an answer here: gamedev.stackexchange.com/questions/47225/… – Anonymous Entity Jan 15 '13 at 14:31

If I'm understanding your question correctly, you want to select agents within the map, but outside of the current view/camera.

The approach is to convert your mouse/screen coordinates into world coordinates, by using your view position to offset the mouse.

Short example:

def ViewToWorld(view, mouseX, mouseY):
finalPos.x = view.LeftX + mouseX
finalPos.y = view.TopY  + mouseY

return finalPos


You will need to update the view reference coordinates every time the view is moved around. I use top-left corner in the example above as the reference.

One of your links above contains a question about optimizing drawing sprites. At one point or another, most games have a Game View structure that contains functionality to convert coordinates to and from Screen/World, and it is also used to skip drawing things that are outside of the view, as a first step in optimization.

• This might work, but is there a more direct way to solve it? What you posted feels like a work-around to some more serious design flaw in my program, and I would rather fix the fundamental problem if I knew what it was. – Anonymous Entity Jan 14 '13 at 21:34
• It's not a design flaw, and there is no fundamental problem. You're essentially doing a coordinate system conversion, which happens very frequently. Only change I would make to the code you've posted above is to change the mapSurf so that it's width and height equal the size of the window, and from there figure out what objects need to be displayed and draw those using -- this time the other way -- World to Screen coordinate conversion. – Jovan Jan 14 '13 at 21:40

Using the advice from Jovan, I was able to solve my problem with this code:

vec2d(pos) + (vec2d(self.mapSurfRect.topleft) - ((self.mod_w * 2), (self.mod_h * 2)))


Where mod_w and mod_h are variables which get increased or decreased according to camera movement.