Python Forum

Full Version: Common Tasks
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
This thread is a series of posts that include an example that are commonly asked on the forum. It is more efficient to make a thread containing them all then write them up upon each request. The posts are in no particular order. These get appended with new examples every time i repeatedly post one for more than one person. You can often make a small change to accommodate what you are doing with these examples. There are even more and more detailed examples at Mekire repos.
Time: Do something every second
This example shows a random number every second
import pygame as pg
import random

pg.init()

screen = pg.display.set_mode((800,600))
screen_rect = screen.get_rect()
clock = pg.time.Clock()
done = False

class Number:
    def __init__(self):
        self.timer = 0.0
        self.delay = 1000
        self.new_num()

    def new_num(self):
        num = random.randint(1,100)
        self.image, self.rect = self.make_text(str(num), (255,0,0), screen_rect.center, 75, 'Ariel')

    def make_text(self,message,color,center,size, fonttype):
        font = pg.font.SysFont(fonttype, size)
        text = font.render(message,True,color)
        rect = text.get_rect(center=center)
        return text,rect

    def update(self):
        if pg.time.get_ticks()-self.timer > self.delay:
            self.timer = pg.time.get_ticks()
            self.new_num()

    def draw(self, surf):
        surf.blit(self.image, self.rect)

num = Number()

while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            done = True
    screen.fill((0,0,0))
    num.update()
    num.draw(screen)
    pg.display.update()
    clock.tick(60)
Delta Time Movement
import sys
import math
import pygame as pg
 
 
class Block(pg.sprite.Sprite):
    def __init__(self, pos, speed):
        self.image = pg.Surface((50,50)).convert()
        self.image.fill(pg.Color("red"))
        self.rect = self.image.get_rect(center=pos)
        self.exact_position = list(self.rect.center)
        self.speed = speed #Pixels per second
        self.target = None
        self.vec = None
        self.distance = None
 
    def update(self, dt):
        if self.target:
            travelled = math.hypot(self.vec[0]*dt, self.vec[1]*dt)
            self.distance -= travelled
            if self.distance <= 0:
                self.rect.center = self.exact_position = self.target
                self.target = None
            else:
                self.exact_position[0] += self.vec[0]*dt
                self.exact_position[1] += self.vec[1]*dt
                self.rect.center = self.exact_position
 
    def draw(self, surface):
        surface.blit(self.image, self.rect)
 
    def get_new_instruction(self, target):
        x = target[0]-self.exact_position[0]
        y = target[1]-self.exact_position[1]
        self.distance = math.hypot(x, y)
        try:
            self.vec = self.speed*x/self.distance, self.speed*y/self.distance
            self.target = list(target)
        except ZeroDivisionError:
            pass
       
 
class Control(object):
    def __init__(self):
        pg.init()
        pg.display.set_caption("Move To Target")
        self.screen = pg.display.set_mode((500,500))
        self.screen_rect = self.screen.get_rect()
        self.clock = pg.time.Clock()
        self.fps = 60.0
        self.done = False
        self.player = Block(self.screen_rect.center, 500)
 
    def event_loop(self):
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.done = True
            elif event.type == pg.MOUSEBUTTONDOWN:
                if event.button == 1:
                    self.player.get_new_instruction(event.pos)
 
    def update(self, dt):
        self.player.update(dt)
 
    def draw(self):
        self.screen.fill((30,40,50))
        self.player.draw(self.screen)
 
    def main_loop(self):
        while not self.done:
            dt = self.clock.tick(self.fps)/1000.0
            self.event_loop()
            self.update(dt)
            self.draw()
            pg.display.update()
 
 
def main():
    app = Control()
    app.main_loop()
    pg.quit()
    sys.exit()
 
 
if __name__ == "__main__":
    main()
Simple Pong
This example has a single ball and paddle. It shows how to handle ball bouncing as well as the paddle movement.
import pygame as pg
import random

screen = pg.display.set_mode((800,600))
screen_rect = screen.get_rect()
clock = pg.time.Clock()
done = False

class Ball:
    def __init__(self, screen_rect, size):
        self.screen_rect = screen_rect
        self.height, self.width = size
        self.image = pg.Surface(size).convert()
        self.image.fill((255,0,0))
        self.rect = self.image.get_rect()
        self.speed = 5
        self.set_ball()

    def get_random_float(self):
        '''get float for velocity of ball on starting direction'''
        while True:
            num = random.uniform(-1.0, 1.0)
            if num > -.5 and num < .5: #restrict ball direction to avoid infinity bounce
                continue
            else:
                return num
                
    def set_ball(self):
        '''get random starting direction and set ball to center screen'''
        x = self.get_random_float()
        y = self.get_random_float()
        self.vel = [x, y]
        self.rect.center = self.screen_rect.center
        self.true_pos = list(self.rect.center)
        
    def collide_walls(self):
        if self.rect.y < 0 or self.rect.y > self.screen_rect.bottom - self.height:
            self.vel[1] *= -1;
            
        if self.rect.x < 0 or self.rect.x > self.screen_rect.right- self.height:
            self.vel[0] *= -1;
            print('side wall hit, time to reset ball and give points')
            
    def collide_paddle(self, paddle_rect):
        if self.rect.colliderect(paddle_rect):
            self.vel[0] *= -1;
            
    def move(self):
        self.true_pos[0] += self.vel[0] * self.speed
        self.true_pos[1] += self.vel[1] * self.speed
        self.rect.center = self.true_pos
            
    def update(self, paddle_rect):
        self.collide_walls()
        self.collide_paddle(paddle_rect)
        self.move()

    def render(self, screen):
        screen.blit(self.image, self.rect)
        
class Paddle:
    def __init__(self, screen_rect, size):
        self.screen_rect = screen_rect
        self.image = pg.Surface(size).convert()
        self.image.fill((255,255,0))
        self.rect = self.image.get_rect()
        self.rect.x += 25 #spacer from wall
        self.speed = 5
        
    def move(self, x, y):
        self.rect[0] += x * self.speed
        self.rect[1] += y * self.speed
        
    def update(self, keys):
        self.rect.clamp_ip(self.screen_rect)
        if keys[pg.K_UP] or keys[pg.K_w]:
            self.move(0, -1)
        if keys[pg.K_DOWN] or keys[pg.K_s]:
            self.move(0, 1)
        
    def render(self, screen):
        screen.blit(self.image, self.rect)

paddle = Paddle(screen_rect, (25,100))
ball = Ball(screen_rect, (25,25))

while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            done = True
    keys = pg.key.get_pressed()
    screen.fill((0,0,0))
    paddle.update(keys)
    ball.update(paddle.rect)
    paddle.render(screen)
    ball.render(screen)
    clock.tick(60)
    pg.display.update()
Rotate Object
This example shows a constant rotating object. This shows how to rotate an object as well as how to not obscure it by using a master image to rotate instead of the previous rotated image to rotate. This is a big deal because an image rotated can get distorrted if not done this way.
import pygame as pg

screen = pg.display.set_mode((800,600))
screen_rect = screen.get_rect()
clock = pg.time.Clock()
done = False

class Rotator:
    def __init__(self, screen_rect):
        self.screen_rect = screen_rect
        self.master_image = pg.Surface([100,100]).convert_alpha()
        self.master_image.fill((255,0,0))
        self.image = self.master_image.copy()
        self.rect = self.image.get_rect(center=self.screen_rect.center)
        self.delay = 10
        self.timer = 0.0
        self.angle = 0

    def new_angle(self):
        self.angle += 1
        self.angle %= 360

    def rotate(self):
        self.new_angle()
        self.image = pg.transform.rotate(self.master_image, self.angle)
        self.rect = self.image.get_rect(center=self.screen_rect.center)

    def update(self):
        if pg.time.get_ticks()- self.timer > self.delay:
            self.timer = pg.time.get_ticks()
            self.rotate()

    def draw(self, surf):
        surf.blit(self.image, self.rect)

rotator = Rotator(screen_rect)

while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            done = True
    screen.fill((0,0,0))
    rotator.update()
    rotator.draw(screen)
    pg.display.update()
more information on this thread regarding rotating.
Shrink and Expand Image
https://python-forum.io/attachment.php?aid=271
[attachment=768]
An example of shrinking and expanding an image based on mouse position on the screen
import pygame as pg

class Player:
    def __init__(self, screen_rect):
        self.screen_rect = screen_rect
        self.image_orig = pg.image.load("default.png")
        self.image = self.image_orig.copy()
        self.rect = self.image.get_rect(center=screen_rect.center)

    def update(self):
        x,y = pg.mouse.get_pos()
        self.image = pg.transform.scale(self.image_orig, (x,y))
        self.rect = self.image.get_rect(center=self.screen_rect.center)

    def draw(self, surf):
        surf.blit(self.image, self.rect)

screen = pg.display.set_mode((800,600))
screen_rect = screen.get_rect()
done = False
player = Player(screen_rect)
while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            done = True
    screen.fill((0,0,0))
    player.update()
    player.draw(screen)
    pg.display.update()
Credit Screen
This is a basic credit screen like the end of a movie that scrolls text by vertically
import pygame as pg

pg.init()

text_list = '''I'm Henry the eighth, I am
Henry the eighth, I am, I am
I got married to the widow next door
She's been married seven times before
And every one was an Henry (Henry)
She wouldn't have a Willy or a Sam (No Sam)
I'm her eighth old man, I'm Henry
Henry the eighth I am
Second verse, same as the first
I'm Henry the eighth, I am
Henry the eighth, I am, I am
I got married to the widow next door
She's been married seven times before
And every one was an Henry (Henry)
She wouldn't have a Willy or a Sam (No Sam)
I'm her eighth old man, I'm Henry
Henry the eighth I am
I'm Henry the eighth, I am
Henry the eighth, I am, I am
I got married to the widow next door
She's been married seven times before
And every one was an Henry (Henry)
She wouldn't have a Willy or a Sam (No Sam)
I'm her eighth old man, I'm Henry
Henry the eighth I am
H-E-N-R-Y
Henry (Henry)
Henry (Henry)
Henry the eighth I am, I am
Henry the eighth I am
Yeah!
'''.split('\n')

class Credits:
    def __init__(self, screen_rect, lst):
        self.srect = screen_rect
        self.lst = lst
        self.size = 16
        self.color = (255,0,0)
        self.buff_centery = self.srect.height/2 + 5
        self.buff_lines = 50
        self.timer = 0.0
        self.delay = 50
        self.make_surfaces()


    def make_text(self,message):
        font = pg.font.SysFont('Arial', self.size)
        text = font.render(message,True,self.color)
        rect = text.get_rect(center = (self.srect.centerx, self.srect.centery + self.buff_centery) )
        return text,rect

    def make_surfaces(self):
        self.text = [ ]
        for i, line in enumerate(self.lst):
            l = self.make_text(line)
            l[1].y += i*self.buff_lines
            self.text.append(l)

    def update(self):
        if pg.time.get_ticks()-self.timer > self.delay:
            self.timer = pg.time.get_ticks()
            for text, rect in self.text:
                rect.y -= 1

    def render(self, surf):
        for text, rect in self.text:
            surf.blit(text, rect)

screen = pg.display.set_mode((800,600))
screen_rect = screen.get_rect()
clock = pg.time.Clock()
done = False
cred = Credits(screen_rect, text_list)

while not done:
    for event in pg.event.get(): 
        if event.type == pg.QUIT:
            done = True
    screen.fill((0,0,0))
    cred.update()
    cred.render(screen)
    pg.display.update()
    clock.tick(60)
Character Jump
This example is a rectangle that jumps and moves around the screen with WASD and SPACEBAR. You can easily attach a spritesheet to animate to the position of the rectangle and draw it over that position.
import pygame as pg

class Player:
    def __init__(self, screen_rect):
        self.screen_rect = screen_rect
        self.width = 50
        self.height = 75
        self.image = pg.Surface([self.width, self.height])
        self.image.fill((255,255,255))
        starting_loc = (0, screen_rect.height)
        self.rect = self.image.get_rect(bottomleft=starting_loc)
        self.speed = 5
        self.grav = .5

        self.jumping = False
        self.y_vel = 0
        
    def update(self):
        self.rect.clamp_ip(self.screen_rect)
        self.jump_update()
        
    def render(self, screen):
        screen.blit(self.image, self.rect)
        
    def move(self, x, y):
        self.rect.x += x * self.speed
        self.rect.y += y * self.speed
                
    def jump_update(self):
        if self.jumping:
            self.y_vel += self.grav
            self.rect.y += self.y_vel
            if self.is_touching_ground():
                self.jumping = False
                
    def is_touching_ground(self):
        return self.rect.y >= self.screen_rect.height - self.height
            
        
    def jump(self):
        if not self.jumping:
            self.y_vel = -12
            self.jumping = True
            
        

class Control:
    def __init__(self):
        self.screensize = (600,400)
        self.screen = pg.display.set_mode(self.screensize)
        self.screen_rect = self.screen.get_rect()
        self.clock = pg.time.Clock()
        self.fps = 60
        self.quit = False
        self.keys = pg.key.get_pressed()
        
        self.player = Player(self.screen_rect)
        
    def run(self):
        while not self.quit:
            now = pg.time.get_ticks()
            self.held_keys(self.keys)
            self.event_loop()
            self.update()
            self.render()
            pg.display.update()
            self.clock.tick(self.fps)
            
    def event_loop(self):
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.quit = True
            elif event.type in (pg.KEYDOWN, pg.KEYUP):
                self.keys = pg.key.get_pressed()
                if event.type == pg.KEYDOWN:
                    if event.key == pg.K_SPACE:
                        self.player.jump()
            
    def held_keys(self, keys):
        if keys[pg.K_a]:
            self.player.move(-1, 0)
        if keys[pg.K_d]:
            self.player.move(1, 0)
        
    def render(self):
        self.screen.fill((0,0,0))
        self.player.render(self.screen)
        
    def update(self):
        self.player.update()

app = Control()
app.run()
Basic Pause Feature
This example does not show anything on the screen. However it uses prints to show what is happening based on whether the game is paused or not. Use P to switch between states.
import pygame as pg

class Control:
    def __init__(self):
        self.screen_size = (600,400)
        self.screen = pg.display.set_mode(self.screen_size)
        self.done = False
        self.pause = False
        
    def run(self):
        while not self.done:
            self.get_events()
            if not self.pause:
                self.update()
                self.render()
                print('executing update functions and render functions')
            else:
                print('pause update and render')
            
    def get_events(self):
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.done = True
            elif event.type == pg.KEYDOWN:
                if event.key == pg.K_p:
                    self.pause = not self.pause
                
    def update(self):
        pass
        
    def render(self):
        self.screen.fill((0,0,0))
        pg.display.update()

app = Control()
app.run()
Rotate to Mouse Position
import pygame as pg
import math

class Rotator:
    def __init__(self, screen_rect):
        self.orig_image = pg.Surface([10,100]).convert_alpha() #
        self.image = self.orig_image
        self.image.fill((255,255,255))
        self.rect = self.image.get_rect(center=screen_rect.center)
        self.angle = 0
        self.distance = 0
        self.angle_offset = 0

    def render(self, screen):
        screen.blit(self.image, self.rect)
        
    def get_angle(self):
        mouse = pg.mouse.get_pos()
        offset = (self.rect.centerx-mouse[0],self.rect.centery-mouse[1])
        self.angle = math.degrees(math.atan2(*offset)) - self.angle_offset
        old_center = self.rect.center
        self.image = pg.transform.rotate(self.orig_image, self.angle)
        self.rect = self.image.get_rect(center=old_center)
        self.distance = math.sqrt((offset[0] * offset[0]) + (offset[1] * offset[1]))
        
    def update(self):
        self.get_angle()
        self.display = 'angle:{:.2f} disatance:{:.2f}'.format(self.angle, self.distance)

if __name__ == '__main__':
    running = True
    pg.init()
    screen = pg.display.set_mode((600,400))
    screen_rect = screen.get_rect()
    rotator = Rotator(screen_rect)
    clock = pg.time.Clock()

    while running:
        screen.fill((0,0,0))
        for event in pg.event.get():
            if event.type == pg.QUIT:
                running = False
        rotator.update()
        rotator.render(screen)
        pg.display.set_caption(rotator.display)
        pg.display.update()
        clock.tick(60)
Pages: 1 2