square.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. import pygame
  2. import math
  3. import random
  4. from pygame.locals import *
  5. from OpenGL.GL import *
  6. from OpenGL.GLU import *
  7. # 初始化Pygame和OpenGL
  8. pygame.init()
  9. # 设置窗口大小
  10. WIDTH, HEIGHT = 800, 800
  11. screen = pygame.display.set_mode((WIDTH, HEIGHT), DOUBLEBUF | OPENGL)
  12. pygame.display.set_caption("3D立方体容器 - 透明立方体")
  13. # 设置OpenGL视角
  14. gluPerspective(45, (WIDTH / HEIGHT), 0.1, 50.0)
  15. glTranslatef(0.0, 0.0, -5)
  16. # 启用深度测试和混合
  17. glEnable(GL_DEPTH_TEST)
  18. glEnable(GL_BLEND)
  19. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
  20. class Cube:
  21. def __init__(self, x, y, z, size, color):
  22. self.x = x
  23. self.y = y
  24. self.z = z
  25. self.size = size
  26. self.color = color
  27. self.rotation_x = 0
  28. self.rotation_y = 0
  29. self.rotation_z = 0
  30. self.vx = random.uniform(-0.01, 0.01)
  31. self.vy = random.uniform(-0.01, 0.01)
  32. self.vz = random.uniform(-0.01, 0.01)
  33. def move(self, container_size):
  34. # 更新位置
  35. self.x += self.vx
  36. self.y += self.vy
  37. self.z += self.vz
  38. # 检查与大立方体边界的碰撞
  39. half_size = container_size / 2
  40. cube_half = self.size / 2
  41. if abs(self.x) + cube_half > half_size:
  42. self.x = (half_size - cube_half) * (1 if self.x >= 0 else -1)
  43. self.vx *= -1
  44. if abs(self.y) + cube_half > half_size:
  45. self.y = (half_size - cube_half) * (1 if self.y >= 0 else -1)
  46. self.vy *= -1
  47. if abs(self.z) + cube_half > half_size:
  48. self.z = (half_size - cube_half) * (1 if self.z >= 0 else -1)
  49. self.vz *= -1
  50. def draw(self):
  51. glPushMatrix()
  52. glColor4f(self.color[0], self.color[1], self.color[2], self.color[3]) # 包含透明度
  53. glTranslatef(self.x, self.y, self.z)
  54. glRotatef(self.rotation_x, 1, 0, 0)
  55. glRotatef(self.rotation_y, 0, 1, 0)
  56. glRotatef(self.rotation_z, 0, 0, 1)
  57. # 绘制立方体
  58. half_size = self.size / 2
  59. vertices = (
  60. (half_size, -half_size, -half_size),
  61. (half_size, half_size, -half_size),
  62. (-half_size, half_size, -half_size),
  63. (-half_size, -half_size, -half_size),
  64. (half_size, -half_size, half_size),
  65. (half_size, half_size, half_size),
  66. (-half_size, -half_size, half_size),
  67. (-half_size, half_size, half_size)
  68. )
  69. edges = (
  70. (0,1), (1,2), (2,3), (3,0), # 底面
  71. (4,5), (5,7), (7,6), (6,4), # 顶面
  72. (0,4), (1,5), (2,7), (3,6) # 连接边
  73. )
  74. glBegin(GL_LINES)
  75. for edge in edges:
  76. for vertex in edge:
  77. glVertex3fv(vertices[vertex])
  78. glEnd()
  79. # 绘制面以增加立体感
  80. faces = (
  81. (0,1,2,3), # 底面
  82. (4,5,7,6), # 顶面
  83. (0,1,5,4), # 前面
  84. (2,3,6,7), # 后面
  85. (0,3,6,4), # 左面
  86. (1,2,7,5) # 右面
  87. )
  88. glBegin(GL_QUADS)
  89. for face in faces:
  90. for vertex in face:
  91. glVertex3fv(vertices[vertex])
  92. glEnd()
  93. glPopMatrix()
  94. def draw_container_cube(size):
  95. glColor4f(1.0, 1.0, 1.0, 0.1) # 白色,10% alpha (90% 透明度)
  96. half_size = size / 2
  97. vertices = (
  98. (half_size, -half_size, -half_size),
  99. (half_size, half_size, -half_size),
  100. (-half_size, half_size, -half_size),
  101. (-half_size, -half_size, -half_size),
  102. (half_size, -half_size, half_size),
  103. (half_size, half_size, half_size),
  104. (-half_size, -half_size, half_size),
  105. (-half_size, half_size, half_size)
  106. )
  107. edges = (
  108. (0,1), (1,2), (2,3), (3,0), # 底面
  109. (4,5), (5,7), (7,6), (6,4), # 顶面
  110. (0,4), (1,5), (2,7), (3,6) # 连接边
  111. )
  112. glBegin(GL_LINES)
  113. for edge in edges:
  114. for vertex in edge:
  115. glVertex3fv(vertices[vertex])
  116. glEnd()
  117. # 绘制面以增加立体感
  118. faces = (
  119. (0,1,2,3), # 底面
  120. (4,5,7,6), # 顶面
  121. (0,1,5,4), # 前面
  122. (2,3,6,7), # 后面
  123. (0,3,6,4), # 左面
  124. (1,2,7,5) # 右面
  125. )
  126. glBegin(GL_QUADS)
  127. for face in faces:
  128. for vertex in face:
  129. glVertex3fv(vertices[vertex])
  130. glEnd()
  131. def check_collision(cube1, cube2):
  132. # 简单的边界框碰撞检测
  133. half_size1 = cube1.size / 2
  134. half_size2 = cube2.size / 2
  135. # 检查各轴是否有重叠
  136. x_overlap = abs(cube1.x - cube2.x) < (half_size1 + half_size2)
  137. y_overlap = abs(cube1.y - cube2.y) < (half_size1 + half_size2)
  138. z_overlap = abs(cube1.z - cube2.z) < (half_size1 + half_size2)
  139. if x_overlap and y_overlap and z_overlap:
  140. # 发生碰撞,交换速度分量
  141. cube1.vx, cube2.vx = cube2.vx, cube1.vx
  142. cube1.vy, cube2.vy = cube2.vy, cube1.vy
  143. cube1.vz, cube2.vz = cube2.vz, cube1.vz
  144. # 分离立方体以避免重叠
  145. min_dist = half_size1 + half_size2
  146. dist_x = abs(cube1.x - cube2.x)
  147. dist_y = abs(cube1.y - cube2.y)
  148. dist_z = abs(cube1.z - cube2.z)
  149. if dist_x < dist_y and dist_x < dist_z:
  150. # X轴方向分离
  151. sign = 1 if cube1.x < cube2.x else -1
  152. cube1.x -= sign * (min_dist - dist_x) / 2
  153. cube2.x += sign * (min_dist - dist_x) / 2
  154. elif dist_y < dist_z:
  155. # Y轴方向分离
  156. sign = 1 if cube1.y < cube2.y else -1
  157. cube1.y -= sign * (min_dist - dist_y) / 2
  158. cube2.y += sign * (min_dist - dist_y) / 2
  159. else:
  160. # Z轴方向分离
  161. sign = 1 if cube1.z < cube2.z else -1
  162. cube1.z -= sign * (min_dist - dist_z) / 2
  163. cube2.z += sign * (min_dist - dist_z) / 2
  164. def main():
  165. clock = pygame.time.Clock()
  166. # 大立方体参数
  167. container_size = 3.0
  168. # 创建3个小立方体
  169. cubes = []
  170. cube_size = 0.4 # 小立方体尺寸
  171. # 随机生成小立方体的位置,确保它们不重叠
  172. for i in range(3):
  173. placed = False
  174. attempts = 0
  175. while not placed and attempts < 1000:
  176. # 在大立方体内部随机选择一个位置
  177. half_container = container_size / 2 - cube_size / 2
  178. x = random.uniform(-half_container, half_container)
  179. y = random.uniform(-half_container, half_container)
  180. z = random.uniform(-half_container, half_container)
  181. # 检查是否与其他立方体重叠
  182. valid_position = True
  183. for other_cube in cubes:
  184. dx = x - other_cube.x
  185. dy = y - other_cube.y
  186. dz = z - other_cube.z
  187. distance = math.sqrt(dx**2 + dy**2 + dz**2)
  188. min_distance = cube_size # 最小安全距离
  189. if distance < min_distance:
  190. valid_position = False
  191. break
  192. if valid_position:
  193. # 白色,90% 透明度
  194. cubes.append(Cube(x, y, z, cube_size, (1.0, 1.0, 1.0, 0.1)))
  195. placed = True
  196. attempts += 1
  197. if not placed:
  198. print(f"无法放置第 {i+1} 个小立方体,可能空间不足")
  199. break
  200. rotation_x = 0
  201. rotation_y = 0
  202. drag = False
  203. last_pos = (0, 0)
  204. running = True
  205. while running:
  206. for event in pygame.event.get():
  207. if event.type == pygame.QUIT:
  208. running = False
  209. elif event.type == pygame.KEYDOWN:
  210. if event.key == pygame.K_ESCAPE:
  211. running = False
  212. elif event.type == pygame.MOUSEBUTTONDOWN:
  213. if event.button == 1: # 左键按下
  214. drag = True
  215. last_pos = event.pos
  216. elif event.type == pygame.MOUSEBUTTONUP:
  217. if event.button == 1: # 左键释放
  218. drag = False
  219. elif event.type == pygame.MOUSEMOTION:
  220. if drag:
  221. dx = event.pos[0] - last_pos[0]
  222. dy = event.pos[1] - last_pos[1]
  223. rotation_y += dx * 0.5
  224. rotation_x += dy * 0.5
  225. last_pos = event.pos
  226. # 清除屏幕和深度缓冲区
  227. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
  228. # 应用旋转
  229. glPushMatrix()
  230. glRotatef(rotation_x, 1, 0, 0)
  231. glRotatef(rotation_y, 0, 1, 0)
  232. # 绘制大立方体容器
  233. draw_container_cube(container_size)
  234. # 移动所有小立方体并检查边界碰撞
  235. for cube in cubes:
  236. cube.move(container_size)
  237. # 更新旋转
  238. cube.rotation_x += 0.5
  239. cube.rotation_y += 0.3
  240. cube.rotation_z += 0.2
  241. # 检查小立方体之间的碰撞
  242. for i in range(len(cubes)):
  243. for j in range(i + 1, len(cubes)):
  244. check_collision(cubes[i], cubes[j])
  245. # 绘制所有小立方体
  246. for cube in cubes:
  247. cube.draw()
  248. glPopMatrix()
  249. pygame.display.flip()
  250. clock.tick(60)
  251. pygame.quit()
  252. if __name__ == "__main__":
  253. main()