I'm creating 2-player PONG game with pygame.I have my Racquets on both sides.
One of them move with W and S and another with UP and DOWN arrow.
I'm using this code to move Racquets:
chx = 0.051
chy = 0.051
def ychangeneg():
global y
if y <= 4:
return
else:
y -= chy
return
def ychangepos():
global y
if y >= 327:
return
else:
y += chy
return
def y1changeneg():
global y1
if y1 <= 4:
return
else:
y1 -= chy
return
def y1changepos():
global y1
if y1 >= 327:
return
else:
y1 += chy
return
while True:
for event in pygame.event.get():
keyQ = pygame.key.get_pressed()
if event.type == pygame.QUIT:
system("cls")
quit()
keyboard.add_hotkey("w",lambda:ychangeneg())
keyboard.add_hotkey("s",lambda:ychangepos())
keyboard.add_hotkey("up",lambda:y1changeneg())
keyboard.add_hotkey("down",lambda:y1changepos())
chy variable changes y of Racquet and moves it.But I have these problems:
When I start holding a key,Racquet starts moving with delay and then becomes faster
When I holding 2 key (W and UP arrow) at a same time, Racquets don't move
At first, I found some codes that using key= pygame.key.get_pressed() but when you hold a key with this code, It moves but not continuously.
Do not mix the pygame.key module with the python keyboard module.
See How can I make a sprite move when key is held down and that changes the y-coordinate, depending on the keys pressed:
def move_y(y, keys, up, down):
new_y = y + (keys[down] - keys[up]) * chy
return max(4, min(327, new_y))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
system("cls")
quit()
keyQ = pygame.key.get_pressed()
y = move_y(y, keyQ, pygame.K_w, pygame.K_s)
y1 = move_y(y1, keyQ, pygame.K_UP, pygame.K_DOWN)
Minimal example:
import pygame
pygame.init()
window = pygame.display.set_mode((400, 350))
clock = pygame.time.Clock()
paddle1 = pygame.Rect(10, 0, 10, 20)
paddle1.centery = window.get_rect().centery
paddle2 = pygame.Rect(380, 0, 10, 20)
paddle2.centery = window.get_rect().centery
chy = 10
def move_y(y, keys, up, down):
new_y = y + (keys[down] - keys[up]) * chy
return max(4, min(327, new_y))
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keyQ = pygame.key.get_pressed()
paddle1.y = move_y(paddle1.y, keyQ, pygame.K_w, pygame.K_s)
paddle2.y = move_y(paddle2.y, keyQ, pygame.K_UP, pygame.K_DOWN)
window.fill(0)
pygame.draw.rect(window, (255, 255, 255), paddle1)
pygame.draw.rect(window, (255, 255, 255), paddle2)
pygame.display.flip()
clock.tick(60)
pygame.quit()
exit()
I'd suggest not using the keyboard module. Instead look, which key is pressed by using pygame.key.get_pressed(). Check if the key is in there, and if so then change the coordinates.
somewhat like this:
pressed_keys = pygame.key.get_pressed()
if pressed_keys[pygame.UP]: # this evaluates to true if the up key is pressed
ychangeneg()
if pressed_keys[pygame.DOWN]:
ychangepos()
# and so on...
Related
I am trying to make a python program to draw a line and turn it into a circle with an animation using pygame, yet I haven't even gotten through the drawing-the-line code. I have noticed that python is changing the wrong or both items in a list that contains the starting point when the user presses down the left click, stored as the first item, and the current point of the user's mouse as the second.
This is generally what I want it to do: https://youtu.be/vlqZ0LubXCA
Here are the outcomes with and without the lines that update the 2nd item:
with:
without:
As you can see, or read in the descriptions, the line is necessary to cover the previous frame.
I have marked the lines that change the outcome with arrows:
import pygame, PIL, random
print('\n')
#data
bubbles = []
color_options = [[87, 184, 222]]
pressed = False
released = False
bubline_start = []
background = [50, 25, 25]
size = [500, 500]
#pygame
display = pygame.display.set_mode(size)
pygame.init()
#functions
def new_bub_color():
color_index = random.randint(0, len(color_options)-1)
lvl = random.randrange(85, 115)
bub_color = []
for val in color_options[color_index]:
bub_color.append(val*(lvl/100))
return bub_color
def bubble_line():
global display, pressed, bubline_start, released, bubbles, color_options
if len(bubbles) > 0:
if not bubbles[-1][0] == 0:
#first frame of click
bub_color = new_bub_color()
bubbles.append([0, bub_color, [bubline_start, list(pygame.mouse.get_pos())]])
pygame.draw.line(display, bub_color, bubline_start, pygame.mouse.get_pos())
else:
#draw after drags
pygame.draw.line(display, bubbles[-1][1], bubbles[-1][2][0], list(pygame.mouse.get_pos()))
bubbles[-1][2][1] = list(pygame.mouse.get_pos())# <-- HERE
else:
#first bubble
bub_color = new_bub_color()
bubbles.append([0, bub_color, [bubline_start, list(pygame.mouse.get_pos())]])
pygame.draw.line(display, bub_color, bubline_start, pygame.mouse.get_pos())
if released:
bubbles[-1][0] = 1
bubbles[-1][2][1] = list(pygame.mouse.get_pos())# <-- HERE
released = False
def cover_prev_frame():
global bubbles, background, size
min_pos = []
max_pos = []
for bubble in bubbles:
min_pos = bubble[2][0]
max_pos = bubble[2][0]
for point in bubble[2]:
#x min and max
if point[0] < min_pos[0]:
min_pos[0] = point[0]
elif point[0] > max_pos[0]:
max_pos[0] = point[0]
#y min and max
if point[1] < min_pos[1]:
min_pos[1] = point[1]
elif point[1] > max_pos[1]:
max_pos[1] = point[1]
max_pos = [max_pos[0]-min_pos[0]+1, max_pos[1]-min_pos[1]+1]
if type(background) == str:
#image background
later = True
elif type(background) == list:
#solid color background
pygame.draw.rect(display, background, pygame.Rect(min_pos, max_pos))
while True:
pygame.event.pump()
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.MOUSEBUTTONDOWN and not pressed:
bubline_start = list(pygame.mouse.get_pos())
pressed = True
elif event.type == pygame.MOUSEBUTTONUP and pressed:
pressed = False
released = True
cover_prev_frame()
if pressed or released:
bubble_line()
try:
pygame.display.update()
except:
break
if not bubbles[-1][0] == 0: is False as long as the mouse is not released. Therefore add many line segments, each starting at bubline_start and ending at the current mouse position.
You must redraw the scene in each frame. bubbles is a list of bubbles and each bubble has a list of points. Add a new point to the last bubble in the list while the mouse is held down. Start a new bubble when the mouse is pressed and end a bubble when it is released. This greatly simplifies your code.
Minimal example
import pygame, random
size = [500, 500]
pygame.init()
display = pygame.display.set_mode(size)
clock = pygame.time.Clock()
pressed = False
bubbles = []
background = [50, 25, 25]
run = True
while run:
clock.tick(100)
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.MOUSEBUTTONDOWN:
start_pos = list(event.pos)
bubble_color = pygame.Color(0)
bubble_color.hsla = (random.randrange(0, 360), 100, 50, 100)
bubbles.append((bubble_color, [start_pos]))
pressed = True
elif event.type == pygame.MOUSEMOTION and pressed:
new_pos = list(event.pos)
if len(bubbles[-1][1]) > 0 and bubbles[-1][1] != new_pos:
bubbles[-1][1].append(new_pos)
elif event.type == pygame.MOUSEBUTTONUP:
pressed = False
end_pos = list(event.pos)
if len(bubbles[-1][1]) > 0 and bubbles[-1][1] != end_pos:
bubbles[-1][1].append(list(event.pos))
display.fill(background)
for i, bubble in enumerate(bubbles):
if len(bubble[1]) > 1:
closed = not pressed or i < len(bubbles) - 1
pygame.draw.lines(display, bubble[0], closed, bubble[1], 3)
pygame.display.update()
pygame.quit()
For the animation I propose to create a class that represents a bubble and a method animate that slowly turns the polygon into a circle.
Minimal example
import pygame, random
size = [500, 500]
pygame.init()
display = pygame.display.set_mode(size)
clock = pygame.time.Clock()
class Bubble:
def __init__(self, start):
self.color = pygame.Color(0)
self.color.hsla = (random.randrange(0, 360), 100, 50, 100)
self.points = [list(start)]
self.closed = False
self.finished = False
def add_point(self, point, close):
self.points.append(list(point))
self.closed = close
if self.closed:
x_, y_ = list(zip(*self.points))
x0, y0, x1, y1 = min(x_), min(y_), max(x_), max(y_)
rect = pygame.Rect(x0, y0, x1-x0, y1-y0)
self.center = rect.center
self.radius = max(*rect.size) // 2
def animate(self):
if self.closed and not self.finished:
cpt = pygame.math.Vector2(self.center) + (0.5, 0.5)
self.finished = True
for i, p in enumerate(self.points):
pt = pygame.math.Vector2(p)
v = pt - cpt
l = v.magnitude()
if l + 0.5 < self.radius:
self.finished = False
v.scale_to_length(min(self.radius, l+0.5))
pt = cpt + v
self.points[i] = [pt.x, pt.y]
def draw(self, surf):
if self.finished:
pygame.draw.circle(surf, self.color, self.center, self.radius, 3)
elif len(self.points) > 1:
pygame.draw.lines(surf, self.color, self.closed, self.points, 3)
bubbles = []
pressed = False
background = [50, 25, 25]
run = True
while run:
clock.tick(100)
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.MOUSEBUTTONDOWN:
bubbles.append(Bubble(event.pos))
pressed = True
elif event.type == pygame.MOUSEMOTION and pressed:
bubbles[-1].add_point(event.pos, False)
elif event.type == pygame.MOUSEBUTTONUP:
bubbles[-1].add_point(event.pos, True)
pressed = False
for bubble in bubbles:
bubble.animate()
display.fill(background)
for bubble in bubbles:
bubble.draw(display)
pygame.display.update()
pygame.quit()
I was learning python and trying to make snake game using pygame library. I made a rectangle which moves using the pressing of keys but rather than moving one block it moves to the end of the block.
Whenever i press in any direction whether it be up , left, right, or down rather than moving 1 box size it moves to the end of the other direction
Could someone tell me why that happens.
import pygame
box_size = 50
num_box = 15
color1 = (169, 215, 81)
color2 = (169,250,81)
x = 0
y = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
break
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
if x < width - box_size:
x = x + box_size
if keys[pygame.K_LEFT]:
if x > 0:
x = x - box_size
if keys[pygame.K_UP]:
if y > 0:
y = y - box_size
if keys[pygame.K_DOWN]:
if y < height - box_size:
y = y + box_size
print(x,y)
for i in range(0,num_box):
if i %2 == 0:
for j in range(0,num_box):
if j%2 == 0:
pygame.draw.rect(win, color1, (box_size*j, box_size*i, box_size, box_size))
else:
pygame.draw.rect(win, color2, (box_size * j, box_size * i, box_size, box_size))
else:
for k in range(0,num_box):
if k%2 == 0:
pygame.draw.rect(win, color2, (box_size*k, box_size*i, box_size, box_size))
else:
pygame.draw.rect(win, color1, (box_size * k, box_size * i, box_size, box_size))
pygame.draw.rect(win, (0, 0, 250), (x, y, box_size, box_size))
# # rect(surface, color, (left, top, width, height))
pygame.display.update()
pass
See pygame.time.Clock.tick():
This method should be called once per frame.
Use pygame.time.Clock to control the frames per second and thus the game speed. The method tick() of a pygame.time.Clock object, delays the game in that way, that every iteration of the loop consumes the same period of time. e.g.:
clock = pygame.time.Clock()
while True:
clock.tick(100)
for event in pygame.event.get():
# [...]
If you want to move the object step by step you need to use KEYDOWN event instead of pygame.key.get_pressed():
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# INDENTATION
#-->|
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
if x < width - box_size:
x = x + box_size
if event.key == pygame.K_LEFT:
if x > 0:
x = x - box_size
if event.key == pygame.K_UP:
if y > 0:
y = y - box_size
if event.key == pygame.K_DOWN:
if y < height - box_size:
y = y + box_size
See How to get keyboard input in pygame? and How can I make a sprite move when key is held down.
pygame.key.get_pressed() returns a sequence 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.
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 like jumping or spawning a bullet or a step-by-step movement.
Im creating a snake Pygame with a menu and am fine tuning the bugs and such when I come across the error
IndexError: list index out of range
the error actually appears after I open the tab itself and move the cursor over it
I have a faint idea of what it actually means but I am quite new to python and coding in general so I would appreciate it if someone could explain and show a solution,
thank you very much and here is the code
import pygame
import sys
import random
import time
pygame.init()
WHITE = (255, 255, 255)
YELLOW = (255, 255, 102)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
DARKRED = (125, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
screenWidth = 800
screenHeight = 800
screen = pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption('Snake Game')
clock = pygame.time.Clock()
snakeBlock = 10
snakeSpeed = 15
fontTitle = pygame.font.SysFont("arial",100)
fontStyle = pygame.font.SysFont("ariel", 50)
scoreFont = pygame.font.SysFont("ariel", 35)
def score(score):
value = scoreFont.render(" Score: " + str(score), True, BLACK)
screen.blit(value, [50, 50])
def snake(snakeBlock, snake_list):
for x in snake_list:
pygame.draw.rect(screen, GREEN, [x[0], x[1], snakeBlock, snakeBlock])
def message(msg, colour):
msg = fontStyle.render(msg, True, BLACK)
screen.blit(msg, [screenWidth / 20, screenHeight / 2])
def gameLoop():
gameOver = False
gameEnd = False
instructions = False
game = True
intro = True
main = True
x1 = screenWidth / 2
y1 = screenHeight / 2
dx = 0
dy = 0
snakeList = []
snakeLength = 2
foodx = round(random.randrange(0, screenWidth - snakeBlock) / 10.0) * 10.0
foody = round(random.randrange(0, screenHeight - snakeBlock) / 10.0) * 10.0
def menu(titles):
buttonTitleFont = pygame.font.SysFont("arial", 52)
selection = []
rectWidth = 400
rectHeight = 60
x = int(screen.get_width()/2 - rectWidth/2)
y = 450
length = len(titles)
num = 0
hover = False
# creates the Rects (containers) for the buttons
for i in range (0,length,1):
choiceRect = pygame.Rect(x,y,rectWidth,rectHeight)
selection.append(choiceRect)
y += 100
#main loop in menu
menu = True
while menu:
for event in pygame.event.get():
if event.type == pygame.QUIT:
menu = False
pygame.quit()
sys.exit()
if event.type ==pygame.MOUSEMOTION: # if mouse moved
hover = False
mx, my = pygame.mouse.get_pos() # get the mouse position
for i in range (length):
if selection[i].collidepoint((mx,my)): # check if x,y of mouse is in a button
num = i
hover = True
if event.type == pygame.MOUSEBUTTONDOWN and hover == True: #if mouse is in button
menu = False # and has been clicked
# draw all buttons
for choice in selection:
pygame.draw.rect(screen,WHITE,choice,0)
# redraw selected button in another colour
pygame.draw.rect(screen,GREEN,selection[num],0)
# draw all the titles on the buttons
x = int(screen.get_width()/2 - 150)
y = 450
for i in range(0,length,1):
buttonTitle = buttonTitleFont.render(titles[i],True,BLACK)
screen.blit(buttonTitle,(x,y))
y += 100
pygame.display.update()
return num
while main:
for event in pygame.event.get(): # check for any events (i.e key press, mouse click etc.)
if event.type ==pygame.QUIT: # check to see if it was "x" at top right of screen
main = False # set the "main" variable to False to exit while loop
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
main = False
intro = False
screen.fill(BLACK)
menuMain = ["Launch", "Instructions","QUIT"]
mainMenu = True
mainInt = True
while mainInt:
for event in pygame.event.get():
if event.type == pygame.QUIT:
main = False
intro = False
mainInt = False
screen.fill(BLACK)
#Centers the rendered tiles
textTitle = fontTitle.render("Snake", True, GREEN )
textW = textTitle.get_width()
textH = textTitle.get_height()
xTitle = int(screenWidth/2 - textW/2)
yTitle = int(screenHeight/4 - textH/2)
screen.blit(textTitle, (xTitle,yTitle))
pygame.display.update()
# in the intro, this asks the user where they would like to go
if mainMenu ==True:
choose = menu(menuMain)
if choose == 0:
menu = False
intro = False
mainInt = False
mainMenu = False
game = True
screen.fill(BLACK)
elif choose ==1:
menu = False
instructions = True
mainMenu = False
screen.fill(BLACK)
pygame.display.update()
else:
menu = False
main = False
intro = False
mainInt = False
mainMenu = False
while game:
if gameOver == True:
game = False
while gameEnd == True:
screen.fill(DARKRED)
message("You Lost! Press C to Play Again or Q to Quit", RED)
score(snakeLength - 1)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameOver = True
gameEnd = False
if event.key == pygame.K_c:
gameLoop()
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameOver = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
dx = -snakeBlock
dy = 0
elif event.key == pygame.K_RIGHT:
dx = snakeBlock
dy = 0
elif event.key == pygame.K_UP:
dx = 0
dy = -snakeBlock
elif event.key == pygame.K_DOWN:
dx = 0
dy = snakeBlock
if x1 >= screenWidth or x1 < 0 or y1 >= screenHeight or y1 < 0:
gameEnd = True
x1 += dx
y1 += dy
screen.fill(WHITE)
pygame.draw.rect(screen, RED, [foodx, foody, snakeBlock, snakeBlock])
snakeHead = []
snakeHead.append(x1)
snakeHead.append(y1)
snakeList.append(snakeHead)
if len(snakeList) > snakeLength:
del snakeList[0]
for x in snakeList[:-1]:
if x == snakeHead:
gameEnd = True
snake(snakeBlock, snakeList)
score(snakeLength - 1)
pygame.display.update()
if x1 == foodx and y1 == foody:
foodx = round(random.randrange(0, screenWidth - snakeBlock) / 10.0) * 10.0
foody = round(random.randrange(0, screenHeight - snakeBlock) / 10.0) * 10.0
snakeLength += 1
clock.tick(snakeSpeed)
pygame.quit()
quit()
gameLoop()
I see that in your code, you're referencing selection[some_index] multiple times. If you look into what selection actually is, you'll find that it's an array with one rectangle object inside of it:
[<rect(200, 450, 400, 60)>]
This rectangle never changes, so I suggest referencing it directly by calling
selection[0]
For example, here is the snippet of code that's giving you the error.
for i in range (length):
if selection[i].collidepoint((mx,my)): # check if x,y of mouse is in a button
num = i
hover = True
Because selection is an array with one element that never changes, you get an Index out of range error after the first iteration of your for loop. Perhaps this looks familiar:
IndexError: list index out of range
What you can do to fix this is get rid of the loop (because it's unnecessary - you shouldn't be looping through indices if there's only one rectangle in the selection list!) and extracting the rectangle at the 0-th index.
if selection[0].collidepoint((mx,my)): # check if x,y of mouse is in a button
num = i
hover = True
This isn't the only bug I ran into in your code, but I believe this will help you on your way!
I am creating a basic game. I have mainly two codes for :(i) Menu (ii) Basic Game. I want to run 'while game_over' loop after clicking 'start' button. But the code does not respond after I click 'start' button.
import pygame
import random
import sys
pygame.init()
w=800
h=600
yellow=(255,255,0)
player_size=25
player_pos=[w/2,h-(2*player_size)]
enemy_size=25
enemy_pos=[random.randint(0,w-enemy_size),0]
enemy_list=[ ]
Menu_bg_color=(34,139,34)
red=(255,0,0)
blue=(0,0,125)
bright_blue=(0,0,255)
font_size=35
b1_pos=[w/2-50,h/2]
b1_size=[105,50]
bg_color=(0,0,0)
screen=pygame.display.set_mode((w,h))
speed=10
score=0
clock=pygame.time.Clock()
myFont=pygame.font.SysFont("monospace",font_size)
Menu_myFont=pygame.font.SysFont("freesansbold.tff",font_size)
running=True
Menu_running=True
#GAME CODE
def GameCode():
global game_over
global score
global speed
global player_pos
def set_level(score,speed):
if score<10:
speed=5
elif score<20:
speed=6
elif score<30:
speed=8
elif score<40:
speed=10
elif score<50:
speed=13
elif score<200:
speed=15
else:
speed=20
return speed
def drop_enemies(enemy_list):
delay=random.random()
if len(enemy_list)<6 and delay<0.1:
x_pos=random.randint(0,w-enemy_size)
y_pos=0
enemy_list.append([x_pos,y_pos])
def draw_enemies(enemy_list):
for enemy_pos in enemy_list:
pygame.draw.rect(screen,blue, (enemy_pos[0],enemy_pos[1],enemy_size,enemy_size))
def update_enemy_pos(enemy_list,score):
for idx,enemy_pos in enumerate(enemy_list):
if enemy_pos[1]>=0 and enemy_pos[1]<h:
enemy_pos[1]+=speed
else:
enemy_list.pop(idx)
score+=1
return score
def detect_collision(player_pos,enemy_pos):
p_x=player_pos[0]
p_y=player_pos[1]
e_x=enemy_pos[0]
e_y=enemy_pos[1]
if (e_x>=p_x and e_x<(p_x+player_size)) or (p_x>=e_x and p_x<(e_x+enemy_size)):
if (e_y>=p_y and e_y<(p_y+player_size)) or (p_y>=e_y and p_y<(e_y+enemy_size)):
return True
return False
def collision_check(enemy_list,player_pos):
for enemy_pos in enemy_list:
if detect_collision(enemy_pos,player_pos):
return True
return False
while game_over==False:
for event in pygame.event.get():
if event.type==pygame.QUIT:
sys.exit()
if event.type==pygame.KEYDOWN:
x=player_pos[0]
y=player_pos[1]
if event.key==pygame.K_LEFT:
x-=player_size
elif event.key==pygame.K_UP:
y-=player_size
elif event.key==pygame.K_RIGHT:
x+=player_size
elif event.key==pygame.K_DOWN:
y+=player_size
player_pos=[x,y]
screen.fill(bg_color)
#screen.blit(road,(0,0))
drop_enemies(enemy_list)
score=update_enemy_pos(enemy_list,score)
speed=set_level(score,speed)
text='Your Score is:' + str(score)
label=myFont.render(text,1,yellow)
screen.blit(label,(w/2,h-40))
if collision_check(enemy_list,player_pos):
game_over=True
break
draw_enemies(enemy_list)
pygame.draw.rect(screen,red,(player_pos[0],player_pos[1],player_size,player_size))
clock.tick(30)
pygame.display.update()
pygame.display.flip()
#MENU CODE
def MenuCode():
global game_over
def button(b1_pos,b1_size):
mouse_pos=pygame.mouse.get_pos()
click=pygame.mouse.get_pressed()
if (b1_pos[0]<mouse_pos[0]<(b1_pos[0]+b1_size[0])) and (b1_pos[1]<mouse_pos[1]<(b1_pos[1]+b1_size[1])):
pygame.draw.rect(screen,bright_blue,(b1_pos[0],b1_pos[1],b1_size[0],b1_size[1]))
if click[0]==1:
game_over=False
else:
pygame.draw.rect(screen,blue,(b1_pos[0],b1_pos[1],b1_size[0],b1_size[1]))
text='START'
label=Menu_myFont.render(text,1,red)
screen.blit(label,(w/2-38,h/2+5))
Menu_running=True
while Menu_running:
for event in pygame.event.get():
if event.type==pygame.QUIT:
sys.exit()
screen.fill(Menu_bg_color)
button(b1_pos,b1_size)
#button(b1_pos,b1_size,'quit')
pygame.display.update()
clock.tick(30)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
break;
screen.fill(bg_color)
if MenuCode():
if game_over==False:
GameCode()
clock.tick(30)
pygame.display.update()
Here's a substantially revised version of your code that doesn't have the problem. I have revised the code so it closely adheres to the PEP 8 - Style Guide for Python Code guidelines and also eliminated many of the global variables you had by making them local to the function that uses them.
One of the primary cosmetic things I did was determine which of the globals were unchanging constants and which were variables whose values actually changed. After doing that, I changed the names of the constant ones to all UPPERCASE (as per PEP 8) and moved those with varying values to inside whichever function was actually using them.
The most extensive changes were made to the menu handling function — now named menu_code() — which was probably the main source of your problems. To help facilitate the rewrite, I've added a MenuButton class to encapsulate their behavior to a large degree and reduce repetitious code.
Note that there may be problems with the game_code() function because because I didn't attempted to optimize, test, or debug it.
Hopefully this will provide you with a good base upon which to further develop the game. I strongly suggest you read and start following PEP 8.
import random
import pygame as pyg
W, H = 800, 600
RED = (255, 0, 0)
BLUE = (0, 0, 125)
BRIGHT_BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
PLAYER_SIZE = 25
ENEMY_SIZE = 25
FONT_SIZE = 35
BG_COLOR = BLACK
FPS = 30
START, QUIT = 0, 1 # Button selection codes returned by menu_code()
pyg.init()
screen = pyg.display.set_mode((W, H))
pyg.display.set_caption('Basic Game')
clock = pyg.time.Clock()
game_font = pyg.font.SysFont("monospace", FONT_SIZE)
menu_font = pyg.font.SysFont("freesansbold.ttf", FONT_SIZE)
def game_code():
enemy_pos = [random.randint(0, W-ENEMY_SIZE), 0]
enemy_list = []
game_over = False
player_pos = [W/2, H - 2*PLAYER_SIZE]
score = 0
speed = 10
def get_speed(score):
if score < 10:
speed = 5
elif score < 20:
speed = 6
elif score < 30:
speed = 8
elif score < 40:
speed = 10
elif score < 50:
speed = 13
elif score < 200:
speed = 15
else:
speed = 20
return speed
def drop_enemies(enemy_list):
delay = random.random()
if len(enemy_list) < 6 and delay < 0.1:
x_pos = random.randint(0, W-ENEMY_SIZE)
y_pos = 0
enemy_list.append([x_pos, y_pos])
def draw_enemies(enemy_list):
for enemy_pos in enemy_list:
pyg.draw.rect(screen, BLUE,
(enemy_pos[0], enemy_pos[1], ENEMY_SIZE, ENEMY_SIZE))
def update_enemy_pos(enemy_list, score):
for idx, enemy_pos in enumerate(enemy_list):
if enemy_pos[1] >= 0 and enemy_pos[1] < H:
enemy_pos[1] += speed
else:
enemy_list.pop(idx)
score += 1
return score
def detect_collision(player_pos, enemy_pos):
p_x, p_y = player_pos
e_x, e_y = enemy_pos
if ((e_x >= p_x and e_x < (p_x + PLAYER_SIZE))
or (p_x >= e_x and p_x < (e_x + ENEMY_SIZE))):
if ((e_y >= p_y and e_y < (p_y+PLAYER_SIZE))
or (p_y >= e_y and p_y < (e_y + ENEMY_SIZE))):
return True
return False
def collision_check(enemy_list, player_pos):
for enemy_pos in enemy_list:
if detect_collision(enemy_pos, player_pos):
return True
return False
while not game_over:
for event in pyg.event.get():
if event.type == pyg.QUIT:
game_over = True
break
if event.type == pyg.KEYDOWN:
x = player_pos[0]
y = player_pos[1]
if event.key == pyg.K_LEFT:
x -= PLAYER_SIZE
elif event.key == pyg.K_UP:
y -= PLAYER_SIZE
elif event.key == pyg.K_RIGHT:
x += PLAYER_SIZE
elif event.key == pyg.K_DOWN:
y += PLAYER_SIZE
player_pos = [x, y]
screen.fill(BG_COLOR)
drop_enemies(enemy_list)
score = update_enemy_pos(enemy_list, score)
speed = get_speed(score)
text = 'Your Score is:' + str(score)
label = game_font.render(text, 1, YELLOW)
screen.blit(label, (W/2, H-40))
if collision_check(enemy_list, player_pos):
game_over = True
break
draw_enemies(enemy_list)
pyg.draw.rect(screen, RED,
(player_pos[0], player_pos[1], PLAYER_SIZE, PLAYER_SIZE))
clock.tick(FPS)
pyg.display.update()
# pyg.display.flip() # Don't do both update() and flip().
class MenuButton:
def __init__(self, text, value, rect):
self.text = text
self.value = value
self.rect = rect
def draw(self):
# Background color determined by whether mouse is positioned over label.
mouse_pos = pyg.mouse.get_pos()
fg_color = RED
bg_color = BRIGHT_BLUE if self.rect.collidepoint(mouse_pos) else BLUE
pyg.draw.rect(screen, bg_color, self.rect)
pyg.draw.rect(screen, YELLOW, self.rect, 1) # Draw a border.
label = menu_font.render(self.text, 1, fg_color)
# Center lable text inside its rectangle.
txw, txh = menu_font.size(self.text)
screen.blit(label, (self.rect.left + txw/2, self.rect.top + txh/2))
def menu_code():
MENU_BG_COLOR = (34, 139, 34)
LABEL_SIZE = LABEL_WIDTH, LABEL_HEIGHT = (105, 50)
B1_RECT = pyg.Rect((W/2 - LABEL_WIDTH/2, H/2 - LABEL_HEIGHT/2), LABEL_SIZE)
B2_RECT = pyg.Rect((W/2 - LABEL_WIDTH/2, H/2 + LABEL_HEIGHT/2), LABEL_SIZE)
MENU_BUTTONS = [MenuButton('Start', START, B1_RECT),
MenuButton('Quit', QUIT, B2_RECT)]
choice = None
while choice is None:
screen.fill(MENU_BG_COLOR)
for button in MENU_BUTTONS:
button.draw()
for event in pyg.event.get():
if event.type == pyg.QUIT:
choice = QUIT
# Handle left mouse button clicks.
if event.type == pyg.MOUSEBUTTONDOWN and event.button == 1:
for button in MENU_BUTTONS:
if button.rect.collidepoint(event.pos):
choice = button.value
break
pyg.display.update()
clock.tick(FPS)
return choice
# Main loop.
running = True
while running:
for event in pyg.event.get():
if event.type == pyg.QUIT:
running = False
break;
screen.fill(BG_COLOR)
choice = menu_code()
if choice == START:
game_code()
if choice == QUIT:
running = False
pyg.display.update()
clock.tick(FPS)
I am trying to find a way to get the rotation of the ship and apply it to the beam so that it will travel in the direction it was shot in.. I really have no idea how I would do this but here is my code: Please excuse the messiness of it, I put comments in so you know whats what.
import sys, pygame, math, time;
from pygame.locals import *;
spaceship = ('spaceship.png')
mouse_c = ('crosshair.png')
backg = ('background.jpg')
fire_beam = ('beams.png')
pygame.init()
screen = pygame.display.set_mode((800, 600))
bk = pygame.image.load(backg).convert_alpha()
mousec = pygame.image.load(mouse_c).convert_alpha()
space_ship = pygame.image.load(spaceship).convert_alpha()
f_beam = pygame.image.load(fire_beam).convert_alpha()
f_beam = pygame.transform.scale(f_beam, (50, 50))
f_beam_rect = f_beam.get_rect()
clock = pygame.time.Clock()
pygame.mouse.set_visible(False)
space_ship_rect = space_ship.get_rect()
space_ship_rect.centerx = 375
space_ship_rect.centery = 300
speed = 3.5
pressed_down = 0
while True:
clock.tick(60)
screen.blit(bk, (0, 0))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONDOWN and event.button == 3:
pressed_down = 1
elif event.type == MOUSEBUTTONUP:
pressed_down = 0
if pressed_down == 1:
x, y = pygame.mouse.get_pos()
x1, y1 = x - space_ship_rect.x, y - space_ship_rect.y
angle = math.atan2(y1, x1)
dx = speed*math.cos(angle)
dy = speed*math.sin(angle)
movex = space_ship_rect.centerx = space_ship_rect.centerx + dx#ship x
movey = space_ship_rect.centery = space_ship_rect.centery + dy#ship y
if event.type == MOUSEMOTION:
x1, y1 = pygame.mouse.get_pos()
x2, y2 = space_ship_rect.x, space_ship_rect.y
dx, dy = x2 - x1, y2 - y1
rads = math.atan2(dx, dy)
degs = math.degrees(rads)
display_s = pygame.transform.rotate(space_ship, (degs))#rotation of ship
if event.type == MOUSEBUTTONDOWN and event.button == 1:
#Is it possible for me to get the degree rotation of the space_ship and apply it to here so the beam will travel in the direction it was shot in?
screen.blit(display_s, (space_ship_rect.centerx, space_ship_rect.centery))
pos = pygame.mouse.get_pos()
screen.blit(mousec, (pos))
pygame.display.update()
I see you have problem with ship rotation.
If you create rotated spaceship display_s you get image with different size than space_ship size so you have to get display_s rectangle and assign spaceship center to display_s center.
display_s_rect = display_s.get_rect( center=spaceship_rect.center)
Now you have to use display_s_rect to display display_s
screen.blit(display_s, display_s_rect)
By the way:
blit() expect position where to put left top corner of blited image on screen.
With
screen.blit(display_s, (space_ship_rect.centerx, space_ship_rect.centery))
left top corner of display_s will be put in (space_ship_rect.centerx, space_ship_rect.centery) but I think you want to put display_s center in (space_ship_rect.centerx, space_ship_rect.centery)
Assign center values (as before) to (space_ship_rect.centerx, space_ship_rect.centery) but use (space_ship_rect.x, space_ship_rect.y) in blit().
You can use space_ship_rect in place of (space_ship_rect.x, space_ship_rect.y) in blit() with the same result.
I think you have the same problem with mousec position in blit().
Get mousec rectangle, assign mouse position to rectangle center and than use rectangle x,y to blit.
mousec_rect = mousec.get_rect( center = pygame.mouse.get_pos() )
screen.blit(mousec, mousec_rect)
EDIT:
your mainloop after my modification - now ship is rotate as it should
display_s = space_ship # default value at start when ship wasn't rotate
while True:
clock.tick(60)
screen.blit(bk, (0, 0))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONDOWN and event.button == 3:
pressed_down = 1
elif event.type == MOUSEBUTTONUP:
pressed_down = 0
if pressed_down == 1:
x, y = pygame.mouse.get_pos()
x1, y1 = x - space_ship_rect.x, y - space_ship_rect.y
angle = math.atan2(y1, x1)
dx = speed*math.cos(angle)
dy = speed*math.sin(angle)
movex = space_ship_rect.centerx = space_ship_rect.centerx + dx#ship x
movey = space_ship_rect.centery = space_ship_rect.centery + dy#ship y
if event.type == MOUSEMOTION:
x1, y1 = pygame.mouse.get_pos()
x2, y2 = space_ship_rect.centerx, space_ship_rect.centery
dx, dy = x2 - x1, y2 - y1
rads = math.atan2(dx, dy)
degs = math.degrees(rads)
display_s = pygame.transform.rotate(space_ship, (degs))#rotation of ship
display_s_rect = display_s.get_rect(center = space_ship_rect.center)
if event.type == MOUSEBUTTONDOWN and event.button == 1:
#Is it possible for me to get the degree rotation of the space_ship and apply it to here so the beam will travel in the direction it was shot in?
pass
screen.blit(display_s, display_s_rect)
#screen.blit(display_s, space_ship_rect)
pos = pygame.mouse.get_pos()
mousec_rect = mousec.get_rect(centerx=pos[0], centery=pos[1])
screen.blit(mousec, mousec_rect )
pygame.display.update()
Before the While Loop:
beam_speed=<somevalue>
f_beam_rect=space_ship_rect #initialise beam position
fired=False #check if beam is fired or not
Inside While Loop
##If beam is fired(right click) blit images through-out the path
if fired:
b_angle = math.atan2(by1, bx1)
bdx = beam_speed*math.cos(b_angle)
bdy = beam_speed*math.sin(b_angle)
f_beam_rect.centerx = f_beam_rect.centerx + bdx
f_beam_rect.centery = f_beam_rect.centery + bdy
screen.blit(f_beam,f_beam_rect)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
###If mouse is clicked then find the direction (mouse position and spaceship)
elif event.type == MOUSEBUTTONDOWN and event.button == 1:
bx, by = pygame.mouse.get_pos()
bx1, by1 = bx - space_ship_rect.x, by - space_ship_rect.y
fired=True
Now you can make a function which checks that beam collides with enemy objects and if True then stop blitting both the beam and that object.
Also reset the variable fired=False and reset beam position to start from spaceship again f_beam_rect=space_ship_rect