1 // Ship.cpp -- The player's ship.
2 // Copyright (C) 2008 Nick Gasson
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 //
17
18 #include "Ship.hpp"
19 #include "OpenGL.hpp"
20
21 #include <string>
22 #include <cmath>
23
24 //
25 // Defines a simplified polygon representing the ship.
26 //
27 const Point Ship::hotspots[] = {
28 {2, 31}, {2, 26}, {4, 14}, {16, 0},
29 {29, 14}, {31, 26}, {31, 31}, {17, 31} };
30
31
Ship(Viewport * v)32 Ship::Ship(Viewport* v)
33 : shipImage("images/ship.png"),
34 xpos(0), ypos(0), speedX(0), speedY(0), angle(0), viewport(v),
35 thrusting(false),
36 boingSound(LocateResource("sounds/boing1.wav"))
37 {
38
39 }
40
Display() const41 void Ship::Display() const
42 {
43 int dx = (int)xpos - viewport->GetXAdjust();
44 int dy = (int)ypos - viewport->GetYAdjust();
45
46 shipImage.Draw(dx, dy, angle);
47 }
48
DrawExhaust()49 void Ship::DrawExhaust()
50 {
51 exhaust.Draw((float)viewport->GetXAdjust(),
52 (float)viewport->GetYAdjust());
53 }
54
DrawExplosion()55 void Ship::DrawExplosion()
56 {
57 explosion.Draw((float)viewport->GetXAdjust(),
58 (float)viewport->GetYAdjust());
59 }
60
Move()61 void Ship::Move()
62 {
63 RotatePoints(hotspots, points, NUM_HOTSPOTS, angle*M_PI/180, -16, 16);
64
65 xpos += speedX;
66 ypos += speedY;
67
68 // Check bounds
69 if (xpos <= 0.0) {
70 xpos = 0.0;
71 speedX *= -0.5;
72 boingSound.Play();
73 }
74 else if (xpos + shipImage.GetWidth() > viewport->GetLevelWidth()) {
75 xpos = (double)(viewport->GetLevelWidth() - shipImage.GetWidth());
76 speedX *= -0.5;
77 boingSound.Play();
78 }
79 if (ypos <= 0.0) {
80 ypos = 0.0;
81 speedY *= -0.5;
82 boingSound.Play();
83 }
84 else if (ypos + shipImage.GetHeight() > viewport->GetLevelHeight()) {
85 ypos = (double)(viewport->GetLevelHeight() - shipImage.GetHeight());
86 speedY *= -0.5;
87 boingSound.Play();
88 }
89
90 exhaust.xpos = xpos + shipImage.GetWidth()/2
91 - (shipImage.GetWidth()/2)*sin(angle*(M_PI/180));
92 exhaust.ypos = ypos + shipImage.GetHeight()/2
93 + (shipImage.GetHeight()/2)*cos(angle*(M_PI/180));
94
95 const float SCALE = 1.0f;
96 exhaust.yi_bias = SCALE * cosf(angle*M_PI/180) + speedY;
97 exhaust.xi_bias = SCALE * -sinf(angle*M_PI/180) + speedX;
98
99 explosion.xpos = xpos + shipImage.GetWidth()/2;
100 explosion.ypos = ypos + shipImage.GetHeight()/2;
101 }
102
ProcessEffects(bool paused,bool exploding)103 void Ship::ProcessEffects(bool paused, bool exploding)
104 {
105 exhaust.Process(thrusting, !paused);
106 explosion.Process(exploding);
107 }
108
ThrustOn()109 void Ship::ThrustOn()
110 {
111 thrusting = true;
112 }
113
ThrustOff()114 void Ship::ThrustOff()
115 {
116 thrusting = false;
117 }
118
Thrust(double speed)119 void Ship::Thrust(double speed)
120 {
121 speedX += speed * sin(angle*(M_PI/180));
122 speedY -= speed * cos(angle*(M_PI/180));
123 }
124
Turn(double delta)125 void Ship::Turn(double delta)
126 {
127 angle += delta;
128 }
129
ApplyGravity(double gravity)130 void Ship::ApplyGravity(double gravity)
131 {
132 speedY += gravity;
133 }
134
Bounce()135 void Ship::Bounce()
136 {
137 speedX *= -1;
138 speedY *= -1;
139 speedX /= 2;
140 speedY /= 2;
141 }
142
CentreInViewport()143 void Ship::CentreInViewport()
144 {
145 int centrex = (int)xpos + (shipImage.GetWidth()/2);
146 int centrey = (int)ypos + (shipImage.GetHeight()/2);
147 OpenGL& opengl = OpenGL::GetInstance();
148 viewport->SetXAdjust(centrex - (opengl.GetWidth()/2));
149 viewport->SetYAdjust(centrey - (opengl.GetHeight()/2));
150 }
151
152 //
153 // Reset at the start of a new level.
154 //
Reset()155 void Ship::Reset()
156 {
157 exhaust.Reset();
158 explosion.Reset();
159
160 xpos = (double)viewport->GetLevelWidth()/2;
161 ypos = SHIP_START_Y - 40;
162
163 angle = 0.0f;
164 speedX = 0.0f;
165 speedY = 0.0f;
166 }
167
RotatePoints(const Point * pPoints,Point * pDest,int nCount,double angle,int adjustx,int adjusty)168 void Ship::RotatePoints(const Point* pPoints, Point* pDest, int nCount,
169 double angle, int adjustx, int adjusty)
170 {
171 for (int i = 0; i < nCount; i++) {
172 int x = pPoints[i].x + adjustx;
173 int y = pPoints[i].y*-1 + adjusty;
174 pDest[i].x = (int)(x*cos(angle)) + (int)(y*sin(angle));
175 pDest[i].y = (int)(y*cos(angle)) - (int)(x*sin(angle));
176 pDest[i].y -= adjusty;
177 pDest[i].x -= adjustx;
178 pDest[i].y *= -1;
179 }
180 }
181
182 //
183 // Check for collision between the ship and a polygon.
184 //
HotSpotCollision(LineSegment & l,double dx,double dy) const185 bool Ship::HotSpotCollision(LineSegment& l, double dx, double dy) const
186 {
187 for (int i = 0; i < NUM_HOTSPOTS; i++) {
188 if (CheckCollision(l, dx + points[i].x, dy + points[i].y))
189 return true;
190 }
191
192 return false;
193 }
194
195 //
196 // Checks for collision between the ship and a box.
197 //
BoxCollision(int x,int y,int w,int h) const198 bool Ship::BoxCollision(int x, int y, int w, int h) const
199 {
200 if (!viewport->PointInScreen(x, y, w, h))
201 return false;
202
203 LineSegment l1(x, y, x + w, y);
204 LineSegment l2(x + w, y, x + w, y + h);
205 LineSegment l3(x + w, y + h, x, y + h);
206 LineSegment l4(x, y + h, x, y);
207
208 return HotSpotCollision(l1) || HotSpotCollision(l2)
209 || HotSpotCollision(l3) || HotSpotCollision(l4);
210 }
211
212 //
213 // Checks for collision between the ship and a line segment.
214 //
CheckCollision(LineSegment & l,double dx,double dy) const215 bool Ship::CheckCollision(LineSegment& l, double dx, double dy) const
216 {
217 double xpos = this->xpos + dx;
218 double ypos = this->ypos + dy;
219
220 if (!viewport->PointInScreen
221 ((int)xpos, (int)ypos, shipImage.GetWidth(), shipImage.GetHeight()))
222 return false;
223
224 // Get position after next move
225 double cX = xpos + speedX;
226 double cY = ypos + speedY;
227
228 // Get displacement
229 double vecX = cX - xpos;
230 double vecY = cY - ypos;
231
232 // Get line position
233 double wallX = (double)(l.p2.x - l.p1.x);
234 double wallY = (double)(l.p2.y - l.p1.y);
235
236 // Work out numerator and denominator (used parametric equations)
237 double numT = wallX * (ypos - l.p1.y) - wallY * (xpos - l.p1.x);
238 double numU = vecX * (ypos - l.p1.y) - vecY * (xpos - l.p1.x);
239
240 // Work out denominator
241 double denom = wallY * (cX - xpos) - wallX * (cY - ypos);
242
243 // Work out u and t
244 double u = numU / denom;
245 double t = numT / denom;
246
247 // Collision occured if (0 < t < 1) and (0 < u < 1)
248 return (t > 0.0f) && (t < 1.0f) && (u > 0.0f) && (u < 1.0f);
249 }
250
251