I am trying to resize my game from a menu but I am stuck. I am trying to scale the size of the screen the menu has to be when I click on new game. Does anyone have an idea on how to fix this since I cant find anything else.
import pygame
import runpy
import webbrowser, os
from Game import *
pygame.init()
class Option:
hovered = False
def __init__(self, text, pos):
self.text = text
self.pos = pos
self.set_rect()
self.draw()
def draw(self):
self.set_rend()
screen.blit(self.rend, self.rect,)
def set_rend(self):
self.rend = menu_font.render(self.text, True, self.get_color())
def get_color(self):
if self.hovered:
return (255,255,255)
else:
return (100,100,100)
def set_rect(self):
self.set_rend()
self.rect = self.rend.get_rect()
self.rect.topleft = self.pos
def onSelect(self):
if self.text == "Quit":
pygame.quit()
quit()
if self.text == "Instructions":
webbrowser.open_new("file://" + os.path.realpath("Manual.pdf"))
**if self.text == "New game":
Main()**
class Background(pygame.sprite.Sprite):
def __init__(self, image_file,):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
pygame.init()
pygame.mixer.music.load('Really Slow Motion - Fjord Keeper (Epic Intense Uplifting).mp3')
pygame.mixer.music.play(-1)
BackGround = Background('bg.png')
screen = pygame.display.set_mode((480, 320))
menu_font = pygame.font.Font(None, 40)
options = [Option("New game", (2, 195)), Option("Instructions", (2, 245)),
Option("Quit", (2, 295))]
while True:
pygame.event.pump()
screen.fill((0, 0, 0))
screen.blit(BackGround.image, BackGround.rect)
ev = pygame.event.get()
for event in ev:
if event.type == pygame.QUIT:
pygame.quit()
for option in options:
if option.rect.collidepoint(pygame.mouse.get_pos()):
option.hovered = True
else:
option.hovered = False
if option.hovered:
for event in ev:
if event.type == pygame.MOUSEBUTTONDOWN:
option.onSelect()
option.draw()
pygame.display.update()
This is my menu so far, but I'm trying to scale it so it will be 1300x1000.
I'm on mobile and I don't know how to do the code thing so I'll just type it out, k? K....
screen = pygame.display.set_mode((1300, 1300))
Put this where you want it to change. So lets say you put it as the f key. Then when you press f it should change the screen res to the set_mode.
just reset the display:
screen=pg.display.set_mode((1300,1000))
If you put this wherever you want the screen size to change, it'll work :)
Related
I'm trying to learn OOP but my pygame window wont update with the background I'm trying to put in. The gameObject class is in another file. Filling it with white color also isn't working and I don't know why. I was able to display a background on another project I did but I cant now and I have no idea what's different. I have compared the code and they seem like they should be doing the same thing.
gameObject.py
import pygame
class GameObject:
def __init__(self, x, y, width, height, image_path):
self.background= pygame.image.load(image_path)
self.background = pygame.transform.scale(self.background, (width, height))
self.x = x
self.y = y
self.width = width
self.height = height
main.py
import pygame
from gameObject import GameObject
pygame.init()
class Player(GameObject):
def __init__(self, x, y, width, height, image_path, speed):
super().__init__(x, y, width, height, image_path)
self.speed = speed
def move(self, direction, max_height):
if (self.y >= max_height - self.height and direction > 0) or (self.y <= 0 and direction < 0):
return
self.y += (direction * self.speed)
class Game:
def __init__(self):
self.width = 800
self.height = 800
self.color = (255, 255, 255)
self.game_window = pygame.display.set_mode((self.width, self.height))
self.clock = pygame.time.Clock()
self.background = GameObject(0, 0, self.width, self.height, 'assets/background.png')
self.player1 = Player(375, 700, 50, 50, 'assets/player.png', 10)
self.level = 1.0
def draw_objects(self):
self.game_window.fill(self.white_color)
self.game_window.blit(self.background.image, (self.background.x, self.background.y))
pygame.display.update()
def run_game_loop(self):
gameRunning = True
while gameRunning:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameRunning = False
if gameRunning == False:
pygame.quit()
self.draw_objects()
self.clock.tick(60)
game = Game()
game.run_game_loop()
quit()
I have tried basic research on it and looking at other code that uses a custom background with pygame
It is a matter of indentation. self.draw_objects() must be called in the application loop not after the application loop:
class Game:
# [...]
def run_game_loop(self):
gameRunning = True
while gameRunning:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameRunning = False
if gameRunning == False:
pygame.quit()
# INDENTATION
#-->|
self.draw_objects()
self.clock.tick(60)
Your loop never actually does anything but clear the event queue looking for pygame.QUIT.
You need to indent the calls to self.draw_objects() and self.clock.tick(60) so they are inside the loop.
I want to remove the sprite and not display it on screen after click. The screenshot show that the sprite is successfully removed from the group, but it is still drawn on the screen. I would be happy to get help on this matter.
import pygame as pg
class Figure1(pg.sprite.Sprite):
def __init__(self, width: int, height: int):
super().__init__()
self.image = pg.Surface((width, height))
self.image.fill((0,0,0))
self.rect = self.image.get_rect()
class Game:
def __init__(self, main_surface: pg.Surface):
self.main_surface = main_surface
self.group = pg.sprite.Group()
self.main_sprite = Figure1(40,40)
self.group.add(self.main_sprite)
self.group.draw(self.main_surface)
self.selected = None
def btn_down(self, pos, btn):
if btn == 1:
if self.main_sprite.rect.collidepoint(pos):
print(self.group.sprites())
print(self.main_sprite.alive())
self.main_sprite.kill()
print(self.group.sprites())
print(self.main_sprite.alive())
self.group.draw(self.main_surface)
pg.init()
clock = pg.time.Clock()
screen = pg.display.set_mode((200,200))
screen.fill((100,100,100))
pg.display.update()
g = Game(screen)
run = True
while run:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
run = False
if event.type == pg.MOUSEBUTTONDOWN:
g.btn_down(event.pos, event.button)
clock.tick(60)
pg.display.update()
The sprite doesn't disappear just because you stop drawing it. Of course, you need to clear the screen. You have to clear the screen in every frame. 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()
import pygame as pg
class Figure1(pg.sprite.Sprite):
def __init__(self, width: int, height: int):
super().__init__()
self.image = pg.Surface((width, height))
self.image.fill((0,0,0))
self.rect = self.image.get_rect()
class Game:
def __init__(self, main_surface: pg.Surface):
self.main_surface = main_surface
self.group = pg.sprite.Group()
self.main_sprite = Figure1(40,40)
self.group.add(self.main_sprite)
self.selected = None
def btn_down(self, pos, btn):
if btn == 1:
if self.main_sprite.rect.collidepoint(pos):
self.main_sprite.kill()
def draw(self):
self.group.draw(self.main_surface)
pg.init()
clock = pg.time.Clock()
screen = pg.display.set_mode((200,200))
g = Game(screen)
run = True
while run:
# limit the frames per second
clock.tick(60)
# handle the events and update objects
for event in pg.event.get():
if event.type == pg.QUIT:
run = False
if event.type == pg.MOUSEBUTTONDOWN:
g.btn_down(event.pos, event.button)
# clear the screen
screen.fill((100,100,100))
# draw the objects
g.draw()
# update the display
pg.display.update()
pg.quit()
For some reason, my return isn't working. This is from a tutorial. When I download the file and edit it from there it works, but if I copy and paste it from the exact file it doesn't work. Sorry, I am a beginner - open to any suggestions
The is the tutorial I used:
https://www.youtube.com/watch?v=G8MYGDf_9ho
Code:
import pygame
import sys
pygame.init()
WinHeight = 600
WinWidth = 900
Window = pygame.display.set_mode((WinWidth,WinHeight))
#button class
class Button():
def __init__(self, x, y, image, scale):
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.scale(image, (int(width * scale), int(height * scale)))
self.rect = self.image.get_rect()
self.rect.topleft = (x, y)
self.clicked = False
def draw(self, surface):
action = False
#get mouse position
pos = pygame.mouse.get_pos()
#check mouseover and clicked conditions
if self.rect.collidepoint(pos):
if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
self.clicked = True
action = True
if pygame.mouse.get_pressed()[0] == 0:
self.clicked = False
#draw button on screen
surface.blit(self.image, (self.rect.x, self.rect.y))
return action
Good_ball_img = pygame.image.load("GoodBall.png")
Bad_ball_img = pygame.image.load("BadBall.png")
#Button instances
Good_ball = Button(100,100,Good_ball_img,2)
Bad_ball = Button(200,200,Bad_ball_img,3)
def drawwin():
Window.fill((202,241,208))
Good_ball.draw(Window)
Bad_ball.draw(Window)
pygame.display.update()
def Main():
run = True
while run:
if Good_ball.draw(Window):
print("green clicked")
if Bad_ball.draw(Window)=="t":
print("red clicked")
for event in pygame.event.get():
#quit game
if event.type == pygame.QUIT:
run = False
pygame.quit()
sys.exit()
drawwin()
checkpress()
if __name__ == "__main__":
Main()
Code works for me if I change order - first process all events later check mouse position.
Problema can be because PyGame updates values in pygame.mouse and pygame.key only if you run pygame.event.get() - so it may need pygame.event.get() or at least pygame.event.pump() before other functions.
for event in pygame.event.get():
#quit game
if event.type == pygame.QUIT:
run = False
pygame.quit()
sys.exit()
if Good_ball.draw(Window):
print("green clicked")
if Bad_ball.draw(Window):
print("red clicked")
EDIT:
In documentation for pygame.event there is
To get the state of various input devices, you can forego the event queue and
access the input devices directly with their appropriate modules: `pygame.mouse`,
`pygame.key` and `pygame.joystick`. If you use this method, remember
that pygame requires some form of communication with the system window manager
and other parts of the platform. To keep pygame in sync with the system,
you will need to call `pygame.event.pump()` to keep everything current.
Minimal working code - with surfaces instead images so everyone can simply copy and run it
import pygame
import sys
# --- constants --- # PEP8: `UPPER_CASE_NAMES`
WINDOW_WIDTH = 900
WINDOW_HEIGHT = 600
# --- classes --- # PEP8: `CamelCaseNames`
class Button():
def __init__(self, x, y, image, scale):
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.scale(image, (int(width * scale), int(height * scale)))
self.rect = self.image.get_rect()
self.rect.topleft = (x, y)
self.clicked = False
def check_click(self):
action = False
# get mouse
pos = pygame.mouse.get_pos()
left_button = pygame.mouse.get_pressed()[0]
# check mouseover and clicked conditions
if left_button:
if self.rect.collidepoint(pos) and not self.clicked:
self.clicked = True
action = True
else:
self.clicked = False
return action
def draw(self, surface):
# draw button on screen
surface.blit(self.image, self.rect)
# --- functions --- # PEP8: `lower_case_names`
def draw_window(window):
window.fill((202, 241, 208))
good_ball.draw(window)
bad_ball.draw(window)
pygame.display.update()
# --- main ---
pygame.init()
window = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
# button class
#good_ball_img = pygame.image.load("GoodBall.png")
good_ball_img = pygame.Surface((100, 50))
good_ball_img.fill((0, 255, 0))
#bad_ball_img = pygame.image.load("BadBall.png")
bad_ball_img = pygame.Surface((100, 50))
bad_ball_img.fill((255,0,0))
# Button instances
good_ball = Button(100, 100, good_ball_img, 2) #
bad_ball = Button(200, 200, bad_ball_img, 3)
run = True
while run:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
sys.exit()
# - checks and updates -
if good_ball.check_click():
print("green clicked")
if bad_ball.check_click():
print("red clicked")
#checkpress()
# - draws -
draw_window(window)
PEP 8 -- Style Guide for Python Code
class menu:
hover = False
def __init__(self, text, pos):
self.text = text
self.pos = pos
self.set_rect()
self.draw()
def draw(self):
self.set_render()
screen.blit(self.render, self.rect)
def set_render(self):
self.render = subFont.render(self.text, True, self.get_color())
def get_color(self):
if self.hover:
return (BLACK)
else:
return (GREEN)
def set_rect(self):
self.set_render()
self.rect = self.render.get_rect()
self.rect.topleft = self.pos
select = [menu("Computer Virus", (100, 200)),
menu("Computer Crime", (100, 300)),
menu("QUIT", (100, 400))]
running = True
while running:
for evnt in event.get():
if evnt.type == QUIT:
running = False
screen.fill(WHITE)
title()
for menu in select:
if menu.rect.collidepoint(mouse.get_pos()):
menu.hover = True
else:
menu.hover = False
menu.draw()
pointer()
display.update()
This is my game menu where hovering over will allow you it to change colour
Im planning to make it so the that when you click on one of the options, it would bring you elsewhere. How do I find the position of the rect and with which text it the mouse collides with?
This code does what you want:
class menu:
hover = False
def __init__(self, text, pos, callback):
self.text = text
self.pos = pos
self.callback = callback # so we now what function to call
self.set_rect()
self.draw()
# the rest of your code
def quit_loop():
global running
running = False
select = [menu("Computer Virus", (100, 200), lambda: print("Computer Virus")), # Add a callback
menu("Computer Crime", (100, 300), lambda: print("Computer Crime")),
menu("QUIT", (100, 400), quit_loop)]
running = True
while running:
for evnt in event.get():
if evnt.type == QUIT:
running = False
if evnt.type == MOUSEBUTTONDOWN: # if a mousebutton got pressed
if evnt.button == 1: # if the first button got pressed
for menu in select:
if menu.rect.collidepoint(evnt.pos): # does this one collide
menu.callback() # call the callback
I have this code for a button that is pressable:
def button(msg,xloc,yloc,xlong,ylong,b1,b2,action=None):
hover = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if xloc < hover [0] < xloc+xlong and yloc< hover [1] < yloc+ylong:
pygame.draw.rect(display, b1, (xloc ,yloc ,xlong,ylong))
if click [0]==1 and action != None:
action()
else:
pygame.draw.rect(gameDisplay, inactiveButton, (xloc ,yloc ,xlong,ylong))
label = pygame.font.SysFont("arial",16)
textSurf, textBox = textMsg(msg, label)
textBox.center = ((xloc +(300)),((yloc +(150))
gameDisplay.blit(textSurf,textBox)
and the code for the scoring is:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN:
score+=1
print (score)
I would like have a score that – upon pressing the correct button in the choices in order to answer in a quiz game – will be displayed and incremented by 1. How can I do that?
Here's the simplest way to implement a button that I know. Create a rect for the button and draw it with pygame.draw.rect (or blit an image). For the collision detection, check if the event.pos of a pygame.MOUSEBUTTONDOWN event collides with the rect and then just increment the score variable.
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
GRAY = pg.Color('gray15')
BLUE = pg.Color('dodgerblue1')
def main():
clock = pg.time.Clock()
font = pg.font.Font(None, 30)
button_rect = pg.Rect(200, 200, 50, 30)
score = 0
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1:
if button_rect.collidepoint(event.pos):
print('Button pressed.')
score += 1
screen.fill(GRAY)
pg.draw.rect(screen, BLUE, button_rect)
txt = font.render(str(score), True, BLUE)
screen.blit(txt, (260, 206))
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
main()
pg.quit()
Addendum: Actually, I would implement a button with the help of classes, sprites and sprite groups. If you don't know how classes and sprites work, I'd recommend to check out Program Arcade Games (chapter 12 and 13).
import pygame as pg
pg.init()
GRAY= pg.Color('gray12')
BLUE = pg.Color('dodgerblue1')
FONT = pg.font.Font(None, 30)
# The Button is a pygame sprite, that means we can add the
# instances to a sprite group and then update and render them
# by calling `sprite_group.update()` and `sprite_group.draw(screen)`.
class Button(pg.sprite.Sprite):
def __init__(self, pos, callback):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((50, 30))
self.image.fill(BLUE)
self.rect = self.image.get_rect(topleft=pos)
self.callback = callback
def handle_event(self, event):
"""Handle events that get passed from the event loop."""
if event.type == pg.MOUSEBUTTONDOWN:
if self.rect.collidepoint(event.pos):
print('Button pressed.')
# Call the function that we passed during the
# instantiation. (In this case just `increase_x`.)
self.callback()
class Game:
def __init__(self):
self.screen = pg.display.set_mode((800, 600))
self.clock = pg.time.Clock()
self.x = 0
self.button = Button((200, 200), callback=self.increase_x)
self.buttons = pg.sprite.Group(self.button)
self.done = False
# A callback function that we pass to the button instance.
# It gets called if a collision in the handle_event method
# is detected.
def increase_x(self):
"""Increase self.x if button is pressed."""
self.x += 1
def run(self):
while not self.done:
self.handle_events()
self.run_logic()
self.draw()
self.clock.tick(30)
def handle_events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
for button in self.buttons:
button.handle_event(event)
def run_logic(self):
self.buttons.update()
def draw(self):
self.screen.fill(GRAY)
self.buttons.draw(self.screen)
txt = FONT.render(str(self.x), True, BLUE)
self.screen.blit(txt, (260, 206))
pg.display.flip()
if __name__ == "__main__":
Game().run()
pg.quit()