As a beginner im trying to create flappy bird to learn the basics of python and pygame. But when i run this code and click the button that is created the code just stops and python becomes not responsive. Does any one know why?
import pygame
import math
import random
import pyautogui as pg
pygame.init()
screenWidth, screenHeight = pg.size()
gameDisplay = pygame.display.set_mode((screenWidth, screenHeight), pygame.FULLSCREEN)
pygame.display.set_caption("Flappy by Tallik")
time = pygame.time.Clock()
crashed = False
bg = (0, 0, 0)
textSize = 32
font = pygame.font.Font("freesansbold.ttf", textSize)
buttonClicked = [0, 0]
mainGame = False
titleScreen = True
settings = False
changeBird = False
dead = False
phase = 1
def buttonFunc(x, y, width, height, color1, color2, text, textColor, textColor2, buttonNum, dissaperance):
global buttonClicked
mouseClick = pygame.mouse.get_pressed()
mouseX, mouseY = pygame.mouse.get_pos()
buttonText = font.render(str(text), True, textColor)
buttonText2 = font.render(str(text), True, textColor2)
textX = x + 10
textY = y + (height//3)
buttonClicked = [0, buttonNum]
if mouseX >= x and mouseX <= x + width and mouseY >= y and mouseY <= y + height:
pygame.draw.rect(gameDisplay, (color2), (x, y, width, height))
gameDisplay.blit(buttonText2, (textX, textY))
if mouseClick[0] == True:
buttonClicked[0] = 1
if dissaperance == False:
pygame.draw.rect(gameDisplay, (color2), (x, y, width, height))
gameDisplay.blit(buttonText2, (textX, textY))
buttonClicked[0] = 1
else:
gameDisplay.fill(bg)
else:
pygame.draw.rect(gameDisplay, (color1), (x, y, width, height))
gameDisplay.blit(buttonText, (textX, textY))
class bird(object):
def __init__(self, birdVelMultiplier, skin, width, height):
self.birdVelMultiplier = birdVelMultiplier
self.skin = skin
self.grav = -1
self.height = height
self.width = width
self.y = screenHeight//2
self.x = screenWidth//30
self.vel = screenHeight//100
self.jumps = 0
self.minVel = -20
self.maxVel = 20
def jump(self):
if keys[pygame.K_SPACE] and self.jumps == 0:
self.vel = -15
self.jumps += 1
if keys[pygame.K_UP] and self.jumps == 0:
self.vel = -15
self.jumps += 1
if not keys[pygame.K_UP] and not keys[pygame.K_SPACE]:
self.jumps = 0
def drawToGame(self, gameDisplay):
if self.y + self.height <= screenHeight:
if self.y >= 0:
if self.vel < self.maxVel and self.vel > self.minVel:
self.vel -= self.grav
self.y += self.vel
else:
if abs(self.vel)/self.vel == 1:
self.vel = self.maxVel
self.vel -= self.grav
self.y += self.vel
else:
self.vel = self.minVel
self.vel -= self.grav
self.y += self.vel
else:
self.y = 0
self.vel = 1
else:
self.y = screenHeight//2
self.vel = 0
pygame.draw.rect(gameDisplay, (0, 0, 255), (self.x, self.y, self.width, self.height))
class obstacle(object):
def __init__(self, speedMultiplier, width):
self.speedMultiplier = speedMultiplier
self.width = width
self.ranHeight = random.randrange(50, screenHeight - (screenHeight//16)*4)
self.ranHeight2 = (screenHeight - self.ranHeight) - 150
def spawn(self):
print(1)
def drawToSurface(self, gameDisplay):
print(3)
bird1 = bird(1, 1, 60, 60)
pipe = obstacle(1, 130)
sB = bird1
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
gameDisplay.fill(bg)
keys = pygame.key.get_pressed()
if buttonClicked == [1, 1]:
phase = 4
if phase == 1:
buttonFunc(screenWidth//2, screenHeight//4, screenWidth//18, screenHeight//20, (115, 115, 115), (85, 85, 85), "Start!", (0, 0, 0), (0, 0, 0), 1, True)
elif phase == 2:
print("?")
elif phase == 3:
print("??")
elif phase == 4:
while dead == False:
sB.jump()
sB.drawToGame(gameDisplay)
pygame.display.update()
time.tick(30)
pygame.quit()
quit()
To specify: after i have pressed the button created by buttFunc and the phase variable gets to 4 the program just stops and no eroor message is recieved. Also when closing the program the IDLE shell says the program is still running. I posted all the code because i dont know what made it break.
The program does not "crash", you just have an infinite loop. You do not need a loop that controls the game in the application loop. The application loop is continuously executed. Remove while dead == False::
while not crashed and not dead:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
gameDisplay.fill(bg)
keys = pygame.key.get_pressed()
if buttonClicked == [1, 1]:
phase = 4
if phase == 1:
buttonFunc(screenWidth//2, screenHeight//4, screenWidth//18, screenHeight//20, (115, 115, 115), (85, 85, 85), "Start!", (0, 0, 0), (0, 0, 0), 1, True)
elif phase == 2:
print("?")
elif phase == 3:
print("??")
elif phase == 4:
sB.jump()
sB.drawToGame(gameDisplay)
pygame.display.update()
time.tick(30)
How would I get the enemy to avoid the characters line at all costs while still trying to eliminate him? The code I have as far makes the enemy run straight to the player and die pretty much straight away.
Does anyone have any idea how to keep the enemy from touching the players line?
Here is the code:
import random
import pygame, sys
from pygame.locals import *
import time
GREEN=(0,125,0)
BLUE=(0,0,125)
Yplayer = 225/2
Xplayer = 350
playerlinesavedata = []
playercurrent = []
Xplayerchange=0
Yplayerchange=0
Yenemy = 450
Xenemy = 300
enemylinesavedata = []
enemycurrent = []
Xenemychange=0
Yenemychange=0
windowX = 900
windowY = 600
pygame.init()
DISPLAY=pygame.display.set_mode((windowX,windowY),0,32)
def enemymovement():
global Xplayer,Yplayer,Xenemy,Yenemy
enemy1 = True
enemydirection = random.randint(1,4)
# enemy moves toward player
if Xenemy > Xplayer: enemydirection = 1
elif Xenemy < Xplayer: enemydirection = 2
elif Yenemy > Yplayer: enemydirection = 3
elif Yenemy < Yplayer: enemydirection = 4
while enemy1 == True:
if enemydirection == 1:
Xenemychange= -random.randint(1,4)
Xenemy+=Xenemychange
if enemydirection == 2:
Xenemychange= random.randint(1,4)
Xenemy+=Xenemychange
if enemydirection == 3:
Yenemychange= -random.randint(1,4)
Yenemy+=Yenemychange
if enemydirection == 4:
Yenemychange= random.randint(1,4)
Yenemy+=Yenemychange
enemylinesavedata.append([Xenemy,Yenemy])
enemy()
break
def enemy():
for XnY in enemylinesavedata:
pygame.draw.rect(DISPLAY,BLUE, [XnY[0],XnY[1],5,5])
def player():
for XnY in playerlinesavedata:
pygame.draw.rect(DISPLAY,GREEN,[XnY[0],XnY[1],5,5])
def main():
global playerlinesavedata, enemylinesavedata
global Xplayer, Yplayer, Xenemy, Yenemy
WHITE = (255,255,255)
size = 5
clock = pygame.time.Clock()
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
keys = pygame.key.get_pressed()
Xplayer += (keys[pygame.K_d] - keys[pygame.K_a]) * size
Yplayer += (keys[pygame.K_s] - keys[pygame.K_w]) * size
playerlinesavedata.append((Xplayer, Yplayer))
enemymovement()
player_rectlist = [pygame.Rect(x, y, size, size) for x, y in playerlinesavedata]
enemy_rectlist = [pygame.Rect(x, y, size, size) for x, y in enemylinesavedata]
if player_rectlist[-1].collidelist(enemy_rectlist) >= 0:
pygame.quit()
sys.exit()
if enemy_rectlist[-1].collidelist(player_rectlist) >= 0:
playerlinesavedata = []
Yplayer = 225//2
Xplayer = 350
enemylinesavedata = []
Yenemy = 450
Xenemy = 300
DISPLAY.fill(WHITE)
player()
enemy()
pygame.display.update()
main()
It is a bad practice to use globalize variables. It is much better to use python classes as the pygame objects.
Here is a cleaned up version of your code so that you or other users on Stack Overflow can help you with your problem more easily:
import random
import pygame, sys
from pygame.locals import *
import time
pygame.init()
GREEN = (0, 125, 0)
BLUE = (0, 0, 125)
WHITE = (255,255,255)
windowX = 900
windowY = 600
wn = pygame.display.set_mode((windowX, windowY), 0, 32)
class Object:
def __init__(self, X, Y, enemy=False, color=GREEN):
self.enemy = enemy
self.X = X
self.Y = Y
self.current = []
self.Xchange = 0
self.Ychange = 0
self.direction = 0
self.rectlist = []
self.color = color
self.size = 5
def movement(self):
for rect in self.rectlist:
pygame.draw.rect(wn, self.color, rect)
if self.enemy:
if self.X > player.X:
self.direction = 1
elif self.X < player.X:
self.direction = 2
elif self.Y > player.Y:
self.direction = 3
elif self.Y < player.Y:
self.direction = 4
if self.direction == 1:
self.Xchange = -random.randint(1,4)
self.X += self.Xchange
if self.direction == 2:
self.Xchange = random.randint(1,4)
self.X += self.Xchange
if self.direction == 3:
self.Ychange = -random.randint(1,4)
self.Y += self.Ychange
if self.direction == 4:
self.Ychange = random.randint(1,4)
self.Y += self.Ychange
else:
keys = pygame.key.get_pressed()
player.X += (keys[pygame.K_d] - keys[pygame.K_a]) * player.size
player.Y += (keys[pygame.K_s] - keys[pygame.K_w]) * player.size
self.rectlist.append(pygame.Rect(self.X, self.Y, self.size, self.size))
player = Object(350, 225 / 2)
enemy = Object(450, 300, enemy=True, color=BLUE)
def main():
clock = pygame.time.Clock()
size = 5
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
player.movement()
enemy.movement()
if player.rectlist[-1].collidelist(enemy.rectlist) >= 0:
pygame.quit()
sys.exit()
if enemy.rectlist[-1].collidelist(player.rectlist) >= 0:
player.rectlist = []
player.X = 350
player.Y = 225 // 2
enemy.rectlist = []
enemy.X = 450
enemy.Y = 300
pygame.display.update()
wn.fill(WHITE)
main()
Here is my implementation of how to let the enemy avoid the player, though it is very buggy, as in, it will go through the player's line
most of the time:
import random
import pygame, sys
from pygame.locals import *
import time
pygame.init()
GREEN = (0, 125, 0)
BLUE = (0, 0, 125)
WHITE = (255,255,255)
windowX = 900
windowY = 600
wn = pygame.display.set_mode((windowX, windowY), 0, 32)
class Object:
def __init__(self, X, Y, enemy=False, color=GREEN):
self.enemy = enemy
self.X = X
self.Y = Y
self.current = []
self.Xchange = 0
self.Ychange = 0
self.direction = 0
self.rectlist = []
self.color = color
self.size = 5
self.bounce = 0
def movement(self):
for rect in self.rectlist:
pygame.draw.rect(wn, self.color, rect)
if self.enemy:
enemydirection = random.randint(1,4)
if not self.bounce:
if self.X > player.X:
self.direction = 1
elif self.X < player.X:
self.direction = 2
elif self.Y > player.Y:
self.direction = 3
elif self.Y < player.Y:
self.direction = 4
else:
self.bounce -= 1
if self.direction == 1:
self.Xchange = -random.randint(1,4)
self.X += self.Xchange
if self.direction == 2:
self.Xchange = random.randint(1,4)
self.X += self.Xchange
if self.direction == 3:
self.Ychange = -random.randint(1,4)
self.Y += self.Ychange
if self.direction == 4:
self.Ychange = random.randint(1,4)
self.Y += self.Ychange
else:
keys = pygame.key.get_pressed()
player.X += (keys[pygame.K_d] - keys[pygame.K_a]) * player.size
player.Y += (keys[pygame.K_s] - keys[pygame.K_w]) * player.size
self.rectlist.append(pygame.Rect(self.X, self.Y, self.size, self.size))
player = Object(350, 225 / 2)
enemy = Object(450, 300, enemy=True, color=BLUE)
def main():
clock = pygame.time.Clock()
size = 5
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
player.movement()
enemy.movement()
if player.rectlist[-1].collidelist(enemy.rectlist) >= 0:
pygame.quit()
sys.exit()
if enemy.rectlist[-1].collidelist(player.rectlist) >= 0:
if not enemy.bounce:
while enemy.rectlist[-1].collidelist(player.rectlist) >= 0:
enemy.rectlist.pop()
enemy.rectlist.pop()
enemy.rectlist.pop()
enemy.X, enemy.Y = enemy.rectlist[-1].x, enemy.rectlist[-1].y
enemy.direction = enemy.direction - 2 if enemy.direction - 2 else enemy.direction + 2
enemy.bounce = 40
pygame.display.update()
wn.fill(WHITE)
main()
Output:
I made code for the snake game, but now, I am trying to edit that code to have the snake move without having to use the keys. I have tried editing my move function and changing event.type and pygame.keydown, but the snake isn't moving without the keys. When I try to alter the code so the snake moves automatically at a certain point on the grid, the snake automatically dies right after it gets to the coordinate.
import random
import pygame
import tkinter as tk
from tkinter import messagebox
import sys
import time
pygame.display.set_caption('SNAKE GAME BOT!')
class cube(object):
rows = 20
w = 800
def __init__(self, start, dirnx=1, dirny=0, color=(30,144,255)):
self.pos = start
self.dirnx = 1
self.dirny = 0
self.color = color
def move(self, dirnx, dirny):
self.dirnx = dirnx
self.dirny = dirny
self.pos = (self.pos[0] + self.dirnx, self.pos[1] + self.dirny)
def draw(self, surface, eyes=False):
dis = self.w // self.rows
i = self.pos[0]
j = self.pos[1]
pygame.draw.rect(surface, self.color, (i * dis + 1, j * dis + 1, dis - 2, dis - 2))
if eyes:
centre = dis // 2
radius = 3
circleMiddle = (i * dis + centre - radius, j * dis + 8)
circleMiddle2 = (i * dis + dis - radius * 2, j * dis + 8)
pygame.draw.circle(surface, (0,128,0), circleMiddle, radius)
pygame.draw.circle(surface, (0,128,0), circleMiddle2, radius)
class snake(object):
body = []
turns = {}
def __init__(self, color, pos):
self.color = color
self.head = cube(pos)
self.body.append(self.head)
self.dirnx = 0
self.dirny = 1
self.direction = direction
def move(self):
for i, c in enumerate(self.body):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
if (event.key == pygame.K_LEFT or event.key == pygame.K_a) and self.direction != "right":
self.direction = 'left'
self.dirnx = -1
self.dirny = 0
self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]
elif (event.key == pygame.K_RIGHT or event.key == pygame.K_d) and self.direction != "left":
self.direction = 'right'
self.dirnx = 1
self.dirny = 0
self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]
elif (event.key == pygame.K_UP or event.key == pygame.K_w) and self.direction != "down":
self.direction = 'up'
self.dirnx = 0
self.dirny = -1
self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]
elif (event.key == pygame.K_DOWN or event.key == pygame.K_s) and self.direction != "up":
self.direction = 'down'
self.dirnx = 0
self.dirny = 1
self.turns[self.head.pos[:]] = [self.dirnx, self.dirny]
p = c.pos[:]
if p in self.turns:
turn = self.turns[p]
c.move(turn[0], turn[1])
if i == len(self.body) - 1:
self.turns.pop(p)
else:
reset = (0, 10)
if c.dirnx == -1 and c.pos[0] <= 0:
show_score(0, red, 'times', 75, len(s.body))
time.sleep(1)
s.reset(reset)
elif c.dirnx == 1 and c.pos[0] >= c.rows - 1:
show_score(0, red, 'times', 75, len(s.body))
time.sleep(1)
s.reset(reset)
elif c.dirny == 1 and c.pos[1] >= c.rows - 1:
show_score(0, red, 'times', 75, len(s.body))
time.sleep(1)
s.reset(reset)
elif c.dirny == -1 and c.pos[1] <= 0:
show_score(0, red, 'times', 75, len(s.body))
time.sleep(1)
s.reset(reset)
else:
c.move(c.dirnx, c.dirny)
def reset(self, pos):
self.head = cube(pos)
self.body = []
self.body.append(self.head)
self.turns = {}
self.dirnx = 0
self.dirny = 1
def addCube(self):
tail = self.body[-1]
dx, dy = tail.dirnx, tail.dirny
if dx == 1 and dy == 0:
self.body.append(cube((tail.pos[0] - 1, tail.pos[1])))
elif dx == -1 and dy == 0:
self.body.append(cube((tail.pos[0] + 1, tail.pos[1])))
elif dx == 0 and dy == 1:
self.body.append(cube((tail.pos[0], tail.pos[1] - 1)))
elif dx == 0 and dy == -1:
self.body.append(cube((tail.pos[0], tail.pos[1] + 1)))
self.body[-1].dirnx = dx
self.body[-1].dirny = dy
def draw(self, surface):
for i, c in enumerate(self.body):
if i == 0:
c.draw(surface, True)
else:
c.draw(surface)
def drawGrid(w, rows, surface):
sizeBtwn = w // rows
x = 0
y = 0
for l in range(rows):
x = x + sizeBtwn
y = y + sizeBtwn
pygame.draw.line(surface, (255, 255, 255), (x, 0), (x, w))
pygame.draw.line(surface, (255, 255, 255), (0, y), (w, y))
def redrawWindow(surface):
global rows, width, s, snack
surface.fill((154,205,50))
s.draw(surface)
snack.draw(surface)
drawGrid(width, rows, surface)
pygame.display.update()
def randomSnack(rows, item):
positions = item.body
while True:
x = random.randrange(rows)
y = random.randrange(rows)
if len(list(filter(lambda z: z.pos == (x, y), positions))) > 0:
continue
else:
break
return (x, y)
def message_box(subject, content):
root = tk.Tk()
root.attributes("-topmost", True)
root.withdraw()
messagebox.showinfo(subject, content)
try:
root.destroy()
except:
pass
def show_score(choice, color, font, size, score):
score_font = pygame.font.SysFont(font, size)
score_surface = score_font.render('BOTS SCORE : ' + str(score), True, color)
score_rect = score_surface.get_rect()
if choice == 1:
score_rect.midtop = (60, 60)
else:
score_rect.midtop = (400, 400)
win.blit(score_surface, score_rect)
pygame.display.flip()
def main():
global width, rows, s, snack, win, direction, red
direction = 'right'
width = 800
rows = 20
red = pygame.Color(255, 0, 0)
check_errors = pygame.init()
if check_errors[1] > 0:
print(f'[!] Had {check_errors[1]} errors when initializing game, exiting...')
sys.exit(-1)
else:
print('[+] Game successfully initialized')
win = pygame.display.set_mode((width, width))
s = snake((30,144,255), (0, 10))
snack = cube(randomSnack(rows, s), color=(255, 0, 0))
flag = True
clock = pygame.time.Clock()
while flag:
pygame.time.delay(1)
clock.tick(10)
s.move()
if s.body[0].pos == snack.pos:
s.addCube()
snack = cube(randomSnack(rows, s), color=(255, 0, 0))
for x in range(len(s.body)):
if s.body[x].pos in list(map(lambda z: z.pos, s.body[x + 1:])):
show_score(0, red, 'times', 80, len(s.body))
print('BOTS SCORE: ', len(s.body))
time.sleep(1)
s.reset((0, 10))
break
redrawWindow(win)
main()
Please Help!
import pygame
import random
import os
from Snake import Snake
from Food import Food
from Block import Block
from World import worlds
from tkinter import *
import tkinter.simpledialog
head_path = os.path.join('Assets','Images','head.png')
index3_path = os.path.join('Assets','Images','index3.jpg')
python_path = os.path.join( 'Assets','Images','python.jpg')
point_path = os.path.join('Assets','Sounds','Point.wav')
pygame.mixer.pre_init(44100, -16, 2, 2048)
pygame.mixer.init()
pygame.init()
#intiating sounds
intro_sound = pygame.mixer.Sound(os.path.join('Assets','Sounds','intro.wav'))
game_sound = pygame.mixer.Sound(os.path.join('Assets','Sounds','gamesound.wav'))
pause_sound = pygame.mixer.Sound(os.path.join('Assets','Sounds','pausesound.wav'))
endgame_sound = pygame.mixer.Sound(os.path.join('Assets','Sounds','endsound.wav'))
#the volume are set such that sounds are pleasant
intro_sound.set_volume(0.1)
game_sound.set_volume(0.6)
pause_sound.set_volume(0.1)
endgame_sound.set_volume(0.12)
width, height = 1000, 600
game_display = pygame.display.set_mode((width, height))
game_display.fill((170,150,255))
blist=[]
pygame.display.set_caption('SNAKES')
img = pygame.image.load(head_path)
pygame.display.set_icon(img)
dirn = "right"
clock = pygame.time.Clock()
font = pygame.font.SysFont("comicsansms", 35)
FPS = 25
def total(score, i):
""" function for total score """
return score + i * 10
# for highscore
highscorefile = open('highscore.txt', 'rt')
highscore = highscorefile.readline()
try:
highscore = int(highscore)
except ValueError:
highscore = 0
namehighscore = highscorefile.readline()
highscorefile.close()
def pause(scorestr):
#stop in game music and play pause music
game_sound.stop()
pause_sound.play(-1)
paused = True
while paused:
showButton()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
keyp = action()
if event.type == pygame.KEYDOWN or keyp != None:
try:
if keyp == 'c' or event.key == pygame.K_c:
paused = False
except:
pass
try:
if keyp == 'q' or event.key == pygame.K_q:
print('quit')
pygame.quit()
quit()
except:
pass
message("Paused", (0, 0, 0))
message("C to continue, Q to Quit", (200, 0, 0), 40)
# display score on pause
message(scorestr, (255, 0, 0), 80)
pygame.display.update()
clock.tick(5)
#stop pause music and play in game music if game continues
if paused == False:
pause_sound.stop()
game_sound.play(-1)
def button(msg,x,y,w,h):
mouse = pygame.mouse.get_pos()
if x+w > mouse[0] > x and y+h > mouse[1] > y:
pygame.draw.rect(game_display, (0,0,250),(x,y,w,h))
else:
pygame.draw.rect(game_display, (0,0,100),(x,y,w,h))
smallText = pygame.font.Font("freesansbold.ttf",20)
text= smallText.render(msg, True, (0,200,0))
t=text.get_rect()
t.center = ( (x+(w/2)), (y+(h/2)) )
game_display.blit(text, t)
def intro():
#play intro music infinite loop
intro_sound.play(-1)
i=True
while i:
for event in pygame.event.get():
keyp=action()
if event.type==pygame.QUIT:
pygame.quit()
quit()
if keyp!=None or event.type==pygame.KEYDOWN :
try:
if keyp=='c' or event.key==pygame.K_c :
i=False
except:
continue
showButton()
image = pygame.image.load(index3_path)
game_display.blit(image,(0,0))
message(" Welcome to Snakes!!",(200,0,0),-59)
message("Press C to continue",(100,0,100),260)
pygame.display.update()
clock.tick(15)
def showButton():
global blist
pygame.draw.rect(game_display, (170, 150, 255), (800, 0, 200, 600))
button("Continue", 800, 200, 130, 30)
blist.append((800, 200, 130, 30,'c'))
button("Exit", 935, 200, 65, 30)
blist.append((935, 200, 65, 30,'q'))
button("Up", 870, 235, 50, 30)
blist.append((870, 235, 50, 30,'up'))
button("Down", 865, 305, 60, 30)
blist.append((865, 305, 60, 30,'dn'))
button("Right", 895, 270, 60, 30)
blist.append((895, 270, 60, 30,'rt'))
button("Left", 830, 270, 60, 30)
blist.append((830, 270, 60, 30,'lt'))
button("Pause",830,340,125,30)
blist.append((830,340,125,30,'p'))
button("Shift", 830, 375, 125, 30)
blist.append((830, 375, 125, 30,'st'))
pygame.draw.line(game_display,(0,200,100),(800,0),(800,600),5)
def action():
global blist
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
for tup in blist:
if tup[0] + tup[2] > mouse[0] > tup[0] and tup[1] + tup[3] > mouse[1] > tup[1]:
if click[0] == 1:
return tup[4]
return None
def message(m, color, dispy=0):
text = font.render(m, True, color)
t = text.get_rect()
t.center = (400), (300) + dispy
game_display.blit(text, t)
def food_collides_block(food_rect, blocks):
""" Returns True if any of the blocks collide with the food """
for block in blocks:
if food_rect.colliderect(block.get_rect()):
return True
return False
def get_blocks(food_rect, n):
""" Generates `n` blocks at random x, y """
blocks = list()
for i in range(n):
block_x = round(random.randrange(0, (width)) / 10.0) * 10
block_y = round(random.randrange(0, height) / 10.0) * 10
block_width, block_height = 10, 10
block = Block(block_x, block_y, block_width, block_height)
# if the block collides with food, generate at other x, y.
if food_rect.colliderect(block.get_rect()):
i -= 1
continue
blocks.append(block)
return blocks
def gameLoop():
global dirn, k, highscore, namehighscore
pyExit = False
pyOver = False
#stop intro music and play in game music infinite loop
intro_sound.stop()
game_sound.play(-1)
score = 0
world_num = 0
scorestr = "Score:0"
# Initialize the game
snake = Snake(200, 200, img)
food = Food(int(width / 2), int(height / 2))
blocks = worlds(width - 200, height, world_num)
# Keeps track of the direction of the snake.
dx, dy = 0, 0
lossreason = ''
while not pyExit:
if pyOver == True:
#play end music
endgame_sound.play(-1)
while pyOver:
image = pygame.image.load(python_path)
game_display.blit(image, (0, 0))
message("Game Over! Press C to play Again, Q to Quit",
(255, 0, 0), -20)
message(lossreason, (255, 0, 0), 30)
# display score on game over
message("Your" + scorestr, (255, 0, 0), 80)
if totalscore > highscore:
# message("Highscore!!!",(255,0,0),120)
# write new highscore
highscorefile = open('highscore.txt', 'wt')
highscorefile.write(str(totalscore) + "\n")
# name window
def namewrite():
highscorefile.write(v.get())
scorewindow.destroy()
scorewindow = Tk()
scorewindow.geometry('300x100')
frame = Frame(scorewindow, width=100, height=100)
frame.pack()
scorewindow.title("congratulations")
Label(frame, text='you\'ve made highscore!!!!').pack(side='top')
v = StringVar()
v.set("type your name")
textbox = Entry(frame, textvariable=v)
textbox.pack(side='top')
okbutton = Button(frame, text="ok", fg="black",
bg="white", command=namewrite)
okbutton.pack(side='bottom')
scorewindow.mainloop()
highscorefile.close()
# incase user wants to countinue after creating highscore
# to read his new score
highscorefile = open('highscore.txt', 'rt')
highscore = highscorefile.readline()
highscore = int(highscore)
namehighscore = highscorefile.readline()
highscorefile.close()
else:
message("Highscore by " + namehighscore +
":" + str(highscore), (255, 0, 0), 120)
pygame.display.update()
for event in pygame.event.get():
keyp = action()
if keyp != None or event.type == pygame.KEYDOWN:
try:
if keyp == 'q' or event.key == pygame.K_q:
pyExit = True
pyOver = False
except:
blank = [] # bypass the exception
try:
if keyp == 'c' or event.key == pygame.K_c:
#stop endgame music
endgame_sound.stop()
gameLoop()
except:
blank = [] # bypass the exception
""" Events """
#the conditions are modified to work with the buttons
for event in pygame.event.get():
keyp = action()
# blank is not used anywhere
# it is just used to jump the exception
if event.type == pygame.QUIT:
pyExit = True
if event.type == pygame.KEYDOWN or keyp != None:
try:
if keyp == 'lt' or event.key == pygame.K_LEFT and dirn != "right":
dirn = "left"
dx = -1
dy = 0
except:
blank = []
try:
if keyp == 'rt' or event.key == pygame.K_RIGHT and dirn != "left":
dirn = "right"
dx = 1
dy = 0
except:
blank = []
try:
if keyp == 'up' or event.key == pygame.K_UP and dirn != "down":
dirn = "up"
dy = -1
dx = 0
except:
blank = []
try:
if keyp == 'dn' or event.key == pygame.K_DOWN and dirn != "up":
dirn = "down"
dy = 1
dx = 0
except:
blank = []
try:
if keyp == 'p' or event.key == pygame.K_p:
pause(scorestr)
except:
blank = []
try:
if keyp == 'q' or event.key == pygame.K_q:
pygame.quit()
quit(0)
except:
blank = []
# level changer value
if score > 10:
score = 0
world_num += 1
blocks = worlds(width - 200, height, world_num)
food.x, food.y = int(width / 2), int(height / 2)
# Engage boost of pressing shift
keyp=action()
keyPresses = pygame.key.get_pressed()
boost_speed = keyPresses[pygame.K_LSHIFT] or keyPresses[pygame.K_RSHIFT] or keyp=='st'
# if boost_speed is true it will move 2 blocks in one gameloop
# else it will just move one block
iterations = [1]
if boost_speed == 1:
iterations.append(2)
for i in iterations:
""" Update snake """
snake.move(dx, dy, 10)
snake.check_boundary(width, height)
snake_rect = snake.get_rect()
food_rect = food.get_rect()
""" Snake-Snake collision """
if snake.ate_itself():
#stop game sound
game_sound.stop()
pyOver = True
lossreason = 'Oooops You Hit YOURSELF'
""" Snake-Block collision """
for block in blocks:
block_rect = block.get_rect()
if block_rect.colliderect(snake_rect):
#stop game sound
game_sound.stop()
pyOver = True
lossreason = 'Ooops You Hit a BLOCKER'
""" Snake-Food collision """
# if snake collides with food, increase its length.
if food_rect.colliderect(snake_rect):
score += 1
snake.increment_length()
sound = pygame.mixer.Sound(point_path)
sound.set_volume(0.3)
sound.play()
# generate food at random x, y.
food.generate_food(width, height)
# try generating the food at a position where blocks are not present.
while food_collides_block(food.get_rect(), blocks):
food.generate_food(width - food.size, height - food.size)
""" Draw """
game_display.fill((255, 255, 255))
showButton()
# draw the food and snake.
snake.draw(game_display, dirn, (0, 155, 0))
food.draw(game_display, (0, 255, 0))
# draw the blocks.
for block in blocks:
block.draw(game_display, (255, 0, 0))
# count and display score on screen
totalscore = total(score, world_num)
scorestr = 'Score: ' + str(totalscore)
font = pygame.font.SysFont(None, 30)
text = font.render(scorestr, True, (0, 0, 255))
game_display.blit(text, (0, 0, 20, 20))
pygame.display.update()
clock.tick(FPS)
pygame.quit()
quit()
intro()
gameLoop()
I'm working on python project right now using pygame library and I need help with this project I make. I want my tank to shoot bullets and so those bullets ricochet from the walls. What is the best way possible to do this?
I'm sorry that my code looks so messy, I've been watching different youtube tutorials and they all do differently.
Here is my code
import pygame
pygame.init()
# ======================= Variables =======================
# ------------------------ Screen -------------------------
screenWidth = 1060
screenHeight = 798
screenSize = (screenWidth, screenHeight)
display = pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption("Tank game")
bg = pygame.image.load("sprites/background/background1.png")
bg = pygame.transform.scale(bg, (screenWidth, screenHeight))
# ------------------------ Player -------------------------
# ------------------------ Enemy -------------------------
# ----------------------- Other ---------------------------
red = (155, 0, 0)
clock = pygame.time.Clock()
fps = 60
# ========================= Clases ========================
class player(pygame.sprite.Sprite):
def __init__(self, location, angle, vel, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("sprites/player/player_tank.png")
self.x = x
self.y = y
self.vel = vel
self.angle = angle
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
if self.angle == 360:
self.angle = 0
def rotate(self):
rot_image = pygame.transform.rotate(self.image, self.angle)
rot_rect = rot_image.get_rect(center=self.rect.center)
return rot_image, rot_rect
def moving_after_angle_change(self):
x = round(math.cos(math.radians(self.angle + 90)), 1) * self.vel
y = round(math.sin(math.radians(self.angle - 90)), 1) * self.vel
return x, y
class enemy(pygame.sprite.Sprite):
def __init__(self, x, y, width, height, end):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("sprites/enemy/enemy_tank.png")
self.x = x
self.y = y
self.width = width
self.height = height
self.end = end
self.path = [self.x, self.y, self.end]
self.vel = 5
def draw(self, display):
self.move()
display.blit(self.image, (self.x, self.y))
def move(self):
if self.vel > 0:
pass
# Bullet
bullet = pygame.image.load("sprites/bullet/bullet.png")
bullet = pygame.transform.scale(bullet, (16, 16))
bullet_x = 0
bullet_y = 480
bullet_x_change = 0
bullet_y_change = 10
bullet_state = 'ready'
# ======================= Functions =======================
def redrawGameWindow():
display.blit(bg, (0, 0))
display.blit(player_tank.image, player_tank.rect)
display.blit(enemy_tank.image, (enemy_tank.x, enemy_tank.y))
#display.blit(bullet, (player_tank.x + 160, player_tank.y + 100))
pygame.display.flip()
def fireBullet(x, y):
global bullet_state
bullet_state = 'fire'
display.blit(bullet, (x + 16, y + 10))
player_location = [70, 570]
player_angle = 270
player_angle_change = 0
player_vel = 0
player_x_change = 0
player_y_change = 0
player_tank_x_change_store = 0
player_tank_y_change_store = 0
run = True
while run:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
player_vel = 2
elif event.key == pygame.K_DOWN:
player_vel = -2
elif event.key == pygame.K_LEFT:
player_angle_change = 2
elif event.key == pygame.K_RIGHT:
player_angle_change = -2
if event.key == pygame.K_SPACE:
display.blit(bullet, (player_tank.x + 160, player_tank.y + 100))
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
player_vel = 0
elif event.key == pygame.K_DOWN:
player_vel = 0
elif event.key == pygame.K_LEFT:
player_angle_change = 0
elif event.key == pygame.K_RIGHT:
player_angle_change = 0
player_angle += player_angle_change
player_tank = player(player_location, player_angle, player_vel, player_x_change, player_y_change)
enemy_tank = enemy(800, 170, 64, 64, 700)
player_tank.image, player_tank.rect = player_tank.rotate()
player_tank.x_change, player_tank.y_change = player_tank.moving_after_angle_change()
player_tank_x_change_store += player_tank.x_change
player_tank_y_change_store += player_tank.y_change
player_tank.rect.centerx += player_tank_x_change_store
player_tank.rect.centery += player_tank_y_change_store
# Bullet movement
if bullet_state == "fire":
fireBullet(player_tank.x, bullet_y)
bullet_y -= bullet_y_change
redrawGameWindow()
pygame.quit()
quit()
One way to do this is to make the bullets velocity flip when it hits a wall. Now I'm assuming the walls are the edge of the screen so what you need to do is in the loop, check if the bullet is about to hit a wall (the edge of the screen) and if it is, flip its x_change and y_change. So something like this:
if bullet_y <= 0:
bullet_y_change *= -1
bullet_y = 0
if bullet_y >= screenHeight:
bullet_y_change *= -1
bullet_y = screenHeight
if bullet_x <= 0:
bullet_x_change *= -1
bullet_x = 0
if bullet_x >= screenWidth:
bullet_x_change *= 1
bullet_x = screenWidth
Here's a full example, based on an old answer:
import pygame
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((32, 32))
self.image.fill((0, 0, 0))
self.image.set_colorkey((0, 0, 0))
pygame.draw.polygon(self.image, pygame.Color('dodgerblue'), ((0, 0), (32, 16), (0, 32)))
self.org_image = self.image.copy()
self.angle = 0
self.direction = pygame.Vector2(1, 0)
self.rect = self.image.get_rect(center=(200, 200))
self.pos = pygame.Vector2(self.rect.center)
def update(self, events, dt):
for e in events:
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_SPACE:
self.groups()[0].add(Projectile(self.rect.center, self.direction.normalize()))
pressed = pygame.key.get_pressed()
if pressed[pygame.K_a]:
self.angle += 3
if pressed[pygame.K_d]:
self.angle -= 3
self.direction = pygame.Vector2(1, 0).rotate(-self.angle)
self.image = pygame.transform.rotate(self.org_image, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
class Projectile(pygame.sprite.Sprite):
def __init__(self, pos, direction):
super().__init__()
self.image = pygame.Surface((8, 8))
self.image.fill((0, 0, 0))
self.image.set_colorkey((0, 0, 0))
pygame.draw.circle(self.image, pygame.Color('orange'), (4, 4), 4)
self.rect = self.image.get_rect(center=pos)
self.direction = direction
self.pos = pygame.Vector2(self.rect.center)
self.lives = 15
def update(self, events, dt):
# Bounding box of the screen
screen_r = pygame.display.get_surface().get_rect()
# where we would move next
next_pos = self.pos + self.direction * dt
# we hit a hall
if not screen_r.contains(self.rect):
# after 15 hits, destroy self
self.lives -= 1
if self.lives == 0:
return self.kill()
# horizontal reflection
if next_pos.x > screen_r.right or next_pos.x < screen_r.left:
self.direction.x *= -1
# vertical reflection
if next_pos.y > screen_r.bottom or next_pos.y < screen_r.top:
self.direction.y *= -1
# move after applying reflection
next_pos = self.pos + self.direction * dt
# set the new position
self.pos = next_pos
self.rect.center = self.pos
def main():
pygame.init()
screen = pygame.display.set_mode((500, 500))
sprites = pygame.sprite.Group(Player())
clock = pygame.time.Clock()
dt = 0
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
sprites.update(events, dt)
screen.fill((30, 30, 30))
sprites.draw(screen)
pygame.display.update()
dt = clock.tick(60)
if __name__ == '__main__':
main()
See how using the Vector2 class makes this kind of tasks very easy to solve.
Also, look at the proper usage of the Sprite class. Each Sprite minds its own business: the Player class handles rotating the player and creating projectiles, Projectile handles moving the projectiles and bouncing of the wall.
I wrote simple snake game. Code here:
import pygame
import random
from collections import deque
import time
DISPLAY_WIDTH = 100
DISPLAY_HEIGHT = 100
HEAD_SIZE = 10
FOOD_SIZE = HEAD_SIZE
TAIL_SIZE = 5
BLACK = (0,0,0)
WHITE = (255,255,255)
ONE_MOVE = 5
pygame.init()
gameDisplay = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
pygame.display.set_caption("Snake")
clock = pygame.time.Clock()
class Snake:
def __init__(self):
self.x = 0
self.y = 0
self.snake_lenght = 0
self.tail = []
def draw_head(self):
pygame.draw.rect(gameDisplay, BLACK, [self.x, self.y, HEAD_SIZE, HEAD_SIZE])
def draw_tail(self):
self.tail.append([self.x, self.y])
for i in self.tail:
pygame.draw.rect(gameDisplay, BLACK, [int(i[0]), int(i[1]), TAIL_SIZE, TAIL_SIZE])
def rise(self):
foodx = random.randrange(ONE_MOVE, DISPLAY_WIDTH - ONE_MOVE, 5) # random food in a distance from the wall
foody = random.randrange(ONE_MOVE, DISPLAY_HEIGHT - ONE_MOVE, 5)
for i in self.tail:
if foodx == i[0] and foody == i[1]: # avoid food in tail
self.rise()
break
self.snake_lenght += 20
return foodx, foody, self.snake_lenght
def direction_of_movement(self, direction):
if direction == "turn_right":
return [ONE_MOVE, 0, 0, 0]
elif direction == "turn_left":
return [0, ONE_MOVE, 0, 0]
elif direction == "turn_down":
return [0, 0, ONE_MOVE, 0]
elif direction == "turn_up":
return [0, 0, 0, ONE_MOVE]
def crash(self): # restart game after failing
time.sleep(2)
self.game_loop()
def game_loop(self):
self.x = (DISPLAY_WIDTH * 0.5)
self.y = (DISPLAY_HEIGHT * 0.5)
start = 0
self.snake_lenght = 10 # reset snake's lenght after calling game_loop again
self.tail = deque([], maxlen=self.snake_lenght)
while True:
if start == 0: # start to move
speed = self.direction_of_movement("turn_right")
foodx, foody, self.snake_lenght = self.rise()
start += 1
for event in pygame.event.get(): # quit if exit pressed
if event.type == pygame.QUIT:
quit()
if event.type == pygame.KEYDOWN: # arrow navigation
if event.key == pygame.K_RIGHT:
speed = self.direction_of_movement("turn_right")
elif event.key == pygame.K_LEFT:
speed = self.direction_of_movement("turn_left")
elif event.key == pygame.K_DOWN:
speed = self.direction_of_movement("turn_down")
elif event.key == pygame.K_UP:
speed = self.direction_of_movement("turn_up")
# game logic
self.x += speed[0] #moving directions
self.x -= speed[1]
self.y += speed[2]
self.y -= speed[3]
if self.x < 0 or self.x + ONE_MOVE > DISPLAY_WIDTH: # hit into wall
self.crash()
elif self.y < 0 or self.y + ONE_MOVE > DISPLAY_HEIGHT:
self.crash()
for i in self.tail: # bite itself
if self.x == i[0]:
if self.y == i[1]:
self.crash()
if self.x == foodx and self.y == foody:
foodx, foody, self.snake_lenght = self.rise()
self.tail = deque(self.tail, maxlen=self.snake_lenght)
# draw
gameDisplay.fill(WHITE)
self.draw_head()
self.draw_tail()
pygame.draw.rect(gameDisplay, BLACK, [foodx, foody, FOOD_SIZE, FOOD_SIZE])
pygame.display.update()
clock.tick(10) # game speed
snake = Snake()
snake.game_loop()
In another file I'm importing whole class, adding constants and run it. In shortcut:
from snake_file import Snake
class Snake_for_AI(Snake):
def __init__(self):
pass
def trying(self):
print("hey")
thing = Snake_for_AI()
thing.trying()
Here is my question. It's never printing "hey". Moreover, it runs game_loop and starts the game when I create class object thing = Snake_for_AI, no need to call thing.game_loop(). Why?
Any code review is very appreciated too.
When importing, you will execute the two lines at the bottom of the file. If that is not the desired behavior, surround them as such:
if __name__ == "__main__":
snake = Snake()
snake.game_loop()
That will cause them to be interpreted only if you actually run that file.