Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ActionRegistry pattern #70

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions docs/Patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,118 @@ TODO
## ApeDestroy

TODO

## Actions

Action systems allow entities to respond to events. For example, an entity could perform an action when the player presses a key, or could perform an action when the player steps on a button.

Registering a seperate component and system for each action can be tedious. By using an action registry, the component and system can be generated by template code.

```js
import { System, Component } from 'ape-ecs';

// the action registry
export class ActionRegistry {
constructor(world) {
this.world = world;
}

register_action(action_config) {
let { action_name, action_setting_properties, on_system_config, on_entity_action } = action_config;

// Generate a class and register it as a component for the action itself
let Action = class extends Component {
static get typeName() { return action_name; }//webpack decided not to work with static properties, so I get to do this stupid thing.
static get properties() { return { action_key: '' } }//webpack decided not to work with static properties, so I get to do this stupid thing.
}
this.world.registerComponent(Action);

// Generate a class and register it as a component for any settings inherent to the action
let ActionSettings = class extends Component {
static get typeName() { return action_name + 'Settings'; }//webpack decided not to work with static properties, so I get to do this stupid thing.
static get properties() { return Object.assign(action_setting_properties, { action_key: '' }); }//webpack decided not to work with static properties, so I get to do this stupid thing.
}
this.world.registerComponent(ActionSettings);

// Generate a class and register it as a system for the consequences of an action being performed
let ActionSystem = class ActionSystemClass extends System {
init() {
// set up the actors query
this.actors_query = this.createQuery().fromAll(action_name);
on_system_config(this);// set up any additional queries
}
update(currentTick) {
// fetch the actors and iterate through them
const actors = this.actors_query.refresh().execute();
for (let actor of actors) {
let actions = actor.getComponents(action_name);

// iterate through the instances of the action
for (let action of actions) {
// find any settings that match this action. Filter for the one with the appropriate key.
let settings = Array.from(actor.getComponents(action_name + 'Settings'));
let specific_setting = settings.find(ele => ele.action_key == action.action_key);
on_entity_action(this, actor, action, specific_setting);
}

}
}
}
this.world.registerSystem('frame', ActionSystem);

// Return the classes for later use if you need them.
return [ Action, ActionSettings ];
}
}

//create an action registry
let action_registry = new ActionRegistry(world);

//register the fireProjectile action
let [FireProjectile, FireProjectileSettings] = action_registry.register_action({
action_name: 'FireProjectile',
action_setting_properties: {
target: EntityRef,
image: './assets/stub.png'
},
on_system_config: (system) => {// set up queries
console.log('no queries!');
},
on_entity_action: (system, entity, action, settings) => {// perform the action
if (!settings) {
console.log('no settings for FireProjectile.');
entity.removeComponent(action);
return;
}

console.log('fired')

// originate the projectile at the entity that acted.
let location = entity.getOne('Location');
let target = settings.target.getOne('Location');

// create the projectile. Assume location, image, and destination components.
world.createEntity({
components: [
{
type: 'Location',
x: location.x,
y: location.y,
},
{
type: 'Image',
path: settings.image
},
{
type: 'Destination',
x: target.x,
y: target.y
}
]
})

// remove the FireProjectile component
entity.removeComponent(action);
}
});
```