I'm making a simple game in pygame, in which you're supposed to dodge or shoot the targets that descend through the screen. So far, I've created the ship and managed to set the movement of both the bullet and the ship, as for their key bindings. However, the bullet's x coordinate doesn't seem to change at all, even though I've defined in the init method in the bullet class that the bullet x coordinate is equal to the ship x coordinate, therefore, the bullet would always be leaving the ship's position. Instead, the bullet always leaves the middle of the screen. I can't find the issue. Any help would be very much appreciated
import pygame, sys
pygame.init()
clock = pygame.time.Clock()
screen_width = 600
screen_height = 800
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Space Race Game")
class ROCKET:
def __init__(self):
self.rocketImg = pygame.image.load("spaceship.png")
self.rocket_x = screen_width/2 - 32
self.rocket_y = screen_height/2 + 100
def draw_rocket(self):
screen.blit(self.rocketImg, (self.rocket_x, self.rocket_y))
def move_rocket(self):
key = pygame.key.get_pressed()
if key[pygame.K_LEFT] and self.rocket_x + 15 > 0:
self.rocket_x -= 5
if key[pygame.K_RIGHT] and self.rocket_x < screen_width - 40:
self.rocket_x += 5
class BULLET(ROCKET):
def __init__(self):
super().__init__()
self.bullet_width = 10
self.bullet_height = 20
self.bullet_x = self.rocket_x + 25
self.bullet_y = self.rocket_y
self.move = [0, 0]
self.bullet_speed = 5
self.bullet_rect = pygame.Rect(self.bullet_x, self.bullet_y, self.bullet_width, self.bullet_height)
def draw_bullet(self):
key = pygame.key.get_pressed()
if key[pygame.K_SPACE]:
self.bullet_x = self.rocket_x
self.move[1] = -1
self.bullet_y += self.move[1] * self.bullet_speed
self.bullet_rect.topleft = (self.bullet_x, self.bullet_y)
if self.bullet_y < self.rocket_y - 10:
pygame.draw.rect(screen, (0, 0, 0), self.bullet_rect)
if self.bullet_y < - 20:
self.bullet_y = self.rocket_y
self.move[1] = 0
rocket = ROCKET()
bullet = BULLET()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.fill((255, 255, 255))
rocket.draw_rocket()
rocket.move_rocket()
bullet.draw_bullet()
pygame.display.flip()
clock.tick(60)
You have to set the x-coordinate of the bullet by the current x-coordinate of the rocket.
Add an argument rocket to the method draw_bullet of the class BULLET. Make sure that you can only fire the bullet if the bullet has not yet been fired (self.move[1] == 0). Compute the center of the rocket and set the position of the bullet (rocket.rocket_x + self.rocketImg.get_width() // 2):
class BULLET(ROCKET):
# [...]
def draw_bullet(self, rocket):
key = pygame.key.get_pressed()
if key[pygame.K_SPACE] and self.move[1] == 0:
rocket_center_x = rocket.rocket_x + self.rocketImg.get_width() // 2
self.bullet_x = rocket_center_x - self.bullet_width // 2
self.move[1] = -1
# [...]
Passe the instance of ROCKET to the method draw_bullet:
while True:
# [...]
bullet.draw_bullet(rocket)
# [...]
If you want to fire multiple bullets, see the answers to the questions:
How can i shoot a bullet with space bar?
How do I stop more than 1 bullet firing at once?
Related
I'm trying to make a circle move from the middle of the screen to the top, and then back to the middle, and so on, using Pygame.
import pygame
import sys
pygame.init()
gameOver = False
speed = 5
clock = pygame.time.Clock()
fps = 20
class Screen:
largeur = 600
hauteur = 600
demiLargeur = int(largeur/2)
demiHauteur = int(hauteur/2)
screen = pygame.display.set_mode((Screen.largeur, Screen.hauteur))
class Couleurs:
bleu = (000,000,255)
noir = (000,000,000)
class Cercle:
diametre = 50
epaisseur = 5
posTop = [Screen.demiLargeur, Screen.demiHauteur-2*diametre]
class CirclePos:
top = [Cercle.posTop[0],Cercle.posTop[1]]
circleListTop = [CirclePos.top]
class DrawCircles:
def top (circleListTop):
for CirclePos.top in circleListTop:
pygame.draw.circle(screen, Couleurs.bleu, (CirclePos.top[0],CirclePos.top[1]),Cercle.diametre,Cercle.epaisseur)
class UpdateCirclesPositions:
def top(circleListTop):
for idx,CirclePos.top in enumerate(circleListTop):
if CirclePos.top[1] > Cercle.diametre :
CirclePos.top[1] -= speed
else:
circleListTop.pop(idx)
while not gameOver:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.fill(Couleurs.noir)
clock.tick(fps)
DrawCircles.top(circleListTop)
UpdateCirclesPositions.top(circleListTop)
pygame.display.update()
I have this code so far, the idea being to make it move up, make it desappear, and then create another list to move circles from top to middle. I feel it's a bad idea.
Any idea ?
Thanks
As for me you have too much classes. In class Circle you should have its properties and methods update and draw.
When circle is at the top then it should change speed - speed = -speed. The same when it is in the middle. This way it may move all time. But it may need variable direction to check if it already changed direction because it can be in place where it may change speed all time (in every move).
import pygame
# --- constans ---
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
FPS = 20
SPEED = 5
# --- classes ---
class Colors:
blue = (000, 000, 255)
black = (000, 000, 000)
red = (255, 000, 000)
class Circle:
def __init__(self, x, y, size=50, thick=5, color=Colors.blue, speed=SPEED):
self.size = size
self.thick = thick
self.color = color
self.rect = pygame.Rect(0, 0, 2*size, 2*size)
self.rect.centerx = x
self.rect.centery = y
if speed >= 0:
self.direction = 'up'
else:
self.direction = 'down'
self.speed = speed
def draw(self, screen):
pygame.draw.circle(screen, self.color, self.rect.center, self.size, self.thick)
def update(self):
self.rect.y -= self.speed
if self.rect.top <= 0 and self.direction == 'up':
self.direction = 'down'
self.speed = -self.speed
if self.rect.bottom >= screen_rect.centery and self.direction == 'down':
self.direction = 'up'
self.speed = -self.speed
# --- main ---
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
screen_rect = screen.get_rect()
circles = [
Circle(screen_rect.centerx, screen_rect.centery),
Circle(screen_rect.centerx, 0, speed=-SPEED, color=Colors.red)
]
clock = pygame.time.Clock()
game_over = False
while not game_over:
# --- events ----
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
# --- updates --- (without draws)
for item in circles:
item.update()
# --- draws --- (without updates)
screen.fill(Colors.black)
for item in circles:
item.draw(screen)
pygame.display.update()
clock.tick(FPS)
pygame.quit() # close window
import pygame
import os
import random
from pygame.locals import * # Constants
import math
import sys
import random
pygame.init()
screen=pygame.display.set_mode((1280,700)) #(length,height)
screen_rect=screen.get_rect()
background = pygame.Surface(screen.get_size())
background.fill((255,255,255)) # fill the background white
background = pygame.image.load('stage.png').convert()
Black=(0,0,0)
class Player(pygame.sprite.Sprite):
x = 20
y = 615
def __init__(self):
super().__init__() # calls the parent class allowing sprite to initalize
self.image = pygame.Surface((50,25)) # this is used to create a blank image with the size inputted
self.image.fill((0,0,128)) # fills the blank image with colour
self.rect = self.image.get_rect(topleft =(20,615)) # This place the player at the given position
self.dist = 10
def update(self): # code to make the character move when the arrow keys are pressed
if self.rect.right > 100: # These are to make the player so move constantly
self.rect.y += 1
self.rect.x += 2
if self.rect.bottom == 700:
pygame.quit()
keys = pygame.key.get_pressed()
if keys[K_LEFT]:
self.rect.move_ip(-1,0)
elif keys[K_RIGHT]:
self.rect.move_ip(0.5,0)
elif keys[K_UP]:
self.rect.move_ip(0,-0.5)
elif keys[K_DOWN]:
self.rect.move_ip(0,1)
self.rect.clamp_ip(screen_rect)
#while self.rect == (20,615):
if keys [K_SPACE]:
self.rect = self.image.get_rect(topleft =(100,100))
class Enemy(pygame.sprite.Sprite): # the enemy class which works fine
def __init__(self):
super().__init__()
x = random.randint(50,450)
self.image = pygame.Surface((50,25))
self.image.fill((128,0,0))
self.rect = self.image.get_rect(topleft (300, 50))
self.direction = 0
def update(self):
self.rect.y += 2 if self.direction == 0 else -2
if self.rect.bottom >= 600:
self.direction = 1
if self.rect.top <= 50:
self.direction = 0
clock = pygame.time.Clock() # A clock to limit the frame rate.
player = Player()
enemy = Enemy()
enemy_list = pygame.sprite.Group() # a group where the enemys will be put
sprites = pygame.sprite.Group(player) # The group where evry spirte will be put into
for i in range (5): # creates 5 enemy spirtes
enemy = Enemy() # calls the enemy class
enemy.rect.x = random.randrange(200, 1100) # makes the enemny spawn random
enemy.rect.y = random.randrange(50, 600)
enemy_list.add(enemy) # adds the enemy to the group
sprites.add(enemy)
I got the code so that the enemies will randomly and then they will move up and down however since the spawning is random they will sometimes overlap i was wondering how i would get it so that they don't overlap when they move up and down
i was wondering if i could do it so they have a gap when they spawns e.g. 50 in x axis but still spawn five enemies
def main(): #my main loop
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
sprites.update()
screen.blit(background, (0, 0))
sprites.draw(screen)
clock.tick(100) # Limit the frame rate to 60 FPS.
pygame.display.flip() #updates the whole screen
#Collison check
player_hit_list = pygame.sprite.spritecollide(player, enemy_list, True)
for enemy in player_hit_list:
pygame.quit()
if __name__ == '__main__':
main()
Try this approach (I've purposely made the code a little verbose to try to explain what's going on):
...
number_of_enemies = 5
min_enemy_x = 200
max_enemy_x = 1100
enemy_x_range = max_enemy_x - min_enemy_x # zone in which enemies can spawn
enemy_zone_width = enemy_x_range / number_of_enemies # zone width for each enemy
pixel_buffer = 50 # gap between enemies
for i in range (number_of_enemies): # creates 5 enemy spirtes
enemy = Enemy() # calls the enemy class
min_x = min_enemy_x + enemy_zone_width * i + pixel_buffer / 2 # minimum x at which current enemy can spawn (including buffer)
max_x = min_enemy_x + enemy_zone_width * (i + 1) - pixel_buffer / 2 # maximum x at which current enemy can spawn (including buffer)
enemy.rect.x = random.randrange(min_x, max_x) # makes the enemy spawn random
enemy.rect.y = random.randrange(50, 600)
enemy_list.add(enemy) # adds the enemy to the group
...
Note that this will produce a 25 pixel buffer at the start and end (so enemies will actually spawn between 225 and 1075), but you can either adjust min_enemy_x and max_enemy_x to compensate, or remove the buffering for the first and last loop iterations.
As you might probably be able to guess, I'm quite new to Python! I'm trying to write a (very) simple Space Invaders game. Nothing flashy. No sounds, no explosions, not even any scores tracking (although, at some point, the aliens will move and shoot!).
Right now though the problem with my code is that I can shoot (and destroy) any aliens in the bottom row - but I can't destroy aliens in any other row. It's most perplexing - and I'd welcome any advice that anyone can offer.
This is my code:
# !/usr/bin/python
import pygame
bulletDelay = 40
class Bullet(object):
def __init__(self, xpos, ypos):
self.image = pygame.image.load("bullet.bmp")
self.rect = self.image.get_rect()
self.x = xpos
self.y = ypos
def current_position(self):
return [self.x, self.y]
def draw(self, surface):
surface.blit(self.image, (self.x, self.y))
class Player(object):
def __init__(self, screen):
self.image = pygame.image.load("spaceship.bmp") # load the spaceship image
self.rect = self.image.get_rect() # get the size of the spaceship
size = screen.get_rect()
self.x = (size.width * 0.5) - (self.rect.width * 0.5) # draw the spaceship in the horizontal middle
self.y = size.height - self.rect.height # draw the spaceship at the bottom
def current_position(self):
return self.x
def draw(self, surface):
surface.blit(self.image, (self.x, self.y)) # blit to the player position
class Alien(object):
def __init__(self, xpos, ypos):
self.image = pygame.image.load("alien.bmp") # load the alien image
self.rect = self.image.get_rect() # get the size of the alien
self.x = xpos
self.y = ypos
def current_position(self):
return [self.x, self.y]
def draw(self, surface):
surface.blit(self.image, (self.x, self.y)) # blit to the player position
def collision(alien,bullet):
if ((alien.current_position()[0] < bullet.current_position()[0] + 10) and
(alien.current_position()[0] > bullet.current_position()[0] - 10) and
(alien.current_position()[1] == bullet.current_position()[1])):
return True
else:
return False
def destroyObject(objectArray,killList):
if len(killList) > 0: # remove any bullets that have hit an alien
for item in killList:
del objectArray[item]
pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
player = Player(screen) # create the player sprite
missiles = [] # create missile array
aliensW = 6
aliensH = 3
# layout the initial field of aliens
aliens = [[Alien((screen.get_rect().width/7)*(x+0.75),(screen.get_rect().height/5)*(y+0.5)) for x in range(aliensW)] for y in range(aliensH)]
running = True
counter = bulletDelay
while running: # the event loop
counter=counter+1
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
key = pygame.key.get_pressed()
dist = 5 # distance moved for each key press
if key[pygame.K_RIGHT]: # right key
player.x += dist
elif key[pygame.K_LEFT]: # left key
player.x -= dist
elif key[pygame.K_SPACE]: # fire key
if counter > bulletDelay:
missiles.append(Bullet(player.current_position(),screen.get_rect().height))
counter=0
screen.fill((255, 255, 255)) # fill the screen with white - without this the old graphics will remain onscreen.
for m in missiles:
if m.y < (screen.get_rect()).height+1 and m.y > 0:
m.draw(screen)
m.y -= 5
else:
missiles.pop(0)
alienGrid = []
for a in aliens:
killList=[]
spentBullets=[]
alienNumber=0
alienRow = a
for b in alienRow:
#need to move aliens as well!
missileNumber=0
for m in missiles:
if (collision(b,m)):
killList.insert(0,alienNumber)
spentBullets.insert(0,missileNumber)
missileNumber+=1
alienNumber += 1
b.draw(screen)
destroyObject(alienRow,killList)
destroyObject(missiles,spentBullets)
alienGrid.insert(0,alienRow)
aliens = alienGrid
player.draw(screen) # draw the spaceship to the screen
pygame.display.update() # update the screen
clock.tick(40)
Of course, I also welcome any other advice that you might be able to offer for improving my code!
Use print() to check values in variables and which part of code is executed. This way you can find problem (if you don't know how to use debuger)
Problem is
alien.current_position()[1] == bullet.current_position()[1]
which not always is true because missile moves 5 pixels, not 1px.
Besides you use 0.75 and 0.5 in calculations of alien positions so you have float values.
You could use self.rect to keep position and then you could use
def collision(alien, bullet):
return alien.rect.colliderect(bullet.rect)
and
def draw(self, surface):
surface.blit(self.image, self.rect)
My version with many modifications. I use class inherition. And I use time (instead of counting frame) to control missiles.
# !/usr/bin/python
import pygame
# --- constants ---
BULLET_DELAY = 1000 # 1000ms = 1s
BULLET_DIST = 5 # distance moved for each key press
RED = (255, 0, 0)
WHITE = (255, 255, 255)
FPS = 40
# --- classes ---
class Sprite(object):
def __init__(self, xpos, ypos, image=None):
if image:
self.image = pygame.image.load(image)
else:
self.image = pygame.Surface(50,50)
self.image.fill(RED)
self.rect = self.image.get_rect(x=xpos, y=ypos)
def current_position(self):
return self.rect
def draw(self, surface):
surface.blit(self.image, self.rect)
class Bullet(Sprite):
def __init__(self, xpos, ypos):
Sprite.__init__(self, xpos, ypos, "bullet.bmp")
# modificate position
self.rect.centerx = xpos
self.rect.bottom = ypos
class Alien(Sprite):
def __init__(self, xpos, ypos):
Sprite.__init__(self, xpos, ypos, "alien.bmp")
class Player(Sprite):
def __init__(self, xpos, ypos):
Sprite.__init__(self, xpos, ypos, "spaceship.bmp")
# modificate position
self.rect.centerx = xpos
self.rect.bottom = ypos
# --- main ---
pygame.init()
screen = pygame.display.set_mode((640, 480))
screen_rect = screen.get_rect()
# -
player = Player(screen_rect.centerx, screen_rect.bottom) # create the player sprite
# -
missiles = [] # create missile array
# -
aliensW = 6
aliensH = 3
# layout the initial field of aliens
sx = screen_rect.width/7
sy = screen_rect.width/7
aliens = [[Alien(sx*(x+0.75),sy*(y+0.5)) for x in range(aliensW)] for y in range(aliensH)]
# move direction
move_left = False
# ---
current_time = pygame.time.get_ticks()
# missile delay
next_missile_time = current_time
# --- mainloop ---
clock = pygame.time.Clock()
running = True
while running: # the event loop
current_time = pygame.time.get_ticks()
# --- events ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
key = pygame.key.get_pressed()
if key[pygame.K_RIGHT]: # right key
player.rect.x += BULLET_DIST
if player.rect.right > screen_rect.right:
player.rect.right = screen_rect.right
if key[pygame.K_LEFT]: # left key
player.rect.x -= BULLET_DIST
if player.rect.left < screen_rect.left:
player.rect.left = screen_rect.left
if key[pygame.K_SPACE]: # fire key
if current_time >= next_missile_time:
print('[D] fire')
missiles.append(Bullet(player.rect.centerx, player.rect.top))
# missile delay
next_missile_time = current_time + BULLET_DELAY
# --- updates (without draws) ---
# move missiles (and remove if leaves screen)
temp = []
for m in missiles:
m.rect.y -= BULLET_DIST
if m.rect.bottom >= 0:
temp.append(m)
missiles = temp
# move aliens (and check collisio)
temp = []
next_direction = move_left
for row in aliens:
temp_row = []
for a in row:
if move_left:
# move
a.rect.x -= 1
# check collision
for i, m in enumerate(missiles):
if a.rect.colliderect(m.rect):
# remove missile
del missiles[i]
# don't check collisions with other misilles
break
else: # chech only if "no break" so "no collide"
# chech if change direction
if a.rect.left == screen_rect.left:
# need to change direction but don't change `move_left` yet
next_direction = False
# add if not collide
temp_row.append(a)
else:
# move
a.rect.x += 1
# check collision
for i, m in enumerate(missiles):
if a.rect.colliderect(m.rect):
# remove missile
del missiles[i]
# don't check collisions with other misilles
break
else: # chech only if "no break" so "no collide"
# chech if change direction
if a.rect.right == screen_rect.right:
# need to change direction but don't change `move_left` yet
next_direction = True
# add if not collide
temp_row.append(a)
temp.append(temp_row)
# change after all checkings
move_left = next_direction
# new list without hitted aliens
aliens = temp
# --- draws (without updates) ---
screen.fill(WHITE) # fill the screen with white - without this the old graphics will remain onscreen.
for row in aliens:
for a in row:
a.draw(screen)
for m in missiles:
m.draw(screen)
player.draw(screen) # draw the spaceship to the screen
pygame.display.update() # update the screen
# --- FPS ---
clock.tick(FPS)
I have an image of a ufo and a missile. I'm trying to get it to where if the missile hits the ufo they both would explode and disappear and then a few moments later another ufo would respawn but the collision code isn't working. can someone explain to me how to make the code work?
pygame.display.init()
pygame.font.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
ufo = pygame.image.load("ufo.png")
rocket = pygame.image.load("rocket.png")
done = False
debug = False
fontObj = pygame.font.SysFont("Courier New", 20)
#Making my Empty Lists
missiles = [] #[x,y]
ufo_list = [] #[x,y,hspeed]
particle_list = []
#UFO Respawn Info
ufoRespawn = True
ufoHits = 0
ufoSpawnTimer = 0.0
ufoSpeed = 500.0
#MISSILE Info
launchX = 400
launchY = 550
missileSpeed = 100.0
missileDirection = 0
#creating the Starfield
myStars = [] # An (initially) empty list
for i in range(1000):
x = random.randint(0, 800)
y = random.randint(0, 600)
newStar = [x, y] # A 2-element list
myStars.append(newStar)
starSpeed = 100.0 # Rate of star movement (px / s)
starDirection = 0 # 0 = not moving, -1 = left, +1 = right
#input
while not done:
event = pygame.event.poll()
if event.type == pygame.QUIT:
done = True
keys = pygame.key.get_pressed()
if keys[pygame.K_ESCAPE]:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_d:
debug = not debug
dt = clock.tick() /1000.0
#the missile range (making it disappear after it hits the top)
for missile in missiles:
missile[1] -= missileSpeed * dt
if missile[1] < 0: missiles.remove(missle)
#triangle following mouse position
mx, my = pygame.mouse.get_pos()
if mx > launchX:
launchX += .3
if mx < launchX:
launchX -= .3
#bullets firing when pressing with mouse
mbuttons = pygame.mouse.get_pressed()
if mbuttons [0]:
x = launchX
y = launchY
newMissiles = [x,y]
missiles.append(newMissiles)
#Creating the UFOs
ufoSpawnTimer -= dt
if ufoSpawnTimer <= 0:
if random.choice (("head", "tail")) == "head":
x = 0
hspeed = random.randint (10,50)
else:
x = 800
hspeed = random.randint (-50, -10)
y = random.randint (0,300)
new_ufo = [x,y,hspeed]
ufo_list.append(new_ufo)
ufoSpawnTimer = 5.0
#Moving the Starfield
for i in range(len(myStars)):
myStars[i][0] += starSpeed * dt * starDirection
if myStars[i][0] < 0: myStars[i][0] = 800
if myStars[i][0] > 800: myStars[i][0] = 0
screen.fill ((0,0,0))
#drawing the triangle a.k.a missle launcher :D
pygame.draw.polygon(screen, (255,255,255), [[launchX, launchY], [launchX + 10, launchY + 10], \
[launchX - 10, launchY + 10]], 3)
for missile in missiles:
x = int(missile[0])
y = int(missile[1])
screen.blit(rocket, (x,y))
#drawing the ufo
for v in ufo_list:
v[0] += v[2] * dt
screen.blit(ufo,(v[0],v[1]))
#Missle distance from UFO - NEED HELP ON THIS PORTION
#Hit Detection
missileDist = ((x - v[0]) ** 2 + (y - v[1]) ** 2) ** 0.5
if **????** :
ufoRespawn = True
ufoHits += 10
#drawing th starfield
for star in myStars:
x = int(star[0])
y = int(star[1])
pygame.draw.circle(screen, (255,255,255), (x,y), 2)
pygame.display.flip()
pygame.font.quit()
pygame.display.quit()
Well there are many different ways to detect collision, And it might be worth looking at libraries that would do so, but the simplest method by far is to use pygame.sprite.spritecollide().
But before I can show how to use the function, you need to know what a pygame.sprite.Group() is and what a sprite class is.
Basicly, what a pygame.sprite.Group() is, is a way to keep track of and hold multiple sprites. In your case, it seems making a missile group for your missiles would be the best choice.
So I would create a group to hold your missiles:
missiles_group = pygame.sprite.Group(). You can add missiles to the group by saying missiles_group.add(<sprite instance name>).
As for the sprite class, please see this answer I gave to a question. To be terse, a Sprite class is a modular way to create a sprite. Instead of using just a plain image, a sprite class would hold necessary methods and attributes of a sprite. I will be using a sprite class in my example below, so if more detail is needed, please read the answer I linked to above.
With that out of the way, and without going into too much detail, here is how you fill in each function parameter to the above function.
sprite: This is the sprite that will be tested against a group of sprites
group: This is the group that will be used to test with the sprite.
dokill: This is a boolean value. If set to true, each time the sprite parameter collides with something in the group parameter, and object from the group parameter will be deleted. And visa versa if the dokill argument is set to false.
The is one more parameter that the function takes, but for what you're trying to do, it is not needed.
Incorporating the above information, here is an example. The example creates a sprite and a list of sprites. Each time the sprite collides with a sprite from the group, HIT is printed to the screen:
import pygame #import the pygame module into the namespace <module>
WIDTH = 640 # define a constant width for our window
HEIGHT = 480 # define a constant height for our window
#create a pygame window, and
#initialize it with our WIDTH and HEIGHT constants
display = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock() # create a game clock
class Sprite(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((20, 20))
self.image.fill((255, 0, 0))
self.rect = self.image.get_rect()
self.rect.x = WIDTH / 2
self.rect.y = HEIGHT / 2
self.vx = 0
self.vy = 0
def update(self):
self.vx = 0
self.vy = 0
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
self.vx = -1
elif key[pygame.K_RIGHT]:
self.vx = 1
if key[pygame.K_UP]:
self.vy = -1
elif key[pygame.K_DOWN]:
self.vy = 1
self.rect.x += self.vx
self.rect.y += self.vy
# cretae a player sprite
player = Sprite()
# create a group to hold all of our sprites
sprites = pygame.sprite.Group()
# create a group to hold sprites we want to
# test collions against. These sprites will
# still be added to the sprites list
# but we need a seperate group to test for
# collisions against
collision_sprites = pygame.sprite.Group()
# add a sprite to out collison sprite group
# We also add the sprite to our sprites group
# that holds all sprites
tmp = Sprite()
tmp.update = lambda: None
sprites.add(tmp)
collision_sprites.add(tmp)
# add a player sprites to the player group
player.rect.x = 10
sprites.add(player)
running = True # our variable for controlling our game loop
while running:
for e in pygame.event.get(): # iterate ofver all the events pygame is tracking
clock.tick(60) # make our clock keep pour game at 60 FPS
if e.type == pygame.QUIT: # is the user trying to close the window?
running = False # if so break the loop
pygame.quit() # quit the pygame module
quit() # quit is for IDLE friendliness
sprites.update()
# here is where we test for collision
if pygame.sprite.spritecollide(player, collision_sprites, False):
print("HIT!")
display.fill((180, 180, 180)) # fill the pygame screen with white
sprites.draw(display)
pygame.display.flip() # update the screen
My example if fairly big, so take your time and step through it carefully. I tried to add as many good comments as I could. Good luck!
I'm trying to detect collisions between the player and the floor. This is part of my school project so any insight would be helpful. Also suggestions to improve the code will be appreciated. Here is my code:
import pygame
#initialise pygame
pygame.init()
#variables
level = 0
velx = 0
vely = 0
health = 1
floor_group = set([])
clock = pygame.time.Clock()
#collisions
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
#screen size the same size as my background
window = pygame.display.set_mode((900,563))
#Load Images: Backgrounds
background0 = pygame.image.load("background0.png").convert()
#Load Sprites
halfspike = pygame.image.load("halfspike.png").convert_alpha()
spike = pygame.image.load("spike.png").convert_alpha()
platform = pygame.image.load("platform.png").convert_alpha()
spider = pygame.image.load("spider.png").convert_alpha()
char1 = pygame.image.load("char1.png").convert_alpha()
char2 = pygame.image.load("char2.png").convert_alpha()
#Window title
pygame.display.set_caption("Super Boshy Brothers")
# character class
class Sprite:
def __init__(self,x,y):
self.x = x
self.y = y
self.width = 42
self.height = 44
self.velx = 0
self.vely = 0
self.image0 = pygame.image.load("char1.png")
self.image1 = pygame.image.load("char2.png")
self.timeTarget = 10
self.timeNumber = 0
self.currentImage = 0
def update(self):
self.timeNumber += 1
if (self.timeNumber == self.timeTarget):
if (self.currentImage == 0):
self.currentImage = 1
else:
self.currentImage = 0
self.timeNumber = 0
self.render()
def render(self):
if (self.currentImage == 0):
window.blit(self.image0, (self.x, self.y))
else:
window.blit(self.image1, (self.x, self.y))
# Floor class
class Floor:
def __init__(self,x,y):
self.x = x
self.y = y
self.width = 43
self.height = 44
self.image0 = pygame.image.load("floor.png")
def update(self):
self.render()
def render(self):
window.blit(self.image0, (self.x, self.y))
def floor_spawner(row):
global floor_group
for i in range(0,946,43):
floor_group.add(Floor(i,row))
#Create first level floor
floor_spawner(519)
floor_spawner(475)
#player
player = Sprite(0,431)
#create our main loop
gameloop = True
while gameloop:
for event in pygame.event.get(): #get function handles events
if (event.type == pygame.QUIT): #if Quit (red x) pressed exit loop
gameloop = False
if (event.type == pygame.KEYDOWN): #If a key is pressed down
if (event.key ==pygame.K_LEFT): #If Left Arrow
velx = -7
if (event.key ==pygame.K_RIGHT): #If Right Arrow
velx = 7
if (event.key ==pygame.K_UP): #If Up Arrow
vely = -7
if (event.type == pygame.KEYUP): #If a key is pressed down
if (event.key ==pygame.K_LEFT): #If Left Arrow
velx = 0
if (event.key ==pygame.K_RIGHT): #If Right Arrow
velx = 0
if (event.key ==pygame.K_UP): #If Up Arrow
vely = 0
#Level 0
if level == 0:
window.blit(background0, (0,0)) #Bottom bricks
for f in list(floor_group):
f.render()
if player.x <= 0: #Left side collision
player.x = 0
if player.x >= 900: #Level change
level = 1
player.x = 0
#Level 1
if level == 1:
window.blit(background0, (0,0)) #Bottom bricks
for f in list(floor_group):
f.render()
player.x += velx
player.y += vely
player.update()
clock.tick(50) #Tick Tock Tick Tock
pygame.display.flip() #Updates the window
pygame.quit()
It's better if you use pygame sprite to do your assignment.
For managing the floor collision problem, just detect the collision as I do in the code below, if a collision between player and floor occurs then simply move the player back to the previous position.
Here's my code:
import pygame
import random
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BLUE = (0, 255, 0)
WHITE = (255, 255, 255)
#Sprite are basically game images in pygame
#Through sprites collision detection and rendering becomes much easier
class Block(pygame.sprite.Sprite):
#Here I've a block class which is a subclass of the pygame's sprite class
def __init__(self, image):
pygame.sprite.Sprite.__init__(self)
# Here I've initialised he superclass Sprite
self.image = image
#Image of sprite = image .. that's it
self.rect = self.image.get_rect()
#It get's all dimesion's of image which will help it in detecting collision
pygame.init()
infoObject = pygame.display.Info()
# pygame.display.Info() provides us with the information about cureent resolution and a bunch of other stuff
screen = pygame.display.set_mode((infoObject.current_w, infoObject.current_h))
char1 = pygame.image.load("char1.png").convert_alpha()
char2 = pygame.image.load("char2.png").convert_alpha()
char2_list = pygame.sprite.Group()
# Sprite groups are sets for sprites
# i.e. We have different types of object stored in different groups
# In our game the char1 and char2 are of different
#internal interaction between all char2 does'nt matter
#It's the interaction between the char1 and char2 that we've to deal with
all_list = pygame.sprite.Group()
#I've made a group which contains all the blocks which helps me in rendering them all together
for i in range(50):
block = Block(char1)
block.rect.x = random.randrange(infoObject.current_w)
block.rect.y = random.randrange(infoObject.current_h)
charimport pygame
import random
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BLUE = (0, 255, 0)
WHITE = (255, 255, 255)
#Sprite are basically game images in pygame
#Through sprites collision detection and rendering becomes much easier
class Block(pygame.sprite.Sprite):
#Here I've a block class which is a subclass of the pygame's sprite class
def __init__(self, image):
pygame.sprite.Sprite.__init__(self)
# Here I've initialised he superclass Sprite
self.image = image
#Image of sprite = image .. that's it
self.rect = self.image.get_rect()
#It get's all dimesion's of image which will help it in detecting collision
pygame.init()
infoObject = pygame.display.Info()
# pygame.display.Info() provides us with the information about cureent resolution and a bunch of other stuff
screen = pygame.display.set_mode((infoObject.current_w, infoObject.current_h))
char1 = pygame.image.load("char1.png").convert_alpha()
char2 = pygame.image.load("char2.png").convert_alpha()
char2_list = pygame.sprite.Group()
# Sprite groups are sets for sprites
# i.e. We have different types of object stored in different groups
# In our game the char1 and char2 are of different
#internal interaction between all char2 does'nt matter
#It's the interaction between the char1 and char2 that we've to deal with
all_list = pygame.sprite.Group()
#I've made a group which contains all the blocks which helps me in rendering them all together
for i in range(50):
block = Block(char1)
block.rect.x = random.randrange(infoObject.current_w)
block.rect.y = random.randrange(infoObject.current_h)
char2_list.add(block)
all_list.add(block)
player = Block(char2)
running = True
clock = pygame.time.Clock()
score = 1
all_list.add(player)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(BLACK)
pos = pygame.mouse.get_pos()
#Gets position of the mouse
player.rect.x = pos[0]
player.rect.y = pos[1]
char_hit_list = pygame.sprite.spritecollide(player, char2_list, True)#Set it to false and see the result
#Checks collision
for block in char_hit_list:
score += 1
print score
all_list.draw(screen)
#renders(draw) all the sprites onto screen
pygame.display.update()
#update's display
clock.tick(60)
# Sets Frame Rate to 60
pygame.quit()2_list.add(block)
all_list.add(block)
player = Block(char2)
running = True
clock = pygame.time.Clock()
score = 1
all_list.add(player)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(BLACK)
pos = pygame.mouse.get_pos()
#Gets position of the mouse
player.rect.x = pos[0]
player.rect.y = pos[1]
char_hit_list = pygame.sprite.spritecollide(player, char2_list, True)#Set it to false and see the result
#Checks collision
for block in char_hit_list:
score += 1
print score
all_list.draw(screen)
#renders(draw) all the sprites onto screen
pygame.display.update()
#update's display
clock.tick(60)
# Sets Frame Rate to 60
pygame.quit()
And one more thing try not to hard-code stuff like you did for screen dimension.
For learning more about pygame Sprites have a look at this.
If you have any problem, let me know by commenting in the comments section below, I'll try my best to help you out with your problem.
Keep pygaming :)