how to blit a moving thing outside camera view

16 views
Skip to first unread message

Paolo

unread,
Apr 22, 2014, 4:50:48 AM4/22/14
to gummw...@googlegroups.com
I am trying to add a self-moving thing using your tmw demo draw_details method.
It works, but only until the moving thing is blitted inside the window viewed, if the coordinates are outside this window the moving thing becomes invisible and never turns back visible, even if you follow it with the camera (for example: using avatar as follower and walking side by side with the moving thing).
Here is the code I use to blit the moving image, look at the last line "blit(s.image, s.rect.move(-cx,-cy))"

 def draw_detail(self):
            camera = State.camera
            camera_rect = camera.rect
            cx,cy = camera_rect.topleft
            blit = camera.surface.blit
            avatar = self.avatar
            #beast=self.beast
            # Draw static overlay tiles.
            for layer in self.overlays:
                sprites = layer.objects.intersect_objects(camera_rect)
                if layer.visible:
                    if layer is self.avatar_group:
                        sprites.sort(key=lambda o:o.rect.bottom)
                    for s in sprites:
                        if s is avatar:
                            blit(s.image, s.rect.move(camera.anti_interp(s)))
                        else:
                            blit(s.image, s.rect.move(-cx,-cy))

B W

unread,
Apr 22, 2014, 3:49:37 PM4/22/14
to Gummworld2
Hi,

What does this tell you?

if s is beast: # or whatever
    print(camera.rect)
    print(s.rect)
    print(camera.rect.colliderect(s.rect))

Gumm


--
You received this message because you are subscribed to the Google Groups "Gummworld2" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gummworld2+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Paolo

unread,
Apr 23, 2014, 4:34:09 AM4/23/14
to gummw...@googlegroups.com
>What does this tell you?

>if s is beast: # or whatever
>    print(camera.rect)
>    print(s.rect)
>    print(camera.rect.colliderect(
>s.rect))

When the thing is still visible this is what is printed:
<rect(1840, 3924, 800, 600)>
<rect(1856, 4480, 32, 32)>
1

 When the thing disappears this is printed:
<rect(2130, 3924, 800, 600)>
<rect(2272, 4256, 32, 32)>
1

B W

unread,
Apr 23, 2014, 12:54:13 PM4/23/14
to Gummworld2
It tells me the image is visible and would be rendered. This makes it likely that another image is being rendered over top of it. You can detect this by looping over the visible sprites and testing their rects versus the "thing". I expect you will need to sort the layer before rendering:

sort(key=lambda s: s.rect.bottom)

This is the standard trick in a 2.5D app for layers that need to simulate the Z-axis.

This could have a rare corner case where rect.bottom is equal and the two sprites would be arbitrarily ordered. Not sure what to do about this, I have never witnessed it happening. This might be because we always add the sprite last to the layer, and the sort algorithm preserves the inherent order in equal cases (I have to guess, I don't have info on the sort algorithm).


--

Paolo

unread,
Apr 24, 2014, 3:52:08 AM4/24/14
to gummw...@googlegroups.com
Hello again,
I found the solution, I have to add moving things to avatar_group every time camera moves:

 def update_camera_position(self):
            """update the camera's position if any movement keys are held down
            """
            if self.mio_move_to is not None:
                camera = State.camera
                wx,wy = camera.position
                avatar = self.avatar
                # Keep avatar inside map bounds.
                rect = State.world.rect
                wx = max(min(wx,rect.right), rect.left)
                wy = max(min(wy,rect.bottom), rect.top)
                camera.position = wx,wy
                #re-add the moving avatar
                self.avatar_group.add(avatar)
                #(new code to manage moving things other then avatar: re-add all others moving things)
                for beast in self.lista_beast:
                    self.avatar_group.add(beast)


I can not understand the reason why you have to re-add the avatar (and other moving things) to avatar_group if the camera is moving.
Can you give me some short explanation of what is happening when you move the camera to the avatar_group?
 

B W

unread,
Apr 25, 2014, 7:20:31 PM4/25/14
to Gummworld2
Hi,

A layer stores sprites in a spatialhash. A spatialhash uses buckets for its storage. If you modify the coordinates of a sprite then it may need to go in a different bucket. This update is done via the spatialhash's add() method.

If you don't re-add() the sprite after moving it, then when you get the objects within the camera rect the sprite is in a bucket outside the view.


This is one of the penalties of using a spatialhash. It is very efficient in processing collisions (with each other, with a rect, etc.) but it takes a little extra interaction.


--

Paolo

unread,
Apr 26, 2014, 5:43:41 AM4/26/14
to gummw...@googlegroups.com
Thank you,
and what about the memory? Is it released free when the moving object becomes invisible because is in thew wrong bucket?
I mean, adding another time the same object in the right bucket is increasing the memory usage or not? 

bw

unread,
Apr 26, 2014, 12:57:37 PM4/26/14
to gummw...@googlegroups.com
If you view the source for SpatialHash.add you'll see the sprite is removed before it is added.

Gumm

Paolo

unread,
Apr 28, 2014, 2:48:12 AM4/28/14
to gummw...@googlegroups.com
I found another problem: the re-adding and the becoming visible again works if the avatar and camera are moving. If the moving thing is moving from outside the camera  window toward the avatar which is hanging, the moving thing is still invisible until a a key to move avatar is pressed (in other words, to make the moving thing visible you have always to move avatar, a single step is enough).
Any suggestion? I think that re-adding for every single frame the moving thing to avatar-group should work, but I don't know if it is the more appropriate way to do the fix.

bw

unread,
Apr 28, 2014, 3:05:17 AM4/28/14
to gummw...@googlegroups.com
It sounds like you're using the BasicMapRenderer. When you move a thing in the layer you need to tell the renderer where the dirty areas are, e.g.:

renderer.set_dirty(thing.rect)  # redraw the old spot to be vacated
thing.position += step
renderer.set_dirty(thing.rect)  # redraw the new spot occupied

This tells the renderer to scrap the cached tiles that are affected, and render new ones.

If you're moving a number of things it is most efficient to save up their rects and then pass them all at once.

del dirty_rects[:]
dirty_rects.append(thing.rect.copy())
thing.position += step
dirty_rects.append(thing.rect.copy())
renderer.set_dirty(*self.dirty)  # <-- note the * unpacking

Gumm


On 4/27/2014 23:48, Paolo wrote:
I found another problem: the re-adding and the becoming visible again works if the avatar and camera are moving. If the moving thing is moving from outside the camera  window toward the avatar which is hanging, the moving thing is still invisible until a a key to move avatar is pressed (in other words, to make the moving thing visible you have always to move avatar, a single step is enough).
Any suggestion? I think that re-adding for every single frame the moving thing to avatar-group should work, but I don't know if it is the more appropriate way to do the fix.
Reply all
Reply to author
Forward
0 new messages