In my code, my sprite can move in an x-axis left and right. However, it can go off the screen. I would like to prevent it from going outside the screen. I don't know how to do that I have tried writing:
if event.key == pygame.K_LEFT and player.rect.x > 0:
#player moves left
But it didn't work out. The player sprite just runs out of the screen and I can't make it come back. I'm open to all suggestions. Thanks in advance! I separated my code into three different files --> main.py:
import pygame
import os
import sys
import time
from pygame import mixer
from Sprite1 import *
from settings import *
'''
Setup
'''
pygame.init()
clock = pygame.time.Clock()
all_sprites = pygame.sprite.Group()
player = Player(all_sprites)
player.rect.x = 100
player.rect.y = 500
enemy_list = pygame.sprite.Group() # create enemy group
enemy = Enemy(enemy_list)# spawn enemy
enemy.rect.x = 400
enemy.rect.y = 470
showStartScreen(surface)
x = 0
'''
Main loop
'''
main = True
while main == True:
background = pygame.image.load(os.path.join('images', 'Bg.png')).convert()
font = pygame.font.Font('freesansbold.ttf', 32)
text = font.render('Health:', True, BLACK, surface)
textRect = text.get_rect()
textRect.center = (60, 30)
rel_x = x % background.get_rect().width
surface.blit(background, (rel_x - background.get_rect().width, 0))
if rel_x < width:
surface.blit(background, (rel_x, 0))
if player.rect.x >= 560:
x -= 10
elif player.rect.x <= 400:
x += 10
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
main = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.control(-steps,0)
if event.key == pygame.K_RIGHT:
player.control(steps,0)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.control(steps,0)
if event.key == pygame.K_RIGHT:
player.control(-steps,0)
keys = pygame.key.get_pressed()
if not(isJump):
if keys[pygame.K_UP]:
isJump = True
else:
if jumpCount >= -10:
player.rect.y -= (jumpCount * abs(jumpCount)) * 1
jumpCount -= 2
else:
jumpCount = 10
isJump = False
if player.rect.y > width:
go_screen(surface)
surface.blit(text, textRect)
# dt = time since last tick in milliseconds.
dt = clock.tick(60) / 1000
all_sprites.update(dt, enemy_list)
player.update(dt, enemy_list)
enemy_list.update(dt, all_sprites)
all_sprites.draw(surface) #refresh player position
enemy_list.draw(surface)
for e in enemy_list:
e.move()
pygame.display.flip()
settings.py:
import pygame
isJump = False
jumpCount = 10
width = 960
height = 720
FONT_NAME = 'arial'
fps = 40 # frame rate
pygame.display.set_caption('B.S.G.')
surface = pygame.display.set_mode((width, height))
PLAYER_ACC = 0.5
PLAYER_FRICTION = -0.12
PLAYER_GRAV = 0.8
PLAYER_JUMP = 20
PLAYER_LAYER = 2
PLATFORM_LAYER = 1
BLACK = (0, 0, 0)
steps = 10 # how fast to move
Sprite1:
import pygame
import sys
import os
import time
from pygame import mixer
from pygame.locals import *
from settings import *
vec = pygame.math.Vector2
clock = pygame.time.Clock()
def showStartScreen(surface):
show = True
while (show == True):
background = pygame.image.load(os.path.join('images', 'Starting_scr.png'))
surface.blit(background, (0,0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
show = False
def go_screen(surface):
show = True
while (show == True):
background = pygame.image.load(os.path.join('images', 'GO_screen.png'))
surface.blit(background, (0,0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
pygame.quit()
sys.exit()
class Player(pygame.sprite.Sprite):
def __init__(self, all_sprites):
pygame.sprite.Sprite.__init__(self)
self.movex = 0
self.movey = 0
self.frame = 0
self.health = 100
self.jumping = False
self.images = []
self.imagesleft = []
self.imagesright = []
self.imagesdownl = []
self.imagesdownr = []
self.direction = "right"
self.alpha = (0,0,0)
self.ani = 4 # animation cycles
self.all_sprites = all_sprites
self.add(self.all_sprites)
self.fire_timer = .1
self.bullet_timer = .1
self.pos = vec(40, height - 100)
self.vel = vec(0, 0)
self.counter = 0
for i in range(1,5):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img = pygame.transform.rotate(img, -90)
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesdownl.append(img)
self.image = self.imagesdownl[0]
self.rect = self.image.get_rect()
for i in range(1,5):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img = pygame.transform.flip(img, False, True)
img = pygame.transform.rotate(img, -90)
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesdownr.append(img)
self.image = self.imagesdownr[0]
self.rect = self.image.get_rect()
for i in range(1,5):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img = pygame.transform.flip(img, True, False)
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesleft.append(img)
self.image = self.imagesleft[0]
self.rect = self.image.get_rect()
for i in range(1,5):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesright.append(img)
self.image = self.imagesright[0]
self.rect = self.image.get_rect()
def control(self,x,y):
'''
control player movement
'''
self.movex += x
self.movey -= y
def update(self, dt, enemy_list):
'''
Update sprite position
'''
self.rect.x = self.rect.x + self.movex
self.rect.y = self.rect.y + self.movey
# moving left
if self.movex < 0:
self.frame += 1
if self.frame > 3*self.ani:
self.frame = 0
self.image = self.imagesleft[self.frame//self.ani]
self.direction = "left"
# moving right
if self.movex > 0:
self.frame += 1
if self.frame > 3*self.ani:
self.frame = 0
self.image = self.imagesright[self.frame//self.ani]
self.direction = "right"
enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
for enemy in enemy_hit_list:
self.health -= 10
if self.direction == "left":
self.rect.x += 100
else:
self.rect.x -= 100
print(self.health)
if self.health <= 0:
distance = 20
speed = 10
if self.counter >= distance and self.counter <= distance*2:
self.rect.y -= speed
self.counter += 1
if self.rect.y < 291:
self.movey = 10
if self.direction == "left":
self.frame += 1
if self.frame > 3*self.ani:
self.frame = 0
self.image = self.imagesdownr[self.frame//self.ani]
if self.direction == "right":
self.frame += 1
if self.frame > 3*self.ani:
self.frame = 0
self.image = self.imagesdownl[self.frame//self.ani]
if self.rect.y > height:
self.kill()
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
self.bullet_timer -= dt # Subtract the time since the last tick.
if keys[pygame.K_x]:
self.fire_timer -= dt
if self.bullet_timer <= 0:
self.bullet_timer = 100 # Bullet ready.
if keys: # Left mouse button.
# Create a new bullet instance and add it to the groups.
if self.direction == "right":
Bullet([self.rect.x + self.image.get_width(), self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites)
else:
Bullet([self.rect.x, self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites)
self.bullet_timer = .5 # Reset the timer.
if self.fire_timer <= 0:
self.fire_timer = 100
if keys:
if self.direction == "right":
Fire([self.rect.x + 170, self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites)
else:
Fire([self.rect.x - 90, self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites)
self.fire_timer = .1
class Enemy(pygame.sprite.Sprite):
'''
Spawn an enemy
'''
def __init__(self, enemy_list):
pygame.sprite.Sprite.__init__(self)
self.movex = 0
self.movey = 0
self.health = 50
self.frame = 0
self.alpha = (0,0,0)
self.ani = 2 # animation cycles
self.enemy_list = enemy_list
self.add(self.enemy_list)
self.counter = 0 # counter variable
self.imagesleft = []
self.imagesright = []
for i in range(1,17):
img = pygame.image.load(os.path.join('images','Bot' + str(i) + '.png')).convert()
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesleft.append(img)
self.image = self.imagesleft[0]
self.rect = self.image.get_rect()
for i in range(1,17):
img = pygame.image.load(os.path.join('images','Bot' + str(i) + '.png')).convert()
img = pygame.transform.flip(img, True, False)
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesright.append(img)
self.image = self.imagesright[0]
self.rect = self.image.get_rect()
def move(self):
'''
enemy movement
'''
distance = 30
speed = 10
if self.counter >= 0 and self.counter <= distance:
self.rect.x += speed
self.frame += 1
if self.frame > 15*self.ani:
self.frame = 0
self.image = self.imagesright[self.frame//self.ani]
elif self.counter >= distance and self.counter <= distance*2:
self.rect.x -= speed
self.frame += 1
if self.frame > 15*self.ani:
self.frame = 0
self.image = self.imagesleft[self.frame//self.ani]
else:
self.counter = 0
self.counter += 1
def update(self, dt, all_sprites):
self.rect.x = self.rect.x + self.movex
self.rect.y = self.rect.y + self.movey
bullet_list = pygame.sprite.spritecollide(self, all_sprites, True)
for bullets in bullet_list:
self.health -= 10
print(self.health)
if self.health <= 0:
img = pygame.image.load(os.path.join('images','E_dead.png')).convert()
img.convert_alpha()
img.set_colorkey(self.alpha)
self.image = img
distance = 5
speed = 10
if self.counter >= 0 and self.counter <= distance:
self.rect.x += speed
elif self.counter >= distance and self.counter <= distance*2:
self.rect.x -= speed
else:
self.counter = 0
self.counter += 1
self.movey = -20
if self.rect.y < -50:
self.kill()
class Bullet(pygame.sprite.Sprite):
IMAGE = None
FLIPPED_IMAGE = None
def __init__(self, pos, direction, *sprite_groups):
super().__init__(*sprite_groups)
# cache images
if not Bullet.IMAGE:
Bullet.IMAGE = pygame.image.load(os.path.join('images','fireball.png'))
Bullet.FLIPPED_IMAGE = pygame.transform.flip(Bullet.IMAGE, True, False)
if direction == "right":
self.vel = pygame.math.Vector2(750, 0)
self.image = Bullet.IMAGE
else:
self.vel = pygame.math.Vector2(-750, 0)
self.image = Bullet.FLIPPED_IMAGE
self.pos = pygame.math.Vector2(pos)
self.rect = self.image.get_rect(center=pos)
def update(self, dt, enemy_list):
# Add the velocity to the position vector to move the sprite
self.pos += self.vel * dt
self.rect.center = self.pos # Update the rect pos.
if not pygame.display.get_surface().get_rect().colliderect(self.rect):
self.kill()
class Fire(pygame.sprite.Sprite):
IMAGE = None
FLIPPED_IMAGE = None
def __init__(self, pos, direction, *sprite_groups):
super().__init__(*sprite_groups)
# cache images
if not Fire.IMAGE:
Fire.IMAGE = pygame.image.load(os.path.join('images','fire_drag.png'))
Fire.FLIPPED_IMAGE = pygame.transform.flip(Fire.IMAGE, True, False)
if direction == "right":
self.image = Fire.IMAGE
self.vel = pygame.math.Vector2(0, 0)
else:
self.image = Fire.FLIPPED_IMAGE
self.vel = pygame.math.Vector2(0, 0)
self.pos = pygame.math.Vector2(pos)
self.rect = self.image.get_rect(center=pos)
def update(self, dt, enemy_list):
self.too = True
self.pos += self.vel * dt
self.rect.center = self.pos # Update the rect pos.
if self.too == True:
self.kill()
Thanks again!
Player.control just set the moving direction of the player, but it doesn't move the player, so it is completely useless to omit the call of plyer.control(). You have to prevent and limit the movement of the player in the method update:
class Player(pygame.sprite.Sprite):
# [...]
def update(self, dt, enemy_list):
self.rect.x += self.movex
self.rect.y += self.movey
if self.rect.left < 0:
self.rect.left = 0
elif self.rect.right > width:
self.rect.right = width
if self.rect.top < 0:
self.rect.top = 0
elif self.rect.bottom > height:
self.rect.bottom = height
# [...]
Related
I have seen this answer, and am still trying to add this answer. This IS NOT a duplicate.
I have a 20x20 grid, and the screen size is 800x640. The screen cannot see the full grid, and I want it to be able to via a scrolling camera.
However, I am not sure how I would even implement this.
The way my code works is that, in the main loop, player.update() is called to update the player's position and collision, and then an update() function is called, which redraws all sprites in the grid (to show any changes).
Code:
import pygame
from pygame.locals import *
import os
import random
import time
pygame.init()
W, Height = 800, 640
screen = pygame.display.set_mode((W,Height))
SCREEN_SIZE = pygame.Rect((0,0,W,Height))
TILE_SIZE = 48
t0 = time.time()
font = pygame.font.SysFont(None, 24)
print("Time needed to create fonts: " + str(time.time() - t0))
vec = pygame.math.Vector2
# USER CAN MODIFY
ACC = 0.5
FRIC = -0.12
FPS = 60
clock = pygame.time.Clock()
class BlueBlock(pygame.sprite.Sprite):
def __init__(self, x, y):
super(BlueBlock, self).__init__()
self.surf = pygame.Surface((48,48))
self.surf.fill((0,191,255))
self.rect = self.surf.get_rect()
self.original_surface = self.surf
self.hover_surface = self.original_surface.copy()
pygame.draw.rect(self.hover_surface, (255, 255, 0), self.hover_surface.get_rect(), 6)
self.surf = self.original_surface
self.rect = self.surf.get_rect(center = (x, y))
self.hover = False
self.mouse_pos = None
self.count = 0
def update(self):
if player.mode == "build":
mouse_pos = pygame.mouse.get_pos()
self.hover = self.rect.collidepoint(mouse_pos)
self.surf = self.hover_surface if self.hover else self.original_surface
if self.hover and mouse_pos == self.mouse_pos:
self.count += 1
if self.count > 10:
self.image = pygame.Surface((48,48))
self.image.fill((255,255,255))
class textureblock(pygame.sprite.Sprite):
def __init__(self, imagefile, x, y, type):
super(textureblock, self).__init__()
self.imagefile = imagefile
self.original_image = pygame.image.load(imagefile).convert_alpha()
self.original_image = pygame.transform.scale(self.original_image, (48,48))
self.hover_image = self.original_image.copy()
pygame.draw.rect(self.hover_image, (255, 255, 0), self.hover_image.get_rect(), 6)
self.image = self.original_image
self.rect = self.image.get_rect(center = (x, y))
self.hover = False
self.mouse_pos = None
self.count = 0
self.type = type
def update(self):
if player.mode == "build":
pygame.draw.rect(self.hover_image, (255,0,0), self.hover_image.get_rect(), 6)
elif player.mode == "destroy":
pygame.draw.rect(self.hover_image, (255, 255,0), self.hover_image.get_rect(), 6)
mouse_pos = pygame.mouse.get_pos()
self.hover = self.rect.collidepoint(mouse_pos)
self.image = self.hover_image if self.hover else self.original_image
if self.hover and mouse_pos == self.mouse_pos and player.mode == "destroy":
self.count += 1
if self.count > 10:
self.image = pygame.Surface((48,48))
self.image.fill((0,191,255))
item = Item(self.imagefile, self.rect.x, self.rect.y, self.type)
items.add(item)
self.remove(blocks)
else:
self.count = 0
self.mouse_pos = mouse_pos
class Player(pygame.sprite.Sprite):
def __init__(self):
super(Player, self).__init__()
self.surf = pygame.Surface((40,40))
self.surf.fill((255,0,0))
self.rect = self.surf.get_rect()
self.pos = vec(0,144) # Position
self.vel = vec(0,0) # Velocity
self.acc = vec(0,0) # Acceleration
self.inventory = {} # Items can be added
self.mode = "destroy" # Mode. Probably will be changed later
self.selected_item = None # Selected item
def move(self, pressed_keys):
self.acc = vec(0,0.5)
if pressed_keys[K_LEFT]:
self.acc.x = -ACC
if pressed_keys[K_RIGHT]:
self.acc.x = ACC
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos.x += self.vel.x + 0.5 * self.acc.x
self.rect.midbottom = self.pos
hit_side = False
for entity in blocks:
if self.rect.colliderect(entity.rect):
# move left and hit the block on the right
if self.vel.x < 0 and self.rect.right > entity.rect.right:
self.rect.left = entity.rect.right
self.pos.x = self.rect.centerx
hit_side = True
# move right and hit the block on the left
if self.vel.x > 0 and self.rect.left < entity.rect.left:
self.rect.right = entity.rect.left
self.pos.x = self.rect.centerx
hit_side = True
if hit_side:
self.vel.x = 0
self.acc.x = 0
def update(self):
self.acc = vec(0,0.5)
if pressed_keys[K_LEFT]:
self.acc.x = -ACC
if pressed_keys[K_RIGHT]:
self.acc.x = ACC
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos.x += self.vel.x + 0.5 * self.acc.x
self.rect.midbottom = self.pos
hit_side = False
for entity in blocks:
if self.rect.colliderect(entity.rect):
# move left and hit the block on the right
if self.vel.x < 0 and self.rect.right > entity.rect.right:
self.rect.left = entity.rect.right
self.pos.x = self.rect.centerx
hit_side = True
# move right and hit the block on the left
if self.vel.x > 0 and self.rect.left < entity.rect.left:
self.rect.right = entity.rect.left
self.pos.x = self.rect.centerx
hit_side = True
if hit_side:
self.vel.x = 0
self.acc.x = 0
hits = pygame.sprite.spritecollide(self, blocks, False)
self.pos.y += self.vel.y + 0.5 * self.acc.y
self.rect.midbottom = self.pos
for entity in blocks:
if self.rect.colliderect(entity.rect):
if self.vel.y > 0:
self.rect.bottom = entity.rect.top
self.pos.y = self.rect.bottom
self.vel.y = 0
if self.vel.y > 0:
if hits:
self.pos.y = hits[0].rect.top + 1
self.vel.y = 0
def jump(self):
self.vel.y = -15
# Item class - Spawned when a player breaks a block.
class Item(pygame.sprite.Sprite):
def __init__(self, image, x, y, type):
super(Item, self).__init__()
self.image = pygame.image.load(image).convert_alpha()
self.image = pygame.transform.scale(self.image, (24,24))
self.rect = self.image.get_rect()
self.pos = vec(x, y)
self.vel = vec(0,0)
self.acc = vec(0,0)
self.type = type
def move(self):
self.acc = vec(0,0.5)
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos.x += self.vel.x + 0.5 * self.acc.x
self.rect.midbottom = self.pos
hit_side = False
for entity in blocks:
if self.rect.colliderect(entity.rect):
# move left and hit the block on the right
if self.vel.x < 0 and self.rect.right > entity.rect.right:
self.rect.left = entity.rect.right
self.pos.x = self.rect.centerx
hit_side = True
# move right and hit the block on the left
if self.vel.x > 0 and self.rect.left < entity.rect.left:
self.rect.right = entity.rect.left
self.pos.x = self.rect.centerx
hit_side = True
if hit_side:
self.vel.x = 0
self.acc.x = 0
def update(self):
hits = pygame.sprite.spritecollide(self, blocks, False)
self.pos.y += self.vel.y + 0.5 * self.acc.y
self.rect.midbottom = self.pos
for entity in blocks:
if self.rect.colliderect(entity.rect):
if self.vel.y > 0:
self.rect.bottom = entity.rect.top
self.pos.y = self.rect.bottom
self.vel.y = 0
if self.vel.y > 0:
if hits:
self.pos.y = hits[0].rect.top + 1
self.vel.y = 0
# Now we check if we hit the Player
if self.rect.colliderect(player.rect):
# Attempt to check the player inventory
if self.type not in player.inventory.keys():
player.inventory[self.type] = 1
self.kill()
else:
player.inventory.update({self.type: player.inventory.get(self.type) + 1})
self.kill()
player = Player()
blueblock = BlueBlock(0,0)
running = True
all_sprites = pygame.sprite.Group()
blocks = pygame.sprite.Group()
items = pygame.sprite.Group()
miscBlocks = pygame.sprite.Group()
def drawGraph(graph, start):
y = start
x = 0
for item in graph:
if item == "O":
spr = BlueBlock(x, y)
spr.rect.x = x
spr.rect.y = y
all_sprites.add(spr)
miscBlocks.add(spr)
screen.blit(spr.surf, spr.rect)
x += 48
elif item == "G":
spr = textureblock("media/Grass.jpeg", x, y, "Grass")
spr.rect.x = x
spr.rect.y = y
all_sprites.add(spr)
blocks.add(spr)
screen.blit(spr.image, spr.rect)
x += 48
elif item == "S":
spr = textureblock("media/Stone.png",x,y, "Stone")
spr.rect.x = x
spr.rect.y = y
all_sprites.add(spr)
blocks.add(spr)
screen.blit(spr.image, spr.rect)
x += 48
elif item == "C":
spr = textureblock("media/Coal.jpeg",x,y, "Coal")
spr.rect.x = x
spr.rect.y = y
all_sprites.add(spr)
blocks.add(spr)
screen.blit(spr.image, spr.rect)
x += 48
elif item == "NL":
y += 48
x = 0
else:
print("Item not found: " + item)
print("[Debug] Generation finished. Amount of blocks: " + str(len(blocks.sprites())))
def randomGen(graph):
print("[Debug] Begin randomGen...")
# We assume the user has not done anything with the graph, so we add the sky and grass
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('G')
newgraph.append('NL')
# Next begins the random ore gen
for i in range(20):
x = 0
for i in range(20):
# Chance of coal - 1 in 15
iscoal = random.randint(1,15)
if iscoal == 6:
graph.append("C")
else:
graph.append("S")
x += 48
graph.append('NL')
print("[Debug] randomGen finished. Block Stats: %s air blocks, %s grass blocks, %s stone blocks, %s coal blocks, and %s newlines." % (str(graph.count('O')), str(graph.count('G')), str(graph.count('S')), str(graph.count('C')), str(graph.count('NL'))))
newgraph = []
randomGen(newgraph)
all_sprites.add(player)
def update():
for entity in all_sprites:
try:
screen.blit(entity.surf, entity.rect)
except:
screen.blit(entity.image, entity.rect)
screen.blit(player.surf, player.rect)
for entity in blocks:
screen.blit(entity.image, entity.rect)
for entity in items:
screen.blit(entity.image, entity.rect)
pygame.display.update()
drawGraph(newgraph, 0)
# Calculate the size of the level
level_width = 0
for i in newgraph:
if i != "NL":
level_width += 1
elif i == "NL":
break
level_width = level_width * TILE_SIZE
level_height = (newgraph.count("NL")-1)*TILE_SIZE
print("[Debug] Calculated level width and height: %s and %s" % (str(level_width), str(level_height)))
while running:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.jump()
if event.key == pygame.K_ESCAPE:
running = False
pygame.quit()
if event.key == pygame.K_e:
if len(player.inventory) == 0:
print("Player Inventory: Empty")
else:
print("Player Inventory: " + str(player.inventory).replace("{", "").replace("}","").replace(":", " x").replace("'",""))
if event.key == pygame.K_b:
if player.mode == "build":
player.mode = "destroy"
elif player.mode == "destroy":
player.mode = "build"
print("Changed player mode to " + player.mode)
if event.key == pygame.K_1:
player.selected_item = list(player.inventory)[0]
print("Item: " + list(player.inventory)[0])
if event.type == pygame.MOUSEBUTTONDOWN:
x,y = event.pos
if event.type == pygame.QUIT:
running = False
pygame.quit()
miscBlocks.update()
blocks.update()
blocks.draw(screen)
pressed_keys = pygame.key.get_pressed()
for entity in items:
entity.move()
# Commented out because it lagged everything.
items.update()
player.update()
update()
img1 = font.render("FPS: " + str(clock.get_fps()), True, (255,255,0))
img2 = font.render("Mode: " + player.mode, True, (255,0,0))
try:
img3 = font.render("Selected Item: " + player.selected_item, True, (0,255,0))
except Exception:
img3 = font.render("Selected Item: None", True, (0,255,0))
screen.blit(img1, (0,0))
screen.blit(img2, (0,24))
screen.blit(img3, (0,48))
pygame.display.update()
clock.tick(60)
Adding scrolling level is very easy. You just need from x take away a camera x and from y take away a camera y, for example: self.rect = self.image.get_rect(center = (x - camerax, y - cameray)).
How this is working:
Its little bit hard to answer how this works. Normaly if camerapos is always (0, 0) the map will not be scroling but if you move camera with player it will scroll. If you have a square at x 500 and you gona make camerax every second bigger by one it will move, for example: x = 500 and cameray = 100 screen will blit an image at x 400 so the image is moved, the same with the y cordinate.
How to add a camera:
So the most simple way is to create two ints or floats: cx and cy (camerax, cameray). But if you want something more modern you can do something like this:
def camera(pos):
return pos[0] - cx, pos[1] - cy
Modified code:
import pygame
from pygame.locals import *
import os
import random
import time
pygame.init()
W, Height = 800, 640
screen = pygame.display.set_mode((W,Height))
SCREEN_SIZE = pygame.Rect((0,0,W,Height))
TILE_SIZE = 48
t0 = time.time()
font = pygame.font.SysFont(None, 24)
print("Time needed to create fonts: " + str(time.time() - t0))
vec = pygame.math.Vector2
# USER CAN MODIFY
ACC = 0.5
FRIC = -0.12
FPS = 60
cx = 0
cy = 0
def camera(pos):
return pos[0] - cx, pos[1] - cy
clock = pygame.time.Clock()
class BlueBlock(pygame.sprite.Sprite):
def __init__(self, x, y):
super(BlueBlock, self).__init__()
self.surf = pygame.Surface((48,48))
self.surf.fill((0,191,255))
self.rect = self.surf.get_rect()
self.original_surface = self.surf
self.hover_surface = self.original_surface.copy()
pygame.draw.rect(self.hover_surface, (255, 255, 0), self.hover_surface.get_rect(), 6)
self.surf = self.original_surface
self.rect = self.surf.get_rect(center = (x, y))
self.hover = False
self.mouse_pos = None
self.count = 0
def update(self):
if player.mode == "build":
mouse_pos = pygame.mouse.get_pos()
self.hover = self.rect.collidepoint(mouse_pos)
self.surf = self.hover_surface if self.hover else self.original_surface
if self.hover and mouse_pos == self.mouse_pos:
self.count += 1
if self.count > 10:
self.image = pygame.Surface((48,48))
self.image.fill((255,255,255))
class textureblock(pygame.sprite.Sprite):
def __init__(self, imagefile, x, y, type):
super(textureblock, self).__init__()
self.imagefile = imagefile
self.original_image = pygame.image.load('img.png').convert_alpha()
self.original_image = pygame.transform.scale(self.original_image, (48,48))
self.hover_image = self.original_image.copy()
pygame.draw.rect(self.hover_image, (255, 255, 0), self.hover_image.get_rect(), 6)
self.image = self.original_image
self.rect = self.image.get_rect(center = (x, y))
self.hover = False
self.mouse_pos = None
self.count = 0
self.type = type
def update(self):
if player.mode == "build":
pygame.draw.rect(self.hover_image, (255,0,0), self.hover_image.get_rect(), 6)
elif player.mode == "destroy":
pygame.draw.rect(self.hover_image, (255, 255,0), self.hover_image.get_rect(), 6)
mouse_pos = pygame.mouse.get_pos()
self.hover = self.rect.collidepoint(mouse_pos)
self.image = self.hover_image if self.hover else self.original_image
if self.hover and mouse_pos == self.mouse_pos and player.mode == "destroy":
self.count += 1
if self.count > 10:
self.image = pygame.Surface((48,48))
self.image.fill((0,191,255))
item = Item(self.imagefile, self.rect.x, self.rect.y, self.type)
items.add(item)
self.remove(blocks)
else:
self.count = 0
self.mouse_pos = mouse_pos
class Player(pygame.sprite.Sprite):
def __init__(self):
super(Player, self).__init__()
self.surf = pygame.Surface((40,40))
self.surf.fill((255,0,0))
self.rect = self.surf.get_rect()
self.pos = vec(0,144) # Position
self.vel = vec(0,0) # Velocity
self.acc = vec(0,0) # Acceleration
self.inventory = {} # Items can be added
self.mode = "destroy" # Mode. Probably will be changed later
self.selected_item = None # Selected item
def move(self, pressed_keys):
self.acc = vec(0,0.5)
if pressed_keys[K_LEFT]:
self.acc.x = -ACC
if pressed_keys[K_RIGHT]:
self.acc.x = ACC
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos.x += self.vel.x + 0.5 * self.acc.x
self.rect.midbottom = self.pos
global cx, cy
cx = self.pos.x
cy = self.pos.y
hit_side = False
for entity in blocks:
if self.rect.colliderect(entity.rect):
# move left and hit the block on the right
if self.vel.x < 0 and self.rect.right > entity.rect.right:
self.rect.left = entity.rect.right
self.pos.x = self.rect.centerx
hit_side = True
# move right and hit the block on the left
if self.vel.x > 0 and self.rect.left < entity.rect.left:
self.rect.right = entity.rect.left
self.pos.x = self.rect.centerx
hit_side = True
if hit_side:
self.vel.x = 0
self.acc.x = 0
def update(self):
self.acc = vec(0,0.5)
if pressed_keys[K_LEFT]:
self.acc.x = -ACC
if pressed_keys[K_RIGHT]:
self.acc.x = ACC
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos.x += self.vel.x + 0.5 * self.acc.x
self.rect.midbottom = self.pos
global cx, cy
cx = self.pos.x - 400
cy = self.pos.y - 400
hit_side = False
for entity in blocks:
if self.rect.colliderect(entity.rect):
# move left and hit the block on the right
if self.vel.x < 0 and self.rect.right > entity.rect.right:
self.rect.left = entity.rect.right
self.pos.x = self.rect.centerx
hit_side = True
# move right and hit the block on the left
if self.vel.x > 0 and self.rect.left < entity.rect.left:
self.rect.right = entity.rect.left
self.pos.x = self.rect.centerx
hit_side = True
if hit_side:
self.vel.x = 0
self.acc.x = 0
hits = pygame.sprite.spritecollide(self, blocks, False)
self.pos.y += self.vel.y + 0.5 * self.acc.y
self.rect.midbottom = self.pos
for entity in blocks:
if self.rect.colliderect(entity.rect):
if self.vel.y > 0:
self.rect.bottom = entity.rect.top
self.pos.y = self.rect.bottom
self.vel.y = 0
if self.vel.y > 0:
if hits:
self.pos.y = hits[0].rect.top + 1
self.vel.y = 0
def jump(self):
self.vel.y = -15
# Item class - Spawned when a player breaks a block.
class Item(pygame.sprite.Sprite):
def __init__(self, image, x, y, type):
super(Item, self).__init__()
self.image = pygame.image.load('img2.png').convert_alpha()
self.image = pygame.transform.scale(self.image, (24,24))
self.rect = self.image.get_rect()
self.pos = vec(x, y)
self.vel = vec(0,0)
self.acc = vec(0,0)
self.type = type
def move(self):
self.acc = vec(0,0.5)
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos.x += self.vel.x + 0.5 * self.acc.x
self.rect.midbottom = self.pos
hit_side = False
for entity in blocks:
if self.rect.colliderect(entity.rect):
# move left and hit the block on the right
if self.vel.x < 0 and self.rect.right > entity.rect.right:
self.rect.left = entity.rect.right
self.pos.x = self.rect.centerx
hit_side = True
# move right and hit the block on the left
if self.vel.x > 0 and self.rect.left < entity.rect.left:
self.rect.right = entity.rect.left
self.pos.x = self.rect.centerx
hit_side = True
if hit_side:
self.vel.x = 0
self.acc.x = 0
def update(self):
hits = pygame.sprite.spritecollide(self, blocks, False)
self.pos.y += self.vel.y + 0.5 * self.acc.y
self.rect.midbottom = self.pos
for entity in blocks:
if self.rect.colliderect(entity.rect):
if self.vel.y > 0:
self.rect.bottom = entity.rect.top
self.pos.y = self.rect.bottom
self.vel.y = 0
if self.vel.y > 0:
if hits:
self.pos.y = hits[0].rect.top + 1
self.vel.y = 0
# Now we check if we hit the Player
if self.rect.colliderect(player.rect):
# Attempt to check the player inventory
if self.type not in player.inventory.keys():
player.inventory[self.type] = 1
self.kill()
else:
player.inventory.update({self.type: player.inventory.get(self.type) + 1})
self.kill()
player = Player()
blueblock = BlueBlock(0,0)
running = True
all_sprites = pygame.sprite.Group()
blocks = pygame.sprite.Group()
items = pygame.sprite.Group()
miscBlocks = pygame.sprite.Group()
def drawGraph(graph, start):
y = start
x = 0
for item in graph:
if item == "O":
spr = BlueBlock(x, y)
spr.rect.x = x
spr.rect.y = y
all_sprites.add(spr)
miscBlocks.add(spr)
screen.blit(spr.surf, spr.rect)
x += 48
elif item == "G":
global cx
spr = textureblock("media/Grass.jpeg", x, y, "Grass")
spr.rect.x = x
spr.rect.y = y
all_sprites.add(spr)
blocks.add(spr)
screen.blit(spr.image, spr.rect)
x += 48
elif item == "S":
spr = textureblock("media/Stone.png",x,y, "Stone")
spr.rect.x = x
spr.rect.y = y
all_sprites.add(spr)
blocks.add(spr)
screen.blit(spr.image, spr.rect)
x += 48
elif item == "C":
spr = textureblock("media/Coal.jpeg",x,y, "Coal")
spr.rect.x = x
spr.rect.y = y
all_sprites.add(spr)
blocks.add(spr)
screen.blit(spr.image, spr.rect)
x += 48
elif item == "NL":
y += 48
x = 0
else:
print("Item not found: " + item)
print("[Debug] Generation finished. Amount of blocks: " + str(len(blocks.sprites())))
def randomGen(graph):
print("[Debug] Begin randomGen...")
# We assume the user has not done anything with the graph, so we add the sky and grass
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('O')
newgraph.append('NL')
for i in range(20):
newgraph.append('G')
newgraph.append('NL')
# Next begins the random ore gen
for i in range(20):
x = 0
for i in range(20):
# Chance of coal - 1 in 15
iscoal = random.randint(1,15)
if iscoal == 6:
graph.append("C")
else:
graph.append("S")
x += 48
graph.append('NL')
print("[Debug] randomGen finished. Block Stats: %s air blocks, %s grass blocks, %s stone blocks, %s coal blocks, and %s newlines." % (str(graph.count('O')), str(graph.count('G')), str(graph.count('S')), str(graph.count('C')), str(graph.count('NL'))))
newgraph = []
randomGen(newgraph)
all_sprites.add(player)
def update():
screen.blit(player.surf, camera(player.rect))
for entity in blocks:
screen.blit(entity.image, camera(entity.rect))
for entity in items:
screen.blit(entity.image, camera(entity.rect))
pygame.display.update()
drawGraph(newgraph, 0)
# Calculate the size of the level
level_width = 0
for i in newgraph:
if i != "NL":
level_width += 1
elif i == "NL":
break
level_width = level_width * TILE_SIZE
level_height = (newgraph.count("NL")-1)*TILE_SIZE
print("[Debug] Calculated level width and height: %s and %s" % (str(level_width), str(level_height)))
while running:
screen.fill((0, 0, 255))
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.jump()
if event.key == pygame.K_ESCAPE:
running = False
pygame.quit()
if event.key == pygame.K_e:
if len(player.inventory) == 0:
print("Player Inventory: Empty")
else:
print("Player Inventory: " + str(player.inventory).replace("{", "").replace("}","").replace(":", " x").replace("'",""))
if event.key == pygame.K_b:
if player.mode == "build":
player.mode = "destroy"
elif player.mode == "destroy":
player.mode = "build"
print("Changed player mode to " + player.mode)
if event.key == pygame.K_1:
player.selected_item = list(player.inventory)[0]
print("Item: " + list(player.inventory)[0])
if event.type == pygame.MOUSEBUTTONDOWN:
x,y = event.pos
if event.type == pygame.QUIT:
running = False
pygame.quit()
miscBlocks.update()
blocks.update()
# blocks.draw(screen)
pressed_keys = pygame.key.get_pressed()
for entity in items:
entity.move()
# Commented out because it lagged everything.
items.update()
player.update()
update()
img1 = font.render("FPS: " + str(clock.get_fps()), True, (255,255,0))
img2 = font.render("Mode: " + player.mode, True, (255,0,0))
try:
img3 = font.render("Selected Item: " + player.selected_item, True, (0,255,0))
except Exception:
img3 = font.render("Selected Item: None", True, (0,255,0))
screen.blit(img1, (0,0))
screen.blit(img2, (0,24))
screen.blit(img3, (0,48))
pygame.display.update()
!IMPORTANT!
Don't try do cx = playerx it will make your player go to the x 0, for example: if x = 500 and cx = 500 then the screen will blit at x 0. But you can do something like this cx = playerx - 400.
I hope it helped.
This question already exists:
I want to do an explosion animation. I have 4 png files number 0 - 3. In my debris class I loaded them into an image list using a for loop [duplicate]
Closed 1 year ago.
I want to do an explosion animation. I have 4 png files number 0 - 3. In my debris class I loaded them into an image list using a for loop. Then I made an explosion function but when I load my pygame windows and start shooting my cement block sprites, my cement block sprites disappear which is fine but they don't do the exploding animation I want. How can I fix this problem. Would appreciate the help.
My code:
import random
import pygame
import pygame.freetype
pygame.init()
#screen settings
WIDTH = 1000
HEIGHT = 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("AutoPilot")
screen.fill((255, 255, 255))
#fps
FPS = 120
clock = pygame.time.Clock()
#load images
bg = pygame.image.load('background/street.png').convert_alpha() # background
bullets = pygame.image.load('car/bullet.png').convert_alpha()
debris_img = pygame.image.load('debris/cement.png')
#define game variables
shoot = False
#player class
class Player(pygame.sprite.Sprite):
def __init__(self, scale, speed):
pygame.sprite.Sprite.__init__(self)
self.bullet = pygame.image.load('car/bullet.png').convert_alpha()
self.bullet_list = []
self.speed = speed
#self.x = x
#self.y = y
self.moving = True
self.frame = 0
self.flip = False
self.direction = 0
self.score = 0
#load car
self.images = []
img = pygame.image.load('car/car.png').convert_alpha()
img = pygame.transform.scale(img, (int(img.get_width()) * scale, (int(img.get_height()) * scale)))
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
self.update_time = pygame.time.get_ticks()
self.movingLeft = False
self.movingRight = False
self.rect.x = 465
self.rect.y = 325
#draw car to screen
def draw(self):
screen.blit(self.image, (self.rect.centerx, self.rect.centery))
#move car
def move(self):
#reset the movement variables
dx = 0
dy = 0
#moving variables
if self.movingLeft and self.rect.x > 33:
dx -= self.speed
self.flip = True
self.direction = -1
if self.movingRight and self.rect.x < 900:
dx += self.speed
self.flip = False
self.direction = 1
#update rectangle position
self.rect.x += dx
self.rect.y += dy
#shoot
def shoot(self):
bullet = Bullet(self.rect.centerx + 18, self.rect.y + 30, self.direction)
bullet_group.add(bullet)
#check collision
def collision(self, debris_group):
for debris in debris_group:
if pygame.sprite.spritecollide(debris, bullet_group, True):
debris.health -= 1
if debris.health <= 0:
self.score += 1
debris.kill()
#player stats
def stats(self):
myfont = pygame.font.SysFont('comicsans', 30)
scoretext = myfont.render("Score: " + str(self.score), 1, (0,0,0))
screen.blit(scoretext, (100,10))
#bullet class
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y, direction):
pygame.sprite.Sprite.__init__(self)
self.speed = 5
self.image = bullets
self.rect = self.image.get_rect()
self.rect.center = (x,y)
self.direction = direction
def update(self):
self.rect.centery -= self.speed
#check if bullet has gone off screen
if self.rect.centery < 1:
self.kill()
#debris class
class Debris(pygame.sprite.Sprite):
def __init__(self,scale,speed):
pygame.sprite.Sprite.__init__(self)
self.scale = scale
self.x = random.randrange(100,800)
self.speed_y = 10
self.y = 15
self.speed = speed
self.vy = 0
self.on_ground = True
self.move = True
self.health = 4
self.max_health = self.health
self.alive = True
self.velocity = random.randrange(1,2)
self.speed_x = random.randrange(-3,3)
self.moving_down = True
#load debris
self.image = debris_img
self.rect = self.image.get_rect()
self.rect.x = random.randrange(100, 800)
self.rect.y = random.randrange(-150, -100)
self.rect.center = (self.x,self.y)
#load explosion
self.images = []
for i in range(4):
self.images.append(pygame.image.load(f'explosion/{i}.png'))
self.index = 0
self.img = self.images[self.index]
#spawn new debris
def spawn_new_debris(self):
self.rect.x = random.randrange(100, 800)
self.rect.y = random.randrange(-150, -100)
self.velocity = random.randrange(1, 2)
self.speed_x = random.randrange(-3, 3)
#respawn debris when they go of the screen
def boundaries(self):
if self.rect.left > WIDTH + 10 or self.rect.right < -10 or self.rect.top > HEIGHT + 10:
self.spawn_new_debris()
#update image
def update(self):
self.rect.y += self.velocity
self.rect.x += self.speed_x
self.boundaries()
#make debris fall down
def falldown(self):
self.rect.centery += self.velocity
if self.moving_down and self.rect.y > 350:
self.kill()
#explosion
def explode(self):
if self.max_health <= 0:
self.index += 1
if self.index >= len(self.images):
self.index = 0
self.img = self.images[self.index]
######################CAR/DEBRIS##########################
player = Player(1,5)
##########################################################
#groups
bullet_group = pygame.sprite.Group()
debris_group = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
for i in range(50):
d = Debris(1,5)
debris_group.add(d)
all_sprites.add(d)
#game runs here
run = True
while run:
#draw street
screen.blit(bg, [0, 0])
#update groups
bullet_group.update()
bullet_group.draw(screen)
debris_group.update()
debris_group.draw(screen)
#draw car
player.draw()
player.move()
player.collision(debris_group)
player.stats()
#update all sprites
all_sprites.update()
all_sprites.draw(screen)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#check if key is down
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
if event.key == pygame.K_a:
player.movingLeft = True
if event.key == pygame.K_d:
player.movingRight = True
if event.key == pygame.K_SPACE:
player.shoot()
shoot = True
#check if key is up
if event.type == pygame.KEYUP:
if event.key == pygame.K_a:
player.movingLeft = False
if event.key == pygame.K_d:
player.movingRight = False
#update the display
pygame.display.update()
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
So basically I want to my Road class to always know where my Car (Player1) class is so road knows whether to slow down as Car has left road (or be able to speed back up when Car gets back within road area.
As Car only moves left / right and it is the road that speeds up coming down screen, I figured a way to mimic the car using a "self.where_player" at same start position and then add / subtract x position and follow it with key's pressed (a, d), but after awhile it can lose Car placement as Car can either have x values added or subtracted while slipping left or right on ice or have it keys (a, d) temporarily disabled if spinning on oil, while the road does not know these things...
If I could figure out how the Road class could "always" know where the Car class rect.x was, well that would be fantastic!
import pygame
W = 1000
H = 800
pygame.init()
pygame.display.set_mode((W, H))
class Road1(pygame.sprite.Sprite):
def __init__(self, top, player):
pygame.sprite.Sprite.__init__(self)
bkgrnd = pygame.image.load("Images/Road.png").convert_alpha()
self.image = pygame.transform.scale(bkgrnd, (300, 100))
self.rect = self.image.get_rect(topleft = (120, top))
self.top = top
self.speedy = 0
self.player = player
self.out_of_bounds = False
def update(self):
self.top += self.speedy
if self.top >= 800:
self.top = self.top - 900
self.rect.top = self.top
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
self.speedy = min(20, self.speedy + 0.25)
if keys[pygame.K_s]:
self.speedy = max(0, self.speedy - 0.25)
if keys[pygame.K_a]:
self.player -= 5
if self.player <= 120:
self.player = 120
self.out_of_bounds = True
if self.out_of_bounds and self.speedy > 5:
self.speedy -= 0.35
else:
self.out_of_bounds = False
if keys[pygame.K_d]:
self.player += 5
if self.player >= 420:
self.player = 420
self.out_of_bounds = True
if self.out_of_bounds and self.speedy > 5:
self.speedy -= 0.35
else:
self.out_of_bounds = False
The following is a portion from the Main page enough to make Road work:
import pygame
import random
import sys
# from Ice_Patch import Ice1, Ice2
# from Oil_Slick import Oil1, Oil2
from Player1 import Player1, car1_image
# from Player2 import Player2, car2_image
from Roads import Road1, # Road2
W, H = 1000, 800
HW, HH = W / 2, H / 2
AREA = W * H
FPS = 30
GREEN = (0, 200, 0)
pygame.init()
CLOCK = pygame.time.Clock()
DS = pygame.display.set_mode((W, H))
pygame.display.set_caption("Racing Fury")
def events():
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
player = Player1()
all_sprites = pygame.sprite.Group()
road = pygame.sprite.Group()
for i in range(9):
rd = Road1((i - 1) * 100, player)
all_sprites.add(rd)
road.add(rd)
while True:
CLOCK.tick(FPS)
events()
all_sprites.update()
DS.fill(GREEN)
all_sprites.draw(DS)
pygame.display.flip()
Player1 Class:
import pygame
W = 1000
H = 800
pygame.init()
pygame.display.set_mode((W, H))
car1_image = pygame.image.load("Images/GalardB.png").convert_alpha()
car1_image = pygame.transform.scale(car1_image, (40, 70))
GREY = (211, 211, 211)
ANIM_DELAY = 50
POWERUP_TIME = 5000
SPIN_TIME = 1950
class Player1(pygame.sprite.Sprite):
def __init__(self, car1_image, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = car1_image
self.image.set_colorkey(GREY)
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.radius = 25
self.speedx = 0
self.rotations = [self.image]
self.spinning_since = 0
self.rotate()
self.damage = 100
self.shoot_delay = 250
self.last_shot = pygame.time.get_ticks()
self.lives = 3
self.hidden = False
self.hide_timer = pygame.time.get_ticks()
self.score = 0
self.crashx = 0
self.crashy = 0
self.power = 0
self.power_time = pygame.time.get_ticks()
self.not_spinning = True
def update(self):
if self.power >= 1 and pygame.time.get_ticks() - self.power_time > POWERUP_TIME:
self.power -= 1
self.power_time = pygame.time.get_ticks()
if self.hidden and pygame.time.get_ticks() - self.hide_timer > 1500:
self.hidden = False
self.rect.center = (300, 700)
self.speedx = 0
keystate1 = pygame.key.get_pressed()
if keystate1[pygame.K_SPACE]:
self.shoot()
if self.not_spinning:
if keystate1[pygame.K_a]:
self.speedx = -5
if keystate1[pygame.K_d]:
self.speedx = 5
self.rect.x += self.speedx
if self.rect.right > 420:
self.rect.right = 420
if self.rect.left < 120:
self.rect.left = 120
if self.spinning_since > 0:
time_spinning = pygame.time.get_ticks() - self.spinning_since
if time_spinning >= SPIN_TIME:
self.spinning_since = 0
index = 0
self.not_spinning = True
else:
index = int(time_spinning / ANIM_DELAY)
index %= len(self.rotations)
self.not_spinning = False
cx, cy = self.rect.center
self.image = self.rotations[index]
self.rect = self.image.get_rect()
self.rect.centerx = cx
self.rect.centery = cy
def powerup(self):
self.power += 1
self.power_time = pygame.time.get_ticks()
def shoot(self):
now = pygame.time.get_ticks()
if now - self.last_shot > self.shoot_delay:
self.last_shot = now
if self.power == 0:
pass
if self.power >= 1:
bullet1 = Bullet(self.rect.centerx, self.rect.top)
all_sprites.add(bullet1)
bullets1.add(bullet1)
def rotate(self):
ROT_FRAMES = 36
for i in range(ROT_FRAMES):
angle = i * (720 / ROT_FRAMES)
rotated_image = pygame.transform.rotozoom(self.image, angle, 1)
self.rotations.append(rotated_image)
def spin(self):
if self.spinning_since == 0:
self.spinning_since = pygame.time.get_ticks()
else:
pass
def slide(self):
keystate1 = pygame.key.get_pressed()
if keystate1[pygame.K_a]:
self.rect.x -= 2
self.rect.x -= 1.5
self.rect.x -= 1
self.rect.x -= 0.5
self.rect.x -= 0.25
if keystate1[pygame.K_d]:
self.rect.x += 2
self.rect.x += 1.5
self.rect.x += 1
self.rect.x += 0.5
self.rect.x += 0.25
def hide(self):
self.crashx = self.rect.x
self.crashy = self.rect.y
self.hidden = True
self.hide_timer = pygame.time.get_ticks()
self.rect.center = (W * 2, H * 2)
The easiest solution is to make the "road" knowing the player. Add an attribute player the class Road1:
class Road1(pygame.sprite.Sprite):
def __init__(self, top, player):
pygame.sprite.Sprite.__init__(self)
self.player = player
# [...]
Instead of self.where_player you can directly ask self.player for its position.
Pass the player to the road objects when they are constructed. e.g.:
player = Player1(?????)
all_sprites = pygame.sprite.Group()
road = pygame.sprite.Group()
for i in range(9):
rd = Road1((i - 1) * 100, player)
all_sprites.add(rd)
road.add(rd)
An other option would be to add an argument player to the method update:
class Road1(pygame.sprite.Sprite):
# [...]
def update(self, player):
# [...]
Of course you have to separate the update of road and player. e.g.:
player.update()
road.update(player)
I am trying to make my player jump (from this tutorial https://opensource.com/article/19/12/jumping-python-platformer-game) but it only jumps once when you press key_up or key "w". And when I look at the output produced in the terminal while I am running the game.py file I see that it was printed jump several times in the terminal.
game.py:
import pygame
import sys
import os
'''
Objects
'''
class Platform(pygame.sprite.Sprite):
# x location, y location, img width, img height, img file
def __init__(self,xloc,yloc,imgw,imgh,img):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('images',img)).convert()
self.image.convert_alpha()
self.rect = self.image.get_rect()
self.rect.y = yloc
self.rect.x = xloc
class Player(pygame.sprite.Sprite):
'''
Spawn a player
'''
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.movex = 0
self.movey = 0
self.frame = 0
self.health = 10
# gravity variables here
self.collide_delta = 0
self.jump_delta = 6
self.score = 1
self.images = []
for i in range(1,9):
img = pygame.image.load(os.path.join('images','spr' + str(i) + '.png')).convert()
img.convert_alpha()
img.set_colorkey(ALPHA)
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
def jump(self,platform_list):
self.jump_delta = 0
def gravity(self):
self.movey += 3.2 # how fast player falls
if self.movey >= 15:
self.movey = 6
if self.rect.bottom > worldy and self.movey >= 0: # <-- uses bottom
self.movey = 0
self.rect.bottom = worldy # <-- uses bottom
def control(self,x,y):
'''
control player movement
'''
self.movex += x
self.movey += y
def update(self):
'''
Update sprite position
'''
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
for p in plat_hit_list:
self.collide_delta = 0 # stop jumping
self.movey = 0
if self.rect.y > p.rect.y:
self.rect.y = p.rect.y+ty
else:
self.rect.y = p.rect.y-ty
if self.collide_delta < 6 and self.jump_delta < 6:
self.jump_delta = 6*2
self.movey -= 33 # how high to jump
self.collide_delta += 6
self.jump_delta += 6
self.rect.x = self.rect.x + self.movex
self.rect.y = self.rect.y + self.movey
# moving left
if self.movex < 0:
self.frame += 1
if self.frame > ani*3:
self.frame = 0
self.image = self.images[self.frame//ani]
# moving right
if self.movex > 0:
self.frame += 1
if self.frame > ani*3:
self.frame = 0
self.image = self.images[(self.frame//ani)+4]
# collisions
enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
for enemy in enemy_hit_list:
self.health -= 1
print(self.health)
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
for p in plat_hit_list:
self.rect.bottom = p.rect.top
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
for g in ground_hit_list:
self.movey = 0
self.rect.y = worldy-ty-ty
self.collide_delta = 0 # stop jumping
if self.rect.y > g.rect.y:
self.health -= 1
print(self.health)
class Enemy(pygame.sprite.Sprite):
'''
Spawn an enemy
'''
def __init__(self,x,y,img):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('images',img))
#self.image.convert_alpha()
#self.image.set_colorkey(ALPHA)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.counter = 0
def move(self):
'''
enemy movement
'''
distance = 80
speed = 8
if self.counter >= 0 and self.counter <= distance:
self.rect.x += speed
elif self.counter >= distance and self.counter <= distance*2:
self.rect.x -= speed
else:
self.counter = 0
self.counter += 1
class Level():
def bad(lvl,eloc):
if lvl == 1:
enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy
enemy_list = pygame.sprite.Group() # create enemy group
enemy_list.add(enemy) # add enemy to group
if lvl == 2:
print("Level " + str(lvl) )
return enemy_list
def loot(lvl,lloc):
print(lvl)
def ground(lvl,gloc,tx,ty):
ground_list = pygame.sprite.Group()
i=0
if lvl == 1:
while i < len(gloc):
ground = Platform(gloc[i],worldy-ty,tx,ty,'ground.png')
ground_list.add(ground)
i=i+1
if lvl == 2:
print("Level " + str(lvl) )
return ground_list
def platform(lvl,tx,ty):
plat_list = pygame.sprite.Group()
ploc = []
i=0
if lvl == 1:
ploc.append((0,worldy-ty-128,3))
ploc.append((300,worldy-ty-256,3))
ploc.append((500,worldy-ty-128,4))
while i < len(ploc):
j=0
while j <= ploc[i][2]:
plat = Platform((ploc[i][0]+(j*tx)),ploc[i][1],tx,ty,'ground.png')
plat_list.add(plat)
j=j+1
print('run' + str(i) + str(ploc[i]))
i=i+1
if lvl == 2:
print("Level " + str(lvl) )
return plat_list
'''
Setup
'''
worldx = 960
worldy = 720
fps = 40 # frame rate
ani = 4 # animation cycles
clock = pygame.time.Clock()
pygame.init()
main = True
BLUE = (25,25,200)
BLACK = (23,23,23 )
WHITE = (254,254,254)
ALPHA = (0,255,0)
world = pygame.display.set_mode([worldx,worldy])
backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
backdropbox = world.get_rect()
player = Player() # spawn player
player.rect.x = 0
player.rect.y = 0
player_list = pygame.sprite.Group()
player_list.add(player)
steps = 10 # how fast to move
eloc = []
eloc = [200,20]
gloc = []
#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]
tx = 64 #tile size
ty = 64 #tile size
i=0
while i <= (worldx/tx)+tx:
gloc.append(i*tx)
i=i+1
enemy_list = Level.bad( 1, eloc )
ground_list = Level.ground( 1,gloc,tx,ty )
plat_list = Level.platform( 1,tx,ty )
'''
Main loop
'''
while main == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit()
main = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == ord('a'):
print("LEFT")
player.control(-steps,0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
print("RIGHT")
player.control(steps,0)
if event.key == pygame.K_UP or event.key == ord('w'):
print('jump')
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.control(steps,0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
player.control(-steps,0)
if event.key == pygame.K_UP or event.key == ord('w'):
player.jump(plat_list)
if event.key == ord('q'):
pygame.quit()
sys.exit()
main = False
world.blit(backdrop, backdropbox)
player.gravity() # check gravity
player.update()
player_list.draw(world)
enemy_list.draw(world)
ground_list.draw(world)
plat_list.draw(world)
for e in enemy_list:
e.move()
pygame.display.flip()
clock.tick(fps)
The original images are from here https://opengameart.org/sites/default/files/opp2_sprites.zip but I have separated in imgur for easy explanation:
content folder images:
For enemy (sprit) is yeti.png:
For background is stage.png: https://imgur.com/YyiEJ0q
and the image of the player: spr.png:
To do a jump, self.collide_delta and self.jump_delta have to be less than 6. See your code:
if self.collide_delta < 6 and self.jump_delta < 6:
self.jump_delta = 6*2
The issue is that self.collide_delta is not set 0, when the player hits a platform:
(in the 2nd case)
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
for p in plat_hit_list:
self.rect.bottom = p.rect.top
self.collide_delta = 0 # <----- this is missing
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I was working on a movement animations since I saw a youtuber explaining how to do it, but I'm getting this error:
TypeError: argument 1 must be pygame.Surface, not list
My code is about 500 lines.
# Pygame Template - skeleton for a new pygame project
import pygame
import random
import os
from os import path
vec = pygame.math.Vector2
width = 800
height = 600
FPS = 60
POWERUP_TIME = 5000
title = 'Parkourse'
# Player properties
player_acceleration = 0.5
player_friction = -0.12
player_gravity = 0.8
player_jump = 10
# Starting platforms
platforms_list = [(0,height-40,width,50), # Ground
(0,0,800,10), # Top
(0,0,10,600), # Left Border
(790,height-400,10,600),# Right Border
(250,height - 160,width-200,10), # Floor 1
(0,height - 280,width-200,10), # Floor 2
(250,height - 400,width-100,10)] # Floor 3
# Define Colors
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
# set up assets folders
game_folder = os.path.dirname(__file__)
image_folder = os.path.join(game_folder, "Image")
sound_folder = os.path.join(game_folder, "Sound")
# Initialize pygame and create window
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((width,height))
pygame.display.set_caption(title)
clock = pygame.time.Clock()
# Load all game graphics
background = pygame.image.load(path.join(image_folder, "background.png")).convert()
background_rect = background.get_rect()
no_mvmt_0 = pygame.image.load(path.join(image_folder,"no_mvmt_0.png")).convert()
no_mvmt_1 = pygame.image.load(path.join(image_folder,"no_mvmt_1.png")).convert()
running_0 = pygame.image.load(path.join(image_folder,"running_0.png")).convert()
running_1 = pygame.image.load(path.join(image_folder,"running_1.png")).convert()
jumping_0 = pygame.image.load(path.join(image_folder,"jumping_0.png")).convert()
mini_no_mvmt = pygame.transform.scale(no_mvmt_0, (25,48))
mini_no_mvmt.set_colorkey(white)
scissors = pygame.image.load(path.join(image_folder,"scissors.png")).convert()
mob_left = pygame.image.load(path.join(image_folder,"mob_left.png")).convert()
power_upper_image = {}
power_upper_image['shield_0'] = pygame.image.load(path.join(image_folder,"shield_upper_0.png")).convert()
power_upper_image['shield_1'] = pygame.image.load(path.join(image_folder,"shield_upper_1.png")).convert()
power_upper_image['shield_2'] = pygame.image.load(path.join(image_folder,"shield_upper_2.png")).convert()
power_upper_image['life'] = pygame.image.load(path.join(image_folder,"life_upper.png")).convert()
power_upper_image['power'] = pygame.image.load(path.join(image_folder,"power.png")).convert()
explosion_animation = {}
explosion_animation['normal']=[]
explosion_animation['small']=[]
explosion_animation['player']=[]
for explosion in range(5):
explose = 'explosion_{}.png'.format(explosion)
image = pygame.image.load(path.join(image_folder, explose)).convert()
image.set_colorkey(white)
image.set_colorkey(black)
image_normal = pygame.transform.scale(image, (80,80))
explosion_animation['normal'].append(image_normal)
image_small = pygame.transform.scale(image, (30, 30))
explosion_animation['small'].append(image_small)
death = 'dying_{}.png'.format(explosion)
image = pygame.image.load(path.join(image_folder, death)).convert()
image.set_colorkey(white)
explosion_animation['player'].append(image)
#Load all game sounds
scream_sound = []
for scream in ["slightscream_0.wav", "slightscream_1.wav", "slightscream_2.wav",
"slightscream_3.wav", "slightscream_4.wav", "slightscream_5.wav",
"slightscream_6.wav", "slightscream_7.wav", "slightscream_8.wav",
"slightscream_9.wav", "slightscream_10.wav", "slightscream_11.wav",
"slightscream_12.wav", "slightscream_13.wav", "slightscream_14.wav"]:
scream_sound.append(pygame.mixer.Sound(path.join(sound_folder,scream)))
shoot_sound = pygame.mixer.Sound(path.join(sound_folder,"shoot.wav"))
shield = pygame.mixer.Sound(path.join(sound_folder,"shield.wav"))
life = pygame.mixer.Sound(path.join(sound_folder,"life.wav"))
special_power = pygame.mixer.Sound(path.join(sound_folder,"special_power.wav"))
death_sound = pygame.mixer.Sound(path.join(sound_folder,"death.ogg"))
explosion_sound = []
for sound in ["explosion.wav", "explosion_2.wav"]:
explosion_sound.append(pygame.mixer.Sound(path.join(sound_folder, sound)))
pygame.mixer.music.load(path.join(sound_folder,"gameplay.ogg"))
pygame.mixer.music.set_volume(0.6)
font_name = pygame.font.match_font('arial')
def draw_text (surf, text,color,size, x, y):
font = pygame.font.Font(font_name, size)
text_surface = font.render(text, True, color)
text_rect = text_surface.get_rect()
text_rect.midtop = (x, y)
surf.blit(text_surface, text_rect)
def newmob():
m = Mobs()
all_sprites.add(m)
mobs.add(m)
def draw_shield_bar(screen, x,y,percentage):
if percentage < 0:
percentage = 0
bar_lenght = 100
bar_height = 10
fill = (percentage / 100) * bar_lenght
outline_rect = pygame.Rect(x,y,bar_lenght,bar_height)
fill_rect = pygame.Rect(x,y,fill, bar_height)
pygame.draw.rect(screen, green, fill_rect)
pygame.draw.rect(screen, black, outline_rect, 2) # 2 is the the number of pixels
# of how wide you want the outline
# of the rectangle to be
def draw_lives (surface, x, y, lives, image):
for i in range(lives):
image_rect = image.get_rect()
image_rect.x = x + 30 * i
image_rect.y = y
surface.blit(image, image_rect)
score = 0
def show_game_over_screen():
screen.blit(background, background_rect)
draw_text(screen, "Dang..!",red,100, width/2, 200)
draw_text(screen, "Score: " + str(score),blue,30, width/2, 330)
draw_text(screen, "Press any key to retry",blue,30, width/2, 390)
pygame.display.flip()
waiting = True
while waiting:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYUP:
waiting = False
def show_start_screen():
screen.blit(background, background_rect)
draw_text(screen,"Parkourse!", green, 100, width/2, 200)
draw_text(screen, "Use the arrow keys to move, S to fire, and space to Jump",blue,30, width/2, 330)
draw_text(screen, "Press any key to begin",blue,30, width/2, 390)
pygame.display.flip()
waiting = True
while waiting:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYUP:
waiting = False
class Player (pygame.sprite.Sprite):
# Sprite for the player
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.load_movement_images()
self.image = self.standing_frame[0]
self.rect = self.image.get_rect()
self.pos = vec(50,500)
self.vel = vec(0,0)
self.acc = vec(0,0)
self.shield = 100
self.lives = 3
self.hidden = False
self.hide_timer = pygame.time.get_ticks()
self.power = 1
self.power_timer = pygame.time.get_ticks()
self.running = False
self.jumping = False
self.current_frame = 0
self.last_update = 0
def load_movement_images(self):
self.standing_frame = [no_mvmt_0, no_mvmt_1]
self.running_frame_right = [running_0,running_1]
self.running_frame_left = []
for frame in self.standing_frame:
frame.set_colorkey(white)
for frame in self.running_frame_right:
self.running_frame_left.append(pygame.transform.flip(frame,True,False)) # True is horizontaly, False is vertically
frame.set_colorkey(white)
self.jumping_frame = jumping_0
self.jumping_frame.set_colorkey(white)
def animate(self):
now = pygame.time.get_ticks()
if not self.jumping and not self.running:
if now - self.last_update > 350:
self.last_update = now
self.current_frame = (self.current_frame + 1) % len(self.standing_frame)
self.image = self.standing_frame
def jump(self):
# Jump only if standing on a Platform
self.rect.x +=1
hits = pygame.sprite.spritecollide(player,platforms, False)
self.rect.x -= 1
if hits:
self.vel.y = - player_jump
def update(self):
self.animate()
# timeout for powerups
if self.power >=2 and pygame.time.get_ticks() - self.power_time > POWERUP_TIME:
self.power -= 1
self.power_time = pygame.time.get_ticks()
# unhide if hidden
if self.hidden and pygame.time.get_ticks() - self.hide_timer > 1000:
self.hidden = False
self.pos = vec(30, 400)
self.acc = vec(0,player_gravity)
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT] or keystate[pygame.K_a]:
self.acc.x = -player_acceleration
if keystate[pygame.K_RIGHT] or keystate[pygame.K_d]:
self.acc.x = player_acceleration
if keystate[pygame.K_SPACE]:
player.jump()
# apply friction
self.acc.x += self.vel.x * player_friction
# equations of motions
self.vel += self.acc
self.pos += self.vel + 0.5 * self.acc
# wrap around the sides of the screen
if self.pos.x > 750:
self.pos.x = 750
if self.pos.x <= 0:
self.pos.x = 25
self.rect.midbottom = self.pos
def powerup(self):
self.power += 1
self.power_time = pygame.time.get_ticks()
def shoot(self):
if self.power == 1:
bullet = Bullet(self.pos.x + 5, self.pos.y - 20)
all_sprites.add(bullet)
bullets.add(bullet)
shoot_sound.play()
if self.power >= 2:
bullet1 = Bullet(self.pos.x + 5, self.pos.y - 20)
bullet2 = Bullet(self.pos.x + 35, self.pos.y -20)
all_sprites.add(bullet1)
all_sprites.add(bullet2)
bullets.add(bullet1)
bullets.add(bullet2)
shoot_sound.play()
def hide(self):
# hide the player temporarily
self.hidden = True
self.hide_timer = pygame.time.get_ticks()
self.pos = vec(0, 6000)
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = scissors
self.rect = self.image.get_rect()
self.image.set_colorkey(white)
self.image = pygame.transform.scale(scissors, (30,15))
self.rect.bottom = y
self.rect.centerx = x
self.speedx = 10
def update(self):
self.rect.x += self.speedx
# kill if it moves off the top of the screen
if self.rect.bottom < 0:
self.kill()
class Mobs(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = mob_left
self.rect = self.image.get_rect()
self.image.set_colorkey(white)
self.rect.x = random.randrange(0,800)
self.rect.y = 530
self.speedx = 2
def update(self):
self.rect.x -= self.speedx
if self.rect.right < 0:
self.rect.x = 800
class Explosion(pygame.sprite.Sprite):
def __init__(self, center, size, frame):
pygame.sprite.Sprite.__init__(self)
self.size = size
self.image = explosion_animation[self.size][0]
self.rect = self.image.get_rect()
self.rect.center = center
self.frame = 0
self.last_update = pygame.time.get_ticks()
self.frame_rate = frame
def update(self):
now = pygame.time.get_ticks()
if now - self.last_update > self.frame_rate:
self.last_update = now
self.frame += 1
if self.frame == len(explosion_animation[self.size]):
self.kill()
else:
center = self.rect.center
self.image = explosion_animation[self.size][self.frame]
self.rect = self.image.get_rect()
self.rect.center = center
class Normal_Power(pygame.sprite.Sprite):
def __init__(self, center):
pygame.sprite.Sprite.__init__(self)
self.type = random.choice(['shield_0','shield_1','shield_2'])
self.image = power_upper_image[self.type]
self.rect = self.image.get_rect()
self.image.set_colorkey(white)
self.rect.center = center
class Special_Power(pygame.sprite.Sprite):
def __init__(self, center):
pygame.sprite.Sprite.__init__(self)
self.type = random.choice(['life','power'])
self.image = power_upper_image[self.type]
self.rect = self.image.get_rect()
self.image.set_colorkey(white)
self.rect.center = center
class Platform(pygame.sprite.Sprite):
def __init__(self, x, y, w, h):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((w, h))
self.image.fill(black)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
pygame.mixer.music.play(loops=-1) # loops = -1 means that pygame will restart the song when it's finished
# Game loop
running = True
new_game = True
game_over = False
while running:
if new_game:
show_start_screen()
new_game = False
all_sprites = pygame.sprite.Group()
platforms = pygame.sprite.Group()
for plat in platforms_list:
p = Platform (*plat)
all_sprites.add(p)
platforms.add(p)
mobs = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
bullets = pygame.sprite.Group()
powerups = pygame.sprite.Group()
for i in range(1):
newmob()
score = 0
if game_over:
show_game_over_screen()
game_over = False
all_sprites = pygame.sprite.Group()
platforms = pygame.sprite.Group()
for plat in platforms_list:
p = Platform (*plat)
all_sprites.add(p)
platforms.add(p)
mobs = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
bullets = pygame.sprite.Group()
powerups = pygame.sprite.Group()
for i in range(1):
newmob()
score = 0
# Keep loop running at the right speed
clock.tick(FPS)
# Process input (events)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_s:
player.shoot()
# Updates
all_sprites.update()
# check if player hits a platform - only if falling
if player.vel.y > 0:
hits = pygame.sprite.spritecollide(player,platforms,False)
if hits:
player.pos.y = hits[0].rect.top
player.vel.y = 0
# check to see if a bullet hit a mob
hits = pygame.sprite.groupcollide(mobs,bullets,True,True)
for hit in hits:
score += 1
random.choice(explosion_sound).play()
expl = Explosion(hit.rect.center, 'normal', 50)
all_sprites.add(expl)
if random.random() > 0.75:
power = Normal_Power(hit.rect.center)
all_sprites.add(power)
powerups.add(power)
if random.random() > 0.90:
lives = Special_Power(hit.rect.center)
all_sprites.add(lives)
powerups.add(lives)
newmob()
# check to see if the mob hit the player
hits = pygame.sprite.spritecollide(player, mobs,True)
for hit in hits:
random.choice(explosion_sound).play()
player.shield -= 25
newmob()
expl = Explosion(hit.rect.center, 'small', 50)
all_sprites.add(expl)
if player.shield <= 0:
death_sound.play()
death_animation = Explosion(player.rect.center, 'player', 100)
all_sprites.add(death_animation)
player.hide()
player.lives -= 1
player.shield = 100
else:
random.choice(scream_sound).play()
# check if the player hit a powerup
hits = pygame.sprite.spritecollide(player, powerups, True)
for hit in hits:
if hit.type == 'shield_0':
player.shield += 5
if player.shield >= 100:
player.shield = 100
shield.play()
if hit.type == 'shield_1':
player.shield += 20
if player.shield >= 100:
player.shield = 100
shield.play()
if hit.type == 'shield_2':
player.shield += 20
if player.shield >= 100:
player.shield = 100
shield.play()
if hit.type == 'life':
player.lives += 1
if player.lives >= 3:
player.lives = 3
life.play()
if hit.type == 'power':
special_power.play()
player.powerup()
# if the player died and the explosion finished playing
if player.lives == 0 and not death_animation.alive():
game_over = True
# Draw / Render
screen.fill(white)
screen.blit(background, background_rect)
all_sprites.draw(screen)
draw_text(screen,str(score),red,30, width/ 2, 30)
draw_text(screen,"Score:",red,30, width / 2, 3)
draw_shield_bar(screen,90,20, player.shield)
draw_lives(screen,95,40,player.lives, mini_no_mvmt)
# *after* drawing everything, flip the display
pygame.display.flip()
pygame.quit()
quit()
The error is caused by a sprite in your all_sprites group that has a list as its self.image attribute. I've just printed the sprites before the all_sprites.draw(screen) line
for sprite in all_sprites:
print(sprite, sprite.image)
and it was the player sprite which had a list as its image.
<Player sprite(in 1 groups)> [<Surface(40x25x32 SW)>, <Surface(40x25x32 SW)>]
In the load_movement_images method you define self.standing_frame as a list of two images/pygame.Surfaces and in __init__ you set self.image to the first item of that list. But in the animate method you set self.image to the whole list instead of the active image self.image = self.standing_frame and that leads to the error.
class Player (pygame.sprite.Sprite):
# Sprite for the player
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.load_movement_images()
# self.image is the first image in the
# self.standing_frame list.
self.image = self.standing_frame[0]
# ...
def load_movement_images(self):
self.standing_frame = [no_mvmt_0, no_mvmt_1]
# ...
def animate(self):
now = pygame.time.get_ticks()
if not self.jumping and not self.running:
if now - self.last_update > 350:
self.last_update = now
self.current_frame = (self.current_frame + 1) % len(self.standing_frame)
# Here you set the self.image to the self.standing_fram list instead one image.
self.image = self.standing_frame
# It should be:
# self.image = self.standing_frame[self.current_frame]