年末航天有大事,嫦五攬月取巖石,
這幾天,有被嫦娥五號刷屏嗎?就在本周二晚11點11分,嫦娥五號的著陸器–上升器組合體成功登月,現已正式開展月面采樣任務,嫦娥五號將為我國科學家帶回約兩千克月球巖石和土壤,時隔44年,人類終于能再次從月球帶回“土特產”了!
嫦娥五號(圖源:中國探月工程)
作為科技愛好者斜杠程式員爸爸,想不想寫一個酷炫的月球著陸游戲,給娃秀一秀專業技能 讓娃一起開心開心?
今天就來用Python寫一個月球著陸仿真游戲吧!
太長不看提示:本例來源于由“Python之父”吉多·范羅蘇姆推薦的《父與子的編程之旅》,請滑至文末了解如何獲取完整代碼,
游
戲
任
務
我們的飛船正準備登月,它攜帶定量的燃料,這些燃料會為反推發動機提供推力,
在游戲開始時,飛船離月球表面有一定的距離,月球的重力把它向下拉,我們必須使用反推發動機級訓降落速度,讓飛船的縱向速度變為0,從而平緩著陸,
注意,必須小心地操作反推發動機,如果用力不足,飛船就會重重地摔在月面;如果用力過猛,則燃料會很快耗盡,飛船會向上飛入太空!
游
戲
界
面
左下角的小灰條表示反推發動機的操作桿,用滑鼠上下拖動即可控制推力,
燃料表(綠色)顯示當前剩余的燃料,界面上方的文本給出動態變化的速度、加速度、高度和推力,
邏
輯
分
析
反推發動機的推力取決于消耗了多少燃料,有時推力會大于重力,有時則會小于重力,當發動機關閉時,推力為0,此時只剩下重力,
要得到飛船所受的凈作用力,只需把推力和重力相加,由于二者的方向相反,因此可以用一個正數和一個負數來表示,一旦得到飛船所受的凈作用力,就可以利用公式得出它的速度和位置,
我們的程式必須跟蹤以下幾點,
- 飛船相對于月面的高度,以及飛船的速度和加速度,
- 飛船的質量(隨著燃料的消耗,質量會變化),
- 反推發動機的推力,推力越大,燃料消耗得就越快,
- 飛船剩余多少燃料,當反推發動機消耗燃料時,飛船會變輕,但是如果燃料耗盡,就不再有推力了,
- 飛船所受的重力,這取決于月球的大小、飛船的質量、燃料的消耗情況等,
開
始
編
寫
提示:本文假定你已經安裝了Pygame模塊,如果還沒有安裝,請滑至文末查看安裝說明,
我們使用Pygame模塊撰寫該游戲,用單次時鐘“嘀嗒”作為時間單位,每“嘀嗒”一次,程式就要檢查飛船當前所受的凈作用力,并更新高度、速度、加速度和剩余燃料等資訊,然后根據這些資訊更新圖片和文本,
1 首先初始化游戲,創建Pygame視窗,加載影像,并為變數設定一些初始值,
import pygame, sys
pygame.init()
screen = pygame.display.set_mode([400,600])
screen.fill([0, 0, 0])
ship = pygame.image.load('lunarlander.png')
moon = pygame.image.load('moonsurface.png')
ground = 540
start = 90
clock = pygame.time.Clock()
ship_mass = 5000.0
fuel = 5000.0
velocity = -100.0
gravity = 10
height = 2000
thrust = 0
delta_v = 0
y_pos = 90
held_down = False
2 為反推發動機定義Sprite類,
class ThrottleClass(pygame.sprite.Sprite):
def __init__(self, location = [0,0]):
pygame.sprite.Sprite.__init__(self)
image_surface = pygame.surface.Surface([30, 10])
image_surface.fill([128,128,128])
self.image = image_surface.convert()
self.rect = self.image.get_rect()
self.rect.left, self.rect.centery = location
3 計算飛船的高度、速度、加速度和燃料消耗量,
def calculate_velocity():
global thrust, fuel, velocity, delta_v, height, y_pos
delta_t = 1/fps #對應Pygame回圈的一幀
thrust = (500 - myThrottle.rect.centery) * 5.0 #將反推發動機精靈的y坐標轉換為推力
fuel -= thrust /(10 * fps) #根據推力減少燃料
if fuel < 0: fuel = 0.0
if fuel < 0.1: thrust = 0.0
delta_v = delta_t * (-gravity + 200 * thrust / (ship_mass + fuel)) #物理公式
velocity = velocity + delta_v
delta_h = velocity * delta_t
height = height + delta_h
y_pos = ground - (height * (ground - start) / 2000) - 90 #將高度轉換為Pygame的y坐標
4 使用字體物件顯示統計資訊,
def display_stats():
v_str = "velocity: %i m/s" % velocity
h_str = "height: %.1f" % height
t_str = "thrust: %i" % thrust
a_str = "acceleration: %.1f" % (delta_v * fps)
f_str = "fuel: %i" % fuel
v_font = pygame.font.Font(None, 26)
v_surf = v_font.render(v_str, 1, (255, 255, 255))
screen.blit(v_surf, [10, 50])
a_font = pygame.font.Font(None, 26)
a_surf = a_font.render(a_str, 1, (255, 255, 255))
screen.blit(a_surf, [10, 100])
h_font = pygame.font.Font(None, 26)
h_surf = h_font.render(h_str, 1, (255, 255, 255))
screen.blit(h_surf, [10, 150])
t_font = pygame.font.Font(None, 26)
t_surf = t_font.render(t_str, 1, (255, 255, 255))
screen.blit(t_surf, [10, 200])
f_font = pygame.font.Font(None, 26)
f_surf = f_font.render(f_str, 1, (255, 255, 255))
screen.blit(f_surf, [60, 300])
5 畫出尾焰三角形,尾焰大小會隨推力變化而變化,
def display_flames():
flame_size = thrust / 15
for i in range (2):
startx = 252 - 10 + i * 19
starty = y_pos + 83
pygame.draw.polygon(screen, [255, 109, 14], [(startx, starty),
(startx + 4, starty + flame_size),
(startx + 8, starty)], 0)
6 Pygame程式主事件回圈,畫出所有內容,
myThrottle = ThrottleClass([15, 500]) #創建反推發動機物件
running = True
while running:
clock.tick(30)
fps = clock.get_fps()
if fps < 1: fps = 30
if height > 0.01:
calculate_velocity()
screen.fill([0, 0, 0])
display_stats()
pygame.draw.rect(screen, [0, 0, 255], [80, 350, 24, 100], 2)
fuelbar = 96 * fuel / 5000
pygame.draw.rect(screen, [0,255,0],
[84,448-fuelbar,18, fuelbar], 0) #燃料量
pygame.draw.rect(screen, [255, 0, 0],
[25, 300, 10, 200],0) #畫出反推發動機滑塊
screen.blit(moon, [0, 500, 400, 100]) #畫出月球
pygame.draw.rect(screen, [60, 60, 60],
[220, 535, 70, 5],0) #著陸點
screen.blit(myThrottle.image, myThrottle.rect) #畫出操縱桿
display_flames()
screen.blit(ship, [230, y_pos, 50, 90]) #畫出飛船
instruct1 = "Land softly without running out of fuel"
instruct2 = "Good landing: < 15m/s Great landing: < 5m/s"
inst1_font = pygame.font.Font(None, 24)
inst1_surf = inst1_font.render(instruct1, 1, (255, 255, 255))
screen.blit(inst1_surf, [50, 550])
inst2_font = pygame.font.Font(None, 24)
inst2_surf = inst1_font.render(instruct2, 1, (255, 255, 255))
screen.blit(inst2_surf, [20, 575])
pygame.display.flip()
7 收尾部分:檢查滑鼠是否拖動反推發動機,更新反推發動機位置,
else:
display_final()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
held_down = True
elif event.type == pygame.MOUSEBUTTONUP:
held_down = False
elif event.type == pygame.MOUSEMOTION:
if held_down:
myThrottle.rect.centery = event.pos[1]
if myThrottle.rect.centery < 300:
myThrottle.rect.centery = 300
if myThrottle.rect.centery > 500:
myThrottle.rect.centery = 500
pygame.quit()
搞定!到底能不能像嫦娥五號一樣成功登月呢?今晚就和娃一起試試吧!Happy landing!
推
薦
圖
書
沃倫·桑德 卡特·桑德 著
楊文其 蘇金國 易鄭超 譯
老少咸宜的Python編程啟蒙書
“Python之父”龜叔推薦,獲Jolt生產效率獎
新版全彩印刷,插圖生動活潑
“孩子會喜歡上這一本以他們的視角所寫的書,也會學到很多,”
——“Python之父”吉多·范羅蘇姆
“Python,是00后的BASIC,據我觀察,這本書是眾多70后和80后教孩子編程的優選圖書,也是很多家長自己學Python編程的開始,”
——愛編程的魏校長,知名教育博主
“這本書用Python語言教你如何寫程式,是一本老少咸宜的編程書,”
——左耳朵耗子(陳皓)
“近年來少兒編程非常火爆,如果你是一位‘碼農’家長,不如發揮自己的專長,做孩子的啟蒙老師和學習伙伴,這本書就是很棒的‘親子編程學習實踐手冊’,”
——周自恒,公眾號“周花卷”主理人
購書傳送門
文末提示:隨書附贈無毒安裝程式,一鍵式安裝Python 3及Pygame模塊,并獲取本書所有游戲代碼,請在桌面端單擊“閱讀原文”,下載隨書資源,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/232648.html
標籤:其他
上一篇:牧羊人和金斧子|不要和產品聊天!
