main.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. import matplotlib.pyplot as plt
  2. import pygame
  3. import pygame.draw as draw
  4. import math
  5. from time import sleep
  6. pygame.init() # 初始化
  7. display = pygame.display
  8. screen = display.set_mode((640, 480), 0, 32)
  9. display.set_caption("物理: 弹簧实验")
  10. fontObj = pygame.font.Font('ZKST.ttf', 48) # 通过字体文件获得字体对象
  11. fontObj2 = pygame.font.Font('ZKST.ttf', 20) # 通过字体文件获得字体对象
  12. text_M = fontObj.render('M', True, (100, 255, 255)) # 配置要显示的文字
  13. v_list = [] # v-t图像的v
  14. t_list = [] # v-t图像和s-t图像的t
  15. s_list = [] # s-t图像的s
  16. dh_list = [] # dh-t图像的dh
  17. a_list = [] # a-t图像的a
  18. g = 9.8 # 重力加速度
  19. k = 0.4 # 弹簧劲度系数
  20. v = 0 # 物体速度
  21. m = 1 # 物体质量
  22. F = 0 # 物体受力
  23. h = 0 # 物体距离原来高度位置(弹簧伸缩量)
  24. gh = 8 # 距离弹簧对高度
  25. times = 0
  26. get_g = lambda m: g * m # 获取重力(重力方向为正方向)
  27. get_n = lambda h: 0 if h < gh else k * (h - gh) # 计算弹力
  28. get_f = lambda f1, f2: f1 + f2 # 计算力
  29. get_a = lambda f, m: f / m # 计算加速度
  30. get_v = lambda v, a, t: v + a * t # 计算速度
  31. get_s = lambda v, a, t: v * t + 0.5 * a * t ** 2 # 计算位移
  32. to_ypos = lambda y: int((y / 100) * 470 + 30) # 100是虚拟环境的高度,470是画布高度, 10是向下偏移
  33. time = 0.001
  34. now_draw = 0
  35. def sin(): # get sin
  36. a = 0
  37. for i in range(100):
  38. yield math.sin(a), a
  39. a += 1
  40. def draw_font(x, y, text, screen):
  41. tmp_text = fontObj2.render(text, True, (0, 0, 0)) # 配置要显示的文字
  42. tmp = tmp_text.get_rect() # 获得要显示的对象的rect
  43. tmp.center = (x, y) # 设置显示对象的坐标
  44. screen.blit(tmp_text, tmp) # 绘制字体
  45. def draw_(screen, display, h, v, a, n, mg, f, time): # 绘制受力分析图
  46. mh = 50
  47. mw = 60
  48. # 清空
  49. screen.fill((255, 255, 255))
  50. pygame.draw.line(screen, (0, 0, 0), (0, to_ypos(0)), (640, to_ypos(0)), 2) # 绘制最高线h
  51. pygame.draw.line(screen, (0, 0, 0), (0, to_ypos(h)), (640, to_ypos(h)), 1) # 绘制物体高度线:h
  52. draw_font(590, to_ypos(h) + 12, f'h = {h:4.2f}m', screen)
  53. draw_font(640 // 2, to_ypos(h) - 12, f'v = {v:4.2f}m/s, a = {a:4.2f}m/s^2', screen)
  54. pygame.draw.rect(screen, (0, 0, 0), (int(640 / 2 - mw / 2), to_ypos(h), mw, mh), 0)
  55. tmp = text_M.get_rect() # 获得要显示的对象的rect
  56. tmp.center = (640 // 2, to_ypos(h) + mh // 2) # 设置显示对象的坐标
  57. screen.blit(text_M, tmp) # 绘制字体
  58. if h > gh:
  59. max_h = h
  60. else:
  61. max_h = gh
  62. point_list = []
  63. for i in sin():
  64. x = int(i[0] / 2 * mw / 2 + (640 / 2 - 10) + mw / 8) # 换算, + mw / 8是让弹簧居中
  65. y = int(i[1] / 100 * (400 - to_ypos(max_h) - mh) + to_ypos(max_h) + mh) # 换算
  66. point_list.append((x, y))
  67. pygame.draw.lines(screen, (min(max_h / 60 * 255, 255), 0, 0), False, point_list, 2) # 绘制最高线h
  68. x = 60
  69. base_y = 270
  70. pygame.draw.circle(screen, (0, 0, 255), (x, base_y), 5)
  71. y = int(base_y + (mg / 20 * 150))
  72. pygame.draw.line(screen, (0, 0, 0), (x, base_y), (x, y), 3) # 绘制mg
  73. pygame.draw.lines(screen, (0, 0, 0), False, [(x - 5, y - 5), (x, y), (x + 5, y - 5)], 3)
  74. draw_font(x, y + 12, f'mg = {mg:4.2f}N', screen)
  75. if n < 0:
  76. y = int(base_y + (n / 20 * 150))
  77. pygame.draw.line(screen, (0, 0, 0), (x, base_y), (x, y), 3) # 绘制n
  78. pygame.draw.lines(screen, (0, 0, 0), False, [(x - 5, y + 5), (x, y), (x + 5, y + 5)], 3)
  79. draw_font(x, y - 12, f'N = {-n:4.2f}N', screen)
  80. else:
  81. draw_font(x, base_y - 12, f'N = 0N', screen)
  82. y = int(base_y + (f / 20 * 150))
  83. pygame.draw.line(screen, (250, 0, 0), (x, base_y), (x, base_y + int(f / 20 * 150)), 3) # 绘制最高线h
  84. pygame.draw.lines(screen, (0, 0, 0), False, [(x - 5, (y + 5) if f < 0 else (y - 5)), (x, y),
  85. (x + 5, (y + 5) if f < 0 else (y - 5))], 3)
  86. draw_font(x + x, y - 5, f'F = {f:4.2f}N', screen)
  87. draw_font(320, 440 - 12, f'time = {time:4.2f}s, g = {g}m/s^2, m(M) = {m}kg, k = {k}', screen)
  88. draw_font(320, 460 - 12, f'power by SuperHuan (https://www.songzh.website)', screen)
  89. display.update()
  90. # pygame.draw.rect(screen, (0, 0, 0), (5, a, 50, 50), 0)
  91. def is_quit():
  92. for event in pygame.event.get():
  93. if event.type == pygame.QUIT:
  94. return False
  95. elif event.type == pygame.KEYDOWN and event.key == pygame.K_g:
  96. get_new()
  97. return True
  98. def get_new(): # 获取新的数据
  99. try:
  100. type = int(input('''1)重力加速度g
  101. 2)劲度系数k
  102. 3)M的质量
  103. Please Enter The Number: '''))
  104. n = int(input("Please Enter The New Value: "))
  105. except ValueError:
  106. return False
  107. if type == 1:
  108. global g
  109. g = n
  110. elif type == 2:
  111. global k
  112. k = n
  113. elif type == 3:
  114. global m
  115. m = n
  116. return True
  117. if __name__ == "__main__":
  118. try:
  119. while is_quit():
  120. the_g = get_g(m)
  121. the_n = -get_n(h) # 重力方向为正方向
  122. the_f = get_f(the_n, the_g)
  123. the_a = get_a(the_f, m) # 获取当前的加速度
  124. times += time
  125. dh = get_s(v, the_a, time) # 计算位移增量
  126. new_v = get_v(v, the_a, time)
  127. if now_draw == 30:
  128. draw_(screen, display, h, v, the_a, the_n, the_g, the_f, times)
  129. now_draw = 0
  130. else:
  131. sleep(time)
  132. now_draw += 1
  133. v_list.append(v)
  134. s_list.append(dh + h)
  135. dh_list.append(dh)
  136. t_list.append(times)
  137. a_list.append(the_a)
  138. v = new_v
  139. h += dh
  140. plt.figure()
  141. size = (3, 2)
  142. dh_t = plt.subplot2grid(size, (0, 0), colspan=1, rowspan=1)
  143. s_t = plt.subplot2grid(size, (0, 1), colspan=1, rowspan=1)
  144. v_t = plt.subplot2grid(size, (1, 0), colspan=2, rowspan=1)
  145. a_t = plt.subplot2grid(size, (2, 0), colspan=2, rowspan=1)
  146. def set_plot(plot, title, ylabel, xlabel, line, y_list, x_list):
  147. plot.set_title(title)
  148. plot.set_ylabel(ylabel)
  149. plot.set_xlabel(xlabel)
  150. plot.plot(x_list, y_list, line, label=title)
  151. set_plot(v_t, 'v-t', 'v(m/s)', 't(s)', 'r', v_list, t_list)
  152. set_plot(s_t, 'h-t', 'h(m)', 't(s)', 'b', s_list, t_list)
  153. set_plot(dh_t, f'dh-t(dt = {time}s)', 'dh(m)', 't(s)', 'y', dh_list, t_list)
  154. set_plot(a_t, 'a-t', 'a(m/s^2)', 't(s)', 'g', a_list, t_list)
  155. v_t.grid()
  156. s_t.grid()
  157. dh_t.grid()
  158. a_t.grid()
  159. plt.show()
  160. except KeyboardInterrupt:
  161. pass
  162. print("Bye Bye(power by SuperHuan)!")