まず、デバッグ用に、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)]
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)]
#[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)]
#[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>, // 不変の参照
) {
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>
) {
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
.filter_map(|entity| query.get(*entity).ok().map(|card| card.name.clone()))
.collect();
println!("初期の手札は: {:?}でした", cards_list);
}
}
デバッグする為に、敵のXゾーンに5枚カード追加して来る。
loadingに追加してきた。
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);

ステートが変わっても動き続けてるので、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
.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);
let my_entity = commands
.id();
println!("{:?} is spawned", my_entity);
let my_entity = commands
.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);
}
}
ちょっといったんできてそうなので寝る 表記は知らん。
Card {
name: String::from("策謀のエンジュ"),
energy: 5,
},
Location::XZone,
SpinCondition::ReSpin,
FaceCondition::Open,
Guard{},
Fighter { power: 3000 , summoned_sick: true,},
Player2 {},
Card {
name: String::from("参戦のガントッパ"),
energy: 5,
},
Location::XZone,
SpinCondition::ReSpin,
FaceCondition::Open,
Guard{},
Fighter { power: 4000 , summoned_sick: true,},
Player2 {},
Card {
name: String::from("灼熱旋風のランセ"),
energy: 6,
},
Location::XZone,
SpinCondition::ReSpin,
FaceCondition::Open,
Guard{},
Fighter { power: 6000 , summoned_sick: true,},
Player2 {},
Card {
name: String::from("大筒掃射のダイハッパ"),
energy: 8,
},
Location::XZone,
SpinCondition::ReSpin,
FaceCondition::Open,
Guard{},
Fighter { power: 6000 , summoned_sick: true,},
Player2 {},
Card {
name: String::from("決戦突破のダイコガネ"),
energy: 8,
},
Location::InLibrary,
SpinCondition::ReSpin,
FaceCondition::Facedown,
Guard{},
Fighter { power: 8000 , summoned_sick: true,},
Player2 {},
Card {
name: String::from("幽炎のラゲン"),
energy: 6,
},
Location::InLibrary,
SpinCondition::ReSpin,
FaceCondition::Facedown,
Guard{},
Fighter { power: 5000 , summoned_sick: true,},
Player2 {},
Card {
name: String::from("大龍将グレン・ブレイド"),
energy: 10,
},
Location::InLibrary,
SpinCondition::ReSpin,
FaceCondition::Facedown,
Guard{},
Fighter { power: 10000 , summoned_sick: true,},
Player2 {},
Card {
name: String::from("必勝成敗の式目"),
energy: 0,
},
Location::SZone,
SpinCondition::ReSpin,
FaceCondition::Open,
Player2 {},
Card {
name: String::from("煉獄"),
energy: 2,
},
Location::InLibrary,
SpinCondition::ReSpin,
FaceCondition::Facedown,
Player2 {},
Card {
name: String::from("ブレイジング・エリア"),
energy: 0,
},
Location::InLibrary,
SpinCondition::ReSpin,
FaceCondition::Facedown,
Player2 {},