0
votes

I'm looking for the easiest way to implement this. I'm trying to implement platforms (with full collision detection) that you can draw in via mouse. Right now I have a line drawing function that actually draws small circles, but they're so close together that they more or less look like a line. Would the best solution be to create little pygame.Rect objects at each circle? That's going to be a lot of rect objects. It's not an image so pixel perfect doesn't seem like an option?

def drawGradientLine(screen, index, start, end, width, color_mode):
    #color values change based on index
    cvar1 = max(0, min(255, 9 * index-256))
    cvar2 = max(0, min(255, 9 * index))
    #green(0,255,0), blue(0,0,255), red(255,0,0), yellow(255,255,0)
    if color_mode == 'green':
        color = (cvar1, cvar2, cvar1)
    elif color_mode == 'blue':
        color = (cvar1, cvar1, cvar2)
    elif color_mode == 'red':
        color = (cvar2, cvar1, cvar1)
    elif color_mode == 'yellow':
        color = (cvar2, cvar2, cvar1)
    dx = end[0] - start[0]
    dy = end[1] - start[1]
    dist = max(abs(dx), abs(dy))
    for i in xrange(dist):
        x = int(start[0]+float(i)/dist*dx)
        y = int(start[1]+float(i)/dist*dy)
        pygame.draw.circle(screen, color, (x, y), width)

That's my drawing function. And here's my loop that I have put in my main game event loop.

  i = 0
  while (i < len(pointList)-1):
      drawGradientLine(screen, i, pointList[i], pointList[i + 1], r, mode)
      i += 1   

Thanks for any help, collision detection is giving me a huge headache right now (still can't get it right for my tiles either..).

2

2 Answers

0
votes

Any reason you want to stick with circles?

Rectangles will make the line/rectangle a lot more smooth and will make collision detecting a lot easier unless you want to look into pixel perfect collision.

You also don't seem to save your drawn objects anywhere (like in a list or spritegroup), so how are you going to check for collision?


Here's a leveleditor I did for game awhile back, it's not perfect, but it works:

https://gist.github.com/marcusmoller/bae9ea310999db8d8d95

How it works:

  • The whole game level is divided up into 10x10px grid for easier drawing
  • The leveleditor check if the mouse is being clicked and then saves that mouse position
  • The player now moves the mouse to another position and releases the mouse button, the leveleditor now saves that new position.
  • You now have two different coordinates and can easily make a rectangle out of them.
0
votes

Instead of creating a whole bunch of rect objects to test collision against, I'm going to recommend creating something called a mask of the drawn-in collideable object, and test for collision against that. Basically, a mask is a map of which pixels are being used and which are not in an image. You can almost think of it as a shadow or silhouette of a surface.

When you call pygame.draw.circle, you are already passing in a surface. Right now you are drawing directly to the screen, which might not be as useful for what I'm suggesting. I would recommend creating a rect which covers the entire area of the line being drawn, and then creating a surface of that size, and then draw the line to this surface. My code will assume you already know the bounds of the line's points.

line_rect = pygame.Rect(leftmost, topmost, rightmost - leftmost, bottommost - topmost)
line_surf = pygame.Surface((line_rect.width, line_rect.height))

In your drawGradientLine function, you'll have to translate the point coordinates to the object space of the line_surf.

while (i < len(pointList)-1):
    drawGradientLine(line_surf, (line_rect.x, line_rect.y), i, pointList[i], pointList[i+1], r, mode)
    i += 1

def drawGradientLine(surf, offset, index, start, end, width, color_mode):
    # the code leading up to where you draw the circle...
    for i in xrange(dist):
        x = int(start[0]+float(i)/dist*dx) - offset[0]
        y = int(start[1]+float(i)/dist*dy) - offset[1]
        pygame.draw.circle(surf, color, (x, y), width)

Now you'll have a surface with the drawn object blitted to it. Note that you might have to add some padding to the surface when you create it if the width of the lines you are drawing is greater than 1.

Now that you have the surface, you will want to create the mask of it.

surf_mask = pygame.mask.from_surface(line_surf)

Hopefully this isn't getting too complicated for you! Now you can either check each "active" point in the mask for collision within a rect from your player (or whatever other objects you want to collide withe drawn-in platforms), or you can create a mask from the surface of such a player object and use the pygame.Mask.overlap_area function to check for pixel-perfect collision.

# player_surf is a surface object I am imagining exists
# player_rect is a rect object I am imagining exists
overlap_count = surf_mask.overlap_area(player_surf, (line_rect.x - player_rect.x, line_rect.y - player_rect.y))

overlap_count should be a count of the number of pixels that are overlapping between the masks. If this is greater than zero, then you know there has been a collision.

Here is the documentation for pygame.Mask.overlap_area: http://www.pygame.org/docs/ref/mask.html#pygame.mask.Mask.overlap_area