I want "ball.giff" turn around the screen like this.
---> -->
|
^ v
|
|
^ v
| <-- <- -
and my codes :
import sys
import pygame
size = width, height = 600, 600
screen = pygame.display.set_mode(size)
pygame.display.set_caption("wedding")
brade = pygame.image.load("ball.gif")
brade_rect = brade.get_rect()
speed = [10, 0]
black = 0, 0, 0
while True:
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
sys.exit()
brade_rect.move_ip(speed)
if brade_rect.right>width:
speed = [0,10]
if brade_rect.bottom>height:
speed = [-10, 0]
if brade_rect.left<0:
speed = [0, -10]
if brade_rect.top<0:
speed = [10, 0]
pygame.time.delay(100)
screen.fill(black)
screen.blit(brade, brade_rect)
pygame.display.flip()
but there is a problem. after one tour, ball go to right forever. It does not go to down?
What I missed, please can you help?
At the end of the first turn, brad_rect.top becomes -10. You change the speed to [10, 0] but keep brad_rect.top to -10 therefore the last if still activate and erase whatever of can be in speed. You should put back brade_rect in the window:
if brade_rect.right>width:
speed = [0,10]
brade_rect.right=width
if brade_rect.bottom>height:
speed = [-10, 0]
brade_rect.bottom=height
if brade_rect.left<0:
speed = [0, -10]
brade_rect.left=0
if brade_rect.top<0:
speed = [10, 0]
brade_rect.top=0
By the way, you should consider putting some else here.
Related
I'm a beginner programmer who is starting with python and I'm starting out by making a game in pygame.
The game basically spawns circles at random positions and when clicked, it gives you points.
Recently I've hit a roadblock when I want to spawn multiple instances of the same object (in this case circles) at the same time.
I've tried stuff like sleep() and some other code related to counters, but it always results in the next circle spawned overriding the previous one (i.e the program spawns circle 1, but when circle 2 comes in, circle 1 disappears).
Does anyone know a solution to this? I would really appreciate your help!
import pygame
import random
import time
pygame.init()
window = pygame.display.set_mode((800,600))
class circle():
def __init__(self, color, x, y, radius, width,):
self.color = color
self.x = x
self.y = y
self.radius = radius
self.width = width
def draw(self, win, outline=None):
pygame.draw.circle(win, self.color, (self.x, self.y, self.radius, self.width), 0)
run=True
while run:
window.fill((0, 0, 0))
pygame.draw.circle(window, (255, 255, 255), (random.randint(0, 800),random.randint(0, 600)), 20, 20)
time.sleep(1)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run=False
pygame.quit()
quit()
It does not work that way. time.sleep, pygame.time.wait() or pygame.time.delay is not the right way to control time and gameplay within an application loop. The game does not respond while you wait. The application loop runs continuously. You have to measure the time in the loop and spawn the objects according to the elapsed time.
pygame.Surface.fill clears the entire screen. Add the newly created objects to a list. Redraw all of the objects and the entire scene in each frame.
See also Time, timer event and clock
You have 2 options. Use pygame.time.get_ticks() to measure the time. Define a time interval after which a new object should appear. Create an object when the point in time is reached and calculate the point in time for the next object:
object_list = []
time_interval = 500 # 500 milliseconds == 0.1 seconds
next_object_time = 0
while run:
# [...]
current_time = pygame.time.get_ticks()
if current_time > next_object_time:
next_object_time += time_interval
object_list.append(Object())
Minimal example:
repl.it/#Rabbid76/PyGame-TimerSpawnObjects
import pygame, random
pygame.init()
window = pygame.display.set_mode((300, 300))
class Object:
def __init__(self):
self.radius = 50
self.x = random.randrange(self.radius, window.get_width()-self.radius)
self.y = random.randrange(self.radius, window.get_height()-self.radius)
self.color = pygame.Color(0)
self.color.hsla = (random.randrange(0, 360), 100, 50, 100)
object_list = []
time_interval = 200 # 200 milliseconds == 0.2 seconds
next_object_time = 0
run = True
clock = pygame.time.Clock()
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
current_time = pygame.time.get_ticks()
if current_time > next_object_time:
next_object_time += time_interval
object_list.append(Object())
window.fill(0)
for object in object_list[:]:
pygame.draw.circle(window, object.color, (object.x, object.y), round(object.radius))
object.radius -= 0.2
if object.radius < 1:
object_list.remove(object)
pygame.display.flip()
pygame.quit()
exit()
The other option is to use the pygame.event module. Use pygame.time.set_timer() to repeatedly create a USEREVENT in the event queue. The time has to be set in milliseconds. e.g.:
object_list = []
time_interval = 500 # 500 milliseconds == 0.1 seconds
timer_event = pygame.USEREVENT+1
pygame.time.set_timer(timer_event, time_interval)
Note, in pygame customer events can be defined. Each event needs a unique id. The ids for the user events have to be between pygame.USEREVENT (24) and pygame.NUMEVENTS (32). In this case pygame.USEREVENT+1 is the event id for the timer event.
Receive the event in the event loop:
while run:
for event in pygame.event.get():
if event.type == timer_event:
object_list.append(Object())
The timer event can be stopped by passing 0 to the time argument of pygame.time.set_timer.
Minimal example:
repl.it/#Rabbid76/PyGame-TimerEventSpawn
import pygame, random
pygame.init()
window = pygame.display.set_mode((300, 300))
class Object:
def __init__(self):
self.radius = 50
self.x = random.randrange(self.radius, window.get_width()-self.radius)
self.y = random.randrange(self.radius, window.get_height()-self.radius)
self.color = pygame.Color(0)
self.color.hsla = (random.randrange(0, 360), 100, 50, 100)
object_list = []
time_interval = 200 # 200 milliseconds == 0.2 seconds
timer_event = pygame.USEREVENT+1
pygame.time.set_timer(timer_event, time_interval)
run = True
clock = pygame.time.Clock()
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == timer_event:
object_list.append(Object())
window.fill(0)
for object in object_list[:]:
pygame.draw.circle(window, object.color, (object.x, object.y), round(object.radius))
object.radius -= 0.2
if object.radius < 1:
object_list.remove(object)
pygame.display.flip()
pygame.quit()
exit()
I'm new to pygame and I'm trying to do the simplest thing ever here really, I just want to have a circle move across the screen with no input from the user. I only seem to find advice online on how to move an object using the keys which isn't what I want I just want it to move on its own and so that the user can watch it move.
Here's what I was trying to use to do this.
Code Start Here:
import pygame module in this program
import pygame
pygame.init()
white = (255, 255, 255)
green = (0, 255, 0)
blue = (0, 0, 128)
black = (0, 0, 0)
red = (255, 0, 0)
X = 400
Y = 400
display_surface = pygame.display.set_mode((X, Y ))
pygame.display.set_caption('Drawing')
display_surface.fill(white)
x,y=[300,50]
pygame.draw.circle(display_surface,green, (x, y), 20, 0)
clock = pygame.time.Clock()
def move():
global y
y=y+1
while True :
clock.tick(30)
move()
for event in pygame.event.get() :
# if event object type is QUIT
# then quitting the pygame
# and program both.
if event.type == pygame.QUIT :
pygame.quit()
quit()
pygame.display.update()
Code End Here:
You have to redraw the scene in every frame:
import pygame
pygame.init()
white = (255, 255, 255)
green = (0, 255, 0)
blue = (0, 0, 128)
black = (0, 0, 0)
red = (255, 0, 0)
X = 400
Y = 400
display_surface = pygame.display.set_mode((X, Y))
pygame.display.set_caption('Drawing')
clock = pygame.time.Clock()
x,y=[300,50]
def move():
global y
y=y+1
# application loop
run = True
while run:
# limit the frames per second
clock.tick(30)
# event loop
for event in pygame.event.get() :
if event.type == pygame.QUIT:
run = False
# update the position of the object
move()
# clear disaply
display_surface.fill(white)
# draw scene
pygame.draw.circle(display_surface,green, (x, y), 20, 0)
# update disaply
pygame.display.update()
pygame.quit()
quit()
The typical PyGame application loop has to:
limit the frames per second to limit CPU usage with pygame.time.Clock.tick
handle the events by calling either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by calling either pygame.display.update() or pygame.display.flip()
I would like to get an array which would consist of RGBA code of every pixel in the pygame display
I tried this:
for i in range(SCREEN_WIDTH):
for j in range(SCREEN_HEIGHT):
Pixels.append(pygame.Surface.get_at((i, j)))
But I got an error message that Surface.get_at does not work for tuples so I removed one set of bracket and then it told me that Surface.get_at does not work with integers, so I am confused, how can I get the RGBA value of all pixels? Thank you
EDIT, Ok after a comment I post full runable code:
import pygame
pygame.init()
PPM = 15
SCREEN_WIDTH, SCREEN_HEIGHT = 640, 480
pos_X = SCREEN_WIDTH/PPM/3
pos_Y = SCREEN_HEIGHT/PPM/3
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
FPS = 24
TIME_STEP = 1.0 / FPS
running = True
lead_x = pos_X*PPM
lead_y = pos_Y*PPM
k = 0
Pixels = []
while running:
screen.fill((255, 255, 255, 255))
for event in pygame.event.get():
if event.type == pygame.KEYDOWN and event.key == K_ESCAPE:
running = False
if k == 0:
for i in range(SCREEN_WIDTH):
for j in range(SCREEN_HEIGHT):
Pixels.append(pygame.Surface.get_at((i, j)))
k +=1
pygame.draw.rect(screen, (128,128,128), [lead_x, lead_y,50,50])
pygame.display.update()
pygame.display.flip() # Update the full display Surface to the screen
pygame.time.Clock().tick(FPS)
pygame.quit()
And I got these exact error, nothing less and nothing more:
Exception has occurred: TypeError
descriptor 'get_at' for 'pygame.Surface' objects doesn't apply to 'tuple' object
.get_at is a instance function method (see Method Objects) of pygame.Surface. So it has to be called on an instance of pygame.Surface. screen is the Surface object, which represents the window. So it has to be:
Pixels.append(pygame.Surface.get_at((i, j)))
Pixels.append(screen.get_at((i, j)))
respectively
Pixels.append(pygame.Surface.get_at(screen, (i, j)))
To get all pixels value as bytes, you can use
pygame.Surface.get_buffer(screen).raw
While I've been using time.wait in my code since I began learning Python and Pygame, I've been wondering if there are any other ways to do it and what are the advantages and disadvantages of each approach. For example, Pygame also has a pygame.time.wait. What's the difference between python's wait and pygame's wait functions? Which one is better? And are there other ways to wait some time besides using these two functions?
For animation / cooldowns, etc: If you want to 'wait', but still have code running you use: pygame.time.get_ticks
class Unit():
def __init__(self):
self.last = pygame.time.get_ticks()
self.cooldown = 300
def fire(self):
# fire gun, only if cooldown has been 0.3 seconds since last
now = pygame.time.get_ticks()
if now - self.last >= self.cooldown:
self.last = now
spawn_bullet()
For Python in general, you will want to look at the sleep library.
For Pygame, however, using pygame.time.delay() will pause for a given number of milliseconds based on the CPU clock for more accuracy (as opposed to pygame.time.wait).
If you just wait for some time, you can use pygame.time.wait or pygame.time.delay. However, if you want to display a message and then wait some time, you need to update the display beforehand. The display is updated only if either pygame.display.update() or pygame.display.flip()
is called. See pygame.display.flip():
This will update the contents of the entire display.
Further you've to handles the events with pygame.event.pump(), before the update of the display becomes visible in the window. See pygame.event.pump():
For each frame of your game, you will need to make some sort of call to the event queue. This ensures your program can internally interact with the rest of the operating system.
This all means that you have to call pygame.display.flip() and pygame.event.pump() before pygame.time.delay() or pygame.time.wait():
screen.blit(text, (x, y))
pygame.display.flip()
pygame.event.pump()
pygame.time.delay(delay * 1000) # 1 second == 1000 milliseconds
See also Why doesn't PyGame draw in the window before the delay or sleep?
In any case, this is not the way to wait or delay something in a typical application. The game does not respond while you wait. Use pygame.time.get_ticks() to measure the time.
For instance if you want to show a message on the display, get the current time and calculate the point in time after that the message has to disappear. Display the message as long as the current time is below the calculated time:
message_end_time = 0
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# [...]
current_time = pygame.time.get_ticks()
if something_has_happened:
message_surf = font.render('Important message!', True, (255, 0, 0))
message_end_time = pygame.time.get_ticks() + 3000 # display for 3 seconds
window.fill(0)
# [...]
if current_time < message_end_time:
window.blit(message_surf, (x, y))
pygame.display.flip()
See also How do I stop more than 1 bullet firing at once?
Minimal example: repl.it/#Rabbid76/PyGame-MessageDelay
import pygame
pygame.init()
font = pygame.font.SysFont(None, 50)
text = font.render('press key or mouse', True, (255, 0, 0))
window = pygame.display.set_mode((500, 200))
clock = pygame.time.Clock()
message_end_time = pygame.time.get_ticks() + 3000
run = True
while run:
clock.tick(60)
current_time = pygame.time.get_ticks()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
text = font.render(pygame.key.name(event.key) + ' pressed', True, (255, 0, 0))
message_end_time = pygame.time.get_ticks() + 2000
if event.type == pygame.MOUSEBUTTONDOWN:
text = font.render('button ' + str(event.button) + ' pressed', True, (255, 0, 0))
message_end_time = pygame.time.get_ticks() + 2000
window.fill(0)
if current_time < message_end_time:
window.blit(text, text.get_rect(center = window.get_rect().center))
pygame.display.flip()
pygame.quit()
exit()
I have been wondering how collision detection works, I have had many attempts, but can't get it to work. I am new to pygame, so if anyone is kind enough to read this, please can you add the correct lines to my code as well as explaining it. If anyone was wondering what this code did, it has 2 racecars thatare trying to hit a football and move it in the direction the car is hitting it at(I was thinking a possible way to complete this was to check the angle the car is rotated at, and move the ball by that amount, - 180 degrees to move it forward)
Thank you very much
import pygame
from pygame.math import Vector2
pygame.init()
screen = pygame.display.set_mode((1150, 800))
clock = pygame.time.Clock()
BLUECAR_ORIGINAL = pygame.Surface((100, 30), pygame.SRCALPHA)
pygame.draw.polygon(
BLUECAR_ORIGINAL, (0, 0, 255), [(0, 0), (50, 10), (50, 20), (0, 30)])
bluecar = BLUECAR_ORIGINAL
REDCAR_ORIGINAL = pygame.Surface((50, 30), pygame.SRCALPHA)
pygame.draw.polygon(
REDCAR_ORIGINAL, (200, 0, 0), [(0, 0), (50, 10), (50, 20), (0, 30)])
redcar = REDCAR_ORIGINAL
ball = pygame.draw.circle(screen, [255,255,255],[60,60],5)
pos = Vector2(70, 70)
vel = Vector2(7, 0)
poss = Vector2(70,70)
vell = Vector2(7,0)
redrect = redcar.get_rect(center=pos)
redangle = 0
bluerect = bluecar.get_rect(center=pos)
blueangle = 0
run = True
while run:
ball = pygame.draw.circle(screen, [0,0,0],[575,400],30)
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
redangle += 5
vel.rotate_ip(-5)
redcar = pygame.transform.rotate(REDCAR_ORIGINAL, redangle)
redrect = redcar.get_rect(center=pos)
elif keys[pygame.K_RIGHT]:
redangle -= 5
vel.rotate_ip(5)
redcar = pygame.transform.rotate(REDCAR_ORIGINAL, redangle)
redrect = redcar.get_rect(center=pos)
if keys[pygame.K_a]:
blueangle += 5
vell.rotate_ip(-5)
bluecar = pygame.transform.rotate(BLUECAR_ORIGINAL, blueangle)
bluerect = bluecar.get_rect(center=pos)
elif keys[pygame.K_d]:
blueangle -= 5
vell.rotate_ip(5)
bluecar = pygame.transform.rotate(BLUECAR_ORIGINAL, blueangle)
bluerect = bluecar.get_rect(center=poss)
hits = pygame.sprites.groupcollide(bluecar, ball, False, False)
hits = pygame.sprites.spritecollide(bluecar, ball, False)
pos += vel
redrect.center = pos
poss += vell
bluerect.center = poss
bgImg = pygame.image.load("Football_pitch.png")
screen.blit(bgImg, (0,0))
screen.blit(redcar, redrect)
screen.blit(bluecar, bluerect)
pygame.display.flip()
clock.tick(60)
pygame.quit()
There are multiple ways:
you could save the coordinates of each sprite as variables and then compare the coordinates of both sprites to each other than do whatever you need to when they are close enough, for example:
if object1_X <= object2_X+5 and object1_X>= object2_X-5 and object1_Y<= object2_Y+5 and object1_Y>=object2_X-5:
#do something
#all that above basically is just saying if the objects above are within a 10-pixel radius of each other do something
pass
or you could use the distance formula:
distance=((object2_X-object1_X)**2+(object2_Y-object1_Y)**2)**0.5
if distance <= 10:
#do something
pass
which utilises the Pythagorean theorem to find the distance between two objects
or you could use pygame's existing function:
object1=pygame.draw.rect(screen,color,[x,y1,50,30],0)
object2=pygame.draw.rect(screen,colorb,[x2,y2,7,7],0)
if object1.colliderect(object2):
#do something
pass
if you were wondering how it works, I am not 100% sure but it likely uses one of the two rudimentary methods internally to calculate this