Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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

share|improve this question
1  
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/… –  user11177 Jan 15 '13 at 14:31

2 Answers 2

up vote 3 down vote accepted

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.

share|improve this answer
    
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. –  user11177 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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.