小言_互联网的博客

给娃写个游戏,庆祝嫦娥五号登月

332人阅读  评论(0)

年末航天有大事,嫦五揽月取岩石。

这几天,有被嫦娥五号刷屏吗?就在本周二晚11点11分,嫦娥五号的着陆器–上升器组合体成功登月,现已正式开展月面采样任务。嫦娥五号将为我国科学家带回约两千克月球岩石和土壤。时隔44年,人类终于能再次从月球带回“土特产”了!

嫦娥五号(图源:中国探月工程)

作为科技爱好者斜杠程序员爸爸,想不想写一个酷炫的月球着陆游戏,给娃秀一秀专业技能 让娃一起开心开心?

今天就来用Python写一个月球着陆仿真游戏吧!

太长不看提示:本例来源于由“Python之父”吉多·范罗苏姆推荐的《父与子的编程之旅》。请滑至文末了解如何获取完整代码。


我们的飞船正准备登月。它携带定量的燃料,这些燃料会为反推发动机提供推力。

在游戏开始时,飞船离月球表面有一定的距离。月球的重力把它向下拉,我们必须使用反推发动机减缓降落速度,让飞船的纵向速度变为0,从而平缓着陆。

注意,必须小心地操作反推发动机。如果用力不足,飞船就会重重地摔在月面;如果用力过猛,则燃料会很快耗尽,飞船会向上飞入太空!

左下角的小灰条表示反推发动机的操作杆,用鼠标上下拖动即可控制推力。

燃料表(绿色)显示当前剩余的燃料。界面上方的文本给出动态变化的速度、加速度、高度和推力。

反推发动机的推力取决于消耗了多少燃料,有时推力会大于重力,有时则会小于重力。当发动机关闭时,推力为0,此时只剩下重力。

要得到飞船所受的净作用力,只需把推力和重力相加。由于二者的方向相反,因此可以用一个正数和一个负数来表示。一旦得到飞船所受的净作用力,就可以利用公式得出它的速度和位置。

我们的程序必须跟踪以下几点。

- 飞船相对于月面的高度,以及飞船的速度和加速度。

- 飞船的质量(随着燃料的消耗,质量会变化)。

- 反推发动机的推力。推力越大,燃料消耗得就越快。

- 飞船剩余多少燃料。当反推发动机消耗燃料时,飞船会变轻,但是如果燃料耗尽,就不再有推力了。

- 飞船所受的重力。这取决于月球的大小、飞船的质量、燃料的消耗情况等。

提示:本文假定你已经安装了Pygame模块。如果还没有安装,请滑至文末查看安装说明。

我们使用Pygame模块编写该游戏,用单次时钟“嘀嗒”作为时间单位。每“嘀嗒”一次,程序就要检查飞船当前所受的净作用力,并更新高度、速度、加速度和剩余燃料等信息,然后根据这些信息更新图片和文本。

 1  首先初始化游戏。创建Pygame窗口,加载图像,并为变量设置一些初始值。


   
  1. import pygame, sys
  2. pygame.init()
  3. screen = pygame.display.set_mode([ 400, 600])
  4. screen.fill([ 000])
  5. ship = pygame.image.load( 'lunarlander.png')
  6. moon = pygame.image.load( 'moonsurface.png')
  7. ground =  540
  8. start =  90
  9. clock = pygame.time.Clock()
  10. ship_mass =  5000.0
  11. fuel =  5000.0
  12. velocity =  -100.0
  13. gravity =  10
  14. height =  2000
  15. thrust =  0
  16. delta_v =  0
  17. y_pos =  90
  18. held_down = False

 2  为反推发动机定义Sprite类。


   
  1. class ThrottleClass(pygame.sprite.Sprite):
  2.     def __init__(self, location = [ 0, 0]):
  3.         pygame.sprite.Sprite.__init__(self)
  4.         image_surface = pygame.surface.Surface([ 3010])
  5.         image_surface.fill([ 128, 128, 128])
  6.         self.image = image_surface.convert()
  7.         self.rect = self.image.get_rect()
  8.         self.rect.left, self.rect.centery = location

 3  计算飞船的高度、速度、加速度和燃料消耗量。


   
  1. def calculate_velocity():
  2.     global thrust, fuel, velocity, delta_v, height, y_pos
  3.     delta_t =  1/fps #对应Pygame循环的一帧
  4.     thrust = ( 500 - myThrottle.rect.centery) *  5.0 #将反推发动机精灵的y坐标转换为推力
  5.     fuel -= thrust /( 10 * fps) #根据推力减少燃料
  6.      if fuel <  0: fuel =  0.0
  7.      if fuel <  0.1: thrust =  0.0
  8.     delta_v = delta_t * (-gravity +  200 * thrust / (ship_mass + fuel)) #物理公式
  9.     velocity = velocity + delta_v
  10.     delta_h = velocity * delta_t
  11.     height = height + delta_h
  12.     y_pos = ground - (height * (ground - start) /  2000) -  90 #将高度转换为Pygame的y坐标

 4  使用字体对象显示统计信息。


   
  1. def display_stats():
  2.     v_str =  "velocity: %i m/s" % velocity
  3.     h_str =  "height: %.1f" % height
  4.     t_str =  "thrust: %i" % thrust
  5.     a_str =  "acceleration: %.1f" % (delta_v * fps)
  6.     f_str =  "fuel: %i" % fuel
  7.     v_font = pygame.font.Font(None,  26)
  8.     v_surf = v_font.render(v_str,  1, ( 255255255))
  9.     screen.blit(v_surf, [ 1050])
  10.     a_font = pygame.font.Font(None,  26)
  11.     a_surf = a_font.render(a_str,  1, ( 255255255))
  12.     screen.blit(a_surf, [ 10100])
  13.     h_font = pygame.font.Font(None,  26)
  14.     h_surf = h_font.render(h_str,  1, ( 255255255))
  15.     screen.blit(h_surf, [ 10150])
  16.     t_font = pygame.font.Font(None,  26)
  17.     t_surf = t_font.render(t_str,  1, ( 255255255))
  18.     screen.blit(t_surf, [ 10200])
  19.     f_font = pygame.font.Font(None,  26)
  20.     f_surf = f_font.render(f_str,  1, ( 255255255))
  21.     screen.blit(f_surf, [ 60300])

 5  画出尾焰三角形,尾焰大小会随推力变化而变化。


   
  1. def display_flames():
  2.     flame_size = thrust /  15
  3.      for i in  range ( 2):
  4.         startx =  252 -  10 + i *  19
  5.         starty = y_pos +  83
  6.         pygame.draw.polygon(screen, [ 25510914], [(startx, starty),
  7.                                     (startx +  4, starty + flame_size),
  8.                                     (startx +  8, starty)],  0)

 6  Pygame程序主事件循环,画出所有内容。


   
  1. myThrottle = ThrottleClass([ 15500]) #创建反推发动机对象
  2. running = True
  3. while running:
  4.     clock.tick( 30)
  5.     fps = clock.get_fps()
  6.      if fps <  1: fps =  30
  7.      if height >  0.01:
  8.         calculate_velocity()
  9.         screen.fill([ 000])
  10.         display_stats()
  11.         pygame.draw.rect(screen, [ 00255], [ 8035024100],  2)
  12.         fuelbar =  96 * fuel /  5000
  13.         pygame.draw.rect(screen, [ 0, 255, 0],
  14.                [ 84, 448-fuelbar, 18, fuelbar],  0) #燃料量
  15.         pygame.draw.rect(screen, [ 25500],
  16.                [ 2530010200], 0) #画出反推发动机滑块
  17.         screen.blit(moon, [ 0500400100]) #画出月球
  18.         pygame.draw.rect(screen, [ 606060],
  19.                [ 220535705], 0) #着陆点
  20.         screen.blit(myThrottle.image, myThrottle.rect) #画出操纵杆
  21.         display_flames()
  22.         screen.blit(ship, [ 230, y_pos,  5090]) #画出飞船
  23.         instruct1 =  "Land softly without running out of fuel"
  24.         instruct2 =  "Good landing: < 15m/s Great landing: < 5m/s"
  25.         inst1_font = pygame.font.Font(None,  24)
  26.         inst1_surf = inst1_font.render(instruct1,  1, ( 255255255))
  27.         screen.blit(inst1_surf, [ 50550])
  28.         inst2_font = pygame.font.Font(None,  24)
  29.         inst2_surf = inst1_font.render(instruct2,  1, ( 255255255))
  30.         screen.blit(inst2_surf, [ 20575])
  31.         pygame.display.flip()

 7  收尾部分:检查鼠标是否拖动反推发动机,更新反推发动机位置。


   
  1. else:
  2.     display_final()
  3. for event in pygame.event.get():
  4.      if event. type == pygame.QUIT:
  5.         running = False
  6.     elif event. type == pygame.MOUSEBUTTONDOWN:
  7.         held_down = True
  8.     elif event. type == pygame.MOUSEBUTTONUP:
  9.         held_down = False
  10.     elif event. type == pygame.MOUSEMOTION:
  11.          if held_down:
  12.             myThrottle.rect.centery = event.pos[ 1]
  13.              if myThrottle.rect.centery <  300:
  14.                 myThrottle.rect.centery =  300
  15.              if myThrottle.rect.centery >  500:
  16.                 myThrottle.rect.centery =  500
  17. pygame.quit()

搞定!到底能不能像嫦娥五号一样成功登月呢?今晚就和娃一起试试吧!Happy landing!

沃伦·桑德  卡特·桑德   著

杨文其  苏金国  易郑超   译

老少咸宜的Python编程启蒙书

“Python之父”龟叔推荐,获Jolt生产效率奖

新版全彩印刷,插图生动活泼

“孩子会喜欢上这一本以他们的视角所写的书,也会学到很多。”

——“Python之父”吉多·范罗苏姆

“Python,是00后的BASIC。据我观察,这本书是众多70后和80后教孩子编程的优选图书,也是很多家长自己学Python编程的开始。”

——爱编程的魏校长,知名教育博主

“这本书用Python语言教你如何写程序,是一本老少咸宜的编程书。”

——左耳朵耗子(陈皓)

“近年来少儿编程非常火爆。如果你是一位‘码农’家长,不如发挥自己的专长,做孩子的启蒙老师和学习伙伴,这本书就是很棒的‘亲子编程学习实践手册’。”

——周自恒,公众号“周花卷”主理人


购书传送门

文末提示:随书附赠无毒安装程序,一键式安装Python 3及Pygame模块,并获取本书所有游戏代码。请在桌面端单击“阅读原文”,下载随书资源。


转载:https://blog.csdn.net/turingbooks/article/details/110602251
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场