import pygame import math import random from pygame.locals import * from OpenGL.GL import * from OpenGL.GLU import * # 初始化Pygame和OpenGL pygame.init() # 设置窗口大小 WIDTH, HEIGHT = 800, 800 screen = pygame.display.set_mode((WIDTH, HEIGHT), DOUBLEBUF | OPENGL) pygame.display.set_caption("3D立方体容器 - 透明立方体") # 设置OpenGL视角 gluPerspective(45, (WIDTH / HEIGHT), 0.1, 50.0) glTranslatef(0.0, 0.0, -5) # 启用深度测试和混合 glEnable(GL_DEPTH_TEST) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) class Cube: def __init__(self, x, y, z, size, color): self.x = x self.y = y self.z = z self.size = size self.color = color self.rotation_x = 0 self.rotation_y = 0 self.rotation_z = 0 self.vx = random.uniform(-0.01, 0.01) self.vy = random.uniform(-0.01, 0.01) self.vz = random.uniform(-0.01, 0.01) def move(self, container_size): # 更新位置 self.x += self.vx self.y += self.vy self.z += self.vz # 检查与大立方体边界的碰撞 half_size = container_size / 2 cube_half = self.size / 2 if abs(self.x) + cube_half > half_size: self.x = (half_size - cube_half) * (1 if self.x >= 0 else -1) self.vx *= -1 if abs(self.y) + cube_half > half_size: self.y = (half_size - cube_half) * (1 if self.y >= 0 else -1) self.vy *= -1 if abs(self.z) + cube_half > half_size: self.z = (half_size - cube_half) * (1 if self.z >= 0 else -1) self.vz *= -1 def draw(self): glPushMatrix() glColor4f(self.color[0], self.color[1], self.color[2], self.color[3]) # 包含透明度 glTranslatef(self.x, self.y, self.z) glRotatef(self.rotation_x, 1, 0, 0) glRotatef(self.rotation_y, 0, 1, 0) glRotatef(self.rotation_z, 0, 0, 1) # 绘制立方体 half_size = self.size / 2 vertices = ( (half_size, -half_size, -half_size), (half_size, half_size, -half_size), (-half_size, half_size, -half_size), (-half_size, -half_size, -half_size), (half_size, -half_size, half_size), (half_size, half_size, half_size), (-half_size, -half_size, half_size), (-half_size, half_size, half_size) ) edges = ( (0,1), (1,2), (2,3), (3,0), # 底面 (4,5), (5,7), (7,6), (6,4), # 顶面 (0,4), (1,5), (2,7), (3,6) # 连接边 ) glBegin(GL_LINES) for edge in edges: for vertex in edge: glVertex3fv(vertices[vertex]) glEnd() # 绘制面以增加立体感 faces = ( (0,1,2,3), # 底面 (4,5,7,6), # 顶面 (0,1,5,4), # 前面 (2,3,6,7), # 后面 (0,3,6,4), # 左面 (1,2,7,5) # 右面 ) glBegin(GL_QUADS) for face in faces: for vertex in face: glVertex3fv(vertices[vertex]) glEnd() glPopMatrix() def draw_container_cube(size): glColor4f(1.0, 1.0, 1.0, 0.1) # 白色,10% alpha (90% 透明度) half_size = size / 2 vertices = ( (half_size, -half_size, -half_size), (half_size, half_size, -half_size), (-half_size, half_size, -half_size), (-half_size, -half_size, -half_size), (half_size, -half_size, half_size), (half_size, half_size, half_size), (-half_size, -half_size, half_size), (-half_size, half_size, half_size) ) edges = ( (0,1), (1,2), (2,3), (3,0), # 底面 (4,5), (5,7), (7,6), (6,4), # 顶面 (0,4), (1,5), (2,7), (3,6) # 连接边 ) glBegin(GL_LINES) for edge in edges: for vertex in edge: glVertex3fv(vertices[vertex]) glEnd() # 绘制面以增加立体感 faces = ( (0,1,2,3), # 底面 (4,5,7,6), # 顶面 (0,1,5,4), # 前面 (2,3,6,7), # 后面 (0,3,6,4), # 左面 (1,2,7,5) # 右面 ) glBegin(GL_QUADS) for face in faces: for vertex in face: glVertex3fv(vertices[vertex]) glEnd() def check_collision(cube1, cube2): # 简单的边界框碰撞检测 half_size1 = cube1.size / 2 half_size2 = cube2.size / 2 # 检查各轴是否有重叠 x_overlap = abs(cube1.x - cube2.x) < (half_size1 + half_size2) y_overlap = abs(cube1.y - cube2.y) < (half_size1 + half_size2) z_overlap = abs(cube1.z - cube2.z) < (half_size1 + half_size2) if x_overlap and y_overlap and z_overlap: # 发生碰撞,交换速度分量 cube1.vx, cube2.vx = cube2.vx, cube1.vx cube1.vy, cube2.vy = cube2.vy, cube1.vy cube1.vz, cube2.vz = cube2.vz, cube1.vz # 分离立方体以避免重叠 min_dist = half_size1 + half_size2 dist_x = abs(cube1.x - cube2.x) dist_y = abs(cube1.y - cube2.y) dist_z = abs(cube1.z - cube2.z) if dist_x < dist_y and dist_x < dist_z: # X轴方向分离 sign = 1 if cube1.x < cube2.x else -1 cube1.x -= sign * (min_dist - dist_x) / 2 cube2.x += sign * (min_dist - dist_x) / 2 elif dist_y < dist_z: # Y轴方向分离 sign = 1 if cube1.y < cube2.y else -1 cube1.y -= sign * (min_dist - dist_y) / 2 cube2.y += sign * (min_dist - dist_y) / 2 else: # Z轴方向分离 sign = 1 if cube1.z < cube2.z else -1 cube1.z -= sign * (min_dist - dist_z) / 2 cube2.z += sign * (min_dist - dist_z) / 2 def main(): clock = pygame.time.Clock() # 大立方体参数 container_size = 3.0 # 创建3个小立方体 cubes = [] cube_size = 0.4 # 小立方体尺寸 # 随机生成小立方体的位置,确保它们不重叠 for i in range(3): placed = False attempts = 0 while not placed and attempts < 1000: # 在大立方体内部随机选择一个位置 half_container = container_size / 2 - cube_size / 2 x = random.uniform(-half_container, half_container) y = random.uniform(-half_container, half_container) z = random.uniform(-half_container, half_container) # 检查是否与其他立方体重叠 valid_position = True for other_cube in cubes: dx = x - other_cube.x dy = y - other_cube.y dz = z - other_cube.z distance = math.sqrt(dx**2 + dy**2 + dz**2) min_distance = cube_size # 最小安全距离 if distance < min_distance: valid_position = False break if valid_position: # 白色,90% 透明度 cubes.append(Cube(x, y, z, cube_size, (1.0, 1.0, 1.0, 0.1))) placed = True attempts += 1 if not placed: print(f"无法放置第 {i+1} 个小立方体,可能空间不足") break rotation_x = 0 rotation_y = 0 drag = False last_pos = (0, 0) running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: running = False elif event.type == pygame.MOUSEBUTTONDOWN: if event.button == 1: # 左键按下 drag = True last_pos = event.pos elif event.type == pygame.MOUSEBUTTONUP: if event.button == 1: # 左键释放 drag = False elif event.type == pygame.MOUSEMOTION: if drag: dx = event.pos[0] - last_pos[0] dy = event.pos[1] - last_pos[1] rotation_y += dx * 0.5 rotation_x += dy * 0.5 last_pos = event.pos # 清除屏幕和深度缓冲区 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 应用旋转 glPushMatrix() glRotatef(rotation_x, 1, 0, 0) glRotatef(rotation_y, 0, 1, 0) # 绘制大立方体容器 draw_container_cube(container_size) # 移动所有小立方体并检查边界碰撞 for cube in cubes: cube.move(container_size) # 更新旋转 cube.rotation_x += 0.5 cube.rotation_y += 0.3 cube.rotation_z += 0.2 # 检查小立方体之间的碰撞 for i in range(len(cubes)): for j in range(i + 1, len(cubes)): check_collision(cubes[i], cubes[j]) # 绘制所有小立方体 for cube in cubes: cube.draw() glPopMatrix() pygame.display.flip() clock.tick(60) pygame.quit() if __name__ == "__main__": main()