Reputation: 31
I am building a game, and I have a player class, but when it touches the left/right side of a block sprite, it teleports on top of the block. I am not sure how to fix this. No questions I have seen have helped me with this.
I can detect collision by doing
for entity in blocks:
If self.rect.collidepoint(entity.midleft):
Collide = true
For some reason, however, no matter what code I try to implement, it still teleports the player upwards.
I’m quite sure this has something to do with the Player’s velocity, because the values seem to act very weird when it runs into a wall.
Player class:
class Player(pygame.sprite.Sprite):
def __init__(self):
super(Player, self).__init__()
self.surf = pygame.Surface((40,40))
self.surf.fill((255,0,0))
self.rect = self.surf.get_rect()
self.pos = vec(0,144)
self.vel = vec(0,0)
self.acc = vec(0,0)
def move(self, pressed_keys):
self.acc = vec(0,0.5)
if pressed_keys[K_LEFT]:
self.acc.x = -ACC
if pressed_keys[K_RIGHT]:
self.acc.x = ACC
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos += self.vel + 0.5 * self.acc
#if self.pos.x > W:
# self.pos.x = W
#if self.pos.x < 0:
# self.pos.x = 0
self.rect.midbottom = self.pos
def checkCollision(self):
for entity in blocks:
if self.rect.collidepoint(entity.rect.midleft) or self.rect.collidepoint(entity.rect.midright):
return True
return False
def update(self):
hits = pygame.sprite.spritecollide(self, blocks, False)
if self.vel.y > 0:
if hits:
self.pos.y = hits[0].rect.top + 1
self.vel.y = 0
def jump(self):
hits = pygame.sprite.spritecollide(self, blocks, False)
if hits:
self.vel.y = -15
Block class:
class textureblock(pygame.sprite.Sprite):
def __init__(self, imagefile, x, y):
super(textureblock, self).__init__()
self.imagefile = imagefile
self.original_image = pygame.image.load(imagefile).convert_alpha()
self.original_image = pygame.transform.scale(self.original_image, (48,48))
self.hover_image = self.original_image.copy()
pygame.draw.rect(self.hover_image, (255, 255, 0), self.hover_image.get_rect(), 6)
self.image = self.original_image
self.rect = self.image.get_rect(center = (x, y))
self.hover = False
self.mouse_pos = None
self.count = 0
def update(self):
mouse_pos = pygame.mouse.get_pos()
self.hover = self.rect.collidepoint(mouse_pos)
self.image = self.hover_image if self.hover else self.original_image
if self.hover and mouse_pos == self.mouse_pos:
self.count += 1
if self.count > 10:
self.image = pygame.Surface((48,48))
self.image.fill((0,191,255))
item = Item(self.imagefile, self.rect.x, self.rect.y)
items.add(item)
self.remove(blocks)
else:
self.count = 0
self.mouse_pos = mouse_pos
Main Loop:
while running:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.jump()
if event.key == pygame.K_ESCAPE:
running = False
pygame.quit()
if event.type == pygame.QUIT:
running = False
pygame.quit()
blocks.update()
blocks.draw(screen)
pressed_keys = pygame.key.get_pressed()
items.update()
player.update()
player.move(pressed_keys)
update()
pygame.display.update()
clock.tick(60)
You
I just need something to point me in the right direction!
Upvotes: 1
Views: 159
Reputation: 210889
You have to do the collision test for the x and y axis speperately.
First run the collision test for the x-axis. If the player moves into a block, align the player with the block. If the player hits a block from the side, you have to stop (set self.vel.x = 0
and self.acc.x = 0
).
hit_side = False
for entity in blocks:
if self.rect.colliderect(entity.rect):
# move left and hit the block on the right
if self.vel.x < 0 and self.rect.right > entity.rect.right:
self.rect.left = entity.rect.right
hit_side = True
# move right and hit the block on the left
if self.vel.x > 0 and self.rect.left < entity.rect.left:
self.rect.right = entity.rect.left
hit_side = True
if hit_side:
self.vel.x = 0
self.acc.x = 0
After that you can run the collision test for the y axis:
for entity in blocks:
if self.rect.colliderect(entity.rect):
# player is falling
if self.vel.y > 0:
self.rect.bottom = entity.rect.top
First move the player along the x-axis and do the collision check along the x-axis. Then move the player along the y-axis and hack the collision along the y-axis. If the player collides with a block, you need to update self.rect
and self.pos
.
Class Player
class Player(pygame.sprite.Sprite):
def __init__(self):
super(Player, self).__init__()
# [...]
def move(self, pressed_keys):
self.acc = vec(0,0.5)
if pressed_keys[K_LEFT]:
self.acc.x = -ACC
if pressed_keys[K_RIGHT]:
self.acc.x = ACC
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos.x += self.vel.x + 0.5 * self.acc.x
self.rect.midbottom = self.pos
hit_side = False
for entity in blocks:
if self.rect.colliderect(entity.rect):
# move left and hit the block on the right
if self.vel.x < 0 and self.rect.right > entity.rect.right:
self.rect.left = entity.rect.right
self.pos.x = self.rect.centerx
hit_side = True
# move right and hit the block on the left
if self.vel.x > 0 and self.rect.left < entity.rect.left:
self.rect.right = entity.rect.left
self.pos.x = self.rect.centerx
hit_side = True
if hit_side:
self.vel.x = 0
self.acc.x = 0
def update(self):
self.pos.y += self.vel.y + 0.5 * self.acc.y
self.rect.midbottom = self.pos
for entity in blocks:
if self.rect.colliderect(entity.rect):
if self.vel.y > 0:
self.rect.bottom = entity.rect.top
self.pos.y = self.rect.bottom
self.vel.y = 0
# [...]
Do not forget to invoke player.update()
:
while running:
# [...]
player.move(pressed_keys)
player.update()
update()
Upvotes: 1