タイトル画面をクリックして画面遷移する
タイトル画面をクリックして画面遷移する
タイトル画面をクリックしたら、図3のように色ブロックを表示したメインループ画面に遷移させます。ゲームステートが「Title」の場合、OnEnter で「reset_for_title」関数を実行し、更新(Update)ごとに「title_system」関数を実行します。ゲームステートが「MainLoop」なら入り口(OnEnter)で「start_stage」関数を実行します。
・サンプルコード「main.rs」ファイル
(前略)
// メイン
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
title: "Color".into(),
..default()
}),
..default()
}))
.init_state::<GameState>()
.init_resource::<GameData>()
.insert_resource(ClearColor(Color::from(WHITE)))
.add_systems(Startup, setup)
// Title
.add_systems(OnEnter(GameState::Title), reset_for_title)
.add_systems(Update, title_system.run_if(in_state(GameState::Title)))
// MainLoop
.add_systems(OnEnter(GameState::MainLoop), start_stage)
.run();
}
// 初期化
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2d);
commands.spawn((
Sprite::from_image(asset_server.load("images/Title.png")),
Transform::from_xyz(0.0, 0.0, 10.0),
TitleVisual,
));
for i in 0..50 {
let (c_type, path, tint) = match i % 3 {
0 => (ColorType::Red, "images/0.png", RED),
1 => (ColorType::Green, "images/1.png", LIME),
_ => (ColorType::Blue, "images/2.png", BLUE),
};
commands.spawn((
Sprite {
image: asset_server.load(path),
color: Color::from(tint),
..default()
},
Visibility::Hidden,
Transform::default(),
ColorItem {
color_type: c_type,
velocity: Vec2::ZERO,
},
));
}
}
// タイトル
fn title_system(
mouse: Res<ButtonInput<MouseButton>>,
mut next_state: ResMut<NextState<GameState>>,
) {
if mouse.just_pressed(MouseButton::Left) {
next_state.set(GameState::MainLoop);
}
}
// タイトル画像表示
fn reset_for_title(
mut title_q: Query<&mut Visibility, With<TitleVisual>>,
mut item_q: Query<&mut Visibility, (With<ColorItem>, Without<TitleVisual>)>,
) {
if let Ok(mut v) = title_q.single_mut() {
*v = Visibility::Visible;
}
for mut v in &mut item_q {
*v = Visibility::Hidden;
}
}
// Stage開始
fn start_stage(
mut game_data: ResMut<GameData>,
mut title_q: Query<&mut Visibility, With<TitleVisual>>,
mut item_q: Query<(&mut Visibility, &mut Transform, &mut ColorItem), Without<TitleVisual>>,
) {
if let Ok(mut v) = title_q.single_mut() {
*v = Visibility::Hidden;
}
let mut rng = rand::rng();
let active_count = (game_data.stage * 3).min(50);
for (i, (mut vis, mut trans, mut item)) in item_q.iter_mut().enumerate() {
if i < active_count {
*vis = Visibility::Visible;
trans.translation = Vec3::new(
rng.random_range(-450.0..450.0),
rng.random_range(-280.0..280.0),
1.0,
);
item.velocity = Vec2::new(
rng.random_range(-0.2..0.2),
rng.random_range(-0.2..0.2),
);
} else {
*vis = Visibility::Hidden;
}
}
}【サンプルコードの解説】
ECSのSystemでreset_for_title関数、title_system関数、start_stage関数を追加します。
「setup」関数で、アセットから「images/0.png」(Red列挙子を指定)、「images/1.png」(Green列挙子を指定)、「images/2.png」(Blue列挙子を指定)をスポーンします。
title_system関数でマウスがクリックされたらゲームステートをMainLoopにセットします。
reset_for_title関数で色ブロックを全て消し、タイトル画像を表示設定します。
start_stage関数で、ゲーム開始時にランダムな位置にランダムな「velocity(移動速度)」の色ブロックをstageの3倍(3色ずつ)表示します。
色ブロックをクリックして消す
やっとゲームらしく色ブロックを移動し、クリックした色ブロックを消します。ゲームステートがMainLoopの時、更新ごと(Update)に「movement_system」関数と「input_system」関数を呼び出します。
・サンプルコード「main.rs」ファイル
(前略)
// メイン
fn main() {
App::new()
(中略)
.add_systems(
Update,
(
movement_system,
input_system,
)
.run_if(in_state(GameState::MainLoop)),
)
.run();
}
// 初期化
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
(中略)
}
// タイトル
fn title_system(
mouse: Res<ButtonInput<MouseButton>>,
mut next_state: ResMut<NextState<GameState>>,
) {
(中略)
}
// タイトル画像表示
fn reset_for_title(
mut title_q: Query<&mut Visibility, With<TitleVisual>>,
mut item_q: Query<&mut Visibility, (With<ColorItem>, Without<TitleVisual>)>,
) {
(中略)
}
// Stage開始
fn start_stage(
mut game_data: ResMut<GameData>,
mut title_q: Query<&mut Visibility, With<TitleVisual>>,
mut item_q: Query<(&mut Visibility, &mut Transform, &mut ColorItem), Without<TitleVisual>>,
) {
(中略)
}
// 色ブロック移動
fn movement_system(
mut query: Query<(&mut Transform, &ColorItem), With<Visibility>>,
) {
for (mut trans, item) in &mut query {
trans.translation += item.velocity.extend(0.0);
}
}
// クリック処理
fn input_system(
mouse: Res<ButtonInput<MouseButton>>,
windows: Query<&Window, With<PrimaryWindow>>,
camera_q: Query<(&Camera, &GlobalTransform)>,
mut item_q: Query<(&mut Visibility, &Transform, &ColorItem)>,
) {
if !mouse.just_pressed(MouseButton::Left) {
return;
}
let window = windows.single().unwrap();
let (camera, camera_transform) = camera_q.single().unwrap();
if let Some(world_pos) = window
.cursor_position()
.and_then(|c| camera.viewport_to_world_2d(camera_transform, c).ok())
{
for (mut vis, trans, _item) in &mut item_q {
if *vis == Visibility::Visible
&& trans.translation.truncate().distance(world_pos) < SPRITE_SIZE
{
*vis = Visibility::Hidden;
break;
}
}
}
}【サンプルコードの解説】
main関数では「App」構造体のコンストラクタでSystemにmovement_system 関数とinput_system関数を追加します。
movement_system関数で色ブロックをvelocityだけトランスレート(座標変換)して移動します。
input_system関数でクリックした時、マウスカーソルの位置を2Dゲーム画面の座標に変換します。色ブロックが画面外に出たら非表示にします。
ゲーム専用機があるように、「たまごっち」があるように、株式投資専用機があればいいです。そうすれば安全に株式投資が楽しめるのではないでしょうか?調べてみるとプロ用の株OSが月額数10万円であるそうです。個人向けにその1/10の値段で作れば世界中で売れないでしょうか?
