I am a new python and pygame, and I want to learn collisionm but I only know how to detect collision.
How can I add collision that allows me to stand on my big square while my little square moves. I don't know how to make it stand on the other square instead of getting thrown. At the bottom of my script I added collision detection but can't figure out how to make it actually stand on the my big block without it getting thrown to the sides, top and bottom.
pygame.init()
win = pygame.display.set_mode((500,500))
pygame.display.set_caption("THIS GAME IS KINDA ASS")
# first squrae
x = 50
y = 50
height= 50
width = 50
speed = 5
isJump = False
JumpCount = 10
# square 2
cordx = 100
cordy = 200
cordheight = 100
cordwidth = 100
# First Square
# main loop
runningame = True
while runningame:
pygame.time.delay(50)
for event in pygame.event.get():
if event.type == pygame.QUIT:
runningame = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
x -= speed
if keys[pygame.K_RIGHT]:
x += speed
if not(isJump):
if keys[pygame.K_UP]:
y -= speed
if keys[pygame.K_DOWN]:
y += speed
if keys[pygame.K_SPACE]:
isJump = True
else:
if JumpCount >= -10:
y -= (JumpCount *abs(JumpCount))
JumpCount -= 1
else:
isJump = False
JumpCount = 10
win.fill((0,0,0))
# I added a varabial to my player square
Player = pygame.draw.rect(win, (115, 235, 174), (x,y, height,width))
# second square
# this is the big box and its the enemy square that I want my script to stand on
Enemy = pygame.draw.rect(win, (202, 185 , 241), (cordx, cordy, cordheight,cordwidth))
if Player.colliderect(Enemy):
pygame.draw.rect(win, (140, 101, 211), (50,50,50,50))
pygame.display.update()
pygame.quit()
So you have Player.colliderect(Enemy)
so you know when its colliding, you just need to figure out from where and move the player accordingly.
A simple way to do this which is not perfect is to have a direction the player is moving and if the player is moving down, move the player above the enemy.
In your code, you need a direction
direction = "not moving"
...
if keys[pygame.K_LEFT]:
x -= speed
direction = "left"
if keys[pygame.K_RIGHT]:
x += speed
direction = "right"
...
else:
if JumpCount >= -10:
y -= (JumpCount *abs(JumpCount))
JumpCount -= 1
if (JumpCount *abs(JumpCount)) > 0:
direction = "down"
else:
direction = "up"
...
if Player.colliderect(Enemy):
if direction == "down":
y -= player.bottom - enemy.top #get the amount that that the player is overlapping the enemy and take it off y so it no longer overlapping
elif direction == "up":
y += player.top - enemy.bottom
#do the same for left and right
another way is to make player and enemy Rects
and use them to replace x
and y
so
# first squrae
x = 50
y = 50
height= 50
width = 50
player = pygame.Rect(x,y,width,height)
speed = 5
isJump = False
JumpCount = 10
# square 2
cordx = 100
cordy = 200
cordheight = 100
cordwidth = 100
enemy = pygame.Rect(cordc,cordy,cordwidth,cordheight)
you can then draw them with
win.fill((0,0,0))
# I added a varabial to my player square
pygame.draw.rect(win, (115, 235, 174),player)
# second square
# this is the big box and its the enemy square that I want my script to stand on
pygame.draw.rect(win, (202, 185 , 241), enemy)
and update the positions with
if keys[pygame.K_LEFT]:
player.x -= speed
if keys[pygame.K_RIGHT]:
player.x += speed
and for collisions
if player.colliderect(enemy):
if player.centerx < enemy.left: #if the center of player is left of the enemy
player.right = enemy.left
if player.centerx > enemy.right:
player.left = enemy.right
if player.centery < enemy.top:
player.bottom = enemy.top
if player.centery > enemy.bottom:
player.top = enemy.bottom
both ways work ad neither are perfect, there are also more ways to do it, but i think i would recommend the first method as its easier to understand and easier to add to your code. Comment if you need more explanation on how it works or more ways to do it
import pygame
pygame.init()
win = pygame.display.set_mode((500,500))
pygame.display.set_caption("THIS GAME IS KINDA ASS")
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, w, h, col):
pygame.sprite.Sprite.__init__(self)
self.rect = pygame.Rect(x,y,w,h)
self.image = pygame.Surface((w,h))
self.image.fill(col)
self.isJump = False
self.JumpCount = 8
def update(self):
if self.isJump:
if self.JumpCount >= -8:
self.rect.y -= (self.JumpCount *abs(self.JumpCount))
self.JumpCount -= 1
else:
self.isJump = False
self.JumpCount = 8
class Platform(pygame.sprite.Sprite):
def __init__(self, x, y, w, h, col):
pygame.sprite.Sprite.__init__(self)
self.rect = pygame.Rect(x,y,w,h)
self.image = pygame.Surface((w,h))
self.image.fill(col)
# first squrae
x = 50
y = 50
height= 50
width = 50
speed = 5
player = Player(x,y,width, height, (115, 235, 174))
# square 2
cordx = 100
cordy = 200
cordheight = 100
cordwidth = 100
enemy1 = Platform(cordx,cordy,cordwidth, cordheight, (202, 185 , 241))
#square 3
enemy2 = Platform(300,90,100,30,(202, 185 , 241))
all_sprites = pygame.sprite.Group()
all_sprites.add(player)
all_sprites.add(enemy1)
all_sprites.add(enemy2)
enemy_sprites = pygame.sprite.Group()
enemy_sprites.add(enemy1, enemy2)
clock = pygame.time.Clock()
# main loop
runningame = True
while runningame:
clock.tick(50)
for event in pygame.event.get():
if event.type == pygame.QUIT:
runningame = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.rect.x -= speed
if keys[pygame.K_RIGHT]:
player.rect.x += speed
if not(player.isJump):
if keys[pygame.K_UP]:
player.rect.y -= speed
if keys[pygame.K_DOWN]:
player.rect.y += speed
if keys[pygame.K_SPACE]:
player.isJump = True
for enemy in enemy_sprites.sprites():
if player.rect.colliderect(enemy.rect):
if player.rect.centerx < enemy.rect.left: #if the center of player is left of the enemy
player.rect.right = enemy.rect.left
if player.rect.centerx > enemy.rect.right:
player.rect.left = enemy.rect.right
if player.rect.centery < enemy.rect.top:
player.rect.bottom = enemy.rect.top
if player.rect.centery > enemy.rect.bottom:
player.rect.top = enemy.rect.bottom
all_sprites.update()
win.fill((0,0,0))
all_sprites.draw(win)
pygame.display.update()
pygame.quit()
Here is your program but using sprites
As you can see, i have moved any code relating to the squares to their classes. each sprite has a rect
and a image
. The rect is used the same way as the rect i showed above. The image is a surface, because that how pygame puts it on the screen. it the exact same as before by making it the same size and filling it with the colour.
Ive got 2 sprite groups, the all_sprites
group which has all of them and the enemy_sprites
group, which only has enemies(platforms that you can stand on). I can draw all sprites by calling all_sprites.draw(win)
.
For collisions, exact same, except i want to loop through each enemy (as i now have 2). so i can call enemy_sprites.sprites()
to get each sprite.
If you want more explanation or examples, start a chat.