I just started with pyGame and I would like to create a frame that crops whatever I display on screen. i.e. independently of what my world contains, this frame should cover everything but what it contains.
Think about it as the frame used to crop images on the iphone (see picture below). Eventually I want to make the frame interactive, so that I can move it around or change its size, but for the time being a static frame would do. And I have no idea where to start from.. any help is appreciated!
[
There are multiple ways to do this; one way is to draw a black Surface
on the entire screen, but have a "hole" in that black Surface
.
An easy way to create that "hole" is to simply draw a rectangle with the right colorkey
. What is the colorkey
?
When blitting this Surface onto a destination, any pixels that have the same color as the colorkey will be transparent
Sounds useful, so let's give it a try:
import random
import pygame as pg
IMAGE = pg.Surface((50, 50), pg.SRCALPHA)
pg.draw.polygon(IMAGE, (240, 120, 0), [(0, 50), (25, 0), (50, 50)])
class Actor(pg.sprite.Sprite):
def __init__(self, grp, bounds, pos):
self._layer = 0
pg.sprite.Sprite.__init__(self, grp)
self.image = IMAGE
self.rect = self.image.get_rect(center=pos)
self.vec = pg.math.Vector2()
# just a random directon for movement
self.vec.from_polar((10, random.randrange(0, 360)))
self.bounds = bounds
def update(self):
self.rect.move_ip(*self.vec)
# try staying on screen
if not self.bounds.contains(self.rect):
self.vec.from_polar((10, random.randrange(0, 360)))
class Cursor(pg.sprite.Sprite):
def __init__(self, grp, bounds):
self._layer = 1000
pg.sprite.Sprite.__init__(self, grp)
self.image = pg.Surface((bounds.width, bounds.height))
self.image.set_colorkey(pg.Color('yellow'))
# we start with the entire screen black
# if the screen should be fully visible at the start, we could use yellow instead
self.image.fill(pg.Color('black'))
self.rect = self.image.get_rect()
# here we store the position of the mouse when we start drawing the hole
self.start = None
# here we store the entire rect of the hole so we can later move it around
self.inner_rect = None
def mousedown(self):
self.start = pg.mouse.get_pos()
def mouseup(self):
self.start = None
def move(self, rel):
self.inner_rect.move_ip(rel)
self.recreate()
def update(self):
if not self.start:
return
pos = pg.mouse.get_pos()
p = pos[0] - self.start[0], pos[1] - self.start[1]
self.inner_rect = pg.Rect(self.start, p)
self.recreate()
def recreate(self):
# here we update our hole
self.image.fill(pg.Color('black'))
pg.draw.rect(self.image, pg.Color('yellow'), self.inner_rect)
pg.draw.rect(self.image, pg.Color('white'), self.inner_rect, 2)
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.LayeredUpdates()
cursor = Cursor(all_sprites, screen.get_rect())
for _ in range(20):
Actor(all_sprites, screen.get_rect(), (random.randrange(600), random.randrange(440)))
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1:
cursor.mousedown()
if event.type == pg.MOUSEBUTTONUP:
if event.button == 1:
cursor.mouseup()
if event.type == pg.MOUSEMOTION:
if pg.mouse.get_pressed()[2]:
cursor.move(event.rel)
all_sprites.update()
screen.fill(pg.Color('darkblue'))
all_sprites.draw(screen)
pg.display.flip()
clock.tick(60)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
Use the left mouse button to start drawing your frame, and use the right mouse button to move it.
As you can see, we have a black Surface
with yellow as colorkey. When we want to make a part of the screen visible, we draw a yellow rectangle, which in turn will be transparent, making the scene underneath it visible.