Snake Game keep adding food and removing - python

i created a snake game and i have one problem in function food() it keep adding food on screen and removing it i don't know how to fix this i tried with food_statement like = "wait" when there's a food in screen and draw when it's not food can you help me code is working properly until hit food function?
import pygame
import time
import random
pygame.init()
screen = pygame.display.set_mode((800,600))
pygame.display.set_caption('Snake Game by Joelinton')
blue=(0,0,255)
x_change = 0.2
y_change = 0.2
x = 400
y = 250
def creatingsnake():
pygame.draw.rect(screen,blue,[x,y,20,20])
def gameover():
font = pygame.font.SysFont('freesansbold.ttf', 100)
text = font.render('Game Over', True,(255,255,255))
screen.blit(text, (250, 250))
def food():
foodx = random.randint(0,750)
foody = random.randint(0,550)
pygame.draw.rect(screen,blue,[foodx,foody,20,20])
running = True
while running:
screen.fill((0,0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
x -= x_change
if keys[pygame.K_RIGHT]:
x += x_change
if keys[pygame.K_UP]:
y -= y_change
if keys[pygame.K_DOWN]:
y += y_change
if x < 0 or x > 780 or y < 0 or y > 580:
gameover()
running = False
time.sleep(1)
food()
creatingsnake()
pygame.display.update()

food is called in each frame. Thus, when the coordinates are generated in the function 'food', new random coordinates are generated in each frame. You must set the coordinates of the food once before the application loop:
foodx = random.randint(0,750)
foody = random.randint(0,550)
def food():
pygame.draw.rect(screen,blue,[foodx,foody,20,20])
running = True
while running:
# [...]
food()
creatingsnake()
pygame.display.update()

Related

I'm having problem with moving a player object in Pygame [duplicate]

This question already has answers here:
How can I make a sprite move when key is held down
(6 answers)
Closed 1 year ago.
I'm having a problem with moving a player object in Pygame. I have created the class of Player and called it on my main file, but whenever I try to move the player object it won't move. I have also called it inside the Game loop but still, it won't move. I don't know what's going on: Here is the code I have done so far:
screen.py
import pygame
screen.py
class Screen:
def __init__(self, width, height):
self.width = width
self.height = height
def screen_display(self):
return pygame.display.set_mode((self.width,self.height))
player.py
import pygame
class Player:
playerY_change = 0.5
def __init__(self, playerX,playerY, playerWidth,playerHeight,screen,):
self.playerX = playerX
self.playerY = playerY
self.playerWidth = playerWidth
self.playerHeight = playerHeight
self.screen = screen
def create_player(self):
return pygame.draw.rect(self.screen, [0, 0, 0], [self.playerX, self.playerY, self.playerWidth, self.playerHeight])
enemy.py
import pygame
class Enemy:
def __init__(self, enemyX,enemyY, enemyWidth,enemyHeight,screen):
self.enemyX = enemyX
self.enemyY = enemyY
self.enemyWidth = enemyWidth
self.enemyHeight = enemyHeight
self.screen = screen
def create_enemy(self):
return pygame.draw.rect(self.screen, [0, 0, 0], [self.enemyX, self.enemyY, self.enemyWidth, self.enemyHeight])
Here is my Main file main.py:
import pygame,random,math
from screen import Screen
from player import Player
from enemy import Enemy
# Pygame initilaize
pygame.init()
#Game Screen
screenWidth = 800
screenHeight = 500
window = Screen(screenWidth,screenHeight)
screen = window.screen_display()
# Title and Logo
pygame.display.set_caption("ShootBhoot")
icon = pygame.image.load("logo.png")
pygame.display.set_icon(icon)
# Player
playerX = 10
playerY = 10
playerY_change = 200
playerWidth = 15
playerHeight = 50
player = Player(playerX,playerY,playerWidth,playerHeight,screen)
#Enemy
enemyWidth = 15
enemyHeight = 50
enemyX = screenWidth - (enemyWidth + 10)
enemyY = 10
enemy = Enemy(enemyX,enemyY,enemyWidth,enemyHeight,screen)
# Ball
ballRadius = 10
ballX = random.randint(0, screenWidth - 10)
ballY = random.randint(0, screenHeight - 10)
ballX_change = 0.01
ballY_change = 0
def ball_create(screen, ballX, ballY, radius):
return pygame.draw.circle(screen, (10, 10, 10), (ballX, ballY), radius)
def distance(playerX,playerY,ballX,ballY):
calc = math.sqrt((playerX - ballX)**2 + (playerY - ballY)**2)
print(calc)
#Game loop
running = True
while running:
screen.fill((255,255,255))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#Even while I click btn It won't move
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
playerY_change = -0.5
if event.key == pygame.K_DOWN:
playerY_change = 0.5
# Player Move Object not moving
playerY = playerY_change
enemy.create_enemy()
ball_create(screen, ballX, ballY, ballRadius)
player.create_player()
pygame.display.flip()
pygame.display.update()
playerY is just used when to create the player. You have to change the coordinate attribute of the player:
playerY = playerY_change
player.playerY += playerY_change
However I recommend to use pygame.key.get_pressed() instead of the keyboard events.
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN event occurs once every time a key is pressed. KEYUP occurs once every time a key is released. Use the keyboard events for a single action or a step-by-step movement.
pygame.key.get_pressed() returns a list with the state of each key. If a key is held down, the state for the key is True, otherwise False. Use pygame.key.get_pressed() to evaluate the current state of a button and get continuous movement:
clock = pygame.time.Clock()
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.playerY -= 1
if keys[pygame.K_RIGHT]:
player.playerY += 1
screen.fill((255,255,255))
enemy.create_enemy()
ball_create(screen, ballX, ballY, ballRadius)
player.create_player()
pygame.display.flip()

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

Timing the blit of an enemy list in Pygame

Outside of my game loop, I have created a function that creates a list of 200 enemies with random coordinates. These enemies are suppose to start at the top of the screen and then drop down at random speeds. Inside the loop, I use a "for" loop to blit the enemies on screen. It works, but all 200 hundred are spawned and fall at the same time, albeit, at different speeds. So I know I need a timer and herein lies the problem; nothing I do works. Ive tried clock.tick(), pygame.delay(), import time and do the time.time() method. Everything either strobes or the system just crashes. What's causing the problem?
[Code]
import pygame
import sys
import random
import time
pygame.init()
#MAIN GAME
game_screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption("Beer Goggles")
bg = pygame.image.load("bg.png")
bg_image = pygame.transform.scale(bg, (600, 600))
class Object:
def __init__(self, image_path, width, height, x, y):
self.image_path = image_path
self.width = width
self.height = height
self.x = x
self.y = y
player = pygame.image.load(image_path)
self.player_main = pygame.transform.scale(player, (width,height))
def draw(self, background):
background.blit(self.player_main, (self.x, self.y))
#enemies
def enemy():
enemy_list = []
for e in range(200):
x_cor = random.randint(25, 361)
e = Object("enemy.png", 70, 70, x_cor, 25)
enemy_list.append(e)
return enemy_list
#Main Objects
player1 = Object("crate.png", 70, 70, 25, 500)
list1 = enemy()
#ladies
fat_lady = Object("fat_lady.png", 300, 300, 360, 180)
# Main Loop
direction = 0
game_on = True
while game_on:
clock = pygame.time.Clock()
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_on = False
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
direction = 1
elif event.key == pygame.K_LEFT:
direction = -1
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or event.key == pygame.K_LEFT:
direction = 0
game_screen.fill((0,0,0))
game_screen.blit(bg_image, (0,0))
#title.draw(game_screen)
player1.draw(game_screen)
fat_lady.draw(game_screen)
#move
if direction > 0:
player1.x = player1.x + 10
elif direction < 0:
player1.x = player1.x - 10
#boundaries
if player1.x <= 25:
player1.x = 25
elif player1.x >= 360:
player1.x = 360
#for enemy in list1:
for enemy in list1:
a = random.randint(1, 30)
enemy.draw(game_screen)
enemy.y += a
#collisions
#scoring
pygame.display.update()
quit()
In the code where you create the enemy list you could add a drop start time. Just like you create a random x co-ordinate you could create a time to start dropping it. Then later when you start changing the y position for them (dropping them), you would not start it dropping until after that time had passed.
By the way You have a method enemy() and later you have a loop iterator enemy which will override hide the method by that name. After that point if you tried to call the method enemy() it would fail and you would access the loop iterator instead. It does not affect your code here because you do not try to access the method after creating the loop iterator variable, but it is not a great idea and could cause problems if you later changed the code and did try to access that method. You should be careful about name choices.

Making an image move in 4 directions in pygame

Struggling to make my 'cowboy' image move across the screen in all 4 directions. Nothing happens whenever I press the keys. Help please. This is based off the exercise questions in Python Crash Course.
import pygame
pygame.init()
screen = pygame.display.set_mode((500,500))
pygame.display.set_caption("Move the Cowboy")
cowboy = pygame.image.load('images/cowboy.bmp')
cowboy = pygame.transform.scale(cowboy, (50, 50))
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
screen.fill((240,237,207))
cowboy_rect = cowboy.get_rect()
screen_rect = screen.get_rect()
screen_center = screen_rect.center
cowboy_rect.center = screen_rect.center
cowboy_rect.x = cowboy_rect.width
cowboy_rect.y = cowboy_rect.height
cowboy_x = float(cowboy_rect.x)
cowboy_y = float(cowboy_rect.y)
screen.blit(cowboy, screen_center)
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
cowboy_x -= 5
elif keys[pygame.K_RIGHT]:
cowboy_x += 5
elif keys[pygame.K_UP]:
cowboy_y -= 5
elif keys[pygame.K_DOWN]:
cowboy_y += 5
pygame.display.update()
pygame.quit()
You are putting the image at the middle of the screen with screen.blit(cowboy, screen_center). Change screen_center to cowboy_rect as this stores the position of the image.
Also take the cowboy_rect = cowboy.get_rect() out of the loop as this resets it back to 0.
You are then putting the position of cowboy_rect to the center of the screen by doing cowboy_rect.center = screen_rect.center, take that out of the loop so it only happens once, not every frame. Then its getting changed to 50,50 by cowboy_rect.x = cowboy_rect.width and cowboy_rect.y = cowboy_rect.height, so take that out.
Then at the keys, change cowboy_x -= 5 to cowboy_rect.x -= 5 and do the same for the others.
By putting this in: screen.blit(cowboy, screen_center), you are saying that this image will appear at the center of the screen. You want it to appear at (cowboy_x, cowboy_y), as these are the positionment variables you defined. Here is a working version of your code:
import pygame
pygame.init()
screen = pygame.display.set_mode((500,500))
pygame.display.set_caption("Move the Cowboy")
cowboy = pygame.image.load('images/cowboy.bmp')
cowboy = pygame.transform.scale(cowboy, (50, 50))
cowboy_x, cowboy_y = 0, 0
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
screen.fill((240,237,207))
screen.blit(cowboy, (cowboy_x, cowboy_y))
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
cowboy_x -= 1
elif keys[pygame.K_RIGHT]:
cowboy_x += 1
elif keys[pygame.K_UP]:
cowboy_y -= 1
elif keys[pygame.K_DOWN]:
cowboy_y += 1
pygame.display.update()
pygame.quit()
I took the liberty of taking out some completely useless lines of code, and of bringing the stuff you didn't need to re-iterate out of the loop, to save processing space.

Python how to delay bullet shooting

Thank you in advance for your time.
If I fire a bullet with space key, a stream of bullets are created. If I would set a delay with time.sleep() inside 'if keys[pygame.K_SPACE]:' it would also freeze the loop for the set amount of seconds. How could I make it so only 1 bullet fires at a time? This is the copy of my game loop, please tell me if more of the code is needed:
def game_loop():
global pause
x = (display_width * 0.2)
y = (display_height * 0.2)
x_change = 0
y_change = 0
blob_speed = 3
velocity = [2, 2]
pos_x = display_width/1.2
pos_y = display_height/1.2
gameExit = False
while not gameExit:
for event in pygame.event.get():#monitors hardware movement/ clicks
if event.type == pygame.QUIT:
pygame.quit()
quit()
pos_x += velocity[0]
pos_y += velocity[1]
if pos_x + blob_width > display_width or pos_x < 601:
velocity[0] = -velocity[0]
if pos_y + blob_height > display_height or pos_y < 0:
velocity[1] = -velocity[1]
# Checks to see if any keys are held down and remembers them with the variable keys.
keys = pygame.key.get_pressed()
for b in range(len(bullets)):
bullets[b][0] += 6
for bullet in bullets:
if bullet[0] > 1005:
bullets.remove(bullet)
if keys[pygame.K_SPACE]:
bullets.append([x+25, y+24])
# If the player is holding down one key or the other the blob moves in that direction
if x < 0:
x = 0
if keys[pygame.K_a]:
x_change = -blob_speed
if x > 401 - blob_width:
x = 401 - blob_width
if keys[pygame.K_d]:
x_change = blob_speed
if keys[pygame.K_p]:
pause = True
paused()
# If the player is holding down both or neither of the keys the blob stops
if keys[pygame.K_a] and keys[pygame.K_d]:
x_change = 0
if not keys[pygame.K_a] and not keys[pygame.K_d]:
x_change = 0
if y < 0:
y = 0
if keys[pygame.K_w]:
y_change = -blob_speed
if y > display_height - blob_height:
y = display_height - blob_height
if keys[pygame.K_s]:
y_change = blob_speed
if keys[pygame.K_w] and keys[pygame.K_s]:
y_change = 0
if not keys[pygame.K_w] and not keys[pygame.K_s]:
y_change = 0
#print(event)
# Reset x and y to new position
x += x_change
y += y_change
gameDisplay.fill(blue) #changes background surface
pygame.draw.line(gameDisplay, black, (601, display_height), (601, 0), 3)
pygame.draw.line(gameDisplay, black, (401, display_height), (401, 0), 3)
blob(pos_x, pos_y)
blob(x, y)
for bullet in bullets:
gameDisplay.blit(bulletpicture, pygame.Rect(bullet[0], bullet[1], 0, 0))
pygame.display.update() #update screen
clock.tick(120)#moves frame on (fps in parameters)
Here's an answer without classes. You just have to store the previous time when a bullet was fired, subtract it from the current time and check if it's above some time limit (500 ms in this example) to see if we're ready to fire.
import pygame
def game_loop():
pygame.init()
gameDisplay = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
bulletpicture = pygame.Surface((10, 5))
bulletpicture.fill(pygame.Color('sienna1'))
bullets = []
x = 50
y = 240
previous_time = pygame.time.get_ticks()
gameExit = False
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
current_time = pygame.time.get_ticks()
# We're ready to fire when 500 ms have passed.
if current_time - previous_time > 500:
previous_time = current_time
bullets.append([x+25, y+24])
remaining_bullets = []
for bullet in bullets:
bullet[0] += 6 # Move the bullet.
if bullet[0] < 500: # Filter out the bullets.
remaining_bullets.append(bullet)
bullets = remaining_bullets
gameDisplay.fill((30, 30, 30))
for bullet in bullets:
gameDisplay.blit(bulletpicture, pygame.Rect(bullet[0], bullet[1], 0, 0))
pygame.display.update()
clock.tick(120)
game_loop()
pygame.quit()

Categories