Can you import a pygame script without opening a pygame window (until you want to?)
So, I have a game called run.py that I made with pygame, and for the most part, it works fine. And I'm trying to make a launcher for all of my pygames. But when I import it, it immediately opens a blank window. What I want to happen is nothing, until I call run.main()
import tkinter as tk
import run
WIN = tk.Tk()
WIN.mainloop()
run.main()
I understand this is happening because in my pygame scripts I set the window outside of a function, and when I open a tkinter window it leaves the pygame window open until I close the tkinter one. But I want the original games to work without this launcher as well as with it.
Here is the code for my pygame:
import pygame , random
pygame.init()
# This is where it opens the window
WIDTH , HEIGHT = 900 , 500
WIN = pygame.display.set_mode((WIDTH , HEIGHT))
pygame.display.set_caption('game')
BLOCK_MOVEMENT_TIMER_EVENT = pygame.USEREVENT + 1
BLOCK_MOVEMENT_TIME_DELAY = 15
pygame.time.set_timer(BLOCK_MOVEMENT_TIMER_EVENT , BLOCK_MOVEMENT_TIME_DELAY)
BLOCK_CREATE_TIMER_EVENT = pygame.USEREVENT + 2
BLOCK_CREATE_TIME_DELAY = 1500
pygame.time.set_timer(BLOCK_CREATE_TIMER_EVENT, BLOCK_CREATE_TIME_DELAY)
FPS = 60
#colors
WHITE = (255 , 255 ,255)
BLACK = (0 , 0 , 0)
RED = (255 , 0 , 0)
BIGFONT = pygame.font.Font('Retro.ttf' , 65)
SMALLFONT = pygame.font.Font('Retro.ttf' , 20)
FLOOR = pygame.Rect(0 , 400 , 900 , 5)
class Player:
def __init__(self):
self.size = 20
self.x = 75
self.y = 380
self.jumping = False
self.fall = False
self.update_rect()
self.score = 0
def update_rect(self):
self.rect = pygame.Rect(self.x , self.y , self.size , self.size)
def jump(self):
pressed = pygame.key.get_pressed()
if pressed[pygame.K_SPACE] and not self.fall:
self.jumping = True
if self.jumping:
self.y -= 3
if self.y < 300:
self.y = 300
self.fall = True
self.jumping = False
if self.fall:
self.y += 3
if self.y > 380:
self.y = 380
self.fall = False
self.update_rect()
player = Player()
class Obstacles:
def __init__(self , width , height):
self.x = 900
self.y = HEIGHT - height - 100
self.width = width
self.height = height
self.update_rect()
def update_rect(self):
self.rect = pygame.Rect(self.x , self.y , self.width , self.height)
def move_obstacles(obstacle_list):
for obstacle in obstacle_list:
obstacle.x -= 3
if obstacle.x < -100:
obstacle_list.pop(0)
player.score += 1
obstacle.update_rect()
def add_obstacle(obstacle_list):
obstacle1 = Obstacles(20 , 40)
obstacle2 = Obstacles(75 , 20)
obstacle3 = Obstacles(35 , 35)
obstacle4 = Obstacles(50 , 25)
obstacle5 = Obstacles(80 , 10)
obstacle6 = Obstacles(40 , 20)
obstacle7 = Obstacles(20 , 30)
obstacle_options = [obstacle1 , obstacle2 , obstacle3 , obstacle4 , obstacle5 , obstacle6 , obstacle7]
obstacle_list.append(obstacle_options[random.randint(0,6)])
def is_game_over(obstacle_list):
for obstacle in obstacle_list:
if player.rect.colliderect(obstacle):
return True
def game_over():
running = False
while not running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = True
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
player.score = 0
main()
break
if event.key == pygame.K_e:
running = True
quit()
WIN.fill(BLACK)
game_over = BIGFONT.render('GAME OVER', False, WHITE)
WIN.blit(game_over , (200 , 175))
instructions = SMALLFONT.render(f'You scored {player.score}. Press R to restart or E to exit' , False , WHITE)
WIN.blit(instructions , (145 , 290))
pygame.display.flip()
def draw_window(obstacle_list , is_game_over):
WIN.fill(BLACK)
pygame.draw.rect(WIN , WHITE , FLOOR)
pygame.draw.rect(WIN , WHITE , player.rect)
for obstacle in obstacle_list:
pygame.draw.rect(WIN , RED , obstacle.rect)
score_counter = BIGFONT.render(f'SCORE {player.score}', False, (255, 255, 255))
WIN.blit(score_counter , (240 , 100))
pygame.display.flip()
def main():
clock = pygame.time.Clock()
obstacle_list = []
done = False
while not done:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_e:
done = True
quit()
if event.type == BLOCK_MOVEMENT_TIMER_EVENT:
move_obstacles(obstacle_list)
if event.type == BLOCK_CREATE_TIMER_EVENT:
add_obstacle(obstacle_list)
draw_window(obstacle_list , is_game_over(obstacle_list))
player.jump()
is_game_over(obstacle_list)
if is_game_over(obstacle_list):
game_over()
done = True
pygame.display.flip()
if __name__ == '__main__':
main()
I'm sorry if this question doesn't make sense, but any help would be appreciated.
Yes. First off pygame doesn't initialize a game window until you call pygame.display.set_mode((width, height))
.
So you can either move all your game logic inside of run.py
into a function say for example...
def my_game_name():
pygame.init()
WIDTH , HEIGHT = 900 , 500
WIN = pygame.display.set_mode((WIDTH , HEIGHT))
...
class Player:
...
def move_obstacles(obstacle_list):
...
def main():
...
And then inside you main.py
where TK is you can do this.
import run
# When you're ready to run the game
run.my_game_name()
Your second option that I would recommend not to do is this...
Inside main.py
#TK button clicked to start game
def start_my_game():
import run # Window is shown here
run.main() # Game logic begins
I wouldn't recommend this as your relying on the import
to setup stuff in the background which is the reason why you are having the issue you are having now.