Latest commit 789b9ee

变换

相关的官方文档:[transform]、[translation]、[rotation]、[3d_rotation]、[scale]、[move_sprite]、[parenting]


变换使得游戏物体能够被放置在游戏世界中。物体的“平移”(位置/坐标)、“旋转”和“比例”(大小调整)的组合就是变换:

  • 平移:移动物体
  • 旋转:旋转物体
  • 比例:放大或缩小物体
#![allow(unused)]
fn main() {
// 平移
let xf_pos567 = Transform::from_xyz(5.0, 6.0, 7.0);

// 缩放
let xf_scale = Transform::from_scale(Vec3::splat(2.0));

// 旋转 2d 物体(绕 Z 轴旋转) 30°
let xf_rot2d = Transform::from_rotation(Quat::from_rotation_z(30.0_f32).to_radians())

// 3d 旋转 --- 略

// 变换
let xf = Transform::from_xyz(1.0, 2.0, 3.0)
	.with_scale(Vec3::new(0.5, 0.5, 1.0))
	.with_rotation(Quat::from_rotation_y(0.125 * std::f32::conts::PI));
}

变换组件

在 Bevy 中,变换由两个组件表示:TransformGlobalTransform。如果某个实体表示的是游戏世界中的物体,那么这个实体必须同时拥有 TransformGlobalTransform

所有 Bevy 内置的 Bundle 类型都包含 TransformGlobalTransform。自定义 Bundle 类型可以添加这些 Bundle 来确保包含 TrasformGlobalTransform

  • SpatialBundle:transform + visibility
  • TransformBundle:transform
#![allow(unused)]
fn main() {
fn 生成特殊实体(
	mut commands: Commands,
) {
	// 创建一个实体,不使用内置包,但需要 transform 和 visibility 功能
	commands.spawn()
		.insert(ComponentA)
		.insert(ComponentB)
		.insert_bundle(SpatialBundle {
			transform: Transform::from_scale(Vec3::splat(3.0)),
			visibility: Visibility {
				is_visible: false,
			},
		});
}
}

Transform 组件

Transform 最常用,是一个包含平移、旋转和缩放的结构体。要读取或操作这些值,请在系统中用 Query 来访问。

如果实体有父实体,Transform 组件是相对于父实体的。这意味着子实体会与父实体一起移动/旋转/缩放。

#![allow(unused)]
fn main() {
fn 给气球打气 (
	mut query: Query<&mut Transform, With<Balloon>>,
	keyboard: Res<Input<KeyCode>>,
) {
	// 每次按下空格键,所有气球扩大 25%
	if keyboard.just_pressed(KeyCode::Space) {
		for mut transform in &mut query {
			transform.scale *= 1.25;
		}
	}
}
}

GlobalTransform 组件

GlobalTransform 表示世界中的绝对全局位置。如果实体没有父实体,那么这个值和 Transform 相同。GlobalTransform 的值是由 Bevy 内部计算/管理的,视为只读数据,不要进行可变修改。

变换传播

注意:TransformGlobalTransform 的同步是由运行在 PostUpdate 阶段的内部系统(“变换传播系统”)管理的,如果手动修改 TransformGlobalTransform 不会立即更新。也就是:在当前帧里更新 Transform 后立即获取 GlobalTransform 的数值,GlobalTransform 不变,要等到下一帧才能获取正确的 GlobalTransform。

如果要立即处理 GlobalTransform,必须把系统放在 PostUpdate 阶段,并用标签让系统跟在 TransformSystem::TransformPropagate 后面运行。

/// 打印“当前帧”的最新全局位置
fn 调试全局变换(
	query: Query<&GlobalTransform, With<Player>>,
) {
	let gxf = query.single();
	debug!("玩家位于:{:?}", gxf.translation());
}

fn main() {
	use bevy::transform::TransformSystem;

	App::new()
		.add_plugins(DefaultPlugins)
		.add_system_to_stage(
			CoreStage::PostUpdate,
			调试全局变换.after(TransformSystem::TransformPropagete)
		)
		.run();
}