问题描述
我一直在使用 pygame 制作游戏,并发现在这个游戏中需要新窗口.
请注意所有游戏逻辑是如何完全分离的,而且这种方法可以轻松添加其他状态,例如暂停功能或菜单.
当然,还有很多其他方法可以做到这一点,但您会明白的.有关如何在游戏中实现不同状态的另一个想法,请查看此问题一>.
I've been making game using pygame and found out necessity of new window in this game.screenshot of the game
When boy collide with one of the companies(Web Canape, Smolenskiye Brillianty...) new window must be opened to do quize there. The main game also need to continue working, because boy's task is to go through all companies.
Can someone help me with solving this problem, please?
Probably, it is possible to use new module such as PyQt5 or Tkinter in order not to terminate whole game.
https://github.com/TotumRevolutum/shadows-game
import sys
from map import *
import pygame.display
pygame.init()
WIDTH = 11 * 100
HEIGHT = 7 * 100
clock = pygame.time.Clock()
def text_show(number):
intro_text_1 = ["Привет! Меня зовут Емеля.", "Я приглашаю тебя на День",
"Теней на предприятия", "Смоленской области.", " ", " ДАЛЕЕ"]
intro_text_2 = ['"День Теней" - это день,', "в течение которого школьники",
"могут лично следить за работой ", "специалистов с целью проверки",
"правильности выбора профессии.", " ДАЛЕЕ"]
intro_text_3 = ['Мы с тобой будем определяться', "с профессией по принципу ",
'индукции от "частного" к "общему",', 'от "предприятия" к "профессии."',
"", " ДАЛЕЕ"]
intro_text_4 = ['В конце Дня Теней', "ты сможешь выбрать предприятие,",
'на котором хотел бы работать!', '',
"", " ДАЛЕЕ"]
if number == 1:
text = intro_text_1
elif number == 2:
text = intro_text_2
elif number == 3:
text = intro_text_3
else:
text = intro_text_4
back = Background('bg/boy_start.png', [0, 0])
screen.blit(back.image, back.rect)
font = pygame.font.SysFont("Typewriter", 33)
tmp = 0
for line in text:
if line == " ДАЛЕЕ":
lines = font.render(line, 1, pygame.Color('red'))
else:
lines = font.render(line, 1, pygame.Color('black'))
display_rect = lines.get_rect()
tmp += 10
display_rect.y = 140 + tmp
display_rect.x = 640
tmp += display_rect.height
screen.blit(lines, display_rect)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
return
pygame.display.flip()
clock.tick(30)
text_show(1)
text_show(2)
text_show(3)
text_show(4)
running = True
generate_level(load_level())
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
move_boy(keys, player_group)
all_sprites.draw(screen)
tiles_group.draw(screen)
player_group.draw(screen)
pygame.display.flip()
clock.tick(60)
# other parts are located in the git
# https://github.com/TotumRevolutum/shadows-game
You don't need and don't want a new window. Just create another Surface
/Sprite
that renders the text and handles the events.
Here's a simple example I hacked together. Note the comments, as they explain what's going on:
import pygame
import pygame.freetype
# So our game has 2 states.
# Either we're in the world and run around;
# or we're displaying a menu and the player has to make a choice.
WORLD = 0
MENU = 1
# from https://www.pygame.org/docs/ref/freetype.html#pygame.freetype.Font.render_to
def word_wrap(surf, text, font, color=(0, 0, 0)):
font.origin = True
words = text.split(' ')
width, height = surf.get_size()
line_spacing = font.get_sized_height() + 2
x, y = 0, line_spacing
space = font.get_rect(' ')
for word in words:
bounds = font.get_rect(word)
if x + bounds.width + bounds.x >= width:
x, y = 0, y + line_spacing
if x + bounds.width + bounds.x >= width:
raise ValueError("word too wide for the surface")
if y + bounds.height - bounds.y >= height:
raise ValueError("text to long for the surface")
font.render_to(surf, (x, y), None, color)
x += bounds.width + space.width
return x, y
# This sprite handles the menu.
# It renders a box and a text and listens for key presses.
# If a key we're interessed in is pressed, we call the callback function.
class TextMenu(pygame.sprite.Sprite):
def __init__(self, font, text, listen_to, callback):
super().__init__()
self.image = pygame.Surface((400, 400))
self.image.fill(pygame.Color('white'))
self.image.fill(pygame.Color('black'), self.image.get_rect().inflate((-50, -50)))
self.rect = self.image.get_rect(topleft=(50, 50))
word_wrap(self.image.subsurface(self.image.get_rect().inflate((-100, -100))), text, font, pygame.Color('white'))
self.callback = callback
self.listen_to = listen_to
def update(self, events, dt):
for e in events:
if e.type == pygame.KEYDOWN and e.key in self.listen_to:
self.callback(self, e.key)
# This sprite represents a building the player can "walk in" to trigger
# a menu pop up. In this case, we want the user to either press 1 or 2.
# Then we change the color, because why not, something should happen.
class House(pygame.sprite.Sprite):
def __init__(self, pos, player, show_text):
super().__init__()
self.image = pygame.Surface((64, 64))
self.image.fill(pygame.Color('darkred'))
self.rect = self.image.get_rect(center=pos)
self.show_text = show_text
self.player = player
# Since the menu is triggered when the player touches the building,
# we don't want an endless loop, so we need a flag that prevents
# the menu until the player "leaves the building"
self.triggered = False
def change_color(self, key):
if key == pygame.K_1:
self.image.fill(pygame.Color('yellow'))
if key == pygame.K_2:
self.image.fill(pygame.Color('darkblue'))
def update(self, events, dt):
if pygame.sprite.collide_rect(self, self.player):
if not self.triggered:
self.show_text('Welcome, little blue rect. Please press (1) or (2).', (pygame.K_1, pygame.K_2), self.change_color)
self.triggered = True
else:
self.triggered = False
# This is the player.
# Does basically nothing but run around
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((32, 32))
self.image.fill(pygame.Color('dodgerblue'))
self.rect = self.image.get_rect()
self.pos = pygame.Vector2((100, 200))
def update(self, events, dt):
pressed = pygame.key.get_pressed()
move = pygame.Vector2((0, 0))
if pressed[pygame.K_w]: move += (0, -1)
if pressed[pygame.K_a]: move += (-2, 0)
if pressed[pygame.K_s]: move += (0, 2)
if pressed[pygame.K_d]: move += (2, 0)
if move.length() > 0: move.normalize_ip()
self.pos += move*(dt/5)
self.rect.center = self.pos
def main():
pygame.init()
screen = pygame.display.set_mode((500, 500))
font = pygame.freetype.SysFont(None, 32)
clock = pygame.time.Clock()
dt = 0
player = Player()
# keep track of the state we're in.
# we start in the WORLD state, a.k.a. running around.
# the state just tells us which sprites are "active",
# a.k.a. if they are updated by calling thier update function
state = WORLD
# sprite group for all MENU-sprites
menu_sprites = pygame.sprite.Group()
# sprite group for all WORLD-sprites
sprites = pygame.sprite.Group(player)
# this function allows other sprites to trigger a menu
def show_text(text, listen_to, callback):
# this function is called by the menu.
# we change the state back to world and kill the TextMenu sprite
def wrapped_callback(sprite, *args):
nonlocal state
state = WORLD
callback(*args)
sprite.kill()
# so when this function is called , let's switch to the MENU state
nonlocal state
state = MENU
# add the TextMenu sprite to the menu_sprites group so it "lives"
menu_sprites.add(TextMenu(font, text, listen_to, wrapped_callback))
# create some buildings. They are all the same...
for pos in ((300, 300), (200, 400), (100, 100)):
sprites.add(House(pos, player, show_text))
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
# see which sprites are "active". The WORLD sprites or the MENU sprites
if state == WORLD:
sprites.update(events, dt)
else:
menu_sprites.update(events, dt)
screen.fill((30, 30, 30))
sprites.draw(screen)
menu_sprites.draw(screen)
pygame.display.update()
dt = clock.tick(60)
if __name__ == '__main__':
main()
Note how all the game logic is cleanly seperated, and also this approach makes it easy to add other states, like a pause function or a menu.
Of course there are dozen other ways to do this, but you'll get the idea.For another idea of how to implement different states in your game, maybe look at this question.
这篇关于如何在pygame中制作新窗口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!