mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 08:04:01 +02:00
Fish flocking example
This commit is contained in:
parent
9f95a9de89
commit
ee95f7906b
1 changed files with 161 additions and 0 deletions
161
examples/FlockOfFish.js
Normal file
161
examples/FlockOfFish.js
Normal file
|
@ -0,0 +1,161 @@
|
|||
//
|
||||
// flockOfFish.js
|
||||
// examples
|
||||
//
|
||||
// Philip Rosedale
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
// Fish smimming around in a space in front of 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 LIFETIME = 60;
|
||||
var NUM_FISH = 20;
|
||||
var TANK_WIDTH = 3.0;
|
||||
var TANK_HEIGHT = 1.0;
|
||||
var FISH_WIDTH = 0.03;
|
||||
var FISH_LENGTH = 0.15;
|
||||
var MAX_SIGHT_DISTANCE = 0.4;
|
||||
var MIN_SEPARATION = 0.15;
|
||||
var AVOIDANCE_FORCE = 0.2;
|
||||
var COHESION_FORCE = 0.05;
|
||||
var ALIGNMENT_FORCE = 0.05;
|
||||
var SWIMMING_FORCE = 0.05;
|
||||
var SWIMMING_SPEED = 2.0;
|
||||
|
||||
var fishLoaded = false;
|
||||
var fish = [];
|
||||
|
||||
var lowerCorner = { x: 0, y: 0, z: 0 };
|
||||
var upperCorner = { x: 0, y: 0, z: 0 };
|
||||
|
||||
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 updateFish(deltaTime) {
|
||||
if (!Entities.serversExist() || !Entities.canRez()) {
|
||||
return;
|
||||
}
|
||||
if (!fishLoaded) {
|
||||
loadFish(NUM_FISH);
|
||||
fishLoaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var averageVelocity = { x: 0, y: 0, z: 0 };
|
||||
var averagePosition = { x: 0, y: 0, z: 0 };
|
||||
var birdPositionsCounted = 0;
|
||||
var birdVelocitiesCounted = 0;
|
||||
for (var i = 0; i < fish.length; i++) {
|
||||
if (fish[i].entityId) {
|
||||
var properties = Entities.getEntityProperties(fish[i].entityId);
|
||||
// If Bird has been deleted, bail
|
||||
if (properties.id != fish[i].entityId) {
|
||||
fish[i].entityId = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var velocity = properties.velocity;
|
||||
var position = properties.position;
|
||||
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) {
|
||||
var otherProps = Entities.getEntityProperties(fish[j].entityId);
|
||||
var separation = Vec3.distance(properties.position, otherProps.position);
|
||||
if (separation < MAX_SIGHT_DISTANCE) {
|
||||
averageVelocity = Vec3.sum(averageVelocity, otherProps.velocity);
|
||||
averagePosition = Vec3.sum(averagePosition, otherProps.position);
|
||||
othersCounted++;
|
||||
}
|
||||
if (separation < MIN_SEPARATION) {
|
||||
var pushAway = Vec3.multiply(Vec3.normalize(Vec3.subtract(properties.position, otherProps.position)), AVOIDANCE_FORCE);
|
||||
velocity = Vec3.sum(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
|
||||
velocity = Vec3.mix(velocity, Vec3.multiply(Vec3.normalize(averageVelocity), Vec3.length(velocity)), ALIGNMENT_FORCE);
|
||||
// Cohesion: Steer towards center of flock
|
||||
var towardCenter = Vec3.subtract(averagePosition, position);
|
||||
velocity = Vec3.mix(velocity, Vec3.multiply(Vec3.normalize(towardCenter), Vec3.length(velocity)), COHESION_FORCE);
|
||||
// Try to swim at a constant speed
|
||||
velocity = Vec3.mix(velocity, Vec3.multiply(Vec3.normalize(velocity), SWIMMING_SPEED), SWIMMING_FORCE);
|
||||
}
|
||||
|
||||
// Keep fish in their 'tank'
|
||||
if (position.x < lowerCorner.x) {
|
||||
position.x = lowerCorner.x;
|
||||
velocity.x *= -1.0;
|
||||
} else if (position.x > upperCorner.x) {
|
||||
position.x = upperCorner.x;
|
||||
velocity.x *= -1.0;
|
||||
}
|
||||
if (position.y < lowerCorner.y) {
|
||||
position.y = lowerCorner.y;
|
||||
velocity.y *= -1.0;
|
||||
} else if (position.y > upperCorner.y) {
|
||||
position.y = upperCorner.y;
|
||||
velocity.y *= -1.0;
|
||||
}
|
||||
if (position.z < lowerCorner.z) {
|
||||
position.z = lowerCorner.z;
|
||||
velocity.z *= -1.0;
|
||||
} else if (position.z > upperCorner.z) {
|
||||
position.z = upperCorner.z;
|
||||
velocity.z *= -1.0;
|
||||
}
|
||||
|
||||
// Orient in direction of velocity
|
||||
var rotation = Quat.rotationBetween(Vec3.UNIT_NEG_Z, velocity);
|
||||
Entities.editEntity(fish[i].entityId, { position: position, velocity: velocity, rotation: Quat.mix(properties.rotation, rotation, 0.33) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Connect a call back that happens every frame
|
||||
Script.update.connect(updateFish);
|
||||
|
||||
// Delete our little friends if script is stopped
|
||||
Script.scriptEnding.connect(function() {
|
||||
for (var i = 0; i < fish.length; i++) {
|
||||
Entities.deleteEntity(fish[i].entityId);
|
||||
}
|
||||
});
|
||||
|
||||
var STARTING_FRACTION = 0.25;
|
||||
function loadFish(howMany) {
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), 3 * TANK_WIDTH));
|
||||
lowerCorner = { x: center.x - TANK_WIDTH / 2, y: center.y, z: center.z - TANK_WIDTH / 2 };
|
||||
upperCorner = { x: center.x + TANK_WIDTH / 2, y: center.y + TANK_HEIGHT, z: center.z + TANK_WIDTH / 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
|
||||
};
|
||||
|
||||
fish.push({
|
||||
entityId: Entities.addEntity({
|
||||
type: "Box",
|
||||
position: position,
|
||||
rotation: { x: 0, y: 0, z: 0, w: 1 },
|
||||
dimensions: { x: FISH_WIDTH, y: FISH_WIDTH, z: FISH_LENGTH },
|
||||
velocity: { x: SWIMMING_SPEED, y: SWIMMING_SPEED, z: SWIMMING_SPEED },
|
||||
damping: 0.0,
|
||||
dynamic: false,
|
||||
lifetime: LIFETIME,
|
||||
color: { red: 0, green: 255, blue: 255 }
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue