Behind Coleus

大学生なのに特別大学で楽しいことが一 つもない。虐待と男子校病のせいにしてみる。→日本脱出しました 今ジャカルタにいます。→ジャカルタから帰ってきました。→6月19日から小笠原沖で、インドネシア人とメカジキ漁

戦い12

まず、デバッグ用に、escキーでゲームを終わらおせらせられるようにする。

pub fn exit_game(
    keyboard_input: Res<ButtonInput<KeyCode>>,
    mut app_exit_event_writer: EventWriter<AppExit>,
) {
    if keyboard_input.pressed(KeyCode::Escape) {
        app_exit_event_writer.send(AppExit::Success);
    }
}

昔書いたコードを振り返っていたんだけど、これが見つかった。
AppExitって言う、bevyに初期からあるイベントを使えばいいらしいね。
フォルダー内を検索してもこれの定義はなかった。

ただ、これを入れても全然ゲーム終了できなくて、ちょっと保留にします。

 

ターンエンド ターン終了であることを示す ターンプレイヤーを、非ターンプレイヤーにする。 自動的にターンスタートに移行する

アメリカに行ってNMIXXのライブ見る夢見た - Behind Coleus

これで3つ書けばよろし

#[derive(States, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Controller {
    Player,
    Opponent,
}

とりあえず、これでステートを入れて、


pub fn choose_first(mut first_player: ResMut<PlayerSort>, mut next_controller: NextState<Controller>) {
    let (turn_player, non_turn_player) = janken();

    // turn_player を FirstPlayer リソースに格納
    first_player.firstplayer_id = turn_player;
    first_player.secondplayer_id = non_turn_player;
    match turn_player {
        1 => {
            next_controller.set(Controller::Player); // Player が先行の場合
        }
        2 => {
            next_controller.set(Controller::Opponent); // Opponent が先行の場合
        }
        _ => {
            println!("無効なプレイヤーIDです。");
        }
    }
    println!(
        "先行: Player {}, 後攻: Player {}",
        first_player.firstplayer_id, first_player.secondplayer_id,
    );
}

set_upで、こういう風に、初期化した。
ただ、引数が間違っていて、

pub fn choose_first(
    mut first_player: ResMut<PlayerSort>,
    mut next_controller: ResMut<NextState<Controller>>,
) {

ステートを変更するには、ResMutを使わないといけなかった。 超長文エラーが出てきて困った。

pub fn change_turn_player(turn_player: ResMut<TurnPlayer>, mut next_state: ResMut<NextState<PlayState>>, mut next_turn_player: ResMut<NextState<Controller>>){
    println!("{}のターン終了しました。", turn_player.turnplayer_id);
    next_turn_player.set(Controller::Opponent);
    next_state.set(PlayState::TurnStart);
}

turn_endになった時の関数も設定した。

pub struct TurnEndPlugin;
impl Plugin for TurnEndPlugin {
    fn build(&self, app: &mut App) {
        app.insert_resource(Winner::default())
            .add_systems(OnEnter(PlayState::TurnEnd), change_turn_player);
    }
}



#[derive(States, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum Controller {
    #[default]
    Player,
    Opponent,
}

結局デフォルトが無いと話にならなかったので、こういう風にした。

ターンエンドできてなかったので、先ほどのResMutの間違いに気付く。

OK これで、繰り返せるようにしたいので、Start_Turnの関数を見直す。

 
pub struct TurnStartPlugin;
impl Plugin for TurnStartPlugin {
    fn build(&self, app: &mut App) {
        app.insert_resource(TurnPlayer::default())
            .init_resource::<TurnCount>()
            .add_systems(
                OnEnter(GameState::Play),
                (
                    turn_start,
                    automatically_move_to_setup_phase,
                )
                    .chain(),
            );
    }
}

こうなっている。
これでは、起動時に一回しか発動できない。

pub fn automatically_move_to_play_state(mut next_state: ResMut<NextState<GameState>>, mut next_state2: ResMut<NextState<PlayState>>) {
    next_state.set(GameState::Play);
    next_state2.set(PlayState::TurnStart);
    println!("対戦を開始します")
}

GameStateをPlayにする関数を改造して、PlayState::TurnStartにするようにした。

 
pub struct TurnStartPlugin;
impl Plugin for TurnStartPlugin {
    fn build(&self, app: &mut App) {
        app.insert_resource(TurnPlayer::default())
            .init_resource::<TurnCount>()
            .add_systems(
                OnEnter(PlayState::TurnStart),
                (
                    turn_start,
                    automatically_move_to_setup_phase,
                )
                    .chain().run_if(in_state(GameState::Play)),
            );
    }
}

これでどうだろうか。

中途半端なところで止まってしまった。なんでだろう。
しかも、player2のターンってことになってしまっているし、

とりあえず.run_ifを消したら、

初期化した時点でこの関数が呼び出されてしまった。(準備フェーズになりましたが、このプラグインが呼び出された目印)

しかし、繰り返しはうまくいっているように思える。
じゃあ、PlayStateの初期ステートを何の意味も持たないようなステートにしようと思う。

#[derive(States, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum PlayState {
    #[default]
    Default,
    TurnStart,
    SetupPhase,
    WithdrawPhase,
    XPhase,
    MainPhase,
    TurnEnd,
}

ありゃ、またさっきの問題が出てきた。
なんかよくわかんないけど、PlayStateの初期化する場所を変えたりしてたら、上手くいった。

よし、これでターン数情報も保存できているし、大丈夫な気がする。
先行後攻も合っているし


やるべきことは、ターンエンドの実装、ターンプレイヤーの実装、プレイヤー2のステートの実装、カードの効果の実装、勝利条件の実装これらをやらないといけないと思う。

 

ターンエンドの実装はできた。

ターンプレイヤーの実装もできた。
プレイヤー2のターンにやることを実装しなきゃ。
勝利条件の実装しなきゃ
カード効果の実装しなきゃ

カードの効果の実装は最後でいいかな。

簡単そうな勝利条件に実装についてやってく。

勝利条件は二つで、ジュンビフェーズのドローと、Xゾーンのカードが6枚以上になった時の二つである。

pub fn set_up_draw(
    query: Query<(Entity, &Card, &Location)>, // クエリとして受け取る
    mut in_library_cards: ResMut<InLibraryCards>, // ミュータブル参照として受け取る
    mut commands: Commands,                   // コマンド用
    turn_player: ResMut<TurnPlayer>,          // ResMutを使う
    mut winner: ResMut<Winner>,               // ResMutを使う
    mut next_state: ResMut<NextState<GameState>>, // ResMutを使う
    turn: Res<TurnCount>,                     // 不変の参照
) {
    if turn.value == 1 {
        println!("先行なのでドローなしで")
    } else {
        if let Some(&top_card) = in_library_cards.cards.first() {
            if let Ok*1 = query.get(top_card) {
                println!(
                    "あなたは {}, を引きました entity id: {:?},",
                    card.name, top_card
                );
                commands.entity(top_card).insert(Location::InHand);
                in_library_cards.cards.remove(0); // 先頭のカードを削除
            } else {
                println!("No cards available in the deck.");
            }
        } else {
            println!("デッキにカードがありません。");
            winner.winner_id = turn_player.non_turnplayer_id;
            println!("{}, の勝利です", winner.winner_id,);
            next_state.set(GameState::GameOver)
        }
    }
}

過去にゲームオーバーを管理する時は、イベントがいいと知ったので、

pub fn set_up_draw(
    query: Query<(Entity, &Card, &Location)>, // クエリとして受け取る
    mut in_library_cards: ResMut<InLibraryCards>, // ミュータブル参照として受け取る
    mut commands: Commands,                   // コマンド用
    turn_player: ResMut<TurnPlayer>,          // ResMutを使う
    mut winner: ResMut<Winner>,               // ResMutを使う
    mut next_state: ResMut<NextState<GameState>>, // ResMutを使う
    turn: Res<TurnCount>,                     // 不変の参照
    mut game_over_event_writer: EventWriter<GameOver>
) {
    if turn.value == 1 {
        println!("先行なのでドローなしで")
    } else {
        if let Some(&top_card) = in_library_cards.cards.first() {
            if let Ok*2 = query.get(top_card) {
                println!(
                    "あなたは {}, を引きました entity id: {:?},",
                    card.name, top_card
                );
                commands.entity(top_card).insert(Location::InHand);
                in_library_cards.cards.remove(0); // 先頭のカードを削除
            } else {
                println!("No cards available in the deck.");
            }
        } else {
            println!("デッキにカードがありません。");
            winner.winner_id = turn_player.non_turnplayer_id;
            game_over_event_writer.send(GameOver { winner_id: winner.winner_id });
            println!("{}, の勝利です", winner.winner_id,);
            next_state.set(GameState::GameOver)
        }
    }
}

勝者を記録するイベントをつけた。
次に、Xゾーンのカードが6枚以上の時に負けるようにする関数を、

 
pub fn situation_log(
    mut player1_hand: ResMut<Player1Hand>,
    mut player1_szone: ResMut<Player1SZone>,
    mut player1_fzone: ResMut<Player1FZone>,
    mut player2_szone: ResMut<Player2SZone>,
    mut player2_fzone: ResMut<Player2FZone>,
    mut player1_xzone: ResMut<Player1XZone>,
    mut player2_xzone: ResMut<Player2XZone>,
    query: Query<(Entity, &Card, &Location), With<Player1>>,
    query_opponent: Query<(Entity, &Card, &Location), With<Player2>>,
    mut check_event_reader: EventReader<CheckCard>,
    mut start_free_event_writer: EventWriter<StartFree>,
) {
    for _event in check_event_reader.read() {
        // プレイヤー1の手札をチェック
        player1_hand.cards.clear();
        player1_fzone.cards.clear();
        player1_szone.cards.clear();
        player1_xzone.cards.clear();

        for (entity, card, location) in query.iter() {
            if let Location::InHand = location {
                player1_hand.cards.push(entity);
            }
            if let Location::SZone = location {
                player1_szone.cards.push(entity);
            }
            if let Location::FZone = location {
                player1_fzone.cards.push(entity);
            }
            if let Location::XZone = location {
                player1_xzone.cards.push(entity);
            }
        }

        // プレイヤー2のSゾーンとFゾーンをチェック
        player2_szone.cards.clear();
        player2_fzone.cards.clear();
        player2_xzone.cards.clear();

        for (entity, card, location) in query_opponent.iter() {
            if let Location::SZone = location {
                player2_szone.cards.push(entity);
            }
            if let Location::FZone = location {
                player2_fzone.cards.push(entity);
            }
            if let Location::XZone = location {
                player2_xzone.cards.push(entity);
            }
        }
        println!("--- フィールド情報 ---");
        println!("プレイヤー1の手札: {:?}", player1_hand.cards);
        println!("プレイヤー1のSゾーン: {:?}", player1_szone.cards);
        println!("プレイヤー1のFゾーン: {:?}", player1_fzone.cards);
        println!("プレイヤー1のXゾーン: {:?}", player1_xzone.cards);

        println!("プレイヤー2のSゾーン: {:?}", player2_szone.cards);
        println!("プレイヤー2のFゾーン: {:?}", player2_fzone.cards);
        println!("プレイヤー2のXゾーン: {:?}", player2_xzone.cards);

        println!("フィールド情報の更新をしました");
        start_free_event_writer.send(StartFree);
    }
}

これに追加する。

if player1_xzone.cards.len() >= 6 {
            println!("プレイヤー1のXゾーンには6枚以上のカードがあります。");
           
            for (entity, card) in query_first_energy.iter() {
                commands.entity(entity).insert(Location::XZone);
                println!("プレイー1の{}がXゾーンに置かれました。", card.name);
            }
            game_over_event_writer.send(GameOver {
                winner_id: turn_player.non_turnplayer_id,
            });
            next_state.set(GameState::GameOver);
        }

        if player2_xzone.cards.len() >= 6 {
            println!("プレイヤー2のXゾーンには6枚以上のカードがあります。");
           
            for (entity, card) in query_first_energy_opponent.iter() {
                commands.entity(entity).insert(Location::XZone);
                println!("プレイー2の{}がXゾーンに置かれました。", card.name);
            }
            game_over_event_writer.send(GameOver {
                winner_id: turn_player.turnplayer_id,
            });
            next_state.set(GameState::GameOver);
        }

関数の中身しか変えてないのにmod.rsに

エラーが出てきたので、色々調べたら、意味不明な長文えらーが出てくる。

qiita.comらしい。だから、引数を減らそう

結局turn_playerの情報は必要ないと気付いたので、

そのまま入力する形にした。

pub fn situation_log(
    mut player1_hand: ResMut<Player1Hand>,
    mut player1_szone: ResMut<Player1SZone>,
    mut player1_fzone: ResMut<Player1FZone>,
    mut player2_szone: ResMut<Player2SZone>,
    mut player2_fzone: ResMut<Player2FZone>,
    mut player1_xzone: ResMut<Player1XZone>,
    mut player2_xzone: ResMut<Player2XZone>,
    query: Query<(Entity, &Card, &Location), With<Player1>>,
    query_opponent: Query<(Entity, &Card, &Location), With<Player2>>,
    query_first_energy: Query<(Entity, &Card), (With<Player1>, With<FirstEnergy>)>,
    query_first_energy_opponent: Query<(Entity, &Card), (With<Player2>, With<FirstEnergy>)>,
    mut next_state: ResMut<NextState<GameState>>,
    mut check_event_reader: EventReader<CheckCard>,
    mut start_free_event_writer: EventWriter<StartFree>,
    mut game_over_event_writer: EventWriter<GameOver>,
    mut commands: Commands,
) {
    for _event in check_event_reader.read() {
        // プレイヤー1の手札をチェック
        player1_hand.cards.clear();
        player1_fzone.cards.clear();
        player1_szone.cards.clear();
        player1_xzone.cards.clear();

        for (entity, card, location) in query.iter() {
            if let Location::InHand = location {
                player1_hand.cards.push(entity);
            }
            if let Location::SZone = location {
                player1_szone.cards.push(entity);
            }
            if let Location::FZone = location {
                player1_fzone.cards.push(entity);
            }
            if let Location::XZone = location {
                player1_xzone.cards.push(entity);
            }
        }

        // プレイヤー2のSゾーンとFゾーンをチェック
        player2_szone.cards.clear();
        player2_fzone.cards.clear();
        player2_xzone.cards.clear();

        for (entity, card, location) in query_opponent.iter() {
            if let Location::SZone = location {
                player2_szone.cards.push(entity);
            }
            if let Location::FZone = location {
                player2_fzone.cards.push(entity);
            }
            if let Location::XZone = location {
                player2_xzone.cards.push(entity);
            }
        }
        println!("--- フィールド情報 ---");
        println!("プレイヤー1の手札: {:?}", player1_hand.cards);
        println!("プレイヤー1のSゾーン: {:?}", player1_szone.cards);
        println!("プレイヤー1のFゾーン: {:?}", player1_fzone.cards);
        println!("プレイヤー1のXゾーン: {:?}", player1_xzone.cards);

        println!("プレイヤー2のSゾーン: {:?}", player2_szone.cards);
        println!("プレイヤー2のFゾーン: {:?}", player2_fzone.cards);
        println!("プレイヤー2のXゾーン: {:?}", player2_xzone.cards);
        if player1_xzone.cards.len() >= 6 {
            println!("プレイヤー1のXゾーンには6枚以上のカードがあります。");

            for (entity, card) in query_first_energy.iter() {
                commands.entity(entity).insert(Location::XZone);
                println!("プレイー1の{}がXゾーンに置かれました。", card.name);
            }
            game_over_event_writer.send(GameOver {
                winner_id: 2,
            });
            next_state.set(GameState::GameOver);
        }

        if player2_xzone.cards.len() >= 6 {
            println!("プレイヤー2のXゾーンには6枚以上のカードがあります。");

            for (entity, card) in query_first_energy_opponent.iter() {
                commands.entity(entity).insert(Location::XZone);
                println!("プレイー2の{}がXゾーンに置かれました。", card.name);
            }
            game_over_event_writer.send(GameOver {
                winner_id: 1,
            });
            next_state.set(GameState::GameOver);
        }
        println!("フィールド情報の更新をしました");
        start_free_event_writer.send(StartFree);
    }
}

 

 

そのあと、ゲームオーバーステートで以下を読み込むようにしました。

pub fn game_over(
    mut game_over_event_reader: EventReader<GameOver>,
    first_hand: Res<FirstHand>,
    query: Query<&Card>,
) {
    for event in game_over_event_reader.read() {
        println!("ゲームの勝者は、プレイヤー{}です", event.winner_id);
        let cards_list:Vec<String>= first_hand
        .cards
        .iter()
        .filter_map(|entity| query.get(*entity).ok().map(|card| card.name.clone()))
        .collect();
       
        println!("初期の手札は: {:?}でした", cards_list);
    }
}

デバッグする為に、敵のXゾーンに5枚カード追加して来る。
loadingに追加してきた。


    let my_entity = commands
        .spawn*3
        .id();

    println!("{:?} is spawned", my_entity);

    let my_entity = commands
        .spawn*4
        .id();

    println!("{:?} is spawned", my_entity);

    let my_entity = commands
        .spawn*5
        .id();

    println!("{:?} is spawned", my_entity);

    let my_entity = commands
        .spawn*6
        .id();

    println!("{:?} is spawned", my_entity);

 


ステートが変わっても動き続けてるので、mainのシステムにrun_ifをつける。

.run_if(in_state(GameState::Play)),

これつけてきた。

勝者を決めるところは、ターンプレイヤーにしたのでこれでいいんだけど
まだ、これもゲーム終了しても動いているので、直します。
setup_phaseのところも付けました

pub struct SetupPhasePlugin;
impl Plugin for SetupPhasePlugin {
    fn build(&self, app: &mut App) {
        app
        .insert_resource(Winner::default()).add_systems(
            OnEnter(PlayState::SetupPhase),
            (set_up_draw, respin_fzone_cards, respin_s_zone_cards, automatically_move_to_withdraw_state)
                .chain().run_if(in_state(GameState::Play)),
        );
    }
}
pub struct WithdrawPhasePlugin;
impl Plugin for WithdrawPhasePlugin {
    fn build(&self, app: &mut App) {
        app.insert_resource(FieldCondition::default())
            .add_event::<Withdraw>()
            .add_event::<PickFighter>()
            .add_event::<Rethink>()
            .add_systems(
                OnEnter(PlayState::WithdrawPhase),
                (
                    check_fzone_condition,
                    check_xzone_condition,
                    write_think_event,
                ).run_if(in_state(GameState::Play)),
            )
            .add_systems(
                Update,
                (transition_withdraw_state, withdraw, choose_fighther_to_withdraw).run_if(in_state(PlayState::WithdrawPhase)),
            );
    }
}


これで出来てそうです。
勝利条件の関数調整完了っぽいですね

 

プレイヤー2でやることの場合分けは、こういう風にやっていけば良さそうや。

pub fn toggle_simuation(
    keyboard_input: Res<ButtonInput<KeyCode>>,
    simulation_state: Res<State<SimulationState>>,
    mut next_state: ResMut<NextState<SimulationState>>,
) {
    if keyboard_input.just_pressed(KeyCode::Space) {
        match simulation_state.get(){
            SimulationState::Paused => {
                next_state.set(SimulationState::Running);
                println!("Running");
            }
            SimulationState::Running => {
                next_state.set(SimulationState::Paused);
                println!("Paused");
            }
        }
       
    }
}

こういう風に、現在のステートを取得して、そこから処理を決定する。

これをすれば、ターンプレイヤーごとで、処理を記述できる気がする。

pub fn change_turn_player(
    turn_player: ResMut<TurnPlayer>,
    mut next_state: ResMut<NextState<PlayState>>,
    mut next_turn_player: ResMut<NextState<Controller>>,
    controller: Res<State<Controller>>,
) {
    println!("{}のターン終了しました。", turn_player.turnplayer_id);
    match controller.get() {
        Controller::Opponent => {
            next_turn_player.set(Controller::Player);
        }
        Controller::Player => {
            next_turn_player.set(Controller::Opponent);
        }
    }
    next_state.set(PlayState::TurnStart);
}

これでいいな。

昼から帰ってきたら、プレイヤーが関係ある全部のシステムにこの場合分けしてくればいい

取り敢えず、loadingのところを見たら、問題はなかったので、set_upから直していこうと思う。


pub fn transition_mulligan_state(
    mulligan_state: Res<State<MulliganState>>,
    mut next_state: ResMut<NextState<MulliganState>>,
) {
    let choice = check_the_will_of_mulligan();

    match mulligan_state.get() {
        MulliganState::Default => match choice {
            1 => {
                println!("マリガン1回目です");
                next_state.set(MulliganState::First);
            }
            2 => {
                next_state.set(MulliganState::Over);
            }

            _ => {}
        },

        MulliganState::First => match choice {
            1 => {
                println!("マリガン2回目です");
                next_state.set(MulliganState::Second);
            }
            2 => {
                next_state.set(MulliganState::Over);
            }

            _ => {}
        },
        MulliganState::Second => {}

        MulliganState::Over => {}
    }
}

pub fn automatically_move_to_over_state(mut next_state: ResMut<NextState<MulliganState>>) {
    next_state.set(MulliganState::Over);
    println!("最終手札が確定しました")
}

とりあえず

.add_systems(
                OnEnter(GameState::Setup),
                (
                    return_all_hands_to_deck,
                    shuffle_deck,
                    draw_a_card,
                    draw_a_card,
                    draw_a_card,
                    draw_a_card,
                    draw_a_card,
                    show_hands,
                    transition_mulligan_state,
                )
                    .chain(),
            )
            .add_systems(
                OnEnter(MulliganState::First),
                (
                    return_all_hands_to_deck,
                    shuffle_deck,
                    draw_a_card,
                    draw_a_card,
                    draw_a_card,
                    draw_a_card,
                    draw_a_card,
                    show_hands,
                    transition_mulligan_state,
                )
                    .chain(),
            )
            .add_systems(
                OnEnter(MulliganState::Second),
                (
                    return_all_hands_to_deck,
                    shuffle_deck,
                    draw_a_card,
                    draw_a_card,
                    draw_a_card,
                    draw_a_card,
                    draw_a_card,
                    automatically_move_to_over_state,
                )
                    .chain(),
            )
            .add_systems(
                OnEnter(MulliganState::Over),
                (
                    check_last_hand,
                    choose_first,
                    first_energy_open,
                    automatically_move_to_play_state,
                )
                    .chain(),
            );

取り敢えずこれを見て思ったのが、リソースでマリガン回数をチェックして、
山札に戻して5枚引く処理のイベントと、マリガン終了イベントを作らないといけないと思った。

#[derive(Event)]
pub struct Mulligan;

#[derive(Event)]
pub struct MulliganFinish;

#[derive(Event)]
pub struct MulliganOpponent;

#[derive(Event)]
pub struct MulliganFinishOpponent;


#[derive(Default, Resource)]
pub struct MulliganCounter {
    pub counter: u32,
}
pub fn mulligan(
    query: Query<(Entity, &Card, &Location), With<Player1>>,
    mut commands: Commands,
    mut in_library_cards: ResMut<InLibraryCards>,
    mut mulligan_event_reader: EventReader<Mulligan>,
) {
    for event in mulligan_event_reader.read() {
        //手札を山に
        for (entity, card, location) in query.iter() {
            if let Location::InHand = location {
                commands.entity(entity).insert(Location::InLibrary); // 手札のカードをすべて山札に移動
                println!("{}, をデッキに戻しました", card.name);
                in_library_cards.cards.push(entity);
            }
        }
        //シャッフルする
        let mut rng = rand::rng();
        in_library_cards.cards.shuffle(&mut rng);
        println!("Shuffled cards in library:");
        //5枚引く
        for _ in 0..5 {
            if let Some(&top_card) = in_library_cards.cards.first() {
                if let Ok*7 = query.get(top_card) {
                    println!(
                        "あなたは {}, を引きました entity id: {:?},",
                        card.name, top_card
                    );
                    commands.entity(top_card).insert(Location::InHand);
                    in_library_cards.cards.remove(0); // 先頭のカードを削除
                } else {
                    println!("No cards available in the deck.");
                }
            } else {
                println!("デッキにカードがありません。");
            }
        }
        //手札を表示する。
        for (entity, card, location) in query.iter() {
            if let Location::InHand = location {
                println!("{}, ", card.name);
            }
        }
    }
}

 

pub fn transition_mulligan_state2(
    mut mulligan_counter: ResMut<MulliganCounter>,
    mut mulligan_event_writer: EventWriter<Mulligan>,
    mut finish_event_writer: EventWriter<MulliganFinish>,
) {
    // リソースを初期化
    mulligan_counter.counter = 0;

    loop {
        // イベントAを発信
        mulligan_event_writer.send(Mulligan);

        // ユーザーにはいかいいえを答えさせる
        if mulligan_counter.counter >= MAX_MULLIGAN_COUNT {
            println!("マリガンの回数が上限に達しました。");
            break; // ループを抜けてイベントBを発信
        }

        let choice = check_the_will_of_mulligan();

        match choice {
            1 => {
                // はい
                mulligan_counter.counter += 1;
                println!("マリガン{}回目です", mulligan_counter.counter);
            }
            2 => {
                // いいえ
                finish_event_writer.send(MulliganFinish);
                break; // ループを抜けて処理を終了
            }
            _ => {}
        }
    }

    // マリガンの回数が上限に達した場合、イベントBを発信
    finish_event_writer.send(MulliganFinish);
}

この二つの組み合わせで行ける。

で、この後の処理もまとめてみる。

.add_systems(
                OnEnter(MulliganState::Over),
                (
                    check_last_hand,
                    choose_first,
                    first_energy_open,
                    automatically_move_to_play_state,
                )
                    .chain(),
            );

これもまとめる。

非同期処理がうまくいってない
ループにしない方がいい。

4つの段階を踏んだ

 

  • マリガンスタート関数で、マリガンイベントを発生させる。
  • マリガンの処理を実行し、マリガンマネジメントイベントを発生させる。
  • マリガンマネジメントイベントで、はいいいえとマリガン回数をチェックするマリガンイベントか、マリガンフィニッシュイベントを出すようにする。
  • マリガンフィニッシュイベントを処理して、次のステートに行く。

結局4つのステートに悩みに悩んで変えたんだから、当たり前か。

pub const MAX_MULLIGAN_COUNT: u32 = 2;
pub fn mulligan_start(mut mulligan_event_writer: EventWriter<Mulligan>) {
    mulligan_event_writer.send(Mulligan);
}
pub fn mulligan(
    query: Query<(Entity, &Card, &Location), With<Player1>>,
    mut commands: Commands,
    mut in_library_cards: ResMut<InLibraryCards>,
    mut mulligan_event_reader: EventReader<Mulligan>,
    mut mulligan_management_event_writer: EventWriter<MulliganManagement>,
) {
    for event in mulligan_event_reader.read() {
        //手札を山に
        for (entity, card, location) in query.iter() {
            if let Location::InHand = location {
                commands.entity(entity).insert(Location::InLibrary); // 手札のカードをすべて山札に移動
                println!("{}, をデッキに戻しました", card.name);
                in_library_cards.cards.push(entity);
            }
        }
        //シャッフルする
        let mut rng = rand::rng();
        in_library_cards.cards.shuffle(&mut rng);
        println!("Shuffled cards in library:");
        //5枚引く
        for _ in 0..5 {
            if let Some(&top_card) = in_library_cards.cards.first() {
                if let Ok*8 = query.get(top_card) {
                    println!(
                        "あなたは {}, を引きました entity id: {:?},",
                        card.name, top_card
                    );
                    commands.entity(top_card).insert(Location::InHand);
                    in_library_cards.cards.remove(0); // 先頭のカードを削除
                } else {
                    println!("No cards available in the deck.");
                }
            } else {
                println!("デッキにカードがありません。");
            }
        }
        //手札を表示する。
        for (entity, card, location) in query.iter() {
            if let Location::InHand = location {
                println!("{}, ", card.name);
            }
        }
        mulligan_management_event_writer.send(MulliganManagement);
    }
}

pub fn check_the_will_of_mulligan() -> i32 {
    loop {
        println!("[1]:マリガンをする [2]:キープする");
        let mut input = String::new();
        io::stdin()
            .read_line(&mut input)
            .expect("Failed to read line");

        // 入力を整数に変換し、結果を返す
        match input.trim().parse::<i32>() {
            Ok(choice) if choice == 1 || choice == 2 => return choice,
            _ => println!("無効な選択です。もう一度入力してください。"),
        }
    }
}

pub fn mulligan_management(
    mut mulligan_counter: ResMut<MulliganCounter>,
    mut mulligan_event_writer: EventWriter<Mulligan>,
    mut finish_event_writer: EventWriter<MulliganFinish>,
    mut mulligan_management_event_reader: EventReader<MulliganManagement>,
) {
    // リソースを初期化
    for event in mulligan_management_event_reader.read() {
        if mulligan_counter.counter >= MAX_MULLIGAN_COUNT {
            println!("マリガンの回数が上限に達しました。");
            finish_event_writer.send(MulliganFinish);
            return;
        }

        let choice = check_the_will_of_mulligan();

        match choice {
            1 => {
                // はい
                mulligan_counter.counter += 1;
                println!("マリガン{}回目です", mulligan_counter.counter);
                // 次のイベントを発信
                mulligan_event_writer.send(Mulligan); // 必要に応じて次のイベントを発信
            }
            2 => {
                // いいえ
                finish_event_writer.send(MulliganFinish);
            }
            _ => {}
        }
    }

    // マリガンの回数が上限に達した場合、イベントBを発信
}

pub fn mulligan_finish(
    mut first_hand: ResMut<FirstHand>, // リソースとして受け取る
    query: Query<(Entity, &Card, &Location), With<Player1>>,
    mut first_player: ResMut<PlayerSort>,
    mut next_controller: ResMut<NextState<Controller>>,
    query_first_energy: Query<(Entity, &Card, &Location), With<FirstEnergy>>, // 正しい構文
    mut commands: Commands,
    mut next_state: ResMut<NextState<GameState>>,
    mut next_state2: ResMut<NextState<PlayState>>,
    mut finish_event_reader: EventReader<MulliganFinish>,
) {
    for event in finish_event_reader.read() {
        first_hand.cards.clear(); // 前回の結果をクリア
        println!("your first hands are:");

        for (entity, card, location) in query.iter() {
            if let Location::InHand = location {
                first_hand.cards.push(entity); // エンティティIDをリストに追加
                println!("{}, ", card.name);
            }
        }
        // 先行後攻決め

        let (turn_player, non_turn_player) = janken();

        first_player.firstplayer_id = turn_player;
        first_player.secondplayer_id = non_turn_player;
        match turn_player {
            1 => {
                next_controller.set(Controller::Player); // Player が先行の場合
            }
            2 => {
                next_controller.set(Controller::Opponent); // Opponent が先行の場合
            }
            _ => {
                println!("無効なプレイヤーIDです。");
            }
        }
        println!(
            "先行: Player {}, 後攻: Player {}",
            first_player.firstplayer_id, first_player.secondplayer_id,
        );
        //ファーストエナジーオープン
        println!("ファーストエナジーオープン!!");
        for (entity, card, location) in query_first_energy.iter() {
            commands.entity(entity).insert(FaceCondition::Open);
            println!("ファーストエナジーは、{}, です。", card.name)
        }
        //ステート移行
        next_state.set(GameState::Play);
        next_state2.set(PlayState::TurnStart);
        println!("対戦を開始します")
    }
}

これでやったら、

最初の1回目はなぜかもとからあったリトルナイトしか表示されなくて、困った。

同じ関数内で、クエリを複数回取得しても、クエリの中身は更新されないらしいので、
mulligan_managementの方でクエリを取得し、手札を表示する関数を書いた。

pub fn mulligan_management(
    mut mulligan_counter: ResMut<MulliganCounter>,
    mut mulligan_event_writer: EventWriter<Mulligan>,
    mut finish_event_writer: EventWriter<MulliganFinish>,
    mut mulligan_management_event_reader: EventReader<MulliganManagement>,
    query: Query<(Entity, &Card, &Location), With<Player1>>,
) {
    // リソースを初期化
    for event in mulligan_management_event_reader.read() {

        for (entity, card, location) in query.iter() {
            if let Location::InHand = location {
                println!("{}, ", card.name);
            }
        }

これでOKそうだね、
夕飯食ってくる。

戻ってきたけど、やることは、これの2P対応だね。

まずは、相手のデッキを5枚追加して来る。


    println!("{:?} is spawned", my_entity);

    let my_entity = commands
        .spawn*9
        .id();

    println!("{:?} is spawned", my_entity);

    let my_entity = commands
        .spawn*10
        .id();

    println!("{:?} is spawned", my_entity);

    let my_entity = commands
        .spawn*11
        .id();

    println!("{:?} is spawned", my_entity);

    let my_entity = commands
        .spawn*12
        .id();

    println!("{:?} is spawned", my_entity);

    let my_entity = commands
        .spawn*13
        .id();

    println!("{:?} is spawned", my_entity);

    let my_entity = commands
        .spawn*14
        .id();

    println!("{:?} is spawned", my_entity);


これでOK
対戦相手のマリガンも実装しよう。

単純にプレイヤー1マリガン→プレイヤー2マリガン→マリガンフィニッシュ

でよさそう。
取り敢えずそれで実装して、あとで、マリガンの相手ドローを追加する。


pub fn mulligan_opponent(
    query: Query<(Entity, &Card, &Location), With<Player2>>,
    mut commands: Commands,
    mut in_library_cards: ResMut<InLibraryCardsOpponent>,
    mut mulligan_finish_event_reader: EventReader<MulliganFinish>,
    mut mulligan_management_event_writer: EventWriter<MulliganManagementOpponent>,
) {
    for event in mulligan_finish_event_reader.read() {
        //手札を山に
        for (entity, card, location) in query.iter() {
            if let Location::InHand = location {
                commands.entity(entity).insert(Location::InLibrary); // 手札のカードをすべて山札に移動
                println!("{}, をデッキに戻しました", card.name);
                in_library_cards.cards.push(entity);
            }
        }
        //シャッフルする
        let mut rng = rand::rng();
        in_library_cards.cards.shuffle(&mut rng);
        println!("Shuffled cards in library:");
        //5枚引く
        for _ in 0..5 {
            if let Some(&top_card) = in_library_cards.cards.first() {
                if let Ok*15 = query.get(top_card) {
                    println!(
                        "あなたは {}, を引きました entity id: {:?},",
                        card.name, top_card
                    );
                    commands.entity(top_card).insert(Location::InHand);
                    in_library_cards.cards.remove(0); // 先頭のカードを削除
                } else {
                    println!("No cards available in the deck.");
                }
            } else {
                println!("デッキにカードがありません。");
            }
        }
        //手札を表示する。

        mulligan_management_event_writer.send(MulliganManagementOpponent);
    }
}

pub fn mulligan_management_opponent(
    mut mulligan_counter: ResMut<MulliganCounterOpponent>,
    mut mulligan_opponent_event_writer: EventWriter<MulliganOpponent>,
    mut finish_mulligan_opponent_event_writer: EventWriter<MulliganFinishOpponent>,
    mut mulligan_management_opponent_event_reader: EventReader<MulliganManagementOpponent>,
    query: Query<(Entity, &Card, &Location), With<Player2>>,
) {
    // リソースを初期化
    for event in mulligan_management_opponent_event_reader.read() {
        for (entity, card, location) in query.iter() {
            if let Location::InHand = location {
                println!("{}, ", card.name);
            }
        }

        if mulligan_counter.counter >= MAX_MULLIGAN_COUNT {
            println!("マリガンの回数が上限に達しました。");
            finish_mulligan_opponent_event_writer.send(MulliganFinishOpponent);
            return;
        }

        let choice = check_the_will_of_mulligan();

        match choice {
            1 => {
                // はい
                mulligan_counter.counter += 1;
                println!("マリガン{}回目です", mulligan_counter.counter);
                // 次のイベントを発信
                mulligan_opponent_event_writer.send(MulliganOpponent); // 必要に応じて次のイベントを発信
            }
            2 => {
                // いいえ
                finish_mulligan_opponent_event_writer.send(MulliganFinishOpponent);
            }
            _ => {}
        }
    }

    // マリガンの回数が上限に達した場合、イベントBを発信
}

そんなむずくなかった

出来てそう。

クエリが二つ同じものを参照してるから、それは直した。

マリガン1回目が上手くいっていないことに気付いたので、直す。
マリガンフィニッシュを読み込んじゃってるけど、元関数から、マリガンオポネントを送信させたら、治った。



また、ペナルティをつけたかったので、つける。


pub fn mulligan_penalty(
    mut mulligan_counter: ResMut<MulliganCounter>,
    mut mulligan_counter_opponent: ResMut<MulliganCounterOpponent>,
    query: Query<(Entity, &Card, &Location), With<Player1>>,
    query_opponent: Query<(Entity, &Card, &Location), With<Player2>>,
    mut commands: Commands,
    mut in_library_cards: ResMut<InLibraryCards>,
    mut in_library_cards_opponent: ResMut<InLibraryCardsOpponent>,
    mut mulligan_finish_event_writer: EventWriter<MulliganFinish>,
    mut mulligan_penalty_event_reader: EventReader<MulliganPenalty>
) {
    for event in mulligan_penalty_event_reader.read(){
        if mulligan_counter.counter >= MULLIGAN_PENALTY_COUNT {
            if let Some(&top_card) = in_library_cards_opponent.cards.first() {
                if let Ok*16 = query_opponent.get(top_card) {
                    println!(
                        "相手は {}, を引きました entity id: {:?},",
                        card.name, top_card
                    );
                    commands.entity(top_card).insert(Location::InHand);
                    in_library_cards_opponent.cards.remove(0); // 先頭のカードを削除
                } else {
                    println!("No cards available in the deck.");
                }
            } else {
                println!("デッキにカードがありません。");
            }
        }
        if mulligan_counter_opponent.counter >= MULLIGAN_PENALTY_COUNT {
            if let Some(&top_card) = in_library_cards.cards.first() {
                if let Ok*17 = query.get(top_card) {
                    println!(
                        "あなたは {}, を引きました entity id: {:?},",
                        card.name, top_card
                    );
                    commands.entity(top_card).insert(Location::InHand);
                    in_library_cards.cards.remove(0); // 先頭のカードを削除
                } else {
                    println!("No cards available in the deck.");
                }
            } else {
                println!("デッキにカードがありません。");
            }
        }
        mulligan_finish_event_writer.send(MulliganFinish);
    }
   

}

ちょっといったんできてそうなので寝る 表記は知らん。

*1:_, card, _

*2:_, card, _

*3:

            Card {
                name: String::from("策謀のエンジュ"),
                energy: 5,
            },
            Location::XZone,
            SpinCondition::ReSpin,
            FaceCondition::Open,
            Guard{},
            Fighter { power: 3000 , summoned_sick: true,},
            Player2 {},
       

*4:

            Card {
                name: String::from("参戦のガントッパ"),
                energy: 5,
            },
            Location::XZone,
            SpinCondition::ReSpin,
            FaceCondition::Open,
            Guard{},
            Fighter { power: 4000 , summoned_sick: true,},
            Player2 {},
       

*5:

            Card {
                name: String::from("灼熱旋風のランセ"),
                energy: 6,
            },
            Location::XZone,
            SpinCondition::ReSpin,
            FaceCondition::Open,
            Guard{},
            Fighter { power: 6000 , summoned_sick: true,},
            Player2 {},
       

*6:

            Card {
                name: String::from("大筒掃射のダイハッパ"),
                energy: 8,
            },
            Location::XZone,
            SpinCondition::ReSpin,
            FaceCondition::Open,
            Guard{},
            Fighter { power: 6000 , summoned_sick: true,},
            Player2 {},
       

*7:_, card, _

*8:_, card, _

*9:

            Card {
                name: String::from("決戦突破のダイコガネ"),
                energy: 8,
            },
            Location::InLibrary,
            SpinCondition::ReSpin,
            FaceCondition::Facedown,
            Guard{},
            Fighter { power: 8000 , summoned_sick: true,},
            Player2 {},
       

*10:

            Card {
                name: String::from("幽炎のラゲン"),
                energy: 6,
            },
            Location::InLibrary,
            SpinCondition::ReSpin,
            FaceCondition::Facedown,
            Guard{},
            Fighter { power: 5000 , summoned_sick: true,},
            Player2 {},
       

*11:

            Card {
                name: String::from("大龍将グレン・ブレイド"),
                energy: 10,
            },
            Location::InLibrary,
            SpinCondition::ReSpin,
            FaceCondition::Facedown,
            Guard{},
            Fighter { power: 10000 , summoned_sick: true,},
            Player2 {},
       

*12:

            Card {
                name: String::from("必勝成敗の式目"),
                energy: 0,
            },
            Location::SZone,
            SpinCondition::ReSpin,
            FaceCondition::Open,
            Tactics { required_energy: 6 },
            Player2 {},
       

*13:

            Card {
                name: String::from("煉獄"),
                energy: 2,
            },
            Location::InLibrary,
            SpinCondition::ReSpin,
            FaceCondition::Facedown,
            Tactics { required_energy: 5 },
            Player2 {},
       

*14:

            Card {
                name: String::from("ブレイジング・エリア"),
                energy: 0,
            },
            Location::InLibrary,
            SpinCondition::ReSpin,
            FaceCondition::Facedown,
            Tactics { required_energy: 4 },
            Player2 {},
       

*15:_, card, _

*16:_, card, _

*17:_, card, _