I am trying to make a game where if someone press left-click, pygame draws a circle, then a line connecting the circle to the upper left corner. If he/she press right-click, it removes everything created from the screen. I thought about just covering everything with a big black square, but that is not really clearing the screen, just covering it. My code is as follow:
from pygame import *
init()
size = width, height = 650, 650
screen = display.set_mode(size)
button = 0
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
def drawScene(screen, button):
# Draw circle if the left mouse button is down.
if button==1:
draw.circle(screen,GREEN,(mx,my), 10)
draw.line(screen,GREEN, (0,0),(mx,my))
if button == 3:
mouse.set_visible(False)
display.flip()
running = True
myClock = time.Clock()
# Game Loop
while running:
for e in event.get(): # checks all events that happen
if e.type == QUIT:
running = False
if e.type == MOUSEBUTTONDOWN:
mx, my = e.pos
button = e.button
drawScene(screen, button)
myClock.tick(60) # waits long enough to have 60 fps
quit()
Kindly guide me in this situation. Thanks in advance.
I thought about just covering everything with a big black square, but that is not really clearing the screen, just covering it.
There is not any difference between cover and clear. The screen consist of pixels. Drawing an object just changes the color of the pixels. Drawing a black square changes the color of the pixel again.
Note, operations like pygame.draw.circle() and pygame.draw.line() do not create any object. They just change the colors of some pixels of the surface which is passed to the operation.
The easiest way to clear the entire window is pygame.Surface.fill():
screen.fill((0, 0, 0))
respectively
screen.fill(BLACK)
In computer graphics, there is no such thing as "clearing" a screen. you can only overwrite the previous drawing with new pixels. your idea of drawing a big black rectangle would work perfectly but I may be more efficient to use screen.fill(0)
Related
Im trying to make a rectangle bounce, without going off limits.
I want my rectangle to bounce depending on the wall it touched.
In this code im trying to bounce the rectangle in a 90º angle, but it isn't working.
Im using this to calculate each advance:
rect_x += rectxSpeed
rect_y += rectySpeed
When it reachs the limit
if rect_y>450 or rect_y<0:
rectySpeed=5
rect_y=rectySpeed*-(math.pi/2)
if rect_x>650 or rect_x<0:
rectxSpeed=5
rectx_y=rectxSpeed*-(math.pi/2)
Whole code here:
import pygame
import random
import math
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
rect_x= 50.0
rect_y = 50.0
rectxSpeed=5
rectySpeed=5
pygame.init()
# Set the width and height of the screen [width, height]
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
while not done:
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# --- Game logic should go here
# --- Screen-clearing code goes here
# Here, we clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
# If you want a background image, replace this clear with blit'ing the
# background image.
screen.fill(BLACK)
string=str(rect_x)
string2=str(rect_y)
string3="["+string+"]"+"["+string2+"]"
font = pygame.font.SysFont('Calibri', 25, True, False)
text = font.render(string3,True,RED)
screen.blit(text, [0, 0])
#Main rectangle
pygame.draw.rect(screen, WHITE, [rect_x, rect_y, 50, 50])
#Second rectangle inside the rectangle 1
pygame.draw.rect(screen, RED, [rect_x+10, rect_y+10, 30, 30])
rect_x += rectxSpeed
rect_y+=rectySpeed
if rect_y>450 or rect_y<0:
rectySpeed=5
rect_y=rectySpeed*-(math.pi/2)
if rect_x>650 or rect_x<0:
rectxSpeed=5
rect_x=rectxSpeed*-(math.pi/2)
# --- Drawing code should go here
# --- Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# --- Limit to 60 frames per second
clock.tick(20)
# Close the window and quit.
pygame.quit()
¿How can i adjust the advance?
This code produce this:
By Changing the reach limit code with:
if rect_y>450 or rect_y<0:
rectySpeed=rectySpeed*-(math.pi/2)
if rect_x>650 or rect_x<0:
rectxSpeed=rectxSpeed*-(math.pi/2)
Produces this:
I think it's important to recognize here that the speed of the rectangle object here is a scalar value, not it's vector counterpart velocity. You are attempting to multiply the rectySpeed (a scalar value) by -(math/pi)/2, which is a value that will be returned in radians as #0x5453 mentioned. As far as the rectangle bouncing differently depending on the wall that it contacted, you have not specified the differing constraints that you intend to impose. I think you may want to consider why you want the rectangle to always bounce at a 90° angle. Note that a rectangle that always bounces at a 90° angle would yield some very odd functionality to the player/user.
The angle that the rectangle is approaching the wall measured from the horizontal will be equal to the angle that the rectangle will rebound off the wall measured from the vertical line of the wall to it's new path (in the case of an x-directional bounce).
In terms of an accurate physics engine, you may want to consider just simplifying your mechanics to the following in the case that the rectangle contacts a wall:
if rect_y>450 or rect_y<0:
rectySpeed=rectySpeed*-1
if rect_x>650 or rect_x<0:
rectxSpeed=rectxSpeed*-1
The above ensures that the rectangle object simply changes direction, therefore the magnitude of the rectangle's speed does not change, however the velocity indeed does since it is a vector quantity.
This is different to the other questions as it uses another method. I have the following code and need to change it so that it produces a grid (all rows and columns filled in) as per Figure 16.7 on this link: http://programarcadegames.com/index.php?chapter=array_backed_grids
The following code produces a full row and a full column, but I can't quite work out how to extend it to fill the whole screen with rectangles with the appropriate margin built in.
Code:
"""
Create a grid with rows and colums
"""
import pygame
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
pygame.init()
# Set the width and height of the screen [width, height]
size = (255, 255)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
width=20
height=20
margin=5
# -------- Main Program Loop -----------
while not done:
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# --- Game logic should go here
# --- Screen-clearing code goes here
# Here, we clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
# If you want a background image, replace this clear with blit'ing the
# background image.
screen.fill(BLACK)
# --- Drawing code should go here
#for column (that is along the x axis) in range (0 = starting position, 100=number to go up to, width+margin =step by (increment by this number)
#adding the 255 makes it fill the entire row, as 255 is the size of the screen (both ways)
for column in range(0+margin,255,width+margin):
pygame.draw.rect(screen,WHITE, [column,0+margin,width,height])
for row in range(0+margin,255,width+margin):
pygame.draw.rect(screen,WHITE,[0+margin,row,width,height])
#This simply draws a white rectangle to position (column)0,(row)0 and of size width(20), height(20) to the screen
# --- Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# --- Limit to 60 frames per second
clock.tick(60)
# Close the window and quit.
pygame.quit()
The problem lies in the inner loop (for row in...),
where the rect is drawn with:
pygame.draw.rect(screen,WHITE,[0+margin,row,width,height])
Note that the x coordinate always is 0+margin,
no matter which column is currently drawn. So
the code draws 10 columns on top of each other.
As a simple fix, change the line to:
pygame.draw.rect(screen,WHITE,[column,row,width,height])
You might then notice that the other call of the draw method in the outer loop is completely unnecessary. After all, the inner call now draws a rectangle for each row in each column. So you can reduce the loop code to:
for column in range(0+margin, 255, width+margin):
for row in range(0+margin, 255, height+margin):
pygame.draw.rect(screen, WHITE, [column,row,width,height])
I am a beginner in Pygame. I have coded a function for moving two balls in different direction and I follow the instructions coding it but it seems to be not working. I can draw two balls in screen but they will not move. I fixed it for almost 1 hour but no idea why balls aren't moving.
So, Can someone helps me check my code and just give me some hints. I will really appreciate anyone who helps me!
My code shows below
import pygame,sys,time
from pygame.locals import *
# User define function
def ball_move(Surface,white,pos,rad,speed):
size=Surface.get_size()
for item in [0,1]:
pos[item]=pos[item]+speed[item]
if pos[item]<rad:
speed[item]=-speed[item]
if pos[item]+rad>size[item]:
speed[item]=-speed[item]
# Open a brand-new window
pygame.init()
Screen_size = (500,400)
Title = ('Pong')
Frame_Delay = 0.01
Surface= pygame.display.set_mode(Screen_size,0,0)
pygame.display.set_caption(Title)
# Set up white color for drawing balls
white=pygame.Color('white')
# Now, we start to draw two balls
pos1=(100,200)
pos2=(400,200)
rad=10
ball1=pygame.draw.circle(Surface,white,pos1,rad,0)
ball2=pygame.draw.circle(Surface,white,pos2,rad,0)
pygame.display.update()
# Now, define speed
speed1=(2,-2)
speed2=(-2,2)
# Now, we define a loop
while ball1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# Now, we move the ball
ball1move=ball_move(Surface,white,pos1,rad,speed1)
ball2move=ball_move(Surface,white,pos2,rad,speed2)
pygame.draw.circle(Surface,white,pos1,rad,0,0)
pygame.draw.circle(Surface,white,pos2,rad,0,0)
surface.fill(pygame.Color('black'))
Part of saulspatz answer is correct, part is incorrect. You don't have to use sprites if you dont want to. pygame.draw is not pretty but perfectly usable. The main problem does seem to be your understanding of what to do in your event loop. All this should go in it:
while running:
# Handdle your events
# update your state
# draw to your display
pygame.display.update()
Also I notice in your unreachable code after the loop you are filling after your draws. Remember whether you fill, blit, or draw the latest thing goes over the rest. So for your example:
import pygame ,sys, time
from pygame.locals import *
# User define function
def ball_move(surface, pos, rad, speed):
def _add(l_pos, l_speed, l_size):
l_pos += l_speed
if l_pos <= rad or l_pos >= l_size - rad:
l_speed = -l_speed
return l_pos, l_speed
size = surface.get_size()
pos_x, speed_x = _add(pos[0], speed[0], size[0])
pos_y, speed_y = _add(pos[1], speed[1], size[1])
return (pos_x, pos_y), (speed_x, speed_y)
pygame.init()
screen_size = (500, 400)
screen = pygame.display.set_mode(screen_size)
pygame.display.set_caption('Pong')
running = True
pos1 = (100, 200)
pos2 = (400, 200)
speed1 = (2, -2)
speed2 = (-2, 2)
rad = 10
while running:
# Handdle your events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# update your state
pos1, speed1 = ball_move(screen, pos1, rad, speed1)
pos2, speed2 = ball_move(screen, pos2, rad, speed2)
# draw to your display
screen.fill(pygame.Color('black'))
pygame.draw.circle(screen, pygame.Color('white'), pos1, rad)
pygame.draw.circle(screen, pygame.Color('white'), pos2, rad)
pygame.display.update()
There are a lot of problems with your code. The most basic is that you haven't figured out how event-driven programming works. You need to put the code that moves the balls inside your loop.
Another problem is that I don't think you want to use the pygame.draw module. It's been a long time since I wrote any pygame scripts, but as I remember, this module is useful for drawing fixed objects, like the background. A quick look at the docs seems to confirm this.
For moving objects, I think you need to look at the pygame.sprite module. Even if you got this code to work, it wouldn't move the balls. It would just draw a new ball at another position. So you would have first two balls, then four, then eight, ... . Sprites actually move. Not only is the object drawn at the new position, but it's erased at the old position. Your code don't address erasure at all.
Hope this helps.
I am using pygame and python for a project I am building, and I am building a splashscreen for when the game first opens. I have a .png that I want to show for the splashscreen, and decided to fade it in and out from black. the best way I found to do this was by blitting the image with a set alpha. I made this code, but it runs really slowly (the program hangs for 30 seconds) and doesn't give an alpha. Only displays the picture onscreen. What am i doing wrong?
screen = pygame.display.set_mode([1066,600])
#Drawable surface
background = pygame.Surface(screen.get_size())
#Used for converting color maps
background = background.convert()
#Splashscreen
#image fades in
for i in range (225):
background.fill((0,0,0))
image = pygame.image.load("logo.png")
image.set_alpha(i)
logoimage = screen.blit(image,(0,0))
pygame.display.flip()
pygame.time.delay(2000)
#image fades out
#goes on to display main menu
Another problem that you might be having (besides what monkey said) is that you might need to use surface.convert() which converts the image into a form where the alpha can be changed. You can do either of the following.
image = pygame.image.load("logo.png")
image = image.convert()
or
image = pygame.image.load("logo.png").convert()
I have found that, although surface.convert_alpha() should do pretty much the same thing, it doesn't usually work. Try this test code to check.
import pygame, sys
pygame.init()
window=pygame.display.set_mode((1500, 800))
background=pygame.Surface((window.get_rect().width, window.get_rect().height))
background.fill((0, 0, 0))
image=pygame.image.load('InsertImageHere.png')
image=image.convert()
image2=pygame.image.load('InsertImage2Here.png')
image2=image2.convert_alpha()
rect=image.get_rect()
rect2=image2.get_rect()
rect2.left=rect.width+1
i=1
while True:
for event in pygame.event.get():
if event.type==12:
pygame.quit()
sys.exit()
image.set_alpha(i)
image2.set_alpha(i)
window.fill((255, 255, 255))
window.blit(background, background.get_rect())
window.blit(image, rect)
window.blit(image2, rect2)
pygame.time.delay(20)
i+=1
if i==255:
i=1
pygame.display.update()
In my testings, image 1 faded in properly, but image 2 stayed dark the whole time. You should try it for yourself; your computer might work differently.
If surface.convert_alpha() does work for you, you should use it, otherwise, do what I said before. This should solve your problem.
You should also note that I used pygame.time.delay(20) rather than 2000 like you had before. 2000 would be a bit too long if you are increasing the alpha in incraments of one.
[1] You don't want to load the image every iteration. Because creating a new surface is a slow operation. [2] Your loop draws 225 times, then afterward the final iteration, waits 2000ms.
You want:
image = pygame.image.load("logo.png")
for i in range (225):
background.fill((0,0,0))
image.set_alpha(i)
screen.blit(image,(0,0))
pygame.display.flip()
pygame.time.delay(20)
To fade in and out, you need to keep looping until the player clicks/hits a button. Like this:
import pygame
from pygame.locals import *
# ...
def title_loop():
# title screen main loop
image = pygame.image.load("logo.png")
done = False
alpha = 0
alpha_vel = 1
# fade alpha in-out while waiting
while not done:
# get key input
for event in pygame.event.get():
if event.type == QUIT:
done = true
if event.type == KEYDOWN:
if event.key = K_ESCAPE:
done = true
# draw
if alpha >= 255 or alpha <= 0:
alpha_vel *= -1
alpha += alpha_vel
background.fill((0,0,0))
image.set_alpha(i)
screen.blit(image,(0,0))
pygame.display.flip()
pygame.time.delay(20)
PygameNerd your example is close, but it doesn't really work.
The image.convert() will fade properly, but it doesn't support alpha channel. Try it on a non black background & it shows.
The image.convert_alpha() will not fade, but the alpha channel does work properly.
I'm surprised that pygame doesn't support this out of the box, but anyway. Here is an answer:
http://www.nerdparadise.com/tech/python/pygame/blitopacity/
Its a bit complex, but works fine. Transparent background & fading all in one package.
You blit an image onto your surface to use as your background. Then you press button X to blit an image on the same surface, how do you erase the image? I have this so far, but then I end up with a white rectangle in the middle of my background.
screen = pygame.display.set_mode(1280, 512)
screen.blit(background, (0,0))
while True:
pygame.display.flip() #flip is same as update
for event in pygame.event.get():
if (event.type == pygame.KEYDOWN):
if event.key == pygame.K_SPACE:
screen.blit(player, (x, y))
if event.key == pygame.K_BACKSPACE:
pygame.draw.rect(screen, [255,255,255], (x, y, 62,62))
There are basically two things you can do here. You can go the simple route and just draw the background again...
if event.key == pygame.K_BACKSPACE:
screen.blit(background, (0,0))
Or, if you want it to be a little more efficient, you can have the blit method only draw the part of the background that the player image is covering up. You can do that like this...
screen.blit(background, (x, y), pygame.Rect(x, y, 62, 62))
The Rect in the third argument will cause the blit to only draw the 62x62 pixel section of 'background' located at position x,y on the image.
Of course this assumes that the player image is always inside the background. If the player image only partially overlaps the background I'm not entirely sure what will happen. It'll probably throw an exception, or it'll just wrap around to the other side of the image.
Really the first option should be just fine if this is a fairly small project, but if you're concerned about performance for some reason try the second option.
Normally the blit workflow is just to blit the original background to screen.
In your code you would use screen.blit(background, (0,0))
When you start combining lots of surfaces you will probably want either a variable or a list of variables to keep track of screen state.
E.g.
Initialise Background
objectsonscreen = []
objectsonscreen.append(background)
screen.blit(background, (0,0))
Add Sprite
objectsonscreen.append(player)
screen.blit(player, (x, y))
Clear Sprite
objectsonscreen = [background]
screen.blit(background, (0,0))
See here for more information on sprites in Pygame. Note that if your background isn't an image background and is just a solid color you could also use screen.fill([0, 0, 0]) instead.
I personally use
pygame.draw.rect(screen, (RgbColorHere), (x, y, width, height))