任職於「天文數智」的黑蛋在公司部落格發表完「跟著黑蛋用Streamlit速成天文資料分析Web App」系列文章後,收到PM貳婰舞指派的新任務:「我們的老闆,來自喵星的『月影』,發現之前的文章內容對於不懂資料分析的大眾還是有點距離,因此想啟動一個新專案『天文的資料再創作』,希望我們能利用天文資料製作出有趣體驗的應用程式,例如遊戲、網頁、手機app…等等。」於是,黑蛋與他的AI協作夥伴,i蟒,展開新的旅程。
「我們已經用pygame製作出遊戲開始畫面及密室場景畫面。」黑蛋將i蟒從吟遊詩人催眠回製作密室逃脫遊戲的專家,繼續與它協作遊戲。「接下來,請你引導我開發讓玩家等待系外行星資料表載入的畫面,我的需求是當玩家點擊『進入密室』按鈕後,先不要顯示密室場景畫面,而是顯示正在載入資料訊息的畫面,這過程要去取得NASA Exoplanet Archive提供的系外行星資料表,包含系外行星名稱以及它們離地球的距離,若有Python套件可以取得這些資訊,請使用。當成功取得資料表後再顯示密室畫面,而且這個資料表要能在密室畫面中使用,例如從中隨機選一個系外行星名稱,填入原本畫面底下的訊息中,改成『要逃出這個密室,你需要解開…這個系外行星與你的距離』,其中的…為系外行星名稱。請先解說這些功能的開發步驟,不要提供程式碼。」
i蟒邊發出語音邊將文字顯示在螢幕上:「我好睏,先讓我載入一杯咖啡提提神,請稍後……好了,我來根據你的需求列出開發步驟:
「讚唷,請你接著依照這些步驟擴充原本的程式碼。」黑蛋指示道。
「耶,我好棒。我將會在螢幕上顯示修改過的程式碼,以及程式執行後呈現的畫面。另外,當玩家點擊『查看系外行星列表』按鈕後,也會在終端機印出系外行星列表。」
import random
import threading
import pygame
from astroquery.ipac.nexsci.nasa_exoplanet_archive import NasaExoplanetArchive
# 初始化pygame
pygame.init()
# 設定視窗的大小及標題
width, height = 1024, 768
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('逃出天文鎖-系外行星與你的距離')
# 設定顏色
WHITE = '#FFFFFF'
GOLD = '#FFD700'
BLACK = '#000000'
DARK_RED = '#8B0000'
# 設定遊戲首頁及密室的背景圖片
background_menu = pygame.image.load('./assets/background_menu.jpg')
background_menu = pygame.transform.scale(background_menu, (width, height))
background_room = pygame.image.load('./assets/background_room.jpg')
background_room = pygame.transform.scale(background_room, (width, height))
# 設定字型
font_path = './assets/NotoSansTC-Black.ttf'
title_font = pygame.font.Font(font_path, 60)
subtitle_font = pygame.font.Font(font_path, 30)
text_font = pygame.font.Font(font_path, 20)
# 設定按鈕參數
button_color = DARK_RED
button_width, button_height = 200, 50
exoplanet_button_rect = pygame.Rect(20, 20, button_width, button_height)
distance_converter_button_rect = pygame.Rect(width - 220, 20, button_width, button_height)
enter_room_button_rect = pygame.Rect(width // 2 - 100, height // 3 + 50, button_width, button_height)
# 呈現遊戲開始畫面的函式
def display_menu_page():
# 放置背景圖
screen.blit(background_menu, (0, 0))
# 放置主標題、副標題和作者資訊
title = title_font.render('逃出天文鎖-系外行星與你的距離', True, GOLD)
subtitle = subtitle_font.render('為了逃脫《天文鎖》密室,請你解開系外行星與你的距離', True, GOLD)
author_info = text_font.render('由astrobackhacker.tw製作', True, GOLD)
screen.blit(title, (width // 2 - title.get_width() // 2, height // 6 - 15))
screen.blit(subtitle, (width // 2 - subtitle.get_width() // 2, height // 6 + 60))
screen.blit(author_info, (width // 2 - author_info.get_width() // 2, height - 35))
# 放置進入密室的按鈕
pygame.draw.rect(screen, button_color, enter_room_button_rect)
enter_button_text = subtitle_font.render('進入密室', True, WHITE)
screen.blit(enter_button_text, (enter_room_button_rect.x + (enter_room_button_rect.width - enter_button_text.get_width()) // 2, enter_room_button_rect.y + (enter_room_button_rect.height - enter_button_text.get_height()) // 2))
# 呈現正在載入系外行星資料畫面的函式
def display_loading_page():
screen.fill(BLACK)
loading_text = subtitle_font.render('正在載入系外行星資料...', True, WHITE)
screen.blit(loading_text, (width // 2 - loading_text.get_width() // 2, height // 2 - loading_text.get_height() // 2))
pygame.display.flip()
# 從NASA Exoplanet Archive載入系外行星資料的函式
def load_exoplanet_data():
global exoplanet_data
exoplanet_table = NasaExoplanetArchive.query_criteria(
table='pscomppars', select='pl_name, sy_dist'
)
exoplanet_data = exoplanet_table.to_pandas()
exoplanet_data = exoplanet_data.dropna(subset=['sy_dist'])
exoplanet_data.sort_values(by='pl_name', inplace=True, ignore_index=True)
exoplanet_data = exoplanet_data.rename(
columns={
'pl_name': '行星名稱',
'sy_dist': '與地球的距離(秒差距)'
}
)
# 呈現密室畫面的函式
def display_room_page(planet_name):
# 放置背景圖
screen.blit(background_room, (0, 0))
# 放置對話框及密室描述
pygame.draw.rect(screen, BLACK, (0, height - 100, width, 100))
room_description = f'你身處在一個系外行星主題的密室,左邊牆上掛著NASA提供的系外行星列表,右邊則有一台距離轉換器。要逃出這個密室,你需要解開{planet_name}這個系外行星與你的距離。'
room_description_sentences = room_description.split('。')
room_description_sentences = [sentence + '。' for sentence in room_description_sentences if sentence]
y_text = height - 80
for sentence in room_description_sentences:
rendered_text = text_font.render(sentence, True, GOLD)
screen.blit(rendered_text, (10, y_text))
y_text += text_font.size(sentence)[1]
# 放置按鈕
pygame.draw.rect(screen, button_color, exoplanet_button_rect)
exoplanet_button_text = text_font.render('查看系外行星列表', True, WHITE)
screen.blit(exoplanet_button_text, (exoplanet_button_rect.x + 20, exoplanet_button_rect.y + 7))
pygame.draw.rect(screen, button_color, distance_converter_button_rect)
distance_converter_button_text = text_font.render('啟動距離轉換器', True, WHITE)
screen.blit(distance_converter_button_text, (distance_converter_button_rect.x + 20, distance_converter_button_rect.y + 7))
# 初始化遊戲狀態、系外行星資料載入的變數及執行緒
game_state = 'menu'
exoplanet_data = None
loading_thread = None
selected_exoplanet_name = None
# 遊戲主循環
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if game_state == 'menu' and enter_room_button_rect.collidepoint(event.pos):
game_state = 'loading'
# 建立並啟動新執行緒以載入系外行星資料
loading_thread = threading.Thread(target=load_exoplanet_data)
loading_thread.start()
if game_state == 'room':
if exoplanet_button_rect.collidepoint(event.pos):
print('系外行星列表按鈕被點擊')
print(exoplanet_data)
elif distance_converter_button_rect.collidepoint(event.pos):
print('距離轉換器按鈕被點擊')
# 依據遊戲狀態更新畫面
if game_state == 'menu':
display_menu_page()
elif game_state == 'loading':
display_loading_page()
# 檢查執行緒是否還在運行
if not loading_thread.is_alive():
selected_exoplanet_name = random.choice(exoplanet_data['行星名稱'])
game_state = 'room'
elif game_state == 'room':
display_room_page(selected_exoplanet_name)
pygame.display.flip()
# 關閉pygame程式結束遊戲主循環
pygame.quit()
「酷耶!請你把這段程式更新到GitHub的『Fun with Astrodata Apps』這個大專案底下的『escape-room-exoplanet-distance』專案中。完成後,請再度轉生成星際吟遊詩人,讓我先休息一下,你先吟唱一段廣告。」
「好…的…
在東方崛起了一群星,Astrohackers名聲響亮清, 中央大學天文所攜手共同征,Python技能映照星空廣。
天文學的奧秘深不可測,Python語言如鑰開啟此門, 交流思想,共享知識,不斷進步,開放天文,目標堅定不替換。
Astrohackers-TW,社群的呼喚, 探索宇宙,用程式碼描繪夜晚, 夥伴們聚,分享經驗,共成長, 天文領域,Python舞動光芒。
在這裡,每顆心懷抱星空夢想, 學習Python,開啟知識之窗。 Astrohackers-TW,激情澎湃, 一起描繪夜空最美麗的畫。」
此篇文是由蘇羿豪經ChatGPT協助創作,文章以「創用CC姓名標示-非商業性-禁止改作 4.0(CC BY-NC-ND 4.0)國際版授權條款」釋出,相關程式碼以MIT授權條款釋出。