Skip to content

Instantly share code, notes, and snippets.

@PhilipRosedale
Last active January 3, 2018 22:54
Show Gist options
  • Save PhilipRosedale/5aee80677b60678a24db7e092cb2209d to your computer and use it in GitHub Desktop.
Save PhilipRosedale/5aee80677b60678a24db7e092cb2209d to your computer and use it in GitHub Desktop.
//
// nearbyUpdate.js
// examples/entityScripts
//
// Philip Rosedale, December 26, 2017
//
// This entity script is a way to efficiently update entities based on how far away from you they are,
// dropping the update rate as a function of distance squared. This works well for the most typical case of a
// large number of entities arranged roughly randomly on a sheet.
//
// This is a simple form of distributed computing, with distant items computed less frequently, and with a
// minimal update frequency set by MINIMUM_UPDATE_MSECS, so that you do not update something if someone else
// has done it more recently.
//
var MINIMUM_UPDATE_MSECS = 150;
var AVERAGE_UPDATE_SECONDS_PER_METER_SQUARED = 3;
(function() {
var _this;
// this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember
// our this object, so we can access it in cases where we're called without a this (like in the case of various global signals)
ExampleUpdate = function() {
_this = this;
};
ExampleUpdate.prototype = {
// getDelay() decides how often to check on this entity, based on how far away it is.
getDelay: function() {
var distance = Vec3.distance(MyAvatar.position, Entities.getEntityProperties(_this.entityID).position);
var delay = distance * distance / AVERAGE_UPDATE_SECONDS_PER_METER_SQUARED * 1000 * Math.random();
return delay;
},
// preload() will be called when the entity has become visible (or known) to the interface
// it gives us a chance to set our local JavaScript object up. In this case it means:
// Figure out an initial random delay based on how far we are from the object,
preload: function(entityID) {
this.entityID = entityID;
this.myTimeout = Script.setTimeout(this.maybeUpdate, this.getDelay());
},
// maybeUpdate() is where we check to see if the entity needs to be updated, since someone else
// might have updated it.
maybeUpdate: function() {
if (Date.now() - Entities.getEntityProperties(_this.entityID, "lastEdited").lastEdited / 1000 > MINIMUM_UPDATE_MSECS) {
_this.update();
}
_this.myTimeout = Script.setTimeout(_this.maybeUpdate, _this.getDelay());
},
// update() is where we do whatever we really want to do to the entity...
update: function() {
//
// In this simple example of a complex system we will wander around looking for other
// sphere entities that we are touching/interpenetrating, and swap colors with them if we
// are the dominant color in a rock-scissors-paper (RGB) way.
//
var RED = { red: 255, green: 0, blue: 0 };
var GREEN = { red: 0, green: 255, blue: 0 };
var BLUE = { red: 0, green: 0, blue: 255 };
var MAX_MOVEMENT_UPDATE = 0.0;
var properties = Entities.getEntityProperties(_this.entityID, ["position", "dimensions", "color"]);
nearbyEntities = Entities.findEntities(properties.position, properties.dimensions.x / 2);
//
// Check for someone to conquer!
//
for (i = 0; i < nearbyEntities.length; i++) {
var nearbyProperties = Entities.getEntityProperties(nearbyEntities[i], ["position", "color", "type"]);
if (properties.color.red && nearbyProperties.color.green) {
Entities.editEntity(nearbyEntities[i], { color: RED })
} else if (properties.color.green && nearbyProperties.color.blue) {
Entities.editEntity(nearbyEntities[i], { color: GREEN })
} else if (properties.color.blue && nearbyProperties.color.red) {
Entities.editEntity(nearbyEntities[i], { color: BLUE })
}
}
// Move a little!
Entities.editEntity(_this.entityID,
{ position: Vec3.sum(properties.position,
{ x: (Math.random() - 0.5) * MAX_MOVEMENT_UPDATE,
y: 0,
z: (Math.random() - 0.5) * MAX_MOVEMENT_UPDATE })
}
);
},
// unload() will be called when our entity is no longer available. It may be because we were deleted,
// or because we've left the domain or quit the application. In all cases we want to unhook our connection
// to the update signal
unload: function(entityID) {
Script.clearTimeout(this.myTimeout);
},
};
// entity scripts always need to return a newly constructed object of our type
return new ExampleUpdate();
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment