Loading is borked, but tutorial worked...

main
Elijah C. Voigt 1 year ago
parent 2a33dd7464
commit 2295de0043

@ -83,21 +83,34 @@ But first things first! How do you play the dang game?
""",
]
objective = [
"The Goal of Martian Chess is to have more points than your opponent when the game ends.",
"You get points by capturing your opponent's pieces.",
"The game ends when one player has no more pieces in their zone.",
"""
The Goal of Martian Chess is to have more points than your opponent when the game ends.
""",
"""
You get points by capturing your opponent's pieces.
""",
"""
The game ends when one player has no more pieces in their zone.
""",
]
ownership = [
"""
This here line is called the canal. And blow me down if she aint a beaut! See herein lies the kicker of Martian warfare: You control any and only the pieces on your side of the canal. When you move a piece across the canal, your opponent assumes control over it.
This here line down the middle is called the canal. And blow me down if she aint a beaut! See herein lies the kicker of Martian warfare: You control any and only the pieces on your side of the canal. When you move a piece across the canal, your opponent assumes control over it.
""",
"""
Keep playing and try to score some points!
""",
"Keep playing and try to score some points!",
]
promotions = [
"""
Oh and one last thing: real nerds occasionally employ the field promotions strategy. Here's how it works: If you control no drones, you may combine two pawns to make a drone. Similarly, if you control no Queens, you may combine two drones to make a queen.
Real nerds occasionally employ the field promotions strategy. Here's how it works: If you control no drones, you may combine two pawns to make a drone. Similarly, if you control no Queens, you may combine a drone and a pawn to make a queen.
""",
]
undo = [
"""
One last thing: no take-backsies. You cannot 'undo' a piece's last move if it crossed the canal.
"""
]
outro = [
"""
Ok I gotta go now, but You now know enough to prevent human extinction. Do you want to finish this practice round?
@ -105,12 +118,44 @@ Ok I gotta go now, but You now know enough to prevent human extinction. Do you w
]
[tutorial.pieces]
prompt = ["Try picking up a piece"]
pawn = ["Pawn. The Pawn is worth 1 point, and moves 1 space diagonally. This thing ain't worth your time. Put it down."]
drone = ["Drone. The Drone is worth 2 points, and moves 1 or 2 spaces horizontally or vertically. Neat. Back on the board."]
queen = ["Queen. The Queen is worth 3 Points, and moves any distance in a straight line. Woah, watch where you point that thing. Best put it back down."]
jumping = ["Note that jumping is not allowed. Martians banned any and all jumping in their society long ago."]
end = ["Ok, now move some pieces somewheres!"]
prompt = [
"""
Try picking up a piece
"""
]
pawn = [
"""
Pawn.
A captured Pawn is worth 1 point, and moves 1 space diagonally. This thing ain't worth your time. Put it down.
""",
]
drone = [
"""
Drone.
A captured Drone is worth 2 points, and moves 1 or 2 spaces horizontally or vertically. Neat. Back on the board.
"""
]
queen = [
"""
Queen.
A captured Queen is worth 3 Points, and moves any distance in a straight line. Woah, watch where you point that thing. Best put it back down.
"""
]
jumping = [
"""
Note that jumping over pieces is not allowed.
Martians banned any and all jumping in their society long ago.
"""
]
end = [
"""
Ok, now move some pieces somewheres!
"""
]
[resolution]

@ -22,9 +22,8 @@ impl Plugin for Display3dPlugin {
.add_systems(
OnExit(GameState::Loading),
(
fix_skybox.before(initialize),
initialize,
update_tweaks.run_if(resource_exists::<tweak::GameTweaks>),
fix_skybox,
initialize.after(fix_skybox),
),
)
// Systems related to color and camera
@ -84,6 +83,7 @@ impl Plugin for Display3dPlugin {
select
.run_if(in_state(GameState::Play))
.run_if(in_state(DisplayState::Display3d))
.run_if(not(in_state(MenuState::On)))
.run_if(just_pressed(MouseButton::Left)),
pick_up.run_if(any_component_added::<game::Selected>()),
put_down.run_if(any_component_removed::<game::Selected>()),
@ -221,7 +221,7 @@ fn load_assets(
/// Initialize the board and pieces
fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<AssetsMap>) {
info!("Initializing root");
debug!("Initializing root");
commands
.spawn((
SpatialBundle {
@ -232,7 +232,7 @@ fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<Asset
DisplayState::Display3d,
))
.with_children(|parent| {
info!("Intializing 3D Board!");
debug!("Intializing 3D Board!");
parent
.spawn((
Display3d,
@ -330,7 +330,7 @@ fn hydrate_camera(
.iter()
.filter(|(name, _)| name.as_str() == "GameCam")
.for_each(|(_, entity)| {
info!("Initialize 3d camera");
debug!("Initialize 3d camera");
let skybox_handle = tweak
.get_handle::<Image>("display3d_models_skybox_file")
.unwrap();
@ -339,7 +339,7 @@ fn hydrate_camera(
.get::<f32>("display3d_environment_map_light_intensity")
.unwrap();
info!("Hydrating camera {:?}", entity);
debug!("Hydrating camera {:?}", entity);
// Populate the components for the camera
commands.entity(entity).insert((
DisplayState::Display3d,
@ -446,7 +446,7 @@ fn fix_skybox(
.unwrap();
let image = images.get_mut(handle).unwrap();
info!("Loaded skybox image");
debug!("Loaded skybox image");
// NOTE: PNGs do not have any metadata that could indicate they contain a cubemap texture,
// so they appear as one texture. The following code reconfigures the texture as necessary.
if image.texture_descriptor.array_layer_count() == 1 {
@ -470,7 +470,7 @@ fn set_board_model(
.get(tweaks_file.handle.clone())
.expect("Load tweakfile");
boards.iter_mut().for_each(|mut handle| {
info!("Setting board model");
debug!("Setting board model");
let assets_handle = tweak
.get_handle::<Gltf>("display3d_models_assets_file")
.unwrap();
@ -503,7 +503,7 @@ fn set_title_model(
titles
.iter_mut()
.for_each(|(mut handle, mut transform, mut visibility)| {
info!("Setting title model");
debug!("Setting title model");
let assets_handle = tweak
.get_handle::<Gltf>("display3d_models_assets_file")
.unwrap();
@ -546,7 +546,7 @@ fn board_translation(&BoardIndex { x, y }: &BoardIndex) -> Vec3 {
}
fn capture_translation(side: &Side, num: usize) -> Vec3 {
info!("Side: {:?} Num: {:?}", side, num);
debug!("Side: {:?} Num: {:?}", side, num);
let x = 5.0 - ((num % 4) as f32 * 1.3);
let y = -1.3;
let z = 4.0 + ((num / 4) as f32 * 1.3);
@ -634,7 +634,7 @@ fn update_pieces(
// Set position of piece
let new_translation = board_translation(board_index);
if transform.translation != new_translation {
info!("Updating piece transform");
debug!("Updating piece transform");
transform.translation = new_translation;
}
@ -644,7 +644,7 @@ fn update_pieces(
.count();
if animating > 0 {
info!("Piece {:?} is animating. Skipping...", entity);
debug!("Piece {:?} is animating. Skipping...", entity);
} else {
debug!("Checking piece object scene for {:?}", entity);
@ -679,7 +679,6 @@ fn select(
selected: Query<Entity, With<game::Selected>>,
state: Res<State<game::TurnState>>,
) {
// info!("Board index selected: {:?}", board_index);
match *piece {
PiecePointer(Some(e)) => {
query.get(e).iter().for_each(|(board_index, side)| {
@ -799,7 +798,7 @@ fn set_valid_move_model(
.get_handle::<Gltf>("display3d_models_assets_file")
.unwrap();
if let Some(gltf) = gltfs.get(assets_handle) {
info!("Setting valid move model");
debug!("Setting valid move model");
events.iter_mut().for_each(|(mut handle, mut visibility)| {
*handle = gltf
@ -834,19 +833,19 @@ fn pick_up(
.get(tweaks_file.handle.clone())
.expect("Load tweakfile");
events.iter_mut().for_each(|(entity, piece)| {
info!("Picking up piece");
debug!("Picking up piece");
let assets_handle = tweak
.get_handle::<Gltf>("display3d_models_assets_file")
.unwrap();
let gltf = gltfs.get(assets_handle).expect("Load GLTF content");
info!("Pickup animation for {:?}", entity);
debug!("Pickup animation for {:?}", entity);
children.iter_descendants(entity).for_each(|child| {
info!(" Child: {:?}", child);
debug!(" Child: {:?}", child);
if let Ok((name, mut player)) = players.get_mut(child) {
let pickup_animation =
format!("display3d_models_animations_pick_up_{}", name.as_str(),);
info!(
debug!(
"Picking up {:?} ({:?}) {:?} {:?}",
name, entity, piece, pickup_animation
);
@ -905,7 +904,7 @@ fn put_down(
.expect("Load tweakfile");
events.read().for_each(|entity| {
if let Ok(_) = query.get_mut(entity) {
info!("Putting down piece");
debug!("Putting down piece");
let assets_handle = tweak
.get_handle::<Gltf>("display3d_models_assets_file")
@ -913,7 +912,7 @@ fn put_down(
let gltf = gltfs.get(assets_handle).expect("Load GLTF content");
children.iter_descendants(entity).for_each(|child| {
if let Ok((name, mut player)) = players.get_mut(child) {
info!("Putting down {:?}", entity);
debug!("Putting down {:?}", entity);
let putdown_animation =
format!("display3d_models_animations_put_down_{}", name.as_str());
let putdown_handle = gltf
@ -927,7 +926,7 @@ fn put_down(
.expect("PutDown Animation");
if let Some(putdown_clip) = clips.get(putdown_handle) {
if putdown_clip.compatible_with(name) {
info!("Compatible with put-down clip!");
debug!("Compatible with put-down clip!");
player
.start_with_transition(
putdown_handle.clone(),
@ -935,20 +934,20 @@ fn put_down(
)
.set_repeat(RepeatAnimation::Never);
} else {
info!(
debug!(
"Clip {:?}({:?}) not compatible with {:?}",
putdown_animation, putdown_clip, name
);
}
} else {
info!("Clip not found");
debug!("Clip not found");
}
} else {
info!("Player not found");
debug!("Player not found");
}
})
} else {
info!("Piece+Side not found for entity");
debug!("Piece+Side not found for entity");
}
})
}
@ -957,7 +956,7 @@ fn set_tile_hitbox(
mut events: Query<(&mut Transform, &BoardIndex), (With<Display3d>, Added<game::Tile>)>,
) {
events.iter_mut().for_each(|(mut transform, index)| {
info!("Setting tile hitbox");
debug!("Setting tile hitbox");
*transform = Transform::from_translation(board_translation(index));
});
@ -965,7 +964,7 @@ fn set_tile_hitbox(
fn opening_animation(mut players: Query<&mut AnimationPlayer, (With<Camera>, With<Display3d>)>) {
players.iter_mut().for_each(|mut player| {
info!("Playing intro camera animation");
debug!("Playing intro camera animation");
player.resume()
});
}
@ -1009,7 +1008,7 @@ fn switch_sides(
.unwrap();
let gltf = gltfs.get(assets_handle).expect("Load GLTF content");
players.iter_mut().for_each(|mut player| {
info!("Switching sides");
debug!("Switching sides");
let animation = match state.get() {
game::TurnState(game::Side::A) => gltf.named_animations.get(
@ -1072,7 +1071,7 @@ fn setup_dissolve_materials(
.filter(|(child, _, _)| query.iter_many(parents.iter_ancestors(*child)).count() > 0)
// Handle this entity (mesh)
.for_each(|(child, std_handle, name)| {
info!("Setting up dissolve material for {:?} {:?}", name, child);
debug!("Setting up dissolve material for {:?} {:?}", name, child);
// Get dissolvable data for percentage start
let dissolvable = query
@ -1138,7 +1137,7 @@ fn capture_piece(
// Wait for fade-out animation
// If all pieces are done dissolving
if dissolving.is_empty() {
info!("Nothing dissolving, moving on to next step!");
debug!("Nothing dissolving, moving on to next step!");
// Move to next state now that animation is done
*state = s.next();
// This takes effect after updating all children
@ -1150,7 +1149,7 @@ fn capture_piece(
.expect("Visibility and Transform of captured piece");
// HACK: This is dirty. Why side, but score.captures(!side)?
info!(
debug!(
"Capture translation: ({:?}, {:?}) {:?}",
side,
score.captures(!*side).saturating_sub(1),
@ -1168,7 +1167,7 @@ fn capture_piece(
game::CaptureFlow::FadeIn(_entity) => {
// If we have completed the dissolve-in animation
if dissolving.is_empty() {
info!("Nothing dissolving, moving on to next step!");
debug!("Nothing dissolving, moving on to next step!");
// Move to next state now that animation is done
*state = s.next();
@ -1215,14 +1214,14 @@ fn monitor_animations(
// Remove Animating component from players that are done
active.iter().for_each(|(entity, player)| {
if player.is_finished() {
info!("Entity {:?} is done, removing animating marker", entity);
debug!("Entity {:?} is done, removing animating marker", entity);
commands.entity(entity).remove::<Animating>();
}
});
// Set inactive entities to active
inactive.iter_mut().for_each(|(entity, mut player)| {
if !player.is_finished() && *player.animation_clip() != Handle::<AnimationClip>::default() {
info!(
debug!(
"Entity {:?} is playing {:?}, adding animating marker",
entity,
player.animation_clip()
@ -1328,7 +1327,7 @@ fn dissolve_animation(
// If animation is done, remove dissolving component
if percentage <= 0.0 || percentage >= 1.0 {
info!(
debug!(
"Removing dissolving from {:?} with percentage {:?}",
entity, percentage
);
@ -1485,3 +1484,4 @@ fn animate_title_light_out(
})
});
}

@ -158,7 +158,7 @@ pub(crate) struct ValidMove;
pub(crate) struct Captured;
#[derive(Debug, Component)]
pub(crate) struct Merged;
pub(crate) struct Promoted;
// manually for the type.
impl std::fmt::Display for Piece {
@ -300,7 +300,7 @@ pub(crate) enum MoveType {
#[default]
Invalid,
Capture,
Merge(Piece),
Promotion(Piece),
}
#[derive(Debug, Component, PartialEq, Clone, Copy, Eq, Hash, Default)]
@ -372,10 +372,14 @@ impl Board {
fn new() -> Board {
Board::from_ascii(
r#".....dqq
dpp..pdq
qdp..ppd
qqd....."#,
// r#".....dqq
// dpp..pdq
// qdp..ppd
// qqd....."#,
r#"........
...p....
..p.....
........"#,
)
}
@ -439,11 +443,10 @@ impl Board {
MoveType::Invalid => {
Err(GameError::InvalidMove)
},
MoveType::Valid | MoveType::Capture | MoveType::Merge(..) => {
MoveType::Valid | MoveType::Capture | MoveType::Promotion(..) => {
// The current epoch is the last epoch + 1
let epoch = self.current_epoch();
// Local moves vec we can return
let mut moves = vec![];
@ -465,7 +468,20 @@ impl Board {
move_type: move_type.clone(),
});
self.inner[to.y][to.x] = Some(*from_piece);
self.inner[to.y][to.x] = match move_type {
MoveType::Promotion(_) => {
match (self.at(from), self.at(to)) {
(Some(Piece::Pawn), Some(Piece::Pawn)) => {
Some(Piece::Drone)
},
(Some(Piece::Pawn), Some(Piece::Drone)) | (Some(Piece::Drone), Some(Piece::Pawn)) => {
Some(Piece::Queen)
},
_ => panic!("Merges can only happen between pawn+pawn or pawn+drone!")
}
},
_ => Some(*from_piece)
};
self.inner[from.y][from.x] = None;
self.moves.extend(moves.clone());
@ -554,10 +570,10 @@ impl Board {
Some(to_piece) => {
match (piece, to_piece) {
(Piece::Pawn, Piece::Pawn) => {
(!side_has_drone).then_some(MoveType::Merge(Piece::Drone))
(!side_has_drone).then_some(MoveType::Promotion(Piece::Drone))
}
(Piece::Drone, Piece::Pawn) | (Piece::Pawn, Piece::Drone) => {
(!side_has_queen).then_some(MoveType::Merge(Piece::Queen))
(!side_has_queen).then_some(MoveType::Promotion(Piece::Queen))
},
_ => {
Some(MoveType::Invalid)
@ -605,7 +621,7 @@ impl Board {
let result = self.move_type(current_board_index, *move_index);
match result {
MoveType::Invalid => None,
MoveType::Capture | MoveType::Merge(..) | MoveType::Valid => {
MoveType::Capture | MoveType::Promotion(..) | MoveType::Valid => {
Some(*move_index)
},
}
@ -764,7 +780,7 @@ mod test {
assert_eq!(expected, given, "Pawn can merge to make a drone");
let move_type = board.move_type((0, 0).into(), (1, 1).into());
assert_eq!(MoveType::Merge(Piece::Drone), move_type);
assert_eq!(MoveType::Promotion(Piece::Drone), move_type);
}
// Pawn cannot merge with queen
@ -909,10 +925,10 @@ mod test {
assert_eq!(MoveType::Capture, capture_move);
let merge_move = board.move_type((3, 1).into(), (2, 1).into());
assert_eq!(MoveType::Merge(Piece::Queen), merge_move);
assert_eq!(MoveType::Promotion(Piece::Queen), merge_move);
let long_merge_move = board.move_type((3, 1).into(), (3, 3).into());
assert_eq!(MoveType::Merge(Piece::Queen), long_merge_move);
assert_eq!(MoveType::Promotion(Piece::Queen), long_merge_move);
let jump_move = board.move_type((3, 1).into(), (1, 1).into());
assert_eq!(MoveType::Invalid, jump_move);
@ -936,7 +952,7 @@ mod test {
// Pawn + Pawn on same side = Promotion
let merge_move = board.move_type((3, 1).into(), (2, 2).into());
assert_eq!(MoveType::Merge(Piece::Drone), merge_move);
assert_eq!(MoveType::Promotion(Piece::Drone), merge_move);
// Pawn + Pawn on other side = Capture
let capture_move = board.move_type((3, 1).into(), (4, 2).into());
@ -1023,7 +1039,7 @@ pub(crate) fn update_board(
}
if *from != *to_idx {
match move_type {
MoveType::Merge(piece) => {
MoveType::Promotion(piece) => {
error!("Hey Eli, this is where you are merging pieces");
// Here we insert a new Piece type based on the merge
// Other system should automatically update the model
@ -1049,11 +1065,11 @@ pub(crate) fn update_board(
.remove::<BoardIndex>()
.insert(Captured);
},
MoveType::Merge(..) => {
MoveType::Promotion(..) => {
commands
.entity(entity)
.remove::<BoardIndex>()
.insert(Merged);
.insert(Promoted);
},
_ => {
panic!("How did you do this!?");

@ -70,9 +70,10 @@ fn loading(
.all(|id| server.is_loaded_with_dependencies(id));
let f = (!fonts.is_empty()) && fonts.ids().all(|id| server.is_loaded_with_dependencies(id));
debug!("s {} g {} t {} f {}", s, g, t, f);
info!("Loading :: images: {} :: gltfs: {} :: tweaks: {} :: fonts: {}", s, g, t, f);
if t {
if s && g && t && f {
info!("Starting game intro");
next_state.set(GameState::Intro)
}
}

@ -17,7 +17,7 @@ impl Plugin for MenuPlugin {
manage_state_entities::<MenuState>().run_if(state_changed::<MenuState>),
)
.add_systems(
Update,
PostUpdate,
(
handle_button_press::<GameState>,
handle_button_press::<MenuState>,
@ -340,5 +340,8 @@ fn handle_button_press<S: States + Clone + Component>(
.filter_map(|(interaction, button_action)| {
(*interaction == Interaction::Pressed).then_some(button_action)
})
.for_each(|ButtonAction(ba)| next_state.set(ba.clone()));
.for_each(|ButtonAction(ba)| {
info!("Button press: {:?} => {:?}", next_state, ba);
next_state.set(ba.clone())
});
}

@ -17,31 +17,29 @@ impl Plugin for TutorialPlugin {
(
// Evaluate if a piece is selected
step.run_if(
state_exists::<TutorialState>.and_then(
// A piece changes sides
any_component_changed::<game::Side>()
// When a piece is selected, we
.or_else(any_component_added::<game::Selected>())
// A piece is de-selected
.or_else(any_component_removed::<game::Selected>())
// TEMP: The user hits 'enter'
.or_else(
just_pressed(KeyCode::Enter)
.or_else(just_pressed(MouseButton::Left)),
),
),
// A piece changes sides
any_component_changed::<game::Side>()
// When a piece is selected, we
.or_else(any_component_added::<game::Selected>())
// A piece is de-selected
.or_else(any_component_removed::<game::Selected>())
// TEMP: The user hits 'enter'
.or_else(
just_pressed(KeyCode::Enter)
.or_else(just_pressed(MouseButton::Left)),
),
),
),
)
// Manage visible/hidden states
.add_systems(
Update,
manage_state_entities::<TutorialState>().run_if(state_changed::<TutorialState>),
)
.add_systems(
Update,
activate_tutorial_step
.run_if(state_exists::<TutorialState>.and_then(state_changed::<TutorialState>)),
(
manage_state_entities::<TutorialState>(),
activate_tutorial_step,
)
.run_if(not(in_state(GameState::Loading)))
.run_if(state_changed::<TutorialState>),
);
}
}
@ -60,7 +58,7 @@ pub(crate) enum TutorialState {
PieceJump,
PieceEnd,
Ownership,
_Promotions,
Promotions,
Outro,
}
@ -106,7 +104,7 @@ fn initialize_tutorial(
.expect("Tutorial ownership"),
),
(
TutorialState::_Promotions,
TutorialState::Promotions,
tweak
.get::<Vec<String>>("tutorial_promotions")
.expect("Tutorial promotions"),
@ -201,7 +199,7 @@ fn initialize_tutorial(
.map(|line| TextSection {
value: line.clone(),
style: TextStyle {
font_size: 8.0,
font_size: 12.0,
color: Color::hex(&text_visible_hex).unwrap(),
font: ui_font.handle.clone(),
},
@ -248,7 +246,7 @@ fn initialize_tutorial(
value: "R e s t a r t".into(),
style: TextStyle {
color: Color::WHITE,
font_size: 8.0,
font_size: 10.0,
font: font_handle.clone(),
},
}],
@ -287,7 +285,7 @@ fn initialize_tutorial(
value: "C o n t i n u e".into(),
style: TextStyle {
color: Color::WHITE,
font_size: 12.0,
font_size: 8.0,
font: font_handle.clone(),
},
}],
@ -341,6 +339,7 @@ fn step(
| TutorialState::PieceEnd
| TutorialState::PieceJump
| TutorialState::Empty
| TutorialState::Promotions
| TutorialState::Ownership => {
// PERF: Doing all of this work up front results in unnecessary work
let piece_selected = !pieces.is_empty();
@ -351,6 +350,7 @@ fn step(
let ownership_done = seen.0.contains(&TutorialState::Ownership);
let ownership_check = !ownership_done && transitions.iter().count() > 0;
let jump_done = seen.0.contains(&TutorialState::PieceJump);
let promotions_done = seen.0.contains(&TutorialState::Promotions);
let queen_selected = pieces.iter().filter(|&p| *p == game::Piece::Queen).count() > 0;
let queen_seen = seen.0.contains(&TutorialState::PieceQueen);
let drone_selected = pieces.iter().filter(|&p| *p == game::Piece::Drone).count() > 0;
@ -375,7 +375,7 @@ fn step(
// There are no pieces selected
} else {
// All move, jump, and ownership tutorials done, say goodbye
if all_moves_done && jump_done && ownership_done {
if all_moves_done && jump_done && ownership_done && promotions_done {
TutorialState::Outro
}
// A piece moves sides, so talk about ownership
@ -385,11 +385,17 @@ fn step(
// We have not touched on jumping yet
else if all_moves_done && !jump_done {
TutorialState::PieceJump
}
// We have not touched on field promotions yet
else if all_moves_done && !promotions_done {
TutorialState::Promotions
}
// All pieces tutorialized, so prompt user to move pieces for more tutorial
} else if all_moves_done {
else if all_moves_done {
TutorialState::PieceEnd
}
// Default, empty (tutorial doesn't always need to show something)
} else {
else {
TutorialState::PieceIntro
}
};
@ -398,7 +404,6 @@ fn step(
}
// After the outro, we exit the tutorial
TutorialState::Outro => error!("Press a button!"),
TutorialState::_Promotions => todo!("Not implemented yet!"),
}
}
@ -406,7 +411,7 @@ fn activate_tutorial_step(
state: Res<State<TutorialState>>,
mut query: Query<(&mut Visibility, &TutorialState), Without<GameState>>,
) {
info!("Activating step {:?}", state.get());
info!("Activating tutorial step {:?}", state.get());
// Iterate over all entities with TutorialState components
query.iter_mut().for_each(|(mut v, s)| {

Loading…
Cancel
Save