How to not initialize the def init every time - python
this code is by tech with tim but i am trying to tweak it, i am trying to make the rotation velocity vary everytime.
import pygame
import time
import math
from utility import scale_image, blit_rotate_center
rotation_speed=2
Joystickx=0
GRASS = scale_image(pygame.image.load("Sprites/grass.png"),2.5)
TRACK = scale_image(pygame.image.load("Sprites/track.png"),0.7)
TRACK_BORDER = scale_image(pygame.image.load("Sprites/track-border.png"),0.7)
Car = scale_image(pygame.image.load("Sprites/F1.xcf"),0.1)
FINISH=pygame.image.load("Sprites/finish.png")
WIDTH, HEIGHT= TRACK.get_width(), TRACK.get_height()
WIN = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("F1")
FPS = 60
class AbstractCar:
def __init__(self,max_vel,rotation_vel):
self.img=self.IMG
self.max_vel=max_vel
self.vel = 0
self.rotation_vel = rotation_vel
self.angle = 90
self.x, self.y = self.START_POS
def rotate(self, left=False, right=False):
if left:
self.angle += self.rotation_vel
print(self.angle)
elif right:
self.angle -= self.rotation_vel
print(self.angle)
def draw(self):
blit_rotate_center(WIN, self.img,(self.x, self.y), self.angle)
class PlayerCar(AbstractCar):
IMG = Car
START_POS = (180,200)
def draw(win,images, player_car):
for img, pos in images:
win.blit(img,pos)
player_car.draw()
pygame.display.update()
run=True
clock = pygame.time.Clock()
images = [(GRASS, (0,0)),(TRACK,(0,0))]
def rotate():
global rotation_speed
global Joystickx
rotation_speed+=2*Joystickx
rotation_speed*=0.9
while run:
clock.tick(FPS)
rotate()
player_car = PlayerCar(4, rotation_speed)
draw(WIN, images, player_car)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
break
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
player_car.rotate(left=True)
Joystickx=-1
elif keys[pygame.K_d]:
player_car.rotate(right=True)
Joystickx=1
else:
Joystickx=0
pygame.quit()
however, every time the class is ran, the code will set self.angle to 90, i do not want that to happen, what can i do to not let the def init run as that will set the self.angle to 94 instead remembering the last self.angle
This is OOP (Object Oriented Programming) thing. I really suggest you to look it up, it's not an easy topic at first, but it's also not that hard to understand everything in it, it's just the first time is hard.
So, the __init__ is the constructor of your AbstractCar class. This will always run when you make a new object from this class.
The simple way to fix this is to place the line where you define your car a bit above, outside the while loop and to keep the rotation_vel updated, we make a new method in the AbstractCar class and call it instead:
class AbstractCar:
def set_rotation_vel(self, new_rotation_vel):
self.rotation_vel = new_rotation_vel
[...]
player_car = PlayerCar(4, rotation_speed)
while run:
clock.tick(FPS)
rotate()
player_car.set_rotation_vel(rotation_speed)
draw(WIN, images, player_car)
Related
I am making snake in pygame and python is giving me an error that one of my objects is actually a string, but its not meant to be
The error that shows up in python right now is Traceback (most recent call last): File "C:\Users\Eduardo.Graglia\AppData\Local\Programs\Python\Python37\Start.py", line 66, in <module> snake = snake(self) # create an instance File "C:\Users\Eduardo.Graglia\AppData\Local\Programs\Python\Python37\Start.py", line 17, in __init__ food.image = pygame.image.load("food.png") AttributeError: 'str' object has no attribute 'image' I am very new to python and pygame, so most of the code I've been using is stuff I've taken and adapted from stack overflow What I was trying to do with the food object was make it so that it was all in one player class because I am confused on how to call methods from other classes and use objects from other classes in one class. If anyone has any alternatives to what I've done please tell me. import pygame import os import time import math import random length = 650 width = 400 headx = 0 heady = 0 class snake(object): def __init__(self, food): self.image = pygame.image.load("head.png") self.x = 0 self.y = 0 food.image = pygame.image.load("food.png") food.x = 0 food.y = 0 def handle_keys(self): """ Handles Keys """ key = pygame.key.get_pressed() dist = 25 # distance moved in 1 frame, try changing it to 5 if key[pygame.K_DOWN]: # down key self.y += dist # move down heady = heady - dist elif key[pygame.K_UP]: # up key self.y -= dist # move up heady = heady - dist if key[pygame.K_RIGHT]: # right key self.x += dist # move right headx = headx - dist elif key[pygame.K_LEFT]: # left key self.x -= dist # move left headx = headx - dist def fooddrop(food, surface): newfoodx = 1 newfoody = 1 while newfoodx % 25 != 0 or newfoodx !=0: newfoodx = random.randint(0,650) while newfoody % 25 != 0 or newfoody !=0: newfoody = random.randint(0,400) food.x = newfoodx food.y = newfoody surface.blit(food.image,(food.x,food.y)) def draw(self, surface): """ Draw on surface """ # blit yourself at your current position surface.blit(self.image, (self.x, self.y)) self = 'null' food = 'null' pygame.init() screen = pygame.display.set_mode((length, width)) snake = snake(self) # create an instance food = snake(food) running = True while running: # handle every event since the last frame. for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() # quit the screen running = False if snake.y > width or snake.y < 0 or snake.x > length or snake.x < 0: #Border Created pygame.quit() # quit the screen running = False time.sleep(0.125) snake.handle_keys() # handle the keys screen.fill((0,0,0)) # fill the screen with white snake.draw(screen) # draw the snake to the screen snake.fooddrop(screen) pygame.display.update() # update the screen clock.tick(40) Feel free to completely destroy my code because I am new and need to learn. Thanks in advance!
You have to distinguish between Classes and instances of classes (objects). Create a class Snake (or whatever name). Please use a leading capital letter for the name of the class to avoid confusions (see Style Guide for Python Code - Class Names). The constructor of the class has 1 parameter (beside self), the name of the image: class Snake(object): def __init__(self, imagename): self.image = pygame.image.load(imagename) self.x = 0 self.y = 0 Create 2 instances of the class: snake = Snake("head.png") food = Snake("food.png")
Is there a way to change my_sprite or my_group to change the animation displayed?
I'm making animated sprites in pygame, and would like help finding a way to flip from one to the other? The current code looks something like this: class normal(pygame.sprite.Sprite): def __init__(self): #etc, list of images to create the animation class tall(pygame.sprite.Sprite): def __init__(self): #rinse and repeat with a different set of images I already have an idea for how to trigger the change via keystroke. But I'm not sure which variable to change, and to what. When I try to change with the following code, nothing happens fps = 25 pygame.init() my_sprite = normal() my_group = pygame.sprite.Group(my_sprite) #etc until we get to the part where it changes if event.type == pygame.KEYDOWN: if event.key == pygame.K_RETURN: if my_sprite == normal(): my_sprite = tall() fps = 30 else: my_sprite = normal() fps = 25 I'm not sure exactly what isn't working in my code as it doesn't come back with an error. Can someone point me in the right direction?
It's not working because when the code calls normal() it's creating a new instance of an object. So the call: if my_sprite == normal(): Is saying "is my existing sprite object == this new sprite object", which is never true. You can use the python function to type() of the object to do the same thing, or add your own type-function as I have presented in the code below. I would track the state of the sprite inside the class, and use some functions grow() and shrink() to change the size automatically. class GrowingSprite( pygame.sprite.Sprite, x, y ): def __init__( self ): #etc, list of images to create the animation self.image_short = ... # load "short" image self.image_tall = ... # load "tall" image # Set the initial state self.image = self.image_short # start short self.rect = self.image.get_rect() self.rect.centerx = x self.rect.centery = y self.state = 'short' def getState( self ): return self.state def grow( self ): self.state = 'tall' self.image = self.image_tall current_x = self.rect.centerx # preserve existing location current_y = self.rect.centery self.rect = self.image.get_rect() self.rect.center = ( current_x, current_y ) def shrink( self ): self.state = 'short' self.image = self.image_short current_x = self.rect.centerx # preserve existing location current_y = self.rect.centery self.rect = self.image.get_rect() self.rect.center = ( current_x, current_y )
I found a workaround that is a bit redundant, but it makes it possible to expand it in case there are more groups It requires making two groups that can be pulled back and fourth, and changing the foo.draw(screen) to the new group. This is how it looks nml_sprite = normal() tal_sprite = tall() tg = 1 #this is nothing more than a switch to trigger the change tal_group = pygame.sprite.Group(tal_sprite) nml_group = pygame.sprite.Group(nml_sprite) cursprite = nml_group #this variable determines which sprite set is loaded ... ... if event.key == pygame.K_RETURN: if tg == 1: curspt = tal_group tg = 2 else: curspt = nml_group tg = 2 ... ... nml_group.update() tal_group.update() curspt.draw(screen) ...
How to make a wave timer in pygame
So, I'm totally new to programming (been doing it for a couple of months) and decided to try coding a game. On that note, a big thanks to Chris Bradfield for his series of tutorials in pygame coding, they are absolutely great! However, now that I'm done with the tutorials and need to work on my own, I've come across a problem. I'm making a top-down shooter and making it wave-based. So, when zombies in one wave die, I want to show a timer that counts down until the next wave begins. I THINK I'm down the right path atm, let me show you what I'm working with. def new(self) ''' self.timer_flag = False self.x = threading.Thread(target=self.countdown, args=(TIME_BETWEEN_WAVES,)) ''' def countdown(self, time_between_waves): self.wave_timer = time_between_waves for i in range(TIME_BETWEEN_WAVES): while self.timer_flag: self.wave_timer -= time.sleep(1) def update(self) ''' self.countdown_has_run = False if len(self.mobs) == 0: self.timer_flag = True if not self.countdown_has_run: self.countdown_has_run = True self.x.start() ''' Now, I also draw my timer when the timer_flag is True, but it doesn't decrement, so I assume the problem lies somewhere in calling/starting the threaded countdown function? Also, it's my first time posting here, so please let me know what to do to format better etc for you to be able to help
Don't bother with threads. No need to make your live complicated. Usually, you use a Clock anyway in your game (if not, you should start using it) to limit the framerate, and to ensure that your world moves at a constant rante (if not, you should start doing it). So if you want to trigger something in, say, 5 seconds, just create a variable that holds the value 5000, and substract the time it took to process your last frame (which is returned by Clock.tick): clock = pygame.time.Clock() dt = 0 timer = 5000 while True: ... timer -= dt if timer <= 0: do_something() dt = clock.tick(60) I hacked together a simple example below. There, I use a simple class that is also a Sprite to draw the remaining time to the screen. When the timer runs out, it calls a function that creates a new wave of zombies. In the main loop, I check if there's no timer running and no zombies, and if that's the case, a new timer is created. Here's the code: import pygame import pygame.freetype import random # a dict that defines the controls # w moves up, s moves down etc CONTROLS = { pygame.K_w: ( 0, -1), pygame.K_s: ( 0, 1), pygame.K_a: (-1, 0), pygame.K_d: ( 1, 0) } # a function that handles the behaviour a sprite that # should be controled with the keys defined in CONTROLS def keyboard_controlled_b(player, events, dt): # let's see which keys are pressed, and create a # movement vector from all pressed keys. move = pygame.Vector2() pressed = pygame.key.get_pressed() for vec in (CONTROLS[k] for k in CONTROLS if pressed[k]): move += vec if move.length(): move.normalize_ip() move *= (player.speed * dt/10) # apply the movement vector to the position of the player sprite player.pos += move player.rect.center = player.pos # a function that let's a sprite follow another one # and kill it if they touch each other def zombie_runs_to_target_b(target): def zombie_b(zombie, events, dt): if target.rect.colliderect(zombie.rect): zombie.kill() return move = target.pos - zombie.pos if move.length(): move.normalize_ip() move *= (zombie.speed * dt/10) zombie.pos += move zombie.rect.center = zombie.pos return zombie_b # a simple generic sprite class that displays a simple, colored rect # and invokes the given behaviour class Actor(pygame.sprite.Sprite): def __init__(self, color, pos, size, behavior, speed, *grps): super().__init__(*grps) self.image = pygame.Surface(size) self.image.fill(color) self.rect = self.image.get_rect(center=pos) self.pos = pygame.Vector2(pos) self.behavior = behavior self.speed = speed def update(self, events, dt): self.behavior(self, events, dt) # a sprite class that displays a timer # when the timer runs out, a function is invoked # and this sprite is killed class WaveCounter(pygame.sprite.Sprite): font = None def __init__(self, time_until, action, *grps): super().__init__(grps) self.image = pygame.Surface((300, 50)) self.image.fill((3,2,1)) self.image.set_colorkey((3, 2, 1)) self.rect = self.image.get_rect(topleft=(10, 10)) if not WaveCounter.font: WaveCounter.font = pygame.freetype.SysFont(None, 32) WaveCounter.font.render_to(self.image, (0, 0), f'new wave in {time_until}', (255, 255, 255)) self.timer = time_until * 1000 self.action = action def update(self, events, dt): self.timer -= dt self.image.fill((3,2,1)) WaveCounter.font.render_to(self.image, (0, 0), f'new wave in {int(self.timer / 1000) + 1}', (255, 255, 255)) if self.timer <= 0: self.action() self.kill() def main(): pygame.init() screen = pygame.display.set_mode((600, 480)) screen_rect = screen.get_rect() clock = pygame.time.Clock() dt = 0 sprites_grp = pygame.sprite.Group() zombies_grp = pygame.sprite.Group() wave_tm_grp = pygame.sprite.GroupSingle() # the player is controlled with the keyboard player = Actor(pygame.Color('dodgerblue'), screen_rect.center, (32, 32), keyboard_controlled_b, 5, sprites_grp) # this function should be invoked once the timer runs out def create_new_wave_func(): # let's create a bunch of zombies that follow the player for _ in range(15): x = random.randint(0, screen_rect.width) y = random.randint(-100, 0) Actor((random.randint(180, 255), 0, 0), (x, y), (26, 26), zombie_runs_to_target_b(player), random.randint(2, 4), sprites_grp, zombies_grp) while True: events = pygame.event.get() for e in events: if e.type == pygame.QUIT: return # no timer, no zombies => create new timer if len(wave_tm_grp) == 0 and len(zombies_grp) == 0: WaveCounter(5, create_new_wave_func, sprites_grp, wave_tm_grp) sprites_grp.update(events, dt) screen.fill((80, 80, 80)) sprites_grp.draw(screen) pygame.display.flip() dt = clock.tick(60) if __name__ == '__main__': main()
It looks to me you are lacking the mechanism to check how many mobs are left on screen. I imagine it could be something like this: class CountdownClock: def __init__(self): self.start_no = 1 self.time_between_waves = 5 self.t = threading.Thread(target=self.check_mobs_left) self.t.start() def check_mobs_left(self): self.mobs = ["mob" for _ in range(randint(2, 7))] #generate 2-7 mobs per level print (f"Wave {self.start_no} : Total {len(self.mobs)} mobs found!") while self.mobs: print (f"Still {len(self.mobs)} mobs left!") time.sleep(1) del self.mobs[-1] #simulate mob kill - remove this line from your actual setting self.next_wave(self.time_between_waves) self.time_between_waves +=2 #increased time for each wave def next_wave(self,time_between_waves): self.time_left = time_between_waves print(f"Wave {self.start_no} cleared!") self.start_no += 1 while self.time_left: print (f"Next wave in...{self.time_left}") self.time_left -=1 time.sleep(1) self.t = threading.Thread(target=self.check_mobs_left) self.t.start() a = CountdownClock() You will have this up constantly without the need to call the method every round and set flag and stuff.
How do i instance sprites in Pygame? Do i need too?
So im working on a game for some coursework in my computing course, im almost finished but for the life of me i cant get multiple of the Spider sprite to spawn in at the correct locations or reset properly between levels. I've tried adding different instances to groups before but i always get a different error with each method that i try. the code is below and im fairly new to pygame so sorry for the messy code.. # class Spider(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load( 'Assets/Level-Assets/Level 1/Enemies/Spider_Down.png') self.rect = self.image.get_rect() self.Health = 3 self.Spawned = False self.range = 100 self.Gravity= 6 self.pos_difference = 0 self.Active = False self.Fall = False self.Spiders = [] ################################################################################################################## def Set_Position(self): if self.Spawned == False: self.rect.center = (World.mapx, World.mapy) Enemies.add(self) self.Spawned = True else: self.rect.center = self.rect.center ###################################################################################################################### def update(self): self.pos_difference = Player.rect.centery - self.rect.centery if Player.rect.centerx >= self.rect.centerx -4 or Player.rect.centerx >= self.rect.centerx + 4: if Player.rect.centery > self.rect.centery: if self.pos_difference < 200: self.Active = True self.Fall = True if self.Active == True: if self.Fall == True: self.rect.centery += self.Gravity This is the code for the Spider, its not actually doing anything until it is called within the World class, which is where i believe the majority of the problem is... def DisplayWorld(self): self.MapLoad = False for Row in range(len(self.newMap)): for Col in range(len(self.newMap[Row])): self.mapx = Col * 64 self.mapy = ((Row + self.Height_modifier) * 64) self.tile_pos = (self.mapx, self.mapy ) if int(self.newMap[Row][Col]) == 1: self.rect = self.Brick_Center.get_rect(left = (self.mapx) , bottom = (self.mapy)) self.World_sprites.add(World) self.Camera_Pos_Check() Player.Collision_Check() Spider.Collision_Check() Shoot.Collision_Check() self.World_sprites.draw(screen) elif int(self.newMap[Row][Col]) == 2: Enemies.add(Spider(screen)) def main(): play = True while play: if pygame.key.get_pressed()[pygame.K_ESCAPE]: play = False if not Sprites.sprites(): Sprites.add(Player,Spider) print(Sprites) clock.tick(CLOCKRATE) pygame.mouse.set_visible(False) for event in pygame.event.get(): if event.type == pygame.QUIT: play = False screen.blit(bgi,(0,0)) screen.blit(bgi,(0,500)) World.findLevel() Sprites.update() Enemies.draw(screen) Sprites.draw(screen) if Shoot.bullet == True: Shoot.update() for b in range(len(Shoot.bullets)): screen.blit(Shoot.image, (Shoot.bullets[b][0],Shoot.bullets[b][1])) UI.Health_Display() pygame.display.flip() Sprites = pygame.sprite.Group() Enemies = pygame.sprite.Group() UI = User_Interface() World = World() Player = Proto() Shoot = Shoot() Portal = Portals() Spider = Spider() main()
I've found your problem: you overwrite your Spider class by an instance of it (Spider()) and then give it the same name. Thus you're consistently adding the same single spider to your enemies list. Instead, you should remove this definition on the bottom of your file and where ever you're adding the (multiple) spider(s), you should create this instance. In a more general remark, it is considered bad style (and not too great for performance) to use global variables as widely as you do. It'd be much better to pass them around between functions and classes. Also, the CamelCase capitalization you use for all of your variables is commonly only used for classes. I'd recommend checking up on pep8 to learn more about how to use common Python styles. It makes these kinds of problems easier to spot, less likely to occur, and simplifies the reading for anyone involved. Using these points properly might even improve your grade significantly ;).
Why is this small (155 lines-long) Pacman game on Python running so slow?
I have already cut everything I could from the main loop. I also optimized collisions for dynamic and static objects, reducing considerably the number of iterations. But it is still slow on his machine. I'll post the entire file for the case someone wants to test it, but you can just jump to the main loop at "while Exit==false:". import pygame from pyeuclid import Vector2 from math import sin,cos,pi from random import random class Thing: def __init__(self,pos): self.pos = pos things.append(self) def update(self): pass def draw(self,img): pass def collide(self,who): pass class DynamicThing(Thing): def __init__(self,pos): Thing.__init__(self,pos) self.vel = Vector2(0,0) self.lastPos = pos self.col = (255,255,0) self.r = 12 dynamic_things.append(self) def update(self): self.lastPos = self.pos self.pos = self.pos + self.vel def draw(self,img): pygame.draw.circle(img, (0,0,0), [int(n) for n in self.pos], self.r, self.r) pygame.draw.circle(img, self.col, [int(n) for n in self.pos], self.r-2, self.r-2) def collide(self,obj): Thing.collide(self,obj) if isinstance(obj,Wall): self.pos = self.lastPos class Wall(Thing): def draw(self,img): x,y = self.pos.x, self.pos.y pygame.draw.rect(img, (90,90,200), (x-16,y-16,32,32), 0) class Pacman(DynamicThing): def __init__(self): DynamicThing.__init__(self,Vector2(32*9+16,32*12+16)) self.col = (255,255,0) def update(self): DynamicThing.update(self) if (keyPressed[pygame.K_LEFT]): self.vel.x = -1 if (keyPressed[pygame.K_RIGHT]): self.vel.x = 1 if (keyPressed[pygame.K_DOWN]): self.vel.y = 1 if (keyPressed[pygame.K_UP]): self.vel.y = -1 if (self.vel.x==-1 and not keyPressed[pygame.K_LEFT]): self.vel.x = 0 if (self.vel.x==1 and not keyPressed[pygame.K_RIGHT]): self.vel.x = 0 if (self.vel.y==1 and not keyPressed[pygame.K_DOWN]): self.vel.y = 0 if (self.vel.y==-1 and not keyPressed[pygame.K_UP]): self.vel.y = 0 def collide(self,obj): DynamicThing.collide(self,obj) if isinstance(obj,Ghost): self.pos = Vector2(32*9+16,32*12+16) class Ghost(DynamicThing): def __init__(self): DynamicThing.__init__(self,Vector2(32*9+16,32*10+16)) self.col = (int(random()*255),int(random()*255),int(random()*255)) self.vel = Vector2(0,-2) def update(self): DynamicThing.update(self) if random()<0.01: self.vel = [Vector2(2,0),Vector2(-2,0),Vector2(0,2),Vector2(0,-2)][int(random()*4)] def collide(self,obj): DynamicThing.collide(self,obj) if isinstance(obj,Wall): self.vel = [Vector2(2,0),Vector2(-2,0),Vector2(0,2),Vector2(0,-2)][int(random()*4)] def thingAtPos(pos): tile_pos = Vector2(int(pos.x/32),int(pos.y/32)) return map[tile_pos.y][tile_pos.x] # initializate stuff pygame.init() clock = pygame.time.Clock() screen = pygame.display.set_mode([32*19,32*22]) points_in_unit_circle_border = [Vector2(cos(float(a)/8*2*pi),sin(float(a)/8*2*pi)) for a in xrange(8)] things = [] dynamic_things = [] exit = False map = [[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1], [1,0,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,0,1], [1,0,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,0,1], [1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1], [1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1], [1,1,1,1,0,1,0,0,0,0,0,0,0,1,0,1,1,1,1], [1,1,1,1,0,1,0,1,1,0,1,1,0,1,0,1,1,1,1], [1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1], [1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1], [1,1,1,1,0,1,0,0,0,0,0,0,0,1,0,1,1,1,1], [1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1], [1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1], [1,0,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,0,1], [1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1], [1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1], [1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1], [1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]] #create pacman, walls, ghosts pacman = Pacman() for y in xrange(len(map)): for x in xrange(len(map[y])): if (map[y][x]==1): map[y][x] = Wall(Vector2(x*32+16,y*32+16)) for i in xrange(4): Ghost() while exit==False: clock.tick(45) screen.fill([255,255,255]) keyPressed = pygame.key.get_pressed() # events for event in pygame.event.get(): if event.type == pygame.QUIT: exit = True if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: exit = True # more ghosts if random()<0.001: Ghost() # updates e draws for thing in things: thing.update() thing.draw(screen) # collisions for A in dynamic_things: #dynamic vs dynamic for B in dynamic_things: if A!=B and abs(A.pos-B.pos)<(A.r+B.r): A.collide(B) B.collide(A) #dynamic vs walls for circle_point in points_in_unit_circle_border: thing_in_a_border = thingAtPos(A.pos+circle_point*12) if isinstance(thing_in_a_border,Wall): A.collide(thing_in_a_border) pygame.display.flip() pygame.quit ()
You are redrawing and fliping the whole screen in every loop. I didn't test your program, but on the pacman I know, there are only 5 moving sprites on the screen, you should try to only blit those every frame (and of course if something else changes, that too). And don't display.flip(), just update the areas of the screen that you changed (that normally speeds up a lot). Of course you need to stop blanking the screen every frame for that, and there will be much management of what to update. There is some extra support for dirty sprites in pygame http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.DirtySprite that help you with that. Or you could maybe just update all 'active' sprites by blanking the position they where and redrawing them in the new position (and obviously everything that also is in those two areas). Collect the effected rects in a list and pass that to update_rects() instead of flipping the screen. There should be no need in drawing the walls in a pacman game in every frame...
Probably not a big source of slowness, but "while exit==False:" requires a little more bytecode to execute than "while not exit:".