3 #include "../entity/Ship.h"
4 #include "../graphics/const.h"
5 #include "../graphics/Camera.h"
6 #include "../graphics/Canvas.h"
7 #include "../graphics/Color.h"
14 Autopilot::Autopilot(Ship &ctrl, const Vector<float> &target)
21 void Autopilot::Update(float deltaT) {
23 ctrl->linThrottle = 0;
24 ctrl->rotThrottle = 0;
28 dp = *target - ctrl->pos;
31 speed = Length(ctrl->vel);
32 normVel = ctrl->vel / speed;
33 proj = ctrl->pos + (normVel * (DistanceToHalt() * 2));
35 if (Distance() < 0.75) {
36 if (DistanceToHalt() < Distance() + (speed * dt)) {
37 if (StandingStill()) {
48 if (StandingStill()) {
50 AccelerateAlong(normDP);
54 const Vector<float> projDiff = *target - proj;
55 const float projDist = Length(projDiff);
56 const Vector<float> normProj = projDiff / projDist;
57 const float onProj = Dot(normProj, normVel);
59 if (projDist <= 0.75 || (onProj < -0.9 && !StandingStill())) {
65 AccelerateAlong(normProj);
71 ctrl->linThrottle = 1;
72 } else if (ReallyClose() && Speed() <= ctrl->MaxFwdAcc()) {
73 ctrl->linThrottle = Speed() / ctrl->MaxRevAcc() * -1;
74 } else if (InBrakingDistance()) {
75 ctrl->linThrottle = -1;
77 ctrl->linThrottle = 1;
79 } else if (FacingOpposite()) {
82 } else if (ReallyClose() && Speed() <= ctrl->MaxFwdAcc()) {
83 ctrl->linThrottle = Speed() / ctrl->MaxFwdAcc();
84 } else if (InBrakingDistance()) {
85 ctrl->linThrottle = 1;
87 ctrl->linThrottle = -1;
95 const Vector<float> correction =
96 *target - ctrl->pos - (normVel * Distance());
98 const Vector<float> normCorrection = Norm(correction);
99 float faceCorrection = Dot(normCorrection, ctrl->Dir());
101 Face(normCorrection);
102 ctrl->linThrottle = faceCorrection * faceCorrection;
105 bool Autopilot::StandingStill() const {
106 return ctrl->vel.x * dt < std::numeric_limits<float>::epsilon()
107 && ctrl->vel.y * dt < std::numeric_limits<float>::epsilon();
110 bool Autopilot::ReallySlow() const {
111 return Speed() < ctrl->MaxFwdAcc() * dt;
114 bool Autopilot::FacingTarget() const {
115 return Facing(normDP);
118 bool Autopilot::FacingOpposite() const {
119 return Facing(-normDP);
122 bool Autopilot::Facing(Vector<float> v) const {
123 return std::abs(Dot(ctrl->Dir(), v) - 1)
124 < std::numeric_limits<float>::epsilon();
127 bool Autopilot::OnTarget() const {
128 return std::abs(Dot(Norm(ctrl->vel), Norm(*target - ctrl->pos)) - 1)
129 < std::numeric_limits<float>::epsilon();
133 float Autopilot::Speed() const {
136 float Autopilot::Distance() const {
140 float Autopilot::DistanceToHalt() const {
141 if (StandingStill()) {
144 const float timeToHalt = Speed() / ctrl->MaxFwdAcc();
145 const float angDiff = std::acos(Dot(normVel, ctrl->Dir()));
146 const float timeToTurn = std::sqrt(angDiff / ctrl->MaxRotAcc());
147 return (ctrl->MaxFwdAcc() * timeToHalt * timeToHalt) / 2
148 + timeToTurn * Speed();
151 bool Autopilot::ReallyClose() const {
152 return Distance() <= ctrl->MaxFwdAcc();
155 bool Autopilot::InBrakingDistance() const {
156 return Distance() <= DistanceToHalt();
159 bool Autopilot::FarAway() const {
160 return Distance() > 1.5 * DistanceToHalt();
164 float Autopilot::TargetVelAngle() const {
165 return std::atan2(normDP.y, normDP.x) - std::atan2(normVel.y, normVel.x);
169 void Autopilot::FaceTarget() {
170 Face(Norm(*target - ctrl->pos));
173 void Autopilot::Face(Vector<float> tgt) {
174 const Vector<float> dir = ctrl->Dir();
176 float angle = std::atan2(tgt.y, tgt.x) - std::atan2(dir.y, dir.x);
177 if (angle > PI) angle -= PI2;
178 if (angle < -PI) angle += PI2;
179 const float absAngle = std::abs(angle);
180 const int sigAngle = sigma(angle);
182 const float absRotVel = std::abs(ctrl->rotVel);
183 const int sigRotVel = sigma(ctrl->rotVel);
184 const float rotMaxAcc = ctrl->MaxRotAcc();
185 const float rotTTH = absRotVel / rotMaxAcc;
186 const float rotDTH = (rotMaxAcc * rotTTH * rotTTH) / 2;
188 // pos rot = clockwise
189 // neg rot = counter clockwise
193 if (absRotVel <= rotMaxAcc) {
194 ctrl->rotThrottle = -sigRotVel * absRotVel / rotMaxAcc;
196 ctrl->rotThrottle = -sigRotVel;
200 ctrl->rotThrottle = 0;
202 } else if (sigAngle == sigRotVel) {
203 // turning in the right direction
204 if (rotDTH >= absAngle) {
206 if (absRotVel <= rotMaxAcc) {
207 ctrl->rotThrottle = -sigAngle * absRotVel / rotMaxAcc;
209 ctrl->rotThrottle = -sigAngle;
212 ctrl->rotThrottle = sigAngle;
215 // turning in the wrong direction
216 ctrl->rotThrottle = sigAngle;
220 void Autopilot::Halt() {
221 if (StandingStill()) {
226 Vector<float> nnVel = Norm(-normVel);
230 ctrl->linThrottle = Speed() / ctrl->MaxFwdAcc();
231 } else if (Facing(-nnVel)) {
232 ctrl->linThrottle = -Speed() / ctrl->MaxFwdAcc();
235 AccelerateAlong(nnVel);
239 void Autopilot::AccelerateAlong(Vector<float> v) {
240 const float pointing = Dot(v, ctrl->Dir());
241 if (std::abs(pointing) > 0.7071) {
242 ctrl->linThrottle = pointing * pointing * sigma(pointing);
244 ctrl->linThrottle = 0;
249 void Autopilot::Render(Canvas &canv, const Camera &cam) const {
250 constexpr Color tgtColor(0xFF, 0x00, 0x00);
251 constexpr Color velColor(0x00, 0x00, 0xFF);
252 constexpr Color planColor(0x00, 0xFF, 0x00);
254 Vector<float> screenPos(cam.ToScreen(ctrl->pos));
255 Vector<float> screenTgt(cam.ToScreen(*target));
256 Vector<float> screenProj(cam.ToScreen(proj));
258 canv.SetColor(tgtColor);
259 canv.Arrow(screenPos, screenTgt);
261 canv.SetColor(velColor);
262 canv.Arrow(screenPos, screenProj);
264 canv.SetColor(planColor);
265 canv.Arrow(screenProj, screenTgt);