I've been struggling with this problem for a couple days now. I want to eventually convert my snake game script to an exe, for my friends to play. I want the snake to move at the same speed, no matter the size of the window.
For Example: My window size right now is (400, 400). If I increase the size to (800, 800), the snake will move slower. However, the snake velocity is constant at 20 pixels. It almost seems like my main game loop is looping at a slower pace as the window size increases.
I know that the snake has more pixels to traverse with a bigger window size, but how does that affect the snake velocity at all? I'm thinking the solution lies somewhere in the speed at which I'm drawing the snake to the screen, but can't be sure.
import pygame
import sys
import random
import math
import time
pygame.display.set_caption('Snake')
pygame.font.init()
game_running = True
width = 400
height = 400
size = (width, height)
window = pygame.display.set_mode(size) # our surface type
pygame.display.set_caption("Snake Game by Nick Rinaldi")
class Food:
def __init__(self, block_size, surface, x_loc, y_loc): # pass in color and random_x/random_y. block size is a constant
self.block_size = block_size
self.surface = surface # green
self.x_loc = x_loc
self.y_loc = y_loc
self.mask = pygame.mask.from_surface(self.surface)
def draw(self, window):
window.blit(self.surface, (self.x_loc, self.y_loc))
class Snake:
def __init__(self, block_size, surface, x_loc, y_loc):
self.block_size = block_size
self.surface = surface # red
self.x_loc = x_loc
self.y_loc = y_loc
self.body = []
self.direction = None
self.velocity = 20
self.mask = pygame.mask.from_surface(self.surface)
def draw(self, color, window, block_size):
self.seg = []
self.head = pygame.Rect(self.x_loc, self.y_loc, block_size, block_size)
pygame.draw.rect(window, color, self.head)
if len(self.body) > 0:
for unit in self.body:
segment = pygame.Rect(unit[0], unit[1], block_size, block_size)
pygame.draw.rect(window, color, segment)
self.seg.append(segment)
def add_unit(self):
if len(self.body) != 0:
index = len(self.body) - 1
x = self.body[index][0]
y = self.body[index][1]
self.body.append([x, y])
else:
self.body.append([1000, 1000])
def move(self, step):
for index in range(len(self.body) -1, 0, -1):
x = self.body[index-1][0]
y = self.body[index-1][1]
self.body[index] = [x, y]
if len(self.body) > 0:
self.body[0] = [self.x_loc, self.y_loc]
if self.direction == "right": # if specific constant, keep moving in direction
self.x_loc += self.velocity * step
if self.direction == "left":
self.x_loc -= self.velocity * step
if self.direction == "down":
self.y_loc += self.velocity * step
if self.direction == "up":
self.y_loc -= self.velocity * step
def collision(self, obj):
return collide(food)
def gameOver(snake):
white = pygame.Color(255, 255, 255)
display = True
while display:
window.fill(white)
score_font = pygame.font.SysFont("Courier New", 16)
score_label = score_font.render("Your score was: " + str(len(snake.body) + 1), 1, (0, 0, 0))
replay_label = score_font.render("To replay, click the mouse button", 1, (0, 0, 0))
window.blit(score_label, (50, 100))
window.blit(replay_label, (50, 130))
pygame.display.update()
for event in pygame.event.get(): # if we hit "x" to close out the game, close out the game.
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == pygame.MOUSEBUTTONDOWN:
main()
pygame.quit()
sys.exit()
clock = pygame.time.Clock()
def main():
game_over = False
x = 20 # x position
y = 20 # y position
block_snakes = []
pygame.init()
clock = pygame.time.Clock()
red = pygame.Color(255, 0, 0)
green = pygame.Color(0, 255, 0)
white = pygame.Color(255, 255, 255)
black = pygame.Color(0, 0, 0)
block_size = 20
randx_green = random.randrange(0, width, 20)
randy_green = random.randrange(0, height, 20)
randx_red = random.randrange(0, width, 20)
randy_red = random.randrange(0, height, 20)
red_square = pygame.Surface((block_size, block_size))
red_square.fill(red)
green_square = pygame.Surface((block_size, block_size))
green_square.fill(green)
snake = Snake(block_size, red_square, 20, 20) # create snake instance
food = Food(block_size, green_square, randx_green, randy_green) # create food instance
def redraw_window():
draw_grid(window, height, width, white)
while game_running:
dt = clock.tick(30) # time passed between each call
step = dt/1000
print(step)
FPS = 60
window.fill(black)
food.draw(window)
snake.draw(red, window, block_size)
redraw_window()
for event in pygame.event.get(): # if we hit "x" to close out the game, close out the game.
if event.type == pygame.QUIT:
pygame.quit()
exit()
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]: # sets direction attribute as a constant
snake.direction = "right"
if keys[pygame.K_LEFT]:
snake.direction = "left"
if keys[pygame.K_DOWN]:
snake.direction = "down"
if keys[pygame.K_UP]:
snake.direction = "up"
snake.move(step)
collision = collide_food(snake.x_loc, snake.y_loc, food.x_loc, food.y_loc)
if collision:
ac_rand_x = random.randrange(0, width, 20) # after collision, random x
ac_rand_y = random.randrange(0, height, 20) # after collision, random y
# check snake.direction.
food = Food(block_size, green_square, ac_rand_x, ac_rand_y)
food.draw(window)
snake.add_unit()
wall_collide = collide_wall(snake.x_loc, snake.y_loc)
if wall_collide:
gameOver(snake)
# break
for block in snake.body:
if snake.x_loc == block[0] and snake.y_loc == block[1]:
gameOver(snake)
pygame.display.update()
# clock.tick(FPS)
def collide_food(snake_x, snake_y, obj_x, obj_y):
distance = math.sqrt((math.pow(snake_x - obj_x, 2)) + (math.pow(snake_y - obj_y, 2)))
if distance < 20:
return True
else:
return False
def collide_wall(snake_x, snake_y):
if snake_x > width:
game_over = True
return game_over
if snake_y > height:
game_over = True
return game_over
if snake_x < 0:
game_over = True
return game_over
if snake_y < 0:
game_over = True
return game_over
def collide_self(snake_x, snake_y, body_x, body_y):
if (snake_x and snake_y) == (body_x and body_y):
return True
else:
return False
def draw_grid(window, height, width, color):
x = 0
y = 0
grid_blocks = 20
for i in range(height):
x += 20
pygame.draw.line(window, color, (x, 0), (x, height), 1)
for j in range(width):
y += 20
pygame.draw.line(window, color, (0, y), (height, y), 1)
# pygame.display.update()
def display_score():
score_font = pygame.font.SysFont()
def main_menu(width, height):
clock = pygame.time.Clock()
FPS = 60
width = width
height = height
run = True
title_font = pygame.font.SysFont("Courier New", 16)
title_font.set_bold(True)
white = pygame.Color(255, 255, 255)
while run:
window.fill(white)
title_label = title_font.render("Snake Game by Nick Rinaldi ", 1, (0, 0, 0))
sponser_label = title_font.render("Sponsored by @goodproblemsnyc", 1, (0, 0, 0))
window.blit(title_label, ((width/4, height/4)))
window.blit(sponser_label, ((width/4, height/4 + 30)))
pygame.display.update()
for event in pygame.event.get(): # if we hit "x" to close out the game, close out the game.
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == pygame.MOUSEBUTTONDOWN:
main()
pygame.quit()
main_menu(width, height)```