Behind Coleus

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

戦い9

今日は朝からあまり体調がよくない。

昨日作ったカルボナーラ食べる前に、賞味期限が5日キレた牛乳を一気飲みしたのと、
19時以降に結構活動してたのがよくなかったかもしれない。

ご飯炊いてみたはいいけど、おなかがすいていない。

 

今日の目標メインフェーズの実装をする。

目的への取り組み

 

フリーステート

  • デフォルトである
  • 相手の各領域にあるカードについての情報を表示する。
  • 自分の各領域にあるカードについての情報を表示する。
  • 入力を受け付け、ターンエンドに移行できるようにする。
  • 条件を確認し、プレイできるカードや、攻撃できるファイターの選択肢を表示する。
  • 入力を受け付け、カードプレイステートに移行する
  • 入力を受け付け、バトルステートに移行する。

brogmymxo.hatenablog.comやることとしては、結構ある。

 

  • カードのオーナーの設定をしないといけない。←プレイステート全体の修正にもつながってくる。
  • ファイターの召喚酔いを設定しないといけない。←準備フェーズ
  • タクティクスの実装。←必要エナジーというのをどう実装するか

 

 

とりあえず、フリーステートから作っていく。

まずは、ステートを作っておくか、


#[derive(States, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum MainPhaseState {
    #[default]
    Free,
    Battle,
    CardPlay,
}

pub struct MainPhasePlugin;
impl Plugin for MainPhasePlugin {
    fn build(&self, app: &mut App) {
        app.init_state::<MainPhaseState>()
            .add_systems(
                OnEnter(PlayState::MainPhase),
                (list_facedown_cards_in_xzone, transition_x_phase).chain(),
            )
            .add_systems(
                Update,
                (select_facedown_card, xskill).run_if(in_state(PlayState::XPhase)),
            );
    }
}

取り敢えずはファイル階層は、

これのシステムにコードを書いていけばいい。

あとで、分割はする。

とりあえずやることは、元のコードを修正しなくてもかける、ステートの移行関数を書いていこう←コピペでOK


pub fn check_the_will_of_turn_end() -> i32 {
    loop {
        println!("[1]:メインフェーズを続ける [0]:ターンエンドする");
        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 == 0 => return choice,
            _ => println!("無効な選択です。もう一度入力してください。"),
        }
    }
}

pub fn transition_turn_end(
    mut next_state: ResMut<NextState<PlayState>>,
    mut start_free_event_reader: EventReader<StartFree>,
    mut choose_card_event_writer: EventWriter<ChooseCard>,
) {
    for event in start_free_event_reader.read() {
        let choice = check_the_will_of_turn_end();

        match choice {
            1 => {
                choose_card_event_writer.send(ChooseCard);
            }
            0 => {
                println!("ターンエンドしました");
                next_state.set(PlayState::TurnEnd);
            }

            _ => {}
        }
    }
}

pub fn start_free(mut start_free_event_writer: EventWriter<StartFree>){
    start_free_event_writer.send(StartFree);
}

取り敢えず、初期のこれを作った。

動いているね

 

Fゾーンのファイター選んだら、バトルステートに行ってほしいから、それも後回しかな。

ファイターの実装とかをちょっと変える。

じゃあやりますか、タクティクス行こうぜ!!

#[derive(Component)]
pub struct Card {
    pub power: Option<u32>,
    pub name: String,
    pub energy: u32,
}

元々こうなっていたんだけど、Cardに必要なのは、(ライジングを考えなければ)

名前とエナジーだけだ。

だから、powerはファイターコンポーネントに移譲して、

タクティクス特有の必要エナジーもタクティクスコンポーネントに入れる。
これにより多分Withが使いやすくなる。

取り敢えず、タクティクスと召喚酔いの実装してる。


#[derive(Component)]
pub struct Fighter {
    pub power: u32,
    pub summoned_sick: bool,
}
#[derive(Component)]
pub struct Tactics {
    pub required_energy: u32,
}

これでコンポーネントの中身をいれた。

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

    println!("{:?} is spawned", my_entity);
let my_entity = commands
        .spawn*2
        .id();

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

こんな風にFighterに格納する形で、powerと召喚酔いの情報を入力することにした。

 

そして、リスピン関数もちょっと改造する。

pub fn respin_s_zone_cards(
    query: Query<(Entity, &Card, &Location, &SpinCondition)>,
    mut commands: Commands,
) {
    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);
            }
        }
    }
}
pub fn respin_fzone_cards(
    query: Query<(Entity, &Card, &SpinCondition, &Fighter), With<Fighter>>, // &Fighter を取得
    mut commands: Commands,
) {
    for (entity, card, spincondition, fighter) in query.iter() { // mut ではなく、immutable で取得
        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);

        }
    }
}

 

そしたら、Sゾーンをリスピンするシステムが動いていないことと、Sゾーンのカードもなぜか召喚酔いが解除されているので修正

for (entity, card,location, fighter) in query.iter() { // mut ではなく、immutable で取得
        if let Location::FZone = location {
            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);

        }
    }

Okkと思ったけど、アサシンタイクーンはリスピン状態なので、2重リスピンしてて、キモい。

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

このように場合分けを追加した。



よし、これで、アタックの実装始められる。と思ったけど、相手プレイヤーのカードも追加しとかないとだめだわ。
スピン状態のFゾーンのファイター、
Sゾーンのファイター、Sゾーンのファーストエナジー、Sゾーンのタクティクス
この4種類を導入しないといけない。

pub fn opponent_setup_deck(mut commands: Commands) {
    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);
}
pub fn opponent_setup_first_energy(mut commands: Commands) {
    let my_entity = commands
        .spawn*7
        .id();

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

   
}



こんな感じでカードを追加した。追記必勝成敗の式目がPlayer1だった。

 


スピン状態の相手ファイターが欲しいから、スピンの関数をちょっと調整した。

pub fn respin_s_zone_cards(
    query: Query<(Entity, &Card, &Location, &SpinCondition), With<Player1>>,
    mut commands: Commands,
) {
    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);
            }
        }
    }
}
pub fn respin_fzone_cards(
    query: Query<(Entity, &Card, &Location, &SpinCondition, &Fighter), (With<Fighter>, With<Player1>)>,
    // プレイヤー1の&Fighter を取得
    mut commands: Commands,
) {
    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);
        }
    }
}

また、相手とデッキが混ざらないように、

pub fn my_cards_in_deck(
    mut in_library_cards: ResMut<InLibraryCards>, // リソースとして受け取る
    query: Query<(Entity, &Card, &Location), With<Player1>>,
) {
    in_library_cards.cards.clear(); // 前回の結果をクリア
    println!("Cards in your deck are:");

    for (entity, card, location) in query.iter() {
        if let Location::InLibrary = location {
            in_library_cards.cards.push(entity); // エンティティIDをリストに追加
            println!("{}, ", card.name);
        }
    }
}

デッキのカードは、With<Player1>を取った。これを確認する為に、Player2のデッキのカードも1枚追加しとく

カード混ざってない。OKKK

まぁちょっと腹立つけど、ファーストエナジーオープンの掛け声はforループの外に出しておこう。

ここも混ざってないし、多分OKやろ。

やるべきことは、手札のカードと、Fゾーンの召喚酔いしていないファイターのリストアップ。それで選択したら、イベントを出す。

取り敢えず、状況記述関数で、状況を記述する。
状況記述すべき内容は

player1の手札の内容、player1と2のSゾーンの状況 player1と2のFゾーンの状況

取り敢えず、


pub fn check_player_hand( mut player1_hand: ResMut<Player1Hand>, // リソースとして受け取る
    query: Query<(Entity, &Card, &Location), With<Player1>>,
    mut check_event_reader: EventReader<CheckCard>
) {
    for event in check_event_reader.read(){
        player1_hand.cards.clear(); // 前回の結果をクリア

        for (entity, card, location) in query.iter() {
            if let Location::InHand = location {
                player1_hand.cards.push(entity); // エンティティIDをリストに追加
            }
        }
    }
   
}

pub fn check_player_szone( mut player1_szone: ResMut<Player1SZone>, // リソースとして受け取る
    query: Query<(Entity, &Card, &Location), With<Player1>>,
    mut check_event_reader: EventReader<CheckCard>
) {
    for event in check_event_reader.read(){
        player1_szone.cards.clear(); // 前回の結果をクリア

        for (entity, card, location) in query.iter() {
            if let Location::SZone = location {
                player1_szone.cards.push(entity); // エンティティIDをリストに追加
            }
        }
    }
   
}

pub fn check_player_fzone( mut player1_fzone: ResMut<Player1FZone>, // リソースとして受け取る
    query: Query<(Entity, &Card, &Location), With<Player1>>,
    mut check_event_reader: EventReader<CheckCard>
) {
    for event in check_event_reader.read(){
        player1_fzone.cards.clear(); // 前回の結果をクリア

        for (entity, card, location) in query.iter() {
            if let Location::SZone = location {
                player1_fzone.cards.push(entity); // エンティティIDをリストに追加
            }
        }
    }
   
}

pub fn check_opponent_szone( mut player2_szone: ResMut<Player2SZone>, // リソースとして受け取る
    query: Query<(Entity, &Card, &Location), With<Player2>>,
    mut check_event_reader: EventReader<CheckCard>
) {
    for event in check_event_reader.read(){
        player2_szone.cards.clear(); // 前回の結果をクリア

        for (entity, card, location) in query.iter() {
            if let Location::SZone = location {
                player2_szone.cards.push(entity); // エンティティIDをリストに追加
            }
        }
    }
   
}

pub fn check_opponent_fzone( mut player2_fzone: ResMut<Player2FZone>, // リソースとして受け取る
    query: Query<(Entity, &Card, &Location), With<Player2>>,
    mut check_event_reader: EventReader<CheckCard>
) {
    for event in check_event_reader.read(){
        player2_fzone.cards.clear(); // 前回の結果をクリア

        for (entity, card, location) in query.iter() {
            if let Location::SZone = location {
                player2_fzone.cards.push(entity); // エンティティIDをリストに追加
            }
        }
    }
   
}

今まで使っていた関数をまねて、作ってみたんだけど、分かりにくいから、
5つ同時に作れる関数をGPTに作ってもらった。

pub fn check_player_zones(
    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>,
    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();
        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);
            }
        }

        // プレイヤー2のSゾーンとFゾーンをチェック
        player2_szone.cards.clear();
        player2_fzone.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);
            }
        }
        start_free_event_writer.send(StartFree);
    }
}

これでOKじゃない?と思ったけど、カードを表示しなきゃダメだと気付いて、

println!("--- フィールド情報 ---");
        println!("プレイヤー1の手札: {:?}", player1_hand.cards);
        println!("プレイヤー1のSゾーン: {:?}", player1_szone.cards);
        println!("プレイヤー1のFゾーン: {:?}", player1_fzone.cards);
        println!("プレイヤー2のSゾーン: {:?}", player2_szone.cards);
        println!("プレイヤー2のFゾーン: {:?}", player2_fzone.cards);

これを入れた。

各種リソース イベントをインサートした。

出来た気がするけど、

entityの名前じゃわからないよねー 正直この部分はUIだから、別にいいんじゃねとは思う。ただ、俺にもどれがどのカードかわからん。
一回無視する。これは、今回の問題の範疇ではない。

大丈夫そう。

まず、攻撃するかカードをプレイするか選ばせる。

pub fn check_the_will_of_battle_or_play() -> i32 {
    loop {
        println!("[1]:ファイターで攻撃する [2]:カードをプレイする [0]:メインフェーズ終了する");
        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 == 0 || choice == 2 => return choice,
            _ => println!("無効な選択です。もう一度入力してください。"),
        }
    }
}

pub fn transition_battle_or_play(
    mut next_state: ResMut<NextState<PlayState>>,
    mut select_attacker_event_writer: EventWriter<SelectAttacker>,
    mut select_hand_event_writer: EventWriter<SelectHand>,

    mut state_move_event_reader: EventReader<StateMove>,
) {
    for event in state_move_event_reader.read() {
        let choice = check_the_will_of_battle_or_play();

        match choice {
            1 => {
                println!("バトルに移行します");
                select_attacker_event_writer.send(SelectAttacker);
               
            }

            2 => {
                println!("カードプレイに移行します");
                select_hand_event_writer.send(SelectHand);
               
            }
            0 => {
                println!("メインフェーズ終了しました");
                next_state.set(PlayState::TurnEnd);
            }

            _ => {}
        }
    }
}

イベントが有能だったので、メインフェーズ内のステート分けは没にして、これで入力結果に応じてバトルするか、カードをプレイするか選べるようにした。

さっき作ったfzoneのリストから召喚酔いしていないやつをピックアップして、それを選択する関数を作った。

pub fn choose_fighter_from_fzone(
    player1_fzone: ResMut<Player1FZone>,
    query: Query<(Entity, &Card, &Fighter, &Location), With<Player1>>, // Fighterコンポーネントを追加
    mut commands: Commands,
    mut atack_event_writer: EventWriter<Attack>,
    mut select_attacker_event_reader: EventReader<SelectAttacker>
) {
    for _event in select_attacker_event_reader.read() {
        let mut available_fighters = Vec::new();

        println!("Fゾーンにある召喚酔いしていないあなたのファイターは:");

        for &entity in &player1_fzone.cards {
            if let Ok*8 = query.get(entity) {
                if !fighter.summoned_sick { // 召喚酔いでない場合
                    available_fighters.push(entity);
                    println!("{}: {}[{}]", available_fighters.len(), card.name, card.energy);
                }
            }
        }

        if available_fighters.is_empty() {
            println!("召喚酔いしていないファイターがFゾーンにありません。");
            return;
        }

        println!("ファイターを選択してください (1-{}):", available_fighters.len());

        let mut input = String::new();
        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 <= available_fighters.len() {
                let selected_entity = available_fighters[selected_index - 1];

                if let Ok*9 = query.get(selected_entity) {
                    atack_event_writer.send(Attack {
                        attacker_id: selected_entity,
                    });
                    println!("{} をするファイターとして選択しました", card.name); // カード名を表示
                }
                println!("選択したファイターのエンティティID: {:?}", selected_entity);
            } else {
                println!("無効な選択です。");
            }
        } else {
            println!("有効な番号を入力してください。");
        }
    }
}

これを実行したところ以下の結果を得た。

アタックできるカードのリストは、パワーを表示した方がいいかもなぁ。
あと入力を受け付ける関数は、別枠にして、エラーが起きないようにした方がいいってのと、
誤字脱字直して、
選択したファイターのIDは表示しなくていいなぁ
攻撃したらスピンしろ
と5つ思った。

pub fn choose_fighter_from_fzone(
    player1_fzone: ResMut<Player1FZone>,
    query: Query<(Entity, &Card, &Fighter, &Location), With<Player1>>, // Fighterコンポーネントを追加
    mut commands: Commands,
    mut atack_event_writer: EventWriter<Attack>,
    mut select_attacker_event_reader: EventReader<SelectAttacker>
) {
    for _event in select_attacker_event_reader.read() {
        let mut available_fighters = Vec::new();

        println!("Fゾーンにある召喚酔いしていないあなたのファイターは:");

        for &entity in &player1_fzone.cards {
            if let Ok*10 = query.get(entity) {
                if !fighter.summoned_sick { // 召喚酔いでない場合
                    available_fighters.push(entity);
                    println!("{}: {}[{}]", available_fighters.len(), card.name, fighter.power);
                }
            }
        }

        if available_fighters.is_empty() {
            println!("召喚酔いしていないファイターがFゾーンにありません。");
            return;
        }

        println!("ファイターを選択してください (1-{}):", available_fighters.len());

        let mut input = String::new();
        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 <= available_fighters.len() {
                let selected_entity = available_fighters[selected_index - 1];

                if let Ok*11 = query.get(selected_entity) {
                    atack_event_writer.send(Attack {
                        attacker_id: selected_entity,
                    });
                    println!("{} を攻撃するファイターとして選択しました", card.name); // カード名を表示
                    commands.entity(selected_entity).insert(SpinCondition::Spin);
                }
            } else {
                println!("無効な選択です。");
            }
        } else {
            println!("有効な番号を入力してください。");
        }
    }
}

これでいいんでね?

入力方式を変えるのはちょっと待って、あとでまとめてやる。
攻撃対象を決める関数をさっきと同じように組んでみた、変えた点は以下の通り
・Attackイベントを受け取った時実行する。
・player2_szone.cardsのリスト全体と、player2_fzone.cardsのカードのうち、スピンしているものを組み合わせたリストを番号付きで表示する。
・入力を受け付けて、その番号を入力させる
・BeingAttackedイベントで選んだカードのエンティティidをattacked_card_idとして送信する。
・その他エラー処理などは、以下の関数に準じる。


pub fn choose_card_being_attacked(
    player2_szone: ResMut<Player2SZone>,
    player2_fzone: ResMut<Player2FZone>,
    query: Query<(Entity, &Card, &Fighter, &SpinCondition), With<Player2>>, // Fighterコンポーネントを追加
    mut commands: Commands,
    mut being_attacked_event_writer: EventWriter<BeingAttacked>,
    mut attack_event_reader: EventReader<Attack>
) {
    for _event in attack_event_reader.read() {
        let mut available_cards = Vec::new();

        // Sゾーンのカードをリストアップ
        for &entity in &player2_szone.cards {
            if let Ok*12 = query.get(entity) {
                available_cards.push(entity);
                println!("{}: {} (Sゾーン)", available_cards.len(), card.name);
            }
        }

        // Fゾーンのスピン中のカードをリストアップ
        for &entity in &player2_fzone.cards {
            if let Ok*13 = query.get(entity) {
                if let SpinCondition::Spin = spincondition { // スピンしている場合
                    available_cards.push(entity);
                    println!("{}: {} (Fゾーン)[{}]", available_cards.len(), card.name, fighter.power);
                }
            }
        }

        if available_cards.is_empty() {
            println!("攻撃対象となるカードがありません。");
            return;
        }

        println!("攻撃対象を選択してください (1-{}):", available_cards.len());

        let mut input = String::new();
        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 <= available_cards.len() {
                let selected_entity = available_cards[selected_index - 1];

                if let Ok*14 = query.get(selected_entity) {
                    being_attacked_event_writer.send(BeingAttacked {
                        attacked_card_id: selected_entity,
                    });
                    println!("{} を攻撃対象として選択しました", card.name); // カード名を表示
                }
            } else {
                println!("無効な選択です。");
            }
        } else {
            println!("有効な番号を入力してください。");
        }
    }
}

そしたら、以上の結果を得た。問題は、ファーストエナジーが表示されていないこと、Sゾーンのファイターのパワーが表示されていないこと。
もろもろを修正した。


pub fn choose_card_being_attacked(
    player2_szone: ResMut<Player2SZone>,
    player2_fzone: ResMut<Player2FZone>,
    query: Query<(Entity, &Card, Option<&Fighter>, &SpinCondition), With<Player2>>, // Fighterコンポーネントを追加
    mut commands: Commands,
    mut being_attacked_event_writer: EventWriter<BeingAttacked>,
    mut attack_event_reader: EventReader<Attack>,
) {
    for _event in attack_event_reader.read() {
        let mut available_cards = Vec::new();

        // Sゾーンのカードをリストアップ
        for &entity in &player2_szone.cards {
            if let Ok*15 = query.get(entity) {
                available_cards.push(entity);
                if let Some(fighter) = fighter_option {
                    println!(
                        "{}: {} (Sゾーン)[パワー: {}]",
                        available_cards.len(),
                        card.name,
                        fighter.power
                    );
                } else {
                    println!("{}: {} (Sゾーン)", available_cards.len(), card.name);
                }
            }
        }

        // Fゾーンのスピン中のカードをリストアップ
        for &entity in &player2_fzone.cards {
            if let Ok*16 = query.get(entity) {
                available_cards.push(entity);
                if let SpinCondition::Spin = spincondition {
                    // スピンしている場合
                    if let Some(fighter) = fighter {
                        println!(
                            "{}: {} (Fゾーン)[パワー: {}]",
                            available_cards.len(),
                            card.name,
                            fighter.power
                        );
                    } else {
                        println!("{}: {} (Fゾーン)", available_cards.len(), card.name);
                    }
                }
            }
        }

        if available_cards.is_empty() {
            println!("攻撃対象となるカードがありません。");
            return;
        }

        println!("攻撃対象を選択してください (1-{}):", available_cards.len());

        let mut input = String::new();
        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 <= available_cards.len() {
                let selected_entity = available_cards[selected_index - 1];

                if let Ok*17 = query.get(selected_entity) {
                    being_attacked_event_writer.send(BeingAttacked {
                        attacked_card_id: selected_entity,
                    });
                    println!("{} を攻撃対象として選択しました", card.name); // カード名を表示
                }
            } else {
                println!("無効な選択です。");
            }
        } else {
            println!("有効な番号を入力してください。");
        }
    }
}

はい、これでOKだろ

これでOKやろう。
攻撃するカードと攻撃対象を選ぶことに成功したぜ!!


色々考えて、BeingAttackedのイベントは二つのEntityを持つようにして、

#[derive(Event)]
pub struct BeingAttacked {
    pub attacker_id: Entity,
    pub attacked_card_id: Entity,
}
if let Ok(selected_index) = input.trim().parse::<usize>() {
            if selected_index > 0 && selected_index <= available_cards.len() {
                let selected_entity = available_cards[selected_index - 1];

                if let Ok*18 = query.get(selected_entity) {
                    being_attacked_event_writer.send(BeingAttacked {
                        attacked_card_id: selected_entity,attacker_id: event.attacker_id
                    });
                    println!("{} を攻撃対象として選択しました", card.name); // カード名を表示
                }
            } else {
                println!("無効な選択です。");
            }

このように、attacker_idは先ほどのイベントリーダーから引っ張ってきたやつです。
バトルの処理を考えるにあたって、戦闘には4パターンあるそうです。

バトルFゾーンファイター

  1. パワー比べを行う(バトル)
  2. バトル終了時効果や破壊時効果を発動させる
  3. 撤退と墓地移動選択を行う。
  4. リセットして、フリーステートに戻る

バトルSゾーンファイター

  1. 緩いパワー比べを行う(バトル)
  2. バトル終了時効果や破壊時効果を発動させる
  3. ペナルティを行う。
  4. リセットして、フリーステートに戻る

バトルタクティクス

  1. 必ずバトルに勝つ
  2. バトル終了時効果や破壊時効果を発動させる
  3. ペナルティを行う
  4. リセットして、フリーステートに戻る

アタックファーストエナジー

  1. デッキの一番上からカードをXゾーンに1枚裏側で置くペナルティを行う。(バトル時効果は行われない)
  2. リセットして、フリーステートに戻る

brogmymxo.hatenablog.comこれに従って、取り敢えず、場合分けの関数を作りました。

pub fn handle_being_attacked(
    query: Query<(Entity, &Card, Option<&Fighter>, &Location, Option<&FirstEnergy>, Option<&Tactics>), With<Player2>>,
    mut being_attacked_event_reader: EventReader<BeingAttacked>,
    mut commands: Commands,
) {
    for event in being_attacked_event_reader.read() {

        if let Ok*19 = query.get(event.attacked_card_id) {
            match *location {
                Location::FZone => {
                    // Fゾーンにいる場合の処理
                    println!("{} は Fゾーンにいます", card.name);
                    // 追加の処理をここに記述する
                }
                Location::SZone => {
                    // Sゾーンにいる場合の処理
                    if let Some(_) = fighter_option {
                        println!("{} は Sゾーンにいるファイターです", card.name);
                        // ファイターの特殊な処理をここに記述する
                    }
                }
                _ =>{

                }
            }

            // FirstEnergyコンポーネントがある場合の処理
            if first_energy_option.is_some() {
                println!("{} は ファーストエナジー です", card.name);
                // FirstEnergy に関連する処理をここに記述する
            }

            // Tacticsコンポーネントがある場合の処理
            if tactics_option.is_some() {
                println!("{} は タクティクスです", card.name);
                // Tactics に関連する処理をここに記述する
            }
        } else {
            println!("攻撃対象の情報を取得できませんでした。エンティティID: {:?}", event.attacked_card_id);
        }
    }
}

 

この場合分けを成功した。

取り敢えず、一番簡単な、ファーストエナジーを攻撃した時のペナルティを実装していこう。そのためには、山札を作ってきます。

pub fn opponent_cards_in_deck(
    mut in_library_cards: ResMut<OpponentInLibraryCards>, // リソースとして受け取る
    query: Query<(Entity, &Card, &Location), With<Player2>>,
) {
    in_library_cards.cards.clear(); // 前回の結果をクリア
    println!("Cards in your deck are:");

    for (entity, card, location) in query.iter() {
        if let Location::InLibrary = location {
            in_library_cards.cards.push(entity); // エンティティIDをリストに追加
            println!("{}, ", card.name);
        }
    }
}

ドローの時とほとんど同じ関数なので、それを引っ張ってきて、

pub fn first_energy_penalty(
    mut first_energy_penalty_event_reader: EventReader<FirstEnergyPenalty>,
    mut commands: Commands,
    mut in_library_cards: ResMut<OpponentInLibraryCards>,
    mut check_card_event_writer: EventWriter<CheckCard>,
) {
    for event in first_energy_penalty_event_reader.read() {
        if let Some(&top_card) = in_library_cards.cards.first() {
            commands.entity(top_card).insert(Location::XZone);
            in_library_cards.cards.remove(0); // 先頭のカードを削除
            println!("プレイヤー2は1枚ペナルティを受けました。");
            check_card_event_writer.send(CheckCard);
        } else {
            println!("No cards available in the deck.");
        }
    }
}

こういう関数を作りました。

これを見て、攻撃条件がリスピンであることが含まれていないことに気付いた。
なので、それを修正した。


また、相手のXゾーンのカードもリストにした方がいいと思った。

もう疲れたから省略するけど、取り敢えず、Xゾーンの表示もできるようになったわ!!

 

 

 

 

 

 

 

 

*1:

            Card {
                name: String::from("ハームゥのラッパ"),
                energy: 1,
            },
            Location::InLibrary,
            SpinCondition::ReSpin,
            FaceCondition::Facedown,
            Tactics { required_energy: 2 },
            Player1 {},
       

*2:

            Card {
                name: String::from("三剣士のソードホーク"),
                energy: 6,
            },
            Location::SZone,
            SpinCondition::Spin,
            FaceCondition::Open,
            Fighter { power: 5000 , summoned_sick: true,},
            Player1 {},
       

*3:

            Card {
                name: String::from("飛翔のタカノメ"),
                energy: 1,
            },
            Location::SZone,
            SpinCondition::ReSpin,
            FaceCondition::Open,
            Fighter { power: 500, summoned_sick: true,},
            Player2 {},
       

*4:

            Card {
                name: String::from("十字紋のカクレボウ"),
                energy: 2,
            },
            Location::FZone,
            SpinCondition::Spin,
            FaceCondition::Open,
            Fighter { power: 1000 , summoned_sick: false,},
            Player2 {},
       

*5:

            Card {
                name: String::from("匠のテダマ"),
                energy: 3,
            },
            Location::InLibrary,
            SpinCondition::ReSpin,
            FaceCondition::Facedown,
            Fighter { power: 2000 , summoned_sick: false,},
            Player2 {},
       

*6:

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

*7:

            Card {
                name: String::from("情熱のエナジー"),
                energy: 2,
            },
            Location::SZone,
            SpinCondition::ReSpin,
            FaceCondition::Facedown,
            FirstEnergy {},
            Player2 {},
       

*8:_, card, fighter,_

*9:_, card, _, _

*10:_, card, fighter,_

*11:_, card, _, _

*12:_, card, _, _

*13:_, card, fighter, spincondition

*14:_, card, _, _

*15:_, card, fighter_option, _

*16:_, card, fighter, spincondition

*17:_, card, _, _

*18:_, card, _, _

*19:_, card, fighter_option, location, first_energy_option, tactics_option