I am trying to create a menu screen for my game. At the moment im using sprites for buttons and everything works well, and I can create an infinite amount of buttons (currently I just have Start and Options), but only the first button I call appears on the screen. I think it has something to do with the while loop in the button class but I am not sure on how to fix it. I am probably making no sense here so if you need me to clarify anything I will. Thanks!
import pygame
import random
import time
pygame.init()
#colours
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,155,0)
blue = (50,50,155)
display_width = 800
display_height = 600
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('Numeracy Ninjas')
clock = pygame.time.Clock()
img_button_start = pygame.image.load('Sprites/Buttons/button_start.png')
img_button_options = pygame.image.load('Sprites/Buttons/button_options.png')
gameDisplay.fill(white)
class Button(pygame.sprite.Sprite):
def __init__(self, sprite, buttonX, buttonY):
super().__init__()
gameDisplay.blit(sprite, (buttonX, buttonY))
pygame.display.update()
running = True
while (running):
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
# Set the x, y postions of the mouse click
x, y = event.pos
print(x, y)
if x <= (150 + buttonX) and x >=(0 + buttonX) and y <= (75 + buttonY) and y >= (0 + buttonY):
print('clicked on button')
def gameIntro():
button_start = Button(img_button_start, 27, 0)
button_options = Button(img_button_options, 27, 500)
gameIntro()
In the constructor of your Button class, you have an infinite loop. This means you never get to the code part where you make your second Button.
def gameIntro():
button_start = Button(img_button_start, 27, 0) #stuck in infinite loop
print('This print statement is never reached')
button_options = Button(img_button_options, 27, 500)
Instead, what you want to do is initialize two Buttons, and then have a main game loop in your gameIntro() method that checks for events. If a mousebuttondown event occured, you want to pass the event (or even just the event position, if you don't care which mouse button was clicked) to a function of button that checks whether this instance of button was clicked and then handles the input (possibly by returning something which you handle in the main game loop).
Note that I haven't run the following code, I'm just trying to give you an idea how it should be structured:
class Button(pygame.sprite.Sprite):
def __init__(self, image, buttonX, buttonY):
super().__init__()
self.image = image
self.rect = image.getRect()
self.rect.x = buttonX
self.rect.y = buttonY
def wasClicked(event):
if self.rect.collidepoint(event.pos):
return True
def gameIntro():
#initialize buttons
buttons = pygame.sprite.Group() #make a group to make drawing easier
button_start = Button(img_button_start, 27, 0)
button_options = Button(img_button_options, 27, 500)
#draw buttons to display
buttons.draw(gameDisplay)
pygame.display.update()
#main game loop
running = True
while (running):
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
#check for every button whether it was clicked
for btn in buttons:
if btn.wasClicked():
#do something appropriate
if event.type == pygame.QUIT:
pygame.quit()
Related
I am making a text based RPG as my first python/pygame project. In my game I would like to present the player with choices then ask them to type it in. I was able to download and import a module which accepts user input and displays it on the screen. However, before using it for anything like..lets say, if the user input is 'yes', then they go to a new area, I'd like the program to only accept the user input once they hit the enter key. I believe the tutorial for the textinput module I downloaded has directions to do this, but to be honest I just don't understand what it's saying. I've tried multiple types of loops but nothing is happening. Any help will be appreciated. Here is my main game code:
import pygame_textinput
import pygame
pygame.init()
#fps
clock=pygame.time.Clock()
# create font here
font_name = pygame.font.get_default_font()
WHITE_TEXT_COLOR = (255, 255, 255)
# create screen and window and display and font here
screen_width, screen_height = 800, 700
background_color_black = (0, 0, 0)
screen = pygame.display.set_mode((screen_width, screen_height))
our_game_display = pygame.Surface((screen_width, screen_height))
pygame.display.set_caption('MyRPGGame')
#create text input object
textinput = pygame_textinput.TextInput()
def draw_text(text, size, x, y):
pygame.font.init()
font = pygame.font.Font(font_name, size)
text_surface = font.render(text, True, WHITE_TEXT_COLOR)
text_rect = text_surface.get_rect()
text_rect.center = (x, y)
our_game_display.blit(text_surface, text_rect)
def choose_to_play():
draw_text("You've decided to play",20,screen_width/2,screen_height/2+50)
def first_area():
our_game_display.fill(background_color_black)
draw_text('The story of this game depends on your choices. Do you wish to play?', 20, screen_width / 2,screen_height / 2 - 100)
draw_text('Type your answer and hit enter.', 20, screen_width / 2,screen_height / 2 - 50)
draw_text('Yes', 20, screen_width/2,screen_height/2+50)
draw_text('No', 20, screen_width/2,screen_height/2+100)
screen.blit(our_game_display, (0, 0))
pygame.display.update()
while True:
our_game_display.fill((background_color_black))
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
exit()
first_area()
# Feed it with events every frame
textinput.update(events)
# Blit its surface onto the screen
screen.blit(textinput.get_surface(), (10, 600))
pygame.display.update()
clock.tick(30)
Now here is the source for the pygame textinput module, figured I would link to the code so this post isn't too crowded:
https://github.com/Nearoo/pygame-text-input
You need to a variable for the state of the game. Once enter is pressed change the state. Implement different cases in the application loop depending on the state of the game::
game_state = 'start'
while True:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
game_state = 'input'
our_game_display.fill((background_color_black))
if game_state == 'input':
textinput.update(events)
# [...]
This is my python code, using pygame. When I pressed my mouse down, scene 1 does not switch to scene 2. I am coming from Code HS, so the scene switch is from the Tell A Story project. I realized that code is not the same as pygame's. So I used pygame docs and see what I can learn from that, but nothing still. Please can any one help me. Thank you.
import pygame as pg
pg.init()
win = pg.display.set_mode((500,500))
pg.display.set_caption('Scene Switcher')
center_x = 250 - 130
center_y = 250
black= (0,0,0)
red = (255,0,0)
blue = (0,0,255)
def ct(font, size, text, color):
mf = pg.font.Font(font, size)
t = mf.render(text, True, color)
return t
def draw_scene1():
print("This is Scene 1")
txt = ct("SB.ttf", 40, "Hello World!", black)
win.blit(txt, (center_x,center_y))
def draw_scene2():
print("This is scene 2")
txt2 = ct("SB.ttf", 40, "scene2 ", black)
win.blit(txt2, (center_x,center_y))
while True:
win.fill(red)
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
quit()
mouses = pg.mouse.get_pressed()
scene_counter = 0
# When this function is called the next scene is drawn.
def draw_next_screen():
global scene_counter
scene_counter += 1
if scene_counter == 1:
draw_scene1()
else:
draw_scene2()
if mouses:
draw_next_screen()
pg.display.update()
You have to initialize scene_counter before the application loop rather than in the application loop.
The pygame.mouse.get_pressed() returns a list of Boolean values that represent the state (True or False) of all mouse buttons. The state of a button is True as long as a button is held down. Therefor the scene_counter is continuously incremented in each frame as long a mouse button is hold down.
The MOUSEBUTTONDOWN event occurs once when you click the mouse button and the MOUSEBUTTONUP event occurs once when the mouse button is released. Increment the counter when the MOUSEBUTTONDOWN event occurs:
scene_counter = 0
run = True
while run:
for event in pg.event.get():
if event.type == pg.QUIT:
run = False
elif event.type == pg.MOUSEBUTTONDOWN:
scene_counter += 1
win.fill(red)
if scene_counter == 0:
draw_scene1()
else:
draw_scene2()
pg.display.update()
pg.quit()
import pygame
#Initialise pygame
pygame.init()
#Create the screen
screen = pygame.display.set_mode((1200,800))
#Change the title and the icon
pygame.display.set_caption('The Thoughtful Minds')
icon = pygame.image.load('IA.png')
pygame.display.set_icon(icon)
#Dots
dot = pygame.image.load('point.png')
class Dot:
def update(self):
self.cx, self.cy = pygame.mouse.get_pos()
def draw(self):
screen.blit(dot,(self.cx-8 , self.cy-8))
dots = [Dot() for i in range(5)]
sticking_image = False
i = 0
#Running the window
running = True
while running:
screen.fill((20,20,20))
mp = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
dots[i].update()
sticking_image = True
if sticking_image:
for i in range(i):
dots[i].draw()
i += 1
pygame.display.flip()
pygame.quit()
quit()
When I run my program it says, 'Dot' object has no attribute 'cx'
I really don't know how to fix this
Please help
What I mainly want to do is to create a screen that allows the user to draw a dot wherever he clicks in the screen.
I mean multiple dots, I don't need just one
Add a constructor to the class Dot and remove update:
class Dot:
def __init__(self, pos):
self.cx, self.cy = pos
def draw(self):
screen.blit(dot,(self.cx-8 , self.cy-8))
Create an empty list of dots:
dots = []
Create a Dot object at the current mouse position and add it to the list of dots, when the mouse button is pressed:
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
# append a new dot at the current mouse position
dots.append(Dot(event.pos))
# clear the display
screen.fill((20,20,20))
# draw all the dots
for d in dots:
d.draw()
# update the dispalay
pygame.display.flip()
When I press a button, two buttons are being pressed.
I made images to act like a button but when I press the first button, the second button is pressed too.
I'm new to pygame and trying to make the buttons do separate things when I click each one.
import pygame
import time
pygame.init();
screen = pygame.display.set_mode((340,340));
img = pygame.image.load('3.gif')
iimg = pygame.image.load('2.gif')
mg = pygame.image.load('4.gif').convert()
g = pygame.image.load('5.gif')
waitingForInput = False
pygame.display.set_caption("SIMON");
BEEP1 = pygame.mixer.Sound('beep1.wav')
BEEP2 = pygame.mixer.Sound('beep2.wav')
BEEP3 = pygame.mixer.Sound('beep3.wav')
BEEP4 = pygame.mixer.Sound('beep4.wav')
screen.blit(img,(0,0))
screen.blit(mg,(150,0))
pygame.display.flip()
def main():
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = event.pos
if img.get_rect().collidepoint(mouse_pos):
print ('button was pressed at {0}'.format(mouse_pos))
BEEP1.play()
screen.blit(iimg,(0,0))
pygame.display.flip()
time.sleep(.30)
screen.blit(img,(0,0))
pygame.display.flip()
if mg.get_rect().collidepoint(mouse_pos):
print ('button was pressed at {0}'.format(mouse_pos))
BEEP2.play()
screen.blit(g,(150,0))
pygame.display.flip()
time.sleep(.30)
screen.blit(mg,(150,0))
pygame.display.flip()
main()
If you call get_rect on a Surface, the resulting Rect that is returned will always have an x and y value of 0.
So when you run if img.get_rect().collidepoint(mouse_pos) in your event loop, you're NOT checking if the Surface was a clicked. You check if the mouse position is in the top left corner of the screen.
Maybe use some print statements to check for yourself.
What you can do is to create a Rect for each button outside of your main loop, and then use these rects for blitting:
...
img = pygame.image.load('3.gif')
img_rect = img.get_rect()
...
mg = pygame.image.load('4.gif').convert()
mg_rect = img.get_rect(topleft=(150,0))
...
while True:
...
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = event.pos
if img_rect().collidepoint(mouse_pos):
BEEP1.play()
if mg_rect ().collidepoint(mouse_pos):
BEEP2.play()
screen.blit(img, img_rect)
screen.blit(mg, mg_rect)
Note that you also should avoid time.sleep or multiple calls of pygame.display.flip() in your main loop.
Another solution is to use the pygame's Sprite class, which allows you to combine a Surface and a Rect.
I am trying to have an onclick button print a check and run my pencil function. At the moment if I hover over the Box sprite.. it will run the print and pencil function. It should be ONCLICK it runs those 2. Can anyone help me out? Thanks! (this should be all relevant code, if you need more please let me know :)
class Box(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((35, 30))
self.image = self.image.convert()
self.image.fill((255, 0, 0))
self.rect = self.image.get_rect()
self.rect.centerx = 25
self.rect.centery = 505
self.dx = 10
self.dy = 10
while keepGoing:
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
box = Box()
allSprites = pygame.sprite.Group(box)
allSprites.draw(screen)
if event.type == MOUSEMOTION:
x,y = event.pos
if box.rect.collidepoint(x,y) and pygame.MOUSEBUTTONUP:
print("collide works")
pencil(background,clock,keepGoing,screen)
pygame.display.flip()
Your code is not checking for mouse clicks, but rather mouse movement.
If you want to be testing for a click on your box, change condition to check for MOUSEBUTTONDOWN or MOUSEBUTTONUP events (depending on what part of the click you want to react to), rather than MOUSEMOTION events.
There are some other issues with your code though. For instance, you're creating your Box and Group after every event. Probably you want to just create them once, before going into the game loop (this will both make more sense and perform better).