2023年 3月 19日

python-pygame与pymunk-台球游戏

大家好,我是涵子。今天我为大家带来pygame-pymunk的台球游戏!

友情提醒:

如果不认识pymunk的同学可以去看看之前的文章:

python-编程宇宙-计算机网络的宇宙希望大家可以更加了解pymunk!


目录

 一、前面准备

二、中间程序

 三、最后程序

四、效果图

五、完整代码

六、总结


 一、前面准备

和之前一样,就是加了一个pymunk和一些变量:

  1. # -coding utf-8 -
  2. # import pygame, pymunk and sys
  3. import pygame as pg
  4. import pymunk as pm
  5. import sys
  6. # init program
  7. pg.init()
  8. # set screen
  9. screen = pg.display.set_mode((800, 500)) # cannot change the size of the screen
  10. # set title
  11. pg.display.set_caption("Billiards", "4.0")
  12. # pymunk Space
  13. space = pm.Space()
  14. # gravity
  15. # gravity and speed
  16. space.gravity = (0, 0) # gravity = 0
  17. # colors for draw
  18. white = (236, 240, 241) # white
  19. gray = (123, 125, 125) # gray
  20. stage = (51, 51, 51) # stage
  21. points = [""] * 16 # particleBalls
  22. balls = [""] * 16 # rigid bodies
  23. y = 0 # Ypos
  24. x = 0 # Xpos
  25. n = 5 # create n
  26. # colors, use for balls
  27. colors = ["yellow", "blue", "red", "purple", "orange", "green", "brown", "black",
  28. "yellow", "blue", "red", "purple", "orange", "green", "brown","white"]

pymunk.sapce和gravity是啥?没事,我们来看看:

这就是用pymunk做的一个程序。之前的文章里有代码。

space就是指一个空间,gravity就是重力。我们不需要重力。

二、中间程序

  1. # def draw
  2. def draw():
  3. # screen fill
  4. screen.fill(white)
  5. # draw stage
  6. pg.draw.line(screen, gray, (0, 250), (800, 250), 500)
  7. pg.draw.line(screen, stage, (20, 250), (780, 250), 460)
  8. # draw a ball in the pygame, pos is the points' and balls'
  9. # make the ball has gravity
  10. # show the ball
  11. # use range
  12. for i in range(16):
  13. # if it appears, then--
  14. # if it doesn't, don't draw it, or system wrong
  15. if points[i]:
  16. # --draw circle
  17. pg.draw.circle(screen, colors[i], points[i].position, 10)
  18. # update space, can change ball's position
  19. space.step(0.2) # use space.step
  20. # create holes this list
  21. holes = [(20,20),(400,20),(780,20),(20,480),(400,480),(780,480)]
  22. # def drawHole
  23. def drawHole():
  24. # use loop
  25. for h in holes:
  26. # draw circle
  27. pg.draw.circle(screen,'gray',h,20)
  28. # def dis
  29. def dis():
  30. # global first
  31. global points,balls
  32. # use loop
  33. for i,p in enumerate(points):
  34. # check pos
  35. for h in holes:
  36. # check
  37. if p and (p.position[0]-h[0])**2+(p.position[1]-h[1])**2<400:
  38. # make the ball disappear
  39. points[i] = ""
  40. balls[i] = ""
  41. # def friction
  42. def friction():
  43. # make the balls speed be slower and slower
  44. # global first!
  45. global points
  46. for v in points:
  47. # if v is appear
  48. if v:
  49. # then make the speed slower
  50. v.velocity *= 0.99
  51. # def cue
  52. def cue():
  53. # get white ball speed(velocity)
  54. # it is a little bit difficult
  55. # if abs(speed) < 0.1, the do next
  56. # because of there will have -num, so we need abs!
  57. # first need loop!
  58. # staticflag
  59. staticFlag = 1
  60. for i in points:
  61. # check
  62. # switch thinking is on again!
  63. if i and (abs(i.velocity[0]) > 0.1 or abs(i.velocity[1]) > 0.1):
  64. # there's a ball is running!
  65. staticFlag = 0
  66. # then check
  67. if points[15] and staticFlag == 1:
  68. # get pos
  69. mPos = pg.mouse.get_pos()
  70. # draw cue
  71. pg.draw.line(screen,(249,231,159),points[15].position,mPos,5)
  72. # get if pressed
  73. if pg.mouse.get_pressed()[0]:
  74. # move ball and cue, and boom!
  75. # wallop!
  76. points[15].apply_impulse_at_local_point(((points[15].position[0]-mPos[0]),(points[15].position[1]-mPos[1])),(0,0))
  77. # create balls
  78. # def create
  79. def create():
  80. # global first, or system error
  81. global points,balls
  82. # create y, x, n
  83. y = 0
  84. x = 0
  85. n = 5
  86. # create balls of particle balls and rigid bodies
  87. for i in range(15):
  88. # creat particle balls and rigid bodies
  89. points[i] = pm.Body(1,2000)
  90. points[i].position = 150+x,250+y-n*10
  91. balls[i] = pm.Circle(points[i],10)
  92. # elasticity
  93. balls[i].elasticity = 0.95
  94. space.add(points[i],balls[i])
  95. y+=20
  96. # check pos
  97. if y>=20*n:
  98. # change y
  99. y = 0
  100. # change x
  101. x +=20
  102. # chang n
  103. n-=1
  104. # create white ball
  105. points[15] = pm.Body(1,2000)
  106. points[15].position = 450,250
  107. balls[15] = pm.Circle(points[15],10)
  108. balls[15].elasticity = 0.95
  109. space.add(points[15],balls[15])
  110. # def wall
  111. def wall():
  112. # create a wall
  113. # it umm... difficult, not very easy for everyone
  114. # it just like a air wall
  115. # put these static_body wall into a list
  116. lines = [
  117. pm.Segment(space.static_body,(10,10),(790,10),20),
  118. pm.Segment(space.static_body,(10,10),(10,490),20),
  119. pm.Segment(space.static_body,(790,10),(790,490),20),
  120. pm.Segment(space.static_body,(10,490),(790,490),20)
  121. ]
  122. # use range to check lines
  123. for line in lines:
  124. # elasticity
  125. line.elasticity = 1
  126. # friction
  127. line.friction = 0.9
  128. space.add(*lines) # add lines

额,好长是不?

 没事,我慢慢讲。(此时我已经开始颤抖)

注释里有,自己去翻译吧!

首先,遇到的问题就是画画。

  1. # def draw
  2. def draw():
  3. # screen fill
  4. screen.fill(white)
  5. # draw stage
  6. pg.draw.line(screen, gray, (0, 250), (800, 250), 500)
  7. pg.draw.line(screen, stage, (20, 250), (780, 250), 460)
  8. # draw a ball in the pygame, pos is the points' and balls'
  9. # make the ball has gravity
  10. # show the ball
  11. # use range
  12. for i in range(16):
  13. # if it appears, then--
  14. # if it doesn't, don't draw it, or system wrong
  15. if points[i]:
  16. # --draw circle
  17. pg.draw.circle(screen, colors[i], points[i].position, 10)
  18. # update space, can change ball's position
  19. space.step(0.2) # use space.step

首先画好外面的边框,填满里面的颜色,然后再画出里面的球(后面的程序衔接上这个函数)。可是有一个问题,为什么要有if points[i],你想想,要是球掉洞里了还会出现吗?

然后面临的问题是画洞和判断球进去了没。

  1. # create holes this list
  2. holes = [(20,20),(400,20),(780,20),(20,480),(400,480),(780,480)]
  3. # def drawHole
  4. def drawHole():
  5. # use loop
  6. for h in holes:
  7. # draw circle
  8. pg.draw.circle(screen,'gray',h,20)
  9. # def dis
  10. def dis():
  11. # global first
  12. global points,balls
  13. # use loop
  14. for i,p in enumerate(points):
  15. # check pos
  16. for h in holes:
  17. # check
  18. if p and (p.position[0]-h[0])**2+(p.position[1]-h[1])**2<400:
  19. # make the ball disappear
  20. points[i] = ""
  21. balls[i] = ""

这里用到了enumerate,额,有难了点哈。

想让球消失,那就把i索引的东西删掉(就是变成一个空字符串)

下面就是噩梦了!(苦痛之路)

  1. # def friction
  2. def friction():
  3. # make the balls speed be slower and slower
  4. # global first!
  5. global points
  6. for v in points:
  7. # if v is appear
  8. if v:
  9. # then make the speed slower
  10. v.velocity *= 0.99
  11. # def cue
  12. def cue():
  13. # get white ball speed(velocity)
  14. # it is a little bit difficult
  15. # if abs(speed) < 0.1, the do next
  16. # because of there will have -num, so we need abs!
  17. # first need loop!
  18. # staticflag
  19. staticFlag = 1
  20. for i in points:
  21. # check
  22. # switch thinking is on again!
  23. if i and (abs(i.velocity[0]) > 0.1 or abs(i.velocity[1]) > 0.1):
  24. # there's a ball is running!
  25. staticFlag = 0
  26. # then check
  27. if points[15] and staticFlag == 1:
  28. # get pos
  29. mPos = pg.mouse.get_pos()
  30. # draw cue
  31. pg.draw.line(screen,(249,231,159),points[15].position,mPos,5)
  32. # get if pressed
  33. if pg.mouse.get_pressed()[0]:
  34. # move ball and cue, and boom!
  35. # wallop!
  36. points[15].apply_impulse_at_local_point(((points[15].position[0]-mPos[0]),(points[15].position[1]-mPos[1])),(0,0))
  37. # create balls
  38. # def create
  39. def create():
  40. # global first, or system error
  41. global points,balls
  42. # create y, x, n
  43. y = 0
  44. x = 0
  45. n = 5
  46. # create balls of particle balls and rigid bodies
  47. for i in range(15):
  48. # creat particle balls and rigid bodies
  49. points[i] = pm.Body(1,2000)
  50. points[i].position = 150+x,250+y-n*10
  51. balls[i] = pm.Circle(points[i],10)
  52. # elasticity
  53. balls[i].elasticity = 0.95
  54. space.add(points[i],balls[i])
  55. y+=20
  56. # check pos
  57. if y>=20*n:
  58. # change y
  59. y = 0
  60. # change x
  61. x +=20
  62. # chang n
  63. n-=1
  64. # create white ball
  65. points[15] = pm.Body(1,2000)
  66. points[15].position = 450,250
  67. balls[15] = pm.Circle(points[15],10)
  68. balls[15].elasticity = 0.95
  69. space.add(points[15],balls[15])
  70. # def wall
  71. def wall():
  72. # create a wall
  73. # it umm... difficult, not very easy for everyone
  74. # it just like a air wall
  75. # put these static_body wall into a list
  76. lines = [
  77. pm.Segment(space.static_body,(10,10),(790,10),20),
  78. pm.Segment(space.static_body,(10,10),(10,490),20),
  79. pm.Segment(space.static_body,(790,10),(790,490),20),
  80. pm.Segment(space.static_body,(10,490),(790,490),20)
  81. ]
  82. # use range to check lines
  83. for line in lines:
  84. # elasticity
  85. line.elasticity = 1
  86. # friction
  87. line.friction = 0.9
  88. space.add(*lines) # add lines

包含了摩擦力,球杆控制和墙体的定义。

看到了这里,还不点个赞?(非强迫,喜欢就点)

接下来就是干货!(此时要有bgm响起!)

和之前一样用循环遍历所有球,如果有球就减速。没有的话就跳过。接下来$%!)@(*#@$(*&

算了,我已经看见了你们满脸的疑惑。来,我还是慢慢来吧!

这里又一次运用到了开关思维。实在不行的同学直接跳过。到达最后的完整代码就可以了。

太难了是不?

接下来就是用上质点和刚体组成现实(游戏)中的球。相当于用pymunk做出原子核,用pygame泼油漆,做模型。 

后面用segment和列表把墙体加入游戏。

后面就是结尾了!

 三、最后程序

  1. # use wall
  2. wall()
  3. # create balls before loop, or boom, or system wrong
  4. create()
  5. # check fps and events
  6. fps = pg.time.Clock()
  7. while True:
  8. # tick fps
  9. fps.tick(60)
  10. # quit events
  11. event = pg.event.poll()
  12. if event.type==pg.QUIT:
  13. pg.quit()
  14. sys.exit()
  15. exit()
  16. # main program
  17. dis()
  18. draw()
  19. friction()
  20. cue()
  21. drawHole()
  22. # display program
  23. pg.display.update()

好像平平无奇是吗?挺简单的是吗?额,的确是的。

就是调用函数,检查程序退出。

四、效果图

 牛皮吧?

五、完整代码

附上完整代码:

  1. # -coding utf-8 -
  2. # import pygame, pymunk and sys
  3. import pygame as pg
  4. import pymunk as pm
  5. import sys
  6. # init program
  7. pg.init()
  8. # set screen
  9. screen = pg.display.set_mode((800, 500)) # cannot change the size of the screen
  10. # set title
  11. pg.display.set_caption("Billiards", "4.0")
  12. # pymunk Space
  13. space = pm.Space()
  14. # gravity
  15. # gravity and speed
  16. space.gravity = (0, 0) # gravity = 0
  17. # colors for draw
  18. white = (236, 240, 241) # white
  19. gray = (123, 125, 125) # gray
  20. stage = (51, 51, 51) # stage
  21. points = [""] * 16 # particleBalls
  22. balls = [""] * 16 # rigid bodies
  23. y = 0 # Ypos
  24. x = 0 # Xpos
  25. n = 5 # create n
  26. # colors, use for balls
  27. colors = ["yellow", "blue", "red", "purple", "orange", "green", "brown", "black",
  28. "yellow", "blue", "red", "purple", "orange", "green", "brown","white"]
  29. # def draw
  30. def draw():
  31. # screen fill
  32. screen.fill(white)
  33. # draw stage
  34. pg.draw.line(screen, gray, (0, 250), (800, 250), 500)
  35. pg.draw.line(screen, stage, (20, 250), (780, 250), 460)
  36. # draw a ball in the pygame, pos is the points' and balls'
  37. # make the ball has gravity
  38. # show the ball
  39. # use range
  40. for i in range(16):
  41. # if it appears, then--
  42. # if it doesn't, don't draw it, or system wrong
  43. if points[i]:
  44. # --draw circle
  45. pg.draw.circle(screen, colors[i], points[i].position, 10)
  46. # update space, can change ball's position
  47. space.step(0.2) # use space.step
  48. # create holes this list
  49. holes = [(20,20),(400,20),(780,20),(20,480),(400,480),(780,480)]
  50. # def drawHole
  51. def drawHole():
  52. # use loop
  53. for h in holes:
  54. # draw circle
  55. pg.draw.circle(screen,'gray',h,20)
  56. # def dis
  57. def dis():
  58. # global first
  59. global points,balls
  60. # use loop
  61. for i,p in enumerate(points):
  62. # check pos
  63. for h in holes:
  64. # check
  65. if p and (p.position[0]-h[0])**2+(p.position[1]-h[1])**2<400:
  66. # make the ball disappear
  67. points[i] = ""
  68. balls[i] = ""
  69. # def friction
  70. def friction():
  71. # make the balls speed be slower and slower
  72. # global first!
  73. global points
  74. for v in points:
  75. # if v is appear
  76. if v:
  77. # then make the speed slower
  78. v.velocity *= 0.99
  79. # def cue
  80. def cue():
  81. # get white ball speed(velocity)
  82. # it is a little bit difficult
  83. # if abs(speed) < 0.1, the do next
  84. # because of there will have -num, so we need abs!
  85. # first need loop!
  86. # staticflag
  87. staticFlag = 1
  88. for i in points:
  89. # check
  90. # switch thinking is on again!
  91. if i and (abs(i.velocity[0]) > 0.1 or abs(i.velocity[1]) > 0.1):
  92. # there's a ball is running!
  93. staticFlag = 0
  94. # then check
  95. if points[15] and staticFlag == 1:
  96. # get pos
  97. mPos = pg.mouse.get_pos()
  98. # draw cue
  99. pg.draw.line(screen,(249,231,159),points[15].position,mPos,5)
  100. # get if pressed
  101. if pg.mouse.get_pressed()[0]:
  102. # move ball and cue, and boom!
  103. # wallop!
  104. points[15].apply_impulse_at_local_point(((points[15].position[0]-mPos[0]),(points[15].position[1]-mPos[1])),(0,0))
  105. # create balls
  106. # def create
  107. def create():
  108. # global first, or system error
  109. global points,balls
  110. # create y, x, n
  111. y = 0
  112. x = 0
  113. n = 5
  114. # create balls of particle balls and rigid bodies
  115. for i in range(15):
  116. # creat particle balls and rigid bodies
  117. points[i] = pm.Body(1,2000)
  118. points[i].position = 150+x,250+y-n*10
  119. balls[i] = pm.Circle(points[i],10)
  120. # elasticity
  121. balls[i].elasticity = 0.95
  122. space.add(points[i],balls[i])
  123. y+=20
  124. # check pos
  125. if y>=20*n:
  126. # change y
  127. y = 0
  128. # change x
  129. x +=20
  130. # chang n
  131. n-=1
  132. # create white ball
  133. points[15] = pm.Body(1,2000)
  134. points[15].position = 450,250
  135. balls[15] = pm.Circle(points[15],10)
  136. balls[15].elasticity = 0.95
  137. space.add(points[15],balls[15])
  138. # def wall
  139. def wall():
  140. # create a wall
  141. # it umm... difficult, not very easy for everyone
  142. # it just like a air wall
  143. # put these static_body wall into a list
  144. lines = [
  145. pm.Segment(space.static_body,(10,10),(790,10),20),
  146. pm.Segment(space.static_body,(10,10),(10,490),20),
  147. pm.Segment(space.static_body,(790,10),(790,490),20),
  148. pm.Segment(space.static_body,(10,490),(790,490),20)
  149. ]
  150. # use range to check lines
  151. for line in lines:
  152. # elasticity
  153. line.elasticity = 1
  154. # friction
  155. line.friction = 0.9
  156. space.add(*lines) # add lines
  157. # use wall
  158. wall()
  159. # create balls before loop, or boom, or system wrong
  160. create()
  161. # check fps and events
  162. fps = pg.time.Clock()
  163. while True:
  164. # tick fps
  165. fps.tick(60)
  166. # quit events
  167. event = pg.event.poll()
  168. if event.type==pg.QUIT:
  169. pg.quit()
  170. sys.exit()
  171. exit()
  172. # main program
  173. dis()
  174. draw()
  175. friction()
  176. cue()
  177. drawHole()
  178. # display program
  179. pg.display.update()

六、总结

通过这次学习和实践,我们更加了解了pymunk和pygame,认识到了python的强大。

最后,我希望大家:点个赞!关注一下。

我将持续更新关于编程的优质文章。希望大家可以和我一起学习知识,一起领略知识的力量!