Python/Pygame can't get collisions to detect correctly - python

The collisions between the creature class objects and plant class objects in my code will not register, if anyone has any ideas on how I can get each rectangle to check for collisions with a sprite group, delete that member of the sprite group it's colliding into, and effect a statistic in only the member of the creature class that collided with the secondary sprite group. Please help me out if you can, and thank you for your time.
class Creature(pg.sprite.Sprite):
def __init__(self, pos, game_area):
super().__init__()
self.image = pg.Surface((5, 5))
self.image.fill(pg.Color('Blue'))
self.rect = self.image.get_rect(center=pos)
self.vel = Vector2(2, 0).rotate(random.randrange(360))
self.pos = Vector2(pos)
self.game_area = game_area
self.energymax=10000
self.energy=10000
def update(self):
self.pos += self.vel
self.rect.center = self.pos
self.vel = Vector2(2, 0).rotate(random.randrange(360))
if not self.game_area.contains(self.rect):
self.kill()
self.energy=self.energy-10
if self.energy<=0:
self.kill()
pg.sprite.spritecollide(self,plant_sprites,True)
if pg.sprite.spritecollide(self,plant_sprites,True) and self.energy<self.energymax-1000:
self.energy=self.energy+1000
Plant.self.kill()
def main():
screen = pg.display.set_mode((640, 480))
game_area = pg.Rect(60, 60, 520, 360)
game_area_color = pg.Color('aquamarine2')
clock = pg.time.Clock()
all_sprites = pg.sprite.Group(Creature(game_area.center, game_area))
plant_sprites=pg.sprite.Group(Plant(game_area.center, game_area))
q_pressed = False
p_pressed = False
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_q:
q_pressed = True
if event.key == pg.K_p:
p_pressed = True
if event.type == pg.KEYUP:
if event.key == pg.K_q:
q_pressed = False
if event.key == pg.K_p:
p_pressed = False
mp=pg.mouse.get_pos()
if mp!=None and q_pressed==True:
all_sprites.add(Creature(mp, game_area))
all_sprites.update()
if mp!=None and p_pressed==True:
all_sprites.add(Plant(mp, game_area))
screen.fill((30, 30, 30))
all_sprites.draw(screen)
pg.draw.rect(screen, game_area_color, game_area, 2)
pg.display.flip()
clock.tick(60)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
Final code after problem was solved:
import pygame as pg
from pygame.math import Vector2
class Plant(pg.sprite.Sprite):
def __init__(self, pos, game_area):
super().__init__()
self.image = pg.Surface((2, 2))
self.image.fill(pg.Color('Green'))
self.rect = self.image.get_rect(center=pos)
self.game_area = game_area
def update(self):
if not self.game_area.contains(self.rect):
self.kill()
screen = pg.display.set_mode((640, 480))
game_area = pg.Rect(60, 60, 520, 360)
game_area_color = pg.Color('aquamarine2')
clock = pg.time.Clock()
plant_sprites=pg.sprite.Group(Plant(game_area.center, game_area))
q_pressed = False
p_pressed = False
class Creature(pg.sprite.Sprite):
def __init__(self, pos, game_area):
super().__init__()
self.image = pg.Surface((5, 5))
self.image.fill(pg.Color('Blue'))
self.rect = self.image.get_rect(center=pos)
self.vel = Vector2(2, 0).rotate(random.randrange(360))
self.pos = Vector2(pos)
self.game_area = game_area
self.energymax=10000
self.energy=10000
def update(self):
self.pos += self.vel
self.rect.center = self.pos
self.vel = Vector2(2, 0).rotate(random.randrange(360))
if not self.game_area.contains(self.rect):
self.kill()
self.energy=self.energy-10
if self.energy<=0:
self.kill()
if pg.sprite.spritecollide(self,plant_sprites,True):
if self.energy<self.energymax-2000:
self.energy=self.energy+2000
def main():
screen = pg.display.set_mode((640, 480))
game_area = pg.Rect(60, 60, 520, 360)
game_area_color = pg.Color('aquamarine2')
clock = pg.time.Clock()
global plant_sprites
all_sprites = pg.sprite.Group(Creature(game_area.center, game_area))
plant_sprites=pg.sprite.Group(Plant(game_area.center, game_area))
q_pressed = False
p_pressed = False
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_q:
q_pressed = True
if event.key == pg.K_p:
p_pressed = True
if event.type == pg.KEYUP:
if event.key == pg.K_q:
q_pressed = False
if event.key == pg.K_p:
p_pressed = False
mp=pg.mouse.get_pos()
if mp!=None and q_pressed==True:
all_sprites.add(Creature(mp, game_area))
all_sprites.update()
if mp!=None and p_pressed==True:
global new_plant
new_plant = Plant(mp, game_area)
plant_sprites.add(new_plant)
screen.fill((30, 30, 30))
all_sprites.draw(screen)
plant_sprites.draw(screen)
pg.draw.rect(screen, game_area_color, game_area, 2)
pg.display.flip()
clock.tick(60)
if __name__ == '__main__':
pg.init()
main()
pg.quit()```

See pygame.sprite.spritecollide
Return a list containing all Sprites in a Group that intersect with another Sprite. Intersection is determined by comparing the Sprite.rect attribute of each Sprite.
The dokill argument is a bool. If set to True, all Sprites that collide will be removed from the Group.
Therefore, if you call this function twice in one line with dokill set True, the 2nd call does not detect collisions, as all colliding objects have been removed before.
Call pygame.sprite.spritecollide just once:
class Creature(pg.sprite.Sprite):
# [...]
def update(self):
self.pos += self.vel
self.rect.center = self.pos
self.vel = Vector2(2, 0).rotate(random.randrange(360))
if not self.game_area.contains(self.rect):
self.kill()
self.energy=self.energy-10
if self.energy<=0:
self.kill()
# pg.sprite.spritecollide(self,plant_sprites,True) <--- DELETE
if pg.sprite.spritecollide(self,plant_sprites,True) and self.energy<self.energymax-1000:
self.energy=self.energy+1000
Plant.self.kill()
You must use the global statement, if you want to set a variable in global namespace within a function:
def main():
global plant_sprites
# [...]
plant_sprites = pg.sprite.Group(Plant(game_area.center, game_area))
# [...]
You must add new Plants to the plant_sprites Group:
if mp!=None and p_pressed==True:
new_plant = Plant(mp, game_area)
plant_sprites.add(new_plant)

Related

How to fix object image not loading properly

I'm writing a code where several enemies can spawn on the screen.
The enemy attribute used to take a color attribute that was used for all of the enemies, and I am now trying to change it to an image that I can load.
I am also interested in doing this so that I can get_rect() from the image that I will use for checking when the enemies are at a certain position on the screen.
The problem is that as I tried to replace the color attribute with an image attribute, the previous code was so dependent on loading up the enemies with the color attribute that I'm having a hard time getting the code to work.
With the current code I've written, it doesn't load the image properly.
This is the old (functional, using the color attribute) that I started with:
import sys
import pygame as pg
class Enemy:
def __init__(self, pos, color):
self.rect = pg.Rect(pos, (26, 45))
self.color = color
self.pos = pg.math.Vector2(pos)
def update(self, player):
vel = (player.center - self.pos).normalize() * 4
self.pos += vel
self.rect.center = self.pos
def draw(self, screen):
pg.draw.rect(screen, self.color, self.rect)
def main():
screen = pg.display.set_mode((640, 480))
bg_color = pg.Color('gray12')
player_color = pg.Color('dodgerblue1')
enemy_color = pg.Color('sienna1')
clock = pg.time.Clock()
player = pg.Rect((100, 300), (26, 50))
enemy_list = [Enemy((100, 300), enemy_color)]
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_f:
enemy_list.append(Enemy((400, 0), enemy_color))
keys = pg.key.get_pressed()
if keys[pg.K_a]:
player.x -= 5
elif keys[pg.K_d]:
player.x += 5
if keys[pg.K_w]:
player.y -= 5
elif keys[pg.K_s]:
player.y += 5
for enemy in enemy_list:
enemy.update(player)
screen.fill(bg_color)
pg.draw.rect(screen, player_color, player)
for enemy in enemy_list:
enemy.draw(screen)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()
And the following is the code that I have tried to change, but as of now can't get to work:
import sys
import pygame as pg
import os
from os import path
pg.init()
screen = pg.display.set_mode((640, 480))
game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, "images")
enemy_img = pg.image.load(path.join(img_folder, "goblin.png"))
class Enemy(pg.sprite.Sprite):
def __init__(self, pos, image):
pg.sprite.Sprite.__init__(self)
self.image = pg.transform.scale(enemy_img, (48,37))
self.image.set_colorkey((0,0,0))
self.rect = self.image.get_rect()
self.pos = pg.math.Vector2(pos)
def update(self, player):
vel = [-5,0]
self.pos += vel
self.rect.center = self.pos
def draw(self, screen):
screen.blit(Enemy.image, Enemy.rect)
def main():
bg_color = pg.Color('gray12')
player_color = pg.Color('dodgerblue1')
clock = pg.time.Clock()
player = pg.Rect((100, 300), (26, 50))
enemy_list = [Enemy((100, 300), enemy_img)]
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_f:
enemy_list.append(Enemy((400, 0), enemy_img))
keys = pg.key.get_pressed()
if keys[pg.K_a]:
player.x -= 5
elif keys[pg.K_d]:
player.x += 5
if keys[pg.K_w]:
player.y -= 5
elif keys[pg.K_s]:
player.y += 5
for enemy in enemy_list:
enemy.update(player)
screen.fill(bg_color)
#pg.draw.rect(screen, player_color, player)
for enemy in enemy_list:
enemy.draw(screen)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()
Could someone please help me figure out what went wrong and what code I'm supposed to alter or add? Thank you very much for your time.
Your problen is this line:
screen.blit(Enemy.image, Enemy.rect)
Here you're trying to access the image class attribute of Enemy, but the Enemy class does not have such an attribute, and also no rect attribute.
You could fix this by using
screen.blit(self.image, self.rect)
which will use the instance attributes.
But since you already use the Sprite class, don't bother with drawing the sprites to the screen yourself and use a Group:
import sys
import pygame as pg
import os
from os import path
pg.init()
screen = pg.display.set_mode((640, 480))
game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, "images")
enemy_img = pg.image.load(path.join(img_folder, "goblin.png"))
class Enemy(pg.sprite.Sprite):
def __init__(self, pos, image):
pg.sprite.Sprite.__init__(self)
self.image = pg.transform.scale(enemy_img, (48,37))
self.image.set_colorkey((0,0,0))
self.rect = self.image.get_rect()
self.pos = pg.math.Vector2(pos)
def update(self, player):
vel = [-5,0]
self.pos += vel
self.rect.center = self.pos
def main():
bg_color = pg.Color('gray12')
player_color = pg.Color('dodgerblue1')
clock = pg.time.Clock()
player = pg.Rect((100, 300), (26, 50))
enemy_list = pg.sprite.Group([Enemy((100, 300), enemy_img)])
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_f:
enemy_list.append(Enemy((400, 0), enemy_img))
keys = pg.key.get_pressed()
if keys[pg.K_a]:
player.x -= 5
elif keys[pg.K_d]:
player.x += 5
if keys[pg.K_w]:
player.y -= 5
elif keys[pg.K_s]:
player.y += 5
enemy_list.update(player)
screen.fill(bg_color)
enemy_list.draw(screen)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()

Pygame: bullets sticks to the screen

My problem is very simple. The bullets I fire sticks to the screen if I shoot fast. If I shoot slowly, they don't stick. Anyone have an idea how this phenomenon occurs?
screenshot of the bullets sticking to the screen
Below I have entered the code. I follow this default game flowchart:
I am curious about the origin of the problem. Is it the code or hardware?
import sys
import pygame
from pygame.sprite import Sprite
from pygame.sprite import Group
# pygame initializing
pygame.init()
#create the screen surface
screen = pygame.display.set_mode((800, 700))
class Color():
def __init__(self):
self.black = (0, 0, 0)
self.white = (255, 255, 255)
self.red = (255, 0, 0)
self.green = (0, 255, 0)
self.green_lambda = (10, 255, 150)
self.blue = (0, 0, 255)
# set up the colors
color = Color() # make an instance of this class - this makes some colors available
class Spaceship(Sprite):
"""
This class represents the Spaceship.
It derives from the "Sprite" class in Pygame.
"""
def __init__(self):
""" Constructor"""
# Call the parent class (Sprite) constructor
super().__init__()
width = 22
height = 32
self.screen = screen
self.image = pygame.Surface((width, height))
self.image.fill(color.black)
self.image.set_colorkey(color.black)
pygame.draw.polygon(self.image, color.green_lambda, [[10,0],[15,22],[20,30],[10,27],[0,30],[5,22]],2)
self.rect = self.image.get_rect()
self.screen_rect = self.screen.get_rect()
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
# As the rect method only take integers we store a
# This value is only used at the beginning, i.e. before the game loop starts
self.center_x = self.rect.centerx
self.center_y = self.rect.centery
class Bullet(Sprite):
"""
This class represents the bullets.
It derives from the "Sprite" class in Pygame.
"""
def __init__(self):
# Call the parent class (Sprite) constructor
super().__init__()
self.image = pygame.Surface((8,10))
self.image.fill(color.red)
self.image.set_colorkey((color.red))
pygame.draw.ellipse(self.image, color.green, [1, 0, 5, 8], 2)
self.rect = self.image.get_rect()
self.rect.centerx = defender.rect.centerx
self.rect.bottom = defender.rect.top
# def function to move the bullets
def update_pos(self):
self.rect.y -= bullet_speed
# create spaceship instance
defender = Spaceship()
# create group to store sprites in
all_sprites_list = Group()
all_sprites_list.add(defender)
ship_speed = 0.5
bullet_speed = 3
def run_game():
m_right = False
m_left = False
m_up = False
m_down = False
new_bullet = False
while True:
"""This is the user interaction section"""
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
sys.exit()
elif event.key == pygame.K_RIGHT:
m_right = True
elif event.key == pygame.K_LEFT:
m_left = True
elif event.key == pygame.K_UP:
m_up = True
elif event.key == pygame.K_DOWN:
m_down = True
elif event.key == pygame.K_SPACE:
new_bullet = Bullet()
#print(dir(new_bullet))
all_sprites_list.add(new_bullet)
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
m_right = False
elif event.key == pygame.K_LEFT:
m_left = False
elif event.key == pygame.K_UP:
m_up = False
elif event.key == pygame.K_DOWN:
m_down = False
"""Below is the game logic, which gets input from the user interaction
section and more"""
# Movement of spaceship depending on the flag boolean value and on screen width and height
if m_right and defender.rect.right < defender.screen_rect.right:
defender.center_x += ship_speed
if m_left and defender.rect.left > defender.screen_rect.left:
defender.center_x -= ship_speed
if m_up and defender.rect.top > defender.screen_rect.top:
defender.center_y -= ship_speed
if m_down and defender.rect.bottom < defender.screen_rect.bottom:
defender.center_y += ship_speed
# The cumulative value (which is a float number) for the spaceships movement
# is given to the spaceship rect variable (which can only be integer) now.
# This enables fine adjusting of the speed
defender.rect.centerx = defender.center_x
defender.rect.centery = defender.center_y
all_sprites_list.update()
screen.fill(color.black)
if new_bullet:
new_bullet.update_pos()
# Below the bullets which leaves the screen display are deleted
if new_bullet.rect.bottom < defender.screen_rect.top:
all_sprites_list.remove(new_bullet)
all_sprites_list.draw(screen)
print(all_sprites_list)
pygame.display.flip()
run_game()
instead of just updating the position of new_bullet
# if new_bullet:
# new_bullet.update_pos()
# # Below the bullets which leaves the screen display are deleted
# if new_bullet.rect.bottom < defender.screen_rect.top:
# all_sprites_list.remove(new_bullet)
update the position of all bullets
for bullet in all_sprites_list:
if isinstance(bullet,Bullet):
bullet.update_pos()
if bullet.rect.bottom < defender.screen_rect.top:
all_sprites_list.remove(bullet)
del bullet
Joran Beasley's answer is correct. I'd just like to point out that you can also put the behavior of the sprites into their update methods which get called automatically when you call all_sprites_list.update(). You can actually move most of the code in the while loop to the update methods.
I've got an example with these changes and some more tips in the comments (a quick code review):
import pygame
from pygame.sprite import Sprite
from pygame.sprite import Group
# I'd just define some global constants for the colors.
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
GREEN_LAMBDA = (10, 255, 150)
class Spaceship(Sprite):
"""This class represents the Spaceship."""
def __init__(self, screen):
"""Constructor"""
super().__init__()
self.screen = screen
# pygame.SRCALPHA makes the surface transparent.
self.image = pygame.Surface((22, 32), pygame.SRCALPHA)
pygame.draw.polygon(
self.image, GREEN_LAMBDA,
[[10,0],[15,22],[20,30],[10,27],[0,30],[5,22]], 2
)
self.screen_rect = self.screen.get_rect()
# You can pass the position as the midbottom argument to `get_rect`.
self.rect = self.image.get_rect(midbottom=self.screen_rect.midbottom)
self.center_x = self.rect.centerx
self.center_y = self.rect.centery
# I've removed the `m_right`, etc. variables and just set the speed
# of the sprite in the event loop.
self.max_speed = 3.5
self.speed_x = 0
self.speed_y = 0
def update(self):
# Move the sprite.
self.center_x += self.speed_x
self.center_y += self.speed_y
self.rect.centerx = self.center_x
self.rect.centery = self.center_y
# Keep the sprite on the screen.
if not self.screen_rect.contains(self.rect):
self.rect.clamp_ip(self.screen_rect)
self.center_x, self.center_y = self.rect.center
class Bullet(Sprite):
"""This class represents the bullets."""
def __init__(self, pos):
super().__init__()
self.image = pygame.Surface((8, 10), pygame.SRCALPHA)
pygame.draw.ellipse(self.image, GREEN, [1, 0, 5, 8], 2)
self.rect = self.image.get_rect(midbottom=pos)
self.speed = 3 # The speed is now an attribute.
def update(self):
self.rect.y -= self.speed
if self.rect.top < 0:
self.kill() # Remove the sprite from all groups.
def run_game():
pygame.init()
screen = pygame.display.set_mode((800, 700))
clock = pygame.time.Clock() # Use a clock to limit the frame rate.
defender = Spaceship(screen)
all_sprites = Group() # Changed the name because groups are not lists.
all_sprites.add(defender)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
return
elif event.key == pygame.K_RIGHT:
defender.speed_x = defender.max_speed
elif event.key == pygame.K_LEFT:
defender.speed_x = -defender.max_speed
elif event.key == pygame.K_UP:
defender.speed_y = -defender.max_speed
elif event.key == pygame.K_DOWN:
defender.speed_y = defender.max_speed
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(defender.rect.midtop) # Pass the pos.
all_sprites.add(new_bullet)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT and defender.speed_x > 0:
defender.speed_x = 0
elif event.key == pygame.K_LEFT and defender.speed_x < 0:
defender.speed_x = 0
elif event.key == pygame.K_UP and defender.speed_y < 0:
defender.speed_y = 0
elif event.key == pygame.K_DOWN and defender.speed_y > 0:
defender.speed_y = 0
all_sprites.update() # Calls the update methods of all sprites.
screen.fill(BLACK)
all_sprites.draw(screen)
pygame.display.flip()
clock.tick(60) # Limit the frame rate to 60 FPS.
run_game()

Creating a Group to add my Class to in Pygame

I am currently making a game in Pygame, and would like to generate several platforms randomly throughout my screen. However, I can't seem to figure out how to create a group so that I can draw several sprites at once. I have tried using super.__init__(self) and also replacing self with (*Group) , yet it isn't working. I also have just tried to add it to a group. How should I make my group and how do I correctly add my sprite to it?
Here is the code (the sprite I want to add in is created here but not drawn):
######## basic setup
import pygame, sys, time, random, threading, tkinter, ctypes
from threading import Timer
from pygame.locals import *
from tkinter import *
pygame.init()
WINDOWHEIGHT = 720
WINDOWWIDTH = 1280
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
pygame.display.set_caption('Hitman Grandma | vB1.0 (prealpha)')
white = (255,255,255)
red = (255,0,0)
black = (0,0,0)
green = (0,255,0)
blue = (0,0,255)
cyan = (0,255,255)
lightgrey = (198,198,198)
windowSurface.fill(lightgrey)
pygame.display.update()
mainClock = pygame.time.Clock()
########## variables
level = 0
touching = False
global x_speed
x_speed = 0
y_speed = 0
leftallowed = True
rightallowed = True
hgturnright = True
hgjumpallowed = True
########### the grandma d'awesome murder sorts
hgimage = pygame.image.load('hgfinal.png')
hgimage.convert_alpha()
class HG(object):
def __init__(self,x,y,image):
self.image = image
self.rect = self.image.get_rect()
self.x = x
self.y = y
def draw(self):
windowSurface.blit(self.image,(self.x,self.y))
def move(self):
self.x += x_speed
self.y += y_speed
def topcollide(self,box):
if not self.rect.colliderect(box.rect):
global y_speed
if y_speed < 20:
y_speed += 1
elif y_speed == 20:
y_speed = 20
print('shhoooo')
elif self.rect.colliderect(box.rect):
y_speed = 0
print('flop')
hg = HG(0,0,hgimage)
########### land and boundary
lands = pygame.image.load('hgland1.png')
floorland = pygame.transform.scale(lands,(1280,50))
sideedge = pygame.Rect(0,0,1,720),pygame.Rect(1279,0,1,720)
topedge = pygame.Rect(0,0,1280,1)
class Floor(object):
def __init__(self,x,y,image):
self.image = image
self.x = x
self.y = y
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def draw(self):
windowSurface.blit(self.image,(self.x,self.y))
class Ground(object):
def __init__(self,x,y,image):
self.image = image
self.x = x
self.y = y
self.rect = self.image.get_rect()
def draw(self):
windowSurface.blit(self.image,(self.x,self.y))
class Ground(object):
def __init__(self,x,y,image):
super.__init__(self)
self.image = image
self.x = x
self.y = y
self.rect = self.image.get_rect(topleft = (x,y))
def draw(self):
windowSurface.blit(self.image,(self.x,self.y))
floor = Floor(0,670,floorland)
platform1 = Ground((random.randint(0,800)),(random.randint(50,620)),lands)
########### WHILE
while True:
########### background
windowSurface.fill(lightgrey)
########### hg movement
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_LEFT and hg.x > 0 and leftallowed:
x_speed = -4
hgturnright = False
if event.key == K_RIGHT and (hg.x + 36) < WINDOWWIDTH and rightallowed:
x_speed = 4
hgturnright = True
if event.key == K_UP and hgjumpallowed:
y_speed = -17
if event.type == KEYUP:
if event.key == K_RIGHT:
x_speed = 0
if event.key == K_LEFT:
x_speed = 0
if event.type == KEYDOWN:
########### ctrl+q
if event.key == K_q and pygame.key.get_mods() & pygame.KMOD_CTRL:
pygame.quit()
sys.exit()
exit
########### [x]
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
exit
########### drawing and .move()
floor.draw()
hg.draw()
hg.move()
hg.topcollide(floor)
########### technicals
pygame.display.update()
mainClock.tick(40)
and here is the class I want to use:
class Ground(object):
def __init__(self,x,y,image):
super.__init__(self)
self.image = image
self.x = x
self.y = y
self.rect = self.image.get_rect(topleft = (x,y))
def draw(self):
windowSurface.blit(self.image,(self.x,self.y))
platform1 = Ground((random.randint(0,800)),(random.randint(50,620)),lands)
Also, here are the two images to use:
Your classes should inherit from pygame.sprite.Sprite, so that they can be put into sprite groups, e.g. class Platform(pg.sprite.Sprite):. Don't forget to call the __init__ method of the parent class super().__init__(). Then create the sprite groups (all_sprites = pg.sprite.Group()) and the sprite instances and call the add method of the groups to add the sprite.
Then you just have to call all_sprites.update() and all_sprites.draw(screen) in the main loop.
from random import randrange
import pygame as pg
class Platform(pg.sprite.Sprite):
def __init__(self, x, y, width, height):
super().__init__()
self.image = pg.Surface((width, height))
self.image.fill(pg.Color('dodgerblue1'))
self.rect = self.image.get_rect(topleft=(x, y))
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group() # This group that will contain all sprites.
# You probably want to add the platforms to a separate
# group as well, so that you can use it for collision detection.
platforms = pg.sprite.Group()
for _ in range(6): # Create six platforms at random coords.
platform = Platform(randrange(600), randrange(440), 170, 20)
platforms.add(platform)
all_sprites.add(platform)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
all_sprites.update()
screen.fill((30, 30, 30))
all_sprites.draw(screen)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()

How to move my player sprite?

Here is my code. How can I move my class Player sprite? Would I add an x,y to my def __init__? like def __init__(self, x, y)? Thanks for the answers,
import pygame as pg
WIDTH = 800
HEIGHT = 600
CLOCK = pg.time.Clock()
FPS = 60
GREEN = (0, 255, 0)
LIGHTBLUE = (20, 130, 230)
BGCOLOR = LIGHTBLUE
class Player(pg.sprite.Sprite):
def __init__(self, x, y):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((50, 50))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.center = ((WIDTH / 2, HEIGHT / 2))
self.x = x
self.y = y
player = Player()
pg.init()
screen = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption('The Moon Smiles Back')
running = True
while running:
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
if event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
running = False
all_sprites = pg.sprite.Group()
all_sprites.add(player)
all_sprites.update()
screen.fill(BGCOLOR)
all_sprites.draw(screen)
pg.display.flip()
CLOCK.tick(FPS)
pg.quit()
Add two attributes to the Player class to store the current velocity of the player. In the update method, add the velocities to the x and y attributes and then set the rect to the new position.
class Player(pg.sprite.Sprite):
def __init__(self, x, y):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((50, 50))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.x = x
self.y = y
self.velocity_x = 0
self.velocity_y = 0
def update(self):
self.x += self.velocity_x
self.y += self.velocity_y
self.rect.center = (self.x, self.y)
To move the player to the right, set the player.velocity_x to the desired speed if the 'd' key is pressed (in this example), and back to 0 if the key is released. Do the same for the other directions.
if event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
running = False
elif event.key == pg.K_d:
player.velocity_x = 3
elif event.type == pg.KEYUP:
if event.key == pg.K_d:
player.velocity_x = 0

NameError: global name 'self' is not defined i cant fix this

import pygame, random
pygame.init()
screen = pygame.display.set_mode((640, 480))
class Ship(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.screen = screen
self.image = pygame.image.load("ship.jpg")
self.image = self.image.convert()
self.rect = self.image.get_rect()
self.rect.center = (320, 400)
self.dx = 0
self.dy = 0
self.x = self.rect.centerx
self.y = self.rect.centery
def update(self):
self.checkBounds()
def checkBounds(self):
screen = self.screen
if self.x > screen.get_width():
self.x = screen.get_width()
if self.x < 0:
self.x = 0
class Missile(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("missile.jpg")
self.image = self.image.convert()
self.rect = self.image.get_rect()
self.reset()
def update(self):
self.rect.centery += self.dy
if self.rect.top > screen.get_height():
self.reset()
def reset(self):
self.rect.bottom = 0
self.rect.centerx = random.randrange(0, screen.get_width())
self.dy = random.randrange(5, 10)
def main():
background = pygame.Surface(screen.get_size())
background.fill((0, 0, 0))
screen.blit(background, (0, 0))
ship = Ship()
missile = Missile()
allSprites = pygame.sprite.Group(missile, ship)
clock = pygame.time.Clock()
keepGoing = True
while keepGoing:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
ship.rect.centerx = ship.rect.centerx-10
elif event.key == pygame.K_RIGHT:
ship.rect.centerx = ship.rect.centerx + 10
elif event.type == pygame.KEYUP:
ship.rect.centerx = ship.rect.centerx + 0
elif event.key == pygame.K_DOWN:
ship.rect.centerx = ship.rect.centerx - 0
if pygame.sprite.collide_rect(ship,missile) == True:
self.image = pygame.image.load("explosion.jpg")
allSprites.clear(screen, background)
allSprites.update()
allSprites.draw(screen)
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
self.image = pygame.image.load("explosion.jpg")
This line is not part of any class. There is no self here. I guess you mean
ship.image = pygame.image.load("explosion.jpg")
or something similar. Might as well be
missile.image = pygame.image.load("explosion.jpg")

Categories