Rust Bevy 使ってみたメモ

Rust Bevy 使ってみたメモ

Rust Bevyを使っているのですが一回のコンパイルにそれなりに時間がかかるのでテスト結果を忘れないようにメモっていきます

ウィンドウの生成まではできてる前提で書いています

rustc -V
rustc 1.80.1
bevy -version
0.14.1

目次

MouseMotion構造体のイベント

MouseMotion構造体はイベントなのでEventReaderで読み取る

//一フレームあたりのマウス位置の変化量
fn test(
    mut mouse_motion_event: EventReader<MouseMotion>
) {
    for ev in mouse_motion_event.read() {
        println!("( {} : {} )", ev.delta.x, ev.delta.y);
    }
}

出力

**省略
( 0 : -1 )
( 0 : -1 )
( 0 : -1 )
( 0 : -1 )
**省略

Updateに入れたので1フレーム毎の変化量が出力される

CursorEntered構造体のイベント

CursorEntered構造体はイベントなのでイベントリーダーで読み取る

//ウィンドウ内に入ったかどうか
fn test(
    mut cursor_enter_event: EventReader<CursorEntered>
) {
    for ev in cursor_enter_event.read() {
        println!("{:?}", ev);
    }
}

出力

**省略
CursorEntered { window: Entity { index: 0, generation: 1 } }
CursorEntered { window: Entity { index: 0, generation: 1 } }
CursorEntered { window: Entity { index: 0, generation: 1 } }
**省略

マウスカーソルがウィンドウに入ったら上記が出力された

試行錯誤

CursorEnteredの出力はEntityのため、ウィンドウに入ったかどうかを判定できなさそう?

ついでにCursorLeft構造体とWindow構造体のクエリを試してみよう!ってことで

//ウィンドウ内に入ったらマウスカーソルの位置を出力
fn test(
    cursor_enter_event: EventReader<CursorEntered>,
    cursor_left_event : EventReader<CursorLeft>,
    q_window: Query<&Window, With<PrimaryWindow>>,
) {
    let mut state = 0;
    if !cursor_enter_event.is_empty() {
        println!("マウスカーソルがウィンドウ内に入りました!");
        state = 1;
    }else if !cursor_left_event.is_empty() {
        println!("マウスカーソルがウィンドウ外に出ました!");
        state = 0
    }
    if state == 1 {
        if let Some(position) = q_window.single().cursor_position(){
            println!("{}", position);
        }
    }
}

出力

**省略
[1267, 155]
マウスカーソルがウィンドウ外に出ました!
マウスカーソルがウィンドウ外に出ました!
マウスカーソルがウィンドウ外に出ました!
マウスカーソルがウィンドウ内に入りました!
[1278, 180]
マウスカーソルがウィンドウ内に入りました!
[1277, 180]
マウスカーソルがウィンドウ内に入りました!
[1276, 180]
マウスカーソルがウィンドウ外に出ました!
マウスカーソルがウィンドウ外に出ました!
**省略

ファンクションが呼び出されるたびにstateが0になるんだろうなってことは予想出来ていたのですが、なぜか複数回にわたって出力されています。なぜ?

イベントは1フレームで処理しきらないんでしょうかね?

Window構造体のクエリ

ウィンドウ内のマウスカーソルの位置を取得するだけならこれだけでよさそう

//ウィンドウ内のマウスカーソル位置取得
fn test(
    q_window: Query<&Window, With<PrimaryWindow>>,
) {
    if let Some(position) = q_window.single().cursor_position(){
        println!("{}", position);
    }
}

出力

**省略
[958, 536]
[978, 544]
[1011, 557]
[1046, 570]
[1073, 578]
[1111, 591]
[1147, 604]
[1183, 614]
[1209, 619]
[1248, 626]
**省略

マウスカーソルがウィンドウ内に入ったときだけ出力されます

注意点としてはマウスカーソルの位置はウィンドウ内の相対位置(左上原点)であることくらいですかね

Eventについての調査

どうやらis_empty()のみを実行すると複数回にわたってイベントが残り続けるっぽいです

//ウィンドウ内に入ったかどうか
fn test(
    mut cursor_enter_event: EventReader<CursorEntered>
) {
    if !cursor_enter_event.is_empty() {
        println!("カーソルがウィンドウ内に入りました!")
    }
    for ev in cursor_enter_event.read() {
        println!("{:?}", ev);
    }
}

出力

**省略
カーソルがウィンドウ内に入りました!
CursorEntered { window: Entity { index: 0, generation: 1 } }
カーソルがウィンドウ内に入りました!
CursorEntered { window: Entity { index: 0, generation: 1 } }
**省略
//ウィンドウ内に入ったかどうか
fn test(
    mut cursor_enter_event: EventReader<CursorEntered>
) {
    if !cursor_enter_event.is_empty() {
        println!("カーソルがウィンドウ内に入りました!")
    }
}

出力

**省略
カーソルがウィンドウ内に入りました!
カーソルがウィンドウ内に入りました!
カーソルがウィンドウ内に入りました!
カーソルがウィンドウ内に入りました!
カーソルがウィンドウ内に入りました!
**省略
//ウィンドウ内に入ったかどうか
fn test(
    mut cursor_enter_event: EventReader<CursorEntered>
) {
    for ev in cursor_enter_event.read() {
        println!("{:?}", ev);
    }
    if !cursor_enter_event.is_empty() {
        println!("カーソルがウィンドウ内に入りました!")
    }
}

出力

**省略
CursorEntered { window: Entity { index: 0, generation: 1 } }
CursorEntered { window: Entity { index: 0, generation: 1 } }
**省略

比較としては、.read()するかどうか と 先にするか後にするかです

.is_empty()は単体で呼び出さないほうがよさそうです

簡単なテスト

マウスカーソルの位置を取得できそうなので簡単なテストを作ってみます

//大きさが100×100のSpriteBundle
fn setup(
    mut commands: Commands,
) {
    commands.spawn(SpriteBundle {
        sprite: Sprite {
            color: Color::WHITE,
            ..Default::default()
        },
        transform: Transform {
            scale: (100., 100., 0.).into(),
            ..Default::default()
        },
        ..Default::default()
    });
}

//取得したマウスカーソル位置にオブジェクトを移動ver.2
fn test(
    mut q_obj: Query<&mut Transform, With<Sprite>>,
    q_window: Query<&Window, With<PrimaryWindow>>,
) {
    if let Some(position) = q_window.single().cursor_position(){

        //ウィンドウの解像度 参照で取得
        let window_resolition: &bevy::window::WindowResolution = &q_window.single().resolution;
        //ウィンドウの幅と高さ
        let window_width: f32 = window_resolition.width();
        let window_height: f32 = window_resolition.height();

        //オブジェクトの位置
        let mut transform: Mut<'_, Transform> = q_obj.single_mut();

        //ウィンドウの幅と高さに応じた調整
        transform.translation.x =  position.x - window_width/2.;
        transform.translation.y = -position.y + window_height/2.;
    }
}

結果はマウスカーソルにオブジェクトが追随してくれます(結果乗せるの面倒)

オブジェクトとマウスカーソル位置の原点が違う場所にあったので一筋縄ではいきませんでしたがうまくいって良かったです

まとめ

とりあえず今回はこのあたりで締めたいと思います

windows api をいじるより1000倍くらい楽…Bevy開発陣の皆さんありがとうございます!!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です