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

Rust

テキストの表示ができたので、キャラクターを表示してみます。ここまでやれば大分ノベルゲームっぽくなります。

キャラクターの表示

とりあえずキャラクターを表示させてみます。コードを以下のように記載します

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(SpriteBundle {
        texture: asset_server.load("images/chara.png"),
        transform: Transform { 
            scale: Vec3::new(0.1, 0.1,1.0),
            ..Default::default()
        },
        ..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.just_released(KeyCode::Right) {
        let result = query.get_single_mut();

        let tuple = result.unwrap();

        let mut text = tuple.0;
        let mut message = tuple.1;

        let get_message = message.messages.pop();
        match get_message {
           Some(x) => {
                text.sections[0].value = x;
           },
           None => println!("結果がNoneです")
        }
    }
}
  • SpriteBundle
    • 画像を表示するのに利用します

キャラクターは表示されますが、メッセージエリアと被っているのでキャラクターが隠れています。

透過処理

NodeBundleを生成しているところの、colorをrgbaメソッドを利用して透明度まで指定できるようにします

// 枠の生成
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::rgba(0.0, 0.0, 0.0, 0.6).into(),
            // color: Color::BLACK.into(),
            ..default()
})

それらしくなりました

画像の位置を修正する

画面中央にある画像を、少しだけ上に配置します。SpriteBundleのtransformはtranslationにて位置を設定できます。中央を起点にしますので、y座標だけ少し値を設定してあげます

// キャラクターの表示
command.spawn_bundle(SpriteBundle {
    texture: asset_server.load("images/chara.png"),
    transform: Transform { 
        scale: Vec3::new(0.1, 0.1,1.0),
        translation: Vec3::new(0.0, 70.0, 0.0),
        ..Default::default()
    },
    ..default()
});

VecDeque

現在はVec#popメソッドを使っているので最後に追加されたメッセージから出力されています。

これは感覚的ではないので修正します。

VecDequeにはpop_frontというメソッドがあり、先頭の要素から取得できます。これを利用するように修正します

use std::collections::VecDeque;

use bevy::prelude::*;

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

#[derive(Component)]
struct Message{
    // VecDequeに変更する
    messages: VecDeque<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(SpriteBundle {
        texture: asset_server.load("images/chara.png"),
        transform: Transform { 
            scale: Vec3::new(0.1, 0.1,1.0),
            translation: Vec3::new(0.0, 70.0, 0.0),
            ..Default::default()
        },
        ..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::rgba(0.0, 0.0, 0.0, 0.6).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)
                })
            )
            // ここをVecDequeに変更する
            .insert(Message{
                messages: VecDeque::from([
                    "hello".to_string(),
                    "Do You Like Rust?".to_string()
                ])
            });
        }
    );
}

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();

        let mut text = tuple.0;
        let mut message = tuple.1;

        // pop_frontメソッドに変更
        let get_message = message.messages.pop_front();
        match get_message {
           Some(x) => {
                text.sections[0].value = x;
           },
           None => println!("結果がNoneです")
        }
    }
}
  • messages: VecDeque<String>
    • 型を変更しています
  • messages: VecDeque::from([])
    • 初期化の方法がVecとは異なっています
  • message.messages.pop_front();
    • これが先頭から取得するメソッドになります

これでメッセージも管理しやすくなりました

これでかなりノベルゲームっぽくなりました。ゲーム要素はないですが。

シリーズ記事

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

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

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

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

コメント

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