i'm making a game but when i hit the horizontal and vertical keys at the same time or pressed fast enough, my snake go backwards, which will make a game over screen happen if it's longer then 2 blocks.
I tried making a long if statement. And cleaned up the code.
import pygame
import os
import sys
pygame.mixer.pre_init()
pygame.mixer.init(44100, 16, 2, 262144)
pygame.init()
from pygame.locals import*
import cv2
import time
import random
import pickle
import shutil
dw = 1280
dh = 720
at = 40
bs = 20
screen = pygame.display.set_mode((dw, dh))
clock = pygame.time.Clock()
def pause():
paused = True
while paused:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
paused = False
elif event.key == pygame.K_SPACE:
menu(1)
screen.fill(white)
mts("Paused", black, -100, 100)
mts("Press esc to go back to the game or press space to go back to the menu", black, 25, 45)
pygame.display.update()
clock.tick(60)
#define the apple to spawn in a random place
def randAppleGen():
randAppleX = random.randrange(0, dw-at, bs)
randAppleY = random.randrange(0, dh-at, bs)
return randAppleX,randAppleY
def snake(bs, sl):
for XnY in sl:
pygame.draw.rect(screen, Dgreen, [XnY[0],XnY[1],bs,bs])
def gameLoop():
global at
global bs
hs = pickle.load( open( os.getenv('APPDATA')+str('/Snake Universe/h.SNUN'), "rb" ) )
gameExit = False
gameOver = False
gameHack = False
Speed = 20
lead_x = dw/2
lead_y = dh/2
lead_x_change = 0
lead_y_change = 0
pygame.mixer.music.load(os.path.join(os.getcwd(), 'Sounds', 'music1.ogg'))
pygame.mixer.music.play(-1)
slist = []
sl = 0
if sl > 2304:
gameHack = True
randAppleX,randAppleY = randAppleGen()
while not gameExit:
while gameOver == True:
screen.fill(white)
mts("Game over", red, -50,100)
mts("Press enter to play again or press space to go back to the menu", black, 50,50)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameOver = False
gameExit = True
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_KP_ENTER or event.key==pygame.K_RETURN:
gameLoop()
if event.key == pygame.K_SPACE:
gameExit = False
gameOver = False
menu(1)
while gameHack == True:
pygame.mixer.music.stop()
screen.fill(white)
mts("Hacked", red, -50,100)
mts("You hacked or exploit the game, press enter to quit the game", black, 50,50)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameOver = False
gameExit = True
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_KP_ENTER or event.key==pygame.K_RETURN:
pygame.quit()
sys.exit()
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT and lead_x_change != bs:
lead_x_change = -bs
lead_y_change = 0
elif event.key == pygame.K_RIGHT and lead_x_change != -bs:
lead_x_change = bs
lead_y_change = 0
elif event.key == pygame.K_UP and lead_y_change != bs:
lead_y_change = -bs
lead_x_change = 0
elif event.key == pygame.K_DOWN and lead_y_change != -bs:
lead_y_change = bs
lead_x_change = 0
elif event.key == pygame.K_ESCAPE:
pause()
elif event.key == pygame.K_s and Speed >= 10 and Speed < 60:
Speed += 10
clock.tick(Speed)
elif event.key == pygame.K_d and Speed <= 60 and Speed > 10:
Speed -= 10
clock.tick(Speed)
if not pygame.Rect(0, 0, dw, dh).contains(lead_x, lead_y, bs, bs):
gameOver = True
lead_x += lead_x_change
lead_y += lead_y_change
screen.fill(white)
#draw the apple
apple = pygame.draw.rect(screen, red, [randAppleX,randAppleY,at,at])
sh = []
sh.append(lead_x)
sh.append(lead_y)
slist.append(sh)
snake(bs, slist)
if len(slist) > sl:
del slist[0]
for eachSegment in slist[:-1]:
if eachSegment == sh:
gameOver = True
score(sl)
highscore(hs)
if sl > hs:
hs += 1
os.remove( os.getenv('APPDATA')+str('/Snake Universe/h.SNUN') )
pickle.dump( sl, open( os.getenv('APPDATA')+str('/Snake Universe/h.SNUN'), "wb" ) )
hs = pickle.load( open( os.getenv('APPDATA')+str('/Snake Universe/h.SNUN'), "rb" ) )
pygame.display.update()
#make the apple spawn
if lead_x > randAppleX and lead_x < randAppleX + at or lead_x + bs > randAppleX and lead_x + bs < randAppleX + at:
if lead_y > randAppleY and lead_y < randAppleY + at:
randAppleX,randAppleY = randAppleGen()
sl += 1
elif lead_y + bs > randAppleY and lead_y + bs < randAppleY + at:
randAppleX,randAppleY = randAppleGen()
sl += 1
clock.tick(Speed)
pygame.quit()
quit()
I expected it to not go backwards, even though there's a code for it. I still go backwards. How do you fix it?
The issue occurs, because the events are handled in a loop:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
# [...]
Lets assume the snake moves to the left and lead_x_change == -bs respectively lead_y_change == 0. If (e.g.) pygame.K_UP is pressed and the following condition is fulfilled:
elif event.key == pygame.K_UP and lead_y_change != bs:
This causes that the movement state changes to lead_x_change = 0 and lead_y_change = -bs.
If the pygame.K_RIGHT was pressed a bit later, but fast enough to be handled in the same frame of the main loop, then it is handled in the event loop, one pass later. This causes that the following condition is fulfilled, too:
elif event.key == pygame.K_RIGHT and lead_x_change != -bs:
Now the movement state changes to lead_x_change = bs and lead_y_change = 0. It seems, that the snake turned by 180 degrees. Indeed it change the direction from left to upward and from upwards to right in one frame (in one pass of the main loop, but 2 passes of the event loop).
Fortunately the issue can be solved with ease. Just copy the values of lead_x_change and lead_y_change before the event loop and use the copies to evaluate the movement conditions in the event loop.
Note the conditions have to check against the state of lead_x_change and lead_y_change, which they had have at the begin of the frame:
prev_x, prev_y = lead_x_change, lead_y_change
for event in pygame.event.get():
# [...]
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT and prev_x != bs:
lead_x_change, lead_y_change = -bs, 0
elif event.key == pygame.K_RIGHT and prev_x != -bs:
lead_x_change, lead_y_change = bs, 0
elif event.key == pygame.K_UP and prev_y != bs:
lead_x_change, lead_y_change = 0, -bs
elif event.key == pygame.K_DOWN and prev_y != -bs:
lead_x_change, lead_y_change = 0, bs
# [...]
Related
I am writing my first pygame script, but the K_SPACE event does not work. When the script is run, nothing happens when the space bar is pressed. I have changed K_SPACE to K_LEFT and K_LSHIFT and they work absolutely fine, so I don't think the error is in the code itself?
The Input is mid-way through the code but I wanted to include it all to ensure there were no issues above which were causing it.
Any ideas?
import pygame
import random
pygame.init()
screen = pygame.display.set_mode((800,600))
pygame.display.set_caption("Space Invaders")
icon = pygame.image.load('spaceship.png')
pygame.display.set_icon(icon)
background = pygame.image.load('space.jpg')
playerImg = pygame.image.load('battleship.png')
playerX = 370
playerY = 480
playerX_change = 0
enemy1Img = pygame.image.load('alien.png')
enemy1X = random.randint(0,800)
enemy1Y = random.randint(50,150)
enemy1X_change = 0.1
enemy1Y_change = 40
laserImg = pygame.image.load('laser.png')
laserX = 0
laserY = 480
laserX_change = 0
laserY_change = 0.5
laser_state = "ready"
def player(x, y):
screen.blit(playerImg, (playerX,playerY))
def enemy1(x, y):
screen.blit(enemy1Img, (enemy1X, enemy1Y))
def fire_laser(x, y):
global laser_state
laser_state = "fire"
screen.blit(laserImg, (x+30, y+10))
running = True
while running:
screen.fill((0, 0, 0))
screen.blit(background, (0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
playerX_change = -0.1
elif event.key == pygame.K_RIGHT:
playerX_change = 0.1
elif event.key == pygame.K_SPACE:
if laser_state == 'ready':
laserX = playerX
fire_laser(laserX, laserY)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
playerX_change = 0
playerX += playerX_change
if playerX <= 0:
playerX = 0
if playerX >= 736:
playerX = 736
enemy1X += enemy1X_change
if enemy1X <= 0:
enemy1X_change = 0.1
enemy1Y += enemy1Y_change
elif enemy1X >= 736:
enemy1X_change = -0.1
enemy1Y += enemy1Y_change
if laserY <= 0:
laserY = 480
laser_state = 'ready'
if laser_state == "fire":
fire_laser(laserX,laserY)
laserY -= laserY_change
player(playerX, playerY)
enemy1(enemy1X, enemy1Y)
pygame.display.update()
I can reproduce the issue with your orignal code.
It's a matter of Indentation. You have to handle the events in the event loop not after the event loop.
Move the event handling in the event loop:
running = True
while running:
screen.fill((0, 0, 0))
screen.blit(background, (0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# INDENTATION
#-->|
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
playerX_change = -0.1
elif event.key == pygame.K_RIGHT:
playerX_change = 0.1
elif event.key == pygame.K_SPACE:
if laser_state == 'ready':
laserX = playerX
fire_laser(laserX, laserY)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
playerX_change = 0
import pygame, sys
pygame.init()
pygame.display.set_caption("test 1")
#main Variables
clock = pygame.time.Clock()
window_size = (700, 700)
screen = pygame.display.set_mode(window_size, 0, 32)
#player variables
playerx = 150
playery = -250
player_location = [playerx, playery]
player_image = pygame.image.load("player/player.png").convert_alpha()
player_rect = player_image.get_rect(center = (80,50))
#button variables
move_right = False
move_left = False
move_up = False
move_down = False
while True:
screen.fill((4, 124, 32))
screen.blit(player_image, player_location, player_rect)
if move_right == True:
playerx += 4
if move_left == True:
playerx -= 4
if move_up == True:
playery -= 4
if move_down == True:
playery += 4
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_d:
move_right = True
if event.key == pygame.K_a:
move_left = True
if event.key == pygame.K_w:
move_up = True
if event.key == pygame.K_s:
move_down = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_d:
move_right = False
if event.key == pygame.K_a:
move_left = False
if event.key == pygame.K_w:
move_up = False
if event.key == pygame.K_s:
move_down = False
pygame.display.update()
clock.tick(120)
I cant get it to work. I pressed the button but it wont go up or down. It worked well when i used no rectangle for the player. I wanter so i can move the character up and down in the y axis also. I just started to learn how to use PyGame so please help me thanks.
As you move the player, you change the playerx and playery variables. However, the player id drawn to the position that is stored in player_location. You must update player_location before drawing the player:
while True:
screen.fill((4, 124, 32))
player_location = [playerx, playery]
screen.blit(player_image, player_location, player_rect)
# [...]
Note that you don't need player_location at all. Draw the player at [playerx, playery]:
while True:
screen.fill((4, 124, 32))
screen.blit(player_image, [playerx, playery], player_rect)
I got this far and it kind of got all confusing and I can't figure out one simple problem with the code.
while not gameExit:
while gameOver == True:
pygame.display.flip()
gameDisplay.fill(white)
display_message("OVER. C to continue, Q to quit", red)
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameOver = False
gameExit = True
if event.key == pygame.K_c:
gameLoop()
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
lead_x_change = -10
lead_y_change = 0
elif event.key == pygame.K_RIGHT:
lead_x_change = 10
lead_y_change = 0
elif event.key == pygame.K_UP:
lead_y_change = -10
lead_x_change = 0
elif event.key == pygame.K_DOWN:
lead_y_change = 10
lead_x_change = 0
if ( lead_x < 0 ) or (lead_x >= 600) or ( lead_y < 0 ) or ( lead_y >= 800):
gameOver = True
So when I run this code, and when the snake goes over the boundary, the C for continue and Q for quit thing doesn't come UNTIL I press a button on the keyboard or move my mouse. Why is that?
Move:
if ( lead_x < 0 ) or (lead_x >= 600) or ( lead_y < 0 ) or ( lead_y >= 800):
gameOver = True
out of the pygame.event.get-loop because it will only run if events have taken place (mouse moved, key pressed). Otherwise the code will not reach the check without your action.
So, I'm making my first game in pygame, and have done OK up to this point. I just can't move the image. Can I please get some help?
mc_x = 20
mc_y = 20
spider_x = 690
spider_y = 500
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
mc_x -= 5
elif event.key == pygame.K_RIGHT:
mc_x += 5
elif event.key == pygame.K_UP:
mc_y += 5
elif event.key == pygame.K_DOWN:
mc_y -= 5
screen.blit(background,(0,0))#fixed
screen.blit(spider_small,(spider_x,spider_y))#FIXED
screen.blit(mc,(mc_x,mc_y))
pygame.display.update()
Based on your code:
screen.blit(mc,(mc_x,mc_y))
pygame.display.update()
should be inside the loop so that it would update/refresh your game for every keystroke.
You forgot to update the screen. Set the update function inside the main game loop. This is going to work fine!
Here's my sample code
import pygame
pygame.init()
WHITE = (255, 255, 255)
RED = (255, 0, 0)
canvas = pygame.display.set_mode((800, 600))
pygame.display.set_caption('Example')
gameExit = False
lead_x, lead_y = 300, 300
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
lead_x -= 10
elif event.key == pygame.K_RIGHT:
lead_x += 10
elif event.key == pygame.K_DOWN:
lead_y += 10
elif event.key == pygame.K_UP:
lead_y -= 10
canvas.fill(WHITE)
pygame.draw.rect(canvas, RED, [lead_x, lead_y, 30, 30])
pygame.display.update()
pygame.quit()
quit()
Im working on a simple game( a semi copy of the 'Dodger' game), and the game runs, yet displays nothing. I have a while loop running, so why is nothing showing up? Is it a problem with spacing, the images themselves, or am i just overlooking something?
import pygame,sys,random, os
from pygame.locals import *
pygame.init()
#This One Works!!!!!!!
WINDOWHEIGHT = 1136
WINDOWWIDTH = 640
FPS = 40
TEXTCOLOR = (255,255,255)
BACKGROUNDCOLOR = (0,0,0)
PLAYERMOVEMENT = 6
HARVEYMOVEMENT = 5
TJMOVEMENT = 7
LASERMOVEMENT = 10
ADDNEWBADDIERATE = 8
COLOR = 0
TJSIZE = 65
HARVEYSIZE = 65
#Check the sizes for these
def terminate():
if pygame.event() == QUIT:
pygame.quit()
def startGame():
while True:
for event in pygame.event.get():
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
terminate()
return
def playerHasHitBaddies(playerRect,TjVirus,HarVirus):
for b in TjVirus and HarVirus:
if playerRect.colliderect(b['rect']):
return True
return False
def drawText(text,font,surface, x, y):
textobj = font.render(text, 1, TEXTCOLOR)
textrect = textobj.get_rect()
textrect.topleft = (x, y)
surface.blit(textobj, textrect)
mainClock = pygame.time.Clock()
WindowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.mouse.set_visible(False)
pygame.display.set_caption('Virus')
#Player Images
# Check the name of the .png file
TjImage = pygame.image.load('Virus_TJ_edited-1.png')
TjRect = TjImage.get_rect()
#chanhe this part from the baddies variable in the 'baddies' area
playerImage = pygame.image.load('Tank_RED.png')
playerRect = playerImage.get_rect()
LaserImage = pygame.image.load('laser.png')
LaserRect = LaserImage.get_rect()
pygame.display.update()
startGame()
while True:
TjVirus = []#the red one / make a new one for the blue one
HarVirus = []#The BLue one / Need to create a new dictionary for this one
playerRect.topleft = (WINDOWWIDTH / 2, WINDOWHEIGHT - 50)
moveLeft = moveRight = moveUp = moveDown = laser = False
baddieAddCounter = 0
while True:
for event in pygame.event.get():
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == ord('a'):
moveRight = False
moveLeft = True
if event.key == ord('d'):
moveLeft = False
moveRight = True
if event.key == ord('w'):
moveDown = False
moveUp = True
if event.key == ord('s'):
moveUp = False
moveDown = True
if event.key == K_SPACE:
lasers = True
if event.type == KEYUP:
if evnet.type == K_ESCAPE:
terminate()
if event.key == K_LEFT or event.key == ord('a'):
moveLeft = False
if event.key == K_RIGHT or event.key == ord('d'):
moveRight = False
if event.key == K_UP or event.key == ord('w'):
moveUp = False
if event.key == K_DOWN or event.key == ord('s'):
moveDown = False
if event.key == K_SPACE:
LaserImage.add(LaserRect)
if event.key == ord('j'):
COLOR = 2
if event.key == ord('k'):
if COLOR == 2:
COLOR = 1
playerImage = pygame.image.load('Tank_RED.png')
if COLOR == 1:
COLOR = 2
playerImage = pygame.image.load('Tank_BLUE.png')
if event.type == MOUSEMOTION:
playerRect.move_ip(event.pos[0] - playerRect.centerx, event.pos[1] - playerRect.centery)
if baddieAddCounter == ADDNEWBADDIERATE:
baddieAddCounter = 0
#Dict for TJ(RED) VIRUS
baddieSize = (TJSIZE)
NewTjVirus = {'rect':pygame.Rect(random.rantint(0,WINDOWWIDTH - TJSIZE),0 - TJSIZE,TJSIZE,TJSIZE),
'speed':(TJMOVEMENT),
'surface':pygame.transform.scale(TJImage,(TJSIZE,TJSIZE)),
}
TjVirus.append(NewTjVirus)
#Dict for Harvey(BLUE) virus
baddieSize = (HARVEYSIZE)
NewHarveyVirus = {'rect':pygame.Rect(random.randint(0,WINDOWWIDTH - HARVEYSIZE),0 - HARVEYSIZE,HARVEYSIZE,HARVEYSIZE),
'speed':(HARVEYMOVEMENT),
'surface':pygame.transform.scale(HARVEYSIZE,(HARVEYSIZE,HARVEYSIZE))
}
HarVirus.append(NewHarveyVirus)
#Player Movement
if moveLeft and playerRect.left >0:
playerRect.move_ip(-1*PLAYERMOVEMENT,0)
if moveRight and playerRect.right < WINDOWWIDTH:
playerRect.move_ip(PLAYERMOVEMENT,0)
if moveUp and playerRect.top >0:
playerRect.move_ip(0,-1*PLAYERMOVEMENT)
if moveDown and playerRect.bottom < WINDOWHEIGHT:
playerRect.move_ip(0,PLAYERMOVEMENT)
pygame,mouse.set_pos(playerRect.centerx,playerRect.centery)
#Need to change for each individual virus
for b in HarVirus and TjVirus:
b['rect'].move_ip(0,b['speed'])
for b in HarVirus and TjVirus:
if b['rect'].top > WINDOWHEIGHT:
baddies.remove(b)
windowSurface.fill(pygame.image.load('Background_Proto copy.png'))
for b in HarVirus and TjVirus:
windowSurface.blit(b['surface'],b['rect'])
pygame.display.update()
if playerHasHitBaddies(playerRect,HarVirus,TjVirus):
break
for b in TjVirus and HarVirus[:]:
if b['rect'].top < WINDOWHEIGHT:
HarVirus.remove(b)
TjVirus.remove(b)
mainClock.tick(FPS)
Usally I use pygame.display.flip() not pygame.display.update()
You call your startGame() in your script, which looks like this:
def startGame():
while True:
for event in pygame.event.get():
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
terminate()
return
The game is stuck in that while loop until you press a key.
That's your current problem, but there are other errors as well, like
def terminate():
if pygame.event() == QUIT:
pygame.quit()
pygame.event() is not callable. Maybe you wanted to pass an event as argument here?
And also
pygame,mouse.set_pos(playerRect.centerx,playerRect.centery)
, instead of .