Behind Coleus

大学生なのに特別大学で楽しいことが一 つもない。虐待と男子校病のせいにしてみる。→日本脱出しました 今ジャカルタにいます。→ジャカルタから帰ってきました。

戦い13

カード情報がクエリで更新されない問題はちょっとわからなかったので

飛ばして、もうメインに行きます。

メインは同じイベントを飛ばして、ステートで制御すればいいかなと思った。

ターンスタートについて

pub fn turn_start(mut turn_count: ResMut<TurnCount>) {
    turn_count.value += 1;
    println!("現在{}ターン目です", turn_count.value);

}
pub fn automatically_move_to_setup_phase(mut next_state: ResMut<NextState<PlayState>>) {
    next_state.set(PlayState::SetupPhase);
    println!("準備フェーズになりました")
}

これでいいか。別に分ける必要もないような気がする。

次準備フェーズこれは分ける必要があるかもしれない。

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)),
        );
    }
}

チェインしてるのを、イベントに分ける。

#[derive(Event)]
pub struct SetupDraw;

#[derive(Event)]
pub struct RespinFzone;

#[derive(Event)]
pub struct RespinSzone;


これを取り敢えず登録。

pub struct SetupPhasePlugin;
impl Plugin for SetupPhasePlugin {
    fn build(&self, app: &mut App) {
        app.add_event::<SetupDraw>()
            .add_event::<RespinFzone>()
            .add_event::<RespinSzone>()
            .insert_resource(Winner::default())
            .add_systems(
                OnEnter(PlayState::SetupPhase),
                set_up_start.run_if(in_state(GameState::Play)),
            )
            .add_systems(Update, (set_up_draw, respin_fzone_cards,respin_szone_cards).run_if(in_state(Controller::Player)));
    }
}

既存の関数をchainから、Update+イベントの順序に変更

先行取った時は、動く

後攻では動かない。
OK
これに後攻用の関数を足していけばよい。


pub fn set_up_draw_opponent(
    query: Query<(Entity, &Card, &Location)>, // クエリとして受け取る
    mut in_library_cards: ResMut<InLibraryCardsOpponent>, // ミュータブル参照として受け取る
    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>,
    mut set_up_draw_event_reader: EventReader<SetupDraw>,
    mut respin_fzone_event_writer: EventWriter<RespinFzone>,
) {
    for event in set_up_draw_event_reader.read() {
        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;
                game_over_event_writer.send(GameOver {
                    winner_id: winner.winner_id,
                });
                println!("{}, の勝利です", winner.winner_id,);
                next_state.set(GameState::GameOver)
            }
        }
        respin_fzone_event_writer.send(RespinFzone);
    }
}

pub fn respin_fzone_cards_opponent(
    query: Query<
        (Entity, &Card, &Location, &SpinCondition, &Fighter),
        (With<Fighter>, With<Player2>),
    >,
    // プレイヤー1の&Fighter を取得
    mut commands: Commands,
    mut respin_fzone_event_reader: EventReader<RespinFzone>,
    mut respin_szone_event_writer: EventWriter<RespinSzone>
) {
    for event in respin_fzone_event_reader.read(){
        for (entity, card, location, spincondition, fighter) in query.iter() {
            // mut ではなく、immutable で取得
            if let Location::FZone = location {
                if let SpinCondition::Spin = spincondition {
                    commands.entity(entity).insert(SpinCondition::ReSpin);
                    println!("{}, をリスピンしました", card.name);
                }
   
                // Fighter コンポーネントを新しい summoned_sick で更新
                commands.entity(entity).insert(Fighter {
                    summoned_sick: false,
                    ..*fighter
                }); // power はそのまま
                println!("{}, はアタックできます", card.name);
            }
        }
        respin_szone_event_writer.send(RespinSzone);
    }
   
}

pub fn respin_szone_cards_opponent(
    query: Query<(Entity, &Card, &Location, &SpinCondition), With<Player2>>,
    mut commands: Commands,
    mut respin_szone_event_reader: EventReader<RespinSzone>,
    mut next_state: ResMut<NextState<PlayState>>
) {
    for event in respin_szone_event_reader.read(){
        for (entity, card, location, spincondition) in query.iter() {
            if let Location::SZone = location {
                if let SpinCondition::Spin = spincondition {
                    commands.entity(entity).insert(SpinCondition::ReSpin);
                    println!("{}, をリスピンしました", card.name);
                }
            }
        }
        next_state.set(PlayState::WithdrawPhase);
    }
   
}

取り敢えず、ちょっとだけ変えた関数を作った。
プレイヤー2のクエリに変更したり、in library をinlibrarycardsopponentから取ったりした。

pub struct SetupPhasePlugin;
impl Plugin for SetupPhasePlugin {
    fn build(&self, app: &mut App) {
        app.add_event::<SetupDraw>()
            .add_event::<RespinFzone>()
            .add_event::<RespinSzone>()
            .insert_resource(Winner::default())
            .add_systems(
                OnEnter(PlayState::SetupPhase),
                set_up_start.run_if(in_state(GameState::Play)),
            )
            .add_systems(Update, (set_up_draw, respin_fzone_cards,respin_szone_cards).run_if(in_state(Controller::Player)))
            .add_systems(Update, (set_up_draw_opponent, respin_fzone_cards_opponent,respin_szone_cards_opponent).run_if(in_state(Controller::Opponent)));
    }
}

それをこういう感じで登録。

行けてそう。

帰ったら、撤退フェーズもやるわ。

帰ってきたので、撤退フェーズやるか。。。 プヨグラミングばっかりしてたら教授にキレられましたね。


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)),
            );
    }
}
pub fn check_fzone_condition(
    query: Query<(&Card, &Location), With<Player1>>,
    mut field_conditon: ResMut<FieldCondition>,
) {
    // クエリで取得したカードをチェック
    for (card, location) in query.iter() {
        if let Location::FZone = location {
            field_conditon.has_fzone_card = true;
            println!("Fゾーンにカードが見つかりました"); // FZoneのカードが見つかった場合
            break;
        }
    }
}

pub fn check_xzone_condition(
    query: Query<(&Card, &Location), With<Player1>>,
    mut field_conditon: ResMut<FieldCondition>,
) {
    // クエリで取得したカードをチェック
    for (card, location) in query.iter() {
        if let Location::XZone = location {
            field_conditon.has_xzone_card = true;
            println!("Xゾーンにカードが見つかりました"); // FZoneのカードが見つかった場合
            break;
        }
    }
}

pub fn write_think_event(mut rethink_event_writer: EventWriter<Rethink>) {
    rethink_event_writer.send(Rethink);
}

これを一つにまとめる。
いままではrethink event writerから、transition_withdraw_stateから行ってて分かりにくかったから、withdrawmanagementみたいな名前にする。

pub fn check_condition(
    query: Query<(&Card, &Location), With<Player1>>,
    mut field_conditon: ResMut<FieldCondition>,
    mut check_condition_event_reader: EventReader<CheckCondition>,
    mut withdraw_management_event_writer: EventWriter<WithdrawManagement>,
) {
    for event in check_condition_event_reader.read(){
        for (card, location) in query.iter() {
            if let Location::FZone = location {
                field_conditon.has_fzone_card = true;
                println!("Fゾーンにカードが見つかりました"); // FZoneのカードが見つかった場合
                break;
            }
        }
        for (card, location) in query.iter() {
            if let Location::XZone = location {
                field_conditon.has_xzone_card = true;
                println!("Xゾーンにカードが見つかりました"); // FZoneのカードが見つかった場合
                break;
            }
        }
        withdraw_management_event_writer.send(WithdrawManagement);
    }
}

3つの関数を一つにまとめた。


pub fn withdraw_management(
    mut next_state: ResMut<NextState<PlayState>>,
    mut choose_new_card_event_writer: EventWriter<PickFighter>,
    field_conditon: ResMut<FieldCondition>,
    mut withdraw_management_event_reader: EventReader<WithdrawManagement>
) {
    for event in withdraw_management_event_reader.read() {
        let choice = check_the_will_of_withdraw();

        match choice {
            1 => {
                if field_conditon.has_fzone_card {
                    println!("撤退できます");
                    choose_new_card_event_writer.send(PickFighter);
                } else {
                    if field_conditon.has_xzone_card {
                        println!("Fゾーンにカードが無いのでXフェーズに移行します");
                        next_state.set(PlayState::XPhase)
                    } else {
                        println!(
                            "Xゾーンにカードが無いのでXフェーズをスキップしてメインフェーズに移行します"
                        );
                        next_state.set(PlayState::XPhase)
                    }
                }
            }
            2 => {
                if field_conditon.has_xzone_card {
                    println!("Xフェーズに移行します");
                    next_state.set(PlayState::XPhase);
                } else {
                    println!(
                        "Xゾーンにカードが無いのでXフェーズをスキップしてメインフェーズに移行します"
                    );
                    next_state.set(PlayState::MainPhase);
                }
            }

            _ => {}
        }
    }
}

イベントリーダーの名前と関数名を変えた。

pub fn withdraw_start(mut check_condition_event_writer: EventWriter<CheckCondition>){
    check_condition_event_writer.send(CheckCondition);
}

また、これで最初は対応した。

pub fn withdraw_management(
    mut next_state: ResMut<NextState<PlayState>>,
    mut choose_new_card_event_writer: EventWriter<PickFighter>,
    field_conditon: ResMut<FieldCondition>,
    mut withdraw_management_event_reader: EventReader<WithdrawManagement>
) {
    for event in withdraw_management_event_reader.read() {
        let choice = check_the_will_of_withdraw();

        match choice {
            1 => {
                if field_conditon.has_fzone_card {
                    println!("撤退できます");
                    choose_new_card_event_writer.send(PickFighter);
                } else {
                    if field_conditon.has_xzone_card {
                        println!("Fゾーンにカードが無いのでXフェーズに移行します");
                        next_state.set(PlayState::XPhase)
                    } else {
                        println!(
                            "Xゾーンにカードが無いのでXフェーズをスキップしてメインフェーズに移行します"
                        );
                        next_state.set(PlayState::XPhase)
                    }
                }
            }
            2 => {
                if field_conditon.has_xzone_card {
                    println!("Xフェーズに移行します");
                    next_state.set(PlayState::XPhase);
                } else {
                    println!(
                        "Xゾーンにカードが無いのでXフェーズをスキップしてメインフェーズに移行します"
                    );
                    next_state.set(PlayState::MainPhase);
                }
            }

            _ => {}
        }
    }
}

イベントの名前もわかりにくかったから直す。

とりあえず、同じように成り立ってそうでよかった。

これで、相手プレイヤーのシステムも作っていく。

use bevy::prelude::*;

#[derive(Default, Resource)] // Resourceトレイトを使ってリソースにする
pub struct FieldCondition {
    pub has_fzone_card: bool,
    pub has_xzone_card: bool,
}

#[derive(Default, Resource)] // Resourceトレイトを使ってリソースにする
pub struct FieldConditionOpponent {
    pub has_fzone_card: bool,
    pub has_xzone_card: bool,
}

必要ない気もするけど相手の分もリソースにした。

withdraw finishっていう、撤退時の効果を処理するためのイベントは作っておいた。

pub fn withdraw(
    mut withdraw_event_reader: EventReader<Withdraw>,
    mut withdraw_management_event_writer: EventWriter<WithdrawManagement>,
    query: Query<(&Card, &Location), With<Player1>>,
    mut commands: Commands,
    field_conditon: ResMut<FieldCondition>,
    mut next_state: ResMut<NextState<PlayState>>,
    mut withdraw_finish_event_writer: EventWriter<WithdrawFinish>,
) {
    for event in withdraw_event_reader.read() {
        let mut sum_of_energy = 0;
        for (card, location) in query.iter() {
            if let Location::SZone = location {
                sum_of_energy += card.energy;
                println!("{} {}", card.name, sum_of_energy);
            }
        }

        println!(
            "あなたのSゾーンのエナジーの合計は、{}です。",
            sum_of_energy
        );

        if let Ok*2 = query.get(event.id) {
            sum_of_energy += card.energy;
            if sum_of_energy > 10 {
                println!(
                    "このカードはエナジーが大きすぎて、撤退できません。もう一度選びなおしてください"
                );
                withdraw_management_event_writer.send(WithdrawManagement);
            } else {
                println!("{}を撤退させました", card.name);
                commands.entity(event.id).insert(Location::SZone);
                withdraw_finish_event_writer.send(WithdrawFinish{id: event.id});
                if field_conditon.has_xzone_card {
                    println!("Xフェーズです");
                    next_state.set(PlayState::XPhase);
                } else {
                    println!("Xゾーンにカードが無いので、スキップします。");
                    println!("メインフェーズです");
                    next_state.set(PlayState::MainPhase);
                }
            }
        } else {
            // エンティティが見つからない場合の処理
            println!(
                "Entity ID: {:?} has no components or does not exist.",
                event.id
            );
        }
    }
}
check_condition, withdraw_management, pick_fighter_to_withdraw,  withdraw

この4つの関数にopponentのverを作って引数のリソースをWithPlayer2にしたりリソースをconditionopponentにしたりした。

.add_systems(
                Update,
                (
                    check_condition,
                    withdraw_management,
                    pick_fighter_to_withdraw,
                    withdraw,
                )
                    .run_if(in_state(Controller::Player)),
            )
            .add_systems(
                Update,
                (
                    check_condition_opponent,
                    withdraw_management_opponent,
                    pick_fighter_to_withdraw_opponent,
                    withdraw_opponent,
                )
                    .run_if(in_state(Controller::Opponent)),
            );

こういうふうにイベントは共有しつつステートで分ける処理でやってみた。
どうでしょう?

多分動いてるわ。
Xフェーズの間は、そりゃ何も触ってないんだから、Player1のカードになる。
Xフェーズの二人化やってきますか。

Xスキルは、カードを選ぶかどうかが、ファーストエナジーごとに違うので、Xスキルを使いますか?使います。で、イベントを送って、それで、特定のカードを使いました。
終わりの方がいいかもしれない。
オープンするカードは、リストであとで送ればいい。

#[derive(Event)]
pub struct Xskill{
    pub first_energy_id: Entity,
}

#[derive(Event)]
pub struct OpenedCards{
    pub opened_cards: Vec<Entity>,
}

書き換えた。

pub struct XPhasePlugin;
impl Plugin for XPhasePlugin {
    fn build(&self, app: &mut App) {
        app.insert_resource(FacedownXZoneCards::default())
            .add_event::<PickXzone>()
            .add_event::<Xskill>()
            .add_systems(
                OnEnter(PlayState::XPhase),
                (
                    list_facedown_cards_in_xzone,
                    transition_x_phase,
                ).chain(),
            )
            .add_systems(
                Update,
                (select_facedown_card, xskill).run_if(in_state(PlayState::XPhase)),
            );
    }
}

 


pub fn transition_x_phase(
    mut next_state: ResMut<NextState<PlayState>>,
    in_xzone_card: ResMut<FacedownXZoneCards>,
    mut pick_xzone_event_writher: EventWriter<PickXzone>,
) {
    let choice = check_the_will_of_xskill();

    match choice {
        1 => {
            if in_xzone_card.cards.is_empty() {
                println!("Xゾーンに裏側のカードがありません。メインフェーズに移行します。");
                next_state.set(PlayState::MainPhase);
            } else {
                pick_xzone_event_writher.send(PickXzone);
                println!("オープンするXゾーンのカードを選んでください。");
            }
        }
        2 => {
            println!("メインフェーズに移行します。");
            next_state.set(PlayState::MainPhase);
        }

        _ => {}
    }
}

この関数を改造して、最初に自分のファーストエナジーの名前を表示させる。使用するXゾーンのファーストエナジーを格納した、イベントを書けばいい。

効果は調整中でいい

 

裏を表向きにする作業は、いくつかの問題がある。Xリターンを後に考えた時、どれがどのカードか分からないという情報は必要である。

つまり何がいいたいかというと、クエリでカードリストを追加しちゃうと毎回entityid順になっちゃうから、Xリターンであたりか外れかは、裏向きで分からないってこと。

pub fn xskill(
    mut xskill_event_reader: EventReader<Xskill>,
    mut commands: Commands,
    mut next_state: ResMut<NextState<PlayState>>,
    query: Query<(Entity, &Card), (With<FirstEnergy>, With<Player1>)>,
) {
    for event in xskill_event_reader.read() {
        if let Ok*3= query.get(event.first_energy_id){
            println!("{}のXスキルは調整中です。", card.name)
        }

    }
}
デザイン発表の草稿を提出したら
過去の発表に比べて劣ってるとどやされたので、それをもとに再提出したら、参考文献にしかケチつかなかったんだけど、どうなってる?
pub fn select_a_facedown_card(in_xzone_card: ResMut<FacedownXZoneCards>) -> Entity {
    println!("Select a card by number (1-{}):", in_xzone_card.cards.len());

    loop {

        let mut input = String::new();
        std::io::stdin()
            .read_line(&mut input)
            .expect("Failed to read line");

        if let Ok(selected_index) = input.trim().parse::<usize>() {
            if selected_index > 0 && selected_index <= in_xzone_card.cards.len() {
                let selected_entity = in_xzone_card.cards[selected_index - 1];
                return selected_entity; // 有効な選択が行われた場合に返す
            } else {
                println!(
                    "Invalid selection. Please enter a number between 1 and {}.",
                    in_xzone_card.cards.len()
                );
            }
        } else {
            println!("Please enter a valid number.");
        }
    }
}


pub fn xskill(
    mut xskill_event_reader: EventReader<Xskill>,
    mut commands: Commands,
    mut next_state: ResMut<NextState<PlayState>>,
    query: Query<(Entity, &Card), (With<FirstEnergy>, With<Player1>)>,
) {
    for event in xskill_event_reader.read() {
        if let Ok*4 = query.get(event.first_energy_id) {
            println!("{}のXスキルは調整中です。", card.name)
        }
        next_state.set(PlayState::MainPhase);
    }
}
こういう風に過去の関数を作り直した。
後で必要になるのが、選択したidに合わせて、場合分けする関数や。多分関数で何個も作って、それを場合分けで呼び出せば、Xスキルは実装できる。
取り敢えず
pub struct XPhasePlugin;
impl Plugin for XPhasePlugin {
    fn build(&self, app: &mut App) {
        app.insert_resource(FacedownXZoneCards::default())
            .insert_resource(FacedownXZoneCardsOpponent::default())
            .add_event::<Xskill>()
            .add_event::<ListFacedownCardsInXzone>()
            .add_event::<XPhaseManagement>()
            .add_systems(OnEnter(PlayState::XPhase), x_phase_start)
            .add_systems(
                Update,
                (xskill, list_facedown_cards_in_xzone, x_phase_management)
                    .run_if(in_state(PlayState::XPhase)),
            );
    }
}
こういう風に入れて、やってみる。
 

OKそうだな。
 
pub fn list_facedown_cards_in_xzone(
    query: Query<(Entity, &Card, &Location, &FaceCondition), With<Player1>>,
    mut in_xzone_card: ResMut<FacedownXZoneCards>,
    mut list_facedown_cards_in_xzone_event_reader: EventReader<ListFacedownCardsInXzone>,
    mut x_phase_management_event_writer: EventWriter<XPhaseManagement>,
) {
    for event in list_facedown_cards_in_xzone_event_reader.read() {
        println!("Facedown cards in XZone are:");

        // 裏向きのカードをリストアップ ただ、順番が滅茶滅茶な事に注意!!これはデバッグ用の機能
        for (entity, card, location, face_condition) in query.iter() {
            if let Location::XZone = location {
                if let FaceCondition::Facedown = face_condition {
                    in_xzone_card.cards.push(entity); // エンティティIDを保存
                    println!("{}: {}", in_xzone_card.cards.len(), card.name); // 番号を振って表示
                }
            }
        }
        x_phase_management_event_writer.send(XPhaseManagement);
    }
}
 
 これ、もともとクエリにWith Player1がついてなくて、バグりガチだったけど直した。

あとは、それぞれ複製して、引数をいじった。
.add_systems(
                Update,
                (xskill_opponent, list_facedown_cards_in_xzone_opponent, x_phase_management_opponent)
                    .run_if(in_state(Controller::Opponent)),
            );
これでOK

OKそう
昨日か一昨日Xゾーンに追加したカードは全部オープン状態だったから、これで正解や。

*1:_, card, _

*2:card, location

*3:entity, card

*4:entity, card