示例#1
0
void Robot::lookAtBehind(const Math::Angle &angle) {
  float targetAngle;

  if (angle.rad() > 0.0f)
    targetAngle = angle.rad() - Math::PI;
  else
    targetAngle = angle.rad() + Math::PI;

  lookAt(Math::Rad(targetAngle));
}
示例#2
0
float Movement::computeAngleBetweenVectorsXYPlane(const Math::Vector3d &v1, const Math::Vector3d &v2) const {
	Math::Vector3d v1XY = v1;
	v1XY.z() = 0.0;

	Math::Vector3d v2XY = v2;
	v2XY.z() = 0.0;

	Math::Angle angle = Math::Vector3d::angle(v1XY, v2XY);
	Math::Vector3d cross = Math::Vector3d::crossProduct(v1XY, v2XY);
	if (cross.z() < 0) {
		angle = -angle;
	}

	return angle.getDegrees();
}
示例#3
0
bool KeyframeAnim::KeyframeNode::animate(ModelNode &node, float frame, float fade, bool useDelta) const {
	if (_numEntries == 0)
		return false;

	// Do a binary search for the nearest previous frame
	// Loop invariant: entries_[low].frame_ <= frame < entries_[high].frame_
	int low = 0, high = _numEntries;
	while (high > low + 1) {
		int mid = (low + high) / 2;
		if (_entries[mid]._frame <= frame)
			low = mid;
		else
			high = mid;
	}

	float dt = frame - _entries[low]._frame;
	Math::Vector3d pos = _entries[low]._pos;
	Math::Angle pitch = _entries[low]._pitch;
	Math::Angle yaw = _entries[low]._yaw;
	Math::Angle roll = _entries[low]._roll;

	/** @bug Interpolating between two orientations specified by Euler angles (yaw/pitch/roll)
	 *	by linearly interpolating the YPR values does not compute proper in-between
	 *	poses, i.e. the rotation from start to finish does not go via the shortest arc.
	 *	Though, if the start and end poses are very similar to each other, this can look
	 *	acceptable without visual artifacts.
	 */
	if (useDelta) {
		pos += dt * _entries[low]._dpos;
		pitch += dt * _entries[low]._dpitch;
		yaw += dt * _entries[low]._dyaw;
		roll += dt * _entries[low]._droll;
	}

	node._animPos += (pos - node._pos) * fade;

	Math::Angle dpitch = pitch - node._pitch;
	node._animPitch += dpitch.normalize(-180) * fade;

	Math::Angle dyaw = yaw - node._yaw;
	node._animYaw += dyaw.normalize(-180) * fade;

	Math::Angle droll = roll - node._roll;
	node._animRoll += droll.normalize(-180) * fade;

	return true;
}
示例#4
0
void Robot::lookAt(const Math::Angle &angle) {
  setTargetOmega(Math::limit(angle.rad() * Config::lookAtP, Math::degToRad(Config::lookAtMaxSpeedAngle) * Config::lookAtP));
}
示例#5
0
void Robot::setTargetDir(const Math::Angle &dir, float speed, float omega) {
  Math::Vector dirVector = Math::Vector::createForwardVec(dir.rad(), speed);

  setTargetDir(dirVector.x, dirVector.y, omega);
}
示例#6
0
void Head::lookAt(bool entering, const Math::Vector3d &point, float rate, const Math::Matrix4 &matrix) {
	if (_joint1Node) {
		float step = g_grim->getPerSecond(rate);
		float yawStep = step;
		float pitchStep = step / 3.f;
		if (!entering) {
			//animate yaw
			if (_headYaw > yawStep) {
				_headYaw -= yawStep;
			} else if (_headYaw < -yawStep) {
				_headYaw += yawStep;
			} else {
				_headYaw = 0;
			}
			//animate pitch
			if (_headPitch > pitchStep) {
				_headPitch -= pitchStep;
			} else if (_headPitch < -pitchStep) {
				_headPitch += pitchStep;
			} else {
				_headPitch = 0;
			}
			_joint1Node->_animYaw = _headYaw;
			Math::Angle pi = _headPitch / 3.f;
			_joint1Node->_animPitch += pi;
			_joint2Node->_animPitch += pi;
			_joint3Node->_animPitch += pi;
			_joint1Node->_animRoll = (_joint1Node->_animYaw.getDegrees() / 20.f) *
			_headPitch.getDegrees() / -5.f;

			if (_joint1Node->_animRoll > _maxRoll)
				_joint1Node->_animRoll = _maxRoll;
			if (_joint1Node->_animRoll < -_maxRoll)
				_joint1Node->_animRoll = -_maxRoll;
			return;
		}

		ModelNode *p = _joint3Node;
		while (p->_parent) {
			p = p->_parent;
		}
		p->setMatrix(matrix);
		p->update();

		Math::Vector3d v = point - _joint3Node->_matrix.getPosition();
		if (v.isZero()) {
			return;
		}

		float magnitude = sqrt(v.x() * v.x() + v.y() * v.y());
		float a = v.x() / magnitude;
		float b = v.y() / magnitude;
		float yaw;
		yaw = acos(a) * (180.0f / LOCAL_PI);
		if (b < 0.0f)
			yaw = 360.0f - yaw;

		Math::Angle bodyYaw = matrix.getYaw();
		p = _joint1Node->_parent;
		while (p) {
			bodyYaw += p->_yaw + p->_animYaw;
			p = p->_parent;
		}

		_joint1Node->_animYaw = (- 90 + yaw - bodyYaw);
		if (_joint1Node->_animYaw < -180.) {
			_joint1Node->_animYaw += 360;
		}
		if (_joint1Node->_animYaw > 180.) {
			_joint1Node->_animYaw -= 360;
		}

		if (_joint1Node->_animYaw > _maxYaw)
			_joint1Node->_animYaw = _maxYaw;
		if (_joint1Node->_animYaw < -_maxYaw)
			_joint1Node->_animYaw = -_maxYaw;

		float sqLenght = v.x() * v.x() + v.y() * v.y();
		float h;
		if (sqLenght > 0) {
			h = sqrt(sqLenght);
		} else {
			h = -sqrt(sqLenght);
		}
		magnitude = sqrt(v.z() * v.z() + h * h);
		a = h / magnitude;
		b = v.z() / magnitude;
		Math::Angle pitch;
		pitch = acos(a) * (180.0f / LOCAL_PI);

		if (b < 0.0f)
			pitch = 360.0f - pitch;

		if (pitch > 180)
			pitch -= 360;

		if (pitch > _maxPitch)
			pitch = _maxPitch;
		if (pitch < -_maxPitch)
			pitch = -_maxPitch;

		if ((_joint1Node->_animYaw > 0 && pitch < 0) || (_joint1Node->_animYaw < 0 && pitch > 0)) {
			pitch += _joint1Node->_animYaw / 10.f;
		} else {
			pitch -= _joint1Node->_animYaw / 10.f;
		}

		//animate pitch
		if (pitch - _headPitch > pitchStep)
			pitch = _headPitch + pitchStep;
		if (_headPitch - pitch > pitchStep)
			pitch = _headPitch - pitchStep;

		Math::Angle pi = pitch / 3.f;
		_joint1Node->_animPitch += pi;
		_joint2Node->_animPitch += pi;
		_joint3Node->_animPitch += pi;

		//animate yaw
		if (_joint1Node->_animYaw - _headYaw > yawStep)
			_joint1Node->_animYaw = _headYaw + yawStep;
		if (_headYaw - _joint1Node->_animYaw > yawStep)
			_joint1Node->_animYaw = _headYaw - yawStep;

		_joint1Node->_animRoll = (_joint1Node->_animYaw.getDegrees() / 20.f) *
		pitch.getDegrees() / -5.f;

		if (_joint1Node->_animRoll > _maxRoll)
			_joint1Node->_animRoll = _maxRoll;
		if (_joint1Node->_animRoll < -_maxRoll)
			_joint1Node->_animRoll = -_maxRoll;

		_headPitch = pitch;
		_headYaw = _joint1Node->_animYaw;
	}
}
示例#7
0
void Actor::update(uint frameTime) {
	// Snap actor to walkboxes if following them.  This might be
	// necessary for example after activating/deactivating
	// walkboxes, etc.
	if (_constrain && !_walking) {
		g_grim->getCurrSet()->findClosestSector(_pos, NULL, &_pos);
	}

	if (_turning) {
		float turnAmt = g_grim->getPerSecond(_turnRate) * 5.f;
		Math::Angle dyaw = _moveYaw - _yaw;
		dyaw.normalize(-180);
		// If the actor won't turn because the rate is set to zero then
		// have the actor turn all the way to the destination yaw.
		// Without this some actors will lock the interface on changing
		// scenes, this affects the Bone Wagon in particular.
		if (turnAmt == 0 || turnAmt >= fabsf(dyaw.getDegrees())) {
			setYaw(_moveYaw);
			_turning = false;
		} else if (dyaw > 0) {
			setYaw(_yaw + turnAmt);
		} else {
			setYaw(_yaw - turnAmt);
		}
		_currTurnDir = (dyaw > 0 ? 1 : -1);
	}

	if (_walking) {
		updateWalk();
	}

	if (_walkChore.isValid()) {
		if (_walkedCur) {
			if (!_walkChore.isPlaying()) {
				_walkChore.playLooping(true);
			}
			if (_restChore.isPlaying()) {
				_restChore.stop(true);
			}
		} else {
			if (_walkedLast && _walkChore.isPlaying()) {
				_walkChore.stop(true);
				if (!_restChore.isPlaying()) {
					_restChore.playLooping(true);
				}
			}
		}
	}

	if (_leftTurnChore.isValid()) {
		if (_walkedCur || _walkedLast)
			_currTurnDir = 0;

		if (_restChore.isValid()) {
			if (_currTurnDir != 0) {
				if (getTurnChore(_currTurnDir)->isPlaying() && _restChore.isPlaying()) {
					_restChore.stop(true, 500);
				}
			} else if (_lastTurnDir != 0) {
				if (!_walkedCur && getTurnChore(_lastTurnDir)->isPlaying()) {
					_restChore.playLooping(true);
				}
			}
		}

		if (_lastTurnDir != 0 && _lastTurnDir != _currTurnDir) {
			getTurnChore(_lastTurnDir)->stop(true);
		}
		if (_currTurnDir != 0 && _currTurnDir != _lastTurnDir) {
			getTurnChore(_currTurnDir)->playLooping(true, 500);
		}
	} else {
		_currTurnDir = 0;
	}

	// The rest chore might have been stopped because of a
	// StopActorChore(nil).  Restart it if so.
	if (!_walkedCur && _currTurnDir == 0 && !_restChore.isPlaying()) {
		_restChore.playLooping(true);
	}

	_walkedLast = _walkedCur;
	_walkedCur = false;
	_lastTurnDir = _currTurnDir;
	_currTurnDir = 0;

	// Update lip syncing
	if (_lipSync) {
		int posSound;

		// While getPosIn60HzTicks will return "-1" to indicate that the
		// sound is no longer playing, it is more appropriate to check first
		if (g_grim->getSpeechMode() != GrimEngine::TextOnly && g_sound->getSoundStatus(_talkSoundName.c_str()))
			posSound = g_sound->getPosIn60HzTicks(_talkSoundName.c_str());
		else
			posSound = -1;
		if (posSound != -1) {
			int anim = _lipSync->getAnim(posSound);
			if (_talkAnim != anim) {
				if (anim != -1) {
					if (_talkChore[anim].isValid()) {
						stopMumbleChore();
						if (_talkAnim != -1) {
							_talkChore[_talkAnim].stop();
						}

						// Run the stop_talk chore so that it resets the components
						// to the right visibility.
						stopTalking();
						_talkAnim = anim;
						_talkChore[_talkAnim].play();
					} else if (_mumbleChore.isValid() && !_mumbleChore.isPlaying()) {
						_mumbleChore.playLooping();
						_talkAnim = -1;
					}
				} else {
					stopMumbleChore();
					if (_talkAnim != -1)
						_talkChore[_talkAnim].stop();

					_talkAnim = 0;
					stopTalking();
				}
			}
		}
	}

	frameTime = (uint)(frameTime * _timeScale);
	for (Common::List<Costume *>::iterator i = _costumeStack.begin(); i != _costumeStack.end(); ++i) {
		Costume *c = *i;
		c->setPosRotate(_pos, _pitch, _yaw, _roll);
		int marker = c->update(frameTime);
		if (marker > 0) {
			costumeMarkerCallback(marker);
		}
	}

	for (Common::List<Costume *>::iterator i = _costumeStack.begin(); i != _costumeStack.end(); ++i) {
		Costume *c = *i;
		c->animate();
	}

	for (Common::List<Costume *>::iterator i = _costumeStack.begin(); i != _costumeStack.end(); ++i) {
		Costume *c = *i;
		c->moveHead(_lookingMode, _lookAtVector);
	}
}