Making a platform game and expect the sprite to collide with the wall and be aligned with the top of the wall and not accelerate through the wall but the moment it collides with the wall it slowly sinks through the wall, after testing it has shown that during the sinking part it does not actually collide with the wall. At the moment I've just been focusing on gravity and the y axis.
import os
import pygame
import time
import random
vec = pygame.math.Vector2
class player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image=pygame.image.load("rectmo.png").convert_alpha()
self.image=pygame.transform.scale(self.image, (25,100))
self.rect = self.image.get_rect()
self.rect.center = (width/2,height/2)
self.pos = vec(width/2,height/2)
self.vel = vec(0,0)
self.acc = vec(0,0)
def update(self):
user_input=pygame.key.get_pressed()
if user_input[pygame.K_d]:
self.acc.x=player_acc
if user_input[pygame.K_a]:
self.acc.x=-player_acc
for wall in walls:
if self.rect.colliderect(wall.rect)==True:
if self.acc.x > 0:
self.rect.right=wall.rect.left
self.vel.x=0
if self.acc.x < 0:
self.rect.left=wall.rect.right
self.vel.x=0
if self.acc.y > 0:
self.rect.bottom=wall.rect.top
self.acc.y=0
self.vel.y=0
if self.pos.y < 0:
self.rect.top=wall.rect.bottom
self.acc.y=0
if self.rect.colliderect(wall.rect)==False:
#gravity
self.acc = vec(0,0.5)
#adds Friction
self.acc.x += self.vel.x * player_friction
#applying accelerating equation
self.vel += self.acc
self.pos += self.vel + 0.5 * self.acc
self.rect.center = self.pos
I can't tell if the way I made the wall is the problem so I'll just leave it here.
class Wall(object):
def __init__(self,wx,wy):
walls.append(self)
self.rect= pygame.Rect(wx,wy,30,30)
def reset_wall(self):
self.active = False
walls=[]
levels= [['WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW',
'W E W',
'W W',
'W W',
'W W',
'W W',
'W W',
'W W',
'W W',
'W W',
'W W W',
'W W W',
'W W W',
'W W W W',
'W W W W',
'W W W W',
'W W W W',
'W WWWWWWWWWWWWWWWWWWW W',
'W W',
'W W',
'W W',
'W W',
'W W',
'W W',
'W W',
'WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW',
]]
x=y=0
level=random.choice(levels)
for row in level:
for col in row:
if col=='W':
Wall(x,y)
if col=='E':
end_rect=pygame.Rect(x,y,30,30)
x += 30
y+=30
x=0
Here's the the whole code for testing:
import os
import pygame
import time
import random
vec = pygame.math.Vector2
class player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image=pygame.image.load("rectmo.png").convert_alpha()
self.image=pygame.transform.scale(self.image, (25,100))
self.rect = self.image.get_rect()
self.rect.center = (width/2,height/2)
self.pos = vec(width/2,height/2)
self.vel = vec(0,0)
self.acc = vec(0,0)
def update(self):
user_input=pygame.key.get_pressed()
if user_input[pygame.K_d]:
self.acc.x=player_acc
if user_input[pygame.K_a]:
self.acc.x=-player_acc
for wall in walls:
if self.rect.colliderect(wall.rect)==True:
if self.acc.x > 0:
self.rect.right=wall.rect.left
self.vel.x=0
if self.acc.x < 0:
self.rect.left=wall.rect.right
self.vel.x=0
if self.acc.y > 0:
self.rect.bottom=wall.rect.top
self.vel.y=0
if self.pos.y < 0:
self.rect.top=wall.rect.bottom
self.vel.y=0
if self.rect.colliderect(wall.rect)==False:
self.acc = vec(0,0.5)
#adds Friction
self.acc.x += self.vel.x * player_friction
#applying accelerating equation
self.vel += self.acc
self.pos += self.vel + 0.5 * self.acc
self.rect.center = self.pos
class Wall(object):
def __init__(self,wx,wy):
walls.append(self)
self.rect= pygame.Rect(wx,wy,30,30)
def reset_wall(self):
self.active = False
os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.init()
pygame.display.set_caption('A Game')
width = 1366
height= 768
screen=pygame.display.set_mode((width,height))
clock = pygame.time.Clock()
walls=[]
player_acc=0.5
player_friction=-0.05
rectmo=player()
rectmo.rect.x=500
rectmo.rect.y=400
main_colour=(0,0,0)
colour=main_colour
wall_colour=(255,255,255)
current_score=0
levels= [['WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW',
'W E W',
'W W',
'W W',
'W W',
'W W',
'W W',
'W W',
'W W',
'W W',
'W W W',
'W W W',
'W W W',
'W W W W',
'W W W W',
'W W W W',
'W W W W',
'W WWWWWWWWWWWWWWWWWWW W',
'W W',
'W W',
'W W',
'W W',
'W W',
'W W',
'W W',
'WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW',
]]
x=y=0
level=random.choice(levels)
for row in level:
for col in row:
if col=='W':
Wall(x,y)
if col=='E':
end_rect=pygame.Rect(x,y,30,30)
x += 30
y+=30
x=0
running=True
while running==True:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
rectmo.update()
if running==True:
screen.fill(main_colour)
for wall in walls:
pygame.draw.rect(screen, wall_colour,wall.rect)
pygame.draw.rect(screen,(255,0,0),end_rect)
pygame.draw.rect(screen,colour,rectmo.rect)
all_sprites_list = pygame.sprite.Group()
all_sprites_list.add(rectmo)
all_sprites_list.draw(screen)
pygame.display.flip()
Chang the position of the player, before evaluation the collisions.
If the player collides, then you've to update self.rect
and you have to synchronize self.pos
to self.rect.center
. For instnace:
if self.val.x > 0:
self.rect.right=wall.rect.left
self.vel.x=0
self.pos = vec(self.rect.center)
Evaluate if the player stays on the ground, by testing if the player would intersect the wall if he would be located 1 pixel below:
test_rect = pygame.Rect(self.rect.x, self.rect.y+1, self.rect.width, self.rect.height)
if test_rect.colliderect(wall.rect):
on_ground = True
Set the acceleration in y direction dependent on the state on_ground
:
if on_ground:
self.acc.y = 0
elif self.acc.y == 0:
self.acc.y = 0.5
Method update
:
class player(pygame.sprite.Sprite):
# [...]
def update(self):
user_input=pygame.key.get_pressed()
self.acc.x = 0
if user_input[pygame.K_d]:
self.acc.x=player_acc
if user_input[pygame.K_a]:
self.acc.x=-player_acc
self.vel.x = self.vel.x * 0.95 + self.acc.x
self.vel.y += self.acc.y
self.pos += self.vel
self.rect.center = self.pos
on_ground = False
for wall in walls:
if self.rect.colliderect(wall.rect)==True:
if self.vel.x > 0:
self.rect.right=wall.rect.left
self.vel.x=0
self.pos = vec(self.rect.center)
if self.vel.x < 0:
self.rect.left=wall.rect.right
self.vel.x=0
self.pos = vec(self.rect.center)
if self.vel.y > 0:
self.rect.bottom=wall.rect.top
self.vel.y=0
self.pos = vec(self.rect.center)
if self.vel.y < 0:
self.rect.top=wall.rect.bottom
self.vel.y=0
self.pos = vec(self.rect.center)
test_rect = pygame.Rect(self.rect.x, self.rect.y+1, self.rect.width, self.rect.height)
if test_rect.colliderect(wall.rect):
on_ground = True
if on_ground:
self.acc.y = 0
elif self.acc.y == 0:
self.acc.y = 0.5