Rust – Bevyでノベルゲームを作る 次の文字を表示

Rust

右キーを押下したら次の文字を表示させようと思います。changeTextみたいなのがあればいいのですが、なさそう?

テキストの更新を行っているサンプルを見つけましたので、こちらを参考に実装してみます

Bevy - text
Bevy is a refreshingly simple data-driven game engine built in Rust. It is free and open-source forever!

次のメッセージの表示

use bevy::prelude::*;

fn main() {
    App::new()
    .add_plugins(DefaultPlugins)
    .add_startup_system(setup)
    .add_system(next_message) //定義した関数を追加する
    .run();
}

// メッセージというコンポーネントを定義する
#[derive(Component)]
struct Message;

fn setup(
    mut command: Commands,
    asset_server: Res<AssetServer>
){
    // フォントの取得
    let font = asset_server.load("fonts/FiraMono-Medium.ttf");
    // カメラの生成
    command.spawn_bundle(Camera2dBundle::default());
    // 枠の生成
    command.spawn_bundle(NodeBundle{
                style: Style {
                    size: Size::new(Val::Percent(100.0), Val::Percent(50.0)),
                    margin: UiRect::all(Val::Px(0.0)),
                    align_items: AlignItems::FlexEnd,
                    ..default()
                },
                color: Color::BLACK.into(),
                ..default()
    })
    .with_children(|parent| {
            parent.spawn_bundle(TextBundle::from_section(
                "Bevy | Rust",
                TextStyle {
                    font: font.clone(),
                    font_size: 60.0,
                    color: Color::rgb(0.9, 0.9, 0.9)
                })
            )
            //メッセージの登録
            .insert(Message);
        }
    );
    
}

// キーイベントを受け取り、右キーを押下していたらテキストを書き換える
fn next_message(
    key_input: Res<Input<KeyCode>>,
    mut query: Query<&mut Text, With<Message>>
){
    if key_input.pressed(KeyCode::Right) {
        let text = query.get_single_mut();
        text.unwrap().sections[0].value = "this is next message.".to_string();
    }
}

テキストの更新が行えましたが、実装については駆け足になっています。

複数のメッセージを表示する

次のメッセージが一つしかないのは流石にお粗末なので、複数のメッセージを表示できるようにします。

まずはどうやって複数のメッセージを管理するのか考えたのですが、以下のようにしてみました。

  • Message構造体にmessagesというベクタを定義
  • イベントが発生したらmessagesからpopする
use bevy::prelude::*;

fn main() {
    App::new()
    .add_plugins(DefaultPlugins)
    .add_startup_system(setup)
    .add_system(next_message) //定義した関数を追加する
    .run();
}

// メッセージというコンポーネントを定義する
// い
#[derive(Component)]
struct Message{
    messages: Vec<String>,
}


fn setup(
    mut command: Commands,
    asset_server: Res<AssetServer>
){

    // フォントの取得
    let font = asset_server.load("fonts/FiraMono-Medium.ttf");
    // カメラの生成
    command.spawn_bundle(Camera2dBundle::default());
    // 枠の生成
    command.spawn_bundle(NodeBundle{
                style: Style {
                    size: Size::new(Val::Percent(100.0), Val::Percent(50.0)),
                    margin: UiRect::all(Val::Px(0.0)),
                    align_items: AlignItems::FlexEnd,
                    ..default()
                },
                color: Color::BLACK.into(),
                ..default()
    })
    .with_children(|parent| {
            parent.spawn_bundle(TextBundle::from_section(
                "Bevy | Rust",
                TextStyle {
                    font: font.clone(),
                    font_size: 60.0,
                    color: Color::rgb(0.9, 0.9, 0.9)
                })
            )
            //メッセージの登録
            .insert(Message{
                messages: [
                    "hello".to_string(),
                    "rust novel game".to_string()
                ].to_vec()
            });
        }
    );
    
}

// キーイベントを受け取り、右キーを押下していたらテキストを書き換える
fn next_message(
    key_input: Res<Input<KeyCode>>,
    mut query: Query<(&mut Text, &mut Message)>
){
    if key_input.pressed(KeyCode::Right) {
        let result = query.get_single_mut();
        // クエリの結果からタプルを取り出す
        let tuple = result.unwrap();
        // Text部分
        let mut text = tuple.0;
        // Message部分
        let mut message = tuple.1;
        // 書き換える
        text.sections[0].value = "this is next message.".to_string();
        // Messageのmessagesから1件取り出す
        let get_message = message.messages.pop();
        // 取り出したOptionをmatchにかける
        match get_message {
           Some(x) => println!("{}", x),
           None => println!("結果がNoneです") 
        }
    }
}

messagesで設定した値を正しくpopしていることは確認できますが、一度キーを押しただけなのにすぐに結果がNoneですというログが表示されてしまっていますので、その辺を含めて修正していきます。

余談

この複数のメッセージを表示するっていうのに苦戦しました。最初はイテレータでnext呼べばいいでしょう?となったが、ごちゃごちゃしまくって断念。

その後も配列とカウンタで~とかやってもコンパイルが通らず断念。

結果的には構造体が持つVecをpopして順番に取り出すというのに落ち着きました。

just_released

キーイベントはワンプッシュでも毎フレーム呼ばれるので、popが一気に呼ばれてしまいます。代わりにjust_releasedというメソッドでイベントの監視を行います。

  • pressed
    • キーを押して離す間イベントがtureになる
  • just_released
    • キーを話した時の1フレームがtrueになる

詳細 https://bevy-cheatbook.github.io/input/mouse.html?highlight=button#mouse-buttons

なのでnext_messageメソッドを以下のように修正します

fn next_message(
    key_input: Res<Input<KeyCode>>,
    mut query: Query<(&mut Text, &mut Message)>
){
    // キーを離した時に呼ばれる
    if key_input.just_released(KeyCode::Right) {

        let result = query.get_single_mut();
        // クエリの結果からタプルを取り出す
        let tuple = result.unwrap();
        // Text部分
        let mut text = tuple.0;
        // Message部分
        let mut message = tuple.1;
        
        // Messageのmessagesから1件取り出す
        let get_message = message.messages.pop();
        // 取り出したOptionをmatchにかける
        match get_message {
           Some(x) => {
                // ここで書き換える
                text.sections[0].value = x;
           },
           None => println!("結果がNoneです")  // ここでメッセージが空になったときのイベントを行う
        }
    }
}

右キーを話すと画面のテキストが変更されます。

現在はpopメソッドを使っているので、感覚的には設定するメッセージを後ろから設定していく必要がありますが、ここは次回修正します。

シリーズ記事

◆Rust – Bevyでノベルゲームを作る 文字の表示

◆Rust – Bevyでノベルゲームを作る 枠の表示

◆Rust – Bevyでノベルゲームを作る 次の文字を表示

◆Rust – Bevyでノベルゲームを作る キャラクターを表示する

コメント

タイトルとURLをコピーしました