Python 3.5.2: Pygame Snake Apple location [duplicate] - python

I am making a game in which the player has to use a bowl to catch falling items. I have some images of items in a list and an image of a bowl that is used to catch the items. The items keep on falling and reset to the top of the screen if they reach the boundary (bottom edge). I got this logic done which allows the items to fall but I do not know how to detect when there is a collision between the bowl and item.
My code:
import math
import pygame
import random
pygame.init()
display_width = 800
display_height = 600
game_display = pygame.display.set_mode((display_width, display_height))
clock = pygame.time.Clock()
pygame.display.set_caption("Catch the Ball")
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 255, 0)
player_img = pygame.image.load("Images/soup.png")
thing_imgs = [pygame.image.load('Images/muffin.png'), pygame.image.load('Images/dessert.png'),
pygame.image.load('Images/cheese.png'), pygame.image.load('Images/fruit.png')]
def player(x, y):
game_display.blit(player_img, (x, y))
def things(x, y, img):
game_display.blit(img, (x, y))
def game_loop():
running = True
x = display_width * 0.45
y = display_height * 0.8
x_change = 0
player_width = 64
player_height = 64
things_cor = [[random.randint(0, display_width), 32]]
things_added = [random.choice(thing_imgs)]
thing_height = 32
thing_width = 32
y_change = 5
caught = 0
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = -5
if event.key == pygame.K_RIGHT:
x_change = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
game_display.fill(white)
player(x, y)
x += x_change
for i in range(len(things_cor)):
thing_x, thing_y = things_cor[i]
things(thing_x, thing_y, things_added[i])
for i in range(len(things_cor)):
things_cor[i][1] += y_change
if things_cor[i][1] > display_height:
things_cor[i][1] = random.randint(-2000, -1000)
things_cor[i][0] = random.randint(0, display_width)
things_added[i] = random.choice(thing_imgs)
things_added.append(random.choice(thing_imgs))
if len(things_added) < 6:
things_cor.append(
[random.randint(0, display_width), -10])
if x < 0:
x = 0
elif x > display_width - player_width:
x = display_width - player_width
clock.tick(60)
pygame.display.update()
game_loop()

Use pygame.Rect objects and colliderect() to detect the collision between the bounding rectangles of 2 objects or 2 images:
rect1 = pygame.Rect(x1, y1, w1, h1)
rect2 = pygame.Rect(x2, y2, w2, h2)
if rect1.colliderect(rect2):
# [...]
If you have to images (pygame.Surface objects), the bounding rectangle of can be get by get_rect(), where the location of the Surface has to be set by an keyword argument, since the returned rectangle always starts at (0, 0):
(see Why is my collision test not working and why is the position of the rectangle of the image always wrong (0, 0)?)
def game_loop():
# [...]
while running:
# [...]
player_rect = player_img.get_rect(topleft = (x, y))
for i in range(len(things_cor)):
thing_rect = things_added[i].get_rect(topleft = things_cor[i])
if player_rect.colliderect(thing_rect):
print("hit")
player(x, y)
x += x_change
for i in range(len(things_cor)):
thing_x, thing_y = things_cor[i]
things(thing_x, thing_y, things_added[i])
Use pygame.time.get_ticks() to delay the start of the game for a certain time. pygame.time.get_ticks() return the number of milliseconds since pygame.init() was called. For instance:
def game_loop():
# [...]
while running:
passed_time = pygame.time.get_ticks() # passed time in milliseconds
start_time = 100 * 1000 # start time in milliseconds (100 seconds)
# [...]
# move player
if passed_time >= start_time:
x += x_change
if x < 0:
x = 0
elif x > display_width - player_width:
x = display_width - player_width
# move things
if passed_time >= start_time:
for i in range(len(things_cor)):
things_cor[i][1] += y_change
if things_cor[i][1] > display_height:
things_cor[i][1] = random.randint(-2000, -1000)
things_cor[i][0] = random.randint(0, display_width)
things_added[i] = random.choice(thing_imgs)
things_added.append(random.choice(thing_imgs))
if len(things_added) < 6:
things_cor.append(
[random.randint(0, display_width), -10])
# draw scene and update dispaly
game_display.fill(white)
player(x, y)
for i in range(len(things_cor)):
thing_x, thing_y = things_cor[i]
things(thing_x, thing_y, things_added[i])
pygame.display.update()
clock.tick(60)

Related

How could I optimise this simple python pygame code

I've been set a challenge to make a game using pygame ( I am making snake so it should be easy... but I've never used pygame) so using a more efficient language isn't an option.So my question is that I updating the snake grid is too slow and I'm not experienced enough in pygame to fix this, can anyone who is help.Also as a note if I only fill the grid it doesn't clear behind the Snake.
Using python 3.8
import pygame
import time
import random
pygame.init()
display_width = 800
display_height = 600
display = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("Snake")
pureblue = (0,0,255)
purered = (255,0,0)
puregreen = (0,255,0)
white = (255,255,255)
black = (1,1,1)
grey = (50,50,50)
darkgrey = (25,25,25)
clock = pygame.time.Clock()
snake_block = 10
snake_speed = 30
font_style = pygame.font.SysFont(None, 50)
def drawGrid():
blockSize = 10
for x in range(display_width):
for y in range(display_height):
rect = pygame.Rect(x*blockSize, y*blockSize,blockSize, blockSize)
pygame.draw.rect(display, darkgrey, rect, 1)
def message(msg, colour):
text = font_style.render(msg, True, colour)
display.blit(text, [display_width/2, display_height/2])
def SnakeGameLoop():
game_over = False
X = display_width/2
Y = display_height/2
X_change = 0
Y_change = 0
while not game_over:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
X_change = -10
Y_change = 0
elif event.key == pygame.K_RIGHT:
X_change = 10
Y_change = 0
elif event.key == pygame.K_UP:
X_change = 0
Y_change = -10
elif event.key == pygame.K_DOWN:
X_change = 0
Y_change = 10
if X >= display_width or X < 0 or Y >= display_height or Y < 0:
game_over = True
X += X_change
Y += Y_change
display.fill(grey)
drawGrid()
pygame.draw.rect(display,puregreen,[X,Y,10,10])
pygame.display.update()
clock.tick(15)
message("You lost", purered)
pygame.display.update()
time.sleep(2)
pygame.quit()
quit()
SnakeGameLoop()
To improve the game's performance, draw the grid on a pygame.Surface object with the size of the screen, before the application loop:
def drawGrid(surf):
surf.fill(grey)
blockSize = 10
for x in range(display_width):
for y in range(display_height):
rect = pygame.Rect(x*blockSize, y*blockSize,blockSize, blockSize)
pygame.draw.rect(surf, darkgrey, rect, 1)
grid_surf = pygame.Surface(display.get_size())
drawGrid(grid_surf)
blit the surface once per frame on the display instead of drawing the grid once per frame, in the application loop:
def SnakeGameLoop():
# [...]
while not game_over:
# [...]
display.blit(grid_surf, (0, 0))
pygame.draw.rect(display,puregreen,[X,Y,10,10])
pygame.display.update()

.colliderect not working; why is x and y not updating?

I am currently making a game where you run around as a bear, collect fish, and get points. However, when the bear runs into the fish, it does not pick it up as the bear has run into the fish.
I have tried having the function running in some of the loops where the fish has been made and even making it a function but it does not seem to work.
global screen, grasspic, bearImg, fishpic, screen_width, screen_height, score_number, bearRect
import random
import pygame
import sys
import time
import math
pygame.init()
screen_width = 640
screen_height = 480
sw2 = screen_width/2
sh2 = screen_height/2
bearImg = pygame.image.load('bear.png')
bearImg = pygame.transform.scale(bearImg, (150,150))
green = (24, 255, 0)
bearImg_width = 150
def text_objects(text, font):
textSurface = font.render(text, True, (0,0,0))
return textSurface, textSurface.get_rect()
def message_display(text):
clocktxt = pygame.font.Font('freesans.ttf', 20)
TextSurf, TextRect = text_objects(text, clocktxt)
TextRect.center = (55, 15)
screen.blit(TextSurf, TextRect)
pygame.display.update()
white = (255, 255, 255)
black = (0,0,0)
#NOTE: DOWNLOAD FISH, BEAR, AND GRASS PICTURES|| IT WILL NOT WORK WITHOUT IT
grasspic = []
for i in range(1, 5):
grasspic.append(pygame.image.load('grass%s.png' % i))
fishpic = []
for i in range(1, 3):
fishpic.append(pygame.image.load('fish%s.png' % i))
fishpic[0] = pygame.transform.scale(fishpic[0], (50,50))
fishpic[1] = pygame.transform.scale(fishpic[1], (50,50))
screen = pygame.display.set_mode((screen_width,screen_height))
pygame.display.set_caption('Hungry Boi')
clock = pygame.time.Clock()
camerax = 0
cameray = 0
def getRandomOffCameraPos(camerax, cameray, objWidth, objHeight):
cameraRect = pygame.Rect(camerax, cameray, screen_width, screen_height)
while True:
x = random.randint(camerax - screen_width, camerax + (2*screen_width))
y = random.randint(cameray - screen_height, cameray + (2*screen_height))
objRect = pygame.Rect(x, y, objWidth, objHeight)
if not objRect.colliderect(cameraRect):
return x, y
def makeNewGrass(camerax, cameray):
gr = {}
gr['grassImage'] = random.randint(0, len(grasspic) - 1)
gr['width'] = 80
gr['height'] = 80
gr['x'], gr['y'] = getRandomOffCameraPos(camerax, cameray, gr['width'], gr['height'])
gr['rect'] = pygame.Rect((gr['x'], gr['y'], gr['width'], gr['height']))
return gr
def makeNewFish(camerax, cameray):
fi = {}
fi['fishImage'] = random.randint(0, len(fishpic) - 1)
fi['width'] = 150
fi['height'] = 150
fi['x'], fi['y'] = getRandomOffCameraPos(camerax, cameray, fi['width'], fi['height'])
fi['rect'] = pygame.Rect((fi['x'], fi['y'], fi['width'], fi['height']))
return fi
def bear(x,y):
screen.blit(bearImg,(x,y))
allgrass = []
def makegrass():
for i in range(15):
allgrass.append(makeNewGrass(camerax, cameray))
allgrass[i]['x'] = random.randint(0, screen_width)
allgrass[i]['y'] = random.randint(0, screen_height)
makegrass()
allfish = []
def makefish():
for i in range(2):
allfish.append(makeNewFish(camerax, cameray))
allfish[i]['x'] = random.randint(0, screen_width)
allfish[i]['y'] = random.randint(0, screen_height)
makefish()
def game_loop():
x = (screen_width * 0.4)
y = (screen_height * 0.4)
STARTINGX = (screen_width * 0.4)
STARTINGY = (screen_height * 0.4)
x_change = 0
y_change = 0
vel = 5
gameExit = False
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change -= vel
STARTINGX -= vel
elif event.key == pygame.K_RIGHT:
x_change += vel
STARTINGX += vel
elif event.key == pygame.K_UP:
y_change -= vel
STARTINGY -= vel
elif event.key == pygame.K_DOWN:
y_change += vel
STARTINGY += vel
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
elif event.key == pygame.K_UP or event.key == pygame.K_DOWN:
y_change = 0
#print (event) #see events, basically a console, makes a mess
x += x_change
y += y_change
screen.fill(green)
bearRect = pygame.Rect((STARTINGX, STARTINGY, STARTINGX+150, STARTINGY+150))
for grass in allgrass:
gRect = pygame.Rect((grass['x'] - camerax,
grass['y'] - cameray,
grass['width'],
grass['height']))
screen.blit(grasspic[grass['grassImage']], gRect)
for fish in allfish:
fRect = pygame.Rect((fish['x'] - camerax,
fish['y'] - cameray,
fish['width'],
fish['height']))
screen.blit(fishpic[fish['fishImage']], fRect)
bear(x,y)
score_count()
if bearRect.colliderect(fRect):
makefish()
makegrass()
pygame.display.update()
clock.tick(30) #fps//may not be safe to run really fast
def score_count():
score_number = 0
message_display("Score is: " + str(score_number))
game_loop()
pygame.quit()
quit
Instead of getting a collision and have both the grass and fish images randomize on the screen again, the code will ignore the entire collision. Is there a way to fix it and have it know where the bear and the fish is correctly?
Thank you
Now it works correctly but I made so many changes that it is hard to describe it.
Code did't remove fishes and did't change score so it was hard to say if it checked collision. Now it removes fish (and add new in new place) and change score.
Code keeps position and size in Rect and use only one Rect for every item. I old code Bear had two rect - one to check collision and one to blit it.
In some functions I change names to show that they are very similar and it could be one function.
Every object has image and rect. When you read documentation for pygame.sprite.Sprite then you see that it also uses image and rect.
import random
import pygame
import sys
import time
import math
# --- constants --- (UPPER_CASE_NAMES)
GREEN = (24, 255, 0)
WHITE = (255, 255, 255)
BLACK = (0,0,0)
SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
SW2 = SCREEN_WIDTH/2
SH2 = SCREEN_HEIGHT/2
# --- functions ---
def text_objects(text, font):
surface = font.render(text, True, BLACK)
return surface, surface.get_rect()
def message_display(text):
surface, rect = text_objects(text, CLOCKTXT)
rect.center = (55, 15)
screen.blit(surface, rect)
#pygame.display.update() # use update() olny in one place
def getRandomOffCameraPos(camerax, cameray, objWidth, objHeight):
camera_rect = pygame.Rect(camerax, cameray, SCREEN_WIDTH, SCREEN_HEIGHT)
x1 = camerax - SCREEN_WIDTH
x2 = camerax + (2*SCREEN_WIDTH)
y1 = cameray - SCREEN_HEIGHT
y2 = cameray + (2*SCREEN_HEIGHT)
while True:
x = random.randint(x1, x2)
y = random.randint(y1, y2)
obj_rect = pygame.Rect(x, y, objWidth, objHeight)
if not obj_rect.colliderect(camera_rect):
return x, y
def makeNewGrass(camerax, cameray):
w, h = 80, 80
x, y = getRandomOffCameraPos(camerax, cameray, w, h)
images = grasspic
item = {
'image': random.choice(images),
'rect': pygame.Rect(x, y, w, h),
}
return item
def makeNewFish(camerax, cameray):
w, h = 50, 50
x, y = getRandomOffCameraPos(camerax, cameray, w, h)
images = fishpic
item = {
'image': random.choice(images),
'rect': pygame.Rect(x, y, w, h),
}
return item
def makegrass(number=15):
for i in range(number):
item = makeNewGrass(camerax, cameray)
item['rect'].x = random.randint(0, SCREEN_WIDTH-item['rect'].width)
item['rect'].y = random.randint(0, SCREEN_HEIGHT-item['rect'].height)
allgrass.append(item)
def makefish(number=2):
for i in range(number):
item = makeNewFish(camerax, cameray)
item['rect'].x = random.randint(0, SCREEN_WIDTH-item['rect'].width)
item['rect'].y = random.randint(0, SCREEN_HEIGHT-item['rect'].height)
allfish.append(item)
def score_draw(score):
message_display("Score is: " + str(score))
#--- main ---
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Hungry Boi')
CLOCKTXT = pygame.font.Font('freesans.ttf', 20)
# ---
bear_img = pygame.image.load('bear.png').convert()
bear_img = pygame.transform.scale(bear_img, (150, 150)).convert()
bear_rect = bear_img.get_rect()
bear_rect.x = SCREEN_WIDTH * 0.4
bear_rect.y = SCREEN_HEIGHT * 0.4
bear_vel = 5
grasspic = []
for i in range(1, 5):
image = pygame.image.load('grass%s.png' % i).convert()
grasspic.append(image)
fishpic = []
for i in range(1, 3):
image = pygame.image.load('fish%s.png' % i).convert()
image = pygame.transform.scale(image, (50, 50)).convert()
fishpic.append(image)
# ---
allgrass = []
makegrass()
allfish = []
makefish()
x_change = 0
y_change = 0
camerax = 0
cameray = 0
score = 0
# --- mainloop ---
gameExit = False
clock = pygame.time.Clock()
while not gameExit:
# --- events ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change -= bear_vel
elif event.key == pygame.K_RIGHT:
x_change += bear_vel
elif event.key == pygame.K_UP:
y_change -= bear_vel
elif event.key == pygame.K_DOWN:
y_change += bear_vel
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
x_change += bear_vel
elif event.key == pygame.K_RIGHT:
x_change -= bear_vel
elif event.key == pygame.K_UP:
y_change += bear_vel
elif event.key == pygame.K_DOWN:
y_change -= bear_vel
# --- updates ---
bear_rect.x += x_change
bear_rect.y += y_change
keep_fish = []
for fish in allfish:
if not bear_rect.colliderect(fish['rect']):
keep_fish.append(fish)
else:
makefish(1)
#makegrass()
score += 1
allfish = keep_fish
# --- draws ---
screen.fill(GREEN)
for grass in allgrass:
screen.blit(grass['image'], grass['rect'].move(camerax, cameray))
for fish in allfish:
screen.blit(fish['image'], fish['rect'].move(camerax, cameray))
screen.blit(bear_img, bear_rect.move(camerax, cameray))
score_draw(score)
pygame.display.update()
# --- FPS ---
clock.tick(30) #fps//may not be safe to run really fast
# --- end ---
pygame.quit()

Allow an enemy to follow the player

I am trying to get an enemy, called fudd_img, to follow the player who is playing as bear_img. fudd_img should be slower than the player themselves.
I have tried using the lines:
if bear_rect_x > fudd_rect_x:
fudd_rect_x = fudd_rect_x + max(2, bear_rectx - fudd_rect_x)
elif bear_rect_x < fudd_rect_x:
fudd_rect_x = fudd_rect_x - max(2, fudd_rect_x - bear_rect_x)
but instead, fudd_img will act exactly as bear_img instead of finding a path to the bear_img. Whenever I try to translate this to y, it doesn't work and fudd_img will not move along the y axis.
import random
import pygame
import sys
import time
import math
# --- constants --- (UPPER_CASE_NAMES)
GREEN = (24, 255, 0)
WHITE = (255, 255, 255)
BLACK = (0,0,0)
SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
SW2 = SCREEN_WIDTH/2
SH2 = SCREEN_HEIGHT/2
#---
camerax = 0
cameray = 0
# --- functions ---
def text_objects(text, font):
surface = font.render(text, True, BLACK)
return surface, surface.get_rect()
def message_display(text):
surface, rect = text_objects(text, CLOCKTXT)
rect.center = (58, 15)
screen.blit(surface, rect)
#pygame.display.update() # use update() only in one place
#generate random pos for fish and grass
def getRandomOffCameraPos(camerax, cameray, objWidth, objHeight):
camera_rect = pygame.Rect(camerax, cameray, SCREEN_WIDTH, SCREEN_HEIGHT)
x1 = camerax - SCREEN_WIDTH
x2 = camerax + (2*SCREEN_WIDTH)
y1 = cameray - SCREEN_HEIGHT
y2 = cameray + (2*SCREEN_HEIGHT)
while True:
x = random.randint(x1, x2)
y = random.randint(y1, y2)
obj_rect = pygame.Rect(x, y, objWidth, objHeight)
if not obj_rect.colliderect(camera_rect):
return x, y
def makeNewGrass(camerax, cameray):
w, h = 80, 80
x, y = getRandomOffCameraPos(camerax, cameray, w, h)
images = grasspic
item = {
'image': random.choice(images),
'rect': pygame.Rect(x, y, w, h),
}
return item
def makeNewFish(camerax, cameray):
w, h = 50, 50
x, y = getRandomOffCameraPos(camerax, cameray, w, h)
images = fishpic
item = {
'image': random.choice(images),
'rect': pygame.Rect(x, y, w, h),
}
return item
def makegrass(number=15):
for i in range(number):
item = makeNewGrass(camerax, cameray)
item['rect'].x = random.randint(0, SCREEN_WIDTH-item['rect'].width)
item['rect'].y = random.randint(0, SCREEN_HEIGHT-item['rect'].height)
allgrass.append(item)
def makefish(number=2):
for i in range(number):
item = makeNewFish(camerax, cameray)
item['rect'].x = random.randint(0, SCREEN_WIDTH-item['rect'].width)
item['rect'].y = random.randint(0, SCREEN_HEIGHT-item['rect'].height)
allfish.append(item)
def score_draw(score):
message_display("Score is: " + str(score))
#--- main ---
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Hungry Boi')
CLOCKTXT = pygame.font.Font('freesans.ttf', 20)
# ---
bear_img = pygame.image.load('bear.png')
bear_img = pygame.transform.scale(bear_img, (150, 150))
bear_rect = bear_img.get_rect()
bear_rect.x = SCREEN_WIDTH * 0.4
bear_rect.y = SCREEN_HEIGHT * 0.4
bear_vel = 5
fudd_img = pygame.image.load('fudd.png')
fudd_img = pygame.transform.scale(fudd_img, (150,150))
fudd_rect = fudd_img.get_rect()
fudd_rect.x = SCREEN_WIDTH * 0.4
fudd_rect.y = SCREEN_HEIGHT * 0.4
fudd_vel = 2
grasspic = []
for i in range(1, 5):
image = pygame.image.load('grass%s.png' % i)
grasspic.append(image)
fishpic = []
for i in range(1, 3):
image = pygame.image.load('fish%s.png' % i)
image = pygame.transform.scale(image, (50, 50))
fishpic.append(image)
# ---
allgrass = []
makegrass()
allfish = []
makefish()
x_change = 0
y_change = 0
score = 0
time = 60
# --- mainloop ---
gameExit = False
clock = pygame.time.Clock()
while not gameExit:
# --- events ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change -= bear_vel
elif event.key == pygame.K_RIGHT:
x_change += bear_vel
elif event.key == pygame.K_UP:
y_change -= bear_vel
elif event.key == pygame.K_DOWN:
y_change += bear_vel
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
x_change += bear_vel
elif event.key == pygame.K_RIGHT:
x_change -= bear_vel
elif event.key == pygame.K_UP:
y_change += bear_vel
elif event.key == pygame.K_DOWN:
y_change -= bear_vel
# --- updates ---
bear_rect.x += x_change
bear_rect.y += y_change
keep_fish = []
for fish in allfish:
if not bear_rect.colliderect(fish['rect']):
keep_fish.append(fish)
else:
makefish(1)
#makegrass()
score += 1
allfish = keep_fish
# --- time down ---
for i in range(60):
time -= 1
# --- draws ---
screen.fill(GREEN)
for grass in allgrass:
screen.blit(grass['image'], grass['rect'].move(camerax, cameray))
for fish in allfish:
screen.blit(fish['image'], fish['rect'].move(camerax, cameray))
screen.blit(bear_img, bear_rect.move(camerax, cameray))
screen.blit(fudd_img, fudd_rect.move(camerax, cameray))
score_draw(score)
pygame.display.update()
# --- FPS ---
clock.tick(30) #fps//may not be safe to run really fast
# --- end ---
pygame.quit()
How do I get fudd_img to follow the player, bear_img but not layer on top of the player and spawn on the top left corner of the game? I am hoping that later, this will make it easier for a collision system to work.
Thank you
If it has to follow in a straight line without any obstacles then you can use pygame.math.Vector2D to make all calculations. It has all needed functions to make it simpler and it uses float values so move can be smoother.
First I convert positions from pygame.Rect to pygame.math.Vector2D
player_vector = pygame.math.Vector2(player_rect.center)
enemy_vector = pygame.math.Vector2(enemy_rect.center)
next I calculate difference between both objects (it still gives vector)
diff = player_vector - enemy_vector
If I add it to enemy's position then it gets player's position - enemy would get player in one step but I need shorter vector with the same direction to move enemy slower - to move it in more steps.
If I normalize vector then I get vector with the same direction but shorter. It's length is 1.
move = diff.normalize()
Now I can add it to enemy's position to make small step in player's direction.
enemy_vector += move
And now I can use new position to convert back to position in pygame.Rect
enemy_rect.center = enemy_vector
and draw on screen
pygame.draw.rect(screen, GREEN, player_rect)
pygame.draw.rect(screen, RED, enemy_rect)
If I want to faster move then I can multiplicate normalized vector
move = diff.normalize() * 2
player_vector = pygame.math.Vector2(player_rect.center)
enemy_vector = pygame.math.Vector2(enemy_rect.center)
diff = player_vector - enemy_vector
move = diff.normalize() * 2
enemy_vector += move
enemy_rect.center = enemy_vector
pygame.draw.rect(screen, GREEN, player_rect)
pygame.draw.rect(screen, RED, enemy_rect)
To make move smoother I will keep enemy's position in Vector (as float values) and convert to pygame.Rect only to draw it.
Full working example. Player is in center, enemy starts in random position and move to player. It displays also line between objects. You can move player using arrows.
import pygame
import random
# --- constants --- (UPPER_CASE_NAMES)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
SCREEN_WIDTH = 1000
SCREEN_HEIGHT = 600
SCREEN_WIDTH_HALF = SCREEN_WIDTH//2
SCREEN_HEIGHT_HALF = SCREEN_HEIGHT//2
#--- main ---
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
player_rect = pygame.Rect(0, 0, 16, 16)
player_rect.center = (SCREEN_WIDTH_HALF, SCREEN_HEIGHT_HALF)
player_speed = 2
enemy_rect = pygame.Rect(0, 0, 16, 16)
enemy_rect.centerx = random.randint(0, SCREEN_WIDTH)
enemy_rect.centery = random.randint(0, SCREEN_HEIGHT)
enemy_speed = 2
enemy_vector = pygame.math.Vector2(enemy_rect.center)
#old_rect = enemy_rect.copy()
clock = pygame.time.Clock()
run = True
while run:
clock.tick(15) # 120 FPS
#pygame.time.delay(5)
# --- events ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# --- changes ---
keys = pygame.key.get_pressed()
# move player
if player_rect.top > 0 and keys[pygame.K_UP]:
player_rect.y -= player_speed
if player_rect.bottom < SCREEN_HEIGHT and keys[pygame.K_DOWN]:
player_rect.y += player_speed
if player_rect.left > 0 and keys[pygame.K_LEFT]:
player_rect.x -= player_speed
if player_rect.right < SCREEN_WIDTH and keys[pygame.K_RIGHT]:
player_rect.x += player_speed
# enemy follow player
player_vector = pygame.math.Vector2(player_rect.center)
diff = player_vector - enemy_vector
if diff.length() > 0.1:
move = diff.normalize() * enemy_speed
enemy_vector += move
enemy_rect.center = enemy_vector
# -- draws ---
screen.fill(BLACK)
pygame.draw.line(screen, WHITE, player_rect.center, enemy_rect.center)
pygame.draw.rect(screen, GREEN, player_rect)
pygame.draw.rect(screen, RED, enemy_rect)
#pygame.draw.rect(screen, WHITE, old_rect)
pygame.display.flip()
# --- end ---
pygame.quit()

Hexagon does not show

I have a problem with my code, im trying to draw a hexagon polygon, but nth show up. When i'm trying with eclipse or other pygame.draw functions its ok, problem is with polygons. Here is my code. I think whole program is working fine, the problem is here :
hexagon = Hexagon.hexagon_generator(40,self.rect.x,self.rect.y)
pygame.draw.polygon(self.image,(0,225,0),list(hexagon),0)
Whole program:
import pygame
import random
import Hexagon
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
class Player(pygame.sprite.Sprite):
def __init__(self,x,y):
super().__init__()
self.image = pygame.Surface([100,100])
self.rect = self.image.get_rect()
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
self.rect.x = x
self.rect.y = y
hexagon = Hexagon.hexagon_generator(40,self.rect.x,self.rect.y)
pygame.draw.polygon(self.image,(0,225,0),list(hexagon),0)
self.velocity_y = 0
self.velocity_x = 0
def move(self, x, y):
self.velocity_x += x
self.velocity_y += y
def update(self):
self.rect.x += self.velocity_x
self.rect.y += self.velocity_y
if self.rect.x >785:
self.rect.x =785
elif self.rect.x <0:
self.rect.x =0
elif self.rect.y > 585:
self.rect.y = 585
elif self.rect.y < 0:
self.rect.y = 0
elif self.rect.x<0 and self.rect.y < 0:
self.rect.x = 0
self.rect.y = 0
pygame.init()
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode([screen_width, screen_height])
all_sprites_list = pygame.sprite.Group()
player = Player(200,200)
all_sprites_list.add(player)
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
player.move(0,5)
if event.key == pygame.K_UP:
player.move(0, -5)
if event.key == pygame.K_LEFT:
player.move(-5, 0)
if event.key == pygame.K_RIGHT:
player.move(5, 0)
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN:
player.move(0, -5)
if event.key == pygame.K_UP:
player.move(0, 5)
if event.key == pygame.K_LEFT:
player.move(5, 0)
if event.key == pygame.K_RIGHT:
player.move(-5, 0)
screen.fill(WHITE)
all_sprites_list.update()
all_sprites_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
There is a Hexagon module:
import math
def hexagon_generator(edge_length, x,y):
for angle in range(0, 360, 60):
x += math.cos(math.radians(angle)) * edge_length
y += math.sin(math.radians(angle)) * edge_length
yield x, y
If you print the values that hexagon_generator yields, you'll see that the points are outside of the image (which has a size of 100*100 pixels).
[(240.0, 200.0), (260.0, 234.64101615137753), (240.0, 269.28203230275506), (200.0, 269.28203230275506), (179.99999999999997, 234.64101615137753), (199.99999999999997, 200.0)]
You shouldn't use the world coordinates of the player as the start x, y values. If the hexagon should be centered, you can just pass the half edge length of the image to the generator and add it to x and y:
def hexagon_generator(edge_length):
for angle in range(0, 360, 60):
x = math.cos(math.radians(angle)) * edge_length + edge_length
y = math.sin(math.radians(angle)) * edge_length + edge_length
yield x, y

Python/Pygame Use get_rect() result from Class A to Class B [duplicate]

I am making a game in which the player has to use a bowl to catch falling items. I have some images of items in a list and an image of a bowl that is used to catch the items. The items keep on falling and reset to the top of the screen if they reach the boundary (bottom edge). I got this logic done which allows the items to fall but I do not know how to detect when there is a collision between the bowl and item.
My code:
import math
import pygame
import random
pygame.init()
display_width = 800
display_height = 600
game_display = pygame.display.set_mode((display_width, display_height))
clock = pygame.time.Clock()
pygame.display.set_caption("Catch the Ball")
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 255, 0)
player_img = pygame.image.load("Images/soup.png")
thing_imgs = [pygame.image.load('Images/muffin.png'), pygame.image.load('Images/dessert.png'),
pygame.image.load('Images/cheese.png'), pygame.image.load('Images/fruit.png')]
def player(x, y):
game_display.blit(player_img, (x, y))
def things(x, y, img):
game_display.blit(img, (x, y))
def game_loop():
running = True
x = display_width * 0.45
y = display_height * 0.8
x_change = 0
player_width = 64
player_height = 64
things_cor = [[random.randint(0, display_width), 32]]
things_added = [random.choice(thing_imgs)]
thing_height = 32
thing_width = 32
y_change = 5
caught = 0
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = -5
if event.key == pygame.K_RIGHT:
x_change = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
game_display.fill(white)
player(x, y)
x += x_change
for i in range(len(things_cor)):
thing_x, thing_y = things_cor[i]
things(thing_x, thing_y, things_added[i])
for i in range(len(things_cor)):
things_cor[i][1] += y_change
if things_cor[i][1] > display_height:
things_cor[i][1] = random.randint(-2000, -1000)
things_cor[i][0] = random.randint(0, display_width)
things_added[i] = random.choice(thing_imgs)
things_added.append(random.choice(thing_imgs))
if len(things_added) < 6:
things_cor.append(
[random.randint(0, display_width), -10])
if x < 0:
x = 0
elif x > display_width - player_width:
x = display_width - player_width
clock.tick(60)
pygame.display.update()
game_loop()
Use pygame.Rect objects and colliderect() to detect the collision between the bounding rectangles of 2 objects or 2 images:
rect1 = pygame.Rect(x1, y1, w1, h1)
rect2 = pygame.Rect(x2, y2, w2, h2)
if rect1.colliderect(rect2):
# [...]
If you have to images (pygame.Surface objects), the bounding rectangle of can be get by get_rect(), where the location of the Surface has to be set by an keyword argument, since the returned rectangle always starts at (0, 0):
(see Why is my collision test not working and why is the position of the rectangle of the image always wrong (0, 0)?)
def game_loop():
# [...]
while running:
# [...]
player_rect = player_img.get_rect(topleft = (x, y))
for i in range(len(things_cor)):
thing_rect = things_added[i].get_rect(topleft = things_cor[i])
if player_rect.colliderect(thing_rect):
print("hit")
player(x, y)
x += x_change
for i in range(len(things_cor)):
thing_x, thing_y = things_cor[i]
things(thing_x, thing_y, things_added[i])
Use pygame.time.get_ticks() to delay the start of the game for a certain time. pygame.time.get_ticks() return the number of milliseconds since pygame.init() was called. For instance:
def game_loop():
# [...]
while running:
passed_time = pygame.time.get_ticks() # passed time in milliseconds
start_time = 100 * 1000 # start time in milliseconds (100 seconds)
# [...]
# move player
if passed_time >= start_time:
x += x_change
if x < 0:
x = 0
elif x > display_width - player_width:
x = display_width - player_width
# move things
if passed_time >= start_time:
for i in range(len(things_cor)):
things_cor[i][1] += y_change
if things_cor[i][1] > display_height:
things_cor[i][1] = random.randint(-2000, -1000)
things_cor[i][0] = random.randint(0, display_width)
things_added[i] = random.choice(thing_imgs)
things_added.append(random.choice(thing_imgs))
if len(things_added) < 6:
things_cor.append(
[random.randint(0, display_width), -10])
# draw scene and update dispaly
game_display.fill(white)
player(x, y)
for i in range(len(things_cor)):
thing_x, thing_y = things_cor[i]
things(thing_x, thing_y, things_added[i])
pygame.display.update()
clock.tick(60)

Categories