Ursina Python:如何正确重设Entity的父对象?
问题描述
我用Ursina制作魔方,计划将某一面的所有方块设置为该面中心方块的子对象,通过旋转中心方块实现整面旋转。但仅首次设置父对象有效,后续无法成功修改方块的父对象。尝试过entity.parent = ___和entity.parent_setter(___)两种方式均未成功,相关代码如下:
from ursina import * app = Ursina() cubepiece = Entity(model='cube', color=color.black) blueplate = Entity(model="cube", scale_x=0.9, scale_y=0.9, scale_z=0.1, z=-0.5, color=color.blue, parent=cubepiece) yellowplate = Entity(model="cube", scale_x=0.1, scale_y=0.9, scale_z=0.9, x=-0.5, color=color.yellow, parent=cubepiece) redplate = Entity(model="cube", scale_x=0.9, scale_y=0.1, scale_z=0.9, y=0.5, color=color.red, parent=cubepiece) whiteplate = Entity(model="cube", scale_x=0.1, scale_y=0.9, scale_z=0.9, x=0.5, color=color.white, parent=cubepiece) orangeplate = Entity(model="cube", scale_x=0.9, scale_y=0.1, scale_z=0.9, y=-0.5, color=color.orange, parent=cubepiece) greenplate = Entity(model="cube", scale_x=0.9, scale_y=0.9, scale_z=0.1, z=0.5, color=color.green, parent=cubepiece) cube = [] for i in range(3): layer = [] for j in range(3): line = [] for k in range(3): piece = duplicate(cubepiece) piece.set_position((i-1, j-1, k-1)) line.append(piece) layer.append(line) cube.append(layer) destroy(cubepiece) for layer in cube: for line in layer: for piece in line: if piece != cube[1][1][1]: piece.parent = cube[1][1][1] camera.x = 20 camera.y = 20 camera.fov = 30 camera.look_at((0, 0, 0)) def input(key): if key == 'w': rotateYellow() if key == "up arrow": cube[1][1][1].rotation_x += 45 if key == "down arrow": cube[1][1][1].rotation_x -= 45 if key == "left arrow": cube[1][1][1].rotation_y += 45 if key == "right arrow": cube[1][1][1].rotation_y -= 45 def rotateYellow(): for line in cube[0]: for piece in line: if piece != cube[0][1][1]: piece.parent_setter(cube[0][1][1]) cube[0][1][1].rotation_x += 45 for line in cube[0]: for piece in line: piece.parent_setter(cube[1][1][1]) app.run()
问题根源
- 父对象切换未保留世界坐标:直接修改父对象会让子对象继承父对象的局部空间,导致方块位置偏移,视觉上看起来切换失败。
- 错误使用
parent_setter:Ursina中设置父对象的正确方式是直接赋值entity.parent = 目标对象,parent_setter是内部方法,不应直接调用。 - 旋转后未更新方块索引:魔方旋转后,方块在
cube数组中的索引与实际空间位置不再匹配,后续操作会指向错误的方块。
修正后的代码
from ursina import * app = Ursina() # 定义带六个色块的魔方块 cubepiece = Entity(model='cube', color=color.black) blueplate = Entity(model="cube", scale=(0.9,0.9,0.1), z=-0.5, color=color.blue, parent=cubepiece) yellowplate = Entity(model="cube", scale=(0.1,0.9,0.9), x=-0.5, color=color.yellow, parent=cubepiece) redplate = Entity(model="cube", scale=(0.9,0.1,0.9), y=0.5, color=color.red, parent=cubepiece) whiteplate = Entity(model="cube", scale=(0.1,0.9,0.9), x=0.5, color=color.white, parent=cubepiece) orangeplate = Entity(model="cube", scale=(0.9,0.1,0.9), y=-0.5, color=color.orange, parent=cubepiece) greenplate = Entity(model="cube", scale=(0.9,0.9,0.1), z=0.5, color=color.green, parent=cubepiece) # 生成3x3x3魔方数组,给每个方块标记索引 cube = [] for i in range(3): layer = [] for j in range(3): line = [] for k in range(3): piece = duplicate(cubepiece) piece.set_position((i-1, j-1, k-1)) piece.index = (i,j,k) # 记录初始索引 line.append(piece) layer.append(line) cube.append(layer) destroy(cubepiece) center_piece = cube[1][1][1] # 初始将所有非中心块设为中心块子对象 for layer in cube: for line in layer: for piece in line: if piece != center_piece: piece.parent = center_piece camera.position = (20,20,20) camera.fov = 30 camera.look_at((0,0,0)) def update_cube_indices(layer_idx): """旋转后更新cube数组的方块索引映射""" layer = cube[layer_idx] new_layer = [[None]*3 for _ in range(3)] for j in range(3): for k in range(3): piece = layer[j][k] # 通过世界坐标计算新索引 world_pos = piece.world_position x = round(world_pos.x) + 1 y = round(world_pos.y) + 1 z = round(world_pos.z) + 1 new_layer[y][z] = piece piece.index = (x,y,z) cube[layer_idx] = new_layer def rotateYellow(): yellow_center = cube[0][1][1] # 切换父对象前保存世界坐标,避免位置偏移 for line in cube[0]: for piece in line: if piece != yellow_center: world_pos = piece.world_position piece.parent = yellow_center piece.world_position = world_pos # 平滑旋转并在完成后重置父对象、更新索引 def on_rotation_finish(): for line in cube[0]: for piece in line: if piece != yellow_center: world_pos = piece.world_position piece.parent = center_piece piece.world_position = world_pos update_cube_indices(0) yellow_center.animate('rotation_x', yellow_center.rotation_x + 90, duration=0.2, curve=curve.linear, callback=on_rotation_finish) def input(key): if key == 'w': rotateYellow() if key == "up arrow": center_piece.rotation_x += 45 if key == "down arrow": center_piece.rotation_x -= 45 if key == "left arrow": center_piece.rotation_y += 45 if key == "right arrow": center_piece.rotation_y -= 45 app.run()
关键修正说明
- 保留世界坐标:切换父对象前后,先保存
world_position,设置父对象后再赋值回去,确保方块位置不变。 - 正确设置父对象:使用
piece.parent = 目标对象替代内部方法parent_setter。 - 旋转后更新索引:魔方旋转完成后,根据方块世界坐标重新映射数组索引,保证后续操作能选中正确的方块。
- 平滑旋转回调:用
animate实现平滑旋转,旋转完成后再重置父对象,避免旋转过程中出现坐标混乱。
内容的提问来源于stack exchange,提问作者Iby Morris
相关产品推荐
相关产品推荐

