Pygame Curve Movement Problem How To Fix? - python

VIDEO < I'm trying to make the white rectangle curve slowly and smoothly towards the red rectangle and then stop but for some reason the white rectangle isn't curving right and its moving way to fast I want it to move smoothly and curve smoothly that the eyes can see and also alawys curve to the red rectangle is there a way i could change up my code and get it to work like that?
in my curvemove rect class I have a
self.yspeed = 0.05 self.xspeed = -0.5 self.gravity = -0.01 the x and y speed the rect will move in and the gravity effecting it
then on my redraw on the curvemove class
this is how my rect is moving if the key V is pressed then it should mave the self.move true after that it should run the code which curves the object
if keys[pygame.K_v]:
curve_move1.move = True
if self.move:
curve_move1.x += curve_move1.xspeed
curve_move1.y += curve_move1.yspeed
curve_move1.yspeed += curve_move1.gravity
# curve it towards the red rectangle
else:
curve_move1.move2 = True
class curvemove:
def __init__(self,x,y,height,width,color):
self.x = x
self.y = y
self.height = height
self.width = width
self.color = color
self.rect = pygame.Rect(x,y,height,width)
self.yspeed = 0.05
self.xspeed = -0.5
self.gravity = -0.01
self.move = False
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.rect)
# -------------- curve_move1 is our curving rectangle
if keys[pygame.K_v]:
curve_move1.move = True
if self.move:
curve_move1.x += curve_move1.xspeed
curve_move1.y += curve_move1.yspeed
curve_move1.yspeed += curve_move1.gravity
# curve it towards the red rectangle
else:
curve_move1.move2 = True
full code its all rectangles so you can test it out
import pygame
pygame.init()
# our window
window = pygame.display.set_mode((500,500))
pygame.display.set_caption("test map")
# our class
class curvemove:
def __init__(self,x,y,height,width,color):
self.x = x
self.y = y
self.height = height
self.width = width
self.color = color
self.rect = pygame.Rect(x,y,height,width)
self.yspeed = 0.05
self.xspeed = -0.5
self.gravity = -0.01
self.move = False
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.rect)
# -------------- curve_move1 is our curving rectangle
if keys[pygame.K_v]:
curve_move1.move = True
if self.move:
curve_move1.x += curve_move1.xspeed
curve_move1.y += curve_move1.yspeed
curve_move1.yspeed += curve_move1.gravity
# curve it towards the red rectangle
else:
curve_move1.move2 = True
white = 255,255,255
red = 205,0,10
curve_move1 = curvemove(250,400,50,50,white)
touched = curvemove(250,200,50,50,red)
# our game fps
fps = 60
clock = pygame.time.Clock()
# d redraw()
def redraw():
window.fill((0,0,0))
curve_move1.draw()
touched.draw()
# our main loop
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if curve_move1.rect.colliderect(touched.rect):
curve_move1.move = False
redraw()
pygame.display.update()
pygame.quit()
I want a way to make this rect smooth curve towards the red rectangle not fast but normal this is my best try

The gravitational force must act in the direction of the target.
I recommend to use pygame.math.Vector2 for the calculations. Calculate the direction vector from the object to the target and scale it to the size of the gravitational force. Change the motion vector depending on gravity in each frame:
dir_vec = pygame.math.Vector2(target_pos) - self.rect.center
v_len_sq = dir_vec.length_squared()
if v_len_sq > 0:
dir_vec.scale_to_length(self.gravity)
self.speed = (self.speed + dir_vec) * self.friction
self.pos += self.speed
Minimal example:
import pygame
pygame.init()
class curvemove:
def __init__(self, x, y, height, width, color):
self.pos = pygame.math.Vector2(x, y)
self.color = color
self.rect = pygame.Rect(x, y, height, width)
self.speed = pygame.math.Vector2(-5.0, 0)
self.gravity = 0.5
self.friction = 0.99
def draw(self):
self.rect.center = (self.pos.x, self.pos.y)
pygame.draw.circle(window, self.color, (self.pos.x, self.pos.y), self.rect.width//2)
def update(self, target_pos):
dir_vec = pygame.math.Vector2(target_pos) - self.rect.center
v_len_sq = dir_vec.length_squared()
if v_len_sq > 0:
dir_vec.scale_to_length(self.gravity)
self.speed = (self.speed + dir_vec) * self.friction
self.pos += self.speed
window = pygame.display.set_mode((500,500))
pygame.display.set_caption("test map")
clock = pygame.time.Clock()
white = 255, 255, 255
red = 205, 0, 10
curve_move1 = curvemove(250, 400, 20, 20, white)
touched = curvemove(250, 200, 20, 20, red)
fps = 60
move = False
def redraw():
window.fill((0,0,0))
curve_move1.draw()
touched.draw()
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_v:
move = True
if event.key == pygame.K_r:
move = False
curve_move1 = curvemove(250, 400, 20, 20, white)
if (curve_move1.pos - touched.pos).length() < 10:
move = False
if move:
curve_move1.update(touched.rect.center)
redraw()
pygame.display.update()
clock.tick(fps)
pygame.quit()
exit()
Play around with the values of speed, gravity and friction to get different effects.
e.g.:
self.speed = pygame.math.Vector2(-10.0, 0)
self.gravity = 1
self.friction = 0.95
e.g.:
self.speed = pygame.math.Vector2(-10.0, 0)
self.gravity = 1
self.friction = 0.91

Related

Bullet movement not working as expected when player sprite is moving

My game is a top down shooter. When the player is stationary and is shooting in any direction, the bullet goes in the same direction as the mouse. However, when I move diagonally whilst shooting the bullet is no longer in the direction of the mouse position. So basically it works when the player is stationary, but not when I'm moving.
Edit: I will keep trying to fix this but here is a video to better understand the issue https://imgur.com/a/8QRr1PO
Here is the code:
import pygame
from sys import exit
import math
pygame.init()
# window and text
WIDTH = 1280
HEIGHT = 720
FPS = 60
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption('Shooting problem demo')
game_font = pygame.font.Font('freesansbold.ttf', 50)
clock = pygame.time.Clock()
# loads imgs
background = pygame.image.load("background/gamemap.png").convert()
plain_bg = pygame.image.load("background/plain_bg.png").convert()
bullet_img = pygame.image.load("bullets/bluebullet.png").convert_alpha()
class Player(pygame.sprite.Sprite):
def __init__(self, pos):
super().__init__()
self.image = pygame.image.load("handgun/move/survivor-move_handgun_0.png").convert_alpha()
self.image = pygame.transform.rotozoom(self.image, 0, 0.35)
self.base_player_image = self.image
self.pos = pos
self.base_player_rect = self.base_player_image.get_rect(center = pos)
self.rect = self.base_player_rect.copy()
self.player_speed = 10 # was 4
self.shoot = False
self.shoot_cooldown = 0
def player_turning(self):
self.mouse_coords = pygame.mouse.get_pos()
self.x_change_mouse_player = (self.mouse_coords[0] - (WIDTH // 2))
self.y_change_mouse_player = (self.mouse_coords[1] - (HEIGHT // 2))
self.angle = int(math.degrees(math.atan2(self.y_change_mouse_player, self.x_change_mouse_player)))
self.angle = (self.angle) % 360
self.image = pygame.transform.rotate(self.base_player_image, -self.angle)
self.rect = self.image.get_rect(center=self.base_player_rect.center)
def player_input(self):
self.velocity_x = 0
self.velocity_y = 0
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
self.velocity_y = -self.player_speed
if keys[pygame.K_s]:
self.velocity_y = self.player_speed
if keys[pygame.K_d]:
self.velocity_x = self.player_speed
if keys[pygame.K_a]:
self.velocity_x = -self.player_speed
if self.velocity_x != 0 and self.velocity_y != 0: # moving diagonally
self.velocity_x /= math.sqrt(2)
self.velocity_y /= math.sqrt(2)
if keys[pygame.K_SPACE]:
self.shoot = True
self.is_shooting()
else:
self.shoot = False
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
self.shoot = False
def move(self):
self.base_player_rect.centerx += self.velocity_x
self.base_player_rect.centery += self.velocity_y
self.rect.center = self.base_player_rect.center
def is_shooting(self):
if self.shoot_cooldown == 0 and self.shoot:
self.bullet = Bullet(self.base_player_rect.centerx, self.base_player_rect.centery, self.angle)
self.shoot_cooldown = 20
bullet_group.add(self.bullet)
all_sprites_group.add(self.bullet)
def update(self):
self.player_turning()
self.player_input()
self.move()
if self.shoot_cooldown > 0:
self.shoot_cooldown -= 1
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y, angle):
super().__init__()
self.image = bullet_img
self.image = pygame.transform.rotozoom(self.image, 0, 0.1)
self.image.set_colorkey((0,0,0))
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.x = x
self.y = y
self.speed = 10
self.angle = angle
self.x_vel = math.cos(self.angle * (2*math.pi/360)) * self.speed
self.y_vel = math.sin(self.angle * (2*math.pi/360)) * self.speed
self.bullet_lifetime = 750
self.spawn_time = pygame.time.get_ticks()
def bullet_movement(self):
self.x += self.x_vel
self.y += self.y_vel
self.rect.x = int(self.x)
self.rect.y = int(self.y)
if pygame.time.get_ticks() - self.spawn_time > self.bullet_lifetime:
self.kill()
def update(self):
self.bullet_movement()
class Camera(pygame.sprite.Group):
def __init__(self):
super().__init__()
self.offset = pygame.math.Vector2()
self.floor_rect = background.get_rect(topleft = (0,0))
def custom_draw(self):
self.offset.x = player.rect.centerx - (WIDTH // 2)
self.offset.y = player.rect.centery - (HEIGHT // 2)
#draw the floor
floor_offset_pos = self.floor_rect.topleft - self.offset
screen.blit(background, floor_offset_pos)
for sprite in all_sprites_group:
offset_pos = sprite.rect.topleft - self.offset
screen.blit(sprite.image, offset_pos)
# Groups
all_sprites_group = pygame.sprite.Group()
player = Player((900,900))
all_sprites_group.add(player)
bullet_group = pygame.sprite.Group()
camera = Camera()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.blit(plain_bg, (0,0))
camera.custom_draw()
all_sprites_group.update()
pygame.display.update()
clock.tick(FPS)
Actually, there is no problem at all. It is just an optical illusion. The projectile does not move relative to the player, but relative to the camera. The player is always in the center of the screen, because the player doesn't move, but the camera does. When the camera moves, all objects move with the camera.
For example, if you shoot a bullet to the right and move the player up, it will look like the bullet is moving diagonally to the right and down. To the right because it changes position, to the right and down because the player moves upwards.
To illustrate this, I reduced the speed of the player (self.player_speed = 2) and the speed of the bullet (self.speed = 4) and drew the scene on a checkered background:
if event.type == pygame.KEYUP: only makes sens in the event loop, but not in player_input. Shooting only one bullet at once just needs another condition (and not self.shoot):
if keys[pygame.K_SPACE] and not self.shoot:
self.shoot = True
self.is_shooting()
else:
self.shoot = False

Collision on air [duplicate]

This question already has answers here:
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
How do I detect collision in pygame?
(5 answers)
Closed 2 years ago.
I'm making a platform game and I've got collisions working, however with the platforms there seems to be an extra cube area on the left side which the player can walk on. I can't seem to figure out how to remove it. Below is some of the code I believe is the cause of it however I'm not sure exactly.
. I've trimmed down the image for the platforms etc but the problem persists.
background_image = pygame.image.load("JungleBackground.png")
done = False
clock = pygame.time.Clock()
black = ( 0, 0, 0)
white = ( 255, 255, 255)
x = 300
y = 88
class Character(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((100,100))
self.image.set_colorkey(black)
self.rect = self.image.get_rect(center=(50, 300))
self.rect.x = 50
self.rect.y = 300
self.pos = vec(50, 300)
self.vel = vec(0,0)
self.acc = vec(0,0)
self.image.blit(pygame.image.load("TheoHillsS.png"),(0,0))
def characterJump(self):
self.rect.y += 1
hits = pygame.sprite.spritecollide(self, platforms, False)
self.rect.y -= 1
if hits:
self.vel.y = -13
def update(self):
self.acc = vec(0, 0.5)
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
self.acc.x = -PLAYER_ACC
if keys[pygame.K_d]:
self.acc.x = PLAYER_ACC
# apply friction
self.vel.x *= PLAYER_FRICTION
self.vel += self.acc
self.pos += self.vel
self.rect.midbottom = self.pos
class Platform(pygame.sprite.Sprite):
def __init__(self, x, y, w, h):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((100, 88))
self.image.fill(black)
self.image = pygame.image.load("Platform1.png")
self.rect = self.image.get_rect(topleft=(x, y))
all_sprites = pygame.sprite.Group()
platforms = pygame.sprite.Group()
character = Character()
all_sprites.add(character)
p1 = Platform(-80, 350, WIDTH - 400, HEIGHT - 10)
p2 = Platform(175, 220, WIDTH - 400, HEIGHT - 10)
p3 = Platform(500, 350, WIDTH - 400, HEIGHT - 10)
all_sprites.add(p1, p2, p3)
platforms.add(p1, p2, p3)
# Main Game
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
character.characterJump()
all_sprites.update()
hits = pygame.sprite.spritecollide(character, platforms, False)
for platform in hits:
if character.vel.y > 0:
character.rect.bottom = platform.rect.top
character.vel.y = 0
elif character.vel.y < 0:
character.rect.top = platform.rect.bottom
character.vel.y = 3
character.pos.y = character.rect.bottom
screen.blit(background_image,[0,0])
all_sprites.draw(screen)
pygame.display.flip()
game_intro()
game_loop()
pygame.quit()
quit()
The collision is tested against the bounding rectangle of the image, not the area drawn on the image. Make sure the platforms and player fill almost the entire area of the pygame.Surface.
Instead of drawing the player on a transparent Surface that is much larger than the player, use the Surface created by pygame.image.load directly:
class Character(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("TheoHillsS.png")
self.rect = self.image.get_rect(topleft = (50, 300))
self.pos = vec(50, 300)
self.vel = vec(0,0)
self.acc = vec(0,0)
# [...]

Pygame sprite sheet hitbox broken

I made a simple game, where you have to jump over the stones moving towards you. The problem is that one of those sprites hitboxes is broken, even if the sprite mask is used. The player sprite is generated just dividing the player sprite sheet into 4 columns. Maybe there the problem is hiding?
Pictures for the program:
https://drive.google.com/drive/folders/1We6RDMs3Cwwprf1OY0ow9WCTHF9MHzne?usp=sharing
import pygame, os, random
pygame.init()
W, H = 800,600
HW, HH = W/2,H/2
AREA = W * H
WHITE = (255,255,255)
GREEN = (69,139,0)
FPS = 60
bg = pygame.image.load(os.path.join('Pildid', 'Taust3.png'))
bg = pygame.transform.scale(bg, (2000, 600))
DS = pygame.display.set_mode((W,H))
clock = pygame.time.Clock()
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, py, player, veerg, rida):
super(Player,self).__init__()
'''Mangija huppamine'''
clock.tick(5)
self.x = x
self.y = y
self.jumping = False
self.platform_y = py
self.velocity_index = 0
'''Sprite sheet'''
self.player = pygame.image.load(os.path.join('Pildid', 'karakter.png')).convert_alpha()#pildi uleslaadimine
#self.player = pygame.transform.scale(self.player,(200,100))
self.rect = self.player.get_rect()
'''Sprite sheeti piltide jaotamine pikslite jargi'''
self.veerg = veerg
self.rida = rida
self.kokku = veerg * rida
self.rect = self.player.get_rect()
L = self.veergL = self.rect.width/veerg
K = self.weegK = self.rect.height/rida
PL,PK = self.veergKeskel = (L/2,K/2)
self.veerg = list([(index % veerg * L, int(index/veerg) * K,L,K )for index in range(self.kokku)])
self.handle = list([ #pildi paigutamise voimalikud positsioonid
(0, 0), (-PL, 0), (-L, 0),
(0, -PK), (-PL, -PK), (-L, -PK),
(0, -L), (-PL, -K), (-L, -K),])
self.mask = pygame.mask.from_surface(self.player)
def do_jumpt(self):
'''Huppamine: kiirus, korgus, platvorm'''
global velocity
if self.jumping:
self.y += velocity[self.velocity_index]
self.velocity_index += 1
if self.velocity_index >= len(velocity) - 1:
self.velocity_index = len(velocity) - 1
if self.y > self.platform_y:
self.y = self.platform_y
self.jumping = False
self.velocity_index = 0
def draw(self, DS,veergindex,x,y,handle=0):
DS.blit(self.player,(self.x+self.handle[handle][0], self.y + self.handle[handle][1]),self.veerg[veergindex])
def do(self):
'''Funktsioonide kokkupanek'''
self.do_jumpt()
p.draw(DS,index%p.kokku,190, 359,4)
def update(self):
self.rect.center = self.x, self.y
def keys(player):
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE] or keys[pygame.K_UP] and player.jumping == False:
player.jumping = True
class Obsticles(pygame.sprite.Sprite):
'''Game obsticles: **'''
#img = pygame.image.load(os.path.join('images', 'box.png'))
def __init__(self, x, y):
super(Obsticles,self).__init__()
self.img = pygame.image.load(os.path.join('Pildid', 'kivi.png')).convert_alpha()
self.img = pygame.transform.scale(self.img, (90,90))
self.rect = self.img.get_rect(center=(x, y))
self.x = x
self.y = y
self.mask = pygame.mask.from_surface(self.img)
def draw(self, DS):
'''Obsticle img blitting and hitbox'''
DS.blit(self.img, (self.x, self.y))
def update(self):
if self.x < -64: # Delete the obstacle.
# `kill()` removes this obstacle sprite from all sprite groups.
self.kill()
self.x += speed # Move the obstacle.
# Update the rect because it's used to blit the
# sprite and for the collision detection.
self.rect.center = self.x, self.y
def redrawWindow():
'''Obsticle loop'''
for i in ob:
i.draw(DS)
def text_objects(text, font):
textSurface = font.render(text, True, WHITE)
return textSurface, textSurface.get_rect()
def message_display(text):
largeText = pygame.font.Font('freesansbold.ttf',60)
TextSurf, TextRect = text_objects(text, largeText)
TextRect.center = ((W/2),(H/4))
DS.blit(TextSurf, TextRect)
pygame.display.update()
pygame.time.wait(3000)
def crash():
message_display('Failed')
pygame.time.set_timer(pygame.USEREVENT+2, random.choice([2500, 3000, 1500]))
velocity = list([(i/ 1)-20 for i in range (0,60)]) #Huppe ulatus
index = 3
obsticles = Obsticles(832, 363)
p = Player(190, 359, 359, 'karakter.png', 4, 1)
all_sprites = pygame.sprite.Group(p, obsticles)
ob = pygame.sprite.Group(obsticles)
x = 0
x -= 1
speed = -5
running = True
while running:
# ---Handle the events.---
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.USEREVENT+2:
r = random.randrange(0, 2)
if r == 0:
obsticles = Obsticles(832, 363)
# Add the obstacle to both groups.
ob.add(obsticles)
all_sprites.add(obsticles)
speed += -0.008
# ---Game logic.---
all_sprites.update()
collided = pygame.sprite.spritecollide(p, ob, True,
pygame.sprite.collide_mask)
if collided:
crash()
index += 1
# Background movement.
back_x = x % bg.get_rect().width
x -= 2
# ---Draw everything.---
DS.blit(bg, (back_x - bg.get_rect().width, 0))
if back_x < W:
DS.blit(bg, (back_x, 0))
keys(p)
p.do()
redrawWindow()
pygame.display.update()
clock.tick(60)
pygame.quit()
quit()
The problem is that you use the original image to create the Player.mask. The resulting mask covers all four poses of the character, so even if only one of the sprite sheet frames is visible, the complete original image is used for the collision detection. Your mask looks like the green area in this picture:
You should also use the rect (i.e. the rect.topleft coords) as the blit position, because it is used for the collision detection as well (to find the location of the mask).
I've got a fixed, shortened version of your program in which I've changed a few things to show you how I would solve the problem. First of all, I load the sprite sheet and cut it into several subsurfaces, then I assign the first surface/image to the self.image attribute of the Player. This image can be used to create the rect and the mask.
In the update method I increment the frame_index and assign the current image to self.image in order to animate the sprite. BTW, it would be a good idea to create separate masks for every image and swap them as well during the animation. (I'm just using the first mask here, since the animation frames are so similar.)
Note that if you give your sprites an image and a rect attribute, you can just call all_sprites.update(DS) to blit all sprite images at their corresponding rects.
import random
import pygame
pygame.init()
FPS = 60
DS = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
PLAYER_SHEET = pygame.image.load('karakter.png').convert_alpha()
# Cut the sprite sheet and append the subsurfaces to this list.
PLAYER_IMAGES = []
width = PLAYER_SHEET.get_width() / 4
height = PLAYER_SHEET.get_height()
for x in range(4):
PLAYER_IMAGES.append(PLAYER_SHEET.subsurface(x*width, 0, width, height))
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, py):
super(Player,self).__init__()
self.x = x
self.y = y
self.jumping = False
self.platform_y = py
self.velocity_index = 0
self.velocity = list([(i/ 1)-20 for i in range (0,60)])
self.frame_index = 0
self.image = PLAYER_IMAGES[self.frame_index]
self.rect = self.image.get_rect()
self.mask = pygame.mask.from_surface(self.image)
def do_jump(self):
if self.jumping:
self.y += self.velocity[self.velocity_index]
self.velocity_index += 1
if self.velocity_index >= len(self.velocity) - 1:
self.velocity_index = len(self.velocity) - 1
if self.y > self.platform_y:
self.y = self.platform_y
self.jumping = False
self.velocity_index = 0
def update(self):
self.rect.center = self.x, self.y
self.do_jump()
# Update the animation frame.
self.frame_index += 1
self.frame_index %= len(PLAYER_IMAGES) * 7 # * 7 to slow it down.
# Swap the image.
self.image = PLAYER_IMAGES[self.frame_index//7] # // 7 to slow it down.
def keys(player):
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE] or keys[pygame.K_UP] and player.jumping == False:
player.jumping = True
class Obstacle(pygame.sprite.Sprite):
"""Game Obstacle."""
def __init__(self, x, y):
super(Obstacle,self).__init__()
self.image = pygame.Surface((90, 90), pygame.SRCALPHA)
self.image.fill((100, 150, 0))
self.image = pygame.transform.scale(self.image, (90,90))
self.rect = self.image.get_rect(center=(x, y))
self.x = x
self.y = y
self.mask = pygame.mask.from_surface(self.image)
def update(self):
if self.x < -64:
self.kill()
self.x += speed
self.rect.center = self.x, self.y
pygame.time.set_timer(pygame.USEREVENT+2, random.choice([2500, 3000, 1500]))
index = 3
obstacle = Obstacle(832, 363)
player = Player(190, 359, 359)
all_sprites = pygame.sprite.Group(player, obstacle)
obstacles = pygame.sprite.Group(obstacle)
speed = -5
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.USEREVENT+2:
r = random.randrange(0, 2)
if r == 0:
obstacle = Obstacle(832, 363)
# Add the obstacle to both groups.
obstacles.add(obstacle)
all_sprites.add(obstacle)
keys(player)
# ---Game logic.---
speed += -0.008
all_sprites.update()
collided = pygame.sprite.spritecollide(player, obstacles, True,
pygame.sprite.collide_mask)
if collided:
print('crash')
index += 1
# ---Draw everything.---
DS.fill((30, 30, 30))
all_sprites.draw(DS)
# Here I draw the outline (points) of the player's mask.
px, py = player.rect.topleft
for point in player.mask.outline(8):
x, y = point[0] + px, point[1] + py
pygame.draw.circle(DS, (250, 250, 0), (x, y), 2)
pygame.draw.rect(DS, (0, 0, 250), player.rect, 1)
# Draw the outlines of the obstacles.
for obstac in obstacles:
pygame.draw.rect(DS, (150, 250, 0), obstac.rect, 1)
ox, oy = obstac.rect.topleft
for point in obstac.mask.outline(6):
pygame.draw.circle(DS, (250, 0, 0), (point[0]+ox, point[1]+oy), 2)
pygame.display.update()
clock.tick(60)
pygame.quit()

How do you make the game end when the main player collides with an image (obstacle)?

import math
import random
import pygame
from pygame.locals import *
import sys
def events():
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
pygame.init()
W = 700
H = 400
updater = pygame.time.Clock()
display = pygame.display.set_mode((700, 400))
pygame.display.set_caption("Skating_Game")
x = y = 0
surface = pygame.image.load("man2.png")
pygame.display.set_icon(surface)
class player:
def __init__(self, velocity, maxJumpRange):
self.velocity = velocity
self.maxJumpRange = maxJumpRange
def setLocation(self, x, y):
self.x = x
self.y = y
self.xVelocity = 0
self.jumping = False
self.jumpCounter = 0
self.falling = True
def keys(self):
k = pygame.key.get_pressed()
if k[K_LEFT]:
self.xVelocity = -self.velocity
elif k[K_RIGHT]:
self.xVelocity = self.velocity
else:
self.xVelocity = 0
if k[K_SPACE] and not self.jumping and not self.falling:
self.jumping = True
self.jumpCounter = 0
def move(self):
self.x += self.xVelocity
if self.jumping:
self.y -= self.velocity
self.jumpCounter += 1
if self.jumpCounter == self.maxJumpRange:
self.jumping = False
self.falling = True
elif self.falling:
if self.y <= H - 60 and self.y + self.velocity >= H - 60:
self.y = H - 60
self.falling = False
else:
self.y += self.velocity
def draw(self):
display = pygame.display.get_surface()
character = pygame.image.load("man3.png").convert_alpha()
display.blit(character, (self.x, self.y - 100))
#pygame.draw.circle(display, (255, 255, 255), (self.x, self.y - 25), 25, 0)
def do(self):
self.keys()
self.move()
self.draw()
P = player(3, 50)
P.setLocation(350, 0)
BLACK = ( 0, 0, 0)
g=0
font = pygame.font.SysFont("Plump", 30)
obstacle = pygame.image.load("obstacle.png").convert_alpha()
background = pygame.image.load("Road.png").convert()
x = 0
while True:
events()
rel_x = x % background.get_rect().width
display.blit(background, (rel_x - background.get_rect().width,0))
if rel_x < 700:
display.blit(background, (rel_x, 0))
x -= 1
g += 0.01
pygame.draw.rect(display, (255,255,255,128), [rel_x, 275, 150, 50])
display.blit(obstacle, (rel_x, 250))
text = font.render("Score: "+str(int(g)), True, (255, 255, 255))
display.blit(text, (0,0))
P.do()
if P.rect.collidepoint(self.x,self.y):
pygame.quit()
pygame.display.update()
updater.tick(200)
So if the player collides with the obstacle image the game should stop. How do i do this? I have made a class for the player and the obstacle is just an image which is constantly moving.
I was thinking maybe I could track the x and y coordinate of the player and obstacle and when their radius overlaps the game could stop.
Here's a working (simplified) version of your program with some comments. You have to create rects for the obstacle and the player and then check if the rects collide with the help of the colliderect method.
import sys
import pygame
from pygame.locals import *
pygame.init()
W = 700
H = 400
updater = pygame.time.Clock()
display = pygame.display.set_mode((700, 400))
PLAYER_IMAGE = pygame.Surface((30, 50))
PLAYER_IMAGE.fill(pygame.Color('dodgerblue1'))
class Player:
def __init__(self, x, y, velocity, maxJumpRange):
self.velocity = velocity
self.maxJumpRange = maxJumpRange
self.image = PLAYER_IMAGE # Give the player an image.
# Create a rect with the size of the PLAYER_IMAGE and
# pass the x, y coords as the topleft argument.
self.rect = self.image.get_rect(topleft=(x, y))
self.x = x
self.y = y
self.xVelocity = 0
self.jumping = False
self.jumpCounter = 0
self.falling = True
def keys(self):
k = pygame.key.get_pressed()
if k[K_LEFT]:
self.xVelocity = -self.velocity
elif k[K_RIGHT]:
self.xVelocity = self.velocity
else:
self.xVelocity = 0
if k[K_SPACE] and not self.jumping and not self.falling:
self.jumping = True
self.jumpCounter = 0
def move(self):
self.x += self.xVelocity
if self.jumping:
self.y -= self.velocity
self.jumpCounter += 1
if self.jumpCounter == self.maxJumpRange:
self.jumping = False
self.falling = True
elif self.falling:
if self.y >= H - 160: # Simplified a little.
self.y = H - 160
self.falling = False
else:
self.y += self.velocity
# Update the position of the rect, because it's
# used for the collision detection.
self.rect.topleft = self.x, self.y
def draw(self, display):
# Just draw the image here.
display.blit(self.image, (self.x, self.y))
def do(self):
self.keys()
self.move()
player = Player(350, 0, 3, 50)
obstacle = pygame.Surface((150, 50))
obstacle.fill(pygame.Color('sienna1'))
# Create a rect with the size of the obstacle image.
obstacle_rect = obstacle.get_rect()
g = 0
x = 0
FPS = 60 # Cap the frame rate at 60 or 30 fps. 300 is crazy.
while True:
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
# --- Update the game ---
player.do()
rel_x = x % display.get_width()
x -= 7
g += 0.01
obstacle_rect.topleft = rel_x, 250 # Update the position of the rect.
# --- Draw everything ---
display.fill((30, 30, 30))
display.blit(obstacle, (rel_x, 250))
if g > 30:
display.blit(obstacle, (rel_x+350, 250))
# Check if the obstacle rect and the player's rect collide.
if obstacle_rect.colliderect(player.rect):
print("Game over!") # And call pygame.quit and sys.exit if you want.
# Draw the image/surface of the player onto the screen.
player.draw(display)
# Draw the actual rects of the objects (for debugging).
pygame.draw.rect(display, (200, 200, 0), player.rect, 2)
pygame.draw.rect(display, (200, 200, 0), obstacle_rect, 2)
pygame.display.update()
updater.tick(FPS)
Pygame rectangles include a collidepoint and colliderect method that allows you to check to see if something intersects with a rectangle. So you could have rectangles drawn beneath the obstacle and check to see if the player's coordinates intersect with the rectangle. Like this:
if self.rect.collidepoint(self.x,self.y):
pygame.quit()

How do I get pygame collisions to work

I am making a flappy bird replica and I can't get a collision mechanism. At the moment i'm trying to use .coliderect() but i'm not 100% sure how to. Here is the two classes. I'd like the program to do something, or just print('x') when the bird and the pipe collide, but when they collide at the moment the program does not do or output anything.
import pygame
vec = pygame.math.Vector2
BLACK = (0,0,0)
WIDTH = 500
HEIGHT = 400
pygame.init()
window = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Flappy Bird')
clock = pygame.time.Clock()
class Bird():
def __init__(self):
self.skin = pygame.image.load('bird2.png')
self.rect = self.skin.get_rect()
self.rect.center = (WIDTH / 2, HEIGHT / 2)
self.vx = 0
self.vy = 0
self.pos = vec(WIDTH / 2, HEIGHT / 2)
self.vel = vec(0, 0)
self.acc = vec(0, 0)
def update(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
window.fill(BLACK)
self.acc = vec(0, 0.7) #having 0.5 adds gravity
self.vy = 0
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
self.vel.y = -7
if keys[pygame.K_LEFT]:
self.acc.x = -0.5 #change to y to add vertical motion
if keys[pygame.K_RIGHT]:
self.acc.x = 0.5 #change to y to add vertical motion
#applys friction
self.acc.x += self.vel.x * -0.08 #FRICTION
#motion equations
self.vel += self.acc
self.pos += self.vel + 0.5 * self.acc
self.rect.center = self.pos
window.blit(self.skin, self.pos)
class Pipe():
def __init__(self,x,y):
self.image = pygame.Surface((50,60))
self.image.fill(RED)
self.rect = self.image.get_rect()
self.pos = vec(x,y)
def blit_pipe(self):
window.blit(self.image, self.pos)
def border_check():
if (flappy.pos.y)+32 > HEIGHT: #this is the very top of the flappy
print("You are under\n")
pygame.quit()
quit()
if flappy.pos.y < 0:
print("You are over\n") #this is the very top of the flappy
pygame.quit()
quit()
pipey = Pipe(300,200)
pipey.blit_pipe()
pipey2 = Pipe(100,200)
pipey2.blit_pipe()
flappy = Bird()
window.blit(flappy.skin, flappy.pos)
while True:
border_check()
flappy.update()
pipey.blit_pipe()
pipey2.blit_pipe()
if flappy.rect.colliderect(pipey.rect):
print('x')
clock.tick(30)
pygame.display.update()
You never set the position of the rects of the Pipe instances so they are still positioned at the default coords (0, 0). There are several ways to set the coords, for example you can pass the coords as the topleft argument to get_rect.
self.rect = self.image.get_rect(topleft=(x, y))
If something is wrong with the collision detection, print the rects to see the actual positions.

Categories

Resources