🐦

【Bevy0.13】MaterialMesh2dBundleで生成した図形の色の変更

2024/03/28に公開

概要

MaterialMesh2dBundleで生成した図形の色(ColorMaterial)を変更する方法です

STEP1 図形の表示

とりあえず図形を表示してみることから。
BevyのExampleに載っている図形の描画方法そのままです。

use bevy::{prelude::*, sprite::{MaterialMesh2dBundle, Mesh2dHandle}};

#[derive(Component)]
struct Ball;

fn main(){
   App::new()
      .add_plugins(DefaultPlugins)
      .add_systems(Startup, setup)
      .run();
}

fn setup(
   mut commands : Commands,
   mut meshes : ResMut<Assets<Mesh>>,
   mut materials : ResMut<Assets<ColorMaterial>>
){
   // カメラ生成
   commands.spawn(Camera2dBundle::default());

   // ボールの生成
   commands.spawn((
      Ball,
      MaterialMesh2dBundle{
         mesh : Mesh2dHandle(meshes.add(Circle{radius:30.})),
         material : materials.add(Color::GOLD),
         ..default()
      },
   ));
}

黄色いボールが生成されました。

STEP2 色変更

use bevy::{prelude::*, sprite::{MaterialMesh2dBundle, Mesh2dHandle}};

#[derive(Component)]
struct Ball;

fn main(){
   App::new()
      .add_plugins(DefaultPlugins)
      .add_systems(Startup, setup)
+     .add_systems(Update,change_color)
      .run();
}

fn setup(
   mut commands : Commands,
   mut meshes : ResMut<Assets<Mesh>>,
   mut materials : ResMut<Assets<ColorMaterial>>
){
   // カメラ生成
   commands.spawn(Camera2dBundle::default());

   // ボールの生成
   commands.spawn((
      Ball,
      MaterialMesh2dBundle{
         mesh : Mesh2dHandle(meshes.add(Circle{radius:30.})),
         material : materials.add(Color::GOLD),
         ..default()
      },
   ));
}

+fn change_color(
+   q_ball : Query<&Handle<ColorMaterial>,With<Ball>>,
+   mut materials : ResMut<Assets<ColorMaterial>>
+){
+   // materialsの中からボールのカラーマテリアルを取得
+   let handle: &Handle<ColorMaterial> = q_ball.single();
+   let colormaterial: &mut ColorMaterial = materials.get_mut(handle.id()).unwrap();
+
+   // 取得したカラーマテリアルの色変更
+   colormaterial.color = Color::SEA_GREEN;
+}

ボールが緑色になりました。

何をやっているかよくわからなかった人への解説

先ほどはボールだけでしたが、今回はボールとボックスの二つを作ってみましょう。
そしてそれぞれのmaterialを共通のものにしてみます。

use bevy::{prelude::*, sprite::{MaterialMesh2dBundle, Mesh2dHandle}};

#[derive(Component)]
struct Ball;

+#[derive(Component)]
+struct Box;

fn main(){
   App::new()
      .add_plugins(DefaultPlugins)
      .add_systems(Startup, setup)
      .add_systems(Update,change_color)
      .run();
}

fn setup(
   mut commands : Commands,
   mut meshes : ResMut<Assets<Mesh>>,
   mut materials : ResMut<Assets<ColorMaterial>>
){
   // カメラ生成
   commands.spawn(Camera2dBundle::default());

+   // ボールとボックスに共通のカラーマテリアル
+   let handle_gold : Handle<ColorMaterial> = materials.add(Color::GOLD);

   // ボールの生成
   commands.spawn((
      Ball,
      MaterialMesh2dBundle{
         mesh : Mesh2dHandle(meshes.add(Circle{radius:30.})),
+        material : handle_gold.clone(),
+        transform: Transform::from_xyz(-100., 0., 0.),
         ..default()
      },
   ));

+   // ボックスの生成
+   commands.spawn((
+      Box,
+      MaterialMesh2dBundle{
+         mesh : Mesh2dHandle(meshes.add(Rectangle{half_size: Vec2::new(20., 20.)})),
-         material : materials.add(Color::GOLD),
+         material : handle_gold.clone(),
+         transform: Transform::from_xyz(100., 0., 0.),
+         ..default()
+      },
+   ));
+}


fn change_color(
   q_ball : Query<&Handle<ColorMaterial>,With<Ball>>,
   mut materials : ResMut<Assets<ColorMaterial>>
){
   // materialsの中からボールのカラーマテリアルを取得
   let handle: &Handle<ColorMaterial> = q_ball.single();
   let colormaterial: &mut ColorMaterial = materials.get_mut(handle.id()).unwrap();

   // カラーマテリアルの色変更
   colormaterial.color = Color::SEA_GREEN;
}


change_color関数はボールのカラーマテリアルの色のみを変更したように見えますが、結果を見るとボックスの色も変更されています。これはsetup関数内で図形を生成したとき、ボールとボックスそれぞれに共通のカラーマテリアルを設定しているからです。
materials.add()の戻り値であるHandle<ColorMaterial>とやらはmaterials配列に追加したColorMaterialへのインデックスです。つまり図形に対して色を直接指定しているわけではなく、materials配列に色を格納し、その色へのインデックスを指定しているということです。
色を変えたいときはそのインデックスを元にmaterialsからカラーマテリアルを取得して、その色を変更しているわけです。それがchange_color関数内の処理です。

Discussion