Reputation: 43
I have searched all over the internet and stack for why my pygame won't move my sprite when it collides with a wall that I have in the game. I have the collision detection loop print out "hit2" whenever the player collides with a wall in wall_list
(a sprite group). It instead is only detecting that the walls are colliding, by the looks of it, and not when the player collides with the wall.
Could anyone take a second look at this and tell me what I have done wrong?
import pygame, sys
import random
import os
from pygame.locals import *
pygame.init()
len_sprt_x = 21
len_sprt_y = 32
sprt_rect_x = 5
sprt_rect_y = 160
SPRT_RECT_X=0
SPRT_RECT_Y=0
LEN_SPRT_X=100
LEN_SPRT_Y=100
screen = pygame.display.set_mode((20, 30)) #Create the screen
sheet = pygame.image.load('/Users/***/Downloads/3KvKpwY.png')
sheet_chests = pygame.image.load("/Users/***/Downloads/154057568119963649.png")
monsters = pygame.image.load("/Users/****/Downloads/Typhon_Monster-Sire_Sprite.png")
draw_monsters = pygame.transform.scale(monsters, (55, 45))
sheet.set_clip(pygame.Rect(sprt_rect_x, sprt_rect_y, len_sprt_x, len_sprt_y))
sheet_chests.set_clip(pygame.Rect(32, 8, 34, 33))
draw_me2 = sheet_chests.subsurface(sheet_chests.get_clip())
draw_me = sheet.subsurface(sheet.get_clip()) #Extract the sprite you want
direction = "none"
class EasyChest(pygame.sprite.Sprite):
def __init__(self):
self.x = 425
self.y = 327
self.image = pygame.image.load("/Users/***/Downloads/154057568119963649.png")
self.rect = self.image.get_rect()
class Monster(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.x = 175
self.y = 520
self.image = pygame.image.load("/Users/****/Downloads/Typhon_Monster-Sire_Sprite.png")
self.rect = self.image.get_rect()
class Monster2(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.x = 330
self.y = 400
self.image = pygame.image.load("/Users/***/Downloads/Typhon_Monster-Sire_Sprite.png")
self.rect = self.image.get_rect()
class Monster3(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.x = 285
self.y = 190
self.image = pygame.image.load("/Users/***/Downloads/Typhon_Monster-Sire_Sprite.png")
self.rect = self.image.get_rect()
class Player(pygame.sprite.Sprite):
#direction = "none"
'''
Spawn a player
'''
def __init__(self):
self.x = 450
self.y = 685
self.image = pygame.image.load("/Users/***/Downloads/3KvKpwY.png")
self.rect = self.image.get_rect()
def keys(self):
'''
control player movement
'''
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == ord('a'):
print('left')
direction = "left"
self.x += -steps
if event.key == pygame.K_RIGHT or event.key == ord('d'):
print('right')
direction = "right"
self.x += steps
if event.key == pygame.K_UP or event.key == ord('w'):
print('up')
direction = "up"
self.y += -steps
if event.key == pygame.K_DOWN or event.key == ord('s'):
print('down')
direction = "down"
self.y += steps
print(direction)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == ord('a'):
print('left stop')
if event.key == pygame.K_RIGHT or event.key == ord('d'):
print('right stop')
if event.key == pygame.K_UP or event.key == ord('w'):
print('up stop')
if event.key == pygame.K_DOWN or event.key == ord('s'):
print('down stop')
if event.key == ord('q'):
pygame.quit()
sys.exit()
def update(self, wall_list):
'''
Update sprite position
'''
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
""" Constructor for the wall that the player can run into. """
# Call the parent's constructor
super().__init__()
# Make a blue wall, of the size specified in the parameters
self.image = pygame.Surface([width, height])
self.image.fill(BLUE)
# Make the top-left corner the passed-in location.
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
mapwidth = 20
mapheight= 30
tilesize = 25
#define colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
TROPICBLUE = (152,245,255)
GREY = (142,142,142)
WOOD = (156,102,31)
PATH = (139,115,85)
GINGER = (255,127,0)
FACE = (238,213,183)
FACESHADE = (205,183,158)
RED1 = (165,42,42)
HAIR = 0
SKIN = 1
NOSE = 2
GRASS = 3
WATER = 4
DEEPWATER = 5
MOUTH = 6
DIRT = 7
PATH = 8
colours = {
HAIR: GINGER,
SKIN:FACE,
NOSE: FACESHADE,
GRASS: GREEN,
WATER: TROPICBLUE,
DEEPWATER: BLUE,
MOUTH: RED1,
DIRT: WOOD,
PATH: PATH
}
tilemap = [
[DEEPWATER, WATER, DIRT, DIRT, PATH, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, PATH, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, PATH, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, PATH, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, WATER, WATER, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, PATH, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, PATH, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, PATH, PATH, PATH, DIRT],
[DEEPWATER, WATER, WATER, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, PATH, PATH, PATH, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, PATH, PATH, PATH, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, WATER, DIRT, DIRT, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, PATH, PATH, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, PATH, PATH, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, DEEPWATER, WATER, DIRT, DIRT, DIRT, PATH, PATH, PATH, PATH, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, DEEPWATER, WATER, DIRT, DIRT, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, DEEPWATER, WATER, DIRT, DIRT, DIRT, DIRT, DIRT, PATH, PATH, PATH, PATH, PATH, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, DEEPWATER, WATER, DIRT, DIRT, DIRT, DIRT, DIRT, PATH, PATH, PATH, PATH, PATH, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, DEEPWATER, WATER, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, PATH, PATH, PATH, DIRT, DIRT, DIRT, DIRT, DIRT],
[DEEPWATER, DEEPWATER, WATER, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH],
[DEEPWATER, DEEPWATER, WATER, WATER, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, PATH, PATH, PATH, PATH, PATH, PATH, PATH, PATH],
[DEEPWATER, DEEPWATER, WATER, WATER, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT, DIRT],
]
wall_list = pygame.sprite.Group()
wall1 = Wall(96, 0, 5, 100)
wall_list.add(wall1)
wall2 = Wall(96, 100, 29, 5)
wall_list.add(wall2)
wall3 = Wall(120, 100, 5, 350)
wall_list.add(wall3)
wall4 = Wall(120, 450, 55, 5)
wall_list.add(wall4)
wall4 = Wall(175, 450, 5, 50)
wall_list.add(wall4)
steps = 5
done = False
monster_list = pygame.sprite.Group()
c1 = EasyChest()
m1 = Monster()
monster_list.add(m1)
m2 = Monster2()
monster_list.add(m2)
m3 = Monster3()
monster_list.add(m3)
p1 = Player()
main = 1
offset_x = p1.rect[0] - p1.rect[0]
offset_y = p1.rect[1] - p1.rect[1]
while main == 1: #game loop
for event in pygame.event.get():
if event.type == pygame.QUIT: # lets user close the program
print("UserExit")
main = 0
if pygame.sprite.spritecollide(p1, wall_list, False):
print("sprites have collided!")
print("hit2")
if direction == "left":
screen.blit(p1.image, (p1.x, p1.y + steps))
if direction == "right":
screen.blit(p1.image, (p1.x, p1.y - steps))
if direction == "up":
screen.blit(p1.image, (p1.x - steps, p1.y))
if direction == "down":
screen.blit(p1.image, (p1.x, p1.y + steps))
screen = pygame.display.set_mode((mapwidth * tilesize, mapheight * tilesize))
for row in range(mapheight):
for column in range(mapwidth):
backdrop1 = pygame.draw.rect(screen, colours[tilemap[row][column]],
(column * tilesize, row * tilesize, tilesize, tilesize))
backdrop=backdrop1
print(p1.x, p1.y)
screen.blit(draw_me, (p1.x, p1.y))
screen.blit(draw_me2, (c1.x, c1.y))
screen.blit(draw_monsters, (m1.x, m1.y))
screen.blit(draw_monsters, (m2.x, m2.y))
screen.blit(draw_monsters, (m3.x, m3.y))
wall_list.draw(screen)
pygame.display.update()
p1.keys()
screen.blit(draw_me, (p1.x, p1.y))
pygame.display.update()
Upvotes: 2
Views: 393
Reputation: 20488
You have to move the self.rect
of the player because it is used for the collision detection. If you only want to move in integer steps, you can remove the self.x, self.y
attributes and just use the self.rect
to store the coordinates.
I've also changed a few more things:
p1.keys(event)
call into the event loop.pygame.display.update()
calls and you blitted the player twice.class Player(pygame.sprite.Sprite):
"""Spawn a player."""
def __init__(self):
self.image = draw_me # Assign the player image.
# Assign the topleft coords of the rect.
self.rect = self.image.get_rect(topleft=(450, 685))
# The direction should be an instance attribute not a global variable.
self.direction = None
def keys(self, event):
"""Control player movement."""
if event.type == pygame.KEYDOWN:
if event.key in (pygame.K_LEFT, pygame.K_a):
self.direction = "left"
self.rect.x += -steps
elif event.key in (pygame.K_RIGHT, pygame.K_d):
self.direction = "right"
self.rect.x += steps
elif event.key in (pygame.K_UP, pygame.K_w):
self.direction = "up"
self.rect.y += -steps
elif event.key in (pygame.K_DOWN, pygame.K_s):
self.direction = "down"
self.rect.y += steps
print(self.direction)
The modified main loop:
# I added a wall at the start to test the collisions.
wall5 = Wall(420, 670, 50, 5)
wall_list.add(wall5)
clock = pygame.time.Clock() # A clock to limit the frame rate.
main = True
while main:
for event in pygame.event.get():
if event.type == pygame.QUIT:
main = False
# Pass the previous event to the player in the event loop
# (once per event not per frame).
p1.keys(event)
if pygame.sprite.spritecollide(p1, wall_list, False):
print("sprites have collided!")
# Move the player back one step if a collision occurred.
if p1.direction == "left":
p1.rect.x += steps
elif p1.direction == "right":
p1.rect.x -= steps
elif p1.direction == "up":
p1.rect.y += steps
elif p1.direction == "down":
p1.rect.y -= steps
screen = pygame.display.set_mode((mapwidth * tilesize, mapheight * tilesize))
for row in range(mapheight):
for column in range(mapwidth):
backdrop1 = pygame.draw.rect(screen, colours[tilemap[row][column]],
(column * tilesize, row * tilesize, tilesize, tilesize))
backdrop = backdrop1
screen.blit(draw_me2, (c1.x, c1.y))
screen.blit(draw_monsters, (m1.x, m1.y))
screen.blit(draw_monsters, (m2.x, m2.y))
screen.blit(draw_monsters, (m3.x, m3.y))
wall_list.draw(screen)
# Blit the player image at the player rect.
screen.blit(p1.image, p1.rect)
# Test if the player rect moves correctly.
pygame.draw.rect(screen, (255, 0, 0), p1.rect, 1)
pygame.display.update() # Call `display.update` only once per frame.
clock.tick(60) # Limit the frame rate to 60 FPS.
Upvotes: 1