James B. Pollackatp7e87bfb10 years agoHistory
166 lines · 7.3 KB · JavaScript
RawDownload
////  entityLocalFish.js//  examples////  Philip Rosedale//  Copyright 2016 High Fidelity, Inc.   //  Fish smimming around in a space in front of you//  These fish are overlays, meaning they can only be seen by you. //  Attach this entity script to an object to create fish that stay within the //  dimensions of the object.   //   //  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html (function(){      var NUM_FISH = 25;    var FISH_SCALE = 0.45;    var MAX_SIGHT_DISTANCE = 0.5;    var MIN_SEPARATION = 0.08;      var AVOIDANCE_FORCE = 0.05;      var COHESION_FORCE = 0.025;      var ALIGNMENT_FORCE = 0.025;      var SWIMMING_FORCE = 0.025;       var SWIMMING_SPEED = 0.5;      var VELOCITY_FOLLOW_RATE = 0.25;    var FISH_MODEL_URL = "atp:/fishTank/goodfish5.fbx";     var fishLoaded = false;     var fish = [];     var lowerCorner = { x: 0, y: 0, z: 0 };    var upperCorner = { x: 0, y: 0, z: 0 };     var entityID;        function update(deltaTime) {         var averageVelocity = { x: 0, y: 0, z: 0 };        var averagePosition = { x: 0, y: 0, z: 0 };         for (var i = 0; i < fish.length; i++) {                        // Update position by velocity            fish[i].position = Vec3.sum(fish[i].position, Vec3.multiply(deltaTime, fish[i].velocity));             averageVelocity = { x: 0, y: 0, z: 0 };            averagePosition = { x: 0, y: 0, z: 0 };             var othersCounted = 0;            for (var j = 0; j < fish.length; j++) {                if (i != j) {                    // Get only the properties we need, because that is faster                    var separation = Vec3.distance(fish[i].position, fish[j].position);                    if (separation < MAX_SIGHT_DISTANCE) {                        averageVelocity = Vec3.sum(averageVelocity, fish[j].velocity);                        averagePosition = Vec3.sum(averagePosition, fish[j].position);                        othersCounted++;                    }                    if (separation < MIN_SEPARATION) {                        // Separation:  Push away if you are too close to someone else                        var pushAway = Vec3.multiply(Vec3.normalize(Vec3.subtract(fish[i].position, fish[j].position)), AVOIDANCE_FORCE);                        fish[i].velocity = Vec3.sum(fish[i].velocity, pushAway);                    }                }            }             if (othersCounted > 0) {                averageVelocity = Vec3.multiply(averageVelocity, 1.0 / othersCounted);                averagePosition = Vec3.multiply(averagePosition, 1.0 / othersCounted);                //  Alignment: Follow group's direction and speed                fish[i].velocity = Vec3.mix(fish[i].velocity, Vec3.multiply(Vec3.normalize(averageVelocity), Vec3.length(fish[i].velocity)), ALIGNMENT_FORCE);                // Cohesion: Steer towards center of flock                var towardCenter = Vec3.subtract(averagePosition, fish[i].position);                fish[i].velocity = Vec3.mix(fish[i].velocity, Vec3.multiply(Vec3.normalize(towardCenter), Vec3.length(fish[i].velocity)), COHESION_FORCE);            }             //  Try to swim at a constant speed            fish[i].velocity = Vec3.mix(fish[i].velocity, Vec3.multiply(Vec3.normalize(fish[i].velocity), SWIMMING_SPEED), SWIMMING_FORCE);             //  Keep fish in their 'tank'             if (fish[i].position.x < lowerCorner.x) {                fish[i].position.x = lowerCorner.x;                 fish[i].velocity.x *= -1.0;            } else if (fish[i].position.x > upperCorner.x) {                fish[i].position.x = upperCorner.x;                 fish[i].velocity.x *= -1.0;            }            if (fish[i].position.y < lowerCorner.y) {                fish[i].position.y = lowerCorner.y;                 fish[i].velocity.y *= -1.0;            } else if (fish[i].position.y > upperCorner.y) {                fish[i].position.y = upperCorner.y;                 fish[i].velocity.y *= -1.0;            }             if (fish[i].position.z < lowerCorner.z) {                fish[i].position.z = lowerCorner.z;                 fish[i].velocity.z *= -1.0;            } else if (fish[i].position.z > upperCorner.z) {                fish[i].position.z = upperCorner.z;                 fish[i].velocity.z *= -1.0;            }              //  Orient in direction of velocity             var rotation = Quat.rotationBetween(Vec3.UNIT_NEG_Z, fish[i].velocity);            fish[i].rotation = Quat.slerp(fish[i].rotation, rotation, VELOCITY_FOLLOW_RATE);             //  Update the actual 3D overlay            Overlays.editOverlay(fish[i].overlayID, {   position: fish[i].position,                                                         velocity: fish[i].velocity,                                                         rotation: fish[i].rotation });        }    }        function randomVector(scale) {        return { x: Math.random() * scale - scale / 2.0, y: Math.random() * scale - scale / 2.0, z: Math.random() * scale - scale / 2.0 };    }     function loadFish(entityID, howMany) {         var STARTING_FRACTION = 0.25;         var properties = Entities.getEntityProperties(entityID);        lowerCorner = { x: properties.position.x - properties.dimensions.x / 2,                         y: properties.position.y - properties.dimensions.y / 2,                         z: properties.position.z - properties.dimensions.z / 2 };        upperCorner = { x: properties.position.x + properties.dimensions.x / 2,                         y: properties.position.y + properties.dimensions.y / 2,                         z: properties.position.z + properties.dimensions.z / 2 };         for (var i = 0; i < howMany; i++) {            var position = {                 x: lowerCorner.x + (upperCorner.x - lowerCorner.x) / 2.0 + (Math.random() - 0.5) * (upperCorner.x - lowerCorner.x) * STARTING_FRACTION,                 y: lowerCorner.y + (upperCorner.y - lowerCorner.y) / 2.0 + (Math.random() - 0.5) * (upperCorner.y - lowerCorner.y) * STARTING_FRACTION,                 z: lowerCorner.z + (upperCorner.z - lowerCorner.x) / 2.0 + (Math.random() - 0.5) * (upperCorner.z - lowerCorner.z) * STARTING_FRACTION                };             var rotation = { x: 0, y: 0, z: 0, w: 1 };            fish.push({                    overlayID:  Overlays.addOverlay("model", {                                                    url: FISH_MODEL_URL,                                                    position: position,                                                    rotation: rotation,                                                    scale: FISH_SCALE,                                                     visible: true }),                    position: position,                    rotation: rotation,                    velocity: randomVector(SWIMMING_SPEED)                    });        }        print("Fish loaded");    }     this.preload = function(entityID) {         print("Fish Preload v3");        loadFish(entityID, NUM_FISH);        fishLoaded = true;        Script.update.connect(update);     };      this.unload = function() {        Script.update.disconnect(update);        print("Fish Unload");        for (var i = 0; i < fish.length; i++) {            Overlays.deleteOverlay(fish[i].overlayID);        }    };})