This question already has answers here:
Why is my PyGame application not running at all?
(2 answers)
Why do group lists in pygame have to have "update" functions, and not any other?
(1 answer)
Closed 2 years ago.
I am trying to create a game similar to "Bubble Trouble" in which the player detects eggs that are falling from the top of the screen. I have several problems with this.
The eggs will not appear on the screen no matter how much I attempt at drawing them and having them appear at some point on the y axis
I have no idea if the collision detection will work because
the program wont open and there is no error message.
Please help me figure out a solutions to this problem. I was so excited to work on this when I started but after days of trying I am being disheartened. Thank you in advance.
Code:
import pygame, random
import Tkinter
from pygame.locals import *
# CONSTANTS
WWD = 1280 # Window width
WHT = 720 # Window height
BLACK = (0,0,0) # Colors
WHITE = (255,255,255)
BACK = BLACK # Background Color
FORE = WHITE # Foreground Color
INT = 40 # Time interval for game and key repeat
BG = pygame.image.load("barn.png")
BG = pygame.transform.scale(BG, (1280, 720))
pygame.init()
pygame.key.set_repeat(INT,INT) # pygame.init disables keyboard repetition. This reenables it with a delay and rep interval
class Label:
def __init__(self,surf,cx,cy,fsize,strng,fcolor,bcolor):
self.screen = surf
self.fc = fcolor
self.bc = bcolor
self.font = pygame.font.SysFont(None,fsize)
self.cx = cx
self.cy = cy
self.str = strng
self.vis = False # tells if the label is visible
def draw(self):
self.text = self.font.render(self.str,True,self.fc,self.bc)
self.rect = self.text.get_rect()
self.rect.centerx = self.cx
self.rect.centery = self.cy
self.screen.blit(self.text,self.rect)
pygame.display.update([self.rect])
self.vis = True
def undraw(self):
self.text.fill(self.bc)
self.screen.blit(self.text,self.rect)
pygame.display.update([self.rect])
self.vis = False
def OpeningScreen(Scr):
Scr.blit(BG, (0, 0))
pygame.display.update()
L1 = Label(Display,WWD//2,WHT*3//8,WHT*3//50,"Use Arrow Keys to Begin",WHITE,BLACK) #Creating the menus
L1.draw()
L2 = Label(Display,WWD//2,WHT*4//8,WHT*3//50,"Hit Q to Quit Anytime",WHITE,BLACK) #Second menu option
L2.draw()
class Player:
def __init__(self,Scr,cx,cy,speed,bcolor):
self.screen = Scr
self.surf = pygame.image.load('player.png').convert_alpha()
self.surf = pygame.transform.scale(self.surf, (160, 200)).convert_alpha()
self.rect = self.surf.get_rect()
self.rect.centerx = cx
self.rect.y = 510
self.speed = 30
self.bc = bcolor
def draw(self):
self.screen.blit(self.surf,self.rect).convert_alpha()
pygame.display.update([self.rect])
def undraw(self):
surf = self.surf.copy()
surf.fill(self.bc)
self.screen.blit(surf,self.rect)
pygame.display.update([self.rect])
def move(self,mv):
self.undraw()
if mv == 'd' and self.rect.bottom < WHT:
self.rect.top += self.speed
if mv == 'u' and self.rect.top > 0:
self.rect.top -= self.speed
if mv == 'l' and self.rect.left > 0:
self.rect.left -= self.speed
if mv == 'r' and self.rect.right < WWD:
self.rect.right += self.speed
self.draw()
pygame.display.update()
def jump(self,top,left):
self.undraw()
self.rect.top = top
self.rect.left = left
self.draw()
pygame.display.update()
class EggDrop:
def __init__(self,Scr):
pygame.display.update()
pygame.mixer.music.load('background.mid')
pygame.mixer.music.play(-1,0.0)
self.Mplay = True
self.Player = Player(Scr,WWD//2,WHT//2,6,BLACK)
Scr.blit(BG, (0, 0))
self.Scr = Scr
def toggleMusic(self):
self.Mplay = not self.Mplay
if self.Mplay:
pygame.mixer.music.play(-1,0.0)
else:
pygame.mixer.music.stop()
def togglePlayer(self):
if self.Pvis:
self.Player.undraw()
else:
self.Player.draw()
self.Pvis = not self.Pvis
def hatchGif(self):
#files in order animated
files = ["pics\hatch1.gif", "pics\hatch2.gif", "pics\hatch2.gif", "pics\hatch3.gif", "pics\hatch4.gif", "pics\hatch5.gif", "pics\hatch6.gif", "pics\hatch7.gif", "pics\hatch8.gif", "pics\hatch9.gif", "pics\hatch10.gif", "pics\hatch11.gif", "pics\hatch12.gif", "pics\hatch13.gif"]
photos = [Tkinter.PhotoImage(file=x) for x in files]
label = Tkinter.Label()
label.photos = photos
label.counter = 0
def next_pic():
label['image'] = label.photos[label.counter%len(label.photos)]
label.after(25, next_pic) #25 = speed of animation
label.counter += 1
label.pack()
next_pic()
def splatGif(self):
files = ["pics\splat1.gif", "pics\splat2.gif", "pics\splat2.gif", "pics\splat3.gif", "pics\splat4.gif", "pics\splat5.gif", "pics\splat6.gif", "pics\splat7.gif", "pics\splat8.gif"]
photos = [Tkinter.PhotoImage(file=x) for x in files]
label = Tkinter.Label()
label.photos = photos
label.counter = 0
def next_pic():
label['image'] = label.photos[label.counter%len(label.photos)]
label.after(40, next_pic) #25 = speed of animation
label.counter += 1
label.pack()
next_pic()
def eggs(self):
while self.Player.draw():
self.eggsImage = pygame.image.load('hatch1.gif')
self.eggsImage = pygame.transform.scale(self.eggsImage, (30, 40))
self.screen.blit(self.eggsImage)
pygame.display.update([self.eggsImage])
self.eggsImage.centerx = cx
self.eggsImage.y = 300
self.speed = 30
def detectCollisions(x1,y1,w1,h1,x2,y2,w2,h2):
if (x2+w2>=x1>=x2 and y2+h2>=y1>=y2):
return True
elif (x2+w2>=x1+w1>=x2 and y2+h2>=y1>=y2):
return True
elif (x2+w2>=x1>=x2 and y2+h2>=y1+h1>=y2):
return True
elif (x2+w2>=x1+w1>=x2 and y2+h2>=y1+h1>=y2):
return True
else:
return False
class Sprite:
def __init__(self,x,y,width,height):
self.x=x
self.y=y
self.width=width
self.height=height
def render(self,collision):
if (collision==True):
hatchGif()
else:
pass
Sprite1=Player
Sprite2=eggs
moveX,moveY=0,0
gameLoop=True
while gameLoop:
STOP = False
while not STOP:
for event in pygame.event.get():
if event.type==pygame.QUIT:
gameLoop=False
STOP = True
if event.type==pygame.KEYDOWN:
if event.key==pygame.K_LEFT or event.key == ord('a'):
moveX = -4
if event.key==pygame.K_RIGHT or event.key == ord('d'):
moveX = 4
if event.key== K_SPACE:
detectCollisions()
if event.type==pygame.KEYUP:
if event.key == ord('q'):
STOP = True
if event.key == K_ESCAPE:
STOP = True
if event.key == ord('x'):
top = random.randint(0, WHT - self.Player.rect.height)
left = random.randint(0, WWD - self.Player.rect.width)
self.Player.jump(top,left)
if event.key == ord('m'):
self.toggleMusic()
pygame.mixer.music.stop()
Sprite1.x+=moveX
Sprite1.y+=moveY
collisions=detectCollisions(Sprite1.x,Sprite1.y,Sprite1.width,Sprite1.height,Sprite2.x,Sprite2.y,Sprite2.width,Sprite2.height)
Sprite1.render(collisions)
Sprite2.render(False)
pygame.display.flip()
Display = pygame.display.set_mode((WWD,WHT),0,0)
pygame.display.set_caption('Incubator 3000 V.1')
OpeningScreen(Display)
g = EggDrop(Display)
g.run()
pygame.quit()
Related
First post here. So I am trying to implement a Civilization type of movement game. At the moment, I have one sprite in a cell. I can click it and then if I click another grid, the sprite moves there. What I now want is to spawn 5-6 such sprites, and then do the same thing. Click on a sprite and then click another grid, and that specific sprite moves there without affecting the other sprites. I cannot seem to do that. I can spawn 5-6 random sprites at different grids, but when I click on one of them and then click another grid, all the other sprites are gone. The code is below (not the best as I am learning Pygame). I understand that I have to somehow only update the sprite that was clicked, but I am not sure how to do that.
import pygame
import random
WIDTH = 900
HEIGHT = 700
FPS = 2
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
TURN = "TeamOne"
def main():
# Pygame sprite Example
global x_lines
global y_lines
x_lines = [WIDTH-i*WIDTH/20 for i in range(20,0, -1)]
y_lines = [HEIGHT-j*HEIGHT/20 for j in range(20,0, -1)]
class TeamOne(pygame.sprite.Sprite):
# sprite for the Player
def __init__(self):
# this line is required to properly create the sprite
pygame.sprite.Sprite.__init__(self)
# create a plain rectangle for the sprite image
self.image = pygame.Surface((WIDTH / 20, HEIGHT / 20))
self.image.fill(GREEN)
# find the rectangle that encloses the image
self.rect = self.image.get_rect()
# center the sprite on the screen
self.rect.center = ((random.randint(1,19)*2+1)* WIDTH/ 40, (random.randint(1,19)*2+1)*HEIGHT/40)
def update(self, position):
# any code here will happen every time the game loop updates
(a, b) = position
for index, i in enumerate(x_lines):
if i > a:
self.rect.x = x_lines[index-1]
break
for index, j in enumerate(y_lines):
if j > b:
self.rect.y = y_lines[index-1]
break
# initialize pygame and create window
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("A Game")
clock = pygame.time.Clock()
clicked_sprites = pygame.sprite.Group()
teamone_sprites = pygame.sprite.Group()
for i in range(5):
mob1 = TeamOne()
teamone_sprites.add(mob1)
# Game loop
running = True
j=0
while running:
# keep loop running at the right speed
clock.tick(FPS)
# Process input (events)
for event in pygame.event.get():
# check for closing window
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN and j == 0:
pos = pygame.mouse.get_pos()
for s in teamone_sprites:
if s.rect.collidepoint(pos):
#teamone_sprites.add(s)
clicked_sprites.add(s)
print (clicked_sprites)
j = 1
elif event.type == pygame.MOUSEBUTTONDOWN and j == 1:
new_pos = pygame.mouse.get_pos()
#teamone_sprites.update(new_pos)
clicked_sprites.update(new_pos)
j = 0
# Update
# Draw / render
## screen.fill(BLACK)
## draw_grid(screen)
##
## teamone_sprites.draw(screen)
##
##
##
## # *after* drawing everything, flip the display
## pygame.display.flip()
# Draw / render
screen.fill(BLACK)
draw_grid(screen)
teamone_sprites.draw(screen)
pygame.display.flip()
pygame.quit()
def draw_grid(screen):
for i in range(1, HEIGHT, int(HEIGHT/20)):
pygame.draw.line(screen, GREEN, (1,i) ,(WIDTH,i), 2)
for j in range(1, WIDTH, int(WIDTH/20)):
pygame.draw.line(screen, GREEN, (j,1) ,(j,HEIGHT), 2)
if __name__ == '__main__':
main()
Some tips for you:
Keep your main loop clean
Put logic where it belongs
Only call pygame.display.flip()/pygame.display.update() once
Don't use variable names like j
Since your game is grid based, you should have a way to translate between grid coordinates and screen coordinates
Here's a simple runnable example I hacked together (see the comments for some explanations):
import pygame
import random
WIDTH = 900
HEIGHT = 700
ROWS = 20
COLUMNS = 20
TILE_SIZE = WIDTH / COLUMNS, HEIGHT / ROWS
TILE_W, TILE_H = TILE_SIZE
FPS = 60
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
TURN = "TeamOne"
# some functions to translate grid <-> screen coordinates
def posToScreen(pos):
column, row = pos
return column * TILE_W, row * TILE_H
def screenToPos(pos):
column, row = pos
return column / TILE_W, row / TILE_H
def draw_grid(screen):
for i in range(1, HEIGHT, TILE_H):
pygame.draw.line(screen, GREEN, (1,i) ,(WIDTH,i), 2)
for j in range(1, WIDTH, TILE_W):
pygame.draw.line(screen, GREEN, (j,1) ,(j,HEIGHT), 2)
# a class that handles selecting units
class Cursor(pygame.sprite.Sprite):
def __init__(self, units, *groups):
pygame.sprite.Sprite.__init__(self, *groups)
# group of the units that can be controlled
self.units = units
# we create two images
# to indicate if we are selecting or moving
self.image = pygame.Surface(TILE_SIZE)
self.image.set_colorkey((43,43,43))
self.image.fill((43,43,43))
self.rect = self.image.get_rect()
self.selected_image = self.image.copy()
pygame.draw.rect(self.image, pygame.Color('red'), self.image.get_rect(), 4)
pygame.draw.rect(self.selected_image, pygame.Color('purple'), self.image.get_rect(), 4)
self.base_image = self.image
self.selected = None
def update(self):
# let's draw the rect on the grid, based on the mouse position
pos = pygame.mouse.get_pos()
self.rect.topleft = posToScreen(screenToPos(pos))
def handle_click(self, pos):
if not self.selected:
# if we have not selected a unit, do it now
for s in pygame.sprite.spritecollide(self, self.units, False):
self.selected = s
self.image = self.selected_image
else:
# if we have a unit selected, just set its target attribute, so it will move on its own
self.selected.target = posToScreen(screenToPos(pos))
self.image = self.base_image
self.selected = None
class TeamOne(pygame.sprite.Sprite):
def __init__(self, *groups):
pygame.sprite.Sprite.__init__(self, *groups)
self.image = pygame.Surface(TILE_SIZE)
self.image.fill(GREEN)
self.pos = random.randint(0, COLUMNS), random.randint(0, ROWS)
self.rect = self.image.get_rect(topleft = posToScreen(self.pos))
self.target = None
def update(self):
# do nothing until target is set
# (maybe unset it if we reached our target)
if self.target:
if self.rect.x < self.target[0]:
self.rect.move_ip(1, 0)
elif self.rect.x > self.target[0]:
self.rect.move_ip(-1, 0)
elif self.rect.y < self.target[1]:
self.rect.move_ip(0, 1)
elif self.rect.y > self.target[1]:
self.rect.move_ip(0, -1)
self.pos = screenToPos(self.rect.topleft)
def main():
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("A Game")
clock = pygame.time.Clock()
all_sprites = pygame.sprite.LayeredUpdates()
team_ones = pygame.sprite.Group()
for i in range(5):
TeamOne(all_sprites, team_ones)
cursor = Cursor(team_ones, all_sprites)
# a nice, simple, clean main loop
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# we could also pass all events to all sprites
# so we would not need this special clause for the cursor...
if event.type == pygame.MOUSEBUTTONDOWN:
cursor.handle_click(event.pos)
all_sprites.update()
screen.fill(BLACK)
draw_grid(screen)
all_sprites.draw(screen)
pygame.display.flip()
if __name__ == '__main__':
main()
I have pretty much the same Problem i have a healthbar for my enemie but i want all enemys to have one so its a spritegroup now if i want to change an attribute of one object out of my spritegroup i dont know how to properly access it. The Problem lays in the Healthbaranimation function. I tried self.healthbar.sprites() self.healthbar.sprites and spritedict nothing really semms to work. Is there an easy way to fix this? P.s sorry for my bad code It is my first real attempt making a small game
from os import path
import pygame
from elements.ammo import AMMO
from elements.bigenemy import BIGENEMY
from elements.enemy import ENEMY
from elements.player import PLAYER
from .base import BaseState
from elements.healthbar import HEALTHBAR
class Gameplay(BaseState):
def __init__(self):
super(Gameplay, self).__init__()
self.next_state = "GAME_OVER"
self.x, self.y = 100, 1030
self.playersprite = PLAYER((self.x, self.y))
self.bigenemy = pygame.sprite.GroupSingle(BIGENEMY())
self.bottomrect = pygame.Rect((0, 1030), (1920, 50))
self.enemysprite = ENEMY()
self.ammosprite = AMMO()
self.healthbar = pygame.sprite.Group(HEALTHBAR())
self.displayedimage = self.playersprite.image
self.displayedrect = self.playersprite.rect
self.highscore = self.load_data()
self.points = 0
self.scoretext = f"SCORE: {self.points}"
self.scoresurf = self.font.render(self.scoretext, True, "red")
self.nhstext = "NEW HIGHSCORE!"
self.nhssurf = self.font.render(self.nhstext, True, "red")
self.ammotext = f"AMMO:{self.playersprite.ammunition}"
self.ammosurf = self.font.render(self.ammotext, True, "red")
self.bulletgroup = pygame.sprite.Group()
self.time_active = 0
self.bigenemyexisting = True
def get_event(self, event):
if event.type == pygame.QUIT:
self.quit = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LCTRL:
self.playersprite.crouching = True
elif event.key == pygame.K_SPACE:
self.playersprite.jumping = True
elif event.key == pygame.K_q and self.playersprite.ammunition != 0:
self.playersprite.shooting = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_ESCAPE:
self.done = True
elif event.key == pygame.K_LCTRL:
self.playersprite.crouching = False
elif event.key == pygame.K_q:
self.playersprite.shooting = False
def draw(self, surface):
surface.fill(pygame.Color("black"))
pygame.draw.rect(surface, "red", self.bottomrect)
surface.blit(self.displayedimage, (self.displayedrect))
surface.blit(self.enemysprite.image, (self.enemysprite.rect))
surface.blit(self.ammosprite.image, (self.ammosprite.rect))
self.healthbar.draw(surface)
self.bigenemy.draw(surface)
self.bulletgroup.draw(surface)
surface.blit(self.scoresurf, (0, 0))
surface.blit(self.ammosurf, (0, 1000))
if self.points > self.highscore: surface.blit(self.nhssurf, (1920 / 2 - 100, 1080 / 2))
def lost(self):
self.enemysprite.startposx = 1920
self.enemysprite.startposy = self.enemysprite.gettypeenemy()
self.enemysprite.speed = 10
self.highscorefunc()
self.points = 0
self.playersprite.ammunition = 30
def collidecheck(self):
self.playermask = pygame.mask.from_surface(self.displayedimage)
self.enemymask = pygame.mask.from_surface(self.enemysprite.image)
offsetx = self.enemysprite.rect.left - self.displayedrect.left
offsety = self.enemysprite.rect.top - self.displayedrect.top
if self.displayedrect.colliderect(self.enemysprite.rect):
if self.playermask.overlap(self.enemymask, (offsetx, offsety)):
self.lost()
self.done = True
elif self.enemysprite.rect.x < 0 and self.enemysprite.speed < 25:
self.points += 1
self.enemysprite.speed += 1
elif self.enemysprite.speed > 25:
self.enemysprite.speed += .5
elif self.displayedrect.colliderect(self.ammosprite.rect):
self.ammosprite.startposx = 2300
self.playersprite.ammunition += 30
elif pygame.sprite.groupcollide(self.bigenemy,self.bulletgroup,False,True):
self.bigenemy.sprite.health -= 10
def shooting(self, dt):
if self.playersprite.ammunition != 0:
if self.playersprite.shooting and not self.playersprite.jumping and not self.playersprite.crouching:
self.time_active += dt
if self.time_active >= 100:
self.bulletgroup.add(self.playersprite.createbullet())
self.time_active = 0
self.playersprite.ammunition -= 1
else:
self.playersprite.shooting = False
def highscorefunc(self):
if self.points > self.highscore:
self.highscore = self.points
with open(path.join(self.dir, self.HS_FILE), 'w') as f:
f.write(str(self.highscore))
def animation(self):
if not self.playersprite.shooting and not self.playersprite.jumping and not self.playersprite.crouching:
if self.playersprite.index >= len(self.playersprite.basicanimation):
self.playersprite.index = 0
self.displayedimage = self.playersprite.basicanimation[int(self.playersprite.index)]
self.playersprite.index += .1
elif self.playersprite.shooting and not self.playersprite.jumping:
if self.playersprite.index >= len(self.playersprite.shootanimation):
self.playersprite.index = 0
self.displayedimage = self.playersprite.shootanimation[int(self.playersprite.index)]
self.playersprite.index += .1
elif self.playersprite.jumping:
self.displayedimage = self.playersprite.imagejump
elif self.playersprite.crouching:
self.displayedimage = self.playersprite.slidingimage
def healthbaranimation(self):
if self.bigenemy.sprite.health < 90:
self.healthbar.spritedict.index = 1
if self.bigenemy.sprite.health < 80:
self.healthbar.sprite.index = 2
if self.bigenemy.sprite.health < 70:
self.healthbar.sprite.index = 3
if self.bigenemy.sprite.health < 60:
self.healthbar.sprite.index = 4
if self.bigenemy.sprite.health < 50:
self.healthbar.sprite.index = 5
if self.bigenemy.sprite.health < 40:
self.healthbar.sprite.index = 6
if self.bigenemy.sprite.health < 30:
self.healthbar.sprite.index = 7
if self.bigenemy.sprite.health < 20:
self.healthbar.sprite.index = 8
if self.bigenemy.sprite.health < 10:
self.healthbar.sprite.index = 9
def spawnbigenemies(self):
if self.bigenemyexisting:
if self.bigenemy.sprite.health < 3:
self.bigenemy.add(BIGENEMY())
self.bigenemyexisting = True
def update(self, dt):
try:
self.bigenemy.sprite.update()
except:
pass
self.healthbaranimation()
self.healthbar.update()
self.playersprite.jump()
self.animation()
self.shooting(dt)
self.bulletgroup.update()
self.enemysprite.update()
self.ammosprite.update()
self.collidecheck()
self.spawnbigenemies()
self.scoretext = f"SCORE: {self.points}"
self.scoresurf = self.font.render(self.scoretext, True, "black")
self.ammotext = f"AMMO:{self.playersprite.ammunition}"
self.ammosurf = self.font.render(self.ammotext, True, "red")
Been trying to add a scoring system to my game but I keep getting a weird error and now I'm stumped. Here's the code:
##Space Invaders##
import pygame
import sys
from random import shuffle
from pygame.locals import *
##CONSTANTS##
## Colors ##
GRAY = (100,100,100)
NAVYBLUE = (60,60,100)
WHITE = (255,255,255)
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
YELLOW = (255,255,0)
ORANGE = (255,128,0)
PURPLE = (255,0,255)
CYAN = (0,255,255)
BLACK = (0,0,0)
NEARBLACK = (19,15,48)
COMBLUE = (233,232,255)
## Player ##
PLAYERWIDTH = 40
PLAYERHEIGHT = 10
PLAYERCOLOR = COMBLUE
PLAYER1 = 'Player 1'
PLAYERSPEED = 5
PLAYERCOLOR = GREEN
## Display ##
GAMETITLE =('SPACE INVADERS')
DISPLAYWIDTH = 640
DISPLAYHEIGHT = 480
BGCOLOR = NEARBLACK
XMARGIN = 50
YMARGIN = 50
## Bullet ##
BULLETWIDTH = 5
BULLETHEIGHT = 5
BULLETOFFSET = 700
## Enemy ##
ENEMYWIDTH = 25
ENEMYHEIGHT = 25
ENEMYNAME = 'Enemy'
ENEMYGAP = 20
ARRAYWIDTH = 10
ARRAYHEIGHT = 4
MOVETIME = 1000
MOVEX = 10
MOVEY = ENEMYHEIGHT
TIMEOFFSET = 300
## SCORE ##
score=0
## This allows for shooting bullets while moving without
## the inputs interupting each other.
DIRECT_DICT = {pygame.K_LEFT : (-1),
pygame.K_RIGHT : (1)}
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.width = PLAYERWIDTH
self.height = PLAYERHEIGHT
self.image = pygame.Surface((self.width, self.height))
self.color = PLAYERCOLOR
self.image.fill(self.color)
self.rect = self.image.get_rect()
self.name = PLAYER1
self.speed = PLAYERSPEED
self.vectorx = 0
def update(self, keys, *args):
for key in DIRECT_DICT:
if keys[key]:
self.rect.x += DIRECT_DICT[key] * self.speed
self.checkForSide()
self.image.fill(self.color)
def checkForSide(self):
if self.rect.right > DISPLAYWIDTH:
self.rect.right = DISPLAYWIDTH
self.vectorx = 0
elif self.rect.left < 0:
self.rect.left = 0
self.vectorx = 0
class Blocker(pygame.sprite.Sprite):
def __init__(self, side, color, row, column):
pygame.sprite.Sprite.__init__(self)
self.width = side
self.height = side
self.color = color
self.image = pygame.Surface((self.width, self.height))
self.image.fill(self.color)
self.rect = self.image.get_rect()
self.name = 'blocker'
self.row = row
self.column = column
class Bullet(pygame.sprite.Sprite):
def __init__(self, rect, color, vectory, speed):
pygame.sprite.Sprite.__init__(self)
self.width = BULLETWIDTH
self.height = BULLETHEIGHT
self.color = color
self.image = pygame.Surface((self.width, self.height))
self.image.fill(self.color)
self.rect = self.image.get_rect()
self.rect.centerx = rect.centerx
self.rect.top = rect.bottom
self.name = 'bullet'
self.vectory = vectory
self.speed = speed
def update(self, *args):
self.oldLocation = (self.rect.x, self.rect.y)
self.rect.y += self.vectory * self.speed
if self.rect.bottom < 0:
self.kill()
elif self.rect.bottom > 500:
self.kill()
class Enemy(pygame.sprite.Sprite):
def __init__(self, row, column):
pygame.sprite.Sprite.__init__(self)
self.width = ENEMYWIDTH
self.height = ENEMYHEIGHT
self.row = row
self.column = column
self.image = self.setImage()
self.rect = self.image.get_rect()
self.name = 'enemy'
self.vectorx = 1
self.moveNumber = 0
self.moveTime = MOVETIME
self.timeOffset = row * TIMEOFFSET
self.timer = pygame.time.get_ticks() - self.timeOffset
def update(self, keys, currentTime):
if currentTime - self.timer > self.moveTime:
if self.moveNumber < 6:
self.rect.x += MOVEX * self.vectorx
self.moveNumber += 1
elif self.moveNumber >= 6:
self.vectorx *= -1
self.moveNumber = 0
self.rect.y += MOVEY
if self.moveTime > 100:
self.moveTime -= 50
self.timer = currentTime
def setImage(self):
if self.row == 0:
image = pygame.image.load('alien1.png')
elif self.row == 1:
image = pygame.image.load('alien2.png')
elif self.row == 2:
image = pygame.image.load('alien3.png')
else:
image = pygame.image.load('alien1.png')
image.convert_alpha()
image = pygame.transform.scale(image, (self.width, self.height))
return image
class Text(object):
def __init__(self, font, size, message, color, rect, surface):
self.font = pygame.font.Font(font, size)
self.message = message
self.surface = self.font.render(self.message, True, color)
self.rect = self.surface.get_rect()
self.setRect(rect)
def setRect(self,rect):
self.rect.centerx = rect.centerx - 5
self.rect.centery = rect.centery - 5
def draw(self, surface):
surface.blit(self.surface, self.rect)
class App(object):
def __init__(self):
pygame.init()
self.displaySurf, self.displayRect = self.makeScreen()
self.gameStart = True
self.gameOver = False
self.gameWon = False
self.beginGame = False
self.laserSound = pygame.mixer.Sound('laser.ogg')
self.startLaser = pygame.mixer.Sound('alienLaser.ogg')
self.playIntroSound = True
def resetGame(self):
self.gameStart = True
self.needToMakeEnemies = True
self.introMessage1 = Text('orena.ttf', 50,'Space Invaders',GREEN, self.displayRect,self.displaySurf)
self.introMessage2 = Text('orena.ttf', 25,'Press Space to Continue',GREEN, self.displayRect,self.displaySurf)
self.introMessage2.rect.top = self.introMessage1.rect.bottom + 5
self.gameOverMessage = Text('orena.ttf', 50,'GAME OVER',GREEN, self.displayRect,self.displaySurf)
self.gameWinMessage = Text('orena.ttf',50,'Congrats You Won',GREEN,self.displayRect,self.displaySurf)
self.gameWinMessage2 = Text('orena.ttf', 30,'Click Space to return to the menu',GREEN, self.displayRect,self.displaySurf)
self.gameWinMessage2.rect.top = self.gameWinMessage.rect.bottom + 5
self.scoreText = Text('orena.ttf',10,'Score:',WHITE,self.displayRect,self.displaySurf)
self.player = self.makePlayer()
self.bullets = pygame.sprite.Group()
self.greenBullets = pygame.sprite.Group()
self.blockerGroup1 = self.makeBlockers(0)
self.blockerGroup2 = self.makeBlockers(1)
self.blockerGroup3 = self.makeBlockers(2)
self.blockerGroup4 = self.makeBlockers(3)
self.allBlockers = pygame.sprite.Group(self.blockerGroup1, self.blockerGroup2,self.blockerGroup3, self.blockerGroup4)
self.allSprites = pygame.sprite.Group(self.player, self.allBlockers)
self.keys = pygame.key.get_pressed()
self.clock = pygame.time.Clock()
self.fps = 60
self.score = score
self.enemyMoves = 0
self.enemyBulletTimer = pygame.time.get_ticks()
self.gameOver = False
self.gameWon = False
self.gameOverTime = pygame.time.get_ticks()
self.gameWinTime = pygame.time.get_ticks()
if self.playIntroSound:
self.startLaser.play()
self.playIntroSound = False
def makeBlockers(self, number=1):
blockerGroup = pygame.sprite.Group()
for row in range(5):
for column in range(7):
blocker = Blocker(10, GREEN, row, column)
blocker.rect.x = 50 + (150 * number) + (column * blocker.width)
blocker.rect.y = 375 + (row * blocker.height)
blockerGroup.add(blocker)
for blocker in blockerGroup:
if (blocker.column == 0 and blocker.row == 0
or blocker.column == 6 and blocker.row == 0):
blocker.kill()
return blockerGroup
def checkForEnemyBullets(self):
redBulletsGroup = pygame.sprite.Group()
for bullet in self.bullets:
if bullet.color == RED:
redBulletsGroup.add(bullet)
for bullet in redBulletsGroup:
if pygame.sprite.collide_rect(bullet, self.player):
if self.player.color == GREEN:
self.player.color = YELLOW
elif self.player.color == YELLOW:
self.player.color = RED
elif self.player.color == RED:
self.gameOver = True
self.gameOverTime = pygame.time.get_ticks()
bullet.kill()
def shootEnemyBullet(self, rect):
if (pygame.time.get_ticks() - self.enemyBulletTimer) > BULLETOFFSET:
self.bullets.add(Bullet(rect, RED, 1, 5))
self.allSprites.add(self.bullets)
self.enemyBulletTimer = pygame.time.get_ticks()
def findEnemyShooter(self):
columnList = []
for enemy in self.enemies:
columnList.append(enemy.column)
#get rid of duplicate columns
columnSet = set(columnList)
columnList = list(columnSet)
shuffle(columnList)
column = columnList[0]
enemyList = []
rowList = []
for enemy in self.enemies:
if enemy.column == column:
rowList.append(enemy.row)
row = max(rowList)
for enemy in self.enemies:
if enemy.column == column and enemy.row == row:
self.shooter = enemy
def makeScreen(self):
pygame.display.set_caption(GAMETITLE)
displaySurf = pygame.display.set_mode((DISPLAYWIDTH, DISPLAYHEIGHT))
displayRect = displaySurf.get_rect()
displaySurf.fill(BGCOLOR)
displaySurf.convert()
return displaySurf, displayRect
def makePlayer(self):
player = Player()
#Place the player centerx and five pixels from the bottom
player.rect.centerx = self.displayRect.centerx
player.rect.bottom = self.displayRect.bottom - 5
return player
def makeEnemies(self):
enemies = pygame.sprite.Group()
for row in range(ARRAYHEIGHT):
for column in range(ARRAYWIDTH):
enemy = Enemy(row, column)
enemy.rect.x = XMARGIN + (column * (ENEMYWIDTH + ENEMYGAP))
enemy.rect.y = YMARGIN + (row * (ENEMYHEIGHT + ENEMYGAP))
enemies.add(enemy)
return enemies
def checkInput(self):
for event in pygame.event.get():
self.keys = pygame.key.get_pressed()
if event.type == QUIT:
self.terminate()
elif event.type == KEYDOWN:
if event.key == K_SPACE and len(self.greenBullets) < 1:
if self.score < 1000:
bullet = Bullet(self.player.rect, GREEN, -1, 20)
self.greenBullets.add(bullet)
self.bullets.add(self.greenBullets)
self.allSprites.add(self.bullets)
self.laserSound.play()
elif event.key == K_ESCAPE:
self.terminate()
def calculate_score(self, row):
scores = {0: 30,
1: 20,
2: 20,
3: 10,
4: 10,
5: choice([50, 100, 150, 300])
}
score = scores[row]
self.score += score
return score
def gameStartInput(self):
for event in pygame.event.get():
if event.type == QUIT:
self.terminate()
elif event.type == KEYUP:
self.gameWon = False
self.gameOver = False
self.gameStart = False
self.beginGame = True
def gameOverInput(self):
for event in pygame.event.get():
if event.type == QUIT:
self.terminate()
elif event.type == KEYUP:
self.gameStart = True
self.beginGame = False
self.gameOver = False
self.gameWon = False
def gameWonInput(self):
for event in pygame.event.get():
if event.type == QUIT:
self.terminate()
elif event.type == KEYUP:
self.gameStart = True
self.beginGame = False
self.gameOver = False
self.gameWon = False
def checkCollisions(self):
self.checkForEnemyBullets()
enemiesdict = pygame.sprite.groupcollide(self.bullets, self.enemies, True, True)
if enemiesdict:
for value in enemiesdict.values():
for currentSprite in value:
self.killedRow = currentSprite.row
self.killedColumn = currentSprite.column
score = self.calculate_score(currentSprite.row)
self.enemies.remove(currentSprite)
self.allSprites.remove(currentSprite)
pygame.sprite.groupcollide(self.enemies, self.allBlockers, False, True)
self.collide_green_blockers()
self.collide_red_blockers()
def collide_green_blockers(self):
for bullet in self.greenBullets:
casting = Bullet(self.player.rect, GREEN, -1, 20)
casting.rect = bullet.rect.copy()
for pixel in range(bullet.speed):
hit = pygame.sprite.spritecollideany(casting,self.allBlockers)
if hit:
hit.kill()
bullet.kill()
break
casting.rect.y -= 1
def collide_red_blockers(self):
reds = (shot for shot in self.bullets if shot.color == RED)
red_bullets = pygame.sprite.Group(reds)
pygame.sprite.groupcollide(red_bullets, self.allBlockers, True, True)
def checkGameOver(self):
if len(self.enemies) == 0:
self.gameWon = True
self.gameStart = False
self.beginGame = False
self.gameOverTime = pygame.time.get_ticks()
self.gameWinTime = pygame.time.get_ticks()
else:
for enemy in self.enemies:
if enemy.rect.bottom > DISPLAYHEIGHT:
self.gameOver = True
self.gameStart = False
self.beginGame = False
self.gameOverTime = pygame.time.get_ticks()
def terminate(self):
pygame.quit()
sys.exit()
def mainLoop(self):
while True:
if self.gameStart:
self.resetGame()
self.gameOver = False
self.displaySurf.fill(BGCOLOR)
self.introMessage1.draw(self.displaySurf)
self.introMessage2.draw(self.displaySurf)
self.scoreText2 = Text('orena.ttf', 20, str(self.score), GREEN, 85, 5)
self.scoreText.draw(self.screen)
self.scoreText2.draw(self.screen)
self.gameStartInput()
pygame.display.update()
elif self.gameOver:
self.playIntroSound = True
self.displaySurf.fill(BGCOLOR)
self.gameOverMessage.draw(self.displaySurf)
#prevent users from exiting the GAME OVER screen
#too quickly
if (pygame.time.get_ticks() - self.gameOverTime) > 2000:
self.gameOverInput()
pygame.display.update()
elif self.gameWon:
self.gameOver = False
self.playIntroSound = True
self.displaySurf.fill(BGCOLOR)
self.gameWinMessage.draw(self.displaySurf)
self.gameWinMessage2.draw(self.displaySurf)
if (pygame.time.get_ticks() - self.gameWinTime) > 2000:
self.gameWonInput()
pygame.display.update()
elif self.beginGame:
if self.needToMakeEnemies:
self.enemies = self.makeEnemies()
self.allSprites.add(self.enemies)
self.needToMakeEnemies = False
pygame.event.clear()
else:
currentTime = pygame.time.get_ticks()
self.displaySurf.fill(BGCOLOR)
self.checkInput()
self.allSprites.update(self.keys, currentTime)
self.scoreText2 = Text('orena.ttf', 20, str(self.score), WHITE, 85, 5)
self.scoreText.draw(self.screen)
self.scoreText2.draw(self.screen)
if len(self.enemies) > 0:
self.findEnemyShooter()
self.shootEnemyBullet(self.shooter.rect)
self.checkCollisions()
self.allSprites.draw(self.displaySurf)
self.blockerGroup1.draw(self.displaySurf)
pygame.display.update()
self.checkGameOver()
self.clock.tick(self.fps)
if __name__ == '__main__':
app = App()
app.mainLoop()
Error (Line 178):
AttributeError: 'int' object has no attribute 'centerx'
Game files like pictures, sound files, etc. can be changed/replaced. If you need the files let me know. However I'd prefer if I could keep those private.
Thanks in advance! Any help is appreciated.
In this class:
class Text(object):
def __init__(self, font, size, message, color, rect, surface):
In the init you have:
self.rect = self.surface.get_rect()
self.setRect(rect)
Notice you are setting self.rect but sending rect to the function
It should be
self.rect = self.surface.get_rect()
self.setRect(self.rect)
The issue also comes from this call:
self.scoreText2 = Text('orena.ttf', 20, str(self.score), GREEN, 85, 5)
Most places you call it by sending something like:
self.introMessage1 = Text('orena.ttf', 50,'Space Invaders',GREEN, self.displayRect,self.displaySurf)
self.displayRect has a centerx. The int 85 does not.
Debugging
Read and understand your error message:
It is telling you rect is an int but you are expecting a rect type. Print your values until you find where it changes from being correct to wrong to narrow down the issue.
Also, by creating a Minimal, Complete, and Verifiable example, a lot of the noise goes away and you are able to focus on your issue and can often catch errors like these yourself.
I am building a game and I keep on running up against this error. I can't seem to fix it. I believe the problem is either in the function "main" at the bottom or in the classes "Level" and "Level01". If you find there is a way I can improve my code can you also tell me as I am just learning how to build games with OOP.
File "C:/Users/fabma/Documents/PythonGames/RPG/Scroller!.py", line 148, in main
currentLevel.drawer(display)
TypeError: drawer() missing 1 required positional argument: 'display1'
Here is my code:
import pygame
# Colours + Global constants
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WIDTH = 800
HEIGHT = 600
SIZE = (WIDTH, HEIGHT)
# CLASSES
# Block is the common platform
class Block(pygame.sprite.Sprite):
def __init__(self, length, height, colour):
super().__init__()
# Making image
self.image = pygame.Surface([length, height])
self.image.fill(colour)
self.rect = self.image.get_rect()
# Setting Y coordinates
self.rect.y = HEIGHT * 0.95
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
# Is it touching the floor?
self.velocity = 0
self.standing = True
# Rendering image and creating some variables
self.height = 40
self.length = 40
self.sprite_x_change = 0
self.sprite_y_change = 0
self.image = pygame.Surface([self.height, self.length])
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.y = HEIGHT * 0.884
self.level = None
# Mobility: Left, right, up and stop
def move_right(self):
self.sprite_x_change = 15
def move_left(self):
self.sprite_x_change = -15
def move_up(self, platform):
# Seeing if we hit anything if so then we can jump!
self.rect.y -= 2
hit_list = pygame.sprite.spritecollide(self, platform, False)
if len(hit_list) > 0 or self.rect.bottom >= HEIGHT - Block.height:
self.change_y = -10
def stop(self):
self.sprite_x_change = 0
def updater(self):
self.gravity()
platforms_hit = pygame.sprite.spritecollide(self, self.level.platforms, False)
for blocks in platforms_hit:
self.sprite_y_change = 0
# Going down
if self.sprite_y_change > 0:
self.rect.bottom = blocks.rect.top
self.velocity = 0
self.standing = True
# Going up
if self.sprite_y_change < 0:
self.rect.top = blocks.rect.bottom
self.standing = False
if self.sprite_x_change > 0:
self.rect.right = blocks.rect.left
if self.sprite_x_change < 0:
self.rect.left = blocks.rect.right
if self.sprite_x_change == 0 and self.sprite_y_change == 0:
self.rect.y = HEIGHT * 0.884
if self.standing == False:
self.velocity += 1
self.rect.x += self.sprite_x_change
self.rect.y += self.sprite_y_change
def gravity(self):
self.sprite_y_change += 0.980665*self.velocity
class Level:
def __init__(self):
# Creating groups
self.sprites = pygame.sprite.Group()
self.all_things = pygame.sprite.Group()
self.platforms = pygame.sprite.Group()
def drawer(self, display1):
display1.fill(BLUE)
self.all_things.draw(display1)
class Level01(Level):
def __init__(self, player1):
# Initialise level1
Level.__init__(self)
# Level01 things
block = Block(WIDTH, HEIGHT * 0.05, RED)
Level.all_things = self.all_things
self.sprites.add(player1)
self.platforms.add(block)
self.all_things.add(player1, block)
def main():
# Init pygame
pygame.init()
# Set screen
display = pygame.display.set_mode(SIZE)
# Creating FPS thingy
clock = pygame.time.Clock()
# Making levels + Player
player = Player()
level_1 = Level01(player)
# Choosing level
levelList = []
levelList.append(Level01)
currentLevelNumber = 0
currentLevel = levelList[currentLevelNumber]
# Game loop
loop = True
while loop == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
player.move_right()
if event.key == pygame.K_LEFT:
player.move_left()
if event.key == pygame.K_UP:
player.move_up(currentLevel.platforms)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and player.sprite_x_change < 0:
player.stop()
if event.key == pygame.K_RIGHT and player.sprite_x_change > 0:
player.stop()
# Update things
currentLevel.all_things.update()
currentLevel.drawer(display)
# Refresh screen
clock.tick(30)
pygame.display.update()
pygame.quit()
if __name__ == "__main__":
main()
You need to create an instance of your level rather than just appending the class itself into your list:
levelList.append(Level01)
should be...
levelList.append(level_1)
As it stands, you're using the class object rather than an instance of it, which means that the display you're passing is getting put into the self argument (because the class object won't pass along an instance, because it's not one). Once you're calling it on an instance of the class, the self argument will be automatically passed and thus your display argument will get passed to the correct spot.
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
Can anyone help me I'm trying to get my space background to work on the game but it I can't seem to do it, can anyone spot something I can't or see where I am going wrong. I have merged two of my codes so I am unsure where I have gone wrong but have tried fix it, but just get a blur.
import pygame, random, time
import os,sys,random
import pygame
from pygame.locals import *
pygame.init()
#set up the graphics window
size = [800, 595]
screen = pygame.display.set_mode(size, 0)
screenrect = screen.get_rect()
pygame.display.set_caption("Mathsvaders")
clock = pygame.time.Clock()
# set some variables
done = False
life = 3
aliens = pygame.sprite.Group()
allsprites = pygame.sprite.Group()
bombs = pygame.sprite.Group()
green = [0, 255, 0]
white = [255, 255, 255]
def disp(phrase, loc, screen, color): # func to display text
s = font.render(phrase, True, color)
screen.blit(s, loc)
def draw_star(star): # drawing a star
# you only need to change a pixel, so use set_at, not draw.line
screen.set_at((star[0], star[1]), (255, 255, 255))
star[0] -= 1
if star[0] < 0:
star[0] = screen.get_width()
star[1] = random.randint(0, screen.get_height())
# creating list of stars, used multi-line for loop for readability
stars = []
for i in range(200):
x = random.randint(0, screen.get_width())
y = random.randint(0, screen.get_height())
stars.append([x,y])
# drawing stars
for star in stars:
draw_star(star)
screen.fill((0,0,0))
pygame.display.flip()
clock.tick(22)
# create a timer to control how often the screen updates
clock = pygame.time.Clock()
fps = 100
# loads images to use in the game which link in with my classes(further down)
cannon = pygame.image.load("spaceship.png").convert()
cannon.set_colorkey(white)
blast = pygame.image.load("blast.png").convert_alpha()
boom = pygame.image.load("expl.png").convert_alpha()
bomb = pygame.image.load("missile_player.png").convert_alpha()
back = pygame.image.load("rsz_space.png").convert()
enemy = pygame.image.load("sii.png").convert_alpha()
lives2 = pygame.image.load("alien2.png").convert()
lives2.set_colorkey(white)
lives3 = pygame.image.load("alien3.png").convert()
lives3.set_colorkey(white)
lives1 = pygame.image.load("alien1.png").convert()
lives1.set_colorkey(white)
# (Classes)
# the explosion class
class Explosion(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = boom
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.centery = y
self.count = 6
def update(self):
self.count -= 1
if self.count < 1:
self.kill()
class scoreClass:
def __init__(self):
self.value = 0
# set a font, default font size 28
self.font = pygame.font.Font(None, 28)
def update(self):
text = self.font.render("Score: %s" % self.value, True, (green))
textRect = text.get_rect()
textRect.centerx = screenrect.centerx
screen.blit(text, textRect)
class Msg:
def __init__(self, words):
# set a font, default font size 28
self.font = pygame.font.Font(None, 28)
self.text = self.font.render(words, True, (green))
self.textRect = self.text.get_rect()
def update(self):
self.textRect.centerx = screenrect.centerx
self.textRect.centery = screenrect.centery
screen.blit(self.text, self.textRect)
# the invader class
class Pi(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
aliens.add(self)
self.image = enemy
self.rect = self.image.get_rect()
self.rect.left = x
self.rect.top = y
self.speed = 1
def update(self):
self.rect.right += self.speed
if self.rect.right >= (screenrect.right -5):
self.speed = -1
self.rect.top += self.rect.height
if self.rect.left <= (screenrect.left +5):
self.speed = 1
self.rect.top += self.rect.height
if self.rect.top > screenrect.bottom:
self.kill()
i = random.randrange(200)
j = self.rect.centerx
if i == 1:
laser_bomb = Bomb(j, self.rect.bottom)
allsprites.add(laser_bomb)
aliens.add(laser_bomb)
class Gun(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = cannon
self.rect = self.image.get_rect()
self.rect.bottom = screenrect.bottom
self.rect.centerx = screenrect.centerx
self.speed=0
def update(self):
self.rect.centerx += self.speed
if self.rect.right >= screenrect.right:
self.rect.centerx = 0
if self.rect.right <= 0:
self.rect.right = screenrect.right
# bomb class
class Bomb(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = bomb
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.centery = y
bombs.add(self)
def update(self):
self.rect.centery +=1
# the laser blast class
class Blast(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = blast
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.top = (player.rect.top + 5)
self.rect.centerx = player.rect.centerx
self.speed = 0
def update(self):
if self.speed == 0:
self.rect.centerx = player.rect.centerx
self.rect.top -= self.speed
# function to make a sheet of invaders
def invade():
for j in range(10, 240, 120):
for i in range(5):
aliens.add(Pi((i*70)+10, j))
def gameover():
message = Msg("Game Over")
message.update()
player.kill()
shot.kill()
pre-game window
invade()
message = Msg("Press a key to play.")
allsprites.add(aliens)
key = True
while key:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
for item in (aliens):
item.kill()
key = False
allsprites.update()
allsprites.draw(screen)
message.update()
# set the loop to 40 cycles per second
clock.tick(fps)
# update the display
pygame.display.flip()
# Main Game Starts Here
score = scoreClass()
player = Gun()
shot = Blast()
invade()
allsprites.add(player, aliens, shot)
while done==False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done=True
if life <= 0:
gameover()
else:
# shoots laser missile
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
if shot.speed == 0:
shot.speed = 5
#laser.play()
if event.key == pygame.K_LEFT:
player.speed = -3
if event.key == pygame.K_RIGHT:
player.speed = 3
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.speed = 0
if event.key == pygame.K_RIGHT:
player.speed = 0
hit = pygame.sprite.spritecollide(shot, aliens, 1)
if len(hit) > 0:
explosion1 = Explosion(shot.rect.centerx, shot.rect.top)
score.value += 100
shot.kill()
#explode.play()
shot = Blast()
allsprites.add(shot, explosion1)
hit2 = pygame.sprite.spritecollide(player, aliens, 1)
if len(hit2) > 0:
life -= 1
#explode.play()
explosion2 = Explosion(player.rect.centerx, player.rect.centery)
allsprites.add(explosion2)
player.kill()
shot.kill()
if life > 0:
ready = Msg("Push Harder !!.")
ready.update()
allsprites.update()
allsprites.draw(screen)
score.update()
pygame.display.flip()
for item in bombs:
item.kill()
while 1:
event = pygame.event.wait()
if event.type == pygame.KEYDOWN:
break
player = Gun()
shot = Blast()
allsprites.add(player, shot)
if shot.rect.top <= screenrect.top:
shot.kill()
shot = Blast()
allsprites.add(shot)
if life == 2:
men = lives2
if life == 1:
men = lives1
if life == 3:
men = lives3
if life > 0:
screen.blit(men, (0,0))
allsprites.update()
allsprites.draw(screen)
score.update()
# set the loop to "fps" cycles per second
clock.tick(fps)
# update the display
pygame.display.flip()
# close pygame
pygame.quit()
You are erasing the screen after drawing the stars. Change:
# drawing stars
for star in stars:
draw_star(star)
screen.fill((0,0,0))
pygame.display.flip()
to:
screen.fill((0,0,0))
# drawing stars
for star in stars:
draw_star(star)
pygame.display.flip()
i'd like to add the same collision detection used by the player sprite to the enemy sprites or 'creeps' ive added all the relevant code I can see yet collisons are still not being detected and handled, please find below the class, I have no idea what is wrong currently, the list of walls to collide with is 'wall_list'
import pygame
import pauseScreen as dm
import re
from pygame.sprite import Sprite
from pygame import Rect, Color
from random import randint, choice
from vec2d import vec2d
from simpleanimation import SimpleAnimation
import displattxt
black = (0,0,0)
white = (255,255,255)
blue = (0,0,255)
green = (101,194,151)
global currentEditTool
currentEditTool = "Tree"
global editMap
editMap = False
open('MapMaker.txt', 'w').close()
def draw_background(screen, tile_img):
screen.fill(black)
img_rect = tile_img.get_rect()
global rect
rect = img_rect
nrows = int(screen.get_height() / img_rect.height) + 1
ncols = int(screen.get_width() / img_rect.width) + 1
for y in range(nrows):
for x in range(ncols):
img_rect.topleft = (x * img_rect.width,
y * img_rect.height)
screen.blit(tile_img, img_rect)
def changeTool():
if currentEditTool == "Tree":
None
elif currentEditTool == "Rock":
None
def pauseGame():
red = 255, 0, 0
green = 0,255, 0
blue = 0, 0,255
screen.fill(black)
pygame.display.update()
if editMap == False:
choose = dm.dumbmenu(screen, [
'Resume',
'Enable Map Editor',
'Quit Game'], 64,64,None,32,1.4,green,red)
if choose == 0:
print("hi")
elif choose ==1:
global editMap
editMap = True
elif choose ==2:
print("bob")
elif choose ==3:
print("bob")
elif choose ==4:
print("bob")
else:
None
else:
choose = dm.dumbmenu(screen, [
'Resume',
'Disable Map Editor',
'Quit Game'], 64,64,None,32,1.4,green,red)
if choose == 0:
print("Resume")
elif choose ==1:
print("Dis ME")
global editMap
editMap = False
elif choose ==2:
print("bob")
elif choose ==3:
print("bob")
elif choose ==4:
print("bob")
else:
None
class Wall(pygame.sprite.Sprite):
# Constructor function
def __init__(self,x,y,width,height):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([width, height])
self.image.fill(green)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class insertTree(pygame.sprite.Sprite):
def __init__(self,x,y,width,height, typ):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images/map/tree.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class insertRock(pygame.sprite.Sprite):
def __init__(self,x,y,width,height, typ):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images/map/rock.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class Creep(pygame.sprite.Sprite):
""" A creep sprite that bounces off walls and changes its
direction from time to time.
"""
change_x=0
change_y=0
def __init__(
self, screen, creep_image, explosion_images,
field, init_position, init_direction, speed):
""" Create a new Creep.
screen:
The screen on which the creep lives (must be a
pygame Surface object, such as pygame.display)
creep_image:
Image (surface) object for the creep
explosion_images:
A list of image objects for the explosion
animation.
field:
A Rect specifying the 'playing field' boundaries.
The Creep will bounce off the 'walls' of this
field.
init_position:
A vec2d or a pair specifying the initial position
of the creep on the screen.
init_direction:
A vec2d or a pair specifying the initial direction
of the creep. Must have an angle that is a
multiple of 45 degres.
speed:
Creep speed, in pixels/millisecond (px/ms)
"""
Sprite.__init__(self)
self.screen = screen
self.speed = speed
self.field = field
self.rect = creep_image.get_rect()
# base_image holds the original image, positioned to
# angle 0.
# image will be rotated.
#
self.base_image = creep_image
self.image = self.base_image
self.explosion_images = explosion_images
# A vector specifying the creep's position on the screen
#
self.pos = vec2d(init_position)
# The direction is a normalized vector
#
self.direction = vec2d(init_direction).normalized()
self.state = Creep.ALIVE
self.health = 15
def is_alive(self):
return self.state in (Creep.ALIVE, Creep.EXPLODING)
def changespeed(self,x,y):
self.change_x+=x
self.change_y+=y
def update(self, time_passed, walls):
""" Update the creep.
time_passed:
The time passed (in ms) since the previous update.
"""
if self.state == Creep.ALIVE:
# Maybe it's time to change the direction ?
#
self._change_direction(time_passed)
# Make the creep point in the correct direction.
# Since our direction vector is in screen coordinates
# (i.e. right bottom is 1, 1), and rotate() rotates
# counter-clockwise, the angle must be inverted to
# work correctly.
#
self.image = pygame.transform.rotate(
self.base_image, -self.direction.angle)
# Compute and apply the displacement to the position
# vector. The displacement is a vector, having the angle
# of self.direction (which is normalized to not affect
# the magnitude of the displacement)
#
displacement = vec2d(
self.direction.x * self.speed * time_passed,
self.direction.y * self.speed * time_passed)
self.pos += displacement
# When the image is rotated, its size is changed.
# We must take the size into account for detecting
# collisions with the walls.
#
self.image_w, self.image_h = self.image.get_size()
bounds_rect = self.field.inflate(
-self.image_w, -self.image_h)
if self.pos.x < bounds_rect.left:
self.pos.x = bounds_rect.left
self.direction.x *= -1
elif self.pos.x > bounds_rect.right:
self.pos.x = bounds_rect.right
self.direction.x *= -1
elif self.pos.y < bounds_rect.top:
self.pos.y = bounds_rect.top
self.direction.y *= -1
elif self.pos.y > bounds_rect.bottom:
self.pos.y = bounds_rect.bottom
self.direction.y *= -1
# collision detection
old_x=bounds_rect.left
new_x=old_x+self.direction.x
bounds_rect.left = new_x
# hit a wall?
collide = pygame.sprite.spritecollide(self, walls, False)
if collide:
# yes
bounds_rect.left=old_x
old_y=self.pos.y
new_y=old_y+self.direction.y
self.pos.y = new_y
collide = pygame.sprite.spritecollide(self, walls, False)
if collide:
# yes
self.pos.y=old_y
elif self.state == Creep.EXPLODING:
if self.explode_animation.active:
self.explode_animation.update(time_passed)
else:
self.state = Creep.DEAD
self.kill()
elif self.state == Creep.DEAD:
pass
#------------------ PRIVATE PARTS ------------------#
# States the creep can be in.
#
# ALIVE: The creep is roaming around the screen
# EXPLODING:
# The creep is now exploding, just a moment before dying.
# DEAD: The creep is dead and inactive
#
(ALIVE, EXPLODING, DEAD) = range(3)
_counter = 0
def _change_direction(self, time_passed):
""" Turn by 45 degrees in a random direction once per
0.4 to 0.5 seconds.
"""
self._counter += time_passed
if self._counter > randint(400, 500):
self.direction.rotate(45 * randint(-1, 1))
self._counter = 0
def _point_is_inside(self, point):
""" Is the point (given as a vec2d) inside our creep's
body?
"""
img_point = point - vec2d(
int(self.pos.x - self.image_w / 2),
int(self.pos.y - self.image_h / 2))
try:
pix = self.image.get_at(img_point)
return pix[3] > 0
except IndexError:
return False
def _decrease_health(self, n):
""" Decrease my health by n (or to 0, if it's currently
less than n)
"""
self.health = max(0, self.health - n)
if self.health == 0:
self._explode()
def _explode(self):
""" Starts the explosion animation that ends the Creep's
life.
"""
self.state = Creep.EXPLODING
pos = ( self.pos.x - self.explosion_images[0].get_width() / 2,
self.pos.y - self.explosion_images[0].get_height() / 2)
self.explode_animation = SimpleAnimation(
self.screen, pos, self.explosion_images,
100, 300)
global remainingCreeps
remainingCreeps-=1
if remainingCreeps == 0:
print("all dead")
def draw(self):
""" Blit the creep onto the screen that was provided in
the constructor.
"""
if self.state == Creep.ALIVE:
# The creep image is placed at self.pos. To allow for
# smooth movement even when the creep rotates and the
# image size changes, its placement is always
# centered.
#
self.draw_rect = self.image.get_rect().move(
self.pos.x - self.image_w / 2,
self.pos.y - self.image_h / 2)
self.screen.blit(self.image, self.draw_rect)
# The health bar is 15x4 px.
#
health_bar_x = self.pos.x - 7
health_bar_y = self.pos.y - self.image_h / 2 - 6
self.screen.fill( Color('red'),
(health_bar_x, health_bar_y, 15, 4))
self.screen.fill( Color('green'),
( health_bar_x, health_bar_y,
self.health, 4))
elif self.state == Creep.EXPLODING:
self.explode_animation.draw()
elif self.state == Creep.DEAD:
pass
def mouse_click_event(self, pos):
""" The mouse was clicked in pos.
"""
if self._point_is_inside(vec2d(pos)):
self._decrease_health(3)
#begin new player
class Player(pygame.sprite.Sprite):
change_x=0
change_y=0
frame = 0
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
# LOAD PLATER IMAGES
# Set height, width
self.images = []
for i in range(1,17):
img = pygame.image.load("images/player/" + str(i)+".png").convert() #player images
img.set_colorkey(white)
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.health = 15
self.image_w, self.image_h = self.image.get_size()
health_bar_x = self.rect.x - 7
health_bar_y = self.rect.y - self.image_h / 2 - 6
screen.fill( Color('red'),
(health_bar_x, health_bar_y, 15, 4))
screen.fill( Color('green'),
( health_bar_x, health_bar_y,
self.health, 4))
def changespeed(self,x,y):
self.change_x+=x
self.change_y+=y
def _decrease_health(self, n):
""" Decrease my health by n (or to 0, if it's currently
less than n)
"""
self.health = max(0, self.health - n)
if self.health == 0:
self._explode()
def update(self,walls):
# collision detection
old_x=self.rect.x
new_x=old_x+self.change_x
self.rect.x = new_x
# hit a wall?
collide = pygame.sprite.spritecollide(self, walls, False)
if collide:
# yes
self.rect.x=old_x
old_y=self.rect.y
new_y=old_y+self.change_y
self.rect.y = new_y
collide = pygame.sprite.spritecollide(self, walls, False)
if collide:
# yes
self.rect.y=old_y
# right to left
if self.change_x < 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
# Grab the image, divide by 4
# every 4 frames.
self.image = self.images[self.frame//4]
# Move left to right.
# images 4...7 instead of 0...3.
if self.change_x > 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4+4]
if self.change_y > 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4+4+4]
if self.change_y < 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4+4+4+4]
score = 0
# initialize pyGame
pygame.init()
# 800x600 sized screen
global screen
screen = pygame.display.set_mode([800, 600])
screen.fill(black)
#bg_tile_img = pygame.image.load('images/map/grass.png').convert_alpha()
#draw_background(screen, bg_tile_img)
#pygame.display.flip()
# Set title
pygame.display.set_caption('Test')
#background = pygame.Surface(screen.get_size())
#background = background.convert()
#background.fill(black)
# Create the player
player = Player( 50,50 )
player.rect.x=50
player.rect.y=50
movingsprites = pygame.sprite.RenderPlain()
movingsprites.add(player)
# Make the walls. (x_pos, y_pos, width, height)
global wall_list
wall_list=pygame.sprite.RenderPlain()
wall=Wall(0,0,10,600) # left wall
wall_list.add(wall)
wall=Wall(10,0,790,10) # top wall
wall_list.add(wall)
#wall=Wall(10,200,100,10) # poke wall
wall_list.add(wall)
wall=Wall(790,0,10,600) #(x,y,thickness, height)
wall_list.add(wall)
wall=Wall(10,590,790,10) #(x,y,thickness, height)
wall_list.add(wall)
f = open('MapMaker.txt')
num_lines = sum(1 for line in f)
print(num_lines)
lineCount = 0
with open("MapMaker.txt") as infile:
for line in infile:
f = open('MapMaker.txt')
print(line)
coords = line.split(',')
#print(coords[0])
#print(coords[1])
#print(coords[2])
#print(coords[3])
#print(coords[4])
if "tree" in line:
print("tree in")
wall=insertTree(int(coords[0]),int(coords[1]), int(coords[2]),int(coords[3]),coords[4])
wall_list.add(wall)
elif "rock" in line:
print("rock in")
wall=insertRock(int(coords[0]),int(coords[1]), int(coords[2]),int(coords[3]),coords[4] )
wall_list.add(wall)
width = 20
height = 540
height = height - 48
for i in range(0,23):
width = width + 32
name = insertTree(width,540,790,10,"tree")
#wall_list.add(name)
name = insertTree(width,height,690,10,"tree")
#wall_list.add(name)
CREEP_SPAWN_TIME = 200 # frames
creep_spawn = CREEP_SPAWN_TIME
clock = pygame.time.Clock()
bg_tile_img = pygame.image.load('images/map/grass.png').convert()
img_rect = bg_tile_img
FIELD_RECT = Rect(50, 50, 700, 500)
CREEP_FILENAMES = [
'images/player/1.png',
'images/player/1.png',
'images/player/1.png']
N_CREEPS = 3
creep_images = [
pygame.image.load(filename).convert_alpha()
for filename in CREEP_FILENAMES]
explosion_img = pygame.image.load('images/map/tree.png').convert_alpha()
explosion_images = [
explosion_img, pygame.transform.rotate(explosion_img, 90)]
creeps = pygame.sprite.RenderPlain()
done = False
#bg_tile_img = pygame.image.load('images/map/grass.png').convert()
#draw_background(screen, bg_tile_img)
totalCreeps = 0
remainingCreeps = 3
while done == False:
creep_images = pygame.image.load("images/player/1.png").convert()
creep_images.set_colorkey(white)
draw_background(screen, bg_tile_img)
if len(creeps) != N_CREEPS:
if totalCreeps < N_CREEPS:
totalCreeps = totalCreeps + 1
print(totalCreeps)
creeps.add(
Creep( screen=screen,
creep_image=creep_images,
explosion_images=explosion_images,
field=FIELD_RECT,
init_position=( randint(FIELD_RECT.left,
FIELD_RECT.right),
randint(FIELD_RECT.top,
FIELD_RECT.bottom)),
init_direction=(choice([-1, 1]),
choice([-1, 1])),
speed=0.01))
for creep in creeps:
creep.update(60,wall_list)
creep.draw()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done=True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.changespeed(-2,0)
creep.changespeed(-2,0)
if event.key == pygame.K_RIGHT:
player.changespeed(2,0)
creep.changespeed(2,0)
if event.key == pygame.K_UP:
player.changespeed(0,-2)
creep.changespeed(0,-2)
if event.key == pygame.K_DOWN:
player.changespeed(0,2)
creep.changespeed(0,2)
if event.key == pygame.K_ESCAPE:
pauseGame()
if event.key == pygame.K_1:
global currentEditTool
currentEditTool = "Tree"
changeTool()
if event.key == pygame.K_2:
global currentEditTool
currentEditTool = "Rock"
changeTool()
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(2,0)
creep.changespeed(2,0)
if event.key == pygame.K_RIGHT:
player.changespeed(-2,0)
creep.changespeed(-2,0)
if event.key == pygame.K_UP:
player.changespeed(0,2)
creep.changespeed(0,2)
if event.key == pygame.K_DOWN:
player.changespeed(0,-2)
creep.changespeed(0,-2)
if event.type == pygame.MOUSEBUTTONDOWN and pygame.mouse.get_pressed()[0]:
for creep in creeps:
creep.mouse_click_event(pygame.mouse.get_pos())
if editMap == True:
x,y = pygame.mouse.get_pos()
if currentEditTool == "Tree":
name = insertTree(x-10,y-25, 10 , 10, "tree")
wall_list.add(name)
wall_list.draw(screen)
f = open('MapMaker.txt', "a+")
image = pygame.image.load("images/map/tree.png").convert()
screen.blit(image, (30,10))
pygame.display.flip()
f.write(str(x) + "," + str(y) + ",790,10, tree\n")
#f.write("wall=insertTree(" + str(x) + "," + str(y) + ",790,10)\nwall_list.add(wall)\n")
elif currentEditTool == "Rock":
name = insertRock(x-10,y-25, 10 , 10,"rock")
wall_list.add(name)
wall_list.draw(screen)
f = open('MapMaker.txt', "a+")
f.write(str(x) + "," + str(y) + ",790,10,rock\n")
#f.write("wall=insertRock(" + str(x) + "," + str(y) + ",790,10)\nwall_list.add(wall)\n")
else:
None
#pygame.display.flip()
player.update(wall_list)
movingsprites.draw(screen)
wall_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
Sprite collide is the correct way to do it, you are just handling the return data incorrectly. Basically, sprite collide will no return a boolean of if you are colliding or not with a member of the group. It returns a list of sprites. Basically, it will give you a list of sprites colliding with you in that group. Another thing to watch out for is that the list will also invariably include the sprite itself. After all, it is colliding with itself. Here is a functioning way to test if you are colliding with a wall.
def is_colliding_with_wall(): #this is a function that will determine if you are touching a wall. You have repeated code to test collisions with walls multiple times, so it is best just to have a function
collide = pygame.sprite.spritecollide(self, walls, False) #this gets the list, it is the exact same code as in yours
for collision in collide: #goes through the list, checking each collision
if collision != self: #filters out self collision
return True #if there is a collision that is not self, returns True, that there is a collision with a wall
return False #if it has checked all the collisions and there is only a self collision, then it is not colliding with a wall, so it returns False