Related
I am new to Pygame and I am in the experimentation phase.
What I have here is a simple display surface onto which I have rendered a few overlapping Rectangles with different colors with the same width and height (96 by 144) to simulate playing cards.
I have written some code in order to be able to highlight a card with the color Yellow when I click on it. If you run the code, you'll notice that when I click on the visible part of one of the cards, all the other cards that are behind it, as well as all of those that are overlapping it are being highlighted. I cannot figure out, what should I do to click the visible part of the card and only that card to highlight.
import pygame, sys
class Card(pygame.sprite.Sprite):
def __init__(self, color):
super().__init__()
self.color = color
self.is_highlight = False
def show_card(self, x, y):
self.rect = pygame.rect.Rect(x, y, 96, 144)
pygame.draw.rect(display_surf, self.color, self.rect)
def highlight_card(self):
pos = pygame.mouse.get_pos()
if self.rect.collidepoint(pos):
self.is_highlight = True
else:
self.is_highlight = False
def update(self):
if self.is_highlight:
pygame.draw.rect(display_surf, 'Yellow', self.rect.inflate(5, 5), width=3, border_radius=5)
class Deck(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.card_deck = []
def build_deck(self):
self.card_deck.append(Card('Green'))
self.card_deck.append(Card('Red'))
self.card_deck.append(Card('Blue'))
self.card_deck.append(Card('brown'))
self.card_deck.append(Card('cadetblue'))
self.card_deck.append(Card('cornsilk'))
self.card_deck.append(Card('darkolivegreen'))
self.card_deck.append(Card('darkorchid'))
self.card_deck.append(Card('darksalmon'))
return self.card_deck
pygame.init()
WINDOW_WIDTH = 1280
WINDOW_HEIGHT = 720
display_surf = pygame.display.set_mode((WINDOW_WIDTH,WINDOW_HEIGHT))
pygame.display.set_caption('Simple Card Game')
clock = pygame.time.Clock()
card_deck = Deck().build_deck()
while True:
display_surf.fill((0, 150,0))
distance = 20
for card in card_deck:
card.show_card(distance, 20)
distance += 20
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
for card in card_deck:
card.highlight_card()
for card in card_deck:
card.update()
pygame.display.update()
So I think I have solved my own question and wish to share the solution.
In the show_card method I have added a new scaled_rect which represents only the visible part of the colored card with a width of only 20, while I draw on the display surface the color using the original full sized rectangle:
def show_card(self, x, y):
self.rect = pygame.rect.Rect(x, y, 96, 144)
self.scaled_rect = pygame.rect.Rect((x, y), (20, 144))
pygame.draw.rect(display_surf, self.color, self.rect)
In the highlight_card method I have made only the visible part of the color interactable with the mouse click, by using the new scaled_rect:
def highlight_card(self):
pos = pygame.mouse.get_pos()
if self.scaled_rect.collidepoint(pos):
self.is_highlight = True
else:
self.is_highlight = False
In the end, in the update method that draws the yellow colored highlight, I use the original full sized rectangle:
def update(self):
if self.is_highlight:
pygame.draw.rect(display_surf, 'Yellow', self.rect.inflate(5, 5), width=3, border_radius=5)
so I have a scroll bar in my game what Im trying to do is make it so if my mouse is over the bar1 button and we are on the moving_spot of the bar1 button then we can move it up and down on its y axis
how can I move the bar up and down and if its colliding with with any of the volume buttons I can change the volume of my background music either 0.1 or 0.2 or 0.3 so it controls my game volumepygame.mixer.music.set_volume(0.3)
my problem is im not sure how I could get this started I have everything in place but not sure where to start ***how can I move the bar with my mouse on the moving_spot on its y values only and if the bar1 is over and of the volume1 2 or 3 4 buttons then it should play the volume at defferent level
im not sure how to approach this problem any help is appreciated I just need a way to adjust my music of my game if the player moves the bar up or down
while run:
# Making game run with fps
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
# this is our bar1 the gray part that we will be able to move
if bar1.isOver(pos):
bar1.y = pos
print("WORKING{")
here are my buttons and positions places the move_spot is where the bar1 can only move up and down
the bar1 is the bar that the player can control to control the volume
and also the volume 1 2 3 4 are where the defferent volume of our background music will be set
move_spot = button((colors),720,125,25,260, '')
bar1 = button((colors),715,125,30,60, '')
volume1 = button((colors2),715,145,30,60, '')
volume2 = button((colors2),715,210,30,60, '')
volume3 = button((colors2),715,280,30,60, '')
volume4 = button((colors2),715,350,30,60, '')
buttons = [bar1,move_spot,volume1,volume2,volume3,volume4]
this is my buttons class
# our buttons
class button():
def __init__(self, color, x,y,width,height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
self.over = False
def draw(self,window,outline=None):
#Call this method to draw the button on the screen
if outline:
pygame.draw.rect(window, outline, (self.x-2,self.y-2,self.width+4,self.height+4),0)
pygame.draw.rect(window, self.color, (self.x,self.y,self.width,self.height),0)
if self.text != '':
font = pygame.font.SysFont('image/abya.ttf', 60)
text = font.render(self.text, 1, (255,255,255))
window.blit(text, (self.x + (self.width/2 - text.get_width()/2), self.y + (self.height/2 - text.get_height()/2)))
def isOver(self, pos):
#Pos is the mouse position or a tuple of (x,y) coordinates
if pos[0] > self.x and pos[0] < self.x + self.width:
if pos[1] > self.y and pos[1] < self.y + self.height:
return True
return False
def playSoundIfMouseIsOver(self, pos, sound):
if self.isOver(pos):
if not self.over:
click.play()
self.over = True
else:
self.over = False
here a minimal code you can run and test with this bar image
heres the background music music
import pygame
pygame.init()
window = pygame.display.set_mode((800,800))
# our buttons
class button():
def __init__(self, color, x,y,width,height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
self.over = False
def draw(self,window,outline=None):
#Call this method to draw the button on the screen
if outline:
pygame.draw.rect(window, outline, (self.x-2,self.y-2,self.width+4,self.height+4),0)
pygame.draw.rect(window, self.color, (self.x,self.y,self.width,self.height),0)
if self.text != '':
font = pygame.font.SysFont('freesansbold.ttf', 60)
text = font.render(self.text, 1, (255,255,255))
window.blit(text, (self.x + (self.width/2 - text.get_width()/2), self.y + (self.height/2 - text.get_height()/2)))
def isOver(self, pos):
#Pos is the mouse position or a tuple of (x,y) coordinates
if pos[0] > self.x and pos[0] < self.x + self.width:
if pos[1] > self.y and pos[1] < self.y + self.height:
return True
return False
def playSoundIfMouseIsOver(self, pos, sound):
if self.isOver(pos):
if not self.over:
click.play()
self.over = True
else:
self.over = False
colors = 0,23,56
colors2 = 0,123,56
bar11 = pygame.image.load("bar.png").convert_alpha()
move_spot = button((colors),720,125,25,260, '')
bar1 = button((colors),715,125,30,60, '')
volume1 = button((colors2),715,145,30,60, '')
volume2 = button((colors2),715,210,30,60, '')
volume3 = button((colors2),715,280,30,60, '')
volume4 = button((colors2),715,350,30,60, '')
buttons = [bar1,move_spot,volume1,volume2,volume3,volume4]
# fos
fps = 60
clock = pygame.time.Clock()
# redraw
def redraw():
window.fill((40,100,200))
for button in buttons:
button.draw(window)
window.blit(bar11,(bar1.x,bar1.y))
# main loop
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
redraw()
pygame.display.update()
pygame.quit()
As a general rule of thumb, you want to delegate all the heavy lifting to classes, and leave the "good" stuff to the mainloop of your program. I have created a simple class here, which takes some inputs (width, height, number of slider options), and will take care of all the drawing, positioning, etc. for you. It also has an option of self.chosen, which tells you which option is picked. I then used this to set the volume outputted by the mixer, based on which option is chosen, in the update() function:
class VolumeBar(pygame.sprite.Sprite):
def __init__(self, options, width, height):
# Store these useful variables to the class
self.options = options
self.width = width
self.height = height
# The slider
self.slider = pygame.image.load('slider.png')
self.slider_rect = self.slider.get_rect()
# The background "green" rectangles, mostly for decoration
self.back = []
objectHeight = (height-options*6)/(options-1)
self.backHeight = objectHeight
for index in range(options-1):
self.back.append(pygame.Rect((0, rint((6*index+6)+index*objectHeight)), (width, rint(objectHeight))))
# The foreground "blue" rectangles, mostly for decoration
self.fore = []
for index in range(options):
self.fore.append(pygame.Rect((0, rint(index*(objectHeight+6))), (width, 6)))
# Get list of possible "snaps", which the slider can be dragged to
self.snaps = []
for index in range(options):
self.snaps.append((width/2, 3+(index*(objectHeight+6))))
# A simple variable to tell you which option has been chosen
self.chosen = 0
# Generate the image surface, then render the bar to it
self.image = pygame.Surface((width, height))
self.rect = self.image.get_rect()
self.render()
self.focus = False
def render(self):
self.image.fill([255, 255, 255])
for back in self.back:
pygame.draw.rect(self.image, [0, 192, 0], back)
for fore in self.fore:
pygame.draw.rect(self.image, [0, 0, 0], fore)
self.image.blit(self.slider, (rint((self.width-self.slider_rect.width)/2),
rint(self.snaps[self.chosen][1]-(self.slider_rect.height/2))))
def draw(self, surface):
surface.blit(self.image, self.rect.topleft)
def mouseDown(self, pos):
if self.rect.collidepoint(pos):
self.focus = True
return True
return False
def mouseUp(self, pos):
if not self.focus:
return
self.focus = False
if not self.rect.collidepoint(pos):
return
pos = list(pos)
# We've made sure the mouse started in our widget (self.focus), and ended in our widget (collidepoint)
# So there is no reason to care about the exact position of the mouse, only where it is relative
# to this widget
pos[0] -= self.rect.x
pos[1] -= self.rect.y
# Calculating max distance from a given selection, then comparing that to mouse pos
dis = self.backHeight/2 + 3
for index, snap in enumerate(self.snaps):
if abs(snap[1]-pos[1]) <= dis:
self.chosen = index
break
self.render()
def update(self):
pygame.mixer.music.set_volume((self.options-self.chosen)*0.1)
Most of the __init__ function is spent calculating positions for each of the green and black rectangles, which are drawn in render() and displayed in draw(). The other functions are there for the mouse input, the first checks if the mouseDown happened on said button, and if it did, it sets self.focus to True, so that the mouseUp handler knows that it should change the slider position.
All of this works together to make a working VolumeBar. Below is an example of how it would be used in a mainloop:
import pygame
pygame.init()
rint = lambda x: int(round(x, 0)) # Rounds to the nearest integer. Very useful.
class VolumeBar(pygame.sprite.Sprite):
def __init__(self, options, width, height):
# Store these useful variables to the class
self.options = options
self.width = width
self.height = height
# The slider
self.slider = pygame.image.load('slider.png')
self.slider_rect = self.slider.get_rect()
# The background "green" rectangles, mostly for decoration
self.back = []
objectHeight = (height-options*6)/(options-1)
self.backHeight = objectHeight
for index in range(options-1):
self.back.append(pygame.Rect((0, rint((6*index+6)+index*objectHeight)), (width, rint(objectHeight))))
# The foreground "blue" rectangles, mostly for decoration
self.fore = []
for index in range(options):
self.fore.append(pygame.Rect((0, rint(index*(objectHeight+6))), (width, 6)))
# Get list of possible "snaps", which the slider can be dragged to
self.snaps = []
for index in range(options):
self.snaps.append((width/2, 3+(index*(objectHeight+6))))
# A simple variable to tell you which option has been chosen
self.chosen = 0
# Generate the image surface, then render the bar to it
self.image = pygame.Surface((width, height))
self.rect = self.image.get_rect()
self.render()
self.focus = False
def render(self):
self.image.fill([255, 255, 255])
for back in self.back:
pygame.draw.rect(self.image, [0, 192, 0], back)
for fore in self.fore:
pygame.draw.rect(self.image, [0, 0, 0], fore)
self.image.blit(self.slider, (rint((self.width-self.slider_rect.width)/2),
rint(self.snaps[self.chosen][1]-(self.slider_rect.height/2))))
def draw(self, surface):
surface.blit(self.image, self.rect.topleft)
def mouseDown(self, pos):
if self.rect.collidepoint(pos):
self.focus = True
return True
return False
def mouseUp(self, pos):
if not self.focus:
return
self.focus = False
if not self.rect.collidepoint(pos):
return
pos = list(pos)
# We've made sure the mouse started in our widget (self.focus), and ended in our widget (collidepoint)
# So there is no reason to care about the exact position of the mouse, only where it is relative
# to this widget
pos[0] -= self.rect.x
pos[1] -= self.rect.y
# Calculating max distance from a given selection, then comparing that to mouse pos
dis = self.backHeight/2 + 3
for index, snap in enumerate(self.snaps):
if abs(snap[1]-pos[1]) <= dis:
self.chosen = index
break
self.render()
def update(self):
pygame.mixer.music.set_volume((self.options-self.chosen)*0.1)
screen = pygame.display.set_mode([500, 500])
test = VolumeBar(10, 30, 300)
test.rect.x = 50
test.rect.y = 50
clock = pygame.time.Clock()
game = True
while game:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
game = False
if event.type == pygame.MOUSEBUTTONDOWN:
test.mouseDown(pygame.mouse.get_pos())
if event.type == pygame.MOUSEBUTTONUP:
test.mouseUp(pygame.mouse.get_pos())
if not game:
break
screen.fill([255, 255, 255])
test.update()
test.draw(screen)
pygame.display.update()
clock.tick(60)
The final product:
https://i.gyazo.com/f6c2b5ede828f7715e5fd53a65c32c13.mp4
As long as your mouseDown happened on this widget, mouseUp will determine where the slider ends up. Thusly, you can click, drag, or tap the slider anywhere on it, and the slider will go to the correct position.
Accessing the position of the slider is quite simple, just look at self.chosen. It defaults to 0 (Because it was set to that in the __init__) function, which is at the very top.
I'm trying to generate multiple rectangles which translate across the screen with varying distance of separation between any two consecutive rectangles.
Here's the snippet of the code-
win = pygame.display.set_mode((500, 500)) #canvas size is 500x500
width = 40
height = 60
x = 500 - width
y = 500 - height
vel = 5
state = True
while(state):
pygame.time.delay(50)
x -= vel
pygame.draw.rect(win, (0, 0, 255), (x, y, width, height))
pygame.display.update()
#I have not included the pygame exit code
Now, how do I go about this, without making the rectangles disappear everytime I try to generate a new one?
Create a list of rectangles:
rect_list = []
When you want to add a new rectangle, the append an new pygame.Rect object to the list:
rect_list.append(pygame.Rect(x, y, width, height))
Change the location of the rectangle and draw the rectangles in a loop, in the main application loop:
state = True
while state:
# [...]
for rect_obj in rect_list:
rect_obj.x -= vel
pygame.draw.rect(win, (0, 0, 255), rect_obj)
# [...]
This answer is derived off Rabbid76's answer, but with a slight modification that allows each individual rect to have it's own vel speed and color:
class rectangle:
# You can add as many new values as you like, just be wary about changing the other magic methods
def __init__(top, left, width, height, vel, color=(0, 0, 255)):
self.vel = vel
self.pos = (top, left)
self.size = (width, height)
self.rect = self.pos + self.size
def __iter__(self):
return self.rect
def __getitem__(self, key):
if type(key)!=int:
raise TypeError('invalid key!')
return self.rect[key]
def __len__(self):
return len(self.rect)
def __reversed__(self):
return reversed(self.rect)
def update_rect(self): # This should be called every time you make an adjustment to pos or size
self.rect = self.pos+self.size
def move(self, x, y):
self.pos[0] += x
self.pos[1] += y
self.update_rect
def resize(self, width, height):
self.size = (width, height)
self.update_rect
Now, you store a list of instances:
rect_list = []
rect_list.append(rectangle(top, left, width, height, vel, color)) # You can call this as many times as you want
of these classes instead of a list of pygame.Rects, and when it comes time to draw it, the magic methods will come into play, and magically make it a pygame.Rect object:
for rect in rect_list:
rect.move(x=-rect.vel, y=0) # Move it negative x
pygame.draw.rect(win, rect.color, pygame.Rect(rect)) # Draw it.
I'm fairly new to pygame and was wondering how I can choose the position of where this text box would be displayed, because right now it is always displaying the textbox in the same position.
Ideally, I'd call the function like so: "function("Hi, how are you", (x,y)), though I'm not sure how to implement this.
(I've looked around and I cant find any answers on stackoverflow or reddit and found nothing).
def textBox(Question, Position):
#screen.fill((255,255,255))# fill the screen w/ white
question = eztext.Input(maxlength=100, color=black, prompt=Question)#Create an input with max length 45.
clock = pygame.time.Clock() # create the pygame clock
run = True
while run == True:
clock.tick(30) # make sure the program is running at 30 fps
events = pygame.event.get() # events for txtbx
for event in events:
if event.type == QUIT: # close it if x button is pressed
return
if event.type == KEYDOWN:
if event.key == K_RETURN:
textBox.userResponse = question.value
run = False
screen.fill((255,255,255)) # clear the screen
question.update(events) # update txtbx
question.draw(screen) # blit txtbx on the sceen
pygame.display.flip() # refresh the display
Here is a very simple method of creating a text render function :
def RenderText(Text, Font, Target, X, Y, R, G, B): # The target is your screen
""""Text , font, target surface, X, Y,
and color (RGB)"""
RenderedText = Font.render(Text, True, (R, G, B))
Target.blit(RenderedText, (X, Y))
To use it :
Load font :
default_font = pygame.font.SysFont(None, 30)
See the wiki for font customization
Apply in your loop :
... # Loop Stuff
# I assume that your screen is named `screen` X Y Color in RGB
RenderText('Hi, how are you?', default_font, screen, 50, 50, 255, 255, 255)
# Experiment with all the above args
I'm not using your eztext class, but try this method, it's quite simple.
Get source code of eztext, open in editor and you will see what you can do:
question = eztext.Input(x=10, y=20, ...)
or
question.set_pos(10, 20)
Source code:
class Input:
""" A text input for pygame apps """
def __init__(self, **options):
""" Options: x, y, font, color, restricted, maxlength, prompt """
self.options = Config(options, ['x', '0'], ['y', '0'], ['font', 'pygame.font.Font(None, 32)'],
['color', '(0,0,0)'], ['restricted', '\'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!"#$%&\\\'()*+,-./:;<=>?#[\]^_`{|}~\''],
['maxlength', '-1'], ['prompt', '\'\''])
self.x = self.options.x; self.y = self.options.y
self.font = self.options.font
self.color = self.options.color
self.restricted = self.options.restricted
self.maxlength = self.options.maxlength
self.prompt = self.options.prompt; self.value = ''
self.shifted = False
def set_pos(self, x, y):
""" Set the position to x, y """
self.x = x
self.y = y
To render text
choose font and size
font = pygame.font.Font(None, 40)
render text as pygame.surface.Surface()
text = font.render("Hello World", 1, (255,0,0))
display in position (10,20)
surface.blit(text, (10, 20))
You can use pygame.Rect() to keep position
create rect with size of text
text_rect = text.get_rect()
change position
text_rect.x = 10
text_rect.y = 20
or
text_rect.topleft = (10, 20)
or center on screen (or on other surface like button)
text_rect.cetner = screen.get_rect().center
display using rect
surface.blit(text, text_rect)
I'm making a game in pygame and on the first screen I want there to be buttons that you can press to (i) start the game, (ii) load a new screen with instructions, and (iii) exit the program.
I've found this code online for button making, but I don't really understand it (I'm not that good at object oriented programming). If I could get some explanation as to what it's doing that would be great. Also, when I use it and try to open a file on my computer using the file path, I get the error sh: filepath :Permission denied, which I don't know how to solve.
#load_image is used in most pygame programs for loading images
def load_image(name, colorkey=None):
fullname = os.path.join('data', name)
try:
image = pygame.image.load(fullname)
except pygame.error, message:
print 'Cannot load image:', fullname
raise SystemExit, message
image = image.convert()
if colorkey is not None:
if colorkey is -1:
colorkey = image.get_at((0,0))
image.set_colorkey(colorkey, RLEACCEL)
return image, image.get_rect()
class Button(pygame.sprite.Sprite):
"""Class used to create a button, use setCords to set
position of topleft corner. Method pressed() returns
a boolean and should be called inside the input loop."""
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image, self.rect = load_image('button.png', -1)
def setCords(self,x,y):
self.rect.topleft = x,y
def pressed(self,mouse):
if mouse[0] > self.rect.topleft[0]:
if mouse[1] > self.rect.topleft[1]:
if mouse[0] < self.rect.bottomright[0]:
if mouse[1] < self.rect.bottomright[1]:
return True
else: return False
else: return False
else: return False
else: return False
def main():
button = Button() #Button class is created
button.setCords(200,200) #Button is displayed at 200,200
while 1:
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
mouse = pygame.mouse.get_pos()
if button.pressed(mouse): #Button's pressed method is called
print ('button hit')
if __name__ == '__main__': main()
Thank you to anyone who can help me.
I don't have a code example for you, but how I would do it is to:
Make a Button class, with the text to go on the button as a constructor argument
Create a PyGame surface, either of an image or filled Rect
Render text on it with the Font.Render stuff in Pygame
Blit to game screen, save that rect.
Check, on mouse click, to see the mouse.get_pos() matches a coord in the rect that it returned by the blit of the button to the main surface.
That is similar to what your example is doing, although different still.
Another good way to create buttons on pygame (in Python) is by installing the package called pygame_widgets (pip3 install pygame_widgets).
# Importing modules
import pygame as pg
import pygame_widgets as pw
# Creating screen
pg.init()
screen = pg.display.set_mode((800, 600))
running = True
button = pw.Button(
screen, 100, 100, 300, 150, text='Hello',
fontSize=50, margin=20,
inactiveColour=(255, 0, 0),
pressedColour=(0, 255, 0), radius=20,
onClick=lambda: print('Click')
)
While running:
events = pg.event.get()
for event in events:
if event.type == pg.QUIT:
running = False
button.listen(events)
button.draw()
pg.display.update()
The 'code' you have found online is not that good. All you need to make a button is this. Put this near the beginning of your code:
def Buttonify(Picture, coords, surface):
image = pygame.image.load(Picture)
imagerect = image.get_rect()
imagerect.topright = coords
surface.blit(image,imagerect)
return (image,imagerect)
Put the following in your game loop. Also somewhere in your game loop:
Image = Buttonify('YOUR_PICTURE.png',THE_COORDS_OF_THE_BUTTONS_TOP_RIGHT_CORNER, THE_NAME_OF_THE_SURFACE)
Also put this in your game loop wherever you have done for event in pygame.event.get
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
mouse = pygame.mouse.get_pos
if Image[1].collidepoint(mouse):
#code if button is pressed goes here
So, buttonify loads the image that will be on the button. This image must be a .jpg file or any other PICTURE file in the same directory as the code. Picture is its name. The name must have .jpg or anything else after it and the name must be in quotation marks. The coords parameter in Buttonify is the top-right coordinate on your screen or window that opens from pygame. The surface is this thing:
blahblahblah = pygame.surface.set_mode((WindowSize))
/|\
|
Surface's Name
So it the function makes something called 'image' which is a pygame surface, it puts a rectangle around it called 'imagerect' (to set it at a location and for the second parameter when blitting,) and then it sets it's location, and blits it on the second to last last line.
The next bit of code makes 'Image' a tuple of both 'image' and 'imagerect.'
The last code has if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: which basically means if the left mouse button is pressed. This code MUST be in for event in pygame.event.get. The next line makes mouse a tuple of the mouses position. The last line checks if the mouse cursor is inside the area of Image[1], which as we know is 'imagerect.' The code follows that.
Tell me if I need to explain further.
So you have to make a function named button which receives 8 parameters. 1)Message of button
2)X position of left top corner of the button
3)Y position of left top corner of the button
4)Width of the button
5)Height of button
6)Inactive color(background color)
7)Active color(color when you hover)
8)Name of the action you want to perfom
def button (msg, x, y, w, h, ic, ac, action=None ):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if (x+w > mouse[0] > x) and (y+h > mouse[1] > y):
pygame.draw.rect(watercycle, CYAN, (x, y, w, h))
if (click[0] == 1 and action != None):
if (action == "Start"):
game_loop()
elif (action == "Load"):
##Function that makes the loading of the saved file##
elif (action == "Exit"):
pygame.quit()
else:
pygame.draw.rect(watercycle, BLUE, (x, y, w, h))
smallText = pygame.font.Font("freesansbold.ttf", 20)
textSurf, textRect = text_objects(msg, smallText)
textRect.center = ( (x+(w/2)), (y+(h/2)) )
watercycle.blit(textSurf, textRect)
So when you create your game loop and you call the button function:
button ("Start", 600, 120, 120, 25, BLUE, CYAN, "Start" )
Here is a class for a button I made ages ago:
https://www.dropbox.com/s/iq5djllnz0tncc1/button.py?dl=0
The button is windows 7 style as far as I can remember, and I havent been able to test it recently because I do not have pygame on the computer I am using. Hope this helps!
This is a modified version of a class that was posted by someone else that worked for me on a very similar (but closed) question.
class Button():
def __init__(self, color, x,y,width,height, text=''):
self.color = color
self.ogcol = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
def draw(self,win,outline=None):
#Call this method to draw the button on the screen
if outline:
pygame.draw.rect(win, outline, (self.x-2,self.y-2,self.width+4,self.height+4),0)
pygame.draw.rect(win, self.color, (self.x,self.y,self.width,self.height),0)
if self.text != '':
font = pygame.font.SysFont('Consolas', 24)
text = font.render(self.text, 1, (0,0,0))
win.blit(text, (self.x + (self.width/2 - text.get_width()/2), self.y + (self.height/2 - text.get_height()/2)))
def isOver(self, pos):
global STATE
#Pos is the mouse position or a tuple of (x,y) coordinates
if pos[0] > self.x and pos[0] < self.x + self.width:
if pos[1] > self.y and pos[1] < self.y + self.height:
self.color = (128,128,128)
else:
self.color = self.ogcol
else:
self.color = self.ogcol
global ev
for event in ev:
if event.type == pygame.MOUSEBUTTONDOWN:
if pos[0] > self.x and pos[0] < self.x + self.width:
if pos[1] > self.y and pos[1] < self.y + self.height:
return True
The variable ev will be the events list (pygame.event.get()).
Some example syntax for it is
#class up here
btn = Button((255,0,0),100,100,200,50,text="print hi")
#do above before you start the loop
#all of the pygame init and loop
#Define screen as the window
btn.draw(screen)
if btn.isOver(pygame.mouse.get_pos()) == True:
print("hi")
pygame.display.update()