How do I stop my snake moving into itself (python, pygame) - python

this is my first game I have created using pygame, it's basically snake.
Please do not mind my hideous comments.
## William's Snake Game
import pygame
import time
import random
pygame.init()
##Global variables
# Colours
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
green = (0, 155, 0)
bground = (204, 204, 0)
# Display vars.
display_width = 800
display_height = 600
# Variables
gameDisplay = pygame.display.set_mode((display_width, display_height)) ##resolution, note that this is a tuple.
pygame.display.set_caption("Snake VS Apple") # Title at the top of the screen
icon = pygame.image.load('logoapple32x32.png') # Loads the icon for the top left
pygame.display.set_icon(icon) # Sets the icon for the top left
snakeHeadImg = pygame.image.load("snakeHead.png") # Loads the image for the snake head
appleImg = pygame.image.load("apple20x20.png") # Loads the image for the apple
appleThickness = 20 # Defines how thick apple will be. Note to self: This is changable
clock = pygame.time.Clock() # Starts clocking the game, used later for FPS
blockSize = 20 # Defines how big the snake will be. Changing this will mess up collision detection.
FPS = 15 # Frames per second. Called at the bottom of script
smallfont = pygame.font.SysFont("arial", 25) ## format: ("font", fontsize)
medfont = pygame.font.SysFont("arial", 40) ##
largefont = pygame.font.SysFont("arial", 80) ##
direction = "right" # Starting direction of snake, used in main gameLoop
##
def pauseGame():
gameisPaused = True
while gameisPaused:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
gameisPaused = False
elif event.key == pygame.K_q:
pygame.quit()
quit()
gameDisplay.fill(white)
message_to_screen("Paused",
black,
-100,
size="large")
message_to_screen("Press ESC to continue or Q to quit.",
black,
25,
size="small")
pygame.display.update()
clock.tick(5)
def text_objects(text, color, size): # Function to render text
if size == "small":
textSurface = smallfont.render(text, True, color)
elif size == "medium":
textSurface = medfont.render(text, True, color)
elif size == "large":
textSurface = largefont.render(text, True, color)
return textSurface, textSurface.get_rect()
def message_to_screen(msg, color, y_displace=0, size="medium"): # Function to blit (draw) text to surface
textSurf, textRect = text_objects(msg, color, size)
textRect.center = (display_width / 2), (display_height / 2) + y_displace
gameDisplay.blit(textSurf, textRect)
##
def score(score):
text = smallfont.render("Score: " + str(score), True, black)
gameDisplay.blit(text, [0, 0])
def randAppleGen(): # Function to generate random apples
randAppleX = round(
random.randrange(0, display_width - appleThickness)) # /10.0)*10.0 ##Create another rand X value for new apple
randAppleY = round(
random.randrange(0, display_height - appleThickness)) # /10.0)*10.0 ##Create another rand Y value for new apple
return randAppleX, randAppleY
def gameIntro(): # Function for game menu.
intro = True
while intro: # Event handling during menu
for eachEvent in pygame.event.get():
if eachEvent.type == pygame.QUIT:
pygame.quit()
quit()
if eachEvent.type == pygame.KEYDOWN:
if eachEvent.key == pygame.K_c:
gameLoop()
if eachEvent.key == pygame.K_q:
pygame.quit()
quit()
# Text displayed in menu
gameDisplay.fill(white)
message_to_screen("Welcome to Slither",
green,
-90,
"large")
message_to_screen("The more apples you eat, the longer you are",
black,
100)
message_to_screen("The objective of the game is to eat red apples",
black,
0,
"small")
message_to_screen("If you run into yourself, or the edges, you die!",
black,
30,
"small")
message_to_screen("Press C to play or Q to quit.",
black,
180)
pygame.display.update()
clock.tick(500)
def snake(blockSize, snakeList): # Function to draw snake
if direction == "right":
head = pygame.transform.rotate(snakeHeadImg,
270) # In gameLoop, right,left,up,down are used to change direction of snakeHead
elif direction == "left":
head = pygame.transform.rotate(snakeHeadImg, 90)
elif direction == "up":
head = snakeHeadImg
elif direction == "down":
head = pygame.transform.rotate(snakeHeadImg, 180)
gameDisplay.blit(head, (snakeList[-1][0], snakeList[-1][1])) ##???
for XandY in snakeList[:-1]:
pygame.draw.rect(gameDisplay, green,
[XandY[0], XandY[1], blockSize, blockSize]) ##width height, width height, drawing
##Main Game Loop
def gameLoop():
global direction ## Make direction a global var. Important
# Local variables
gameExit = False
gameOver = False
lead_x = display_width / 2
lead_y = display_height / 2
lead_x_change = 10
lead_y_change = 0
snakeList = []
snakeLength = 3
randAppleX, randAppleY = randAppleGen() # Generate apples. Calls randAppleGen()
# Main Game Loop ##eventHandler
while not gameExit:
snakeHead = [] # Creates list snakeHead
snakeHead.append(lead_x) # Appends snakeHead x value to list
snakeHead.append(lead_y) # Appends snakeHead y value to list
snakeList.append(snakeHead) # Appends coordinates of snakeHead x,y to list
while gameOver == True: # Handles game over
gameDisplay.fill(white)
message_to_screen("Game over",
red,
-50,
size="large")
message_to_screen("Press C to play again or Q to quit",
black,
50,
size="medium")
pygame.display.update()
for event in pygame.event.get(): # eventHandler for loss screen
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameExit = True
gameOver = False
if event.key == pygame.K_c:
direction = "right"
gameLoop()
for event in pygame.event.get(): # eventHandler for keyboard events during game
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == pygame.K_a: # Each of these handles either arrow keys or WASD key events.
lead_x_change = -blockSize
lead_y_change = 0
direction = "left"
elif event.key == pygame.K_RIGHT or event.key == pygame.K_d:
lead_x_change = blockSize
lead_y_change = 0
direction = "right"
elif event.key == pygame.K_UP or event.key == pygame.K_w:
lead_y_change = -blockSize
lead_x_change = 0
direction = "up"
elif event.key == pygame.K_DOWN or event.key == pygame.K_s:
lead_y_change = blockSize
lead_x_change = 0
direction = "down"
elif event.key == pygame.K_ESCAPE:
pauseGame()
# Checks if user has hit screen boundaries.
if lead_x >= display_width or lead_x < 0 or lead_y >= display_height or lead_y < 0: # If user hits display boundaries
gameOver = True # They lose
lead_x += lead_x_change # Ensures continous movement of the snake
lead_y += lead_y_change
# Drawing
gameDisplay.fill(bground) # Fills the display background with predefined bground colour (defined at the top)
gameDisplay.blit(appleImg,
(randAppleX, randAppleY)) ##Draws the apple using the appleImg, at random coordinates.
if len(
snakeList) > snakeLength: # If the length of the list of snake body coordinates is greater than the length
del snakeList[0] # Delete the oldest value in the list (as the snake is constantly moving)
for eachSegment in snakeList[:-1]: # For each coordinate in snakeList
if eachSegment == snakeHead: # If the segment touches the snakeHead
## gameDisplay.fill(bground)
## snake(blockSize, snakeList)
##
## pygame.display.update
time.sleep(0.3)
gameOver = True # Game over
snake(blockSize, snakeList) ##Creates snake using function snake
score(snakeLength - 3) # Displays score (it minuses 3 because the snake starts at 3)
pygame.display.update() ##Updates to screen
## COLLISION DETECTION
if lead_x + blockSize > randAppleX and lead_x < randAppleX + appleThickness:
if lead_y + blockSize > randAppleY and lead_y < randAppleY + appleThickness:
randAppleX, randAppleY = randAppleGen()
snakeLength += 1
clock.tick(FPS)
pygame.quit()
quit()
##update screen
##
gameIntro()
gameLoop()
##Code goes above.
I have a problem where if my snake is going right, and then it turns left, my snake will crash onto itself and the game will end.
I want to design this so when my snake is going right, it cannot simply turn left, crash into itself and end the game. So when it turns right, it can only turn up, down, or keep going right. So simply, I want to make it so it cannot run backwards into itself.
I have tried coding this in myself, and I have tried many methods but nothing has worked.
Please help!!

Without altering your code too much (and without testing), an easy way to get what you want is to add another condition to your key checks. If you alter the relevant code section as follows, all should be fine:
for event in pygame.event.get(): # eventHandler for keyboard events during game
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if (event.key == pygame.K_LEFT or event.key == pygame.K_a) and direction != "right": # Each of these handles either arrow keys or WASD key events.
lead_x_change = -blockSize
lead_y_change = 0
direction = "left"
elif (event.key == pygame.K_RIGHT or event.key == pygame.K_d) and direction != "left":
lead_x_change = blockSize
lead_y_change = 0
direction = "right"
elif (event.key == pygame.K_UP or event.key == pygame.K_w) and direction != "down":
lead_y_change = -blockSize
lead_x_change = 0
direction = "up"
elif (event.key == pygame.K_DOWN or event.key == pygame.K_s) and direction != "up":
lead_y_change = blockSize
lead_x_change = 0
direction = "down"
elif event.key == pygame.K_ESCAPE:
pauseGame()
Mind the parentheses around the or'd key checks!

Related

Problems with moving an enemy towards a character in pygame

I am having problems with making a homing algorithm to move an enemy towards a player in a game. For some reason, the algorithm works sometimes, but as you move the player around, the enemy gets to points where it just stops even though there is still a difference between the player x and y variables and the enemy x and y variables (which the code should be applying to the enemy at all times). If you run the code you'll see what I mean.
Here is my code:
import pygame
import sys, os, random
from pygame.locals import *
from pygame import mixer
import math
clock = pygame.time.Clock()
screen_width = 700
screen_height = 700
screen = pygame.display.set_mode((screen_width, screen_height))
player_rect = pygame.Rect(200, 200, 10, 10)
moving_left = False
moving_right = False
moving_down = False
moving_up = False
hunter_rect = pygame.Rect(500, 500, 48, 60)
player_rect.x = 300
player_rect.y = 200
while True:
screen.fill((50, 50, 50))
#screen.blit(player, (player_rect.x, player_rect.y))
#screen.blit(hunter, (hunter_rect.x, hunter_rect.y))
pygame.draw.rect(screen, (255, 255, 255), player_rect)
pygame.draw.rect(screen, (255, 0, 0), hunter_rect)
#### getting the change in y and the change in x from enemy to player ###
ychange = (hunter_rect.y - player_rect.y)/100
xchange = (hunter_rect.x - player_rect.x)/100
hunter_rect.x -= xchange
hunter_rect.y -= ychange
if moving_left:
player_rect.x -= 4
if moving_right:
player_rect.x += 4
if moving_up:
player_rect.y -= 4
if moving_down:
player_rect.y += 4
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
pygame.quit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == K_a:
moving_left = True
if event.key == K_d:
moving_right = True
if event.key == K_s:
moving_down = True
if event.key == K_w:
moving_up = True
if event.type == KEYUP:
if event.key == K_a:
moving_left = False
if event.key == K_d:
moving_right = False
if event.key == K_w:
moving_up = False
if event.key == K_s:
moving_down = False
pygame.display.update()
clock.tick(60)
Since pygame.Rect is supposed to represent an area on the screen, a pygame.Rect object can only store integral data.
The coordinates for Rect objects are all integers. [...]
The fraction part of the movement gets lost when the movement is add to the position of the rectangle.
If you want to store object positions with floating point accuracy, you have to store the location of the object in separate variables and to synchronize the pygame.Rect object. round the coordinates and assign it to the location (e.g. .topleft) of the rectangle:
hunter_rect = pygame.Rect(500, 500, 48, 60)
hunter_x, hunter_y = hunter_rect.topleft
# [...]
while True:
# [...]
hunter_x -= xchange
hunter_y -= ychange
hunter_rect.topleft = round(hunter_x), round(hunter_y)
# [...]

Collision detection between an image and an object in Pygame

Hope you all are having a great day.
I am trying to detect a collision between my object (the black rectangle) and the food image.
What i want to basically do is whenever my rectangle collides with the food image, the food image is then placed randomly on the screen and the score gets increased by +1.
import pygame
import time
import random
pygame.init()
#Colours
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,155,0)
#Game Display
display_width = 800
display_height = 600
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('KALM Creation')
#Directions
DOWN='down'
UP='up'
LEFT='left'
RIGHT='right'
#Score
score=0
# My food image
foodimg=pygame.image.load("food.png")#.convert_alpha()
foodrect = foodimg.get_rect()
foodrect.centerx = 100
foodrect.centery = 200
#Our Icon For The Game
icon=pygame.image.load('icon1.jpg')
pygame.display.set_icon(icon)
#Clock
clock = pygame.time.Clock()
FPS = 30
cellSize=10
#Font Size
smallfont = pygame.font.SysFont("comicsansms", 25)
medfont = pygame.font.SysFont("comicsansms", 50)
largefont = pygame.font.SysFont("comicsansms", 80)
#The score function - displays the score on top right
def scoredisplay(scoredef=0):
text=smallfont.render("Score :%s" %(scoredef) ,True ,black)
gameDisplay.blit(text,[0,0])
#Starting Of the game
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key ==pygame.K_c:
intro = False
if event.key ==pygame.K_q:
pygame.quit()
quit()
gameDisplay.fill(white)
#Game Initial display message
message_to_screen("Welcome To Eat it Game",
green,
-200,
size="medium")
message_to_screen("Press 'C' to play the game or 'Q' to quit.",
black,
150,
size="small")
pygame.display.update()
clock.tick(15)
#Text Size
def text_objects(text,color, size):
if size=="small":
textSurface=smallfont.render(text, True ,color)
elif size=="medium":
textSurface=medfont.render(text, True ,color)
elif size=="large":
textSurface=largefont.render(text, True ,color)
return textSurface,textSurface.get_rect()
#Message to screen
def message_to_screen(msg,color,y_displace=0,size="small"):
textSurf,textRect=text_objects(msg,color,size)
textRect.center = (display_width / 2),(display_height / 2)+y_displace
gameDisplay.blit(textSurf,textRect)
#Drawing Cells
def drawCell(coords,ccolor):
for coord in coords:
x=coord['x']*cellSize
y=coord['y']*cellSize
makeCell=pygame.Rect(x,y,cellSize,cellSize)
pygame.draw.rect(gameDisplay,ccolor,makeCell)
#The Game run up
def runGame():
score=0
gameExit = False
gameOver = False
#Starting Position of the object
startx=3
starty=3
coords=[{'x':startx,'y':starty}]
direction = RIGHT
while not gameExit:
while gameOver == True:
#Game Over message
gameDisplay.fill(white)
message_to_screen("Game over",
red,
y_displace=-50,
size="large")
message_to_screen("Press C to play again or Q to quit",
black,
y_displace=50,
size="medium")
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()
#Game Controls
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
direction = LEFT
elif event.key == pygame.K_RIGHT:
direction = RIGHT
elif event.key == pygame.K_UP:
direction = UP
elif event.key == pygame.K_DOWN:
direction = DOWN
if direction == UP:
newCell={'x':coords[0]['x'],'y':coords[0]['y']-1}
elif direction == DOWN:
newCell={'x':coords[0]['x'],'y':coords[0]['y']+1}
elif direction == LEFT:
newCell={'x':coords[0]['x']-1,'y':coords[0]['y']}
elif direction == RIGHT:
newCell={'x':coords[0]['x']+1,'y':coords[0]['y']}
del coords[-1]
coords.insert(0, newCell)
gameDisplay.fill(white)
drawCell(coords,black)
clock.tick(FPS)
#If object moves outside the screen , game gets over.
if(newCell['x']<0 or newCell['y']<0 or newCell['x']>display_width/cellSize or newCell['y']>display_height):
gameOver= True
#Displays Score
scoredisplay(score)
gameDisplay.blit(foodimg,foodrect)
#pygame.display.flip()
pygame.display.update()
#The game run up
def gameLoop():
clock.tick(FPS)
runGame()
pygame.quit()
quit()
game_intro()
gameLoop()
In the drawcell() call:
if makecell.colliderect(foodrect):
foodrect.x = random.randint(0, sceeenwidth)
foodrect.y = random.randint(0, screenheight)
Should do it.

How do implement classes into my Nibbles remake?

So I made a Nibbles/Snake remake by following the pygame tutorials on thenewboston youtube channel by sentdex. I made a lot of minor aesthetic changes, but overall, it's the same game. Here's the code for that:
import pygame
import time
import random
pygame.init()
# A few extra colors just for testing purposes.
WHITE = (pygame.Color("white"))
BLACK = ( 0, 0, 0)
RED = (245, 0, 0)
TURQ = (pygame.Color("turquoise"))
GREEN = ( 0, 155, 0)
GREY = ( 90, 90, 90)
SCREEN = (800, 600)
gameDisplay = pygame.display.set_mode(SCREEN)
#Set the window title and picture
pygame.display.set_caption('Slither')
ICON = pygame.image.load("apple10pix.png")
pygame.display.set_icon(ICON)
CLOCK = pygame.time.Clock()
FPS = 20
FONT = pygame.font.SysFont("arial", 25)
SNAKE_SIZE = 10 # The width of the snake in pixels, not the length. Start length is defined in the game loop.
APPLE_SIZE = 10
TINY_FONT = pygame.font.SysFont("candara", 15)
SMALL_FONT = pygame.font.SysFont("candara", 25)
MED_FONT = pygame.font.SysFont("candara", 50)
LARGE_FONT = pygame.font.SysFont("krabbypatty", 75)
HUGE_FONT = pygame.font.SysFont("krabbypatty", 150)
IMG = pygame.image.load("snakehead.png")
APPLE_IMG = pygame.image.load("apple10pix.png")
DIRECTION = "up"
def pause():
paused = True
message_to_screen("Paused",
BLACK,
Y_DISPLACE = -100,
size = "huge")
message_to_screen("Press C to continue or Q to quit.",
BLACK,
Y_DISPLACE = 25)
pygame.display.update()
while paused:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key in (pygame.K_c, pygame.K_p):
paused = False
elif event.key in(pygame.K_q, pygame.K_ESCAPE):
pygame.quit()
quit()
CLOCK.tick(5)
def score(score):
text = SMALL_FONT.render("Score: " + str(score), True, BLACK)
gameDisplay.blit(text, [0, 0])
pygame.display.update
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
intro = False
if event.key in (pygame.K_q, pygame.K_ESCAPE):
pygame.quit()
quit()
gameDisplay.fill(WHITE)
message_to_screen("Welcome to",
GREEN,
Y_DISPLACE = -170,
size = "large")
message_to_screen("Block Worm",
GREEN,
Y_DISPLACE = -50,
size = "huge")
message_to_screen("The objective of the game is to eat apples.",
BLACK,
Y_DISPLACE = 36,
size = "tiny")
message_to_screen("The more apples you eat the longer you get.",
BLACK,
Y_DISPLACE = 68,
size = "tiny")
message_to_screen("If you run into yourself or the edges, you die.",
BLACK,
Y_DISPLACE = 100,
size = "tiny")
message_to_screen("Press C to play or Q to quit.",
GREY,
Y_DISPLACE = 210,)
pygame.display.update()
CLOCK.tick(FPS)
def snake(SNAKE_SIZE, SNAKE_LIST):
if DIRECTION == "right":
HEAD = pygame.transform.rotate(IMG, 270)
elif DIRECTION == "left":
HEAD = pygame.transform.rotate(IMG, 90)
elif DIRECTION == "down":
HEAD = pygame.transform.rotate(IMG, 180)
else:
DIRECTION == "up"
HEAD = IMG
gameDisplay.blit(HEAD, (SNAKE_LIST[-1][0], SNAKE_LIST[-1][1]))
for XnY in SNAKE_LIST[:-1]:
pygame.draw.rect(gameDisplay, GREEN, [XnY[0], XnY[1], SNAKE_SIZE, SNAKE_SIZE])
pygame.display.update
def text_objects(text, color, size):
if size == "tiny":
TEXT_SURFACE = TINY_FONT.render(text, True, color)
elif size == "small":
TEXT_SURFACE = SMALL_FONT.render(text, True, color)
elif size == "medium":
TEXT_SURFACE = MED_FONT.render(text, True, color)
elif size == "large":
TEXT_SURFACE = LARGE_FONT.render(text, True, color)
elif size == "huge":
TEXT_SURFACE = HUGE_FONT.render(text, True, color)
return TEXT_SURFACE, TEXT_SURFACE.get_rect()
def message_to_screen(msg, color, Y_DISPLACE = 0, size = "small"):
TEXT_SURF, TEXT_RECT = text_objects(msg, color, size)
TEXT_RECT.center = (SCREEN[0] / 2), (SCREEN[1] / 2) + Y_DISPLACE
gameDisplay.blit(TEXT_SURF, TEXT_RECT)
def randAppleGen():
randAppleX = random.randrange(0, (SCREEN[0] - APPLE_SIZE), APPLE_SIZE)
randAppleY = random.randrange(0, (SCREEN[1]- APPLE_SIZE), APPLE_SIZE)
return randAppleX, randAppleY
def gameLoop():
global DIRECTION
gameExit = False
gameOver = False
SNAKE_LIST = [] # Where the snake head has been.
SNAKE_LENGTH = 1 #Length that the snake starts.
lead_x = (SCREEN[0] / 2)
lead_y = (SCREEN[1] - (SCREEN[1] / 5))
move_speed = 10
move_speed_neg = move_speed * -1
lead_x_change = 0
lead_y_change = -move_speed
randAppleX, randAppleY = randAppleGen()
while not gameExit:
if gameOver == True:
message_to_screen("Game over",
RED,
Y_DISPLACE = -50,
size = "huge")
message_to_screen("Press C to play again or Q to quit.",
BLACK,
Y_DISPLACE = 50,
size = "small")
pygame.display.update()
while gameOver == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
gameOver = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameOver = False
gameExit = True
elif event.key == pygame.K_c:
gameLoop()
# Handles arrow key and WASD events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
elif event.type == pygame.KEYDOWN:
if event.key in (pygame.K_LEFT, pygame.K_a):
lead_x_change = move_speed_neg
lead_y_change = 0
DIRECTION = "left"
elif event.key in (pygame.K_RIGHT, pygame.K_d):
lead_x_change = move_speed
lead_y_change = 0
DIRECTION = "right"
elif event.key in (pygame.K_UP, pygame.K_w):
lead_y_change = move_speed_neg
lead_x_change = 0
DIRECTION = "up"
elif event.key in (pygame.K_DOWN, pygame.K_s):
lead_y_change = move_speed
lead_x_change = 0
DIRECTION = "down"
elif event.key in (pygame.K_p, pygame.K_ESCAPE):
pause()
# If the snake goes beyond the screen borders the game will end.
if lead_x >= SCREEN[0] or lead_x < 0 or lead_y >= SCREEN[1] or lead_y <0:
gameOver = True
lead_x += lead_x_change
lead_y += lead_y_change
gameDisplay.fill(WHITE)
# Draw the apple on screen
APPLE_RECT = pygame.draw.rect(gameDisplay, RED, [randAppleX, randAppleY, APPLE_SIZE, APPLE_SIZE])
if APPLE_RECT in SNAKE_LIST:
APPLE_RECT #If the apple appears anywhere "under" the snake, it will immediately respawn elsewhere.
# Draw the snake on screen
SNAKE_HEAD = []
SNAKE_HEAD.append(lead_x)
SNAKE_HEAD.append(lead_y)
SNAKE_LIST.append(SNAKE_HEAD)
# If you hit yourself, game over.
if SNAKE_HEAD in SNAKE_LIST[:-1]:
gameOver = True
if len(SNAKE_LIST) > SNAKE_LENGTH:
del SNAKE_LIST[0]
snake(SNAKE_SIZE, SNAKE_LIST)
score(SNAKE_LENGTH - 1)
# If the snake eats the apple
if APPLE_RECT.collidepoint(lead_x, lead_y) == True:
randAppleX, randAppleY = randAppleGen()
SNAKE_LENGTH += 1
pygame.display.update()
CLOCK.tick(FPS)
pygame.quit()
quit()
game_intro()
gameLoop()
It's a pretty solid little game. But I want to make the snake and apple into classes so that I can later spawn other types of snakes (perhaps basic AI?) and other types of apples (maybe ones that are green that grow your snake 3+). I made an attempt at doing this myself with a snake class:
import pygame
import time
import random
pygame.init()
WHITE = (pygame.Color("white"))
BLACK = ( 0, 0, 0)
RED = (245, 0, 0)
TURQ = (pygame.Color("turquoise"))
GREEN = ( 0, 155, 0)
GREY = ( 90, 90, 90)
SCREEN = (800, 600)
gameDisplay = pygame.display.set_mode(SCREEN)
#Set the window title and picture
pygame.display.set_caption('Block Worm')
ICON = pygame.image.load("apple10pix.png")
pygame.display.set_icon(ICON)
CLOCK = pygame.time.Clock()
FPS = 20
FONT = pygame.font.SysFont("arial", 25)
APPLE_SIZE = 10
TINY_FONT = pygame.font.SysFont("candara", 15)
SMALL_FONT = pygame.font.SysFont("candara", 25)
MED_FONT = pygame.font.SysFont("candara", 50)
LARGE_FONT = pygame.font.SysFont("krabbypatty", 75)
HUGE_FONT = pygame.font.SysFont("krabbypatty", 150)
IMG = pygame.image.load("snakehead.png")
APPLE_IMG = pygame.image.load("apple10pix.png")
def pause():
paused = True
message_to_screen("Paused",
BLACK,
Y_DISPLACE = -100,
size = "huge")
message_to_screen("Press C to continue or Q to quit.",
BLACK,
Y_DISPLACE = 25)
pygame.display.update()
while paused:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key in (pygame.K_c, pygame.K_p):
paused = False
elif event.key in(pygame.K_q, pygame.K_ESCAPE):
pygame.quit()
quit()
CLOCK.tick(5)
def score(score):
text = SMALL_FONT.render("Score: " + str(score), True, BLACK)
gameDisplay.blit(text, [5, 5])
pygame.display.update
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
intro = False
if event.key in (pygame.K_q, pygame.K_ESCAPE):
pygame.quit()
quit()
gameDisplay.fill(WHITE)
message_to_screen("Welcome to",
GREEN,
Y_DISPLACE = -170,
size = "large")
message_to_screen("Block Worm",
GREEN,
Y_DISPLACE = -50,
size = "huge")
message_to_screen("The objective of the game is to eat apples.",
BLACK,
Y_DISPLACE = 36,
size = "tiny")
message_to_screen("The more apples you eat the longer you get.",
BLACK,
Y_DISPLACE = 68,
size = "tiny")
message_to_screen("If you run into yourself or the edges, you die.",
BLACK,
Y_DISPLACE = 100,
size = "tiny")
message_to_screen("Press C to play or Q to quit.",
GREY,
Y_DISPLACE = 210,)
pygame.display.update()
CLOCK.tick(FPS)
def text_objects(text, color, size):
if size == "tiny":
TEXT_SURFACE = TINY_FONT.render(text, True, color)
elif size == "small":
TEXT_SURFACE = SMALL_FONT.render(text, True, color)
elif size == "medium":
TEXT_SURFACE = MED_FONT.render(text, True, color)
elif size == "large":
TEXT_SURFACE = LARGE_FONT.render(text, True, color)
elif size == "huge":
TEXT_SURFACE = HUGE_FONT.render(text, True, color)
return TEXT_SURFACE, TEXT_SURFACE.get_rect()
def message_to_screen(msg, color, Y_DISPLACE = 0, size = "small"):
TEXT_SURF, TEXT_RECT = text_objects(msg, color, size)
TEXT_RECT.center = (SCREEN[0] / 2), (SCREEN[1] / 2) + Y_DISPLACE
gameDisplay.blit(TEXT_SURF, TEXT_RECT)
def randAppleGen():
randAppleX = random.randrange(0, (SCREEN[0] - APPLE_SIZE), APPLE_SIZE)
randAppleY = random.randrange(0, (SCREEN[1]- APPLE_SIZE), APPLE_SIZE)
return randAppleX, randAppleY
class Snake:
def __init__(self, image, x, y, direction, speed):
self.image = image
self.rect = self.image.get_rect()
self.width = self.rect.width
self.rect.x = x
self.rect.y = y
self.direction = direction
self.speed = speed
self.trail = [] # Where the snake head has been.
self.length = 1 # Length that the snake starts.
def snake_direction_change(direction):
if direction == "right":
self.image = pygame.transform.rotate(self.image, 270)
elif direction == "left":
self.image = pygame.transform.rotate(self.image, 90)
elif direction == "down":
self.image = pygame.transform.rotate(self.image, 180)
else:
direction == "up"
pygame.display.update
def snake_grow(x, y, z):
gameDisplay.blit(self.image, (self.trail[-1][0], self.trail[-1][1]))
for XnY in snake.trail[:-1]:
pygame.draw.rect(gameDisplay, GREEN, [XnY[0], XnY[1], self.width, self.width])
pygame.display.update
def gameLoop():
gameExit = False
gameOver = False
lead_x_change = 0
lead_y_change = -snake.speed
randAppleX, randAppleY = randAppleGen()
gameDisplay.fill(WHITE)
snake = Snake(IMG,
x = (SCREEN[0] / 2),
y =(SCREEN[1] - (SCREEN[1] / 5)),
direction = "up",
speed = 10,)
while not gameExit:
if gameOver == True:
message_to_screen("Game over",
RED,
Y_DISPLACE = -50,
size = "huge")
message_to_screen("Press C to play again or Q to quit.",
BLACK,
Y_DISPLACE = 50,
size = "small")
pygame.display.update()
while gameOver == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
gameOver = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameOver = False
gameExit = True
elif event.key == pygame.K_c:
gameLoop()
# Handles arrow key and WASD events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
elif event.type == pygame.KEYDOWN:
if event.key in (pygame.K_LEFT, pygame.K_a):
lead_x_change = snake.speed * -1
lead_y_change = 0
snake.snake_direction_change("left")
elif event.key in (pygame.K_RIGHT, pygame.K_d):
lead_x_change = snake.speed
lead_y_change = 0
snake.snake_direction_change("right")
elif event.key in (pygame.K_UP, pygame.K_w):
lead_y_change = snake.speed * -1
lead_x_change = 0
snake.snake_direction_change("up")
elif event.key in (pygame.K_DOWN, pygame.K_s):
lead_y_change = snake.speed
lead_x_change = 0
snake.snake_direction_change("down")
elif event.key in (pygame.K_p, pygame.K_ESCAPE):
pause()
# If the snake goes beyond the screen borders the game will end.
if snake.rect.x >= SCREEN[0] or snake.rect.x < 0 or snake.rect.y >= SCREEN[1] or snake.rect.y <0:
gameOver = True
snake.rect.x += lead_x_change
snake.rect.y += lead_y_change
gameDisplay.fill(WHITE)
# Draw the apple on screen
APPLE_RECT = pygame.draw.rect(gameDisplay, RED, [randAppleX, randAppleY, APPLE_SIZE, APPLE_SIZE])
if APPLE_RECT in snake.trail:
APPLE_RECT #If the apple appears anywhere "under" the snake, it will immediately respawn elsewhere.
# Draw the snake on screen
SNAKE_HEAD = []
SNAKE_HEAD.append(snake.rect.x)
SNAKE_HEAD.append(snake.rect.y)
snake.trail.append(SNAKE_HEAD)
# If you hit yourself, game over.
if SNAKE_HEAD in snake.trail[:-1]:
gameOver = True
if len(snake.trail) > snake.length:
del snake.trail[0]
snake.snake_grow(snake.width, snake.trail)
score(snake.length - 1)
# If the snake eats the apple
if APPLE_RECT.collidepoint(snake.rect.x, snake.rect.y) == True:
randAppleX, randAppleY = randAppleGen()
snake.length += 1
pygame.display.update()
CLOCK.tick(FPS)
pygame.quit()
quit()
game_intro()
gameLoop()
This version isn't nearly as cute. In fact, it doesn't work at all. My understanding off classes and functions is elementary at best. A lot of code from the original was changed or completely deleted in my trial and error processes. I spent several hours trying to make this work to no avail. My main goal was to produce a Snake and Apple class that can be reused for later variations of both of them.
So, I've come to you fine folks to assist me! I have two main questions:
1) What do I have to do to make this work properly?
2) How can I clean up my code to make it easier to read and more efficient overall?
"A lot of code from the original was changed or completely deleted in my trial and error processes"
Bingo. You just found the crux of your issue. Software development should be a controlled, thought out process - not trial and error. You need to proceed thoughtfully, and purposefully.
What you are trying to do (or should be trying to do) when introducing classes is refactoring your code.
You should start again with the original, working copy, and proceed to change as little as possible when you introduce a Snake class. The first step would be to simply convert your snake function into a class, and substitute that in. Below is where you might start: replace your snake method with this Snake class, and change the line where you use it
class Snake:
def __init__(self, SNAKE_SIZE, SNAKE_LIST):
if DIRECTION == "right":
HEAD = pygame.transform.rotate(IMG, 270)
elif DIRECTION == "left":
HEAD = pygame.transform.rotate(IMG, 90)
elif DIRECTION == "down":
HEAD = pygame.transform.rotate(IMG, 180)
else:
DIRECTION == "up" # note: this line does nothing
HEAD = IMG
gameDisplay.blit(HEAD, (SNAKE_LIST[-1][0], SNAKE_LIST[-1][1]))
for XnY in SNAKE_LIST[:-1]:
pygame.draw.rect(gameDisplay, GREEN, [XnY[0], XnY[1], SNAKE_SIZE, SNAKE_SIZE])
pygame.display.update # note: this likely does nothing - I think you want to call it (pygame.display.update())
and change this:
snake(SNAKE_SIZE, SNAKE_LIST)
into:
snake = Snake(SNAKE_SIZE, SNAKE_LIST)
Now at this point, if your code worked before, it should still work (assuming I haven't done anything silly). Is this a good example of a class? No. My Snake class is terrible. Your attempt at a snake class is far, far better. Doing things this way gives you a starting point though. You can then proceed to do things like:
assign the parameters to instance variables
move pretty much all the code into another method
start removing the module-level variables it has access to, and pass in additional arguments
etc.
An alternate way to refactor this module might be to change each of your functions so that none of them rely on module level variables. Pass every variable that each function needs into that function.
The main point I'd like to leave you with is that it is far easier to make working software by writing/changing just a little at a time. Make sure it still works before changing something else. Work on small bits of code & test each change so you'll know exactly where and how your program broke.

adding boulders to pygame snake in python

i have a snake game i made in python and i want to add him boulders that will appear every 10 "apples" he gets, so can you help me please? this is the code right now
import pygame
import random
__author__ = 'Kfir_Kahanov'
init = pygame.init()
def quit_game():
"""
this function will quit the game
:return:
"""
pygame.quit()
quit()
# this will set a nice sound when the player gets an apple
BLOP = pygame.mixer.Sound("Blop.wav")
pygame.mixer.Sound.set_volume(BLOP, 1.0)
volume = pygame.mixer.Sound.get_volume(BLOP)
# making colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 155, 0)
BLUE = (0, 0, 255)
YELLOW = (217, 217, 0)
SNAKE_RED = (152, 2, 2)
def display_fill():
"""
this will fill the screen with a color of my choice
:return:
"""
game_display.fill(GREEN)
def mute():
"""
this will mute the game or unmute it
:return:
"""
if volume == 1.0:
pygame.mixer.Sound.set_volume(BLOP, 0.0)
else:
pygame.mixer.Sound.set_volume(BLOP, 10.0)
# all the pygame stuff for the display
DISPLAY_WIDTH = 800
DISPLAY_HEIGHT = 600
game_display = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
pygame.display.set_caption("The hungry Cobra")
ICON = pygame.image.load("apple_icon.png")
pygame.display.set_icon(ICON)
pygame.display.update()
# deciding on FPS, the size of the snake, apples, and making the fonts for the text
CLOCK = pygame.time.Clock()
BLOCK_SIZE = 20
APPLE_THICKNESS = 30
fps = 15
# BOULDER_THICKNESS = 30
direction = "right" # deciding the starting direction
tiny_font = pygame.font.SysFont("comicsansms", 10)
small_font = pygame.font.SysFont("comicsansms", 25)
med_font = pygame.font.SysFont("comicsansms", 50)
large_font = pygame.font.SysFont("comicsansms", 80)
def text_objects(text, color, size):
"""
defining the text
:param text:
:param color:
:param size:
:return:
"""
global text_surface
if size == "tiny":
text_surface = tiny_font.render(text, True, color)
if size == "small":
text_surface = small_font.render(text, True, color)
if size == "medium":
text_surface = med_font.render(text, True, color)
if size == "large":
text_surface = large_font.render(text, True, color)
return text_surface, text_surface.get_rect()
# loading apple and snake img
IMG = pygame.image.load("snake_head.png")
APPLE_IMG = pygame.image.load("apple_icon.png")
# BOULDER_IMG = pygame.image.load("boulder.png")
def rand_apple_gen():
"""
making apple function
:return:
"""
rand_apple_x = round(random.randrange(10, DISPLAY_WIDTH - APPLE_THICKNESS)) # / 10.0 * 10.0
rand_apple_y = round(random.randrange(10, DISPLAY_HEIGHT - APPLE_THICKNESS)) # / 10.0 * 10.0
return rand_apple_x, rand_apple_y
"""
def rand_boulder_gen():
making the boulder parameters
:return:
rand_boulder_x = round(random.randrange(10, DISPLAY_WIDTH - BOULDER_THICKNESS))
rand_boulder_y = round(random.randrange(10, DISPLAY_WIDTH - BOULDER_THICKNESS))
return rand_boulder_x, rand_boulder_y
"""
def message(msg, color, y_displace=0, size="small"):
"""
making a function for the making of the text
:param msg:
:param color:
:param y_displace:
:param size:
:return:
"""
text_surf, text_rect = text_objects(msg, color, size)
text_rect.center = ((DISPLAY_WIDTH / 2), (DISPLAY_HEIGHT / 2) + y_displace)
game_display.blit(text_surf, text_rect)
def intro_message():
"""
making the intro
:return:
"""
intro = True
while intro:
display_fill()
message("Welcome to ", BLACK, -200, "large")
message("The hungry Cobra!", BLACK, -100, "large")
message("Eat apples to grow, but be care full", BLACK)
message("if you run into yourself or outside the screen", BLACK, 30)
message("you gonna have a bad time", BLACK, 60)
message("Press S to start or E to exit", BLACK, 90)
message("Created by Kfir Kahanov", BLACK, 200, "tiny")
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
display_fill()
pygame.display.update()
quit_game()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_m:
mute()
if event.key == pygame.K_s:
intro = False
if event.key == pygame.K_e:
display_fill()
pygame.display.update()
quit_game()
score_edit = 0
def score_f(score):
"""
making a score_f on the top left
:param score:
:return:
"""
text = small_font.render("Score:" + str(score + score_edit), True, YELLOW)
game_display.blit(text, [0, 0])
def pause_f():
"""
making a pause_f screen
:return:
"""
pause = True
if pause:
message("Paused", RED, -50, "large")
message("Press R to start over, E to exit or C to continue", BLACK)
pygame.display.update()
while pause:
for event in pygame.event.get():
if event.type == pygame.QUIT:
display_fill()
pygame.display.update()
quit_game()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_m:
mute()
if event.key == pygame.K_c or pygame.K_ESCAPE or pygame.K_p:
pause = False
if event.key == pygame.K_r:
global score_edit, direction, cheat1, cheat4, cheat3, cheat2
direction = "right"
score_edit = 0
cheat1 = 16
cheat2 = 16
cheat3 = 16
cheat4 = 16
game_loop()
if event.key == pygame.K_e:
display_fill()
pygame.display.update()
quit_game()
CLOCK.tick(5)
# making cheats
cheat1 = 16
cheat2 = 16
cheat3 = 16
cheat4 = 16
def snake(snake_list):
"""
defining the snake head
:param snake_list:
:return:
"""
global head
if direction == "right":
head = pygame.transform.rotate(IMG, 270)
elif direction == "left":
head = pygame.transform.rotate(IMG, 90)
elif direction == "down":
head = pygame.transform.rotate(IMG, 180)
elif direction == "up":
head = IMG
game_display.blit(head, (snake_list[-1][0], snake_list[-1][1]))
for x_n_y in snake_list[:-1]:
pygame.draw.rect(game_display, SNAKE_RED, [x_n_y[0], x_n_y[1], BLOCK_SIZE, BLOCK_SIZE])
def game_loop():
"""
this will be the game itself
:return:
"""
global cheat1
global cheat2
global cheat3
global cheat4
global direction
global fps
game_exit = False
game_over = False
global score_edit
lead_x = DISPLAY_WIDTH / 2
lead_y = DISPLAY_HEIGHT / 2
# rand_boulder_x, rand_boulder_y = -50, -50
lead_x_change = 10
lead_y_change = 0
snake_list = []
snake_length = 1
rand_apple_x, rand_apple_y = rand_apple_gen()
while not game_exit:
if game_over:
message("Game over!", RED, -50, "large")
message("Press E to exit or R to retry.", BLACK, 20, "medium")
pygame.display.update()
while game_over:
fps = 15
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_exit = True
game_over = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_m:
mute()
if event.key == pygame.K_e:
game_exit = True
game_over = False
if event.key == pygame.K_r:
direction = "right"
score_edit = 0
cheat1 = 16
cheat2 = 16
cheat3 = 16
cheat4 = 16
game_loop()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_exit = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_m:
mute()
if event.key == pygame.K_LEFT and lead_x_change is not BLOCK_SIZE and direction is not "right":
lead_x_change = -BLOCK_SIZE
lead_y_change = 0
direction = "left"
elif event.key == pygame.K_RIGHT and lead_x_change is not -BLOCK_SIZE and direction is not "left":
lead_x_change = BLOCK_SIZE
lead_y_change = 0
direction = "right"
elif event.key == pygame.K_UP and lead_y_change is not BLOCK_SIZE and direction is not "down":
lead_y_change = -BLOCK_SIZE
lead_x_change = 0
direction = "up"
elif event.key == pygame.K_DOWN and lead_y_change is not -BLOCK_SIZE and direction is not "up":
lead_y_change = BLOCK_SIZE
lead_x_change = 0
direction = "down"
elif event.key == pygame.K_p:
pause_f()
elif event.key == pygame.K_ESCAPE:
pause_f()
elif event.key == pygame.K_k: # the cheat
cheat1 = 0
elif event.key == pygame.K_f:
cheat2 = 4
elif event.key == pygame.K_i:
cheat3 = 0
elif event.key == pygame.K_r:
cheat4 = 3
elif cheat1 == 0 and cheat2 == 4 and cheat3 == 0 and cheat4 == 3:
score_edit = 10000
if lead_x >= DISPLAY_WIDTH or lead_x < 0 or lead_y >= DISPLAY_HEIGHT or lead_y < 0:
game_over = True
lead_x += lead_x_change
lead_y += lead_y_change
display_fill()
game_display.blit(APPLE_IMG, (rand_apple_x, rand_apple_y))
snake_head = [lead_x, lead_y]
snake_list.append(snake_head)
if len(snake_list) > snake_length:
del snake_list[0]
for eachSegment in snake_list[:-1]:
if eachSegment == snake_head:
game_over = True
snake(snake_list)
score_f(snake_length * 10 - 10)
pygame.display.update()
if rand_apple_x < lead_x < rand_apple_x + APPLE_THICKNESS or rand_apple_x < lead_x + BLOCK_SIZE < rand_apple_x \
+ APPLE_THICKNESS:
if rand_apple_y < lead_y < rand_apple_y + APPLE_THICKNESS or rand_apple_y < lead_y + BLOCK_SIZE < \
rand_apple_y + APPLE_THICKNESS:
pygame.mixer.Sound.play(BLOP)
rand_apple_x, rand_apple_y = rand_apple_gen()
snake_length += 1
fps += 0.15
"""
if snake_length * 10 - 10 == 20:
rand_boulder_x, rand_boulder_y = rand_boulder_gen()
game_display.blit(BOULDER_IMG, (rand_boulder_x, rand_boulder_y))
elif rand_boulder_x < lead_x < rand_boulder_y + BOULDER_THICKNESS or rand_boulder_x < lead_x + BLOCK_SIZE < \
rand_boulder_x + BOULDER_THICKNESS:
if rand_boulder_x < lead_y < rand_boulder_y + BOULDER_THICKNESS or rand_boulder_y < lead_y + BLOCK_SIZE < \
rand_boulder_y + BOULDER_THICKNESS:
game_over = True
"""
CLOCK.tick(fps)
display_fill()
pygame.display.update()
quit_game()
intro_message()
game_loop()
Maybe try explaining what you have tried and why it isn't working. You would get better help that way.
From what I can see from your code though....
You seem to be on the right track in your commented out code. Evaluating the snake length or score variable during your game loop, then generating a random boulder to the screen. The next step is just handling the collision logic for all the boulders, which I see two ways of doing. First way is creating a lists of the boulder attributes like the x,y positions, similar to how you did the snake list. The second way would be to create a class for boulders, then when the score, or snake length, reaches 10, create a new boulder object. Using a class may make the collision logic much easier to handle.

Pygame Index Out of Range

I am building an asteroids-like game with python, but I'm running into trouble with keeping within the range of my possibleTurrets array. All I'm doing is iterating through the array, and when the edge cases outside of the array occur, I deal with them through:
if currentTurPos > 8:
currentTurPos = 8
elif currentTurPos < 0:
currenTurPos = 0
This is in reference to this array:
possibleTurrets = [ (x-27,y-2),
(x-26,y-5),
(x-25,y-8),
(x-23,y-12),
(x-20,y-14),
(x-18,y-15),
(x-15,y-17),
(x-13,y-19),
(x-11,y-21)
]
For some reason this code works fine on pygame.K_UP but not on pygame.K_DOWN and I have no idea why.
This seems like it should be really obvious, but I've spent an hour trying to fix it, and am drawing a blank. The issue is with my ufo function, and the currentTurPos variable.
# Libraries
import pygame
import time
import random
import os
# Initialize Pygame
pygame.init()
# Colors
white = (255,255,255)
black = (0,0,0)
red = (200,0,0)
blue = (0,0,255)
green = (34,177,76)
light_green = (0,255,0)
yellow = (200,200,0)
light_yellow = (255,255,0)
light_red = (255,0,0)
# Display
display_width = 800
display_height = 600
gameDisplay = pygame.display.set_mode((display_width,display_height))
#pygame.display.set_caption('Slither')
#icon = pygame.image.load('apple.bmp')
#pygame.display.set_icon(icon)
clock = pygame.time.Clock()
# Sprites
ufoWidth = 40
ufoHeight = 20
turretWidth = 5
turretHeight = 10
fps = 15 # Speed
# Fonts
smallFont = pygame.font.SysFont("comicsansms", 25)
medFont = pygame.font.SysFont("comicsansms", 50)
largeFont = pygame.font.SysFont("comicsansms", 80)
def ufo(x,y,turPos):
x = int(x)
y = int(y)
possibleTurrets = [ (x-27,y-2),
(x-26,y-5),
(x-25,y-8),
(x-23,y-12),
(x-20,y-14),
(x-18,y-15),
(x-15,y-17),
(x-13,y-19),
(x-11,y-21)
]
pygame.draw.circle(gameDisplay, blue, (x,y),int(ufoHeight/2))
pygame.draw.ellipse(gameDisplay, black, (x-ufoHeight, y, ufoWidth, ufoHeight))
pygame.draw.line(gameDisplay,blue,(x,y),possibleTurrets[turPos],turretWidth)
# Font sizes
def text_objects(text, color, size):
if size == "small":
textSurface = smallFont.render(text, True, color)
elif size == "medium":
textSurface = medFont.render(text, True, color)
elif size == "large":
textSurface = largeFont.render(text, True, color)
return textSurface, textSurface.get_rect()
# Displays a message: Requires message, color, y-displacement, and size arguments
def message_to_screen(msg, color, y_displace=0, size="small"):
textSurf, textRect = text_objects(msg, color, size)
textRect.center = (int(display_width/2), (int(display_height/2) + y_displace))
gameDisplay.blit(textSurf, textRect)
# Show button text
def text_to_button(msg,color, buttonx,buttony,buttonwidth,buttonheight,size="small"):
textSurf, textRect = text_objects(msg,color,size)
textRect.center = ((buttonx+(buttonwidth/2)), buttony+(buttonheight/2))
gameDisplay.blit(textSurf, textRect)
# On button hover
def button(text,x,y,width,height,inactive_color,active_color,action):
cursor = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x + width > cursor[0] > x and y + height > cursor[1] > y:
pygame.draw.rect(gameDisplay,active_color,(x,y,width,height))
if click[0] == 1 and action != None:
if action == "play":
gameLoop()
if action == "controls":
game_controls()
if action == "quit":
pygame.quit()
quit()
else:
pygame.draw.rect(gameDisplay,inactive_color,(x,y,width,height))
text_to_button(text,black,x,y,width,height)
def game_controls():
gcont = True
while gcont:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
intro = False
if event.key == pygame.K_q:
pygame.quit()
quit()
gameDisplay.fill(white)
message_to_screen("Controls", green, -100, size="large")
message_to_screen("Fire: Spacebar", black, -30, size="small")
message_to_screen("Move turret: Up and Down arrows", black, 10, size="small")
message_to_screen("Move UFO: Left and Right arrows", black, 50, size="small")
message_to_screen("Pause: P", black, 90, size="small")
button("Play",150,450,100,50, green, light_green, action="play")
button("Quit",550,450,100,50, red, light_red, action="quit")
pygame.display.update()
clock.tick(fps)
# Pauses game and gives continue and quit options
def pause():
paused = True
message_to_screen("Paused", black, -100, size="large")
message_to_screen("Press P to play, or Q to quit.", black, 25, size="small")
while paused:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
paused = False
elif event.key == pygame.K_q:
pygame.quit()
quit()
pygame.display.update()
clock.tick(fps)
# Keeps track of, and displays the score
def score(score):
text = smallFont.render(" Score: " + str(score), True, black)
gameDisplay.blit(text, [0,0])
# Barrier
def barrier():
xlocation = (display_width/2) + random.randint(-0.2*displayWidth,0.2*displayWidth)
# Intro screen - Title and directions
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
intro = False
if event.key == pygame.K_q:
pygame.quit()
quit()
gameDisplay.fill(white)
message_to_screen("Welcome to UFO!", green, -100, size="large")
message_to_screen("The objective of the game is to search and destroy.", black, -30, size="small")
message_to_screen("Destroy your opponent before they destroy you.", black, 10, size="small")
message_to_screen("The more enemies you destroy, the harder they get.", black, 50, size="small")
button("Play",150,450,100,50, green, light_green, action="play")
button("Controls",350,450,100,50, yellow, light_yellow, action="controls")
button("Quit",550,450,100,50, red, light_red, action="quit")
pygame.display.update()
clock.tick(fps)
# Main game loop
def gameLoop():
gameExit = False
gameOver = False
mainUfoX = display_width * 0.9
mainUfoY = display_height * 0.9
ufoMove = 0
currentTurPos = 0
changeTur = 0
# Game over screen and changes for key inputs
while not gameExit:
if gameOver == True:
message_to_screen("Game over!", red, -50, size="large")
message_to_screen("Press C to play again, Q to quit.", black, 50, size="medium")
pygame.display.update()
while gameOver == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
gameOver = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameExit = True
gameOver = False
if event.key == pygame.K_c:
gameLoop()
# Make changes for specific key inputs
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
ufoMove = -5
elif event.key == pygame.K_RIGHT:
ufoMove = 5
elif event.key == pygame.K_UP:
changeTur = 1
elif event.key == pygame.K_DOWN:
changeTur = -1
elif event.key == pygame.K_p:
pause()
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
ufoMove = 0
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
changeTur = 0
gameDisplay.fill(white)
mainUfoX += ufoMove
currentTurPos += changeTur
if currentTurPos > 8:
currentTurPos = 8
elif currentTurPos < 0:
currenTurPos = 0
ufo(mainUfoX,mainUfoY,currentTurPos)
pygame.display.update()
clock.tick(fps)
# Quits
pygame.quit()
quit()
# Loads game intro screen
game_intro()
# gameLoop calls itself to begin game
gameLoop()
It was a typo (I'm an idiot).
currentTurPos was currenTurPos.
Lesson learned: complex variable names with repeating letters are dangerous.

Categories

Resources