PyGame - 其他文件中的函数未定义
我正在做我的第一个PyGame项目,之前点击“开始游戏”按钮后会进入游戏窗口,但现在却说游戏未定义。我尝试了调试,但对pygame还比较陌生,有人能解释一下这个问题的解决办法吗?谢谢。下面是代码:
# main.py
import pygame
import sys
from gameplay import *
pygame.init()
#CONSTANTS
screen_width = 800
screen_height = 800
running = True
sky_blue = (102, 230, 225)
white = (255, 255, 255)
black = (0, 0, 0)
blue = (0, 0, 255)
red = (255, 0, 0)
green = (0, 255, 0)
screen = pygame.display.set_mode((screen_height,screen_width))
############# SOURCED FROM: stackoverflow (https://stackoverflow.com/questions/47855725/pygame-how-can-i-allow-my-users-to-change-their-input-keys-custom-keybinding)
def create_key_list(input_map):
"""A list of surfaces of the action names + assigned keys, rects and the actions."""
font = pygame.font.Font(None, 50)
key_list = []
for y, (action, value) in enumerate(input_map.items()):
surf = font.render('{}: {}'.format(action, pygame.key.name(value)), True, red)
rect = surf.get_rect(topleft=(40, y*40+20))
key_list.append([surf, rect, action])
return key_list
def assignment_menu(input_map):
"""Allow the user to change the key assignments in this menu.
The user can click on an action-key pair to select it and has to press
a keyboard key to assign it to the action in the `input_map` dict.
"""
selected_action = None
key_list = create_key_list(input_map)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if selected_action is not None:
# Assign the pygame key to the action in the input_map dict.
input_map[selected_action] = event.key
selected_action = None
# Need to re-render the surfaces.
key_list = create_key_list(input_map)
if event.key == pygame.K_ESCAPE: # Leave the menu.
# Return the updated input_map dict to the main function.
return input_map
elif event.type == pygame.MOUSEBUTTONDOWN:
selected_action = None
for surf, rect, action in key_list:
# See if the user clicked on one of the rects.
if rect.collidepoint(event.pos):
selected_action = action
screen.fill(sky_blue)
# Blit the action-key table. Draw a rect around the
# selected action.
for surf, rect, action in key_list:
screen.blit(surf, rect)
if selected_action == action:
pygame.draw.rect(screen, red, rect, 2)
pygame.display.update()
def draw_button(text, x, y, width, height, colour): # draw button function
font_button = pygame.font.Font(None, 50)
pygame.draw.rect(screen, colour, (x, y, width, height))
text_surface = font_button.render(text, True, white)
text_rect = text_surface.get_rect(center=(x + width / 2, y + height / 2))
screen.blit(text_surface, text_rect)
def bootup_menu(): # main menu function
pygame.display.set_caption("Mimit | Main Menu")
input_map = {"RIGHT": pygame.K_d, "LEFT": pygame.K_a, "UP": pygame.K_w, "DOWN": pygame.K_s, "DASH": pygame.K_LSHIFT, "ATTACK": pygame.K_SPACE, "INVENTORY" : pygame.K_i} ######################
while running:
screen.fill(sky_blue)
font_title = pygame.font.Font(None, 125)
text_surface = font_title.render("Mimit!", True, pygame.Color((25, 25, 255)))
text_rect = text_surface.get_rect()
text_rect.midtop = (screen_width // 2, 88)
screen.blit(text_surface, text_rect) # renders title
draw_button("Start Game!", 200, 300, 400, 48, (25, 25, 255))
draw_button("Settings", 200, 480, 400, 48, (25, 25, 255))
draw_button("Quit", 200, 660, 400, 48, (25, 25, 255)) # render buttons
for event in pygame.event.get(): # give buttons functionality
if event.type == pygame.QUIT:
pygame.quit()
sys.quit()
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_x, mouse_y = pygame.mouse.get_pos()
if (200 <= mouse_x <= 600) and (300 <= mouse_y <= 348): # start game
gameplay(running, input_map)
#character_preset_menu()
pass
elif (200 <= mouse_x <= 600) and (480 <= mouse_y <= 528): # settings
input_map = assignment_menu(input_map)
elif (200 <= mouse_x <= 600) and (660 <= mouse_y <= 708): # quit
pygame.quit()
sys.exit()
if event.type == pygame.K_ESCAPE:
input_map = assignment_menu(input_map)
pygame.display.update() # updates the screen using the variables current states above
def character_preset_menu():
pass
bootup_menu() # loads bootup menu
# gameplay.py
import pygame
import sys
import math
import time
from main import *
import csv
pygame.init()
#consts
screen_width = 800
screen_height = 800
sky_blue = (102, 230, 225)
white = (255, 255, 255)
black = (0, 0, 0)
blue = (0, 0, 255)
red = (255, 0, 0)
green = (0, 255, 0)
map_size = 40
tile_size = 20
PLAYER_SPRITE_STATIONARY = pygame.image.load("assets/PLAYER_SPRITE_STATIONARY.png")
PLAYER_SPRITE_STATIONARY = pygame.transform.scale(PLAYER_SPRITE_STATIONARY, (20, 20))
PLAYER_SPRITE_MOVING = pygame.image.load("assets/PLAYER_SPRITE_STATIONARY.png")
PLAYER_SPRITE_MOVING = pygame.transform.scale(PLAYER_SPRITE_STATIONARY, (20, 20))
#map
MAP = (
"########################################"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"# #"
"########################################"
)
#Initialise the pygame window
screen = pygame.display.set_mode((screen_height,screen_width))
clock = pygame.time.Clock()
#Draw the map based on the MAP string, utilising loops
def draw_map():
for row in range(map_size):
for col in range(map_size): # iterate over each row/column
square = row * map_size + col
pygame.draw.rect(
screen,
(230,15,15) if MAP[square] == "#" else (0,0,255), # Uses the character flags given
(col*tile_size ,row*tile_size , tile_size, tile_size)
)
def user_position_check(self, position_change):
# Up is minus 40, Down is plus 40, left is minus 1, right is plus 1
next_tile = MAP[self.tile + position_change]
if next_tile == "#": # Checks the flags in MAP
return False
else:
return True
class USER(pygame.sprite.Sprite): # Grouping the users sprite as its own class
def __init__(self, x, y):
super().__init__()
self.image = PLAYER_SPRITE_STATIONARY
self.rect = self.image.get_rect()
self.rect.topleft = (x, y)
self.speed = 20
self.tile = 41
self.inventory = {}
self.selected_item = None
self.stamina = 100
self.health = 100
# Self variables update globally and store values about the user only
def update(self, keys, input_map): # Takes key binds from input map and responds with appropriate movement
if keys[input_map["LEFT"]]:
position_change = (-1)
if user_position_check(self, position_change):
self.tile += position_change # position change changes the vector position of the user, not the physical location
self.rect.x -= self.speed # changes the physical location of the sprite
self.image = PLAYER_SPRITE_MOVING # Image of moving, must be changed once graphics are developed
time.sleep(0.2)
elif keys[input_map["RIGHT"]]:
position_change = 1
if user_position_check(self, position_change):
self.tile += position_change
self.rect.x += self.speed
self.image = PLAYER_SPRITE_MOVING
time.sleep(0.2)
elif keys[input_map["UP"]]:
position_change = (-40)
if user_position_check(self, position_change):
self.tile += position_change
self.rect.y -= self.speed
self.image = PLAYER_SPRITE_MOVING
time.sleep(0.2)
elif keys[input_map["DOWN"]]:
position_change = 40
if user_position_check(self, position_change):
self.tile += position_change
self.rect.y += self.speed
self.image = PLAYER_SPRITE_MOVING
time.sleep(0.2)
elif keys[input_map["INVENTORY"]]:
inventory_open(self, input_map)
else:
position_change = 0 # stationary else statement
self.image = PLAYER_SPRITE_STATIONARY
def inventory_open(self, input_map, screen):
inventory_width, inventory_height = 640, 220
selected = None
while selected == None:
pygame.draw.rect(screen, (0,0,0), (80, 290, inventory_width, inventory_height))
screen.blit()
# Create USER sprite using groupings
user = USER(20, 20) # Spawn point in pixels (1st walkable tile)
user_sprites = pygame.sprite.Group()
user_sprites.add(user)
def gameplay(running, input_map):
pygame.display.set_caption("Gameplay!")
screen.fill(sky_blue)
while running: # new game instance
draw_map()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
keys = pygame.key.get_pressed() # Checks state of all keys, returns True when a key is pressed
user_sprites.update(keys, input_map) # Updates based on this check ^
user_sprites.draw(screen)
pygame.display.update()
我已经尝试把函数移动到不同的文件里并重命名,但似乎没有效果。(抱歉我的英语和代码写得不好,我对这两者都很新)
1 个回答
如果你把多个Python文件随便放在同一个文件夹里,它们可能不会正常工作。
特别是,如果你尝试从上级目录运行一个文件,比如在有game_play.py
的情况下运行python game/mygame.py
,这会失败。
最好的办法是把你的项目做成一个简约的Python包,并用可编辑的方式安装。这样,你就可以在一个文件里输入类似from .game_play import *
的代码(注意这里的"game_play"前面有个".")。
顺便提一下,我要提醒你,... import *
通常不是个好选择。一般来说,最好是导入整个模块,并在前面加上模块名,或者明确地导入你需要的名称。
无论如何,如果你的文件在一个叫“game”的文件夹里,要创建一个游戏包,你需要这样做:在“game”的上级目录(也就是“game”所在的目录)创建一个名为“pyproject.toml”的0字节文件。这将使用默认值创建一个项目规范,这些默认值是经典的“setuptools”和“wheel”,而且不需要“setup.py”文件。
然后,在同一个目录下,在操作系统的命令行输入pip install -e .
(最好有一个合适的虚拟环境,但即使没有也能工作,这又是另一个话题)。
从那时起,“game”就成了一个已安装的包,你可以像这样使用import game.game_play
。如果在game文件夹里有一个名为__main__.py
的文件,当你在命令行输入python -m game
时,它会作为入口点运行。