Pygame Binding Menu items to functions (by clicking) - pygame

Modifying the Squirrel Eat Squirrel Pygame for a class project. Trying to add in a menu, with basic Start, Quit and Settings buttons. I have the buttons there, and they will light up as the mouse scrolls over them. However, I can't figure out how to call their respective functions when I click on them. I am trying to call them by this:
def runMenu(self):
mainloop = True
while mainloop:
self.__clock.tick(50)
for event in pygame.event.get():
if event.type == pygame.QUIT:
mainloop == False
if event.type == MOUSEBUTTONDOWN:
for item in self.__items:
#print(item)
if item.isMouseSelecting(pygame.mouse.get_pos()):
print(self.__functions)
self.__functions[item]() #HERE <----
I believe it is because I am using a dictionary in my if name == "main" (See below) therefore it's not actually the dictionary, but its referencing its location? If that makes sense. (i'm not very good at explaining it, so sorry)
if __name__ == "__main__":
screen = pygame.display.set_mode((640, 480), 0 , 32)
menuItems = ('Start', 'Quit', 'Settings')
functions = {'Start': main, 'Quit': terminate, 'Settings': None}
pygame.display.set_caption('Main Menu')
game = MainMenu(screen, functions, menuItems)
game.runMenu()
The error it gives me in shell:
>>> ================================ RESTART ================================
>>>
({'Start': <function main at 0x2969ab0>, 'Settings': None, 'Quit': <function terminate at 0x2969cf0>}, '#')
{'Start': <function main at 0x2969ab0>, 'Settings': None, 'Quit': <function terminate at 0x2969cf0>}
Traceback (most recent call last):
File "/Users/tjleggz/Documents/CS 110/squirrel/squirrel.py", line 501, in <module>
game.runMenu()
File "/Users/tjleggz/Documents/CS 110/squirrel/squirrel.py", line 138, in runMenu
self.__functions[item]() #cant call bc its not same object, just a ref to object or something???#
KeyError: <__main__.MenuItem object at 0x29758c8>
>>>
THANKS!
EDIT:
class MenuItem(pygame.font.Font):
def __init__(self, text, font=None, fontSize=30,
fontColor=(255, 255, 255), (posX, posY)=(0, 0)):
pygame.font.Font.__init__(self, font, fontSize) #initializes font module
self.__text = text
self.__fontSize = fontSize
self.__fontColor = fontColor
self.label = self.render(self.__text, 1, self.__fontColor) #not private??
self.width = self.label.get_rect().width
self.height = self.label.get_rect().height
self.__posX = posX
self.__posY = posY
self.position = posX, posY
def set_position(self, x, y):
self.position = (x, y)
self.__posX = x
self.__posY = y
def isMouseSelecting(self, (posX, posY)): #change to conditional?!
if (posX >= self.__posX and posX <= self.__posX + self.width) and \
(posY >= self.__posY and posY <= self.__posY + self.height):
return True
else:
return False
def setFontColor(self, rgbTuple):
self.fontColor = rgbTuple
self.label = self.render(self.__text, 1, self.fontColor)

Your self.items contains MenuItem objects, not strings which are the keys to your dictionary. You can work around this in a couple ways, for example you could use the __text attribute of MenuItem which is I think what you are looking for.
A better way to do this (instead of using a dictionary of functions like you are now) might be to pass an on_click function to each MenuItem instance you make, and then you just have to write
if item.isMouseSelecting(pygame.mouse.get_pos()):
item.on_click()
however you seem to be relatively new to programming, so you may just want to use the first suggestion.

Related

Tkinter Not Opening Window

I am creating a program that allows a user to make a custom dice, but when I open a GUI window with a button that calls the backend dice roll logic, it breaks. In other words, the window doesn't open, and the code just runs in the terminal. It doesn't happen when the button is clicked like I want it to, instead when I run the code, it doesn't open any GUI window and the code executes in the terminal. The code works without the GUI, and if i take out the dice button callback, the GUI works but together it doesn't.
Any help is appreciated!
import random
import tkinter as tk
def dice_roll():
dice = []
x = 0
# used to check if the input is a whole number, if it isn't, you get a message
while True:
while x == 0:
try:
SIDE_AMT = int(input("How many sides would you like? (min is 2, max is infinite): ")) # amt is amount
x = 1
except ValueError:
print("Sorry it has to be a whole number.")
if SIDE_AMT > 1:
for side in range(SIDE_AMT):
print(f"What would you like side {side + 1} to be?:")
dice.append(str(input()))
break
else:
print("You can't have a dice with one side!")
x = 0
# roll function
def roll():
dice_side = random.choice(dice)
print(f"I choose {dice_side}!")
roll_num = 0
while True:
if roll_num == 0:
spin_it = str(input("Type 'roll' if you would like to roll the dice: "))
if spin_it == "roll":
roll()
else:
print("Sorry, you have to type roll correctly.")
roll_num += 1
elif roll_num == 1:
while True:
spin_it = str(input("Type 'roll' if you would like to roll the dice again!: "))
if spin_it == "roll":
roll()
else:
print("Sorry, you have to type roll correctly.")
if __name__ == '__main__':
gui = tk.Tk()
gui.title("Dice Roll")
gui.geometry("1912x1090")
gui.configure(bg='#a2a2a1', borderwidth=5,
relief="raised")
# title
title = tk.Label(gui, text='Unique Dice', font=("Times
New Roman", 52))
title.configure(bg='#a2a2a1', fg='#195190',
borderwidth=3, relief='raised')
# make a dice?
dice = tk.Button(gui,
text="Yes!",
fg="red",
command=dice_roll())
no_dice = tk.Button(gui,
text="No",
fg="red",
command=quit)
# frame = tk.Frame(gui, height=200, width=200)
# frame['borderwidth'] = 10
# frame['relief'] = 'sunken'
# frame.pack()
dice.pack()
no_dice.pack()
title.pack()
gui.mainloop()
you may want to do something like this:
import tkinter as tk
from random import choice
root = tk.Tk()
root.geometry('400x600')
root.resizable(False, False)
root.config(bg='light blue')
dice_numbers = [1, 2, 3, 4, 5, 6]
rolled_nums = []
def roll():
if len(rolled_nums):
rolled_nums[0].pack_forget()
rolled_nums.pop(0)
chosen_number = choice(dice_numbers)
text = tk.Label(root, text=f'{chosen_number}',
font='arial 500 bold', bg='light blue')
text.pack()
rolled_nums.append(text)
button = tk.Button(root, text='Roll Dice!', font='arial 20 bold', relief='raised', width='300',
bg='dark red', fg='black', command=lambda: roll())
button.pack()
root.mainloop()
fell free to adjust this code and if you have questions -> ask

checking for mouse collison pygame.draw.circle()

I'm making a CheckButton Widget to be able to use in game menus.
Wondering how I might be able to check if the mouse is colliding with the circle?
Using the self.surface.get_rect() method doesn't seem to work. is there a way to calculate where the circle is based on its location in its surface object? I was just going to just draw a smaller black circle inside the circle when self.active == True then back to its default color if its False. should I be using Sprites for this?
class CheckButton():
"""add label?"""
def __init__(self, screen, pos,size=(10,10),color=GREY):
self.screen = screen
self.pos = pos
self.size = size
self.color = color
self.active = False
self.surface = pygame.surface.Surface(self.size)
self.rect = self.surface.get_rect()
self.center = (5,5)
def check_for_click(self):
pos = pygame.mouse.get_pos()
mouseClicked = pygame.mouse.get_pressed()
if self.rect.collidepoint(pos) and mouseClicked == (1,0,0):
self.active = True
print(self.active)
def draw(self):
self.surface.fill(BG_COLOR)
pygame.draw.circle(self.surface,self.color, self.center,5, 0)
self.screen.blit(self.surface, self.pos)
When using pygame, don't give your objects attributes like pos or center (if you don't have to for whatever reasons). Just use the pygame's Sprite and Rect classes, which will handle all these things for you.
Here's a running example. Note the comments for further explanations:
import pygame
from math import hypot
pygame.init()
screen = pygame.display.set_mode((400, 400))
BG_COLOR=(55,0,200)
# note that pygame comes with a lot of colors already defined in THECOLORS
GREY=pygame.color.THECOLORS['grey']
# pygame's Group is great for sprite handling, but it does not offer a function for event handling
# so we create our own simple Group
class EventAwareGroup(pygame.sprite.Group):
def handle(self, event):
for spr in self.sprites():
if hasattr(spr, 'handle'):
spr.handle(event)
class CheckButton(pygame.sprite.Sprite):
def __init__(self, pos, size=(10,10), color=(255,100,200)):
super().__init__()
self.image = pygame.surface.Surface(size)
# we use a random color as colorkey, which means this color acts
# as a substitute for 'transparent'; so we don't have to care about the
# actual background
self.image.set_colorkey((99,32,127))
self.image.fill((99,32,127))
self.rect = self.image.get_rect()
# our image is a simple circle
# note how we can use the attributes of Rect to easily find the center of our Surface
pygame.draw.circle(self.image, color, self.rect.center, size[0]//2, 0)
# when the checkbox is active, we want to show another image, so let's create it here
# we want to do the drawing once, so we do it in the __init__ function
self.toggle_image = self.image.copy()
pygame.draw.circle(self.toggle_image, (0, 0, 0), self.rect.center, size[0]//3, 0)
# now let's position our checkbox at 'pos'
self.rect.center = pos
self.active = False
def handle(self, event):
# since we want to toggle the active state of the checkbox when a mouse click occurs,
# it's better to listen for the MOUSEBUTTONDOWN event
if event.type == pygame.MOUSEBUTTONDOWN:
# to check if the mouse click was actually in the circle, we simple calculate the distance
d = hypot(event.pos[0] - self.rect.center[0], event.pos[1] - self.rect.center[1])
if d <= self.rect.width/2 and event.button == 1:
# now let's toggle the active flag and the images
self.active = not self.active
self.image, self.toggle_image = self.toggle_image, self.image
c = CheckButton([150, 100], [100, 100])
g = EventAwareGroup(c)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
g.handle(event)
# note how simple and clean our main loop is
# when we need other sprites, just add them to the g Group
# no need to change the main loop for that
screen.fill(BG_COLOR)
g.update()
g.draw(screen)
pygame.display.update()

drawing sprite in pygame from a class constructor

import pygame
pygame.init()
class PlayerNinja(pygame.sprite.Sprite):
x = 0
y = 0
width = 112
height = 102
def __init__(self, x, y):
self.x = x
self.y = y
super(PlayerNinja, self).__init__()
self.image = pygame.image.load("player.png")
.
.
.
###########################################################################
def main():
from PlayerNinja import *
print "Testing"
player = PlayerNinja(10, 10)
a = player.getX()
print "X: " + str(a)
player.setX(50)
b = player.getX()
print "new X: " + str(b)
player.setY(50)
c = player.getY()
print "Y: " + str(c)
screenWidth = 800
screenHeight = 700
screen = pygame.display.set_mode((screenWidth, screenHeight))
white = (255,255,255)
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(white)
screen.blit(player, (b, c))
pygame.display.flip()
if __name__ == "__main__": main()
When I run main, I get the error
screen.blit(player, b, c)
TypeError: argument 1 must be pygame.Surface, not PlayerNinja"
I have tried replacing parts of the line with pygame.Surface. When I used the same format (screen.blit(player, (x,y))) with a different character it worked... I think it is because in this case I load the image in the constructor of the class, whereas the other time I wasn't using a class. I had to look up the super().__init__()-part, so maybe that's part of it?
You need to code
screen.blit(player.image, (b, c))
because the .blit method need a pyagme.Surface-object (a loaded image is also a surface in PyGame) as first argument. You need to pass a surface instance to .blit(), which is stored in your PlayerNinja sprite object ("player") as the attribute self.image.
The other parts (super().__init__()) are fine in my opinion. :)

Picture doesn't load in pygame

# 1 - Import library
import pygame
from pygame.locals import *
import math
import random
# 2 - Initialize the game
pygame.init()
width, height = 640, 480
screen=pygame.display.set_mode((width, height))
keys = [False, False, False, False]
playerpos=[100,100]
acc=[0,0]
arrows=[]
badtimer=100
badtimer1=0
badguys=[[640,100]]
healthvalue=194
pygame.mixer.init()
# 3 - Load image
player = pygame.image.load("C:\python27\PyGame\resources\images\dude.png")
grass = pygame.image.load("C:\python27\PyGame\resources\images\grass.png")
castle = pygame.image.load("C:\python27\PyGame\resources\images\castle.png")
arrow = pygame.image.load("C:\python27\PyGame\resources\images\bullet.png")
badguyimg1 = pygame.image.load("C:\python27\PyGame\resources\image\badguy.png")
badguyimg=badguyimg1
healthbar = pygame.image.load("C:\python27\PyGame\resources\images\healthbar.png")
health = pygame.image.load("C:\python27\PyGame\resources\images\health.png")
gameover = pygame.image.load("C:\python27\PyGame\resources\images\gameover.png")
youwin = pygame.image.load("C:\python27\PyGame\resources\images\youwin.png")
# 3.1 - Load audio
hit = pygame.mixer.Sound("C:\python27\PyGame\resources\audio\explode.wav")
enemy = pygame.mixer.Sound("C:\python27\PyGame\resources\audio\enemy.wav")
shoot = pygame.mixer.Sound("C:\python27\PyGame\resources\audio\shoot.wav")
hit.set_volume(0.05)
enemy.set_volume(0.05)
shoot.set_volume(0.05)
pygame.mixer.music.load('C:\python27\PyGame\resources\audio\moonlight.wav')
pygame.mixer.music.play(-1, 0.0)
pygame.mixer.music.set_volume(0.25)
# 4 - keep looping through
running = 1
exitcode = 0
while running:
badtimer-=1
# 5 - clear the screen before drawing it again
screen.fill(0)
# 6 - draw the player on the screen at X:100, Y:100
for x in range(width/grass.get_width()+1):
for y in range(height/grass.get_height()+1):
screen.blit(grass,(x*100,y*100))
screen.blit(castle,(0,30))
screen.blit(castle,(0,135))
screen.blit(castle,(0,240))
screen.blit(castle,(0,345 ))
# 6.1 - Set player position and rotation
position = pygame.mouse.get_pos()
angle = math.atan2(position[1]-(playerpos[1]+32),position[0]-(playerpos[0]+26))
playerrot = pygame.transform.rotate(player, 360-angle*57.29)
playerpos1 = (playerpos[0]-playerrot.get_rect().width/2, playerpos[1]-playerrot.get_rect().height/2)
screen.blit(playerrot, playerpos1)
# 6.2 - Draw arrows
for bullet in arrows:
index=0
velx=math.cos(bullet[0])*10
vely=math.sin(bullet[0])*10
bullet[1]+=velx
bullet[2]+=vely
if bullet[1]<-64 or bullet[1]>640 or bullet[2]<-64 or bullet[2]>480:
arrows.pop(index)
index+=1
for projectile in arrows:
arrow1 = pygame.transform.rotate(arrow, 360-projectile[0]*57.29)
screen.blit(arrow1, (projectile[1], projectile[2]))
# 6.3 - Draw badgers
if badtimer==0:
badguys.append([640, random.randint(50,430)])
badtimer=100-(badtimer1*2)
if badtimer1>=35:
badtimer1=35
else:
badtimer1+=5
index=0
for badguy in badguys:
if badguy[0]<-64:
badguys.pop(index)
badguy[0]-=7
# 6.3.1 - Attack castle
badrect=pygame.Rect(badguyimg.get_rect())
badrect.top=badguy[1]
badrect.left=badguy[0]
if badrect.left<64:
hit.play()
healthvalue -= random.randint(5,20)
badguys.pop(index)
#6.3.2 - Check for collisions
index1=0
for bullet in arrows:
bullrect=pygame.Rect(arrow.get_rect())
bullrect.left=bullet[1]
bullrect.top=bullet[2]
if badrect.colliderect(bullrect):
enemy.play()
acc[0]+=1
badguys.pop(index)
arrows.pop(index1)
index1+=1
# 6.3.3 - Next bad guy
index+=1
for badguy in badguys:
screen.blit(badguyimg, badguy)
# 6.4 - Draw clock
font = pygame.font.Font(None, 24)
survivedtext = font.render(str((90000-pygame.time.get_ticks())/60000)+":"+str((90000-pygame.time.get_ticks())/1000%60).zfill(2), True, (0,0,0))
textRect = survivedtext.get_rect()
textRect.topright=[635,5]
screen.blit(survivedtext, textRect)
# 6.5 - Draw health bar
screen.blit(healthbar, (5,5))
for health1 in range(healthvalue):
screen.blit(health, (health1+8,8))
# 7 - update the screen
pygame.display.flip()
# 8 - loop through the events
for event in pygame.event.get():
# check if the event is the X button
if event.type==pygame.QUIT:
# if it is quit the game
pygame.quit()
exit(0)
if event.type == pygame.KEYDOWN:
if event.key==K_w:
keys[0]=True
elif event.key==K_a:
keys[1]=True
elif event.key==K_s:
keys[2]=True
elif event.key==K_d:
keys[3]=True
if event.type == pygame.KEYUP:
if event.key==pygame.K_w:
keys[0]=False
elif event.key==pygame.K_a:
keys[1]=False
elif event.key==pygame.K_s:
keys[2]=False
elif event.key==pygame.K_d:
keys[3]=False
if event.type==pygame.MOUSEBUTTONDOWN:
shoot.play()
position=pygame.mouse.get_pos()
acc[1]+=1
arrows.append([math.atan2(position[1]-(playerpos1[1]+32),position[0]-(playerpos1[0]+26)),playerpos1[0]+32,playerpos1[1]+32])
# 9 - Move player
if keys[0]:
playerpos[1]-=5
elif keys[2]:
playerpos[1]+=5
if keys[1]:
playerpos[0]-=5
elif keys[3]:
playerpos[0]+=5
#10 - Win/Lose check
if pygame.time.get_ticks()>=90000:
running=0
exitcode=1
if healthvalue<=0:
running=0
exitcode=0
if acc[1]!=0:
accuracy=acc[0]*1.0/acc[1]*100
else:
accuracy=0
# 11 - Win/lose display
if exitcode==0:
pygame.font.init()
font = pygame.font.Font(None, 24)
text = font.render("Accuracy: "+str(accuracy)+"%", True, (255,0,0))
textRect = text.get_rect()
textRect.centerx = screen.get_rect().centerx
textRect.centery = screen.get_rect().centery+24
screen.blit(gameover, (0,0))
screen.blit(text, textRect)
else:
pygame.font.init()
font = pygame.font.Font(None, 24)
text = font.render("Accuracy: "+str(accuracy)+"%", True, (0,255,0))
textRect = text.get_rect()
textRect.centerx = screen.get_rect().centerx
textRect.centery = screen.get_rect().centery+24
screen.blit(youwin, (0,0))
screen.blit(text, textRect)
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit(0)
pygame.display.flip()
here is the error message
Traceback (most recent call last):
File "C:\Python27\game2.py", line 22, in
player = pygame.image.load("C:\python27\PyGame\resources\images\dude.png")
error: Couldn't open C:\python27\PyGame\resources\images\dude.png
What should I do?
First, make sure the file exists.
Next, using single backslashes, \, may lead to problems. For example, \r is the carriage return sequence (\n is the more widely known newline sequence). Your file path, happens to contain a \r, which could be causing your issue.
Try one of these instead:
# Use forward slashes
pygame.image.load("C:/python27/PyGame/resources/images/dude.png")
# Use double back-slashes. For file path specification, \\ indicates '\' (depending
# on the platform)
pygame.image.load("C:\\python27\\PyGame\\resources\\images\\dude.png")
# Use the os module
# Note that this assembles a path relative to your .py file.
# Absolute path can still be done here, it's just more verbose.
pygame.image.load(os.path.join("Pygame", "resources", "images", "dude.png"))
The last option is probably the best practice.

Pygame, simple physics engine, how to hold points between planes?

I'm trying to write this tutorial in Pygame(Python) and having problems about holding points between planes.
My code is: fiz2.py
Vector class: vector.py
If you move mouse on the Pygame screen, the planes will rotate. And when the planes are rotating, points are passing through planes and going outside.
I tried to fix points' positions on every iteration but they still passed the planes. I have no idea about where should I fix their positions.
NOTE: I know my code is a little bit messy, this is my first 2d program and I had really hard times getting used to Pygame's coordinate plane and vectors. I will re-write when I solve this.
NOTE2: Yes, I wrote the comment about how to hold points between planes on the tutorial, I understand the way he fixes positions but have no idea about how(and where, in code) to implement it.
Thanks.
I can't tell looking at the code. My guess is a variable-timestep, causing instability. But I can't verify if the math is right. Although, I have useful information :
Vectors
You can simplify code, by using vectors as a class vs list/tuple. (velocity, acceleration, location) are treated as one object, verses separate .x and .y values.
# example:
pos[0] += vel[0]
pos[1] += vel[1]
# vs
pos += vel
There is a python-only implementation: euclid.py You can use to compare with your vector.py.
Or use NumPy [ used for 3d graphics, in openGL. ] Is a popular, mature lib.
physics
(It looks like you want to learn by writing your own physics), but check out PyMunk
colors
You can use: pygame.Color
import pygame
from pygame import Color
color = Color('white')
color2 = Color('lightgray')
color3 = Color(0,128,128)
collisions
Look at pygame.sprite.*collide , and pygame.Rect.*collide
pygame Game loop with numpy vector's
Boilerplate I wrote
""" Pygame boilerplate. <ninmonkey>2011/04
pygame main Game() loop, and numpy for vector math.
note:
this might not be the most effecient way to use numpy as vectors, but it's an intro.
And this does not force fixed-timesteps. If you want a stable simulation, you need to use a fixed timestep.
see: http://gafferongames.com/game-physics/fix-your-timestep/
Keys:
ESC : exit
Space : game_init()
"""
import pygame
from pygame.locals import *
from pygame import Color, Rect
import numpy as np
def get_screen_size():
"""return screen (width, height) tuple"""
screen = pygame.display.get_surface()
return screen.get_size()
class Actor():
"""basic actor, moves randomly.
members:
loc = position vector
velocity = velocity vector
width, height
"""
def __init__(self, loc=None, velocity=None):
"""optional initial loc and velocity vectors"""
self.width = 50
self.height = 50
# if loc or velocity are not set: use random
if loc is None: self.rand_loc()
else: self.loc = loc
if velocity is None: self.rand_velocity()
else: self.velocity = velocity
def update(self):
"""update movement"""
self.loc += self.velocity
def rand_velocity(self):
"""set a random vector , based on random direction. Using unit circle:
x = cos(deg) * speed
"""
rad = np.radians( np.random.randint(0,360) )
speed = np.random.randint(1,15)
x = np.cos(rad)
y = np.sin(rad)
velocity = np.array( [x,y])
velocity *= speed
self.velocity = velocity
def rand_loc(self):
"""random location onscreen"""
width,height = get_screen_size()
x = np.random.randint(0,width)
y = np.random.randint(0,height)
self.loc = np.array([x,y])
def is_onscreen(self):
"""test is screen.colliderect(actor) true?"""
x,y = self.loc
w,h = get_screen_size()
screen = Rect(0, 0, w, h)
actor = Rect(x, y, self.width, self.height)
if screen.colliderect(actor): return True
else: return False
class GameMain():
"""game Main entry point. handles intialization of game and graphics."""
done = False
debug = False
color_gray = Color('lightgray')
def __init__(self, width=800, height=600, color_bg=None):
"""Initialize PyGame"""
pygame.init()
self.width, self.height = width, height
self.screen = pygame.display.set_mode(( self.width, self.height ))
pygame.display.set_caption( "boilerplate : pygame" )
self.clock = pygame.time.Clock()
self.limit_fps = True
self.limit_fps_max = 60
if color_bg is None: color_bg = Color(50,50,50)
self.color_bg = color_bg
self.game_init()
def game_init(self):
"""new game/round"""
self.actors = [Actor() for x in range(10)]
def loop(self):
"""Game() main loop"""
while not self.done:
self.handle_events()
self.update()
self.draw()
if self.limit_fps: self.clock.tick( self.limit_fps_max )
else: self.clock.tick()
def update(self):
"""update actors, handle physics"""
for a in self.actors:
a.update()
if not a.is_onscreen():
a.rand_loc()
def handle_events(self):
"""handle regular events. """
events = pygame.event.get()
# kmods = pygame.key.get_mods() # key modifiers
for event in events:
if event.type == pygame.QUIT: sys.exit()
elif event.type == KEYDOWN:
if (event.key == K_ESCAPE): self.done = True
elif (event.key == K_SPACE): self.game_init()
def draw(self):
"""render screen"""
# clear screen
self.screen.fill( self.color_bg )
# Actor: draw
for a in self.actors:
x,y = a.loc
w,h = a.width, a.height
r = Rect(x, y, w, h)
self.screen.fill(self.color_gray, r)
# will call update on whole screen Or flip buffer.
pygame.display.flip()
if __name__ == '__main__':
g = GameMain()
g.loop()