| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- 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()
|