I'm trying to simulate shadows for a 2d topdown RPG, but I can't think of the best way to do this

so far I've tried making copies of the original game entities and turning all opaque pixels black (which is a bit slow), then rotating them around the bottom of the original image, But i couldn't quite get that approach to work

So what is the best way to simulate this affect?

Here is the class I use to make the shadow objects and to rotate them:

Code: Select all
`class Shadow():    def __init__(self, game, surface, pos):        self.game = game        self.sun = [0, 650]        self.center = self.game.center_point        self.image = self.renderShadow(surface)        self.og_image = self.image        self.rect = self.image.get_rect(topleft=pos)        self.og_rect = self.rect.copy()    def renderShadow(self, surface):        #Makes the shadow shape out of a surface (slow)        surface = surface.copy()        alphas = pygame.surfarray.pixels_alpha(surface)        pixels = pygame.PixelArray(surface)        for x in xrange(surface.get_width()):            for y in xrange(surface.get_height()):                if alphas[x, y] != 0:                    pixels[x, y] = (0,0,0,50)        sub = pixels.make_surface()        return sub    def rotate(self):        #gets angle from suns pos to centerpoint then makes the shadow rotate by that much (doesnt really work)        self.rect = self.og_rect        self.image = self.og_image        angle = degrees(atan2(self.center[0]-self.sun[0], self.center[1]-self.sun[1]))        angle = 180 + angle        self.image = rotate(self.image, angle)    def moveSun(self, mouse):        self.sun[0] = mouse [0] #the "sun's" x-axis is assigned to the mouse so I can simulate sun movement    def Draw(self, screen):        screen.blit(self.image, (self.game.off(self.rect)))    def update(self, screen):        #ran in loop to update shadows        self.moveSun(pygame.mouse.get_pos())        self.rotate()        self.Draw(screen)`

here is the repo with all the code:
ChristianCareaga

Posts: 54
Joined: Sat Jun 22, 2013 9:54 am

I'll probably clean this up a bit, but here is a pretty simple implementation. I cut the sprite into horizontal strips, setting pixels that are not transparent. Then when drawing I find the slope between the sun and player and offset the x axis accordingly.

Drag the sun around with the mouse to see the shadow move:
http://pastebin.com/4jY6tpgY

-Mek
• Use code tags when posting code.
• Include any errors with your post (in code tags).
• Make examples the minimum length to demonstrate your issue.

Mekire

Posts: 1711
Joined: Thu Feb 07, 2013 11:33 pm
Location: Tucson, Arizona

PERFECT! how do you do it Mek! haha

Thanks so much, I got it implemented really easy! and it looks good!
Last edited by Mekire on Sun Mar 23, 2014 11:02 am, edited 1 time in total.
Reason: Quote removed.
ChristianCareaga

Posts: 54
Joined: Sat Jun 22, 2013 9:54 am

Awesome! Great example
justinmeister

Posts: 9
Joined: Fri Jan 31, 2014 5:01 am

Threw up a repo for this. Also fixed a math error I didn't notice before.
Includes the previous example with the draggable sun and also a more complex example with a sprite that has different animations in each direction.

-Mek
• Use code tags when posting code.
• Include any errors with your post (in code tags).
• Make examples the minimum length to demonstrate your issue.

Mekire

Posts: 1711
Joined: Thu Feb 07, 2013 11:33 pm
Location: Tucson, Arizona

how can I change the alpha of the strips without remaking the whole thing?
ChristianCareaga

Posts: 54
Joined: Sat Jun 22, 2013 9:54 am

In this function:
Code: Select all
`def make_shadow_elements(self, image):    """Split the image into horizontal strips."""    colorkey = image.get_colorkey()    transparent = colorkey if colorkey else (0,0,0,0)    shadow_strips = []    for j in range(self.sprite.rect.height):        strip = pg.Surface((self.sprite.rect.width,1)).convert_alpha()        strip.fill((0,0,0,0))        for i in range(self.sprite.rect.width):            pixel = image.get_at((i,j))            if pixel != transparent:                alpha = min(j*5, 255)                strip.set_at((i,0), (10,0,10,alpha))        shadow_strips.append(strip)    return shadow_strips[::-1]`

It's right here:
Code: Select all
`alpha = min(j*5, 255)strip.set_at((i,0), (10,0,10,alpha))`

I just made it step by 5 until it is completely solid, but it is easily changed.

-Mek
• Use code tags when posting code.
• Include any errors with your post (in code tags).
• Make examples the minimum length to demonstrate your issue.

Mekire

Posts: 1711
Joined: Thu Feb 07, 2013 11:33 pm
Location: Tucson, Arizona

I mean't like change the alpha of the whole shadow on the go. I figured it out, I had to use convert() instead of convert_alpha() and then I blitted it with a color key after making the transparent pixels white and the visible ones black. Thanks Mek!
ChristianCareaga

Posts: 54
Joined: Sat Jun 22, 2013 9:54 am

ChristianCareaga wrote:I figured it out. Thanks Mek!

If you mind, you can actually post your new code, so others can review it in the future, who maybe have a same question.
Due to the reasons discussed here we are moving to python-forum.net on October 1, 2016.

This forum will be closed. Please create an account at the new site to continue discussion.

IRC://irc.freenode.net/python-forum
Kebap

Posts: 689
Joined: Thu Apr 04, 2013 1:17 pm
Location: Germany, Europe