adding a def main to the end of my pong game code - python
I'm trying to add a def main to the end of my pong game to make it easier to read, but i've ran into problems trying to do that. When I add the def main, I just get a black screen, but without it I get the whole game.
import pygame
SCR_WID, SCR_HEI = 640, 480
class Player():
def __init__(self):
self.x, self.y = 16, SCR_HEI/2
self.speed = 3
self.padWid, self.padHei = 8, 64
self.score = 0
self.scoreFont = pygame.font.Font("imagine_font.ttf", 64)
def scoring(self):
scoreBlit = self.scoreFont.render(str(self.score), 1, (255, 255, 255))
screen.blit(scoreBlit, (32, 16))
if self.score == 10:
print ("player 1 wins!")
exit()
def movement(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
self.y -= self.speed
elif keys[pygame.K_s]:
self.y += self.speed
if self.y <= 0:
self.y = 0
elif self.y >= SCR_HEI-64:
self.y = SCR_HEI-64
def draw(self):
pygame.draw.rect(screen, (255, 255, 255), (self.x, self.y, self.padWid, self.padHei))
class Enemy(Player):
def __init__(self):
self.x, self.y = SCR_WID-16, SCR_HEI/2
self.speed = 3
self.padWid, self.padHei = 8, 64
self.score = 0
self.scoreFont = pygame.font.Font("imagine_font.ttf", 64)
def scoring(self):
scoreBlit = self.scoreFont.render(str(self.score), 1, (255, 255, 255))
screen.blit(scoreBlit, (SCR_HEI+92, 16))
if self.score == 10:
print ("Player 2 wins!")
exit()
def movement(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
self.y -= self.speed
elif keys[pygame.K_DOWN]:
self.y += self.speed
if self.y <= 0:
self.y = 0
elif self.y >= SCR_HEI-64:
self.y = SCR_HEI-64
def draw(self):
pygame.draw.rect(screen, (255, 255, 255), (self.x, self.y, self.padWid, self.padHei))
class Ball():
def __init__(self):
self.x, self.y = SCR_WID/2, SCR_HEI/2
self.speed_x = -3
self.speed_y = 3
self.size = 8
def movement(self):
self.x += self.speed_x
self.y += self.speed_y
#wall col
if self.y <= 0:
self.speed_y *= -1
elif self.y >= SCR_HEI-self.size:
self.speed_y *= -1
if self.x <= 0:
self.__init__()
enemy.score += 1
elif self.x >= SCR_WID-self.size:
self.__init__()
self.speed_x = 3
player.score += 1
##wall col
#paddle col
#player
for n in range(-self.size, player.padHei):
if self.y == player.y + n:
if self.x <= player.x + player.padWid:
self.speed_x *= -1
break
n += 1
#enemy
for n in range(-self.size, enemy.padHei):
if self.y == enemy.y + n:
if self.x >= enemy.x - enemy.padWid:
self.speed_x *= -1
break
n += 1
##paddle col
def draw(self):
pygame.draw.rect(screen, (255, 255, 255), (self.x, self.y, 8, 8))
SCR_WID, SCR_HEI = 640, 480
screen = pygame.display.set_mode((SCR_WID, SCR_HEI))
pygame.display.set_caption("Pong")
pygame.font.init()
clock = pygame.time.Clock()
FPS = 60
def main():
ball = Ball()
player = Player()
enemy = Enemy()
while True:
#process
for event in pygame.event.get():
if event.type == pygame.QUIT:
print ("Game exited by user")
exit()
##process
#logic
ball.movement()
player.movement()
enemy.movement()
##logic
#draw
screen.fill((0, 0, 0))
ball.draw()
player.draw()
player.scoring()
enemy.draw()
enemy.scoring()
##draw
#_______
pygame.display.flip()
clock.tick(FPS)
main()
The call for main() on the end should be
if __name__ == "__main__":
main()
So that you can run your code and get the function to run. Also your indentation seems a little off. Is your code structured correctly with regard to spaces?
As already answered, you should insert the following statement at the end of the script:
if __name__ == "__main__":
main()
This answer will give you more info about the meaning of that statement.
What does if __name__ == "__main__": do?
In short, it tells the interpreter what it has to do with the function main():
1) Run it automatically if the file has been executed as stand alone script.
2) Don't run if the file has been imported as module from another script.
In your case, the wanted behaviour is the number one.
Related
My collision detection isn't working and way to laggy
So here's just the base function: def xCollision(self): for tile in tiles: if tile.colliderect(self.rect): if self.x_vel >= 1: self.rect.right = tile.left elif self.x_vel <= -1: self.rect.left = tile.right def yCollision(self): for tile in tiles: if tile.colliderect(self.rect): if self.y_vel >= 1: self.rect.bottom = tile.top elif self.y_vel <= -1: self.rect.top = tile.bottom This is inside the Player class. Now, when i try this my frames go down to around 4 fps and it also isn't working. About it not working it has to do something with the self.rect.something = tile.something because when i replace it with print() it prints whatever. Here is the entire code for reference, And yes i just started out so don't think its gonna be any good ok? import pygame import random import math import time # Initialize Pygame pygame.init() pygame.mixer.init() # Set the size of the window size = (900, 600) screen = pygame.display.set_mode(size) # Set the title of the window pygame.display.set_caption("Classes testing") clock = pygame.time.Clock() fps = 60 pygame.mixer.music.load('PewPewProject/Retro Platform.wav') pygame.mixer.music.set_volume(0.1) pygame.mixer.music.play(-1) pop_sound = pygame.mixer.Sound("PewPewProject/vine-boom.wav") pop_sound.set_volume(0.5) level = [ ['1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'], ['1','E','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1'], ['1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1'], ['1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','E','0','0','0','1'], ['1','0','0','0','1','1','1','0','0','0','0','0','0','0','0','0','0','0','0','1'], ['1','0','0','0','0','1','0','0','0','0','0','0','0','0','0','0','0','0','0','1'], ['1','0','0','1','0','1','0','0','0','0','0','0','0','0','E','0','0','0','0','1'], ['1','0','0','1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1'], ['1','E','1','1','1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1'], ['1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1'], ['1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1'], ['1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1'], ['1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1'], ['1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1'], ['1','0','0','0','0','0','0','0','0','E','0','0','0','0','0','0','0','0','0','1'], ['1','0','0','0','0','0','0','0','0','1','1','1','0','1','0','0','0','0','0','1'], ['1','0','0','0','0','0','0','0','0','1','0','0','0','1','0','0','0','0','0','1'], ['1','0','0','0','0','0','0','0','0','1','0','1','1','1','0','E','0','0','0','1'], ['1','0','0','0','0','0','0','0','0','1','0','1','S','1','0','0','0','0','0','1'], ['1','0','0','0','0','0','0','0','0','1','0','0','0','1','0','0','0','0','0','1'], ['1','0','0','E','0','0','0','0','0','1','1','1','1','1','0','0','0','0','0','1'], ['1','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','1'], ['1','0','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','1'], ] tilex, tiley = [0, 0] tilex_offset, tiley_offset = [0, 0] tile_size = 50 tilemap = pygame.image.load('PewPewProject/tilemap.png') tiles = [] collision_tiles = [] enemy_spawns = [] def Build_Level(): global tiley,tilex tiley = -1 for rows in level: tilex = -1 tiley += 1 for tile in rows: tilex += 1 if tile == '1': tile_rect = pygame.draw.rect(screen, (100, 100, 100), (tilex*tile_size+tilex_offset, tiley*tile_size+tiley_offset, tile_size, tile_size)) tiles.append(tile_rect) elif tile == '0': pass elif tile == 'E': enemy_spawns.append([tilex, tiley]) elif tile == 'S': pygame.draw.rect(screen, (50, 255, 100), (tilex*tile_size+tilex_offset, tiley*tile_size+tiley_offset, tile_size, tile_size)) elif tile == 'R': pygame.draw.rect(screen, (255, 50, 50), (tilex*tile_size+tilex_offset, tiley*tile_size+tiley_offset, tile_size, tile_size)) else: print("Wrong Map Input") def random_except(start, end, exception_start, exception_end): num = random.randint(start, end) while num >= exception_start and num <= exception_end: num = random.randint(start, end) return num class Player: def __init__(self, health, speed, x, y, size, healthboost, collision_tiles): self.speed = speed self.x = x self.y = y self.y_vel = 0 self.x_vel = 0 self.size = size self.hitbox = pygame.draw.rect(screen, (230, 100, 100), (self.x, self.y, self.size, self.size)) self.gunsurface = pygame.Surface((90, 25), pygame.SRCALPHA) self.healthboost = healthboost self.health = health * healthboost self.rotated_gunsurface = self.gunsurface self.gunsurface.fill((150, 150, 150)) self.gunrect = self.gunsurface.get_rect() self.rect = self.hitbox self.projectiles = [Projectile(-100, 0, 0)] self.last_shot_time = 0 self.cooldown = 0.5 self.is_slowed = False self.alive = True def xCollision(self): for tile in tiles: if tile.colliderect(self.rect): if self.x_vel >= 1: self.rect.right = tile.left elif self.x_vel <= -1: self.rect.left = tile.right def yCollision(self): for tile in tiles: if tile.colliderect(self.rect): if self.y_vel >= 1: self.rect.bottom = tile.top elif self.y_vel <= -1: self.rect.top = tile.bottom def Render(self): self.rect = pygame.draw.rect(screen, (230, 100, 100), (self.x, self.y, self.size, self.size)) self.Gun() def Alive(self): if self.health <= 0: self.alive = False def GUI(self): self.empty_health_bar = pygame.draw.rect(screen, (200, 20, 20), (screen.get_width()/4, 10,466, 25)) self.health_bar = pygame.draw.rect(screen, (20, 200, 20), (screen.get_width()/4, 10, self.health*4.66/self.healthboost, 25)) pygame.draw.line(screen, (0, 0, 0), (screen.get_width()/4, 10),(screen.get_width()/4+466, 10), 2) pygame.draw.line(screen, (0, 0, 0), (screen.get_width()/4, 35),(screen.get_width()/4+466, 35), 2) pygame.draw.line(screen, (0, 0, 0), (screen.get_width()/4, 10), (screen.get_width()/4, 35), 2) pygame.draw.line(screen, (0, 0, 0), (screen.get_width()/4+466, 10), (screen.get_width()/4+466, 35), 2) def Gun(self): cursor_x, cursor_y = pygame.mouse.get_pos() dx = cursor_x - (self.x + self.size) dy = cursor_y - (self.y + self.size) angle = math.atan2(dy, dx) self.rotated_gunsurface = pygame.transform.rotate(self.gunsurface, math.degrees(angle * -1)) self.gunrect = self.rotated_gunsurface.get_rect(center = (self.x+self.size/2, self.y+self.size/2)) screen.blit(self.rotated_gunsurface, (self.gunrect.x, self.gunrect.y)) def Shoot(self): if pygame.key.get_pressed()[pygame.K_e]: current_time = time.time() if current_time - self.last_shot_time > self.cooldown: pop_sound.play() cursor_x, cursor_y = pygame.mouse.get_pos() dx = cursor_x - (self.x + self.size/2) dy = cursor_y - (self.y + self.size/2) angle = math.atan2(dy, dx) self.projectiles.append(Projectile(self.x+self.size/2, self.y+self.size/2, angle)) self.last_shot_time = current_time self.cooldown = 0.1 def Movement(self): global tiley_offset, tilex_offset keys = pygame.key.get_pressed() if self.x >= screen.get_width()-100-self.size: # Move to the RIGHT if keys[pygame.K_d]: tilex_offset -= self.speed if keys[pygame.K_a]: self.x_vel = -self.speed if not self.y <= 100: if keys[pygame.K_w]: self.y_vel = -self.speed else: if keys[pygame.K_w]: tiley_offset += self.speed if not self.y >= screen.get_height()-100-self.size: if keys[pygame.K_s]: self.y_vel = self.speed else: if keys[pygame.K_s]: tiley_offset -= self.speed elif self.x <= 100: # Move to the LEFT if keys[pygame.K_a]: tilex_offset += self.speed if keys[pygame.K_d]: self.x_vel = self.speed if not self.y <= 100: if keys[pygame.K_w]: self.y_vel = -self.speed else: if keys[pygame.K_w]: tiley_offset += self.speed if not self.y >= screen.get_height()-100-self.size: if keys[pygame.K_s]: self.y_vel = self.speed else: if keys[pygame.K_s]: tiley_offset -= self.speed elif self.y >= screen.get_height()-100-self.size: # Move DOWN if keys[pygame.K_s]: tiley_offset -= self.speed if keys[pygame.K_w]: self.y_vel = -self.speed if keys[pygame.K_a]: self.x_vel =- self.speed if keys[pygame.K_d]: self.x_vel = self.speed elif self.y <= 100: # Move UP if keys[pygame.K_w]: tiley_offset += self.speed if keys[pygame.K_s]: self.y_vel = self.speed if keys[pygame.K_a]: self.x_vel = -self.speed if keys[pygame.K_d]: self.x_vel = self.speed else: # Default Movement if keys[pygame.K_w]: self.y_vel = -self.speed if keys[pygame.K_s]: self.y_vel = self.speed if keys[pygame.K_a]: self.x_vel = -self.speed if keys[pygame.K_d]: self.x_vel = self.speed self.x += self.x_vel self.xCollision() self.y += self.y_vel self.yCollision() self.y_vel = 0 self.x_vel = 0 class Projectile: def __init__(self, x, y, angle): self.x = x self.y = y self.angle = angle self.speed = 8 self.hitbox = pygame.Rect(self.x, self.y, 5,5) def Move(self): self.x += math.cos(self.angle) * self.speed self.y += math.sin(self.angle) * self.speed def Render(self): self.hitbox = pygame.draw.circle(screen, (255, 255, 0), (int(self.x), int(self.y)), 7) class Enemy: def __init__(self, health, main_speed, tag, size, player, x, y): self.health = health self.main_speed = 3 self.tag = tag self.size = size self.player = player self.speed = 3 self.x = x self.y = y self.alive = True def Destroy(self): self.alive = False def Spawning(self): self.hitbox = pygame.draw.rect(screen, (100, 240, 100), (self.x + tilex_offset, self.y + tiley_offset, self.size, self.size)) def Movement(self): dx = self.player.x - self.x dy = self.player.y - self.y angle = math.atan2(dy - tiley_offset, dx - tilex_offset) self.x += self.speed * math.cos(angle) self.y += self.speed * math.sin(angle) def main(): player = Player(100, 3, screen.get_width()/2-50, screen.get_height()/2-50, 50, 1, tiles) enemies = [] def Spawn_enemies(num_enemies, player): for i in range(num_enemies): x, y = random.choice(enemy_spawns) enemy = Enemy(1, 1, i, 25, player, x*tile_size, y*tile_size) enemies.append(enemy) print(x, y) running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # Main Loop screen.fill((100, 100, 200)) # usage spawn_enemies_chance = random.randint(0, 200) number_of_enemies = len(enemies) if spawn_enemies_chance == 1 and number_of_enemies <= 4: Spawn_enemies(1,player) Build_Level() # enemy for enemy in enemies: if enemy.alive: enemy.Movement() enemy.Spawning() for projectile in player.projectiles: if enemy.hitbox.colliderect(projectile.hitbox): enemy.health -= 1 pop_sound.play() if enemy.health <= 0: enemy.alive = False enemies.remove(enemy) player.projectiles.remove(projectile) keys = pygame.key.get_pressed() if keys[pygame.K_LSHIFT]: # Slow things down by 3 times player.is_slowed = True for enemy in enemies: enemy.speed = enemy.main_speed / 3 for projectile in player.projectiles: projectile.speed = 2.6 player.speed = 1 player.cooldown = 1.5 spawn_enemies_chance = random.randint(0, 1500) else: player.is_slowed = False for enemy in enemies: enemy.speed = enemy.main_speed for projectile in player.projectiles: projectile.speed = 8 player.speed = 3 player.cooldown = 0.5 spawn_enemies_chance = random.randint(0, 500) # Get Hurt for enemy in enemies: if enemy.hitbox.colliderect(player): player.health -= 10 enemies.remove(enemy) # Projectiles for i, projectile in enumerate(player.projectiles): projectile.Move() projectile.Render() if projectile.x < 0 or projectile.x > screen.get_width() or projectile.y < 0 or projectile.y > screen.get_height(): player.projectiles.pop(i) # player player.Alive() player.Movement() player.Shoot() player.Render() # Renders the UI ontop of everything player.GUI() pygame.display.update() clock.tick(fps) pygame.quit() # DO NOT DISTURB! if __name__ == "__main__": main() I honestly don't know why its not working but i think i know why its lagging. It has to check for collision with every tile every single frame which causes some lag if you have a big map i belive, that's just my thought tho.
The actual problem is not the collision detection, but that Build_Level is called in the application loop. Therefore the tiles and enemy_spawns list contain more and more elements over time and your code gets slower and slower. To solve your problem, separate the function into two functions, build_level and draw_level. Call build_level before the application loop, but draw_level in the application loop: def build_level(): for tiley, rows in enumerate(level): for tilex, tile in enumerate(rows): if tile == '1': tile_rect = pygame.Rect(tilex*tile_size+tilex_offset, tiley*tile_size+tiley_offset, tile_size, tile_size) tiles.append(tile_rect) elif tile == '0': pass elif tile == 'E': enemy_spawns.append([tilex, tiley]) elif tile == 'S': pass elif tile == 'R': pass else: print("Wrong Map Input") def draw_level(): for tiley, rows in enumerate(level): for tilex, tile in enumerate(rows): color = None if tile == '1': color = (100, 100, 100) elif tile == 'S': color = (50, 255, 100) elif tile == 'R': color = (255, 50, 50) if color: pygame.draw.rect(screen, color, (tilex*tile_size+tilex_offset, tiley*tile_size+tiley_offset, tile_size, tile_size)) def main(): # [...] build_level() running = True while running: # [...] draw_level()
Object to shoot a projectile
I'm trying to make my tanks shoot, and I did all the code I think I should have done but I don't know why the tanks aren't shooting anything. import pygame, assetloader from pygame.locals import * import random, time, math import pygame GRAD = math.pi/180 blue = (0, 0, 255) wallRects = [] bullets = [] maze = [[] for i in range(25)] assetloader.set_asset_path("assets/") I defined the Bullet Class here: def calculate_dir_with_angle(angle): direction = [0, 0] if (angle > 0 and angle < 180) or (angle > -360 and angle < -180): direction[0] = -1 elif (angle > -180 and angle < 0) or (angle > 180 and angle < 360): direction[0] = 1 elif (angle > -90 and angle < 90) or (angle > 270 and anlge < 360): direction[1] = -1 elif (angle > 90 and angle < 270) or (angle > -270 and angle < -90): direction[1] = 1 return direction class Bullet: def __init__(self, pos, r, angle): self.x = pos[0] self.y = pos[1] self.r = r self.counter = 50 direction = calculate_dir_with_angle(angle) self.vel = [direction[0] * 2, direction[1] * 2] def draw(self, screen): self.x = int(self.x) self.y = int(self.y) pygame.draw.circle(screen, (25, 25, 25), (self.x, self.y), (self.r)) def move(self): self.x += self.vel[0] self.y += self.vel[1] self.rect = pygame.Rect(self.x-self.r, self.y - self.r, 2 * self.r, 2 * self.r) for wr in wallRects: if self.rect.centery >= wr.top and self.rect.centery <= wr.bottom: if self.rect.left <= wr.right and self.rect.left > wr.left: self.vel[0] = -self.vel[0] self.x = wr.right + self.r + 1 self.rect.x = wr.right + 1 elif self.rect.right >= wr.left and self.rect.right < wr.right: self.vel[0] = -self.vel[0] self.x = wr.left + self.r - 1 self.rect.x = wr.left - 2 * self.r - 1 if self.rect.centerx >= wr.left and self.rect.centerx <= wr.right: if self.rect.top <= wr.bottom and self.rect.top > wr.top: self.vel[1] = -self.vel[1] self.y = wr.bottom + self.r + 1 self.rect.y = wr.bottom + 1 elif self.rect.bottom >= wr.top and self.rect.bottom < wr.bottom: self.vel[1] = -self.vel[1] self.y = wr.top - self.r - 1 self.rect.y = wr.top - 2 * self.r - 1 if self.counter > 0: self.counter -= 1 def generateRandomPosition(): row = random.randint(1, 23) col = random.randint(1, 23) while maze[row][col-1] != 0 or maze[row][col] != 0 or maze[row][col+1] != 0: row = random.randint(1, 23) col = random.randint(1, 23) return row, col Player 1: class Player(pygame.sprite.Sprite): def __init__(self, x, y, pos): pygame.sprite.Sprite.__init__(self) self.image, self.rect = assetloader.load_image("Tank.png", -1) self.rect.x = x self.rect.y = y self.rect.clamp_ip(screen.get_rect()) self.rows = pos[0] self.cols = pos[1] self.x = self.cols * gsize self.y = self.rows * gsize self.orig_image, self.orig_rect = assetloader.load_image("Tank.png", -1) self.orig_rect.x = self.x self.orig_rect.y = self.y self.orig_gun_pos = self.orig_rect.midtop self.ammo = 5 def checkCollisions(self): for b in bullets: if b.counter <= 0: if b.rect.colliderect(self.orig_rect): self.dead = True def calculate_gun_pos(self): self.orig_gun_pos = self.orig_rect.midtop new_y = self.orig_gun_pos[1] - self.orig_rect.centery new_x = self.orig_gun_pos[0] - self.orig_rect.centerx rads = self.dir * GRAD gun_x = (new_y * math.sin(rads)) + (new_x * math.cos(rads)) + (self.orig_rect.centerx) gun_y = (new_y * math.cos(rads)) - (new_x * math.sin(rads)) + (self.orig_rect.centery) self.gun_pos = (gun_x, gun_y) def shoot(self): if self.ammo > 0: self.calculate_gun_pos() b = Bullet(self.gun_pos, 3, self.dir) bullets.append(b) self.ammo -= 1 def draw(self, screen): image = pygame.transform.rotate(self.image, self.dir) screen.blit(image, self.rect) def update(self): oldCenter = self.rect.center self.rect = self.image.get_rect() self.rect.center = oldCenter screen_rect = screen.get_rect() keys = pygame.key.get_pressed() if keys[K_m]: p.shoot() if not screen_rect.contains(self.rect): self.rect.clamp_ip(screen_rect) Calling the functions: size = width, height = 500, 400 gsize = 25 start_x, start_y = 0, 0 bgColor = 255, 255, 255 pygame.init() screen = pygame.display.set_mode(size)#, pygame.FULLSCREEN) pygame.display.set_caption("Sample Sprite") clock = pygame.time.Clock() p = Player(width/2, height/4, (3,4)) coll_font = pygame.font.Font(None, 30) going = True while going: clock.tick(60) for event in pygame.event.get(): if event.type == QUIT: going = False elif event.type == KEYDOWN: if event.key == K_ESCAPE: going = False elif event.type == KEYDOWN: if event.key == K_m: p.shoot() for b in bullets: b.move() p.update() screen.fill(bgColor) p.draw(screen) pygame.display.flip() pygame.quit() How would I call the bullet to actually appear and fire because I have the Bullet class which gets called within the Player class in def shoot(self) so does anyone have an idea why the bullets aren't appearing?
I usually add bullets in this way: I pass the group that contains all sprites and the bullet group to the player instance and add new bullets to these group in the player's handle_event method. import pygame as pg from pygame.math import Vector2 pg.init() screen = pg.display.set_mode((640, 480)) screen_rect = screen.get_rect() FONT = pg.font.Font(None, 24) BG_COLOR = pg.Color('gray12') BULLET_IMAGE = pg.Surface((20, 11), pg.SRCALPHA) pg.draw.polygon( BULLET_IMAGE, pg.Color('aquamarine1'), [(0, 0), (20, 5), (0, 11)]) PLAYER_IMAGE = pg.Surface((50, 30), pg.SRCALPHA) pg.draw.polygon( PLAYER_IMAGE, pg.Color('dodgerblue1'), [(0, 0), (50, 15), (0, 30)]) class Player(pg.sprite.Sprite): def __init__(self, pos, all_sprites, bullet_group): super().__init__() self.image = PLAYER_IMAGE self.orig_image = self.image # Needed to preserve image quality. self.rect = self.image.get_rect(center=(pos)) self.pos = Vector2(pos) self.vel = Vector2(1, 0) self.angle = 0 self.angle_speed = 0 self.all_sprites = all_sprites self.bullet_group = bullet_group def handle_event(self, event): if event.type == pg.MOUSEBUTTONDOWN: # Left button fires a bullet from cannon center with # current angle. Add the bullet to the bullet_group. if event.button == 1: bullet = Bullet(self.pos, self.angle) self.bullet_group.add(bullet) self.all_sprites.add(bullet) elif event.type == pg.KEYDOWN: # Rotate self by setting the .angle_speed. if event.key in (pg.K_a, pg.K_LEFT): self.angle_speed = -3 elif event.key in (pg.K_d, pg.K_RIGHT): self.angle_speed = 3 elif event.type == pg.KEYUP: if event.key in (pg.K_a, pg.K_LEFT): self.angle_speed = 0 elif event.key in (pg.K_d, pg.K_RIGHT): self.angle_speed = 0 def update(self): self.pos += self.vel self.rect.center = self.pos if self.angle_speed != 0: self.rotate() def rotate(self): # Update the angle and the velocity vector. self.angle += self.angle_speed self.vel.rotate_ip(self.angle_speed) # Rotate the image and get a new rect with the previous center. self.image = pg.transform.rotozoom(self.orig_image, -self.angle, 1) self.rect = self.image.get_rect(center=self.rect.center) class Bullet(pg.sprite.Sprite): def __init__(self, pos, angle): super().__init__() self.image = pg.transform.rotate(BULLET_IMAGE, -angle) self.rect = self.image.get_rect(center=pos) # To apply an offset (40 pixels) to the start position, # create another vector and rotate it as well. offset = Vector2(40, 0).rotate(angle) # Add the offset vector to the position vector (the center). self.pos = Vector2(pos) + offset # Rotate the start velocity vector (9, 0) by the angle. self.vel = Vector2(9, 0).rotate(angle) def update(self): # Add the velocity to the pos to move the sprite. self.pos += self.vel self.rect.center = self.pos # Update the rect as well. # Remove bullets outside of the screen area. if not screen_rect.contains(self.rect): self.kill() def main(): clock = pg.time.Clock() all_sprites = pg.sprite.Group() # Bullets will be added to this group. bullet_group = pg.sprite.Group() # Pass the bullet group to the player. player = Player((300, 200), all_sprites, bullet_group) all_sprites.add(player) playing = True while playing: for event in pg.event.get(): if event.type == pg.QUIT: playing = False # Pass events to the player instance. player.handle_event(event) all_sprites.update() screen.fill(BG_COLOR) all_sprites.draw(screen) pg.display.update() clock.tick(30) if __name__ == '__main__': main() pg.quit()
IndexError: list index out of range, snake game
''' Created on 13.3.2016 worm game #author: Hai ''' import pygame import random from pygame import * ## class Worm: def __init__(self, surface): self.surface = surface self.x = surface.get_width() / 2 self.y = surface.get_height() / 2 self.length = 1 self.grow_to = 50 self.vx = 0 self.vy = -1 self.body = [] self.crashed = False self.color = 255, 255, 0 def key_event(self, event): """ Handle keyboard events that affect the worm. """ if event.key == pygame.K_UP and self.vy != 1: self.vx = 0 self.vy = -1 elif event.key == pygame.K_RIGHT and self.vx != -1: self.vx = 1 self.vy = 0 elif event.key == pygame.K_DOWN and self.vy != -1: self.vx = 0 self.vy = 1 elif event.key == pygame.K_LEFT and self.vx != 1: self.vx = -1 self.vy = 0 def move(self): """ Moving worm """ self.x += self.vx # add vx to x self.y += self.vy if (self.x, self.y) in self.body: self.crashed = True self.body.insert(0, (self.x, self.y)) # Changes worm to right size so it is grow_to if self.grow_to > self.length: self.length += 1 # If body is longer than length then pop if len(self.body) > self.length: self.body.pop() """ def draw(self): self.surface.set_at((int(self.x), int(self.y)), (255, 255, 255)) self.surface.set_at((int(self.last[0]),int(self.last[1])), (0,0,0)) """ def position(self): return self.x, self.y def eat(self): self.grow_to += 25 def draw(self): x, y = self.body[0] self.surface.set_at((int(x), int(y)), self.color) x, y = self.body[-1] self.surface.set_at((int(x), int(y)), (0, 0, 0)) # for x, y in self.body: # self.surface.set_at((int(x), int(y)), self.color) # pygame.draw.rect(self.surface, self.color, (self.x, self.y, 6, 6), 0) # worm's head class Food: def __init__(self, surface): self.surface = surface self.x = random.randint(0, surface.get_width()) self.y = random.randint(0, surface.get_height()) self.color = 255,255,255 def draw(self): self.surface.set_at((int(self.x),int(self.y)), self.color) pygame.draw.rect(self.surface, self.color, (self.x, self.y, 6, 6), 0) def position(self): return self.x, self.y """ Check if worm have eaten this food """ def check(self, x, y): if x < self.x or x > self.x + 6: return False elif y < self.y or y > self.y + 6: return False else: return True def erase(self): pygame.draw.rect(self.surface, (0,0,0), (int(self.x), int(self.y), 6, 6), 0) w = h = 500 screen = pygame.display.set_mode((w, h)) clock = pygame.time.Clock() pygame.mixer.init() chomp = pygame.mixer.Sound("bow.wav") score = 0 worm = Worm(screen) ### food = Food(screen) running = True while running: # screen.fill((0, 0, 0)) optimized in worm draw() worm.draw() food.draw() worm.move() if worm.crashed or worm.x <= 0 or worm.x >= w-1 or worm.y <= 0 or worm.y >= h-1: print("U lose") running = False elif food.check(worm.x, worm.y): worm.eat() food.erase() chomp.play() score += 1 print("Score is: %d" % score) food = Food(screen) for event in pygame.event.get(): if event.type == pygame.QUIT: # Pressed X running = False elif event.type == pygame.KEYDOWN: # When pressing keyboard worm.key_event(event) pygame.display.flip() clock.tick(100) hello i am getting error x, y = self.body[0] IndexError: list index out of range and i am doing this tutorial: https://lorenzod8n.wordpress.com/2008/03/01/pygame-tutorial-9-first-improvements-to-the-game/ I am very new to python, plz help me
The problem is that in your class's __init__ function, you define self.body = []. This means that the list contains 0 items. Later in your code, you reference self.body[0] and self.body[1], which are the first and second items in the list. Since these do not exist, an error is raised. To fix this, you need to initialize self.body with two items.
Based on the order of the operations you are doing, your body list is actually still empty. Follow the logic of your code, and you will see. You start by instantiating your worm here: worm = Worm(screen) ### So, if you look at the __init__ of Worm, you are setting self.body to an empty list []. If you follow all the code that happens from then until you actually call: worm.draw() You are never actually inserting anything on to your body list. So, when you try to access your body list inside your draw method: error x, y = self.body[0] You are definitely going to get an index out of range error, since there is nothing to access. To rectify this you need to either provide a default like: # arbitrary data self.body = [0, 0] Or, determine in your draw method how to handle empty lists using some condition like: if self.body: # do things
In your Worm's __init__ function you can set self.body[] to self.body[(0, 0)], this works. The error is raised because you defined an empty list at the beginning and later you tried to get an item from the list by passing an index (self.body[0]). But because the list is empty, Python cannot get the asked value. Hope this helps!
Python/Pygame Trouble with Game loop/Getting code to run
For the past few days I've been working on this code for pong and I've almost got it running. Everything works up to the movement of the objects. The screen just freezes when the pygame window opens. There seems to be something wrong in my main() but I am still fairly new to python/pygame and am lost as to what is wrong. import pygame, sys pygame.init() SCR_WID, SCR_HEI = 640, 480 class Player(): def __init__(self): self.x, self.y = 16, SCR_HEI/2 self.x1, self.y1 = SCR_WID-16, SCR_HEI/2 self.speed = 3 self.padWid, self.padHei = 8, 64 self.score = 0 self.scoreFont = pygame.font.Font("imagine_font.ttf", 64) def scoring(self): scoreBlit = self.scoreFont.render(str(self.score), 1, (0,0,0)) screen.blit(scoreBlit, (32, 16)) if self.score == 10: print ("player 1 wins!") exit() def scoring1(self): scoreBlit = self.scoreFont.render(str(self.score), 1, (0,0,0)) screen.blit(scoreBlit, (SCR_HEI+92, 16)) if self.score == 10: print ("Player 2 wins!") exit() def movement(self): keys = pygame.key.get_pressed() if keys[pygame.K_w]: self.y -= self.speed elif keys[pygame.K_s]: self.y += self.speed if self.y <= 0: self.y = 0 elif self.y >= SCR_HEI-64: self.y = SCR_HEI-64 keys1 = pygame.key.get_pressed() if keys1[pygame.K_UP]: self.y1 -= self.speed elif keys1[pygame.K_DOWN]: self.y1 += self.speed if self.y1 <= 0: self.y1 = 0 elif self.y >= SCR_HEI-64: self.y1 = SCR_HEI-64 def draw(self): pygame.draw.rect(screen, (0,0,0), (self.x, self.y, self.padWid, self.padHei)) pygame.draw.rect(screen, (0,0,0), (self.x1, self.y1, self.padWid, self.padHei)) class Ball(): def __init__(self): self.x, self.y = SCR_WID/2, SCR_HEI/2 self.x1, self.y1 = SCR_WID/2, SCR_HEI/2 self.speed_x = -3 self.speed_y = 3 self.size = 8 def movement(self): self.x += self.speed_x self.y += self.speed_y if self.y <= 0: self.speed_y *= -1 elif self.y >= SCR_HEI-self.size: self.speed_y *= -1 if self.x <= 0: self.__init__() enemy.score += 1 elif self.x >= SCR_WID-self.size: self.__init__() self.speed_x = 3 player.score += 1 for n in range(-self.size, player.padHei): if self.y == player.y + n: if self.x <= player.x + player.padWid: self.speed_x *= -1 break n += 1 self.x1 += self.speed_x self.y1 += self.speed_y if self.y1 <= 0: self.speed_y *= -1 elif self.y1 >= SCR_HEI-self.size: self.speed_y *= -1 if self.x1 <= 0: self.__init__() enemy.score += 1 elif self.x1 >= SCR_WID-self.size: self.__init__() self.speed_x = 3 player.score += 1 for n in range(-self.size, enemy.padHei): if self.y1 == enemy.y1 + n: if self.x1 >= enemy.x1 - enemy.padWid: self.speed_x *= -1 break n += 1 def draw(self): pygame.draw.rect(screen, (112,138,144), (self.x, self.y, 8, 8)) SCR_WID, SCR_HEI = 640, 480 screen = pygame.display.set_mode((SCR_WID, SCR_HEI)) player = Player() ball = Ball() enemy = Player() def main(): running = True while running == True: for event in pygame.event.get(): if event.type == pygame.QUIT: print ("Game exited by user") exit() else: running = False pygame.font.init() clock = pygame.time.Clock() FPS = 60 backgroundimage = pygame.image.load("background.png") pygame.display.set_caption("Justin's pong") ball.movement() player.movement() enemy.movement() position = (0,0) screen.fill((0, 0, 0)) screen.blit(backgroundimage, position) ball.draw() player.draw() player.scoring() enemy.draw() enemy.scoring1() pygame.display.flip() clock.tick(FPS) main()
The problem is this code: running = True while running == True: for event in pygame.event.get(): if event.type == pygame.QUIT: print ("Game exited by user") exit() else: running = False You are correctly getting the events, but if there aren't any events (as there aren't in the beginning), you will run forever, checking for events. I assume you want the rest of your code to run in the while loop as well, so you should indent it.
Pygame, keep jumping and glitching through the "ground"
My character won't jump properly, he keeps glitching through the ground. If i hold key up, my character won't stop going higher. Do you have some ideas for how I could fix it? import pygame,sys from pygame.locals import * pygame.init() screen = pygame.display.set_mode((1200, 800)) screen.fill((0,0,0)) pygame.display.set_caption('Jump and Run') BLACK = (0,0,0) WHITE = (250, 250,250) RED = (250, 0, 0) BLUE = (0,0,250) direction = 'right' way = 0 jump_high = 0 class Hero(): def __init__(self, x, y): self.x = x self.y = y self.image = pygame.image.load('hero.bmp') self.groundcontact = True self.vy = 0 alive = True def check_pos(self): if self.y >= 400: self.groundcontact = True elif self.y <= 400: self.groundcontact = False def load_picture(self,surface): surface.blit(self.image,(self.x, self.y)) def check_input(self): key = pygame.key.get_pressed() if key[pygame.K_RIGHT]: self.x += 10 elif key[pygame.K_LEFT]: self.x -= 10 elif key[pygame.K_UP]: self.y -= 50 if not self.groundcontact: self.vy += 1 #max(min(2,200), -200) #self.y += self.vy print "not self.groundcontact" else: self.vy = 0 #self.y += self.vy self.y += self.vy class Monster(): def __init__(self, x, y): self.x = x self.y = y self.image = pygame.image.load('monster.bmp') self.collision = False self.alive = True def load_picture(self,surface): surface.blit(self.image,(self.x, self.y)) def walk(self): global direction global way if direction == "right": self.x += 4 way += 1 if way == 100: direction = "left" elif direction == "left": self.x -= 4 way -= 1 if way == 0: direction = "right" monster2 = Monster( 200, 333) monster1 = Monster(400, 450) hero = Hero(0, 400) clock = pygame.time.Clock() pygame.draw.rect(screen, WHITE,(0,500, 1200, 50)) while True: for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() hero.check_pos() monster1.walk() monster2.walk() hero.check_input() screen.fill(BLACK) hero.load_picture(screen) monster1.load_picture(screen) monster2.load_picture(screen) pygame.draw.rect(screen, WHITE,(0,500, 1200, 50)) pygame.display.update() clock.tick(40)
Regarding my comment above, changing the Hero class to somthing like this: JUMP_POWER = 10 class Hero(): ... def check_input(self): key = pygame.key.get_pressed() ... elif key[pygame.K_UP]: if self.groundcontact: self.vy -= JUMP_SPEED