Thursday, April 5, 2018

Ex10. Label sprites

A sprite has to have an image (self.image) and rect (self.rect). If the label was not static we will have to define an update method where the two properties might change.


We have a sprite group, labels, containing both labels.


Whenever we want to draw a new frame, we will just have to call labels.draw(screen)



# Ex10.py 
# Label Class as sprites

import pygame as pg

FILL_COLOR = pg.Color("cyan")

class Label(pg.sprite.Sprite):
    def __init__(self,text,x,y,back_color,text_color):
        pg.sprite.Sprite.__init__(self)
        self.text = text
        self.font = pg.font.SysFont("arial",24)
        self.back_color = pg.Color(back_color)
        self.text_color = pg.Color(text_color)
        self.pad = 2
        self.image = self.get_surf()
        self.rect = self.image.get_rect()
        self.rect.topleft = (x,y)
 
    def get_surf(self):
        pad_text = ' ' * self.pad
        text_string = pad_text + self.text + pad_text
        text_image = self.font.render(text_string, True,
                                      self.text_color)
        rect = text_image.get_rect()
        rect.height = 2 * round(rect.height/2)
        rect.width = rect.width + 2 * rect.height
        surf = pg.Surface((rect.width+2*rect.height, rect.height))
        surf.fill(FILL_COLOR)
        rect_text = rect.move(rect.height,0)
        pg.draw.rect(surf,self.back_color,rect_text)
        surf.blit(text_image,rect_text)
        left_circ_cen = (rect.height//2,rect.centery)
        pg.draw.circle(surf,self.back_color,
                       left_circ_cen,rect.height//2)
        right_circ_cen = (rect.width+rect.height+rect.height//2,
                          rect.centery)
        pg.draw.circle(surf,self.back_color,right_circ_cen,
                       rect.height//2)
        left_rect = pg.Rect(rect.height//2, 0, rect.height//2,
                            rect.height)
        pg.draw.rect(surf,self.back_color,left_rect)
        right_rect = pg.Rect(rect.width+rect.height, 0,
                             rect.height//2, rect.height)
        pg.draw.rect(surf,self.back_color,right_rect)
        return surf

width, height = 640, 480

pg.init()

screen = pg.display.set_mode((width, height))
pg.display.set_caption('Ex10. Label Sprite Class')
clock = pg.time.Clock()
FPS = 30

w = width // 4
labels = pg.sprite.Group()
label1 = Label("I am label 1", w,  height//2, "red", "blue")
label2 = Label("And I am label 2", w, height//2+100, "blue", "red")
labels.add(label1)
labels.add(label2)

screen.fill(FILL_COLOR)

labels.draw(screen)

pg.display.update()

done = False
while not done:
    clock.tick(FPS)
    for event in pg.event.get():
        if event.type == pg.QUIT:
         done = True

pg.quit()

The output is same as in the previous example.


Ex09. Label

Here we create a simple label class.


For the class, we have to have initialize code which takes the text to write, the screen coordinates in x and y, as well as the background and text color.


The easiest label would be just a rectangle, however here several shapes are joined together in get_surf function: left and right circle, left and right rectangle to cover portions of circle as well as main rectangle with text. Note we fix height of triangle to be a value divisible by 2, that is, we either add 1 to original height from pygame's get_rect should it be odd.



# Ex09.py 
# Label Class

import pygame as pg

FILL_COLOR = pg.Color("cyan")

class Label:
    def __init__(self,text,x,y,back_color,text_color):
        self.text = text
        self.x = x
        self.y = y
        self.font = pg.font.SysFont("arial",24)
        self.back_color = pg.Color(back_color)
        self.text_color = pg.Color(text_color)
        self.pad = 2
        self.surf = self.get_surf()

    def get_surf(self):
        pad_text = ' ' * self.pad
        text_string = pad_text + self.text + pad_text
        text_image = self.font.render(text_string, True,
                                      self.text_color)
        rect = text_image.get_rect()
        rect.height = 2 * round(rect.height/2)
        surf = pg.Surface((rect.width+2*rect.height,rect.height))
        surf.fill(FILL_COLOR)
        pg.draw.rect(surf,self.back_color,rect.move(rect.height,0))
        surf.blit(text_image,rect.move(rect.height,0))
        left_circ_cen = (rect.height//2,rect.centery)
        pg.draw.circle(surf,self.back_color,
                       left_circ_cen,rect.height//2)
        right_circ_cen = (rect.width+rect.height+rect.height//2,
                          rect.centery)
        pg.draw.circle(surf,self.back_color,right_circ_cen,
                       rect.height//2)
        left_rect = pg.Rect(rect.height//2, 0, rect.height//2,
                            rect.height)
        pg.draw.rect(surf,self.back_color,left_rect)
        right_rect = pg.Rect(rect.width+rect.height, 0,
                             rect.height//2, rect.height)
        pg.draw.rect(surf,self.back_color,right_rect)
        return surf

    def draw(self,screen):
        screen.blit(self.surf,(self.x,self.y))


width, height = 640, 480

pg.init()

screen = pg.display.set_mode((width, height))
pg.display.set_caption('Ex09. Label Class')
clock = pg.time.Clock()
FPS = 30

w = width // 4
label1 = Label("I am label 1", w,  height//2, "red", "blue")
label2 = Label("And I am label 2", w, height//2+100, "blue", "red")

screen.fill(FILL_COLOR)

label1.draw(screen)
label2.draw(screen)

pg.display.update()

done = False
while not done:
    clock.tick(FPS)
    for event in pg.event.get():
        if event.type == pg.QUIT:
         done = True

pg.quit()


This is the output:


Saturday, February 4, 2017

Ex08. Keyboard

Here we use a class Keyboard to hold the font, the text surface, rectangle, etc. It is possible we can use several functions instead. However then we will have to deal with a lot of global variables, and using the global keyword.


We create a Keboard object. It gets the letter typed via the getText method. A key press will generate a KEYDOWN event when it is pressed down. Most keys will have a unicode representation. Some might be empty string, if they do not. We can draw the text using its update() method.



# Ex08.py 
# Keyboard

import pygame as pg
width, height = 640, 480

class Keyboard():

 def __init__(self):
  self.font = pg.font.SysFont("arial",72)
  self.col = pg.Color('black')
  self.text = self.font.render(" ", True, self.col)
  self.rect = pg.Rect(0,0,100,100)

 def getText(self,char):
  self.text = self.font.render(" " + char, True, self.col)
  self.rect = self.text.get_rect()
  self.rect.center = (width/2,height/2)

 def update(self,surface):
  surface.blit(self.text,self.rect)


colors = ['red','green','blue','cyan',
    'purple','brown','magenta','orange','white']
cmap = list(map(pg.Color,colors))

pg.init()

screen = pg.display.set_mode((width, height))
pg.display.set_caption('Ex08. Keyboard')

keyboard = Keyboard()

done = False
while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
         done = True
        if event.type == pg.KEYDOWN:
         keyboard.getText(event.unicode)
    
    screen.fill(cmap[-1])
    keyboard.update(screen)
    pg.display.update()
            
pg.quit()

This is the output after pressing P:


Ex07. Text

To create text output, we need a font, and then we may create a text image by using its render method


We use the get_rect method to find the region on main display to blit it to. It is also possible to add more elements to the image prior to sending it to main display, as we will do in Button example later.



# Ex07.py 
# Text

import pygame as pg

colors = ['red','green','blue','cyan',
    'purple','brown','magenta','orange']
cmap = list(map(pg.Color,colors))

width, height = 640, 480

pg.init()

screen = pg.display.set_mode((width, height))
pg.display.set_caption('Ex07. Text')

screen.fill(pg.Color("white"))

# font
font = pg.font.SysFont("arial",56)

# create Text Surface, and get bounding rect
text = font.render("Hello pygame!", True, cmap[0])
rect = text.get_rect()

# center on screen
rect.center = (width/2,height/2)

screen.blit(text,rect)

pg.display.update()

done = False
while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
         done = True
            
pg.quit()

This is the output:


Ex06. 4 Arcs

Arcs are same as an ellipse with start angle of 0 and stop angle of 360.


Here we have 4 arcs based on the same ellipse (and its bounding rectangle), with different start and stop angles.



# Ex06.py 
# 4 Arcs

import pygame as pg
from math import radians as rad

colors = ['red','green','blue','cyan',
    'purple','brown','magenta','orange']
cmap = list(map(pg.Color,colors))


pg.init()

screen = pg.display.set_mode((640, 480))
pg.display.set_caption('Ex06. 4 Arcs')

rect = pg.Rect(50,50,540,380)

screen.fill(pg.Color("white"))

def get_rad(start,stop):
 return rad(start), rad(stop)

# arc angles
arc1_start, arc1_stop = get_rad(0,45)
arc2_start, arc2_stop = get_rad(60,180)
arc3_start, arc3_stop = get_rad(190,255)
arc4_start, arc4_stop = get_rad(260,355)

pg.draw.arc(screen,cmap[0],rect,arc1_start,arc1_stop,3)
pg.draw.arc(screen,cmap[1],rect,arc2_start,arc2_stop,3)
pg.draw.arc(screen,cmap[2],rect,arc3_start,arc3_stop,3)
pg.draw.arc(screen,cmap[3],rect,arc4_start,arc4_stop,3)

pg.display.update()

done = False
while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
         done = True
            
pg.quit()

This is the output:


Ex05. 4 Circles

We use the rectangles from Example 1. For the rectangle we need a center point obtained by rect1.center, etc.


We also need a radius which we have set to 100.



# Ex05.py 
# 4 Circles

import pygame as pg

white = pg.Color('white')
blue = pg.Color('blue')
red = pg.Color('red')
green = pg.Color('green')
purple = pg.Color('purple')

pg.init()

screen = pg.display.set_mode((640, 480))
pg.display.set_caption('Ex05. 4 Circles')

w,h = 250,200 # dimensions of each rectangle
# top row - blue, red
# bottom row - green, purple

padx,pady = 20,10
radius = 100

rect = pg.Rect(0,0,w,h)

rect1 = rect.copy()
rect1.bottomright=(320-padx,240-pady)

rect2 = rect.copy()
rect2.bottomleft=(320+padx,240-pady)

rect3 = rect.copy()
rect3.topright=(320-padx,240+pady)

rect4 = rect.copy()
rect4.topleft=(320+padx,240+pady)


screen.fill(white)
pg.draw.circle(screen,blue,rect1.center,radius)
pg.draw.circle(screen,red,rect2.center,radius)
pg.draw.circle(screen,green,rect3.center,radius)
pg.draw.circle(screen,purple,rect4.center,radius)

pg.display.update()

done = False
while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
         done = True
            
pg.quit()

This is the output:


Ex04. 4 Ellipses

4 ellipses are drawn. We use the same bounding rectangles as in example 1.


Thus we change the draw.rectangle to draw.ellipse from that example.



# Ex04.py 
# 4 Ellipses

import pygame as pg

white = pg.Color('white')
blue = pg.Color('blue')
red = pg.Color('red')
green = pg.Color('green')
purple = pg.Color('purple')

pg.init()

screen = pg.display.set_mode((640, 480))
pg.display.set_caption('Ex01. 4 Ellipses')

w,h = 250,200 # dimensions of each rectangle
# top row - blue, red
# bottom row - green, purple

padx,pady = 20,10

rect = pg.Rect(0,0,w,h)

rect1 = rect.copy()
rect1.bottomright=(320-padx,240-pady)

rect2 = rect.copy()
rect2.bottomleft=(320+padx,240-pady)

rect3 = rect.copy()
rect3.topright=(320-padx,240+pady)

rect4 = rect.copy()
rect4.topleft=(320+padx,240+pady)


screen.fill(white)
pg.draw.ellipse(screen,blue,rect1)
pg.draw.ellipse(screen,red,rect2)
pg.draw.ellipse(screen,green,rect3)
pg.draw.ellipse(screen,purple,rect4)

pg.display.update()

done = False
while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
         done = True
            
pg.quit()

This is the output: