I have some issues with the fullscreen option of pygame. Here is some code that simply draws a blue window and by pressing R we can switch between blue and purple. Then we can also toggle between fullscreen and windowed mode using F or G. F is implemented explicitly and G uses the method toggle_fullscreen().
import pygame, sys
from pygame.locals import *
#Initializes pygame
pygame.init()
#Defines the Clock object
clock = pygame.time.Clock()
#Just draws a blue screen
size = (960, 540)
blue = (0,0,100)
purp = (100,0,100)
is_blue = True
display_surf = pygame.display.set_mode(size, RESIZABLE)
display_surf.fill(blue)
mainLoop = True
is_fullscreen = False
#Mainloop
while mainLoop:
dt = clock.tick(12)
for event in pygame.event.get():
if event.type == pygame.QUIT:
mainLoop = False
if event.type == pygame.KEYDOWN:
#Single key pressed
if event.key == K_f:
#Toggles fullscreen
is_fullscreen = not is_fullscreen
old_surface = display_surf
setmode = FULLSCREEN if is_fullscreen else RESIZABLE
display_surf = pygame.display.set_mode(size, setmode)
display_surf.blit(old_surface, (0,0))
del old_surface
if event.key == K_q:
#Quits the app
mainLoop = False
if event.key == K_r:
#Redraws the blue or purple
print("Trying to flip colors")
display_surf.fill(purp if is_blue else blue)
is_blue = not is_blue
if event.key == K_g:
#Toggles fullscreen with the dedicated method
is_fullscreen = not is_fullscreen
pygame.display.toggle_fullscreen()
pygame.display.update()
pygame.quit()
I am on Ubuntu 18.04 using Python 3.6.8. Here are my observations:
Using pygame 2.0.0.dev6, when going fullscreen with either F or G the screen does the following:
flashes a few times
goes in the task bar as a minimized icon
if I click on the icon the screen flashes a few more times and finally we are fullscreen
problem: the screen is entirely black and the button R does not flip the colors (but prints the message)
Still using pygame 2.0.0.dev6. In this case the G and the F button behave differently: when going back from fullscreen to windowed with G, the R button doesn't flip the colors, even in the windowed version. When using F instead it works.
With pygame version 2.0.0.dev3 the G button does not work at all, while F has the same behavior as before.
My major problem is 1.4.: the fullscreen mode is entirely black.
Now let's do a modification. Change the following line in the code for the F button
setmode = FULLSCREEN|SCALED if is_fullscreen else RESIZABLE #FULLSCREEN -> FULLSCREEN|SCALED
This goes fullscreen with the current screen resolution and not the one I specify at the top. Now the problems 1.1., 1.2 and 1.3. are gone: the app goes to fullscreen immediately. But the problem 1.4. persists and furthermore the program does not accept inputs anymore. If I press Q it won't quit. It doesn't take Alt+Tab or Alt+F4 and so I have to restart the computer.
pygame.display.set_mode creates a pygame.Surface object, which is associated to the window. When pygame.display.set_mode() is called a again, then the object which was associated to the surface before gets invalide.
You've to copy() the "old" surface:
is_fullscreen = not is_fullscreen
old_surface = display_surf.copy()
setmode = FULLSCREEN if is_fullscreen else RESIZABLE
display_surf = pygame.display.set_mode(size, setmode)
display_surf.blit(old_surface, (0,0))
Related
I'm making a game analyser, and I thought it would be nice if I had a user iterface instead of just using text and raw input to communicate. I am having problems with 'blitting' an image to my screen.
My image is inside the pycharm file called 'CATANYLISER' as is my code.
import pygame
pygame.init()
# py-game variables
(width, height) = (1000, 600)
window = pygame.display.set_mode((width, height))
window_title = pygame.display.set_caption('the CATANALYSER')
does_quit = False
# py-game images
empty_board = pygame.image.load('empty_board.png')
# py-game window loop
while not does_quit:
# receives input from window
for event in pygame.event.get():
# stops program when red x clicked
if event.type == pygame.QUIT:
does_quit = True
window.blit(empty_board, (0, 0))
pygame.display.update()
# activates when the loop finishes, just makes sure everything shuts down properly
pygame.quit()
The expected result is the image on the screen in the top left corner. However when I run the program, I have an empty screen (pygame.QUIT still works).
When I run this code there is no error message, and I am completely lost about how to fix this.
first, make sure that the empty_board.png is in your working directory.
Second, you have to clear the screen before each frame using window.fill([255, 255, 255])
Finally, you could try using pygame.display.flip() instead of update()
My code would look like:
import pygame
pygame.init()
window = pygame.display.set_mode([640, 480])
doQuit = False
board = pygame.image.load("empty_board.png")
while not doQuit:
window.fill([255, 255, 255])
window.blit(board, (0, 0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
doQuit = True
pygame.quit()
Below is some code I'm testing to integrate Tkinter and Pygame together. I've managed to get a pygame display inside a Tkinter window, and also show a button ontop of this pygame display. The button simply draws a white circle. The problem starts immediately by not drawing Tkinter's configured cursor (X_cursor) when the program starts. Then, when I mouse over the button and back off of it the cursor starts to flash to pygame's default cursor and then back to Tkinter's configured cursor. Also, the cursor only reverts to pygame's default if the mouse is in motion. Otherwise, it's the correct "X_Cursor".
I'm having a hard time understanding Tkinter's system, and I'm sure the solution is in my face. I just need a little help figuring it out.
import pygame
import pygame.key
from pygame.locals import *
import tkinter as tk
from tkinter import *
import os
#colors#
BLACK = (0,0,0)
WHITE = (255, 255, 255)
GREEN = (0, 255,0)
RED = (255, 0,0)
BLUE = (0,0, 255)
#buttons#
mButton1 = (1, 0, 0)
mButton2 = (0, 1, 0)
mButton3 = (0, 0, 1)
root = tk.Tk()
root.attributes('-fullscreen', True)
root.title("This title isn't visible since it's fullscreen")
root.config(cursor = "X_cursor")
embed = tk.Frame(root, width = 1920, height = 1080) #creates embed frame for pygame window
embed.grid(columnspan = 10, rowspan = 10) # Adds grid
os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
worldWindow = pygame.display.set_mode((0,0), RESIZABLE)
worldWindow.fill(BLACK)
def draw():
pygame.draw.circle(worldWindow, WHITE, (250,250), 125)
IMAGEOBJECT = PhotoImage( file = 'TESTIMAGE.gif')
buttonwin = tk.Frame(root, width = 75, height = 75)
buttonwin.grid(row =8, column = 8)
button1 = Button(root, image = IMAGEOBJECT,text = "Draw a circle", cursor = "circle", command=draw)
button1.grid(row =8 , column = 8)
pygame.display.init()
#loop until user clicks close button
done = False
clock = pygame.time.Clock()
#~~~~~~~~MAIN LOOP~~~~~~~~#
while not done:
for event in pygame.event.get():
if (event.type == pygame.QUIT) or (event.type == pygame.KEYDOWN and pygame.K_ESCAPE):
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:
mButton = pygame.mouse.get_pressed()
if mButton == mButton1:
pos = pygame.mouse.get_pos()
print(pos)
else:
pygame.event.clear()
#limit to 60 frames per second
clock.tick(60)
#update the screen with all the draws
pygame.display.update()
root.update()
pygame.quit()
It appears to be tkinter and pygame 'fighting' over who shows the cursor. I added this to the pygame event loop to check.
elif event.type == pygame.MOUSEMOTION:
pygame.mouse.set_cursor(*pygame.cursors.diamond)
The behavior stays the same, now showing the diamond cursor while moving and 'X' Cursor when stopped. When I comment out the tkinter cursor config, I then get the windows os default cursor when motion is stopped.
The easiest solution in my mind would be to load the tkinter 'X' into pygame cursor compiler and use that as its default or under the Mouse motion event (details in link).
https://www.pygame.org/docs/ref/cursors.html
Another option I kinda liked the look of, would be to use this cursor in the mouse motion elif.
*pygame.cursors.broken_x
I have created some sort of menu navigation system in my game. All the screens are blitted in. The "Play" and "Quit" and "Controls" button works just fine but when I try to press menu from the controls screen, nothing happens. On the controls screen, you can faintly see the first menu screen from before. That might be the problem. I think that as the return to menu button is over the previous controls page button, it somehow is pressing the controls button from before. The button and menu segment of my code will be pasted here and the full thing will be pasted in a pastebin.
def text_to_button(msg,color,buttonx,buttony,buttonwidth,buttonheight,size = "small"):
textSurf, textRect = text_objects(msg,color,size)
textRect.center = ((buttonx + buttonwidth/2)), buttony+(buttonheight/2)
gameDisplay.blit(textSurf, textRect)
def button(text,x,y,width,height,inactive_color,active_color,size = "small",action = None):
cur = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
#print(click)
if x + width > cur[0] > x and y + height > cur[1] > y:
pygame.draw.rect(gameDisplay, active_color,(x,y,width,height))
if click[0] == 1 and action != None:
if action == "quit":
pygame.quit()
quit()
if action == "controls":
game_controls()
if action == "play":
gameLoop()
if action == "main":
game_intro()
else:
pygame.draw.rect(gameDisplay, inactive_color,(x,y,width,height))
text_to_button(text,black,x,y,width,height,size)
def game_controls():
gcont = True
while gcont:
gameDisplay.blit(cont,(0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
button("Play",150,500,100,50,white,gray,"small",action = "play")
button("Main Menu",320,500,150,50,white,gray,"tiny", action = "main")
button("Quit",550,500,100,50,white,gray,"small", action = "quit")
pygame.display.update()
clock.tick(15)
def game_intro():
intro = True
while intro:
gameDisplay.blit(imggg,(0,0))
button("Play",150,500,100,50,white,gray,"small",action = "play")
button("ControLs",320,500,150,50,white,gray,"tiny", action = "controls")
button("Quit",550,500,100,50,white,gray,"small", action = "quit")
pygame.display.update()
clock.tick(15)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
intro = False
Full Code: https://pastebin.com/jrd82gkJ
You will have very hard time to debug your code in order to achieve the behavior you want for one simple reason:
The logic you use to switch between different screens providing different functionality is causing much trouble you can't directly see if you only run the game.
So you think: "oh ... how come the button doesn't work, there must be an issue with the button".
You are probably not aware of the fact that using functions having own while loops you go deeper and deeper into recursive calls with increasing recursion depth with each switch from one view to another - it is not how pygame is thought to be programmed.
I suggest you add some print() commands into your code to see in the console output that the code doesn't really do what you expect even if it appears to be OK at the first glance because it works.
Then I suggest you REWRITE your entire code so that you have one main while notGameExit: loop, and don't use any other looping in the helper functions. If you want use looping in your helper functions at least don't call from the helper functions another functions with own loops (and so on), but RETURN from them with an explicit return to avoid recursion.
If you leave the in the main loop called function with return your main loop will continue running and depending on some switches you can display in it different things on the screen and react differently to user actions.
Maybe looking at a minimal working pygame script showing "action" without usage of a loop you will gain better understanding and some deep "enlightenment" about how pygame works and then start a total rewrite of your game using another approach as this one you have used in the current code? Then come back with what you have achieved if you have further questions, but you won't probably have any, because it would be much easier to debug it yourself if the code will become more straightforward.
import pygame
pygame.init() # start PyGame (necessary because 'import pygame' doesn't start PyGame)
winDisplay = pygame.display.set_mode((1024, 768)) # set PyGame window size to 1024x768 pixel
pygame.display.set_caption("Minimal PyGame Test Script")
# Time in pygame is measured in milliseconds (1/1000 seconds) (defined by TIMER_RESOLUTION constant):
pygame.TIMER_RESOLUTION = 1000 # assure 1000 explicit, don't relay on default value
colorWhite = (255, 255, 255) # RGB color in Pygame format (valueRed=255, valueGreen=255, valueBlue=255)
colorRed = (255, 0, 0)
colorGreen = ( 0, 255, 0)
colorBlue = ( 0, 0, 255)
winDisplay.fill(colorWhite)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorRed)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorGreen)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorBlue)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorWhite)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
I'm currently programming a game in Python 3.6 using Pygame.
My game has a start menu, with a button that is highlighted when hovered over.
When the button is clicked, the start menu disappears and the game starts.
The only problem is, the start button remains... I've tried using boolean values and if statements to make it disappear when the menu does, but to no avail.
To make matters worse, the pygame code that allows the window to be closed doesn't work (highlighted by commenting out). Could anyone help me with these small problems? They seem trivial, but I'm new to pygame and I can't seem to find a fix anywhere.
You will need the pictures below to run the program:
This is the photo of the girl.
This is the background photo.
The code:
#Imports
import sys
import pygame
pygame.init() #Initialise Pygame
#RGB colours
GREY = (128,128,128)
WHITE = (255,255,255)
BLACK = (0,0,0)
#fonts
title_font = pygame.font.Font('freesansbold.ttf',72)
menu_font = pygame.font.Font('freesansbold.ttf',32)
#images
girl_img = pygame.image.load('emily.png')
background_img = pygame.image.load('tech_lab.png')
class Game: #Game Class
def __init__(self): #Constructor
self.size = width, height = (1000,563)
self.screen = pygame.display.set_mode(self.size)
def menu_screen(self): #Menu Screen Function
intro = True
while intro:
## for event in pygame.event.get(): #To close window
## print(event)
## if event.type == pygame.QUIT:
## pygame.quit()
## sys.exit()
self.screen.fill(GREY) #Set background colour
self.screen.blit(title_font.render('EXAMPLE', True, BLACK), (330,100)) #Display game title
start_button = pygame.draw.rect(self.screen, (BLACK), pygame.Rect(410,310,180,55)) #Display start button rect
self.screen.blit(menu_font.render('Play', True, GREY), (425,310)) #Display start button text
pygame.display.flip() #Update display
while True:
pygame.event.get() #Get pygame events
click_pos = pygame.mouse.get_pos() #Get mouse position
if 410+180 > click_pos[0] > 410 and 310+55 > click_pos[1] > 310: #If mouse position within start button rect...
pygame.draw.rect(self.screen, (WHITE), pygame.Rect(410,310,180,55)) #then change colour of start button rect
if (pygame.mouse.get_pressed())[0] == 1: #If start button rect clicked...
start_game(self) #Start main game
else:
pygame.draw.rect(self.screen, (BLACK), pygame.Rect(410,310,180,55)) #Otherwise start button rect colour is black
self.screen.blit(menu_font.render('Play', True, GREY), (425,310))#Display start button text
pygame.display.flip() #Update display
def start_game(game): #Main game function
game.screen.blit(background_img, [0,0]) #Display background image
game.screen.blit(girl_img, [80,25]) #Display image
pygame.display.flip() #Update display
def main():
game = Game() #Instantiate class 'game'
game.menu_screen() #Call menu screen function
main()
This loop within a loop thing is going to cause nothing but problems and has to go:
while intro:
....
while True
....
here is some pseudo code:
Class Game:
def menu_screen():
displaying = True
while displaying:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
# evaluate mouse click
if clicked button
displaying = False
self.game()
# drawing code for your images
pygame.display.flip()
def game():
game_running = True
while game_running:
# game running logic and drawing
def main():
# get the Game setup and call main menu
Basically, have your Game class control everything. it will have a menu function which displays the menu. Then they click the button and it goes to a different function within the game class for the actual game.
The start button was remaining because you never cleared the screen when going into the start_game() function. As far as why the close window button wasn't working, it is because of the loop within a loop as i mentioned above. You were trapped in the inner
while True:
loop and you could never get back to the event checking from above. (The quit code itself is fine, although you don't need pygame.quit() because you are quitting the program entirely with sys.ext())
Short of completely reworking your code, this can get you started on the right track.
I am new into Python and pyGame and i have a problem with scaling an image.
I want to zoom an image in pygame.
The pygame documentation claims that
pygame.transform.scale()
should scale to a new resolution.
But in my example below it does not work - it crops the image instead of resizing it!?
What am i doing wrong?
#!/usr/bin/env python3
# coding: utf-8
import pygame
from pygame.locals import *
# Define some colors
BLACK = (0, 0, 0)
pygame.init()
# Set the width and height of the screen [width, height]
screen = pygame.display.set_mode((1920, 1080))
pic = pygame.image.load('test.jpg').convert()
pic_position_and_size = pic.get_rect()
# Loop until the user clicks the close button.
done = False
# Clear event queue
pygame.event.clear()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == QUIT:
done = True
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
done = True
# background in black
screen.fill(BLACK)
# Copy image to screen:
screen.blit(pic, pic_position_and_size)
# Update the screen with what we've drawn.
pygame.display.flip()
pygame.display.update()
pygame.time.delay(10) # stop the program for 1/100 second
# decreases size by 1 pixel in x and y axis
pic_position_and_size = pic_position_and_size.inflate(-1, -1)
# scales the image
pic = pygame.transform.scale(pic, pic_position_and_size.size)
# Close the window and quit.
pygame.quit()
pygame.transform.scale() does not work very well for your case. If you shrink a Surface by such a small amount, the algorithm just crops the last column and row of pixels. If you now repeat this process over and over again with the same Surface, you get the strange behaviour you see.
A better approach would be to keep a copy of your original Surface around, and use that for creating the scaled image. Also, using smoothscale instead of scale may also lead to a better effect; it's up to you if you want to use it.
Here's a "fixed" version of your code:
#!/usr/bin/env python3
# coding: utf-8
import pygame
from pygame.locals import *
# Define some colors
BLACK = (0, 0, 0)
pygame.init()
# Set the width and height of the screen [width, height]
screen = pygame.display.set_mode((1920, 1080))
org_pic = pygame.image.load('test.jpg').convert()
pic_position_and_size = org_pic.get_rect()
pic = pygame.transform.scale(org_pic, pic_position_and_size.size)
# Loop until the user clicks the close button.
done = False
# Clear event queue
pygame.event.clear()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == QUIT:
done = True
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
done = True
# background in black
screen.fill(BLACK)
# Copy image to screen:
screen.blit(pic, (0,0))
# Update the screen with what we've drawn.
pygame.display.flip()
pygame.display.update()
pygame.time.delay(10) # stop the program for 1/100 second
# decreases size by 1 pixel in x and y axis
pic_position_and_size = pic_position_and_size.inflate(-1, -1)
# scales the image
pic = pygame.transform.smoothscale(org_pic, pic_position_and_size.size)
# Close the window and quit.
pygame.quit()