Skip to content

Commit

Permalink
Extend component list
Browse files Browse the repository at this point in the history
  • Loading branch information
Aceeri committed Jul 8, 2017
1 parent 7ed10df commit a730839
Show file tree
Hide file tree
Showing 25 changed files with 139 additions and 331 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Generated by Cargo
/target/
/specs_derive/target/
Cargo.lock

# Generated by mdbook
Expand Down
12 changes: 8 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<<<<<<< HEAD
[package]
name = "specs"
version = "0.9.2"
Expand Down Expand Up @@ -27,6 +26,9 @@ exclude = ["bors.toml", ".travis.yml"]
[badges]
travis-ci = { repository = "slide-rs/specs" }

[workspace]
members = [ "specs_derive" ]

[dependencies]
atom = "0.3"
fnv = "1.0"
Expand All @@ -46,13 +48,15 @@ common = ["futures"]
serialize = ["serde", "serde_derive"]

[dev-dependencies]
cgmath = { version = "0.14", features = ["eders"] }
cgmath = { version = "0.14", features = ["eders"] }
rand = "0.3"
serde_json = "1.0"
specs_derive = { path = "specs_derive", version = "0.1", features = ["serialize"] }

[[example]]
name = "common"
required-features = ["common"]

[workspace]
members = [ "specs_derive" ]
[[example]]
name = "derive"
required-features = ["serialize"]
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 0 additions & 1 deletion specs_derive/examples/derive.rs → examples/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ fn main() {
#[allow(dead_code)]
struct SomeGroup {
#[group(serialize)]
#[group(id = "5")]
field1: Comp1,

#[group(serialize)]
Expand Down
File renamed without changes.
File renamed without changes.
7 changes: 0 additions & 7 deletions specs/.gitignore

This file was deleted.

49 changes: 0 additions & 49 deletions specs/Cargo.toml

This file was deleted.

107 changes: 0 additions & 107 deletions specs/README.md

This file was deleted.

3 changes: 2 additions & 1 deletion specs_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ authors = ["Aceeri <[email protected]>"]
proc-macro = true

[dependencies]
specs = { path = "../specs", version = "0.9.1" }
specs = { path = "../", version = "0.9.2" }
syn = "0.11.10"
quote = "0.3.15"
serde = { version = "1.0", optional = true }
Expand All @@ -19,3 +19,4 @@ serde_json = "1.0"
[features]
default = []
serialize = ["serde", "specs/serialize"]

117 changes: 44 additions & 73 deletions specs_derive/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# Specs

> **S**pecs **P**arallel **ECS**
# Specs Procedural Derive Macros

[![Build Status][bi]][bl] [![Crates.io][ci]][cl] [![Gitter][gi]][gl] ![MIT/Apache][li] [![Docs.rs][di]][dl]

Expand All @@ -18,90 +16,63 @@
[gi]: https://badges.gitter.im/slide-rs/specs.svg
[gl]: https://gitter.im/slide-rs/specs

Specs is an Entity-Component System written in Rust.
Unlike most other ECS libraries out there, it provides

* easy parallelism
* high flexibility
* contains 5 different storages for components, which can be extended by the user
* it's types are mostly not coupled, so you can easily write some part yourself and
still use Specs
* `System`s may read from and write to components and resources, can depend on each
other and you can use barriers to force several stages in system execution
* high performance for real-world applications
## Component Grouping

## Example
Component grouping allows for non-dynamic dispatch on multiple components without a lot of boilerplate.
Normally if you wanted to generically call a method on a bunch of components you would need to do something
similar to:

```rust
// A component contains data
// which is associated with an entity.
#[derive(Debug)]
struct Vel(f32);
#[derive(Debug)]
struct Pos(f32);

impl Component for Vel {
type Storage = VecStorage<Vel>;
}

impl Component for Pos {
type Storage = VecStorage<Pos>;
}

struct SysA;
fn method<C: Component>() { ... }
method::<Component1>();
method::<Component2>();
...
```

impl<'a> System<'a> for SysA {
// These are the resources required for execution.
// You can also define a struct and `#[derive(SystemData)]`,
// see the `full` example.
type SystemData = (WriteStorage<'a, Pos>, ReadStorage<'a, Vel>);
Which can easily become tedious when it becomes necessary to do this for a changing amount of components.
A side benefit of using this approach means you do not need any dynamic dispatch to do so.

fn run(&mut self, data: Self::SystemData) {
// The `.join()` combines multiple components,
// so we only access those entities which have
// both of them.
### Usage

let (mut pos, vel) = data;
Component groups are defined using a simple `struct` and deriving the `ComponentGroup` trait.
`group` attributes can be used to modify the components and subgroups in the group.

for (pos, vel) in (&mut pos, &vel).join() {
pos.0 += vel.0;
}
}
```rust
#[derive(ComponentGroup)]
struct ExampleGroup {
// The group defaults to just a component.
//
// The field name "component1" will be used as an
// unique identifier.
component1: Component1,
// If you need a subgroup, then you need to
// designate the fields that are subgroups.
#[group(subgroup)]
subgroup1: Subgroup1,

// Component grouping comes with built in support
// for serialization and deserialization with `serde`
// usage
#[group(serialize)]
serialize1: CompSerialize1,
}
```

fn main() {
// The `World` is our
// container for components
// and other resources.
let mut world = World::new();
world.register::<Pos>();
world.register::<Vel>();

// An entity may or may not contain some component.
### Attributes

world.create_entity().with(Vel(2.0)).with(Pos(0.0)).build();
world.create_entity().with(Vel(4.0)).with(Pos(1.6)).build();
world.create_entity().with(Vel(1.5)).with(Pos(5.4)).build();
All attributes used in a `ComponentGroup` derive are designated with a `group` prefix `#[group(...)]`.

// This entity does not have `Vel`, so it won't be dispatched.
world.create_entity().with(Pos(2.0)).build();
`#[group(subgroup)]`

// This builds a dispatcher.
// The third parameter of `add` specifies
// logical dependencies on other systems.
// Since we only have one, we don't depend on anything.
// See the `full` example for dependencies.
let mut dispatcher = DispatcherBuilder::new().add(SysA, "sys_a", &[]).build();
Field is a subgroup, the parent group will try to act like the subgroup's members (components and
nested subgroups) are included in operations.

// This dispatches all the systems in parallel (but blocking).
dispatcher.dispatch(&mut world.res);
}
```
`#[group(serialize)]`

Please look into [the examples directory](examples) for more.
Field should be serialized. Note: This requires that all
components implement `Serialize`/`Deserialize`.

## Contribution
`#[group(id = "0")]`

Contribution is very welcome! If you didn't contribute before, just
filter for issues with "easy" label. Please note that your contributions
are assumed to be dual-licensed under Apache-2.0/MIT.
Uses a dynamic component id for this component. Default is `0usize`.
Loading

0 comments on commit a730839

Please sign in to comment.