You probably know what I want to do from the title but here's a simple example:
#User clicks somewhere in the pygame window
pos = cursorPosition()
#Function/Class that creates a square where the user clicked.
I have tried this:
import pygame
import sys
running = True
pygame.init()
screen = pygame.display.set_mode((800, 500))
pos = pygame.mouse.get_pos()
class Create():
cx, cy = pygame.mouse.get_pos()
square = pygame.Rect(cx, cy, 50, 50)
def cube(self):
self.square = pygame.Rect(self.cx, self.cy, 50, 50)
pygame.draw.rect(screen, (255, 0, 0), self.square)
pygame.display.flip()
create = Create()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
create.cube()
screen.fill((0, 255, 0))
pygame.display.flip()
pygame.quit()
sys.exit()
But it just gives me a Blue screen and when I click anywhere it doesn't do anything, so if you can help me it would be much appreciated. Thanks!
EDIT: I've managed to do it but now I face another problem:
The square would appear only if I hold down the mouse button.
This is the code
import pygame
import sys
running = True
pygame.init()
screen = pygame.display.set_mode((800, 500))
pos = pygame.mouse.get_pos()
class Create():
cx, cy = pygame.mouse.get_pos()
square = pygame.Rect(cx, cy, 50, 50)
def cube(self):
self.cx, self.cy = pygame.mouse.get_pos()
self.square = pygame.Rect(self.cx, self.cy, 50, 50)
pygame.draw.rect(screen, (255, 0, 0), self.square)
pygame.display.flip()
create = Create()
while running:
screen.fill((0, 255, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
create.cube()
pygame.display.flip()
pygame.quit()
sys.exit()
It's great to see that you are making a good effort to solve the by yourself, and that you are editing the question with the work you've done so far!
What I added to the code basically allows the user to change where the cube is being drawn. If you would like to draw multiple cubes, with their positions based on the mouse clicks from the user, edit your question to add those details, and leave a comment below.
First, I wrote a new class called Cube, which essentially has the same code as Create. I won't go into it in detail, but generally in object-oriented programming, objects are nouns, and their methods are actions. Your class is the opposite, which isn't how object-oriented code is generally written.
I added the update() method which simply updates some of the object's fields with the position of the mouse. Your original code was defining class fields or static variables. I won't go into to too much detail here, but if we were to make 100 instances of cube, we would want to have the positions for all the cubes, right? In cases like these, you are operating on the objects, not the class.
Then, there is one variable which gets set to true after the first mouse click, and, as a result, the cube starts being drawn to the screen.
Here is the fixed code:
import pygame
running = True
pygame.init()
screen = pygame.display.set_mode((800, 500))
class Cube:
def update(self):
self.cx, self.cy = pygame.mouse.get_pos()
self.square = pygame.Rect(self.cx, self.cy, 50, 50)
def draw(self):
pygame.draw.rect(screen, (255, 0, 0), self.square)
cube = Cube()
drawing_cube = False
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
cube.update()
drawing_cube = True
screen.fill((0, 255, 0))
if drawing_cube:
cube.draw()
pygame.display.flip()
pygame.quit()
quit()
I hope this answer helped you, and if you have any further questions, please feel free to leave a comment below!
I have also come across this problem and after a lot of messing around and frustration came up with the following:
import sys
import pygame
import time
pygame.init()
white = (255, 255, 255)
red = (255, 0, 0)
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("OwO")
mouse_cords = []
clicked = False
def draw(cord_list, zero):
''' This is what will draw on the screen when the mouse clicks using recursion'''
pygame.draw.circle(screen, red, cord_list[zero], 100, 1)
zero += 1
if len(cord_list) > zero:
draw(cord_list, zero)
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(white)
if pygame.mouse.get_pressed()[0]:
mouse_cords.append(pygame.mouse.get_pos())
clicked = True
if clicked == True:
draw(mouse_cords, 0)
pygame.display.flip()
clock.tick(60)
pygame.quit()
As you can tell I used recursion to solve this problem. Sorry it's circles not boxes but Im sure you can figure out how to change that.
I am a beginner developer and my method is probably not the most efficient, however it does work. I know that I am writing 2 years late, but I am writing this incase anyone has the same question as I did which is to create multiple rectangles, squares or circles with a mousebutton press or in general any event.
I implemented a class to create a Cube object just like Michael O'Dwyer wrote in his explanation, and while his solution works to create one cube at a time, I needed to create multiple for myself.
In addition to his solution, I just created a list "cubeList" and with each mousebutton event I created a new cube object and appended it to that cubeList. Then, I used a for loop in order to iterate through each cube object in the cubeList and used the draw method. This way, I am able to have multiple cubes drawn at the same time, and I am sure there might be a more efficient or better method to do this, but this worked for me.
import pygame
WIDTH, HEIGHT = 900, 500
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
WHITE = (255,255,255)
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
Square1 = pygame.Rect(30,30,60,60)
Square2 = pygame.Rect(90,30,60,60)
class Cube:
def update(self):
self.cx, self.cy = pygame.mouse.get_pos()
self.square = pygame.Rect(self.cx - 25, self.cy - 25, 50, 50)
def draw(self):
pygame.draw.rect(WIN, GREEN, self.square)
def main():
cubeCount = 0
run = True
cubeList = []
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("Ending")
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
cube = Cube()
cubeList.append(cube)
cube.update()
clock.tick(60)
WIN.fill((BLUE))
pygame.draw.rect(WIN,RED, Square1)
pygame.draw.rect(WIN, GREEN, Square2)
for x in cubeList:
x.draw()
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
Related
I'm relatively new to programming, and even newer to pygame. As a high school IT project, I've decided to create a simple rage platformer game in pygame with a goal to improve my Python skills. I've just started the code after watching a few Clear Code videos (lots of inspiration from him). My main issue I'm running into, regardless of any other bad programming practices or mistakes elsewhere, is that when I blit the surfaces player_surf and background_surf onto the screen, only the bottom one appears when I run the code. I orginally thought it was something wrong with the transparency of the images I was importing, but that wasn't the issue after I fixed that. Then, I thought it might be bliting it off the screen, but if I do them seperately, they work. As I'm extrememly new, I'm not sure what went wrong. I would appreciate any advice.
import pygame
from sys import exit
class GameState():
def __init__(self):
self.state = "cutscene"
def cutscene(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.blit(background_surf, (0, 0))
def main_game(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.blit(player_surf, (screen_x / 2, screen_y / 2))
screen.blit(background_surf, (0, 0))
black = pygame.Color(0, 0, 0)
white = pygame.Color(255, 255, 255)
pygame.init()
screen_x = 800
screen_y = 400
screen = pygame.display.set_mode((screen_x, screen_y))
pygame.display.set_caption("Game")
fps = pygame.time.Clock()
game_state = GameState()
# Background
background_surf = pygame.image.load("Game/Background.png").convert()
background_surf = pygame.transform.smoothscale(background_surf, (screen_x, screen_y))
# Player
player_surf = pygame.image.load("Game/Red_Square.png").convert_alpha()
player_rect = player_surf.get_rect(center=(screen_x / 2, screen_y / 2))
while True:
game_state.main_game()
# game_state.cutscene()
pygame.display.update()
fps.tick(60)
You need to draw the background, then the player otherwise the player will be hidden:
def main_game(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
# draw
screen.blit(background_surf, (0, 0))
screen.blit(player_surf, (screen_x // 2, screen_y // 2))
I have a game display on which I used the blit-function to display a flight path as well as a drone. The flight path starts from the right side and goes beyond the left side of the display.
The game display is filled white and what I want is to move my drone via pressed keys from right to left along the flight path (which is just a set of contiguous lines connecting random points).
I want the 'coordinate system' of my display to move/scroll so that you can see where the flight path ends. At the same time I want my drone to maintain a static position during that scrolling, e.g. stay in the middle of the screen while it follows the flight path.
Does anybody know a function that allows me to achieve that? All I found in forums and on YouTube seemed rather complex and required one to have set a background image first. I just want the white-filled screen to scroll while I move my drone to the left to follow the red flight path. Below is what I coded so far.
Thank you a lot in advance for any advice!
import pygame
import pygame.gfxdraw
import random
import sys
white = (255,255,255)
display_width = 1200
display_height = 700
game_screen = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('gameScreen')
the_drone = pygame.image.load('drone.png')
X=1000
Y=350
p1=[X, Y]
p2=[X, Y]
p3=[X, Y]
p4=[X, Y]
p5=[X, Y]
pointlist = [p1, p2, p3, p4, p5]
limit1=1000
limit2=850
for i in pointlist:
i[0] = random.randrange(limit2, limit1)
limit1-=300
limit2-=300
for i in pointlist:
if i == 0:
i[1] = random.randrange(200, 600)
else:
range = i[1]-1
i[1] = random.randrange(range-100, range+100)
def flightpath(pointlist):
pygame.draw.lines(game_screen, (255, 0, 0), False, pointlist, 3)
def drone(x,y):
game_screen.blit(the_drone,(X,Y))
def game_loop():
global X, Y
gameExit = False
while not gameExit:
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:
pygame.quit()
sys.exit()
keys = pygame.key.get_pressed() #checking pressed keys
if keys[pygame.K_LEFT]:
X -= 0.5
if keys[pygame.K_DOWN]:
Y -= 0.5
if keys[pygame.K_UP]:
Y +=0.5
game_screen.fill(white)
flightpath(pointlist)
drone(X,Y)
pygame.display.update()
game_loop()
pygame.quit()
sys.exit()
Hi to be hones I don't really understand your Code but I got it working like that:
import pygame
import sys
import random
# init window
def init():
pygame.init()
pygame.display.set_caption("Drone Game")
screen = pygame.display.set_mode((500, 500))
return screen
# make closing the window possible
def escape():
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# draws all objects on screen
def draw(screen, f, y_pos):
screen.fill((50, 50, 50))
for y in range(20):
for x in range(5):
pygame.draw.rect(screen, f[y][x], (x * 100, (y * 100) - y_pos, 100, 100))
pygame.draw.rect(screen, (250, 0, 0), (240, 240, 20, 20)) # drone
pygame.display.update()
# creates background
def field():
f = []
for y in range(20):
f.append([])
for x in range(5):
f[y].append((random.randint(200, 255), random.randint(200, 255), random.randint(200, 255)))
return f
# combines all functions
def main(screen):
f = field()
y_pos = 500
while True:
pygame.time.Clock().tick(30)
escape()
y_pos -= 1
draw(screen, f, y_pos)
# starts program
if __name__ == '__main__':
main(init())
I hope it works for you. :)
I wanted to write a program that, when the user clicks anywhere on the surface of the box, it reveals another smaller box hidden behind it . The code is quite far from being finished at the moment .
Currently i wanted to do an animation that strats when the user clicks anywhere on the screen and stops when the box that covers the small box is gone.
Here is my code :
import random, pygame, sys
from pygame.locals import *
pygame.init()
done = False
clock = pygame.time.Clock()
white = (255,255,255) # COLLORS
black = (0,0,0)
red = (255,0,0)
green = (0,100,0)
display_width = 800 # SCREEN DIMMENSION
display_height = 600
game_display = pygame.display.set_mode((display_width,display_height)) # SCREEN
REVEALSPEED = 8
def draw_icon(x,y):
icon = pygame.Rect(x+10,y+10,20,20)
pygame.draw.rect(game_display,red,icon)
def draw_cover(x,y,coverage):
pygame.draw.rect(game_display,white,(x,y,40,40))
draw_icon(x,y)
if coverage > 0:
pygame.draw.rect(game_display, green, (x, y, coverage, 40))
pygame.display.update()
clock.tick(10)
def revealBoxesAnimation(x,y): # Do the "box reveal" animation.
for coverage in range(40, (-REVEALSPEED) - 1, -REVEALSPEED):
draw_cover(x, y, coverage)
def game_loop():
done = False
mouseClicked = False
while done != True:
x = (display_width - 40) / 2
y = (display_height - 40) / 2
for event in pygame.event.get(): # PRESSED KEYS EFFECTS
if event.type == pygame.QUIT:
done = True
elif event.type == MOUSEBUTTONUP:
mouseClicked = True
mousex, mousey = pygame.mouse.get_pos()
if mousex != None and mousey != None :
if mouseClicked == True :
revealBoxesAnimation(x, y)
game_display.fill(white)
pygame.display.update()
clock.tick(60)
game_loop()
In the draw_cover function I said that the program should only draw the big box if the value of 'coverage' is greater than zero.
In the revealBoxesAnimation function, I use the range function to lower the value of coverage from 40 all the way to 0 by 8 at a time (40, 32, 24, 16, 8, 0, -8). Still, when the value of coverage hits zero, the animation does not stop. It goes on in an infinite loop.
How so ?
While there was already a fix suggested in another answer, I recommend to rewrite your code entirely.
Note how all the logic is encapsulated in the Box class (especially the update method), instead of 3 different functions; and now we only have a single, non-blocking main loop.
We have a single class for both, the non-shrinking and the shrinking box, but we could also just create another class for the thing that should not shrink and skip the shrinking argument.
So basically, if the box shrinks, we shrink the rect, create a new Surface with the smaller size, and use that for drawing.
When a mouse click occurs, we just need to create two Box instances, one not shrinking, and a bigger one shrinking.
Here's a full, running example:
import random, pygame, sys
from pygame.locals import *
pygame.init()
clock = pygame.time.Clock()
display_width = 800 # SCREEN DIMMENSION
display_height = 600
game_display = pygame.display.set_mode((display_width,display_height)) # SCREEN
colors = pygame.color.THECOLORS
class Box(pygame.sprite.Sprite):
def __init__(self, group, center, size, color, shrinking=False):
pygame.sprite.Sprite.__init__(self, group)
self.image = pygame.surface.Surface((size, size))
self.image.fill(color)
self.shrinking = shrinking
self.rect = self.image.get_rect(center=center)
def update(self):
if self.shrinking:
self.rect.inflate_ip(-1, 0)
new = pygame.surface.Surface((self.rect.w, self.rect.h))
new.blit(self.image, (0, 0))
self.image = new
if self.rect.width <= 0:
self.kill()
sprites = pygame.sprite.OrderedUpdates()
def game_loop():
while True:
for event in pygame.event.get(): # PRESSED KEYS EFFECTS
if event.type == pygame.QUIT:
return
elif event.type == MOUSEBUTTONUP:
Box(sprites, event.pos, 20, colors['red'])
Box(sprites, event.pos, 40, colors['green'], True)
sprites.update()
game_display.fill(colors['white'])
sprites.draw(game_display)
pygame.display.update()
clock.tick(60)
game_loop()
The problem is simply that after setting mouseClicked to True, you never have a way to make it false again. The simplest fix in my opinion would be to replace
elif event.type == MOUSEBUTTONUP:
mouseClicked = True
with
mouseClicked = pygame.mouse.get_pressed()[0]
(Outside of the event for loop, as you only need to do so once per a frame.)
This question already has answers here:
Why is my PyGame application not running at all?
(2 answers)
Closed 1 year ago.
My friends and I are making a quiz game in PyGame and would like to know how, when the user presses a button, he can go to next question (without leaving the previous text behind).
First of all I would suggest that you go to the PyGame documentation and read up a little about PyGame. (Link)
However to save you time what you have to do is before you draw your new set of shapes/writings on the screen you have to use the function screen.fill(#Your chosen colour). That is the function in PyGame that gets rid of the old screen and allows you to draw new items on to a clear screen without the pervious drawings left on there.
Example:
import pygame
import sys
from pygame.locals import *
white = (255,255,255)
black = (0,0,0)
red = (255, 0, 0)
class Pane(object):
def __init__(self):
pygame.init()
self.font = pygame.font.SysFont('Arial', 25)
pygame.display.set_caption('Box Test')
self.screen = pygame.display.set_mode((600,400), 0, 32)
self.screen.fill((white))
pygame.display.update()
def addRect(self):
self.rect = pygame.draw.rect(self.screen, (black), (175, 75, 200, 100), 2)
pygame.display.update()
def addText(self):
self.screen.blit(self.font.render('Hello!', True, black), (200, 100))
pygame.display.update()
def addText2(self):
self.screen.blit(self.font.render('Hello!', True, red), (200, 100))
pygame.display.update()
def functionApp(self):
if __name__ == '__main__':
self.addRect()
self.addText()
while True:
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:
self.screen.fill(white)
self.addRect()
self.addText2() #i made it so it only changes colour once.
display = Pane()
display.functionApp()
In your game loop, before drawing the new frame, fill the frame with the background color.
Example:
ball = pygame.Rect(0,0,10,10)
while True:
mainSurface.fill((0,0,0))
pygame.draw.circle(display,(255,255,255),ball.center,5)
ball.move_ip(1,1)
pygame.display.update()
The key point is the mainSurface.fill which will clear the previous frame.
I have been trying to learn pygame the last day or so, and tried to write a basic program that just has a small image of a leaf falling from the top of the screen.
Nothing appears when I run it, and I imagine I'm missing something obvious with how I'm doing this. (I can tell this is a very inefficient way of doing this as well, so tips would be appreciated!)
Here's the code:
import pygame
from pygame.locals import *
import random
pygame.init()
class Leaf:
def __init__(self):
self.leafimage = pygame.image.load('fallingleaf.jpg').convert()
self.leafrect = self.leafimage.get_rect()
xpos = random.randint(0, 640)
self.leafrect.midtop = (xpos, 0)
def move(self):
self.leafrect = self.leafrect.move([0, 1])
def main():
width= 640
heigth = 480
dimensions = (width, heigth)
screen = pygame.display.set_mode(dimensions)
pygame.display.set_caption('Some Epic Pygame Stuff')
clock = pygame.time.Clock()
leaves = []
for i in range(5):
leaves.append(Leaf())
running = 1
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = 0
for i in leaves:
i.move()
screen.blit(i.leafimage, i.leafrect)
screen.fill((255, 255, 255))
pygame.display.flip()
if __name__ == '__main__': main()
You probably don't want this sequence:
for i in leaves:
i.move()
screen.blit(i.leafimage, i.leafrect)
screen.fill((255, 255, 255))
pygame.display.flip()
You draw the leaves, and then fill the entire screen with white, and then show the screen.
fill the screen, then draw the leaves, then flip()