今日は朝からあまり体調がよくない。
昨日作ったカルボナーラ食べる前に、賞味期限が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 required_energy: u32,
}
これでコンポーネントの中身をいれた。
let my_entity = commands
.id();
println!("{:?} is spawned", my_entity);
let my_entity = commands
.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
.id();
println!("{:?} is spawned", my_entity);
let my_entity = commands
.id();
println!("{:?} is spawned", my_entity);
let my_entity = commands
.id();
println!("{:?} is spawned", my_entity);
let my_entity = commands
.id();
println!("{:?} is spawned", my_entity);
}
pub fn opponent_setup_first_energy(mut commands: Commands) {
let my_entity = commands
.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ゾーンファイター
- パワー比べを行う(バトル)
- バトル終了時効果や破壊時効果を発動させる
- 撤退と墓地移動選択を行う。
- リセットして、フリーステートに戻る
バトルSゾーンファイター
- 緩いパワー比べを行う(バトル)
- バトル終了時効果や破壊時効果を発動させる
- ペナルティを行う。
- リセットして、フリーステートに戻る
バトルタクティクス
- 必ずバトルに勝つ
- バトル終了時効果や破壊時効果を発動させる
- ペナルティを行う
- リセットして、フリーステートに戻る
アタックファーストエナジー
- デッキの一番上からカードをXゾーンに1枚裏側で置くペナルティを行う。(バトル時効果は行われない)
- リセットして、フリーステートに戻る
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);
// ファイターの特殊な処理をここに記述する
}
}
_ =>{
}
}
if first_energy_option.is_some() {
println!("{} は ファーストエナジー です", card.name);
// FirstEnergy に関連する処理をここに記述する
}
println!("{} は タクティクスです", card.name);
}
} 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ゾーンの表示もできるようになったわ!!

Card {
name: String::from("ハームゥのラッパ"),
energy: 1,
},
Location::InLibrary,
SpinCondition::ReSpin,
FaceCondition::Facedown,
Player1 {},
Card {
name: String::from("三剣士のソードホーク"),
energy: 6,
},
Location::SZone,
SpinCondition::Spin,
FaceCondition::Open,
Fighter { power: 5000 , summoned_sick: true,},
Player1 {},
Card {
name: String::from("飛翔のタカノメ"),
energy: 1,
},
Location::SZone,
SpinCondition::ReSpin,
FaceCondition::Open,
Fighter { power: 500, summoned_sick: true,},
Player2 {},
Card {
name: String::from("十字紋のカクレボウ"),
energy: 2,
},
Location::FZone,
SpinCondition::Spin,
FaceCondition::Open,
Fighter { power: 1000 , summoned_sick: false,},
Player2 {},
Card {
name: String::from("匠のテダマ"),
energy: 3,
},
Location::InLibrary,
SpinCondition::ReSpin,
FaceCondition::Facedown,
Fighter { power: 2000 , summoned_sick: false,},
Player2 {},
Card {
name: String::from("必勝成敗の式目"),
energy: 0,
},
Location::SZone,
SpinCondition::ReSpin,
FaceCondition::Open,
Player1 {},
Card {
name: String::from("情熱のエナジー"),
energy: 2,
},
Location::SZone,
SpinCondition::ReSpin,
FaceCondition::Facedown,
FirstEnergy {},
Player2 {},