mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 03:58:07 +02:00
Merge pull request #1068 from ey6es/encircle
First stab at chat circling behavior.
This commit is contained in:
commit
f9992dd704
2 changed files with 102 additions and 0 deletions
|
@ -351,6 +351,8 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateChatCircle(deltaTime);
|
||||||
|
|
||||||
_position += _velocity * deltaTime;
|
_position += _velocity * deltaTime;
|
||||||
|
|
||||||
// Zero thrust out now that we've added it to velocity in this frame
|
// Zero thrust out now that we've added it to velocity in this frame
|
||||||
|
@ -1092,6 +1094,105 @@ void MyAvatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTi
|
||||||
_velocity += bodyPushForce;
|
_velocity += bodyPushForce;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SortedAvatar {
|
||||||
|
public:
|
||||||
|
Avatar* avatar;
|
||||||
|
float distance;
|
||||||
|
glm::vec3 accumulatedCenter;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator<(const SortedAvatar& s1, const SortedAvatar& s2) {
|
||||||
|
return s1.distance < s2.distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::updateChatCircle(float deltaTime) {
|
||||||
|
// find all members and sort by distance
|
||||||
|
QVector<SortedAvatar> sortedAvatars;
|
||||||
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
|
if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
|
||||||
|
SortedAvatar sortedAvatar;
|
||||||
|
sortedAvatar.avatar = (Avatar*)node->getLinkedData();
|
||||||
|
sortedAvatar.distance = glm::distance(_position, sortedAvatar.avatar->getPosition());
|
||||||
|
sortedAvatars.append(sortedAvatar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qSort(sortedAvatars.begin(), sortedAvatars.end());
|
||||||
|
|
||||||
|
// compute the accumulated centers
|
||||||
|
glm::vec3 center = _position;
|
||||||
|
for (int i = 0; i < sortedAvatars.size(); i++) {
|
||||||
|
SortedAvatar& sortedAvatar = sortedAvatars[i];
|
||||||
|
sortedAvatar.accumulatedCenter = (center += sortedAvatar.avatar->getPosition()) / (i + 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove members whose accumulated circles are too far away to influence us
|
||||||
|
const float CIRCUMFERENCE_PER_MEMBER = 2.0f;
|
||||||
|
const float CIRCLE_INFLUENCE_SCALE = 1.1f;
|
||||||
|
for (int i = sortedAvatars.size() - 1; i >= 0; i--) {
|
||||||
|
float radius = (CIRCUMFERENCE_PER_MEMBER * (i + 2)) / PI_TIMES_TWO;
|
||||||
|
if (glm::distance(_position, sortedAvatars[i].accumulatedCenter) > radius * CIRCLE_INFLUENCE_SCALE) {
|
||||||
|
sortedAvatars.remove(i);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sortedAvatars.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
center = sortedAvatars.last().accumulatedCenter;
|
||||||
|
float radius = (CIRCUMFERENCE_PER_MEMBER * (sortedAvatars.size() + 1)) / PI_TIMES_TWO;
|
||||||
|
|
||||||
|
// compute the average up vector
|
||||||
|
glm::vec3 up = getWorldAlignedOrientation() * IDENTITY_UP;
|
||||||
|
foreach (const SortedAvatar& sortedAvatar, sortedAvatars) {
|
||||||
|
up += sortedAvatar.avatar->getWorldAlignedOrientation() * IDENTITY_UP;
|
||||||
|
}
|
||||||
|
up = glm::normalize(up);
|
||||||
|
|
||||||
|
// find reasonable corresponding right/front vectors
|
||||||
|
glm::vec3 front = glm::cross(up, IDENTITY_RIGHT);
|
||||||
|
if (glm::length(front) < EPSILON) {
|
||||||
|
front = glm::cross(up, IDENTITY_FRONT);
|
||||||
|
}
|
||||||
|
front = glm::normalize(front);
|
||||||
|
glm::vec3 right = glm::cross(front, up);
|
||||||
|
|
||||||
|
// find our angle and the angular distances to our closest neighbors
|
||||||
|
glm::vec3 delta = _position - center;
|
||||||
|
glm::vec3 projected = glm::vec3(glm::dot(right, delta), glm::dot(front, delta), 0.0f);
|
||||||
|
float myAngle = glm::length(projected) > EPSILON ? atan2f(projected.y, projected.x) : 0.0f;
|
||||||
|
float leftDistance = PIf;
|
||||||
|
float rightDistance = PIf;
|
||||||
|
foreach (const SortedAvatar& sortedAvatar, sortedAvatars) {
|
||||||
|
delta = sortedAvatar.avatar->getPosition() - center;
|
||||||
|
projected = glm::vec3(glm::dot(right, delta), glm::dot(front, delta), 0.0f);
|
||||||
|
float angle = glm::length(projected) > EPSILON ? atan2f(projected.y, projected.x) : 0.0f;
|
||||||
|
if (angle < myAngle) {
|
||||||
|
leftDistance = min(myAngle - angle, leftDistance);
|
||||||
|
rightDistance = min(PI_TIMES_TWO - (myAngle - angle), rightDistance);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
leftDistance = min(PI_TIMES_TWO - (angle - myAngle), leftDistance);
|
||||||
|
rightDistance = min(angle - myAngle, rightDistance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// split the difference between our neighbors
|
||||||
|
float targetAngle = myAngle + (rightDistance - leftDistance) / 2.0f;
|
||||||
|
glm::vec3 targetPosition = center + (front * sinf(targetAngle) + right * cosf(targetAngle)) * radius;
|
||||||
|
|
||||||
|
// face the center of the circle
|
||||||
|
glm::quat orientation = getOrientation();
|
||||||
|
glm::quat targetOrientation = rotationBetween(orientation * IDENTITY_FRONT, center - targetPosition) * orientation;
|
||||||
|
targetOrientation = rotationBetween(targetOrientation * IDENTITY_UP, up) * targetOrientation;
|
||||||
|
|
||||||
|
// approach the target position/orientation
|
||||||
|
const float APPROACH_RATE = 0.025f;
|
||||||
|
_position = glm::mix(_position, targetPosition, APPROACH_RATE);
|
||||||
|
setOrientation(safeMix(orientation, targetOrientation, APPROACH_RATE));
|
||||||
|
}
|
||||||
|
|
||||||
void MyAvatar::setGravity(glm::vec3 gravity) {
|
void MyAvatar::setGravity(glm::vec3 gravity) {
|
||||||
_gravity = gravity;
|
_gravity = gravity;
|
||||||
_head.setGravity(_gravity);
|
_head.setGravity(_gravity);
|
||||||
|
|
|
@ -94,6 +94,7 @@ private:
|
||||||
void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping);
|
void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping);
|
||||||
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
|
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
|
||||||
void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime );
|
void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime );
|
||||||
|
void updateChatCircle(float deltaTime);
|
||||||
void checkForMouseRayTouching();
|
void checkForMouseRayTouching();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue