--- /dev/null
+/*
+ * Entity.cpp
+ *
+ * Created on: Apr 25, 2012
+ * Author: holy
+ */
+
+#include "Entity.h"
+
+#include "../app/Timer.h"
+#include "../geometry/constants.h"
+
+#include <limits>
+
+using geometry::PI;
+using std::numeric_limits;
+
+namespace game {
+
+
+void Entity::Update(const app::Timer &timer) {
+ translation += linearVelocity * timer.DeltaT();
+ rotation += angularVelocity * timer.DeltaT();
+ if (rotation > 2.0 * PI) {
+ rotation -= 2.0 * PI;
+ } else if (rotation < -(2.0 * PI)) {
+ rotation += 2.0 * PI;
+ }
+ shape->Translate(linearVelocity * timer.DeltaT());
+ shape->Rotate(angularVelocity * timer.DeltaT());
+}
+
+bool Entity::CheckCollision(const Entity &other, Ray &ray) {
+ return shape->CheckCollision(*other.shape, ray);
+}
+
+
+Entity::Vector Entity::VelocityAt(const Vector &p) const {
+ if (angularVelocity == 0 || p == translation) return linearVelocity;
+
+ Vector v(linearVelocity);
+ Vector pRelative(p - translation);
+ v += pRelative.Rotate90() * angularVelocity;
+ return v;
+}
+
+
+void Entity::Rotate(Scalar d) {
+ rotation += d;
+ shape->Rotate(d);
+}
+
+void Entity::Translate(const Vector &d) {
+ translation += d;
+ shape->Translate(d);
+}
+
+void Entity::Accelerate(const Vector &dvl, Scalar dva) {
+ linearVelocity += dvl;
+ angularVelocity += dva;
+}
+
+
+void Entity::CollisionResponse(Entity &a, const Ray &na, Entity &b) {
+ if (a.mass == numeric_limits<Scalar>::infinity()
+ && b.mass == numeric_limits<Scalar>::infinity()) {
+ // special case: collision of two infinitely heavy entities
+ InfInfCollisionResponse(a, na, b);
+ return;
+ }
+
+ const Scalar e(1);
+
+ const Vector va(a.LinearVelocity());
+ const Vector vb(b.LinearVelocity());
+ const Scalar wa(a.AngularVelocity());
+ const Scalar wb(b.AngularVelocity());
+
+ const Vector vap(a.VelocityAt(na.Origin()));
+ const Vector vbp(b.VelocityAt(na.Origin()));
+ const Vector vab = vap - vbp;
+
+ const Vector rap90((na.Origin() - a.Origin()).Rotate90());
+ const Vector rbp90((na.Origin() - b.Origin()).Rotate90());
+
+ const Scalar ia(a.Mass());
+ const Scalar ib(b.Mass());
+
+ const Scalar rap90dotN(rap90.Dot(na.Direction()));
+ const Scalar rbp90dotN(rbp90.Dot(na.Direction()));
+
+ const Scalar j(
+ (((-(1 + e)) * vab).Dot(na.Direction()))
+ / (na.Direction().Dot(na.Direction() * ((1.0 / a.Mass()) + (1.0 / b.Mass())))
+ + ((rap90dotN * rap90dotN) / ia)
+ + ((rbp90dotN * rbp90dotN) / ib) ));
+
+ const Vector va2(va + ((j / a.Mass()) * na.Direction()));
+ const Vector vb2(vb - ((j / b.Mass()) * na.Direction()));
+ const Scalar wa2(wa + ((rap90.Dot(j * na.Direction())) / ia));
+ const Scalar wb2(wb - ((rbp90.Dot(j * na.Direction())) / ib));
+
+ a.linearVelocity = va2;
+ a.angularVelocity = wa2;
+ b.linearVelocity = vb2;
+ b.angularVelocity = wb2;
+}
+
+void Entity::InfInfCollisionResponse(Entity &a, const Ray &na, Entity &b) {
+ // If both elements are standing still or both are moving, move them away
+ // from each other. Otherwise, move the moving one.
+ if ((a.linearVelocity == Vector() && b.linearVelocity == Vector())
+ || (a.linearVelocity != Vector() && b.linearVelocity != Vector())) {
+ a.Translate(na.Direction());
+ b.Translate(-na.Direction());
+ Ray n;
+ while (a.shape->CheckCollision(*b.shape, n)) {
+ a.Translate(n.Direction());
+ b.Translate(-n.Direction());
+ }
+ } else if (a.linearVelocity == Vector()) {
+ b.Translate(-na.Direction());
+ Ray n;
+ while (b.shape->CheckCollision(*a.shape, n)) {
+ b.Translate(n.Direction());
+ }
+ } else {
+ a.Translate(na.Direction());
+ Ray n;
+ while (a.shape->CheckCollision(*b.shape, n)) {
+ a.Translate(n.Direction());
+ }
+ }
+}
+
+}