1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
//! This crate defines the [`ComponentGroup`] trait. //! This trait is used to make managing a group of [`specs::Component`] instances easier. //! This is useful for when you have several components that are often created, read, and updated //! together. You can use this trait to easily move an entire group of components between instances //! of [`specs::World`]. //! //! This crate also provides a custom derive (documented below) that you can use to automatically //! implement the trait. This removes any of the boilerplate you may have needed to write in order //! to implement the trait yourself and makes modifying your group of components much easier. //! //! ```rust,no_run //! // Don't forget to add the component_group crate to your Cargo.toml file! //! use component_group::ComponentGroup; //! # use specs::{World, Component, VecStorage, HashMapStorage}; //! # use specs_derive::Component; //! //! // These components are just for demonstration purposes. You should swap them //! // out for your own. //! //! // Components need to implement Clone to use the automatic derive. //! #[derive(Debug, Clone, Component)] //! #[storage(VecStorage)] //! pub struct Position {x: i32, y: i32} //! //! #[derive(Debug, Clone, Component)] //! #[storage(VecStorage)] //! pub struct Velocity {x: i32, y: i32} //! //! #[derive(Debug, Clone, Component)] //! #[storage(VecStorage)] //! pub struct Health(u32); //! //! #[derive(Debug, Clone, Component)] //! #[storage(HashMapStorage)] //! pub struct Animation {frame: usize} //! //! // This is all of the code you need to write to define the group and its operations! //! #[derive(ComponentGroup)] //! struct PlayerComponents { //! position: Position, //! velocity: Velocity, //! health: Health, //! // This optional component is allowed to not be present //! animation: Option<Animation>, //! } //! //! // Now you can easily add all of these components to an entity, load them all //! // from the world, or even update them all at once! //! ``` //! //! See the documentation for [`ComponentGroup`] for the exact operations you can now perform on //! the `PlayerComponents` struct. The rest of the documentation below goes into the motivation //! behind this crate and details about how to use it. //! //! # Table of Contents //! //! * [Motivation](#motivation) //! * [Manually Implementing `ComponentGroup`](#manually-implementing-componentgroup) //! * [Automatically Implementing `ComponentGroup`](#automatically-implementing-componentgroup) //! * [Optional Components](#optional-components) //! * [Fetching Multiple Component Group Instances](#fetching-multiple-component-group-instances) //! * [Generic Component Groups](#generic-component-groups) //! //! # Motivation //! //! The [`ComponentGroup`] trait makes operating on many components at once much easier and less //! error-prone. Trying to update all of your code every time you add a new component to an entity //! is very difficult to manage. By grouping all of the components together in a single struct, you //! can better manage all of them and make fewer mistakes when you edit your code. The following is //! an example of what your code might look like *without* this trait. //! //! ```rust //! // Rust 2018 edition //! use specs::{World, WorldExt, Builder, Entity, Component, VecStorage, ReadStorage, WriteStorage, Join}; //! use specs::error::Error as SpecsError; //! use specs_derive::Component; //! //! // Let's setup some components to add to our World //! #[derive(Debug, Component)] //! #[storage(VecStorage)] //! pub struct Position {x: i32, y: i32} //! //! #[derive(Debug, Component)] //! #[storage(VecStorage)] //! pub struct Velocity {x: i32, y: i32} //! //! #[derive(Debug, Component)] //! #[storage(VecStorage)] //! pub struct Health(u32); //! //! # use specs::Entities; //! # fn find_player_entity(world: &World) -> Entity { //! # world.system_data::<Entities>().join().next().unwrap() // cheat since only one entity //! # } //! # //! fn main() -> Result<(), SpecsError> { //! // Start the player on level 1 //! let mut level1 = World::new(); //! # level1.register::<Position>(); level1.register::<Velocity>(); level1.register::<Health>(); //! // Add the player to the level //! level1.create_entity() //! // This player only has three components right now, but imagine what could happen //! // to this code as that number grows //! .with(Position {x: 12, y: 59}) //! .with(Velocity {x: -1, y: 2}) //! .with(Health(5)) //! .build(); //! //! // ... //! //! // Player needs to move on to the next level //! let mut level2 = World::new(); //! # level2.register::<Position>(); level2.register::<Velocity>(); level2.register::<Health>(); //! # { // Need to do this in its own scope (not relevant to the example) //! // Somehow find the player in the world it was just in //! let player_entity = find_player_entity(&level1); //! // Need to fetch all the components of the player. Be careful to keep this in sync with //! // the code above! //! let (positions, velocities, healths) = level1.system_data::<( //! ReadStorage<Position>, //! ReadStorage<Velocity>, //! ReadStorage<Health>, //! )>(); //! // If any of these fields were Clone, we could call Option::cloned on the result //! // of `get(entity)` and avoid some of this boilerplate //! let position = positions.get(player_entity).map(|pos| Position {x: pos.x, y: pos.y}) //! .expect("expected a Position component to be present"); //! let velocity = velocities.get(player_entity).map(|vel| Velocity {x: vel.x, y: vel.y}) //! .expect("expected a Velocity component to be present"); //! let health = healths.get(player_entity).map(|health| Health(health.0)) //! .expect("expected a Health component to be present"); //! // Now we can add everything to the new level we created //! level2.create_entity() //! .with(position) //! .with(velocity) //! .with(health) //! .build(); //! # } // Need to do this in its own scope (not relevant to the example) //! //! // ... //! //! // Player needs to go back to previous level //! // Find the player in level **2** //! let player_entity = find_player_entity(&level2); //! // That means that we need to now duplicate everything from above again! //! // This time we're fetching from level2, not level1 //! let (positions, velocities, healths) = level2.system_data::<( //! ReadStorage<Position>, //! ReadStorage<Velocity>, //! ReadStorage<Health>, //! )>(); //! let position = positions.get(player_entity).map(|pos| Position {x: pos.x, y: pos.y}) //! .expect("expected a Position component to be present"); //! let velocity = velocities.get(player_entity).map(|vel| Velocity {x: vel.x, y: vel.y}) //! .expect("expected a Velocity component to be present"); //! let health = healths.get(player_entity).map(|health| Health(health.0)) //! .expect("expected a Health component to be present"); //! // Now that we have the components, we need to re-add them to level **1** for the right //! // entity. //! let player_entity = find_player_entity(&level1); //! // Now we need to fetch write storages for every component, essentially duplicating the //! // code again! This time making sure we get the storages in level **1** //! let (mut positions, mut velocities, mut healths) = level1.system_data::<( //! WriteStorage<Position>, //! WriteStorage<Velocity>, //! WriteStorage<Health>, //! )>(); //! //! positions.insert(player_entity, position)?; //! velocities.insert(player_entity, velocity)?; //! healths.insert(player_entity, health)?; //! //! Ok(()) //! } //! ``` //! //! There is a lot of duplication in this code! Many of the duplicated pieces of code have slight //! differences like which world the components are being fetched from or whether we wanted //! a `ReadStorage` or a `WriteStorage`.The purpose of this crate is to take all of that //! duplication and make reusable methods that operate on all of the components at once. //! //! Instead of having to keep track of all of this code throughout your codebase, implementing the //! `ComponentGroup` trait puts it all in one place. This makes updating your group much less //! error-prone because adding/modifying/removing a component to/from the group only requires //! modifying one area of code. //! //! The code that needs to be written to operate on all of these components together is //! unavoidable given the API that specs provides, but at least you can make it easier by using //! this crate. We've eliminated the need to write most of the repetitive code you saw above by //! allowing you to automatically derive the `ComponentGroup` trait. All you need to do is define //! the components in the group and everything else is generated for you. //! //! The next section of the documentation shows you how to manually implement the [`ComponentGroup`] //! trait for a given group of components. This is still a lot of boilerplate, but it is all //! grouped in one place. The section after that shows how to remove all the boilerplate by //! automatically deriving the trait. //! //! # Manually Implementing `ComponentGroup` //! //! This example is meant to show what manually implementing this trait can be like. The basic idea //! is to move all of the duplicated code from above into reusable methods on a struct that groups //! all of the components that need to be modified together. Implementing it manually like this is //! still quite cumbersome, so a way to automatically derive the trait is also provided. See below //! for more details about that. //! //! ```rust //! // Rust 2018 edition //! // Don't forget to add component_group as a dependency to your Cargo.toml file! //! use component_group::ComponentGroup; //! use specs::{World, WorldExt, Builder, Entity, Entities, Component, VecStorage, ReadStorage, WriteStorage, Join}; //! use specs::error::Error as SpecsError; //! use specs_derive::Component; //! //! // The one benefit of implementing the trait manually is that you don't need to make the //! // fields Clone like you do when automatically deriving the trait. //! #[derive(Debug, Component)] //! #[storage(VecStorage)] //! pub struct Position {x: i32, y: i32} //! //! #[derive(Debug, Component)] //! #[storage(VecStorage)] //! pub struct Velocity {x: i32, y: i32} //! //! #[derive(Debug, Component)] //! #[storage(VecStorage)] //! pub struct Health(u32); //! //! pub struct PlayerComponents { //! position: Position, //! velocity: Velocity, //! health: Health, //! } //! //! impl ComponentGroup for PlayerComponents { //! type UpdateError = SpecsError; //! //! fn first_from_world(world: &World) -> Option<(Entity, Self)> { //! // Needs to be updated every time the struct changes //! let (entities, positions, velocities, healths) = world.system_data::<( //! Entities, //! ReadStorage<Position>, //! ReadStorage<Velocity>, //! ReadStorage<Health>, //! )>(); //! (&entities, &positions, &velocities, &healths).join().next() //! .map(|(entity, pos, vel, health)| (entity, Self { //! // No need to clone because we know and can access all the fields //! position: Position {x: pos.x, y: pos.y}, //! velocity: Velocity {x: vel.x, y: vel.y}, //! health: Health(health.0), //! })) //! } //! //! fn from_world(world: &World, entity: Entity) -> Self { //! // Needs to be updated every time the struct changes //! let (positions, velocities, healths) = world.system_data::<( //! ReadStorage<Position>, //! ReadStorage<Velocity>, //! ReadStorage<Health>, //! )>(); //! Self { //! // If any of these fields were Clone, we could call Option::cloned on the result //! // of `get(entity)` and avoid some of this boilerplate //! position: positions.get(entity).map(|pos| Position {x: pos.x, y: pos.y}) //! .expect("expected a Position component to be present"), //! velocity: velocities.get(entity).map(|vel| Velocity {x: vel.x, y: vel.y}) //! .expect("expected a Velocity component to be present"), //! health: healths.get(entity).map(|health| Health(health.0)) //! .expect("expected a Health component to be present"), //! } //! } //! //! fn create(self, world: &mut World) -> Entity { //! // It's possible to write this code so that the compiler will at the very least //! // warn you if you forget one of the things you need to change when the struct //! // changes. //! //! // Using pattern matching here forces a compiler error whenever the struct changes //! let Self {position, velocity, health} = self; //! //! // Forgetting to add a .with() call will cause an unused variable warning //! world.create_entity() //! .with(position) //! .with(velocity) //! .with(health) //! .build() //! } //! //! fn update(self, world: &mut World, entity: Entity) -> Result<(), Self::UpdateError> { //! // Needs to be updated every time the struct changes //! let (mut positions, mut velocities, mut healths) = world.system_data::<( //! WriteStorage<Position>, //! WriteStorage<Velocity>, //! WriteStorage<Health>, //! )>(); //! //! positions.insert(entity, self.position)?; //! velocities.insert(entity, self.velocity)?; //! healths.insert(entity, self.health)?; //! Ok(()) //! } //! //! fn remove(world: &mut World, entity: Entity) -> Self { //! // Needs to be updated every time the struct changes //! let (mut positions, mut velocities, mut healths) = world.system_data::<( //! WriteStorage<Position>, //! WriteStorage<Velocity>, //! WriteStorage<Health>, //! )>(); //! Self { //! // If any of these fields were Clone, we could call Option::cloned on the result //! // of `get(entity)` and avoid some of this boilerplate //! position: positions.remove(entity).map(|pos| Position {x: pos.x, y: pos.y}) //! .expect("expected a Position component to be present"), //! velocity: velocities.remove(entity).map(|vel| Velocity {x: vel.x, y: vel.y}) //! .expect("expected a Velocity component to be present"), //! health: healths.remove(entity).map(|health| Health(health.0)) //! .expect("expected a Health component to be present"), //! } //! } //! } //! //! # fn find_player_entity(world: &World) -> Entity { //! # world.system_data::<Entities>().join().next().unwrap() // cheat since only one entity //! # } //! # //! fn main() -> Result<(), SpecsError> { //! // Start the player on level 1 //! let mut level1 = World::new(); //! # level1.register::<Position>(); level1.register::<Velocity>(); level1.register::<Health>(); //! // Having all the components together in a struct means that Rust will enforce that you //! // never forget a field. //! // That being said, it is still possible to forget to add a component to the group. Adding //! // a component to the code above can be tricky and easy to mess up, but if you //! // automatically derive the trait, adding a component can be just a one-line change. //! let player = PlayerComponents { //! position: Position {x: 12, y: 59}, //! velocity: Velocity {x: -1, y: 2}, //! health: Health(5), //! }; //! // Add the player to the level //! player.create(&mut level1); //! //! // ... //! //! // Player needs to move on to the next level //! let mut level2 = World::new(); //! # level2.register::<Position>(); level2.register::<Velocity>(); level2.register::<Health>(); //! // Somehow find the player in the world it was just in //! let player_entity = find_player_entity(&level1); //! // Extract the player from the world it was just in //! let player = PlayerComponents::from_world(&level1, player_entity); //! // Add it to the next world since it hasn't been added yet //! player.create(&mut level2); //! //! // ... //! //! // Player needs to go back to previous level //! // Using first_from_world is safe when you know that there is only one entity with all //! // the components in the group //! let (_, player) = PlayerComponents::first_from_world(&level2).unwrap(); //! let player_entity = find_player_entity(&level1); //! // Move the player back //! player.update(&mut level1, player_entity)?; //! //! Ok(()) //! } //! ``` //! //! # Automatically Implementing `ComponentGroup` //! //! You can also automatically implement the [`ComponentGroup`] trait using `#[derive(ComponentGroup)]`. //! This removes all the boilerplate you saw in the example above and automatically provides each //! of the methods in [`ComponentGroup`]. All fields in the struct must implement `Clone` so that //! they can be copied within the methods that get implemented. //! //! ```rust //! // Rust 2018 edition //! use component_group::ComponentGroup; //! use specs::{World, WorldExt, Component, VecStorage}; //! use specs::error::Error as SpecsError; //! use specs_derive::Component; //! //! // Note that components need to be Clone to use the automatic derive //! #[derive(Debug, Clone, Component)] //! #[storage(VecStorage)] //! pub struct Position {x: i32, y: i32} //! //! #[derive(Debug, Clone, Component)] //! #[storage(VecStorage)] //! pub struct Velocity {x: i32, y: i32} //! //! #[derive(Debug, Clone, Component)] //! #[storage(VecStorage)] //! pub struct Health(u32); //! //! // This is all of the code you need to write to define the group and all of its operations! //! #[derive(ComponentGroup)] //! struct PlayerComponents { //! position: Position, //! velocity: Velocity, //! health: Health, //! } //! //! # fn find_player_entity(world: &World) -> specs::Entity { //! # use specs::{Entities, Join}; //! # world.system_data::<Entities>().join().next().unwrap() // cheat since only one entity //! # } //! # //! fn main() -> Result<(), SpecsError> { //! // Start the player on level 1 //! let mut level1 = World::new(); //! # level1.register::<Position>(); level1.register::<Velocity>(); level1.register::<Health>(); //! // Having all the components together in a struct means that Rust will enforce that you //! // never forget a field. You can still forget to add a component to the group, but at //! // least that is just a one-line change thanks to the custom derive. //! let player = PlayerComponents { //! position: Position {x: 12, y: 59}, //! velocity: Velocity {x: -1, y: 2}, //! health: Health(5), //! }; //! // Add the player to the level //! player.create(&mut level1); //! //! // ... //! //! // Player needs to move on to the next level //! let mut level2 = World::new(); //! # level2.register::<Position>(); level2.register::<Velocity>(); level2.register::<Health>(); //! // Somehow find the player in the world it was just in //! let player_entity = find_player_entity(&level1); //! // Extract the player from the world it was just in //! let player = PlayerComponents::from_world(&level1, player_entity); //! // Add it to the next world since it hasn't been added yet //! player.create(&mut level2); //! //! // ... //! //! // Player needs to go back to previous level //! // Using first_from_world is safe when you know that there is only one entity with all //! // the components in the group //! let (_, player) = PlayerComponents::first_from_world(&level2).unwrap(); //! let player_entity = find_player_entity(&level1); //! // Move the player back //! player.update(&mut level1, player_entity)?; //! //! Ok(()) //! } //! ``` //! //! # Optional Components //! //! You can also use `Option` to ignore part of the group if it isn't specified during creation or //! if it isn't available in the `World` during extraction. If the field is `None`, a call to //! `update` will remove that component for that entity from the component's storage. //! //! ```rust //! # use component_group::ComponentGroup; //! # use specs::{World, WorldExt, Component, VecStorage, HashMapStorage}; //! # use specs::error::Error as SpecsError; //! # use specs_derive::Component; //! # #[derive(Debug, Clone, Component)] //! # #[storage(VecStorage)] //! # pub struct Position {x: i32, y: i32} //! # //! # #[derive(Debug, Clone, Component)] //! # #[storage(VecStorage)] //! # pub struct Velocity {x: i32, y: i32} //! # //! # #[derive(Debug, Clone, Component)] //! # #[storage(VecStorage)] //! # pub struct Health(u32); //! // (same components as before) //! //! #[derive(Debug, Clone, Component)] //! #[storage(HashMapStorage)] //! pub struct Animation {frame: usize} //! //! #[derive(ComponentGroup)] //! struct PlayerComponents { //! position: Position, //! velocity: Velocity, //! health: Health, //! // This optional component is allowed to not be present //! animation: Option<Animation>, //! } //! //! # fn find_player_entity(world: &World) -> specs::Entity { //! # use specs::{Entities, Join}; //! # world.system_data::<Entities>().join().next().unwrap() // cheat since only one entity //! # } //! # //! fn main() -> Result<(), SpecsError> { //! // Start the player on level 1 //! let mut level1 = World::new(); //! # level1.register::<Position>(); level1.register::<Velocity>(); level1.register::<Health>(); level1.register::<Animation>(); //! let player = PlayerComponents { //! position: Position {x: 12, y: 59}, //! velocity: Velocity {x: -1, y: 2}, //! health: Health(5), //! // Since this field is None, the Animation component will not be added when the entity //! // is created //! animation: None, // Not animated to begin with //! }; //! player.create(&mut level1); //! //! // ... //! //! // Player needs to move on to the next level //! let mut level2 = World::new(); //! # level2.register::<Position>(); level2.register::<Velocity>(); level2.register::<Health>(); level2.register::<Animation>(); //! // If an Animation component was added between the call to create() and this next call, //! // the field will be set to Some(animation_component) where animation_component is the //! // instance of the Animation component that was added. Otherwise, the field will be None. //! let player_entity = find_player_entity(&level1); //! let player = PlayerComponents::from_world(&level1, player_entity); //! player.create(&mut level2); //! //! // ... //! //! // Player needs to go back to previous level //! // The Animation component may have changed/added/removed, but we don't need to worry //! // about that here! The behaviour is the same as above. //! let (_, player) = PlayerComponents::first_from_world(&level2).unwrap(); //! let player_entity = find_player_entity(&level1); //! // If the animation field is not None, we will call Storage::insert and add it to the //! // component's storage. Otherwise, we will call Storage::remove and get rid of it. //! player.update(&mut level1, player_entity)?; //! //! Ok(()) //! } //! ``` //! //! **Note:** The way we match for the `Option` type is very naive right now. Using //! `Option<YourComponent>` as the type of your field will work, but using //! `std::option::Option<YourComponent>` will not. //! //! # Fetching Multiple Component Group Instances //! //! In the future, when [Generic Associated Types (GATs)] are implemented, this trait may be //! updated as follows: //! //! ```rust,ignore //! pub trait ComponentGroup: Sized { //! type UpdateError; //! type GroupIter<'a>; //! //! // Extracts all instances of this group of components from the world. //! fn all_from_world<'a>(world: &'a World) -> Self::GroupIter<'a>; //! // ...other methods... //! } //! ``` //! //! It just isn't possible to express this as part of the trait right now. Adding this would be a //! breaking change, so that update would not occur without a new major version being released. //! //! As a workaround, you can add the method yourself using the impl Trait feature: //! //! ```rust,no_run //! # use component_group::ComponentGroup; //! # use specs::{World, WorldExt, Component, VecStorage, ReadStorage}; //! # use specs::error::Error as SpecsError; //! # use specs_derive::Component; //! # //! # #[derive(Debug, Clone, Component)] //! # #[storage(VecStorage)] //! # pub struct Position {x: i32, y: i32} //! # //! # #[derive(Debug, Clone, Component)] //! # #[storage(VecStorage)] //! # pub struct Velocity {x: i32, y: i32} //! # //! # #[derive(Debug, Clone, Component)] //! # #[storage(VecStorage)] //! # pub struct Health(u32); //! # //! #[derive(ComponentGroup)] //! struct PlayerComponents { //! position: Position, //! velocity: Velocity, //! health: Health, //! } //! //! impl PlayerComponents { //! pub fn all_from_world<'a>(world: &'a World) -> impl Iterator<Item=Self> + 'a { //! // ...implement this... //! # (0..).map(|_| unimplemented!()) //! } //! } //! //! fn main() { //! let mut level1 = World::new(); //! // ...do stuff... //! //! for group in PlayerComponents::all_from_world(&level1) { //! // ...do stuff with each group... //! } //! } //! ``` //! //! # Generic Component Groups //! //! It is possible to use the [`ComponentGroup`] trait and custom derive with generic structs. Just //! make sure to add `Send + Sync + Component + Clone` trait bounds to the generic type parameters //! or you will get a compile error. (The `Send + Sync` part is required by the `specs` crate.) //! //! ```rust,no_run //! # use component_group::ComponentGroup; //! # use specs::{World, Component, VecStorage, ReadStorage}; //! # use specs::error::Error as SpecsError; //! # use specs_derive::Component; //! # //! #[derive(Debug, Clone, Component)] //! #[storage(VecStorage)] //! pub struct Position {x: i32, y: i32} //! //! #[derive(Debug, Clone, Component)] //! #[storage(VecStorage)] //! pub struct Velocity {x: i32, y: i32} //! //! #[derive(Debug, Clone, Component)] //! #[storage(VecStorage)] //! pub struct AngularVelocity {deg: f64} //! //! // Don't forget the trait bounds! //! #[derive(ComponentGroup)] //! struct PlayerComponents<V: Send + Sync + Component + Clone> { //! position: Position, //! velocity: V, //! } //! //! // Can use this to provide different component groups that share most of their structure //! type RunningPlayer = PlayerComponents<Velocity>; //! type SpinningPlayer = PlayerComponents<AngularVelocity>; //! # //! # fn main() { //! # // Need to use the type aliases for them to be checked //! # let runner: RunningPlayer = unimplemented!(); //! # let spinner: SpinningPlayer = unimplemented!(); //! # } //! ``` //! //! [`ComponentGroup`]: trait.ComponentGroup.html //! [`specs::Component`]: https://docs.rs/specs/*/specs/trait.Component.html //! [`specs::World`]: https://docs.rs/specs/*/specs/world/struct.World.html //! [Generic Associated Types (GATs)]: https://github.com/rust-lang/rust/issues/44265 #![deny(unused_must_use)] #[doc(hidden)] pub use component_group_derive::*; use specs::{World, Entity}; /// Represents a group of [`specs::Component`] fields that can be added or extracted from /// a [`specs::World`]. /// /// To automatically derive this trait using `#[derive(ComponentGroup)]`, all components within /// the group must implement the `Clone` trait. /// /// See the [top-level crate documentation](index.html) for more details. /// /// [`specs::Component`]: https://docs.rs/specs/*/specs/trait.Component.html /// [`specs::World`]: https://docs.rs/specs/*/specs/world/struct.World.html pub trait ComponentGroup: Sized { /// The error type from the [`update` method](#tymethod.update) type UpdateError; /// Extracts the first instance of this component group from the world. /// /// This method is convenient if you know that there is exactly one instance of a this group in /// the world. /// /// Returns `None` if any of the required fields could not be populated. Fields with an /// `Option` type will be set to `None` if their component could not be populated. fn first_from_world(world: &World) -> Option<(Entity, Self)>; /// Extracts this group of components for the given entity from the given world. /// /// Panics if one of the component fields could not be populated. This can happen if the /// component does not exist for this entity. If the field is an `Option` type, its value will /// be set to `None` instead of panicking. fn from_world(world: &World, entity: Entity) -> Self; /// Creates a new entity in the world and adds all the components from this group to that entity. /// /// Any fields with a value of `None` will not be added to the created entity. fn create(self, world: &mut World) -> Entity; /// Update the components of a given entity with all of the components from this group. /// /// Any fields with a value of `None` will be explicitly removed from the given entity. /// /// Note: Any additional components that the entity has other than the ones covered by /// the fields of this group will be left untouched. fn update(self, world: &mut World, entity: Entity) -> Result<(), Self::UpdateError>; /// Removes all the components from this group from their storages in the given world for the /// given entity. Returns the values of the removed components. /// /// Note: Any additional components that the entity has other than the ones covered by /// the fields of this group will be left untouched. /// /// Panics if one of the required component fields was not present for removal. If the field is /// an `Option` type, its value when returned will be set to `None` instead of panicking. fn remove(world: &mut World, entity: Entity) -> Self; }