diff --git a/common/traits/magnetic.trait.js b/common/traits/magnetic.trait.js new file mode 100644 index 0000000..63b80d2 --- /dev/null +++ b/common/traits/magnetic.trait.js @@ -0,0 +1,84 @@ +import {behaviorItemFromJSON, createContext} from '@avocado/behavior'; +import {compose, Property} from '@avocado/core'; +import {StateProperty, Trait} from '@avocado/entity'; +import {Rectangle, Vector} from '@avocado/math'; + +import {TraitPlantPacket} from './trait-plant.packet'; + +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 = 1 - (distance / attraction); + const magnitude = 50 * rdiff; + entity.applyMovement(Vector.scale(unit, magnitude)); + } + } + +} diff --git a/server/create-entity-for-connection.js b/server/create-entity-for-connection.js index c52b458..b56d050 100644 --- a/server/create-entity-for-connection.js +++ b/server/create-entity-for-connection.js @@ -47,6 +47,11 @@ export function createEntityForConnection(socket) { informed: {}, layered: {}, listed: {}, + magnetic: { + params: { + isAttractor: true, + }, + }, mobile: { state: { speed: 100, diff --git a/server/fixtures/kitty-fire.room.js b/server/fixtures/kitty-fire.room.js index 68d2a8f..bf6a18e 100644 --- a/server/fixtures/kitty-fire.room.js +++ b/server/fixtures/kitty-fire.room.js @@ -61,12 +61,15 @@ export function kittyFireJSON() { roomJSON.layers[0].entities.push(positionedEntityJSON(uri, position)); } + for (let i = 0; i < 20; ++i) { + addEntityWithRandomPosition('/rock.entity.json'); + } // for (let i = 0; i < 20; ++i) { // addEntityWithRandomPosition('/flower-barrel.entity.json'); // } - for (let i = 0; i < 3; ++i) { - addEntityWithRandomPosition('/mama-kitty-spawner.entity.json'); - } + // for (let i = 0; i < 3; ++i) { + // addEntityWithRandomPosition('/mama-kitty-spawner.entity.json'); + // } // for (let i = 0; i < 5; ++i) { // addEntityWithRandomPosition('/fire.entity.json'); // } diff --git a/server/fixtures/rock.entity.js b/server/fixtures/rock.entity.js index 84aa941..a01ed65 100644 --- a/server/fixtures/rock.entity.js +++ b/server/fixtures/rock.entity.js @@ -30,6 +30,11 @@ export function rockJSON() { ); return { traits: { + collider: { + params: { + isSensor: true, + }, + }, existent: { state: { name: 'Rock', @@ -51,6 +56,33 @@ export function rockJSON() { }, }, }, + layered: {}, + listed: {}, + magnetic: {}, + mobile: {}, + physical: {}, + pictured: { + params: { + images: { + initial: { + offset: [0, 0], + size: [12, 12], // Derive? + uri: '/rock.png', + }, + } + }, + }, + positioned: {}, + roomed: {}, + shaped: { + params: { + shape: { + type: 'rectangle', + position: [0, 0], + size: [12, 12], + }, + }, + }, spawner: { params: { spawns: { @@ -59,7 +91,8 @@ export function rockJSON() { }, }, }, - } + }, + visible: {}, }, }; }