Pygame - Problem with setting a collision boundary in specific area [duplicate] - python

This question already has answers here:
pygame sprite wall collision [duplicate]
(3 answers)
How do I detect collision in pygame?
(5 answers)
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
Closed 2 years ago.
--- FULL CODE AT BOTTOM OF QUESTION ---
my plan is to add an area of my screen occupied by an NPC to be completely unable to enter by the player. I've tried doing this method by doing this in the NPC class of my code, where the y position of the player is compared to the "self.y"/current y position of the npc:
class NPC(object):
def __init__(self, path, x, y):
self.image = pygame.image.load(path).convert_alpha()
self.x = x
self.y = y
self.width = self.image.get_width()
self.height = self.image.get_height()
self.hitbox = (self.x, self.y, self.width, self.height)
def spawn(self, surface):
surface.blit(self.image, (self.x, self.y))
self.hitbox = (self.x, self.y, self.width, self.height)
pygame.draw.rect(screen, (255, 255, 255), self.hitbox, 2)
def collide(self, x, y, width, height):
if self.y <= y <= self.y + self.height:
print("collide")
up = True
else:
up = False
print("not")
I am aware that I've not properly finished the code yet, I've only added in the part that should stop the player from going up at the moment for testing purposes.
For some reason however, the collision boundary is at the very top of the screen (whilst the NPC is not) and I suspect it's due to the program measuring the height of the npc from the top of the screen (i.e: npc sprite is 32 pixels tall, so collide region is first 32 pixels at top of screen)
The code that stops the player from moving (which is what the "up" boolean refers to outside of the class) also isn't working - is this due to not returning the values, possibly?
FULL CODE:
import pygame
import time
progress = 0
pygame.init()
(width, height) = (600, 400) #specify window resolution
bg_colour = (100,20,156) #specify bg colour
player_path = "downChara.png" #specifies image path
moveDown = True
moveUp = True
moveRight = True
moveLeft = True
class Player(object): #representitive of the player's overworld sprite
def __init__(self):
self.image = pygame.image.load(player_path).convert_alpha() #creates image, the player_path variable allowing it to be updated
self.X = (width/2) -16; # x co-ord of player
self.Y = (height/2)-16; # y co-ord of player
self.width = self.image.get_width()
self.height = self.image.get_height()
self.hitbox = (self.X, self.Y, self.width, self.height)
def handle_keys(self, down, up, left, right): #handling the keys/inputs
key = pygame.key.get_pressed()
dist = 5 #distance travelled in one frame of the program
if key[pygame.K_DOWN] and down == True: #if down
self.Y += dist #move down the length of dist
player_path = "downChara.png" #change image to down
self.image = pygame.image.load(player_path).convert_alpha()
elif key[pygame.K_UP] and up == True: #if up
self.Y -= dist #move up the length of dist
player_path = "upChara.png" #change to up
self.image = pygame.image.load(player_path).convert_alpha()
if key[pygame.K_RIGHT] and right == True: #etc.
self.X += dist
player_path = "rightChara.png"
self.image = pygame.image.load(player_path).convert_alpha()
elif key[pygame.K_LEFT] and left == True:
self.X -= dist
player_path = "leftChara.png"
self.image = pygame.image.load(player_path).convert_alpha()
def outX(coord): #"coord" acts the same as "self"
return (coord.X)
def outY(coord):
return (coord.Y)
def draw(self, surface): #draw to the surface/screen
surface.blit(self.image, (self.X, self.Y))
self.hitbox = (self.X, self.Y, self.width, self.height)
pygame.draw.rect(screen, (255, 255, 255), self.hitbox, 2)
return self.X, self.Y, self.width, self.height
class NPC(object):
def __init__(self, path, x, y):
self.image = pygame.image.load(path).convert_alpha()
self.x = x
self.y = y
self.width = self.image.get_width()
self.height = self.image.get_height()
self.hitbox = (self.x, self.y, self.width, self.height)
def spawn(self, surface):
surface.blit(self.image, (self.x, self.y))
self.hitbox = (self.x, self.y, self.width, self.height)
pygame.draw.rect(screen, (255, 255, 255), self.hitbox, 2)
def collide(self, x, y, width, height):
if self.y <= y <= self.y + self.height:
print("collide")
up = True
else:
up = False
print("not")
##if self.y < player.hitbox[1]
def text_objects(text, font):
textSurface = font.render(text, True, (255, 255, 255))
return textSurface, textSurface.get_rect()
def interact(text):
textbox = pygame.transform.scale(pygame.image.load("bigbox.png"), (600, 111))
textSize = pygame.font.Font("cour.ttf",28) #specify text size
TextSurf, TextRect = text_objects(text, textSize) #allow text to be positioned
TextRect.topleft = (12, 297) #where text will be
screen.blit(textbox, (0, 289))
screen.blit(TextSurf, TextRect) #display text
pygame.display.update() #updates screen
time.sleep(2)
screen.fill(bg_colour, TextRect)
##def checker(array):
## ## check first value of each part of array (all numbers)
## ## compare it to progress
## ## if equal to or less than, cycle through rest of that part of array.
## ## if greater than, then ignore.
## ## e.g: progress = 49, NPC1 will still be on text "0", NPC2 will now be on "33" and NPC3 will be on "0"
##
## placeholderList = []
##
## for x in range(len(array)):
## if array[x][0] <= progress:
## del placeholderList[0:]
## placeholderList.append(array[x][1:])
## for x in range(len(placeholderList)):
## passMe = placeholderList[x]
## print (passMe)
## npc.interact(passMe)
screen = pygame.display.set_mode((width, height)) #create window
pygame.display.set_caption('EduGame') #specify window name
player = Player()
playerx, playery, playerwidth, playerheight = player.draw(screen)
clock = pygame.time.Clock()
person1 = NPC("talkToThis.png",100, 200)
npc = NPC("test.png",0, 0)
def setup(text):
for x in range(len(text)):
passtext = text[x]
interact(passtext)
boarderX = player.outX()
boarderY = player.outY()
##print (boarderX, boarderY) #making sure they both returned properly
pygame.display.flip() #paints screen
gameRun = True #allow game events to loop/be carried out more than once
while gameRun: #while game is running:
person1text2 = [[0,"beginng","www","xxdqsd"],[1,"middle","aa"],[2,"end!"]]
personText = ("hello","hi","bye")
playerx, playery, playerwidth, playerheight = player.draw(screen)
print(playerx, playery, playerwidth, playerheight)
npc.collide(playerx, playery, playerwidth, playerheight)
event = pygame.event.poll()
if event.type == pygame.QUIT: #if the "x" is pressed
pygame.quit() #quit game
gameRun = False #break the loop.
quit()
if event.type == pygame.KEYDOWN and event.key == pygame.K_RETURN:
## checker(person1text2)
setup(personText)
player.handle_keys(moveDown, moveUp, moveLeft, moveRight) #handle keys
screen.fill(bg_colour) #draw background colour
player.draw(screen) #draws player
person1.spawn(screen)
pygame.display.update()
posX = player.outX()
posY = player.outY()
if posX > width - 32: #this is because the sprite's "X" is determined in the top left corner, meaning we have to subtract the width from the measurement
moveRight = False
else:
moveRight = True
if posX < 0:
moveLeft = False
else:
moveLeft = True
if posY > height - 32: #this is because the sprite's "X" is determined in the top left corner, meaning we have to subtract the width from the measurement
moveDown = False
else:
moveDown = True
if posY < 0:
moveUp = False
else:
moveUp = True
clock.tick(60)
it's very WIP, so if you happen to catch anything else whilst checking through it then feel free to bring it up.

Related

How to add snake parts when he eats the food in pygame [duplicate]

This question already has an answer here:
How do I get the snake to grow and chain the movement of the snake's body?
(1 answer)
Closed 24 days ago.
Right now I'm learning oop so I want to practice some on this snake game project.
So when i want to add snake parts when he eat the food i don't know what to do.
here is my code .give me your opinion about it (if you want).(=
import pygame, random, math
pygame.init()
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
BLACK = (0,0,0)
WHITE = (255,255,255)
WINDOW_W = 800
WINDOW_H = 600
BACKGROUND_COLOR = BLACK
clock = pygame.time.Clock()
SNAKE_WIDTH = 25
SNAKE_HEIGHT = 25
SNAKE_COLOR = GREEN
SNAKE_VEL = 25
FOOD_WIDTH = SNAKE_WIDTH
FOOD_HEIGHT = SNAKE_HEIGHT
FOOD_COLOR = RED
FPS = 10
win = pygame.display.set_mode((WINDOW_W, WINDOW_H))
pygame.display.set_caption('G_G')
#-------------------------------------------------------------------------------------------
class Snake:
def __init__(self, WIDTH ,HEIGHT, COLOR, VELOCITY, x, y):
self.WIDTH = WIDTH
self.HEIGHT = HEIGHT
self.COLOR = COLOR
self.VEL = VELOCITY
self.x = x
self.y = y
def draw(self):
pygame.draw.rect(win, self.COLOR, (self.x, self.y, self.WIDTH, self.HEIGHT))
def spawn(self):
if self.x<0:
self.x = WINDOW_W + SNAKE_WIDTH
if self.x > WINDOW_W + SNAKE_WIDTH:
self.x = 0
if self.y < 0:
self.y = WINDOW_H + SNAKE_HEIGHT
if self.y > WINDOW_H + SNAKE_HEIGHT:
self.y = 0
snake = Snake(SNAKE_WIDTH, SNAKE_HEIGHT, SNAKE_COLOR, SNAKE_VEL,1, 1)
#--------------------------------------------------------------------------------------------
class Food:
def __init__(self, WIDTH ,HEIGHT, COLOR, x=random.randrange(1, WINDOW_W+1, FOOD_WIDTH), y=random.randrange(1, WINDOW_H+1, FOOD_HEIGHT)):
self.WIDTH = WIDTH
self.HEIGHT = HEIGHT
self.COLOR = COLOR
self.x = x
self.y = y
def draw(self):
pygame.draw.rect(win, self.COLOR, (self.x, self.y, self.WIDTH, self.HEIGHT))
def snake_eats_food():
dis_snake_food = math.sqrt(((snake.x-food.x))**2+(snake.y-food.y)**2)
if abs(dis_snake_food)<4:
food.x = random.randrange(1, WINDOW_W+1, FOOD_WIDTH)
food.y = random.randrange(1, WINDOW_H+1, FOOD_HEIGHT)
return True
else:
return False
food = Food(FOOD_WIDTH, FOOD_WIDTH, FOOD_COLOR)
#-----------------------------------------------------------------------------------------
def draw():
win.fill(BACKGROUND_COLOR)
for x in range(0, WINDOW_W+1, SNAKE_WIDTH):
pygame.draw.line(win, WHITE, (x, 0), (x, WINDOW_H), 2)
for y in range(0, WINDOW_H+1, SNAKE_HEIGHT):
pygame.draw.line(win, WHITE, (0, y), (WINDOW_W, y), 2)
snake.draw()
food.draw()
def main():
run = True
up,down,right,left = False,False,False,False
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#-----------------------------------
draw()
snake_eats_food()
pygame.display.update()
#------------------------------------
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
up,down,right,left = True,False,False,False
if keys[pygame.K_DOWN]:
down,up,right,left = True,False,False,False
if keys[pygame.K_RIGHT]:
right,down,up,left = True,False,False,False
if keys[pygame.K_LEFT]:
left,down,right,up = True,False,False,False
if up:
snake.y -= snake.VEL
snake.spawn()
if down:
snake.y += snake.VEL
snake.spawn()
if right:
snake.x += snake.VEL
snake.spawn()
if left:
snake.x -= snake.VEL
snake.spawn()
#-----------------------------------
pygame.quit()
if __name__ == "__main__":
main()
I know the code is a bit messy because I wanted to try to implement OOP, since I never used it.
To render the snake:
I would recommend using a list of coordinate pairs named self.snake_array which represents points along the snake. Every unit you go forward, append the current snake coordinate pair to the end of self.snake_array and delete the first element in the coordinate pair array if the array length exceeds self.snake_length.
. I recommend having a self.snake_length variable that determines how many units long the snake is. When you run snake_eats_food, check if it returned true. If it returned true, increase the self.snake_length. All you have left to do is fix your snake draw function so that it loops through the self.snake_array and draws a square at each coordinate.
Hope that helps!

Pygame Curve Movement Problem How To Fix?

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

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()

Categories

Resources