mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 19:55:07 +02:00
Merge pull request #6503 from imgntn/ratsteer
Add rats to Drylake environment
This commit is contained in:
commit
64dd36d140
3 changed files with 709 additions and 0 deletions
55
examples/drylake/createAvatarDetector.js
Normal file
55
examples/drylake/createAvatarDetector.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// createAvatarDetector.js
|
||||
//
|
||||
// Created by James B. Pollack @imgntn on 12/7/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Run this script if you want the rats to run away from you.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
var avatarDetector = null;
|
||||
|
||||
function createAvatarDetector() {
|
||||
|
||||
var detectorProperties = {
|
||||
name: 'Hifi-Avatar-Detector',
|
||||
type: 'Box',
|
||||
position: MyAvatar.position,
|
||||
dimensions: {
|
||||
x: 1,
|
||||
y: 2,
|
||||
z: 1
|
||||
},
|
||||
collisionsWillMove: false,
|
||||
ignoreForCollisions: true,
|
||||
visible: false,
|
||||
color: {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 0
|
||||
}
|
||||
}
|
||||
|
||||
avatarDetector = Entities.addEntity(detectorProperties);
|
||||
};
|
||||
|
||||
var updateAvatarDetector = function() {
|
||||
// print('updating detector position' + JSON.stringify(MyAvatar.position))
|
||||
Entities.editEntity(avatarDetector, {
|
||||
position: MyAvatar.position
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
var cleanup = function() {
|
||||
Script.update.disconnect(updateAvatarDetector);
|
||||
Entities.deleteEntity(avatarDetector);
|
||||
}
|
||||
|
||||
createAvatarDetector();
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
Script.update.connect(updateAvatarDetector);
|
471
examples/drylake/ratCreator.js
Normal file
471
examples/drylake/ratCreator.js
Normal file
|
@ -0,0 +1,471 @@
|
|||
//
|
||||
// ratCreator.js
|
||||
//
|
||||
// Created by James B. Pollack @imgntn on 12/7/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This script spawns some rats that have simple steering behaviors applied to them.
|
||||
// Run it in the 'drylake' environment, or adjust all object locations to match your scene.
|
||||
//
|
||||
// Steering bevhaviors from ratSteer.js:
|
||||
// The rats will move from a spawning point toward their nest.
|
||||
// They will avoid avoider blocks moving across the alley
|
||||
// They will avoid avatars running createAvatarDetector.js
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include('ratSteer.js');
|
||||
var steer = loadSteer();
|
||||
Script.include('../libraries/tween.js');
|
||||
var TWEEN = loadTween();
|
||||
|
||||
var USE_CONSTANT_SPAWNER = true;
|
||||
|
||||
var RAT_SPAWNER_LOCATION = {
|
||||
x: 1000.5,
|
||||
y: 98,
|
||||
z: 1040
|
||||
};
|
||||
|
||||
var RAT_NEST_LOCATION = {
|
||||
x: 1003.5,
|
||||
y: 99,
|
||||
z: 964.2
|
||||
};
|
||||
|
||||
var RAT_DIMENSIONS = {
|
||||
x: 0.22,
|
||||
y: 0.32,
|
||||
z: 1.14
|
||||
};
|
||||
|
||||
var RAT_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/rat/models/rat_model.fbx';
|
||||
var RAT_IDLE_ANIMATION_URL = 'http://hifi-content.s3.amazonaws.com/james/rat/animations/idle.fbx';
|
||||
var RAT_WALKING_ANIMATION_URL = 'http://hifi-content.s3.amazonaws.com/james/rat/animations/walk.fbx';
|
||||
var RAT_RUNNING_ANIMATION_URL = 'http://hifi-content.s3.amazonaws.com/james/rat/animations/run.fbx';
|
||||
var RAT_DEATH_ANIMATION_URL = 'http://hifi-content.s3.amazonaws.com/james/rat/animations/death.fbx';
|
||||
|
||||
var RAT_IN_NEST_DISTANCE = 4;
|
||||
|
||||
//how many milliseconds between rats
|
||||
var RAT_SPAWN_RATE = 2500;
|
||||
|
||||
var RAT_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Rats_Squeaks_Active.wav';
|
||||
var ratRunningSound = SoundCache.getSound(RAT_SOUND_URL);
|
||||
|
||||
function playRatRunningAnimation(rat) {
|
||||
var animationSettings = JSON.stringify({
|
||||
running: true
|
||||
});
|
||||
Entities.editEntity(rat, {
|
||||
animationURL: RAT_RUNNING_ANIMATION_URL,
|
||||
animation: {
|
||||
url: RAT_RUNNING_ANIMATION_URL,
|
||||
running: true,
|
||||
fps: 30
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function playRatDeathAnimation(rat) {
|
||||
var animationSettings = JSON.stringify({
|
||||
running: true
|
||||
});
|
||||
|
||||
Entities.editEntity(rat, {
|
||||
animationURL: RAT_DEATH_ANIMATION_URL,
|
||||
animationSettings: animationSettings
|
||||
});
|
||||
}
|
||||
|
||||
var modelRatProperties = {
|
||||
name: 'rat',
|
||||
type: 'Model',
|
||||
modelURL: RAT_MODEL_URL,
|
||||
dimensions: RAT_DIMENSIONS,
|
||||
position: RAT_SPAWNER_LOCATION,
|
||||
shapeType: 'Box',
|
||||
damping: 0.8,
|
||||
angularDamping: 0.99,
|
||||
friction: 0.75,
|
||||
collisionsWillMove: true,
|
||||
ignoreForCollisions: false,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -9.8,
|
||||
z: 0
|
||||
},
|
||||
lifetime: 30,
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
}
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
var targetProperties = {
|
||||
name: 'Hifi-Rat-Nest',
|
||||
type: 'Box',
|
||||
color: {
|
||||
red: 0,
|
||||
green: 255,
|
||||
blue: 0
|
||||
},
|
||||
dimensions: {
|
||||
x: 1,
|
||||
y: 1,
|
||||
z: 1
|
||||
},
|
||||
visible: false,
|
||||
position: RAT_NEST_LOCATION
|
||||
};
|
||||
|
||||
var target = Entities.addEntity(targetProperties);
|
||||
|
||||
function addRat() {
|
||||
var rat = Entities.addEntity(modelRatProperties);
|
||||
return rat;
|
||||
}
|
||||
|
||||
//every sixth rat will play a sound
|
||||
var RAT_SOUND_RATE = 6;
|
||||
|
||||
//spawn rate will be multiplied by this to clear any sounds hanging around
|
||||
var RAT_SOUND_CLEAR_RATE = 3;
|
||||
|
||||
var rats = [];
|
||||
var metaRats = [];
|
||||
var ratCount = 0;
|
||||
|
||||
var AVOIDER_Y_HEIGHT = 99;
|
||||
var FIRST_AVOIDER_START_POSITION = {
|
||||
x: 1004,
|
||||
y: AVOIDER_Y_HEIGHT,
|
||||
z: 1019
|
||||
};
|
||||
var FIRST_AVOIDER_FINISH_POSITION = {
|
||||
x: 997,
|
||||
y: AVOIDER_Y_HEIGHT,
|
||||
z: 1019
|
||||
};
|
||||
var SECOND_AVOIDER_START_POSITION = {
|
||||
x: 998,
|
||||
y: AVOIDER_Y_HEIGHT,
|
||||
z: 998
|
||||
};
|
||||
var SECOND_AVOIDER_FINISH_POSITION = {
|
||||
x: 1005,
|
||||
y: AVOIDER_Y_HEIGHT,
|
||||
z: 999
|
||||
};
|
||||
var THIRD_AVOIDER_START_POSITION = {
|
||||
x: 1001.5,
|
||||
y: 100,
|
||||
z: 978
|
||||
};
|
||||
var THIRD_AVOIDER_FINISH_POSITION = {
|
||||
x: 1005,
|
||||
y: 100,
|
||||
z: 974
|
||||
};
|
||||
|
||||
cleanupLeftoverAvoidersBeforeStart();
|
||||
|
||||
var avoiders = [];
|
||||
addAvoiderBlock(FIRST_AVOIDER_START_POSITION);
|
||||
addAvoiderBlock(SECOND_AVOIDER_START_POSITION);
|
||||
addAvoiderBlock(THIRD_AVOIDER_START_POSITION);
|
||||
|
||||
function addAvoiderBlock(position) {
|
||||
var avoiderProperties = {
|
||||
name: 'Hifi-Rat-Avoider',
|
||||
type: 'Box',
|
||||
color: {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 255
|
||||
},
|
||||
dimensions: {
|
||||
x: 1,
|
||||
y: 1,
|
||||
z: 1
|
||||
},
|
||||
position: position,
|
||||
collisionsWillMove: false,
|
||||
ignoreForCollisions: true,
|
||||
visible: false
|
||||
};
|
||||
|
||||
var avoider = Entities.addEntity(avoiderProperties);
|
||||
avoiders.push(avoider);
|
||||
}
|
||||
|
||||
|
||||
tweenAvoider(avoiders[0], FIRST_AVOIDER_START_POSITION, FIRST_AVOIDER_FINISH_POSITION);
|
||||
tweenAvoider(avoiders[1], SECOND_AVOIDER_START_POSITION, SECOND_AVOIDER_FINISH_POSITION);
|
||||
tweenAvoider(avoiders[2], THIRD_AVOIDER_START_POSITION, THIRD_AVOIDER_FINISH_POSITION);
|
||||
|
||||
function tweenAvoider(entityID, startPosition, endPosition) {
|
||||
var ANIMATION_DURATION = 4200;
|
||||
|
||||
var begin = {
|
||||
x: startPosition.x,
|
||||
y: startPosition.y,
|
||||
z: startPosition.z
|
||||
};
|
||||
|
||||
var end = endPosition;
|
||||
|
||||
var original = startPosition;
|
||||
|
||||
var tweenHead = new TWEEN.Tween(begin).to(end, ANIMATION_DURATION);
|
||||
|
||||
function updateTo() {
|
||||
Entities.editEntity(entityID, {
|
||||
position: {
|
||||
x: begin.x,
|
||||
y: begin.y,
|
||||
z: begin.z
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateBack() {
|
||||
Entities.editEntity(entityID, {
|
||||
position: {
|
||||
x: begin.x,
|
||||
y: begin.y,
|
||||
z: begin.z
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var tweenBack = new TWEEN.Tween(begin).to(original, ANIMATION_DURATION).onUpdate(updateBack);
|
||||
|
||||
tweenHead.onUpdate(function() {
|
||||
updateTo()
|
||||
});
|
||||
|
||||
tweenHead.chain(tweenBack);
|
||||
tweenBack.chain(tweenHead);
|
||||
tweenHead.start();
|
||||
|
||||
}
|
||||
|
||||
function updateTweens() {
|
||||
TWEEN.update();
|
||||
}
|
||||
|
||||
function createRatSoundInjector() {
|
||||
var audioOptions = {
|
||||
volume: 0.05,
|
||||
loop: false
|
||||
};
|
||||
|
||||
var injector = Audio.playSound(ratRunningSound, audioOptions);
|
||||
|
||||
return injector;
|
||||
}
|
||||
|
||||
function moveRats() {
|
||||
rats.forEach(function(rat) {
|
||||
|
||||
//remove the rat if its near the nest
|
||||
checkDistanceFromNest(rat);
|
||||
|
||||
//see if there are avatars to run from
|
||||
var avatarFlightVectors = steer.fleeAllAvatars(rat);
|
||||
var averageAvatarFlight;
|
||||
var i;
|
||||
for (i = 0; i < avatarFlightVectors.length; i++) {
|
||||
if (i === 0) {
|
||||
averageAvatarFlight = avatarFlightVectors[0];
|
||||
} else {
|
||||
averageAvatarFlight = Vec3.sum(avatarFlightVectors[i - 1], avatarFlightVectors[i]);
|
||||
}
|
||||
}
|
||||
averageAvatarFlight = Vec3.multiply(averageAvatarFlight, 1 / avatarFlightVectors.length);
|
||||
|
||||
//see if there are avoiders to flee
|
||||
var avoidBlockVectors = steer.fleeAvoiderBlocks(rat);
|
||||
var averageAvoiderFlight;
|
||||
var j;
|
||||
for (j = 0; j < avoidBlockVectors.length; j++) {
|
||||
if (j === 0) {
|
||||
averageAvoiderFlight = avoidBlockVectors[0];
|
||||
} else {
|
||||
averageAvoiderFlight = Vec3.sum(avoidBlockVectors[j - 1], avoidBlockVectors[j]);
|
||||
}
|
||||
};
|
||||
averageAvoiderFlight = Vec3.multiply(averageAvoiderFlight, 1 / avoidBlockVectors.length);
|
||||
|
||||
//add all of the vectors and divide them by total to get average vector
|
||||
//start by trying to go toward the nest
|
||||
var seek = steer.arrive(rat, target);
|
||||
var averageVector = seek;
|
||||
var divisorCount = 1;
|
||||
|
||||
//if there are avatars to run away from
|
||||
if (avatarFlightVectors.length > 0) {
|
||||
divisorCount++;
|
||||
averageVector = Vec3.sum(averageVector, averageAvatarFlight);
|
||||
}
|
||||
|
||||
//or if there are avoider blocks to run away from
|
||||
if (avoidBlockVectors.length > 0) {
|
||||
divisorCount++;
|
||||
averageVector = Vec3.sum(averageVector, averageAvoiderFlight);
|
||||
}
|
||||
|
||||
averageVector = Vec3.multiply(averageVector, 1 / divisorCount);
|
||||
|
||||
var thisRatProps = Entities.getEntityProperties(rat, ["position", "rotation"]);
|
||||
var ratPosition = thisRatProps.position;
|
||||
var ratToNest = Vec3.subtract(RAT_NEST_LOCATION, ratPosition);
|
||||
var ratRotation = Quat.rotationBetween(Vec3.UNIT_Z, ratToNest);
|
||||
var eulerAngle = Quat.safeEulerAngles(ratRotation);
|
||||
eulerAngle.x = 0;
|
||||
eulerAngle.z = 0;
|
||||
var constrainedRotation = Quat.fromVec3Degrees(eulerAngle);
|
||||
|
||||
Entities.editEntity(rat, {
|
||||
velocity: averageVector,
|
||||
rotation: constrainedRotation,
|
||||
});
|
||||
|
||||
//have to make a 'meta' rat object to keep track of rats for updating sound injector locations. parenting sounds would make this easy.
|
||||
var metaRat = getMetaRatByRat(rat);
|
||||
if (metaRat !== undefined) {
|
||||
if (metaRat.injector !== undefined) {
|
||||
if (metaRat.injector.isPlaying === true) {
|
||||
metaRat.injector.options = {
|
||||
loop: true,
|
||||
position: ratPosition
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Script.update.connect(moveRats)
|
||||
Script.update.connect(updateTweens);
|
||||
|
||||
function checkDistanceFromNest(rat) {
|
||||
var ratProps = Entities.getEntityProperties(rat, "position");
|
||||
var distance = Vec3.distance(ratProps.position, RAT_NEST_LOCATION);
|
||||
if (distance < RAT_IN_NEST_DISTANCE) {
|
||||
//at nest
|
||||
removeRatFromScene(rat);
|
||||
}
|
||||
}
|
||||
|
||||
function removeRatFromScene(rat) {
|
||||
|
||||
var index = rats.indexOf(rat);
|
||||
if (index > -1) {
|
||||
rats.splice(index, 1);
|
||||
Entities.deleteEntity(rat);
|
||||
|
||||
}
|
||||
|
||||
var metaRatIndex = findWithAttr(metaRats, 'rat', rat);
|
||||
if (metaRatIndex > -1) {
|
||||
metaRats[index].injector.stop();
|
||||
metaRats.splice(index, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function popRatFromStack(entityID) {
|
||||
|
||||
var index = rats.indexOf(entityID);
|
||||
if (index > -1) {
|
||||
rats.splice(index, 1);
|
||||
}
|
||||
|
||||
var metaRatIndex = findWithAttr(metaRats, 'rat', entityID);
|
||||
if (metaRatIndex > -1) {
|
||||
metaRats[index].injector.stop();
|
||||
metaRats.splice(index, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function findWithAttr(array, attr, value) {
|
||||
for (var i = 0; i < array.length; i += 1) {
|
||||
if (array[i][attr] === value) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getMetaRatByRat(rat) {
|
||||
var result = metaRats.filter(function(metaRat) {
|
||||
return rat === metaRat.rat;
|
||||
});
|
||||
return result[0];
|
||||
}
|
||||
|
||||
Entities.deletingEntity.connect(popRatFromStack);
|
||||
|
||||
|
||||
function cleanupLeftoverAvoidersBeforeStart() {
|
||||
//sometimes if we crash or something there could be extra avoider blocks around. clear them out.
|
||||
var nearbyEntities = Entities.findEntities(RAT_SPAWNER_LOCATION, 100);
|
||||
var entityIndex;
|
||||
for (entityIndex = 0; entityIndex < nearbyEntities.length; entityIndex++) {
|
||||
var entityID = nearbyEntities[entityIndex];
|
||||
var entityProps = Entities.getEntityProperties(entityID);
|
||||
if (entityProps.name === 'Hifi-Rat-Avoider') {
|
||||
Entities.deleteEntity(entityID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
while (rats.length > 0) {
|
||||
Entities.deleteEntity(rats.pop());
|
||||
}
|
||||
|
||||
while (avoiders.length > 0) {
|
||||
Entities.deleteEntity(avoiders.pop());
|
||||
}
|
||||
|
||||
Entities.deleteEntity(target);
|
||||
Script.update.disconnect(moveRats);
|
||||
Script.update.disconnect(updateTweens);
|
||||
Entities.deletingEntity.disconnect(popRatFromStack);
|
||||
Script.clearInterval(ratSpawnerInterval);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
|
||||
var ratSpawnerInterval;
|
||||
|
||||
if (USE_CONSTANT_SPAWNER === true) {
|
||||
ratSpawnerInterval = Script.setInterval(function() {
|
||||
var rat = addRat();
|
||||
playRatRunningAnimation(rat);
|
||||
rats.push(rat);
|
||||
ratCount++;
|
||||
if (ratCount % RAT_SOUND_RATE === 0) {
|
||||
var metaRat = {
|
||||
rat: rat,
|
||||
injector: createRatSoundInjector()
|
||||
}
|
||||
metaRats.push(metaRat);
|
||||
|
||||
Script.setTimeout(function() {
|
||||
//if we have too many injectors hanging around there are problems
|
||||
metaRat.injector.stop();
|
||||
delete metaRat.injector;
|
||||
}, RAT_SPAWN_RATE * RAT_SOUND_CLEAR_RATE;
|
||||
}
|
||||
|
||||
}, RAT_SPAWN_RATE);
|
||||
}
|
183
examples/drylake/ratSteer.js
Normal file
183
examples/drylake/ratSteer.js
Normal file
|
@ -0,0 +1,183 @@
|
|||
//
|
||||
// ratSteer.js
|
||||
//
|
||||
// Created by James B. Pollack @imgntn on 12/7/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example of steering behaviors that can be applied entities.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
function flee(thisEntity, target) {
|
||||
var targetPosition = Entities.getEntityProperties(target, "position").position;
|
||||
var properties = Entities.getEntityProperties(thisEntity, ["position", "velocity"]);
|
||||
var location = properties.position;
|
||||
var velocity = properties.velocity;
|
||||
var MAX_SPEED = 1;
|
||||
var MAX_FORCE = 1;
|
||||
var FLEE_RANGE = 2;
|
||||
var desired = Vec3.subtract(location, targetPosition);
|
||||
var d = Vec3.length(desired);
|
||||
desired = Vec3.normalize(desired);
|
||||
desired = Vec3.multiply(MAX_SPEED, desired);
|
||||
if (d < FLEE_RANGE) {
|
||||
var steer = Vec3.subtract(desired, velocity);
|
||||
|
||||
var steerVector = new V3(desired.x, 0, desired.z);
|
||||
steer = steerVector.limit(MAX_FORCE);
|
||||
|
||||
return steer;
|
||||
} else {
|
||||
//target too far away to flee
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function fleeAllAvatars(thisEntity) {
|
||||
//print('FLEE AVATARS');
|
||||
var properties = Entities.getEntityProperties(thisEntity, ["position", "velocity"]);
|
||||
var location = properties.position;
|
||||
var velocity = properties.velocity;
|
||||
|
||||
var nearbyEntities = Entities.findEntities(location, 3);
|
||||
var flightVectors = [];
|
||||
for (var entityIndex = 0; entityIndex < nearbyEntities.length; entityIndex++) {
|
||||
var entityID = nearbyEntities[entityIndex];
|
||||
var entityProps = Entities.getEntityProperties(entityID);
|
||||
if (entityProps.name === 'Hifi-Avatar-Detector') {
|
||||
//found an avatar to flee
|
||||
|
||||
var MAX_SPEED = 8;
|
||||
var MAX_FORCE = 8;
|
||||
var FLEE_AVATAR_RANGE = 3;
|
||||
var desired = Vec3.subtract(location, entityProps.position);
|
||||
var d = Vec3.length(desired);
|
||||
desired = Vec3.normalize(desired);
|
||||
desired = Vec3.multiply(MAX_SPEED, desired);
|
||||
if (d < FLEE_AVATAR_RANGE) {
|
||||
var steer = Vec3.subtract(desired, velocity);
|
||||
var steerVector = new V3(desired.x, 0, desired.z);
|
||||
steer = steerVector.limit(MAX_FORCE);
|
||||
flightVectors.push(steer);
|
||||
} else {
|
||||
// target too far away from this avatar to flee
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return flightVectors;
|
||||
}
|
||||
|
||||
function fleeAvoiderBlocks(thisEntity) {
|
||||
// print('FLEE AVOIDER BLOCKS');
|
||||
var properties = Entities.getEntityProperties(thisEntity, ["position", "velocity"]);
|
||||
var location = properties.position;
|
||||
var velocity = properties.velocity;
|
||||
|
||||
var nearbyEntities = Entities.findEntities(location, 2);
|
||||
var flightVectors = [];
|
||||
for (var entityIndex = 0; entityIndex < nearbyEntities.length; entityIndex++) {
|
||||
var entityID = nearbyEntities[entityIndex];
|
||||
var entityProps = Entities.getEntityProperties(entityID);
|
||||
if (entityProps.name === 'Hifi-Rat-Avoider') {
|
||||
//found an avoiderblock to flee
|
||||
|
||||
var MAX_SPEED = 11;
|
||||
var MAX_FORCE = 6;
|
||||
var FLEE_AVOIDER_RANGE = 5;
|
||||
|
||||
var desired = Vec3.subtract(location, entityProps.position);
|
||||
var d = Vec3.length(desired);
|
||||
desired = Vec3.normalize(desired);
|
||||
desired = Vec3.multiply(MAX_SPEED, desired);
|
||||
|
||||
if (d < FLEE_AVOIDER_RANGE) {
|
||||
var steer = Vec3.subtract(desired, velocity);
|
||||
var steerVector = new V3(desired.x, 0, desired.z);
|
||||
steer = steerVector.limit(MAX_FORCE);
|
||||
flightVectors.push(steer);
|
||||
} else {
|
||||
//target too far away from this avoider to flee
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return flightVectors;
|
||||
}
|
||||
|
||||
function arrive(thisEntity, target) {
|
||||
|
||||
var targetPosition = Entities.getEntityProperties(target, "position").position;
|
||||
var properties = Entities.getEntityProperties(thisEntity, ["position", "velocity"]);
|
||||
var location = properties.position;
|
||||
var velocity = properties.velocity;
|
||||
var MAX_SPEED = 10;
|
||||
var MAX_FORCE = 6;
|
||||
var ARRIVAL_DISTANCE = 2;
|
||||
|
||||
var desired = Vec3.subtract(targetPosition, location);
|
||||
var d = Vec3.length(desired);
|
||||
desired = Vec3.normalize(desired);
|
||||
|
||||
if (d < ARRIVAL_DISTANCE) {
|
||||
var m = scale(d, 0, ARRIVAL_DISTANCE, 0, MAX_SPEED);
|
||||
} else {
|
||||
desired = Vec3.multiply(MAX_SPEED, desired);
|
||||
|
||||
}
|
||||
|
||||
var steer = Vec3.subtract(desired, velocity);
|
||||
var steerVector = new V3(desired.x, 0, desired.z);
|
||||
steer = steerVector.limit(MAX_FORCE);
|
||||
|
||||
return steer;
|
||||
}
|
||||
|
||||
|
||||
function V3(x, y, z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
return
|
||||
}
|
||||
|
||||
V3.prototype.length = function() {
|
||||
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
||||
};
|
||||
|
||||
V3.prototype.limit = function(s) {
|
||||
var len = this.length();
|
||||
|
||||
if (len > s && len > 0) {
|
||||
this.scale(s / len);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
V3.prototype.scale = function(f) {
|
||||
this.x *= f;
|
||||
this.y *= f;
|
||||
this.z *= f;
|
||||
return this;
|
||||
};
|
||||
|
||||
var v3 = new V3();
|
||||
|
||||
var scale = function(value, min1, max1, min2, max2) {
|
||||
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
|
||||
}
|
||||
|
||||
loadSteer = function() {
|
||||
return {
|
||||
flee: flee,
|
||||
fleeAllAvatars: fleeAllAvatars,
|
||||
fleeAvoiderBlocks: fleeAvoiderBlocks,
|
||||
arrive: arrive
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue