程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python入門實踐運行外星人入侵程序出現Segmentation Fault錯誤

編輯:Python

目前在學習《python編程:從入門到實踐》這本書,完成第一個項目“外星人入侵”時所遇到的問題如下圖,詭異的是這個錯誤不是每次運行alien_invasion時都出現(前幾次運行都能正確的完成相應的邏輯功能),出現這個錯誤後我再次重新運行,有時候可以正常運行,有時候繼續報這個錯誤。不知道啥原因,人都麻了。


alien.py 代碼如下

import pygamefrom pygame.sprite import Spriteclass Alien(Sprite): # 表示單個外星人的類 def __init__(self, ai_settings, screen): # 初始化外星人並設置其起始位置 super().__init__() self.screen = screen self.ai_settings = ai_settings # 加載外星人圖像,並設置其rect屬性 self.image = pygame.image.load('images/alien.bmp') self.image = pygame.transform.scale(self.image, (45, 48)) self.rect = self.image.get_rect() # 每個外星人最初都在屏幕左上角附近 # 每個外星人的左邊距都設置為外星人的寬度,並將上邊距設置為外星人的高度 self.rect.x = self.rect.width self.rect.y = self.rect.height # 存儲外星人的准確位置 self.x = float(self.rect.x) def check_edges(self): # 如果外星人位於屏幕邊緣,就返回True screen_rect = self.screen.get_rect() if self.rect.right >= screen_rect.right: return True elif self.rect.left <= 0: return True def update(self): # 向左或向右移動外星人 self.x += (self.ai_settings.alien_speed_factor * self.ai_settings.fleet_direction) self.rect.x =self.x def blitme(self): # 在指定位置繪制外星人 self.screen.blit(self.image, self.rect)

alien_invasion.py 代碼如下

import pygamefrom pygame.sprite import Groupfrom button import Buttonfrom game_stats import GameStatsfrom ship import Shipfrom settings import Settingsimport game_functions as gfdef run_game(): # 初始化pygame、設置和屏幕對象 pygame.init() ai_settings = Settings() # 創建顯示窗口,並指定了游戲窗口的尺寸px,注意使用了兩個括號 screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height)) pygame.display.set_caption("Alien Invasion") ship = Ship(ai_settings, screen) # 創建一艘飛船 bullets = Group() # 創建一個用於存儲子彈的編組 aliens = Group() # 創建一個外星人編組 stats = GameStats(ai_settings) # 創建一個用於存儲游戲統計信息的實例 gf.create_fleet(ai_settings, screen, ship, aliens) # 創建外星人群 play_button = Button(ai_settings, screen, 'Play') # 創建Play按鈕 # 開始游戲的主循環 while True: gf.check_events(ai_settings, screen, stats, play_button, ship, aliens, bullets) # 監視鍵盤和鼠標事件 if stats.game_active: ship.update() # 更新飛船的位置 gf.update_bullets(ai_settings, screen, ship, aliens, bullets) # 更新所有未消失的子彈的位置 gf.update_aliens(ai_settings, stats, screen, ship, aliens, bullets) gf.update_screen(ai_settings, screen, stats, ship, aliens, bullets, play_button) # 使用更新後的位置來重新繪制新屏幕run_game() # 這將初始化游戲並開始主循環

bullet.py 代碼塊

import pygamefrom pygame.sprite import Spriteclass Bullet(Sprite): """一個對飛船發射的子彈進行管理的類""" def __init__(self, ai_settings, screen, ship): # 在飛船所在的位置創建一個子彈對象 super().__init__() self.screen = screen # 在(0,0)處創建一個表示子彈的矩形,再設正確的位置 self.rect = pygame.Rect(0, 0, ai_settings.bullet_width, ai_settings.bullet_height) self.rect.centerx = ship.rect.centerx self.rect.top = ship.rect.top # 將表示子彈的rect 的top屬性設置為飛船的rect 的top 屬性,讓子彈看起來像是從飛船中射出的 # 存儲用小數表示的子彈位置 self.y = float(self.rect.y) self.color = ai_settings.bullet_color self.speed_factor = ai_settings.bullet_speed_factor def update(self): # 向上移動子彈 # 更新表示子彈位置的小數值 self.y -= self.speed_factor # 發射出去後,子彈在屏幕中向上移動,這意味著y 坐標將不斷減小 # 更新表示子彈的rect的位置 self.rect.y = self.y def draw_bullet(self): # 在屏幕上繪制子彈 pygame.draw.rect(self.screen, self.color, self.rect)

button.py 代碼塊

import pygame.font # 將文本渲染到屏幕上class Button(): def __init__(self, ai_settings, screen, msg): # 初始化按鈕的屬性 self.screen = screen self.screen_rect = screen.get_rect() # 設置按鈕的尺寸和其他屬性 self.width, self.height = 200, 50 self.button_color = (67, 205, 128) self.text_color = (255, 255, 255) self.font = pygame.font.SysFont(None, 48) # 實參None 讓Pygame 使用默認字體,48指定文本的字號。 # 創建按鈕的rect對象,並使其居中 self.rect = pygame.Rect(0, 0, self.width, self.height) self.rect.center = self.screen_rect.center # 按鈕的標簽只需創建一次 self.prep_msg(msg) def prep_msg(self, msg): # 將msg渲染為圖像,並使其在按鈕上居中 self.msg_image = self.font.render(msg, True, self.text_color, self.button_color) self.msg_image_rect = self.msg_image.get_rect() self.msg_image_rect.center = self.rect.center def draw_button(self): # 描繪一個用顏色填充的按鈕,再繪制文本 self.screen.fill(self.button_color, self.rect) self.screen.blit(self.msg_image, self.msg_image_rect)

game_functions.py 代碼塊:

import sys # 玩家退出時,使用模塊sys退出游戲from time import sleepimport pygamefrom alien import Alienfrom bullet import Bulletdef check_keydown_events(event, ai_settings, screen, ship, bullets): # 響應按鍵 if event.key == pygame.K_RIGHT: ship.moving_right = True elif event.key == pygame.K_LEFT: ship.moving_left = True elif event.key == pygame.K_UP: ship.moving_up = True elif event.key == pygame.K_DOWN: ship.moving_down = True elif event.key == pygame.K_SPACE: fire_bullet(ai_settings, screen, ship, bullets)def check_keyup_events(event, ship): # 響應松開 if event.key == pygame.K_RIGHT: ship.moving_right = False elif event.key == pygame.K_LEFT: ship.moving_left = False elif event.key == pygame.K_UP: ship.moving_up = False elif event.key == pygame.K_DOWN: ship.moving_down = False elif event.key == pygame.K_q: sys.exit()def check_events(ai_settings, screen, stats, play_button, ship, aliens, bullets): # 響應按鍵和鼠標事件 for event in pygame.event.get(): if event.type == pygame.QUIT: # 玩家單擊游戲窗口關閉按鈕時檢測到 sys.exit() elif event.type == pygame.KEYDOWN: check_keydown_events(event, ai_settings, screen, ship, bullets) elif event.type == pygame.KEYUP: check_keyup_events(event, ship) elif event.type == pygame.MOUSEBUTTONDOWN: mouse_x, mouse_y = pygame.mouse.get_pos() check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y)def check_play_button(ai_settings, screen, stats, play_button, ship, aliens, bullets, mouse_x, mouse_y): # 玩家單擊Play按鈕時開始新游戲 button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y) if button_clicked and not stats.game_active: # 隱藏光標 pygame.mouse.set_visible(False) # 重置游戲統計信息 stats.reset_stats() stats.game_active = True # 清空外星人列表和子彈列表 aliens.empty() bullets.empty() # 創建一群新的外星人,並讓飛船居中 create_fleet(ai_settings, screen, ship, aliens) ship.center_ship()def update_screen(ai_settings, screen, stats, ship, aliens, bullets, play_button): # 更新屏幕上的圖像,並切換到新屏幕 # 每次循環時都重繪屏幕 screen.fill(ai_settings.bg_color) # 在飛船和外星人後面重繪所有子彈 for bullet in bullets.sprites(): bullet.draw_bullet() ship.blitme() aliens.draw(screen) # 如果游戲處於非活動狀態,就繪制Play按鈕 if not stats.game_active: play_button.draw_button() # 不斷更新屏幕,讓最近繪制的屏幕可見 # 在我們移動游戲元素時,pygame.display.flip() 將不斷更新屏幕,以顯示元素的新位置,並在原來的位置隱藏元素,從而營造平滑移動的效果。 pygame.display.flip()def update_bullets(ai_settings, screen, ship, aliens, bullets): # 更新子彈的位置 bullets.update() # 刪除已消失的子彈 for bullet in bullets.copy(): if bullet.rect.bottom <= 0: bullets.remove(bullet) check_bullet_alien_collisions(ai_settings, screen, ship, aliens, bullets)def check_bullet_alien_collisions(ai_settings, screen, ship, aliens, bullets): # 響應子彈和外星人的碰撞 # 刪除發生碰撞的子彈和外星人 collisions = pygame.sprite.groupcollide(bullets, aliens, True, True) if len(aliens) == 0: # 刪除現有的子彈並新建一群外星人 bullets.empty() create_fleet(ai_settings, screen, ship, aliens)def fire_bullet(ai_settings, screen, ship, bullets): # 如果沒有到達限制,就發射一顆子彈 # 創建一顆子彈,並將其加入到編組bullets中 if len(bullets) < ai_settings.bullets_allowed: new_bullet = Bullet(ai_settings, screen, ship) bullets.add(new_bullet)def get_number_aliens_x(ai_settings, alien_width): # 計算每行可容納多少個外星人 avaliable_space_x = ai_settings.screen_width - 2 * alien_width number_aliens_x = int(avaliable_space_x / (2 * alien_width)) return number_aliens_xdef get_number_rows(ai_settings, ship_height, alien_height): # 計算屏幕可容納多少行外星人 available_space_y = (ai_settings.screen_height - (3 * alien_height) - ship_height) number_rows = int(available_space_y / (2 * alien_height)) return number_rowsdef create_alien(ai_settings, screen, aliens, alien_number, row_number): # 創建一個外星人並將其放在當前行 alien = Alien(ai_settings, screen) alien_width = alien.rect.width # 從外星人的rect 屬性中獲取外星人寬度 alien.x = alien_width + 2 * alien_width * alien_number alien.rect.x = alien.x alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_number aliens.add(alien)def create_fleet(ai_settings, screen, ship, aliens): # 創建外星人群 # 創建一個外星人,並計算一行可容納多少個外星人 # 外星人間距為外星人寬度 alien = Alien(ai_settings, screen) number_aliens_x = get_number_aliens_x(ai_settings, alien.rect.width) number_rows = get_number_rows(ai_settings, ship.rect.height, alien.rect.height) # # 創建第一行外星人 # for alien_number in range(number_aliens_x): # create_alien(ai_settings, screen, aliens, alien_number) # 創建外星人群 for row_number in range(number_rows): for alien_number in range(number_aliens_x): create_alien(ai_settings, screen, aliens, alien_number, row_number)def check_fleet_edges(ai_settings, aliens): # 有外星人到達邊緣時采取相應的措施 for alien in aliens.sprites(): if alien.check_edges(): change_fleet_direction(ai_settings, aliens) breakdef change_fleet_direction(ai_settings, aliens): # 將整群外星人向下移動,並改變它們的方向 for alien in aliens.sprites(): alien.rect.y += ai_settings.fleet_drop_speed ai_settings.fleet_direction *= -1def ship_hit(ai_settings, stats, screen, ship, aliens, bullets): # 響應被外星人撞到的飛船 if stats.ships_left > 0: # 將ship_left減 1 stats.ships_left -= 1 # 清空外星人列表和子彈列表 aliens.empty() bullets.empty() # 創建一群新外星人,並把飛船放到底部中央 create_fleet(ai_settings, screen, ship, aliens) ship.center_ship() # 暫停 sleep(0.5) else: stats.game_active = False pygame.mouse.set_visible(True)def check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets): # 檢查是否有外星人到達了屏幕底部 screen_rect = screen.get_rect() for alien in aliens.sprites(): if alien.rect.bottom >= screen_rect.bottom: # 像被飛船撞到一樣處理 ship_hit(ai_settings, stats, screen, ship, aliens, bullets) breakdef update_aliens(ai_settings, stats, screen, ship, aliens, bullets): # 檢查是否有外星人到達了屏幕底部 check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets) # 檢查是否有外星人位於屏幕邊緣,並更新外星人群中所有外星人的位置 check_fleet_edges(ai_settings, aliens) aliens.update() # 檢測外星人和飛船之間的碰撞 if pygame.sprite.spritecollideany(ship, aliens): ship_hit(ai_settings, stats, screen, ship, aliens, bullets)

game_stats.py 代碼塊

class GameStats(): # 跟蹤游戲的統計信息 def __init__(self, ai_settings): # 初始化統計信息 self.ai_settings = ai_settings self.reset_stats() # 讓游戲一開始處於非活動狀態 self.game_active = False def reset_stats(self): # 初始化在游戲運行期間可能變化的統計信息 self.ships_left = self.ai_settings.ship_limit

settings 代碼塊

class Settings(): # 存儲該項目所有設置的類 def __init__(self): # 初始化游戲的設置 # 屏幕設置 self.screen_width = 1000 self.screen_height = 700 self.bg_color = (230, 230, 230) # 飛船的設置 self.ship_left_right_speed_factor = 1.5 # 左右移動速度 self.ship_up_down_speed_factor = 1.5 self.ship_limit = 3 # 子彈設置 self.bullet_speed_factor = 3 self.bullet_width = 3 self.bullet_height = 15 self.bullet_color = 178, 34, 34 self.bullets_allowed = 3 # 外星人設置 self.alien_speed_factor = 0.3 # 外星人移動速度設置 self.fleet_drop_speed = 10 # 外星人群向下移動的速度 # fleet_direction為1表示向右移,為-1表示向左移 self.fleet_direction = 1

ship.py 代碼塊

import pygameclass Ship(): def __init__(self, ai_settings, screen): # 初始化飛船並設置其初始位置 self.screen = screen self.ai_settings = ai_settings # 加載飛船圖像並獲取其外接矩形 self.image = pygame.image.load('images/ship.bmp') self.image = pygame.transform.scale(self.image, (40, 70)) # 將Surface屬性的self.image轉化為30×30的大小 self.rect = self.image.get_rect() self.screen_rect = screen.get_rect() # 將每艘新飛船放在屏幕底部中央 self.rect.centerx = self.screen_rect.centerx self.rect.bottom = self.screen_rect.bottom # 在飛船的屬性center中存儲小數值 self.centerx = float(self.rect.centerx) self.centery = float(self.rect.centery) # 移動標志 self.moving_right = False self.moving_left = False self.moving_up = False self.moving_down = False def update(self): # 根據移動標志調整飛船的位置 # 更新飛船的center值,而不是rect # 讓飛船到達屏幕邊緣後停止移動 if self.moving_right and (self.rect.right < self.screen_rect.right): # 標志為True時向右移動飛船 self.centerx += self.ai_settings.ship_left_right_speed_factor if self.moving_left and (self.rect.left > 0): self.centerx -= self.ai_settings.ship_left_right_speed_factor if self.moving_down and (self.rect.bottom < self.screen_rect.bottom): self.centery += self.ai_settings.ship_up_down_speed_factor if self.moving_up and (self.rect.top > 0): self.centery -= self.ai_settings.ship_up_down_speed_factor # 根據self.centerx/y更新rect對象 self.rect.centerx = self.centerx self.rect.centery = self.centery def blitme(self): # 在指定位置繪制飛船 self.screen.blit(self.image, self.rect) def center_ship(self): # 讓飛船在屏幕居中 # self.center = self.screen_rect.centerx self.rect.midbottom = self.screen_rect.midbottom self.centerx = float(self.rect.centerx) self.centery = float(self.rect.centery)

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved