I am remaking the game Snake with pygame.
How do I detect if the square is outside the screen?
I am using x = and y = to move the square.
This is the code so far:
import pygame, sys, random
from pygame.locals import *
pygame.init()
movement_x = movement_y = 0
RED = (240, 0, 0)
GREEN = (0, 255, 0)
ran = [0,25,50,75,100,125,150,175,200,225,250,275,300,325,350,375,400,425,450,475,500]
ax = 0
ay = 0
x = 0
y = 0
sizex = 500
sizey = 500
tilesize = 25
screen = pygame.display.set_mode((sizex,sizey))
pygame.display.set_caption('Snake')
pygame.display.set_icon(pygame.image.load('images/tile.png'))
tile = pygame.image.load('images/tile.png')
tile = pygame.transform.scale(tile, (tilesize, tilesize))
clock = pygame.time.Clock()
vel_x = 0
vel_y = 0
ap = True
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
for row in range(sizex):
for column in range(sizey):
screen.blit(tile,(column*tilesize, row*tilesize,tilesize,tilesize))
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_UP:
vel_y = -25
vel_x = 0
elif event.key == K_DOWN:
vel_y = 25
vel_x = 0
elif event.key == K_LEFT:
vel_x = - 25
vel_y = 0
elif event.key == K_RIGHT:
vel_x= 25
vel_y = 0
if ap:
pygame.draw.rect(screen, GREEN, pygame.Rect(ax,ay,tilesize,tilesize))
y += vel_y
x += vel_x
if x == ax and y == ay:
pygame.draw.rect(screen, GREEN, pygame.Rect(ax,ay,tilesize,tilesize))
ax = random.choice(ran)
ay = random.choice(ran)
pygame.draw.rect(screen, RED, pygame.Rect(x,y,tilesize,tilesize))
pygame.display.flip()
clock.tick(100)
If a point is inside a rectangle can be checked by pygame.Rect.collidepoint().
The rectangle is defined by the bounds of the screen and the point is the new position of the head of the snake:
inBounds = pygame.Rect(0, 0, sizex, sizey).collidepoint(x+vel_x, y+vel_y)
if inBounds:
y += vel_y
x += vel_x
Related
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 1 year ago.
I'm new to python and only now the basics, I'm trying to make a snake game but I can't seem to figure out how to make my snake grow 1 extra square each time it eats an apple. My reasoning is that I keep a list of all the old positions but only show the last one on the screen, and each time the snakes eats another apple it shows 1 extra old positions making the snake 1 square longer.
This is my code:
import pygame
from random import randint
WIDTH = 400
HEIGHT = 300
dis = pygame.display.set_mode((WIDTH,HEIGHT))
white = (255,255,255)
BACKGROUND = white
blue = [0,0,255]
red = [255,0,0]
class Snake:
def __init__(self):
self.image = pygame.image.load("snake.bmp")
self.rect = self.image.get_rect()
self.position = (10,10)
self.direction = [0,0]
self.positionslist = [self.position]
self.length = 1
pygame.display.set_caption('Snake ')
def draw_snake(self,screen):
screen.blit(self.image, self.position)
def update(self):
self.position = (self.position[0] + self.direction[0],self.position[1] + self.direction[1])
self.rect = (self.position[0],self.position[1],5, 5 )
self.positionslist.append(self.position)
if self.position[0]< 0 :
self.position = (WIDTH,self.position[1])
elif self.position[0] > WIDTH:
self.position = (0,self.position[1])
elif self.position[1] > HEIGHT:
self.position = (self.position[0],0)
elif self.position[1] < 0 :
self.position = (self.position[0],HEIGHT)
class Food:
def __init__(self):
self.image = pygame.image.load("appel.png")
self.rect = self.image.get_rect()
apple_width = -self.image.get_width()
apple_height = -self.image.get_height()
self.position = (randint(0,WIDTH+apple_width-50),randint(0,HEIGHT+apple_height-50))
self.rect.x = self.position[0]
self.rect.y = self.position[1]
def draw_appel(self,screen):
screen.blit(self.image, self.position)
def eat_appel (self, snake):
if self.rect.colliderect(snake.rect) == True:
self.position = (randint(0,WIDTH),randint(0,HEIGHT))
self.rect.x = self.position[0]
self.rect.y = self.position[1]
snake.length += 1
def main():
game_over = False
while not game_over:
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
snake = Snake()
food = Food()
while True:
screen.fill(BACKGROUND)
font = pygame.font.Font('freesansbold.ttf', 12)
text = font.render(str(snake.length), True, red, white)
textRect = text.get_rect()
textRect.center = (387, 292)
screen.blit(text,textRect)
snake.update()
#snake.update_list()
snake.draw_snake(screen)
food.draw_appel(screen)
food.eat_appel(snake)
pygame.display.flip()
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
snake.direction = [0,1]
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
snake.direction = [1,0]
if event.key == pygame.K_LEFT:
snake.direction = [-1,0]
if event.key == pygame.K_UP:
snake.direction = [0,-1]
if event.key == pygame.K_DOWN:
snake.direction = [0,1]
if __name__ == "__main__":
main()
This can have multiple reasons. Firstly, I saw you tried to increase the length of the snake by typing snake.length += 1, which may work (probably won't because the module pygame allows the snake to hover around, but not like the loop or conditional statements). One of my tips would be, to increase the length of the snake by using the idea of adding the score with your present snake.length every time (because once your score is 1 by eating an apple, your snake.length would be 2. And it increases with the score). This is my code (a few modifications might be needed):
import pygame
import time
import random
pygame.init()
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
orange = (255, 165, 0)
width, height = 600, 400
game_display = pygame.display.set_mode((width, height))
pygame.display.set_caption("Snake Mania")
clock = pygame.time.Clock()
snake_size = 10
snake_speed = 15
message_font = pygame.font.SysFont('ubuntu', 30)
score_font = pygame.font.SysFont('ubuntu', 25)
def print_score(score):
text = score_font.render("Score: " + str(score), True, orange)
game_display.blit(text, [0,0])
def draw_snake(snake_size, snake_pixels):
for pixel in snake_pixels:
pygame.draw.rect(game_display, white, [pixel[0], pixel[1], snake_size, snake_size])
def run_game():
game_over = False
game_close = False
x = width / 2
y = height / 2
x_speed = 0
y_speed = 0
snake_pixels = []
snake_length = 1
target_x = round(random.randrange(0, width - snake_size) / 10.0) * 10.0
target_y = round(random.randrange(0, height - snake_size) / 10.0) * 10.0
while not game_over:
while game_close:
game_display.fill(black)
game_over_message = message_font.render("Game Over!", True, red)
game_display.blit(game_over_message, [width / 3, height / 3])
print_score(snake_length - 1)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
game_over = True
game_close = False
if event.key == pygame.K_2:
run_game()
if event.type == pygame.QUIT:
game_over = True
game_close = False
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_speed = -snake_size
y_speed = 0
if event.key == pygame.K_RIGHT:
x_speed = snake_size
y_speed = 0
if event.key == pygame.K_UP:
x_speed = 0
y_speed = -snake_size
if event.key == pygame.K_DOWN:
x_speed = 0
y_speed = snake_size
if x >= width or x < 0 or y >= height or y < 0:
game_close = True
x += x_speed
y += y_speed
game_display.fill(black)
pygame.draw.rect(game_display, orange, [target_x, target_y, snake_size, snake_size])
snake_pixels.append([x, y])
if len(snake_pixels) > snake_length:
del snake_pixels[0]
for pixel in snake_pixels[:-1]:
if pixel == [x, y]:
game_close = True
draw_snake(snake_size, snake_pixels)
print_score(snake_length - 1)
pygame.display.update()
if x == target_x and y == target_y:
target_x = round(random.randrange(0, width - snake_size) / 10.0) * 10.0
target_y = round(random.randrange(0, height - snake_size) / 10.0) * 10.0
snake_length += 1
clock.tick(snake_speed)
pygame.quit()
quit()
run_game()
I am having this problem where I can draw a grid for my snake but I cant fill in the colour between it.It seems like the problem is that because the grid on the surface overrides the actual colour of the background but I dont know how to fix this, can anyone who knows more about pygame help.
See line 74 of my code and that is the colour it should be.
How could I optimise this simple python pygame code
import pygame
import time
import random
pygame.init()
display_width = 960
display_height = 540
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)
green = (0,150,0)
white = (255,255,255)
black = (1,1,1)
grey = (75,75,75)
darkgrey = (50,50,50)
clock = pygame.time.Clock()
snake_block = 10
snake_speed = 5
font_style = pygame.font.SysFont(None, 50)
def drawGrid(surf):
blockSize = snake_block
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)
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 = -snake_block
Y_change = 0
elif event.key == pygame.K_RIGHT:
X_change = snake_block
Y_change = 0
elif event.key == pygame.K_UP:
X_change = 0
Y_change = -snake_block
elif event.key == pygame.K_DOWN:
X_change = 0
Y_change = snake_block
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)
display.blit(grid_surf, (0,0))
pygame.draw.rect(display,puregreen,[X,Y,snake_block,snake_block])
pygame.display.update()
clock.tick(snake_speed)
message("You lost", purered)
pygame.display.update()
time.sleep(2)
pygame.quit()
quit()
SnakeGameLoop()
You need to fill the grid Surface with the background color:
def drawGrid(surf):
surf.fill(grey) # <--- ADD
blockSize = snake_block
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)
Since the grid Surface covers the entire display it is not necessary to clear the display in the application loop:
def SnakeGameLoop():
# [...]
while not game_over:
# [...]
# display.fill(grey) <--- DELETE
display.blit(grid_surf, (0,0))
pygame.draw.rect(display,puregreen,[X,Y,snake_block,snake_block])
pygame.display.update()
# [...]
I am unable to detect when two rectangles of different sizes collide.
I've tried, "if x == obj_x and y == obj_y:" where x is one rectangle's x-value, obj_x is the other rectangle's x value, and the same for the y-values.
import pygame
import time
import random
pygame.init()
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
display_width = 500
display_height = 500
screen = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('Avoid')
x_change = 0
y_change = 0
FPS = 30
block_size = 10
font = pygame.font.SysFont(None, 25)
smallfont = pygame.font.SysFont("comicsansms",25)
def showLives(lives):
text = smallfont.render("Lives: "+str(lives), True, white)
screen.blit(text, [0,0])
def message_to_screen(msg,color):
screen_text = font.render(msg, True, color)
screen.blit(screen_text, [100,250])
clock = pygame.time.Clock()
def gameLoop():
gameExit = False
gameOver = False
x = 250
y = 425
x_change = 0
y_change = 0
obj_speed = 5
obj_y = 0
obj_x = 0
obj2_y = 0
obj2_x = 0
obj2_speed = 3
lives = 3
while not gameExit:
while gameOver == True:
screen.fill(white)
message_to_screen("Game Over, Press C to play again or Q to quit", red)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameExit = True
gameOver = False
if event.key == pygame.K_c:
gameLoop()
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 = -block_size
y_change = 0
elif event.key == pygame.K_RIGHT:
x_change = block_size
y_change = 0
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
x_change = 0
y_change = 0
if x > 500-block_size:
x-=block_size
if x < 0+block_size:
x+=block_size
# if x >= display_width-block_size-block_size or x < 0:
# gameOver = True
obj_y = obj_y + obj_speed
if obj_y > display_height:
obj_x = random.randrange(0, display_width-block_size)
obj_y = -25
obj2_y = obj2_y + obj2_speed
if obj2_y > display_height:
obj2_x = random.randrange(1, display_width-block_size)
obj2_y = -27
x += x_change
y += y_change
screen.fill(black)
pygame.draw.rect(screen,white, [obj_x,obj_y,20,20])
pygame.draw.rect(screen,white, [obj2_x,obj2_y,20,20])
pygame.draw.rect(screen, red, [x,y,block_size,block_size])
showLives(lives)
pygame.display.update()
if x == obj_x and y == obj_y:
lives -= 1
if lives == 0:
gameOver = True
clock.tick(FPS)
pygame.quit()
quit()
gameLoop()
I want the program to detect when any part of the rectangles collide instead of just detecting when one point on each of the rectangles collide.
PyGame has class pygame.Rect() to keep rectangle's position and size. It uses it to draw images/sprites and check collision between sprites.
x = 250
y = 425
obj_y = 0
obj_x = 0
rect_1 = pygame.Rect(x, y, 10, 10)
rect_2 = pygame.Rect(obj_x, obj_y, 20, 20)
and then you can check collision
rect_1.colliderect(rect_2)
You can also use it to draw rectangle on screen
pygame.draw.rect(screen, white, rect_2)
pygame.draw.rect(screen, red, rect_1)
You can also use it to check collision between rectangle and point - ie. to check if button was clicked by mouse
button_rect.collidepoint(event.pos)
To change values in rectangle you have rect_1.x, rect_1.y, rect_1.width, rect_1.height but also
x,y
top, left, bottom, right
topleft, bottomleft, topright, bottomright
midtop, midleft, midbottom, midright
center, centerx, centery
size, width, height
w,h
Some of them takes tuple with (x, y)
for example: center rectangle on screen
rect_1.center = (display_width//2, display_height//2)
or event using screen
rect_1.center = screen.get_rect().center
OR center text on screen
screen_text_rect = screen_text.get_rect()
screen_text_rect.center = screen.get_rect().center
screen.blit(screen_text, screen_text_rect)
I am remaking snake, I have made everything (with a bit of help from you guys) except to end the game if you touch other parts of your snake.
this is the code so far:
import pygame, sys, random
from pygame.locals import *
pygame.init()
movement_x = movement_y = 0
RED = (240, 0, 0)
GREEN = (0, 255, 0)
GREEN2 = (100, 255, 100)
ran = [0,25,50,75,100,125,150,175,200,225,250,275,300,325,350,375,400,425,450,475]
sizex, sizey = 500, 500
tilesize = 25
screen = pygame.display.set_mode((sizex,sizey))
pygame.display.set_caption('Snake')
tile = pygame.Surface((tilesize, tilesize))
tile = pygame.image.load('images/tile.png')
tile = pygame.transform.scale(tile, (tilesize, tilesize))
snake = pygame.image.load('images/snake.png')
snake = pygame.transform.scale(snake, (tilesize, tilesize))
snake2 = pygame.image.load('images/snake2.png')
snake2 = pygame.transform.scale(snake2, (tilesize, tilesize))
apple = pygame.image.load('images/apple.png')
apple = pygame.transform.scale(apple, (tilesize, tilesize))
x2 = 0
pag = 0
clock = pygame.time.Clock()
sx, sy = 0, 0
vel_x, vel_y = 0, 0
x, y = 0, 0
sa = 0
ap = True
snake_parts = []
def slither( new_head_coord ):
for i in range( len(snake_parts)-1, 0, -1 ):
snake_parts[i] = snake_parts[i-1].copy()
snake_parts[0].topleft = new_head_coord
def drawSnake():
for p in snake_parts:
screen.blit(snake, p.topleft)
snake_parts.append(pygame.Rect(x,y,tilesize,tilesize))
ax, ay = random.choice(ran), random.choice(ran)
run = True
while run:
sx, sy = x, y
for row in range(sizex):
for column in range(sizey):
screen.blit(tile,(column*tilesize, row*tilesize,tilesize,tilesize))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
run = False
if event.type == KEYDOWN:
if event.key == K_UP:
vel_x, vel_y = 0, -25
elif event.key == K_DOWN:
vel_x, vel_y = 0, 25
elif event.key == K_LEFT:
vel_x, vel_y = -25, 0
elif event.key == K_RIGHT:
vel_x, vel_y = 25, 0
elif event.key == K_y:
pag = 1
elif event.key == K_n:
pag = 2
inBounds = pygame.Rect(0, 0, sizex, sizey).collidepoint(x+vel_x, y+vel_y)
if inBounds:
y += vel_y
x += vel_x
else:
pygame.quit()
sys.exit()
slither( (x, y) )
if ap:
screen.blit(apple,(ax,ay))
if x == ax and y == ay:
screen.blit(apple,(ax,ay))
ax, ay = random.choice(ran), random.choice(ran)
sa += 1
snake_parts.append(pygame.Rect(x, y, tilesize, tilesize))
drawSnake()
pygame.display.update()
clock.tick(100)
I want to stop you from going inside your snake. I already have a code that stops you going off the screen. However that wont work for the snake as i dont know how to get the pos of the other snake parts.
Thanks!
Check if the head of the snake intersects any other part of the snake. This can be done by pygame.Rect.colliderect():
def snakeHitSelf():
for i in range(1,len(snake_parts)):
if snake_parts[0].colliderect(snake_parts[i]):
return True
return False
or
def snakeHitSelf():
return any([i for i in range(1,len(snake_parts)) if snake_parts[0].colliderect(snake_parts[i])])
Do the check immediately after the positions of the parts of the snake have been updated (after the call to the function slither):
slither( (x, y) )
hitSelf = snakeHitSelf()
if hitSelf:
pygame.quit()
sys.exit()
I have a pause menu for a game im working on for school. If the user clicks 'p' it launches the pause menu. And the pause menu has a function that if a user clicks a button the user will be launched back into the game. Problem is after they are launched into the game the 'p' function to pause doesn't work anymore. I'm not sure if i looped it correctly.
the pong game
import pygame
black = (0,0,0)
white = (255,255,255)
pygame.init()
size = 800,600
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Basketball Shootout")
done = False
clock = pygame.time.Clock()
def player1(x1, y1, xsize, ysize):
pygame.draw.rect(screen, black, [x1, y1, xsize, ysize])
def player2(x2, y2, xsize, ysize):
pygame.draw.rect(screen, black, [x2,y2,xsize,ysize])
def ball(ballx, bally):
pygame.draw.circle(screen, black, [ballx,bally],20)
def Score1(score1):
font = pygame.font.Font("Minecraft.ttf" ,50)
text = font.render(str(score1), True, white)
screen.blit(text, [160, 550])
def Score2(score2):
font = pygame.font.Font("Minecraft.ttf" ,50)
text = font.render(str(score2), True, white)
screen.blit(text, [610, 550])
x1 = 20
y1 = 175
xsize = 35
ysize = 150
speed1 = 0
x2 = 740
y2 = 175
speed2 = 0
ballx = 550
bally = 250
speedx = 8
speedy = 5
score1 = 0
score2 = 0
bg = pygame.image.load("pongbg2.png")
rect1 = pygame.Rect(50,510,100,50)
def pausescreen():
import pausescreen
display_game = True
game_page = 1
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.draw.rect(screen, (255, 255, 255), rect1)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
speed1 = -10
if event.key == pygame.K_s:
speed1 = 10
if event.key == pygame.K_UP:
speed2 = -10
if event.key == pygame.K_DOWN:
speed2 = 10
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
speed1 = 0
if event.key == pygame.K_s:
speed1 = 0
if event.key == pygame.K_UP:
speed2 = 0
if event.key == pygame.K_DOWN:
speed2 = 0
if event.key == pygame.K_p:
pausescreen()
screen.blit(bg, (0, 0))
player1(x1, y1, xsize, ysize)
player2(x2, y2, xsize, ysize)
ball(ballx,bally)
Score1(score1)
Score2(score2)
y1 += speed1
y2 += speed2
ballx += speedx
bally += speedy
if y1 < 0:
y1 = 0
if y1 > 350:
y1 = 350
if y2 < 0:
y2 = 0
if y2 > 350:
y2 = 350
if ballx+20 > x2 and bally-20 > y2 and bally+20 < y2+ysize and ballx < x2+3:
speedx = -speedx
if ballx-20 < x1+35 and bally-20 > y1 and bally+20 < y1+ysize and ballx > x1+38:
speedx = -speedx
if bally > 477 or bally < 23:
speedy = -speedy
if ballx < 13:
score2 += 1
ballx = 350
bally = 250
if ballx > 750:
score1 += 1
ballx = 350
bally = 250
pygame.display.flip()
clock.tick(60)
pygame.quit()
now here is my pause menu code.
import pygame
import sys
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
pygame.init()
# Set the height and width of the screen
size = [800, 600 ]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Basketball Shootout")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
#Rectangles
rect1 = pygame.Rect(300,300,205,80)
rect2 = pygame.Rect(300,400,205,80)
#Font
font3 = pygame.font.Font("Minecraft.ttf", 40)
def playerpong():
import playerpong
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(BLACK)
pygame.draw.rect(screen, GREEN, rect1)
pygame.draw.rect(screen, RED, rect2)
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if rect1.collidepoint(event.pos):
playerpong()
if rect2.collidepoint(event.pos):
pygame.quit()
clock.tick(60)
pygame.display.update()
pygame.quit()
The problem is that you are importing your pause screen from another program which creates a problem as you can import a library only once. You can try to put your pause screen code in the function instead of calling it but if you insist, you can put your pause_screen code in a function and do a from pausescreen import name_of_function so whenever you need to call that code just write name_of_funtion()