问题描述
我使用Python的 pygame 模块制作了一个游戏。我想做一个文件的可执行安装程序,这样任何人都可以玩该游戏,而无需安装python或pygame。我使用模块 cx-freeze 为我的游戏文件创建可执行文件。我将用于制作可执行安装程序的代码存储在名为 setup.py 的文件中,并将其与游戏文件以及游戏所需的所有其他文件(例如图像,声音等)保存在同一目录中。 。
当我执行命令python setup.py build
创建可执行文件时,我开始收到警告,最后发生了此错误:
Traceback (most recent call last):
File "setup.py",line 5,in <module>
cx_Freeze.setup(
File "C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\site-packages\cx_Freeze\dist.py",line 342,in setup
distutils.core.setup(**attrs)
File "C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\distutils\core.py",line 148,in setup
dist.run_commands()
File "C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\distutils\dist.py",line 966,in run_commands
self.run_command(cmd)
File "C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\distutils\dist.py",line 985,in run_command
cmd_obj.run()
File "C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\distutils\command\build.py",line 135,in run
self.run_command(cmd_name)
File "C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\distutils\cmd.py",line 313,in run_command
self.distribution.run_command(command)
File "C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\distutils\dist.py",in run_command
cmd_obj.run()
File "C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\site-packages\cx_Freeze\dist.py",line 217,in run
freezer.Freeze()
File "C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\site-packages\cx_Freeze\freezer.py",line 645,in Freeze
self._WriteModules(fileName,self.finder)
File "C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\site-packages\cx_Freeze\freezer.py",line 536,in _WriteModules
sourcePackageDir = os.path.dirname(module.file)
File "C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\ntpath.py",line 223,in dirname
return split(p)[0]
File "C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\ntpath.py",line 185,in split
p = os.fspath(p)
TypeError: expected str,bytes or os.pathLike object,not nonetype
显示的警告是:
running build
running build_exe
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\site-packages\setuptools\distutils_patch.py:25: UserWarning: distutils was imported before Setuptools. This usage is discouraged and may exhibit undesirable behaviors or errors. Please use Setuptools' objects directly or at least import Setuptools first.
warnings.warn(
C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\site-packages\pygame\examples\chimp.py:32: SyntaxWarning: "is" with a literal. Did you mean "=="?
if colorkey is -1:
C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\site-packages\pygame\tests\test_utils\__init__.py:162: SyntaxWarning: "is not" with a literal. Did you mean "!="?
(rect.left is not 0 and [(rect.left-1,rect.top)] or []) +
copying c:\users\armaan barak\appdata\local\programs\python\python38\python38.dll -> build\exe.win-amd64-3.8\python38.dll
copying c:\users\armaan barak\appdata\local\programs\python\python38\vcruntime140.dll -> build\exe.win-amd64-3.8\vcruntime140.dll
copying c:\users\armaan barak\appdata\local\programs\python\python38\python3.dll -> build\exe.win-amd64-3.8\python3.dll
copying C:\Users\Armaan Barak\AppData\Local\Programs\Python\python38\lib\site-packages\cx_Freeze\bases\Console.exe -> build\exe.win-amd64-3.8\SpaceInvader2.exe
*** WARNING *** unable to create version resource
version must be specified
import cx_Freeze
executable = [cx_Freeze.Executable('SpaceInvader2.py')]
cx_Freeze.setup(
name="Space Invaders 2",options={
"build_exe": {
"packages": [
"pygame","random","math","pygame.mixer","time"
],"include_files": [
"spaceship.png","space.png","home_screen.png","ammunition.png","alien.png","alien2.png","alien3.png","alien4.png","player.png","settings.png","controls.png","game_over.png","background.wav","laser.wav","explosion.wav"
]
}
},executables=executable
)
import pygame
import random
import math
from pygame import mixer
import time
# Game Screen Initialization
pygame.init()
screen = pygame.display.set_mode((800,600))
# Loading Images
icon = pygame.image.load('spaceship.png')
game_background = pygame.image.load('space.png')
home_screen_img = pygame.image.load('home_screen.png')
bullet = pygame.image.load('ammunition.png')
alien_img = pygame.image.load('alien.png')
alien_img2 = pygame.image.load('alien2.png')
alien_img3 = pygame.image.load('alien3.png')
alien_img4 = pygame.image.load('alien4.png')
player_img = pygame.image.load('player.png')
settings_img = pygame.image.load('settings.png')
controls_img = pygame.image.load('controls.png')
game_over_img = pygame.image.load('game_over.png')
# Loading sounds
mixer.music.load('background.wav')
mixer.music.play(-1)
bullet_sound = mixer.sound('laser.wav')
explosion_sound = mixer.sound('explosion.wav')
# Title and Icon
pygame.display.set_caption('Space Invader')
pygame.display.set_icon(icon)
# Bullet variables
bullet_x = 0
bullet_y = 480
bullet_x_change = 0
bullet_y_change = 4
bullet_state = 'ready'
# Player variables
player_x = 370
player_y = 480
player_x_change = 0
# Enemy variables
enemy_img = []
enemy_x = []
enemy_y = []
enemy_x_change = []
enemy_y_change = []
num_of_enemies = 13
# Creating 10 enemy objects
for i in range(num_of_enemies):
enemy_img.append(random.choice([alien_img,alien_img2,alien_img3,alien_img4]))
enemy_x.append(random.randint(0,735))
enemy_y.append(random.randint(50,200))
enemy_x_change.append(2)
enemy_y_change.append(40)
# score variables
score_value = 0
font = pygame.font.Font('freesansbold.ttf',24)
over_font = pygame.font.Font('freesansbold.ttf',80)
text_X = 10
text_y = 10
# Game Functions
def show_score(x,y):
score = font.render('score: ' + str(score_value),True,(165,240,67))
screen.blit(score,(x,y))
def game_over_text():
over_text = over_font.render('GAME OVER!',(255,0))
screen.blit(over_text,(160,250))
def player(x,y):
screen.blit(player_img,y))
def enemy(x,y,i):
screen.blit(enemy_img[i],y))
def fire_bullet(x,y):
global bullet_state
bullet_state = 'fire'
screen.blit(bullet,(x + 16,y + 10))
def is_collision(enemyX,enemyY,bulletX,bulletY):
distance = math.sqrt((math.pow(enemyX - bulletX,2)) + (math.pow(enemyY-bulletY,2)))
return distance < 27
# Button colors and fonts
color = (0,0)
color_light = (100,149,237)
color_dark = (138,43,226)
# Fonts
game_name_font = pygame.font.SysFont("Chiller",140)
btn_font = pygame.font.SysFont('Corbel Bold',34)
random_font = pygame.font.SysFont('Arial',60)
info_btn = pygame.font.SysFont('Century Gothic',24)
controls_font = pygame.font.SysFont('Consolas',15)
credits_btn = pygame.font.SysFont('Consolas',18)
# Texts
game_text = game_name_font.render('Space Invaders!',255,0))
play_text = btn_font.render('Play Game',color)
controls_text = btn_font.render('Controls',color)
credits_text = btn_font.render('Credits',color)
settings_text = btn_font.render('Settings',color)
quit_text = btn_font.render('Quit Game',color)
version_text = btn_font.render('Version 2.8',255))
back_text = btn_font.render('Go Back',color)
under_development_text = random_font.render('This area is under development',(0,0))
# Controls text
controls_1 = controls_font.render('Left Arrow : Spaceship moves Left',(124,252,0))
controls_2 = controls_font.render('Right Arrow : Spaceship moves Right',0))
controls_3 = controls_font.render('Spacebar : Shoots bullets',0))
# Credits text
credits_line_1 = credits_btn.render("The games first version was made while learning from the pygame video",255))
credits_line_2 = credits_btn.render("of FreeCodeCamp.org. The successive updates in version 1 and 2 are",255))
credits_line_3 = credits_btn.render("made by Armaan Barak. No external code was copied. But help was taken",255))
credits_line_4 = credits_btn.render("from google. Images and icons shown this game are taken from freepik.com",255))
credits_line_5 = credits_btn.render("and flaticon.com respectively. The images were resized from",255))
credits_line_6 = credits_btn.render("reduceimages.com and the sounds are imported from github account of",255))
credits_line_7 = credits_btn.render("Mr. Attreya Bhatt. Direct Link to repository:",255))
credits_line_8 = credits_btn.render("https://github.com/attreyabhatt/Space-Invaders-Pygame.",255))
credits_line_9 = credits_btn.render("This game is free and open-source. User is independent for",255))
credits_line_10 = credits_btn.render("manipulating code but it's encouraged that you avoid cheating.",255))
credits_line_11 = credits_btn.render("Creator and Developer: Armaan Barak",255))
# Game loop variables
running = True
home_screen = True
settings = False
controls = False
game_screen = False
credits_screen = False
game_over_screen = False
while running:
# To loop through events untill event is QUIT
for event in pygame.event.get():
# QUIT Button
if event.type == pygame.QUIT:
running = False
# Mouse key controls
if event.type == pygame.MOUSEBUTTONDOWN:
# Game is Over
if game_over_screen:
if 250 <= mouse[0] <= 385 and 520 <= mouse[1] <= 560:
home_screen = True
settings = False
controls = False
game_screen = False
credits_screen = False
game_over_screen = False
for i in range(num_of_enemies):
enemy_y[i] = random.randint(50,200)
player_y = 480
bullet_y = 480
if 420 <= mouse[0] <= 560 and 520 <= mouse[1] <= 560:
quit()
# Play button clicked
if 230 <= mouse[0] <= 370 and 270 <= mouse[1] <= 310:
home_screen = False
settings = False
controls = False
game_screen = True
credits_screen = False
# Instructions button clicked
if 400 <= mouse[0] <= 540 and 270 <= mouse[1] <= 310:
home_screen = False
settings = False
controls = True
game_screen = False
credits_screen = False
# Settings button clicked
if 230 <= mouse[0] <= 370 and 350 <= mouse[1] <= 390:
home_screen = False
settings = True
controls = False
game_screen = False
credits_screen = False
# Credits button clicked
if 400 <= mouse[0] <= 540 and 350 <= mouse[1] <= 390:
home_screen = False
settings = False
controls = False
game_screen = False
credits_screen = True
# Quit button clicked
if 315 <= mouse[0] <= 455 and 430 <= mouse[1] <= 470:
quit()
if settings or controls or credits_screen:
if 50 <= mouse[0] <= 165 and 30 <= mouse[1] <= 70:
home_screen = True
settings = False
controls = False
game_screen = False
credits_screen = False
# KeyBoard Controls
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player_x_change = -3
if event.key == pygame.K_RIGHT:
player_x_change = 3
if event.key == pygame.K_SPACE:
if bullet_state == 'ready':
bullet_sound.play()
bullet_x = player_x
fire_bullet(bullet_x,bullet_y)
# Reseting player's x axis speed when left or right key is lifted
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
player_x_change = 0
# Home Screen
if home_screen:
# displaying main screen
screen.blit(home_screen_img,0))
# Getting Mouse Position
mouse = pygame.mouse.get_pos()
# Changing color of text Boxes on the basis of cursor position
# play game text
if 230 <= mouse[0] <= 370 and 270 <= mouse[1] <= 310:
pygame.draw.rect(screen,color_light,[230,270,140,40])
else:
pygame.draw.rect(screen,color_dark,40])
# instructions text
if 400 <= mouse[0] <= 540 and 270 <= mouse[1] <= 310:
pygame.draw.rect(screen,[400,40])
# settings text
if 230 <= mouse[0] <= 370 and 350 <= mouse[1] <= 390:
pygame.draw.rect(screen,350,40])
# credits text
if 400 <= mouse[0] <= 540 and 350 <= mouse[1] <= 390:
pygame.draw.rect(screen,40])
# quit game text
if 315 <= mouse[0] <= 455 and 430 <= mouse[1] <= 470:
pygame.draw.rect(screen,[315,430,40])
# displaying text
screen.blit(game_text,(90,100))
# displaying buttons
screen.blit(play_text,(240,280))
screen.blit(controls_text,(421,280))
screen.blit(settings_text,(253,360))
screen.blit(credits_text,(427,360))
screen.blit(quit_text,(325,440))
# Version display
screen.blit(version_text,580))
# Updating Screen
pygame.display.update()
# Settings Screen
elif settings:
screen.blit(settings_img,0))
mouse = pygame.mouse.get_pos()
if 50 <= mouse[0] <= 165 and 30 <= mouse[1] <= 70:
pygame.draw.rect(screen,[50,30,115,40])
else:
pygame.draw.rect(screen,40])
screen.blit(back_text,(60,40))
screen.blit(under_development_text,250))
pygame.display.update()
# Controls Screen
elif controls:
screen.blit(controls_img,40))
screen.blit(controls_1,240))
screen.blit(controls_2,290))
screen.blit(controls_3,340))
pygame.display.update()
# Credits Screen
elif credits_screen:
screen.fill((85,107,47))
mouse = pygame.mouse.get_pos()
if 50 <= mouse[0] <= 165 and 30 <= mouse[1] <= 70:
pygame.draw.rect(screen,40))
screen.blit(credits_line_1,(40,150))
screen.blit(credits_line_2,180))
screen.blit(credits_line_3,210))
screen.blit(credits_line_4,240))
screen.blit(credits_line_5,270))
screen.blit(credits_line_6,300))
screen.blit(credits_line_7,330))
screen.blit(credits_line_8,360))
screen.blit(credits_line_9,390))
screen.blit(credits_line_10,420))
screen.blit(credits_line_11,450))
pygame.display.update()
# Game Screen
else:
# Adding background image
screen.blit(game_background,0))
# Player Movement
player_x += player_x_change
if player_x <= 0:
player_x = 0
elif player_x >= 736:
player_x = 736
# Handling movement of enemies
for i in range(num_of_enemies):
# Game Over
if enemy_y[i] > 450:
game_over_screen = True
# Hiding Characters
for j in range(num_of_enemies):
enemy_y[j] = 2000
player_y = -2000
bullet_y = -4000
screen.blit(game_over_img,0))
# Back button
if 250 <= mouse[0] <= 385 and 520 <= mouse[1] <= 560:
pygame.draw.rect(screen,[250,520,40])
else:
pygame.draw.rect(screen,40])
# Quit Button
if 420 <= mouse[0] <= 560 and 520 <= mouse[1] <= 560:
pygame.draw.rect(screen,[420,40])
mouse = pygame.mouse.get_pos()
screen.blit(back_text,(270,530))
screen.blit(quit_text,(430,530))
# Enemy Movement
enemy_x[i] += enemy_x_change[i]
if enemy_x[i] <= 0:
enemy_x_change[i] = 2
enemy_y[i] += enemy_y_change[i]
elif enemy_x[i] >= 736:
enemy_x_change[i] = -2
enemy_y[i] += enemy_y_change[i]
# Collision control
collision = is_collision(enemy_x[i],enemy_y[i],bullet_x,bullet_y)
if collision:
explosion_sound.play()
bullet_y = 480
bullet_state = 'ready'
score_value += 1
enemy_x[i] = random.randint(0,735)
enemy_y[i] = random.randint(50,200)
# drawing enemy
enemy(enemy_x[i],i)
# Bullet Movement
if bullet_y <= 0:
bullet_y = 480
bullet_state = 'ready'
if bullet_state == "fire":
fire_bullet(bullet_x,bullet_y)
bullet_y -= bullet_y_change
# drawing player
player(player_x,player_y)
# Version display
screen.blit(version_text,580))
# drawing score card
show_score(text_X,text_y)
# Updates screen
pygame.display.update()
我尝试使用命令python setup.py bdist_msi
,但发生了同样的事情。
我正在使用python 3.8.6rc1版本,并且我也尝试使用pyinstaller,但是每当我尝试运行pyinstaller生成的可执行文件时,都会说无法执行游戏文件。
我知道这很容易阅读,很难理解。但是我在这里严重需要一些帮助。 如果有人可以建议做什么或如何解决此问题,那将非常有帮助。请告诉我是否需要更多信息来为我提供解决方案。
P.S。所有游戏文件都保存在同一目录中,并且游戏运行无任何错误。我面对的唯一麻烦是在创建此问题的可执行安装程序时。
谢谢
解决方法
我以前没有使用过cxFreeze,所以我不能直接帮助您解决问题,但是我真的建议您使用pyinstaller
来打包python程序。我以前在pygame中使用过它,并且效果很好,甚至不需要安装文件。
可以使用pip安装Pyinstaller,并打包您调用的文件:
pyinstaller file.py
,以及您可能需要的所有标志。通常,我使用pyinstaller file.py --onefile --noconsole
来创建一个可执行文件。
Pyinstaller不会打包资产文件,因此您必须随项目一起提供它们,但是项目使用的所有python文件(包括库)都已打包,因此项目中不需要提供任何代码。
Pyinstaller有时可能很气质,所以我建议首先创建一个简单的hello world文件,并使用pyinstaller helloworld.py --onefile
打包,然后在dist/
文件夹中运行该文件。
docs对于pyinstaller并不总是很有帮助,但是我发现学习打包项目的最佳方法是慢慢增加尝试打包的项目的复杂性,并在打包后检查每个项目的工作。 / p>
如果您使用相对脚本和资产导入(例如pygame.image.load('image.png')
),则需要将生成的.exe
移动到原始脚本的位置(.exe
通常在dist/
文件夹,如果您使用相对导入并从那里运行.exe
,则该文件夹将不起作用。
如果要添加图标,可以使用--icon
标志,如下所示:pyinstaller file.py --icon=image.ico
(图标文件必须是.ico
文件-如果出现以下情况,您可以始终在线上进行转换:需要)