In Pygame, I'm making a game with highscores. I want to blit a highscore variable onto the screen, called c but whenever I try to run the program, it freezes and I don't know why. How can I blit the variable c to the screen without it freezing? Here is the relevant code:
# High score (printed in the corner)
c=0
while c>=0:
c=c+1
highscore=myfont6.render("High score:",True, THECOLORS["purple"])
score=myfont6.render(c, True, THECOLORS["purple"])
screen.blit(highscore, (20,20))
screen.blit(score,(40,20))
It's this chunk right here. Once you hit this chunk of code, your program will continue to loop forever.
c=0
while c>=0:
c=c+1
I'm guessing you intended to have c increase by one on every loop of the main game loop. If that's the case, just remove the first two lines and call c += 1 on each main game loop.
Related
I've just started learning python and started working on a project.
I'm moving my mouse cursor from one area to another. I just want it to stop when it reach a certain point/area/zone. I'm using the mouse position to tell me where it is, currently.
For some reason, when this loops starts, it keeps looping even when the IF statement is true.
But if I started when the IF statement is true, the loops kinda works as intended, so far it's only reading the 'X' values.
I couldn't find an answer to this, or any questions like it. If anyone has an idea or can point me to a similar post, I'll appreciate it.
import pyautogui, sys, time, autoit
#Search for a position on screen manually
try:
while True:
x, y = pyautogui.position()
print(pyautogui.position())
print('Stopping for 1 seconds, keep searching or CTRL + C to end')
time.sleep(1)
#Confirmed location on screen.
if pyautogui.position(x,y) >= pyautogui.position(710, 15):
pyautogui.leftClick()
print('The Eagle has landed')
print(pyautogui.position())
break
Update: I got it! Following mkrieger1 advice, I manage to get the 'x, y' values to update. Code was rewritten.
So I am trying to make a game, in this game I call upon a function that I want to slowly execute, but when I use "time.sleep(x)" it pauses everything in the file instead of just pausing the process of the function. I am trying to add a jump feature to a 2-d game, so if there is a better way to do it then I would be grateful for any advice but this is just the first idea that game to me.
for n in range(15):
Dino.rect.bottom -= 5
update_screen(Dino, screen, cactus)
time.sleep(0.01)
time.sleep(0.25)
inair = False
for n in range(15):
Dino.rect.bottom += 5
update_screen(Dino, screen, cactus)
time.sleep(0.01)
so I have it so that when I jump, it gives me a slow jump instead of just teleporting but like I said, it pauses everything while jumping.
This is not a good approach to timing. As you say, this sleeps the entire program. Multi-threading is a bit complex for simply moving a sprite.
A simple way to solve this problem is to use the PyGame function time.get_ticks() which returns an ever-increasing time in milliseconds.
Using this time-stamp, record the previous-time of an operation, but then do not update again until enough time has elapsed.
For example:
DINO_UPDATE_DELAY = 100 # milliseconds
next_dino_update = 0 # time next move due
[...]
# Move dino, if necessary
time_now = pygame.time.get_ticks()
if ( time_now > next_dino_update ):
Dino.rect.bottom += 5
next_dino_update = time_now + DINO_UPDATE_DELAY # in the future
# Paint the dino, wherever it is
update_screen(Dino, screen, cactus)
It's also possible to request a timer to send the event-loop a message in the future.
MOVE_DINO_EVENT = pygame.USEREVENT + 1
[...]
pygame.time.set_timer( MOVE_DINO_EVENT, DINO_UPDATE_DELAY )
EDIT: More in-depth explanation.
So basically you're implementing an animation, like an anime/cartoon. The thing on the display moves at some speed. In the above code, you seem to be moving a "dino" in the direction of y + 5 every 0.01 seconds (10 milliseconds).
Right now, you paint the dino, then sleep(), then move & paint again. When it hits the apogee of the jump, you wait 250 milliseconds, then repeat the previous phase for the down-jump.
So the problem with using sleep() is that it holds up the whole program (including the event loop, which can cause bad stuff to happen).
So instead of sleeping for some time period, the above example simply looks at the PyGame clock to determine if that same time-period has past. This allows the program to know if the animation needs to be updated.
The whole idea is to keep looking at the clock, using the time as the arbiter of what/where to draw next, rather than multiple calls to sleep().
I have some code that is kinda funky. Basically, the variable gameStart is in a variable that uses the function, cursorOver, which finds and detects where and if the mouse button is and if it is pressed. I have 3 buttons and I want each button to become larger when the cursor is over the button. The first button implementation works. However, if I try to add another button, the button becomes enlarged, however, the button starts flickering.
window.blit(background,(0,0))
window.blit(title,(175,200))
pygame.draw.rect(window,PURPLE,(50,400,200,100),0)
pygame.draw.rect(window,PURPLE,(300,400,200,100),0)
pygame.draw.rect(window,PURPLE,(550,400,200,100),0)
close()
mouseX,mouseY = pygame.mouse.get_pos()
mouseClick = pygame.mouse.get_pressed()[0]
gameStartC = cursorOver(50,400,200,100,mouseX,mouseY)
instructionStartC = cursorOver(300,400,200,100,mouseX,mouseY)
objectiveStartC = cursorOver(550,400,200,100,mouseX,mouseY)
nextStartC = cursorOver(580,250,175,100,mouseX,mouseY)
if gameStartC == True:
while True:
pygame.draw.rect(window,PURPLE,(25,375,250,150),0)
pygame.display.update()
break
else:
pygame.draw.rect(window,PURPLE,(50,400,200,100),0)
pygame.display.update()
#this is the part where the code becomes glitchy
if instructionStartC == True:
while True:
pygame.draw.rect(window,PURPLE,(275,375,250,150),0)
pygame.display.update()
break
else:
pygame.draw.rect(window,PURPLE,(300,400,200,100),0)
pygame.display.update()
It's simply because you call pygame.display.update() multiple times.
You should create a standard game loop that typically does these three things:
handle input
update state
draw to screen
and then repeats.
In the 'draw to screen'-step, you draw all your sprites/rects/whatever to the screen surface, and then eventually call pygame.display.update() once at the end.
Calling pygame.display.update() multiple times, not clearing the screen between iterations of the loop and creating multiple unnecessary event loops are common beginner mistakes that lead to those kind of glitches IMHO.
So in your case, the code should probably look more like this:
if gameStartC:
pygame.draw.rect(window,PURPLE,(25,375,250,150),0)
else:
pygame.draw.rect(window,PURPLE,(50,400,200,100),0)
if instructionStartC:
pygame.draw.rect(window,PURPLE,(275,375,250,150),0)
else:
pygame.draw.rect(window,PURPLE,(300,400,200,100),0)
pygame.display.update()
I don't know what you expected the while-loops to do, and maybe you should use pygames Rect and Sprite classes. It will make your life easier.
I've been working on a snake code for quite a while now. It is still rather primitive and very very basic. I have gotten the collisions to work, food generation and very basic movement. What I'm struggling on is figuring out the movement. Whenever you press WASD or the Arrow Keys it would move the head, and the "body" of the snake follows the part in front of it. So snakecol[1] follows snakecol[0] and so on.
Thank you in advance for any tips and pointers on how to improve my code.
#W to move up, A to move to the left, S to move down, D to move right.
#Snake by Juan Jaramillo
import pygame
import sys
import random
import math
import time
pygame.init()
screen=pygame.display.set_mode((500,500))
point=3
def collision():
global foodx
global foody
global x
global y
global xd
global yd
global point
global snakecol
if snakecol[0].colliderect(foodcol):
foodx=random.randint(0,24)*20
foody=random.randint(0,24)*20
point+=1
snakecol.append(snakecol[len(snakecol)-1])
if xd==20:
snakecol[len(snakecol)-1].x-=20
if xd==-20:
snakecol[len(snakecol)-1].x+=20
if yd==20:
snakecol[len(snakecol)-1].y-=20
if yd==-20:
snakecol[len(snakecol)-1].y==20
print "Snake is",point,"long."
red=(255,0,0)
blue=(0,0,255)
green=(0,255,0)
black=(0,0,0)
block1=0
block2=1
count=0
screen.fill(black)
randFood=random.randint(0,24)
x=60
y=0
foodx=randFood*20
foody=randFood*20
snakecol=list()
snakecol.append(pygame.Rect(x,y,20,20))
snakecol.append(pygame.Rect(x-20,y,20,20))
snakecol.append(pygame.Rect(x-40,y,20,20))
foodcol=pygame.Rect(foodx,foody,20,20)
xd=[20]
yd=[0]
##snakecol=pygame.Rect(x,y,20,20)
foodcol=pygame.Rect(foodx,foody,20,20)
done=False
while not done:
screen.fill(black)
collision()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
#controls
if block1==1:
if(pygame.key.get_pressed()[pygame.K_a]) or (pygame.key.get_pressed()[pygame.K_LEFT]):
yd[0]=0
xd[0]=-20
block1=0
block2=1
if block1==1:
if(pygame.key.get_pressed()[pygame.K_d]) or (pygame.key.get_pressed()[pygame.K_RIGHT]):
yd[0]=0
xd[0]=20
block1=0
block2=1
if block2==1:
if(pygame.key.get_pressed()[pygame.K_w]) or (pygame.key.get_pressed()[pygame.K_UP]):
xd[0]=0
yd[0]=-20
block1=1
block2=0
if block2==1:
if(pygame.key.get_pressed()[pygame.K_s]) or (pygame.key.get_pressed()[pygame.K_DOWN]):
xd[0]=0
yd[0]=20
block1=1
block2=0
#stop moving paddle
for m in range(0,len(snakecol)):
if snakecol[m].x<-20:
snakecol[m].x=500
if snakecol[m].x>500:
snakecol[m].x=-20
if snakecol[m].y<-20:
snakecol[m].y=500
if snakecol[m].y>500:
snakecol[m].y=-20
for m in range(0,len(snakecol)):
snakecol.pop
pygame.draw.rect(screen,(255,255,255),snakecol[m],0)
pygame.draw.rect(screen,(0,0,0),snakecol[m],1)
snakecol[m].x+=xd[0]
snakecol[m].y+=yd[0]
foodcol.x=foodx
foodcol.y=foody
pygame.draw.rect(screen,(255,255,255),(foodx,foody,20,20),0)
pygame.draw.rect(screen,(0,0,0),(foodx,foody,20,20),1)
pygame.display.flip()
time.sleep(0.4)
count+=1
pygame.quit()
The body blocks don't need to know the direction. You can just append a new head block (with the next x, y coords) to the list and remove the last block.
You could also use a collections.deque, pronounced "deck", a double ended queue which allows fast appends and pops on either end (although efficiency isn't really needed here, the code just looks a bit nicer).
A few more suggestions, you should check out how functions, classes and Pygame sprites work. There's a nice, free book about Python and Pygame called Program Arcade Games. Also, you shouldn't use global variables for everything, since they can make code really hard to understand (use classes).
Edit: To emphasize my answer above: Don't move the rects (the parts of the snake) in your list directly by changing their x and y values. Just pop or remove the last rect and append a new head rect. This will create the illusion of movement but the rects actually all stay at the same position.
I mentioned the deque, because it has efficient methods for popping and appending at the left end. For lists this is very inefficient, but I think it won't matter in your case, because the list won't grow too much and computers nowadays are very powerful.
Some code review (this should rather be in https://codereview.stackexchange.com/ though):
Line 132: You don't call pop because you forgot the parentheses. But if you actually called it, the snakecol list would shrink and the game would crash.
Handle the event loop first, then the game logic (e.g. collisions) and then the drawing. In a game class you would use different methods for these parts of the program.
You call pygame.key.get_pressed() several times. Instead assign the keys list to a variable keys = pygame.key.get_pressed() and use this variable later in the loop.
time.sleep is usually not used in Pygame (the game controls will seem to be unresponsive). There's the pygame.time.Clock class which you can use to limit the framerate and you can use a timer variable to keep track of when the snake can move. Instantiate a clock before the main loop clock = pygame.time.Clock() and in the loop you call clock.tick(enter_max_fps_here) every frame.
In pygame, I am trying to make my points increase by 1000 every time a shot impacts my zombie, who's positions are zhot[XX] and zhot[YY]. I attempted to accomplish this by creating a rectangle around my zombie, and using the collidepoint function, however as my shot passes through the rectangle, every change in it's position counts as 1000 points, so shooting one zombie will give me something like 30000 points. How can I fix this?
for shot in shots:
zomrect2=Rect(zhot[XX],zhot[YY],49,38)
if zomrect2.collidepoint(shot[X],shot[Y]):
points+=1000
Once you've awarded points, you need to break out of the for loop.
for shot in shots:
zomrect2=Rect(zhot[XX],zhot[YY],49,38)
if zomrect2.collidepoint(shot[X],shot[Y]):
points+=1000
break #no more points will be awarded, there's no point wasting computation checking the rest.
I guess the loop you posted runs inside your main loop and is invoked every iteration of the main loop.
You should remove the shot from the shots list once it hit your zombie, so it won't be checked again for collision in the next iteration of the main loop.
zomrect2=Rect(zhot[XX],zhot[YY],49,38)
# make a copy of the list so we can savely remove items
# from it while iterating over the list
for shot in shots[:]:
if zomrect2.collidepoint(shot[X],shot[Y]):
points += 1000
shots.remove(shot)
# and also do whatever you have to do to
# erase the shot objects from your game
You need to track the fact that the points have been awarded already. It's not really clear how/when the method or function awarding points is being called, but something like this perhaps:
points_awarded = False
for shot in shots:
zomrect2=Rect(zhot[XX],zhot[YY],49,38)
if zomrect2.collidepoint(shot[X],shot[Y]) and not points_awarded:
points_awarded = True
points+=1000