82 lines
1.8 KiB
JavaScript
82 lines
1.8 KiB
JavaScript
import {compose, Property} from '@avocado/core';
|
|
import {StateProperty, Trait} from '@avocado/entity';
|
|
import {Rectangle, Vector} from '@avocado/math';
|
|
|
|
const decorate = compose(
|
|
StateProperty('attraction', {
|
|
track: true,
|
|
}),
|
|
);
|
|
|
|
export class Magnetic extends decorate(Trait) {
|
|
|
|
static defaultParams() {
|
|
return {
|
|
isAttractor: false,
|
|
};
|
|
}
|
|
|
|
static defaultState() {
|
|
return {
|
|
attraction: 0,
|
|
};
|
|
}
|
|
|
|
static type() {
|
|
return 'magnetic';
|
|
}
|
|
|
|
constructor(entity, params, state) {
|
|
super(entity, params, state);
|
|
}
|
|
|
|
get isAttracted() {
|
|
return !this.params.isAttractor;
|
|
}
|
|
|
|
get isAttractor() {
|
|
return !!this.params.isAttractor;
|
|
}
|
|
|
|
tick(elapsed) {
|
|
if (!this.params.isAttractor) {
|
|
return;
|
|
}
|
|
const attraction = this.entity.attraction;
|
|
if (0 === attraction) {
|
|
return;
|
|
}
|
|
const layer = this.entity.layer;
|
|
if (!layer) {
|
|
return;
|
|
}
|
|
const query = Rectangle.compose(
|
|
Vector.sub(this.entity.position, [32, 32]),
|
|
[64, 64],
|
|
);
|
|
const entities = layer.visibleEntities(query);
|
|
for (let i = 0; i < entities.length; ++i) {
|
|
const entity = entities[i];
|
|
if (!entity.is('magnetic') || !entity.isAttracted) {
|
|
continue;
|
|
}
|
|
if (!entity.is('positioned') || !entity.is('mobile')) {
|
|
continue;
|
|
}
|
|
const distance = Vector.distance(
|
|
this.entity.position,
|
|
entity.position,
|
|
);
|
|
if (distance > attraction) {
|
|
continue;
|
|
}
|
|
const difference = Vector.sub(this.entity.position, entity.position);
|
|
const unit = Vector.normalize(difference);
|
|
const rdiff = Math.max(0.4, 1 - (distance / attraction));
|
|
const magnitude = 100 * rdiff;
|
|
entity.applyMovement(Vector.scale(unit, magnitude));
|
|
}
|
|
}
|
|
|
|
}
|