
Final Submission. I have read and agreed with Statement of Academic Integrity.
Dependencies: mbed
Spaceship.cpp@2:bb50c3a9a05c, 2020-05-22 (annotated)
- Committer:
- Nicholas75179
- Date:
- Fri May 22 10:28:29 2020 +0000
- Revision:
- 2:bb50c3a9a05c
- Parent:
- 0:fde420d18f42
published 11:27 22/5/2020
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Nicholas75179 | 0:fde420d18f42 | 1 | #include "Spaceship.h" |
Nicholas75179 | 0:fde420d18f42 | 2 | |
Nicholas75179 | 0:fde420d18f42 | 3 | void Spaceship::turn_CW() { |
Nicholas75179 | 0:fde420d18f42 | 4 | orientation -= turn_rate; |
Nicholas75179 | 0:fde420d18f42 | 5 | //a variable turn rate makes the gameplay less repetitive |
Nicholas75179 | 0:fde420d18f42 | 6 | |
Nicholas75179 | 0:fde420d18f42 | 7 | if (orientation < 0) orientation += 6.2832f; |
Nicholas75179 | 0:fde420d18f42 | 8 | else if (orientation >= 6.2832f)orientation -= 6.2832f; |
Nicholas75179 | 0:fde420d18f42 | 9 | } |
Nicholas75179 | 0:fde420d18f42 | 10 | |
Nicholas75179 | 0:fde420d18f42 | 11 | void Spaceship::turn_CCW() { |
Nicholas75179 | 0:fde420d18f42 | 12 | orientation += turn_rate; |
Nicholas75179 | 0:fde420d18f42 | 13 | |
Nicholas75179 | 0:fde420d18f42 | 14 | if (orientation >= 6.2832f) orientation -= 6.2832f; |
Nicholas75179 | 0:fde420d18f42 | 15 | else if (orientation < 0) orientation += 6.2832f; |
Nicholas75179 | 0:fde420d18f42 | 16 | } |
Nicholas75179 | 0:fde420d18f42 | 17 | |
Nicholas75179 | 0:fde420d18f42 | 18 | void Spaceship::accelerate() { |
Nicholas75179 | 0:fde420d18f42 | 19 | v_x += acceleration * cos(orientation); |
Nicholas75179 | 0:fde420d18f42 | 20 | v_y += acceleration * sin(orientation); |
Nicholas75179 | 0:fde420d18f42 | 21 | //this function integrates acceleration into velocity in 2D |
Nicholas75179 | 0:fde420d18f42 | 22 | |
Nicholas75179 | 0:fde420d18f42 | 23 | while (sqrt(v_x * v_x + v_y * v_y) > top_speed) { |
Nicholas75179 | 0:fde420d18f42 | 24 | v_x -= (v_x / abs(v_y + v_x)) * 0.5f * acceleration; |
Nicholas75179 | 0:fde420d18f42 | 25 | v_y -= (v_y / abs(v_y + v_x)) * 0.5f * acceleration; |
Nicholas75179 | 0:fde420d18f42 | 26 | } |
Nicholas75179 | 0:fde420d18f42 | 27 | //this while loop makes turning more intuitive |
Nicholas75179 | 0:fde420d18f42 | 28 | //by effectively rotating your heading when the top speed is reached |
Nicholas75179 | 0:fde420d18f42 | 29 | } |
Nicholas75179 | 0:fde420d18f42 | 30 | |
Nicholas75179 | 0:fde420d18f42 | 31 | void Spaceship::deccelerate() { |
Nicholas75179 | 0:fde420d18f42 | 32 | v_x -= acceleration * cos(orientation); |
Nicholas75179 | 0:fde420d18f42 | 33 | v_y -= acceleration * sin(orientation); |
Nicholas75179 | 0:fde420d18f42 | 34 | |
Nicholas75179 | 0:fde420d18f42 | 35 | while (sqrt(v_x * v_x + v_y * v_y) > top_speed) { |
Nicholas75179 | 0:fde420d18f42 | 36 | v_x -= (v_x / abs(v_y + v_x)) * 0.5f * acceleration; |
Nicholas75179 | 0:fde420d18f42 | 37 | v_y -= (v_y / abs(v_y + v_x)) * 0.5f * acceleration; |
Nicholas75179 | 0:fde420d18f42 | 38 | } |
Nicholas75179 | 0:fde420d18f42 | 39 | //entirely identical to accelerate() except direction |
Nicholas75179 | 0:fde420d18f42 | 40 | } |
Nicholas75179 | 0:fde420d18f42 | 41 | |
Nicholas75179 | 0:fde420d18f42 | 42 | void Spaceship::update_position() { |
Nicholas75179 | 0:fde420d18f42 | 43 | pos_x += v_x; |
Nicholas75179 | 0:fde420d18f42 | 44 | pos_y += v_y; |
Nicholas75179 | 0:fde420d18f42 | 45 | //this function integrates velocity to position |
Nicholas75179 | 0:fde420d18f42 | 46 | } |
Nicholas75179 | 0:fde420d18f42 | 47 | |
Nicholas75179 | 0:fde420d18f42 | 48 | void Spaceship::machine_gun(float x, float y) { |
Nicholas75179 | 0:fde420d18f42 | 49 | if (x == y && (clock() - reload_timer) > 15) {//this is the case for forward fire |
Nicholas75179 | 0:fde420d18f42 | 50 | bullet[chamber][0] = pos_x + 3 * cos(orientation); |
Nicholas75179 | 0:fde420d18f42 | 51 | bullet[chamber][1] = pos_y + 3 * sin(orientation); |
Nicholas75179 | 0:fde420d18f42 | 52 | bullet[chamber][2] = cos(orientation) + v_x * 0.25f; |
Nicholas75179 | 0:fde420d18f42 | 53 | bullet[chamber][3] = sin(orientation) + v_y * 0.25f; |
Nicholas75179 | 0:fde420d18f42 | 54 | //storing the x and y velocity in an array is more efficient |
Nicholas75179 | 0:fde420d18f42 | 55 | //than doing expensive calculations each frame |
Nicholas75179 | 0:fde420d18f42 | 56 | |
Nicholas75179 | 0:fde420d18f42 | 57 | chamber++; |
Nicholas75179 | 0:fde420d18f42 | 58 | chamber = chamber % 5; |
Nicholas75179 | 0:fde420d18f42 | 59 | //"chamber" limits the number of particles to 5 |
Nicholas75179 | 0:fde420d18f42 | 60 | reload_timer = clock(); |
Nicholas75179 | 0:fde420d18f42 | 61 | //"reload_timer" will be compared to clock |
Nicholas75179 | 0:fde420d18f42 | 62 | //next time the function is called, to determine fire rate |
Nicholas75179 | 0:fde420d18f42 | 63 | gun_FX = 1; |
Nicholas75179 | 0:fde420d18f42 | 64 | //used to identify when the sound effect should play |
Nicholas75179 | 0:fde420d18f42 | 65 | } |
Nicholas75179 | 0:fde420d18f42 | 66 | else if ((clock() - reload_timer) > 30) {//this is the case for turret fire |
Nicholas75179 | 0:fde420d18f42 | 67 | float angle =- atan(x / y) + 1.5708f; |
Nicholas75179 | 0:fde420d18f42 | 68 | if (y > 0) angle += 3.1416f; |
Nicholas75179 | 0:fde420d18f42 | 69 | bullet[chamber][0] = pos_x + 3 * cos(orientation); |
Nicholas75179 | 0:fde420d18f42 | 70 | bullet[chamber][1] = pos_y + 3 * sin(orientation); |
Nicholas75179 | 0:fde420d18f42 | 71 | bullet[chamber][2] = cos(orientation - angle) + v_x * 0.25f; |
Nicholas75179 | 0:fde420d18f42 | 72 | bullet[chamber][3] = sin(orientation - angle) + v_y * 0.25f; |
Nicholas75179 | 0:fde420d18f42 | 73 | //above adds the ship's velocity to the bullet, Physics! |
Nicholas75179 | 0:fde420d18f42 | 74 | |
Nicholas75179 | 0:fde420d18f42 | 75 | chamber++; |
Nicholas75179 | 0:fde420d18f42 | 76 | chamber = chamber % 5; |
Nicholas75179 | 0:fde420d18f42 | 77 | reload_timer = clock(); |
Nicholas75179 | 0:fde420d18f42 | 78 | gun_FX = 3; |
Nicholas75179 | 0:fde420d18f42 | 79 | //a different sound effect |
Nicholas75179 | 0:fde420d18f42 | 80 | } |
Nicholas75179 | 0:fde420d18f42 | 81 | } |
Nicholas75179 | 0:fde420d18f42 | 82 | |
Nicholas75179 | 0:fde420d18f42 | 83 | void Spaceship::cannon() { |
Nicholas75179 | 0:fde420d18f42 | 84 | //largely similar to machine_gun() |
Nicholas75179 | 0:fde420d18f42 | 85 | //except fire rate and projectile speed |
Nicholas75179 | 0:fde420d18f42 | 86 | if ((clock() - reload_timer) > 60) { |
Nicholas75179 | 0:fde420d18f42 | 87 | bullet[chamber][0] = pos_x + 3 * cos(orientation); |
Nicholas75179 | 0:fde420d18f42 | 88 | bullet[chamber][1] = pos_y + 3 * sin(orientation); |
Nicholas75179 | 0:fde420d18f42 | 89 | bullet[chamber][2] = 0.7f * cos(orientation) + v_x * 0.25f; |
Nicholas75179 | 0:fde420d18f42 | 90 | bullet[chamber][3] = 0.7f * sin(orientation) + v_y * 0.25f; |
Nicholas75179 | 0:fde420d18f42 | 91 | |
Nicholas75179 | 0:fde420d18f42 | 92 | chamber++; |
Nicholas75179 | 0:fde420d18f42 | 93 | chamber = chamber % 5; |
Nicholas75179 | 0:fde420d18f42 | 94 | reload_timer = clock(); |
Nicholas75179 | 0:fde420d18f42 | 95 | gun_FX = 3; |
Nicholas75179 | 0:fde420d18f42 | 96 | } |
Nicholas75179 | 0:fde420d18f42 | 97 | } |
Nicholas75179 | 0:fde420d18f42 | 98 | |
Nicholas75179 | 0:fde420d18f42 | 99 | void Spaceship::update_bullets() { |
Nicholas75179 | 0:fde420d18f42 | 100 | //integrates velocity into position |
Nicholas75179 | 0:fde420d18f42 | 101 | |
Nicholas75179 | 0:fde420d18f42 | 102 | for (int inc2 = 0; inc2 < 5; inc2++) { |
Nicholas75179 | 0:fde420d18f42 | 103 | bullet[inc2][0] += 4 * bullet[inc2][2]; |
Nicholas75179 | 0:fde420d18f42 | 104 | bullet[inc2][1] +=4 * bullet[inc2][3]; |
Nicholas75179 | 0:fde420d18f42 | 105 | } |
Nicholas75179 | 0:fde420d18f42 | 106 | } |
Nicholas75179 | 0:fde420d18f42 | 107 | |
Nicholas75179 | 0:fde420d18f42 | 108 | void Spaceship::update() { |
Nicholas75179 | 0:fde420d18f42 | 109 | //a public function that makes sure |
Nicholas75179 | 0:fde420d18f42 | 110 | //both the ship and its particles update at once |
Nicholas75179 | 0:fde420d18f42 | 111 | |
Nicholas75179 | 0:fde420d18f42 | 112 | update_position(); |
Nicholas75179 | 0:fde420d18f42 | 113 | update_bullets(); |
Nicholas75179 | 0:fde420d18f42 | 114 | } |
Nicholas75179 | 0:fde420d18f42 | 115 | |
Nicholas75179 | 0:fde420d18f42 | 116 | void Spaceship::controls(bool player_ship_type, |
Nicholas75179 | 0:fde420d18f42 | 117 | bool Y, bool A, bool X, bool B, float x, float y) { |
Nicholas75179 | 0:fde420d18f42 | 118 | //calls the private functions all at once |
Nicholas75179 | 0:fde420d18f42 | 119 | //with instructions from main |
Nicholas75179 | 0:fde420d18f42 | 120 | |
Nicholas75179 | 0:fde420d18f42 | 121 | if (Y) turn_CW(); |
Nicholas75179 | 0:fde420d18f42 | 122 | if (A) turn_CCW(); |
Nicholas75179 | 0:fde420d18f42 | 123 | if (X) accelerate(); |
Nicholas75179 | 0:fde420d18f42 | 124 | if (B) deccelerate(); |
Nicholas75179 | 0:fde420d18f42 | 125 | if (abs(x) > 0.1f || abs(y) > 0.1f) { |
Nicholas75179 | 0:fde420d18f42 | 126 | if (player_ship_type == 0) machine_gun(x, y); |
Nicholas75179 | 0:fde420d18f42 | 127 | else cannon(); |
Nicholas75179 | 0:fde420d18f42 | 128 | } |
Nicholas75179 | 0:fde420d18f42 | 129 | #ifdef DEBUG_controls |
Nicholas75179 | 0:fde420d18f42 | 130 | sprintf(g_buffer, "%1.1f,%1.1f", x, y); |
Nicholas75179 | 0:fde420d18f42 | 131 | lcd.printString(g_buffer, 0, 4); |
Nicholas75179 | 0:fde420d18f42 | 132 | printf("Joystick val: %1.1f,%1.1f\n", x, y); |
Nicholas75179 | 0:fde420d18f42 | 133 | #endif |
Nicholas75179 | 0:fde420d18f42 | 134 | update(); |
Nicholas75179 | 0:fde420d18f42 | 135 | } |
Nicholas75179 | 0:fde420d18f42 | 136 | |
Nicholas75179 | 0:fde420d18f42 | 137 | void Spaceship::AI_controls(float target_x, float target_y, float target_orientation) { |
Nicholas75179 | 0:fde420d18f42 | 138 | float diff_x = target_x - pos_x; |
Nicholas75179 | 0:fde420d18f42 | 139 | if (abs(diff_x) < 0.001f) diff_x = 0.001f; |
Nicholas75179 | 0:fde420d18f42 | 140 | |
Nicholas75179 | 0:fde420d18f42 | 141 | float angle_to_target = atan((target_y - pos_y) / diff_x) + 3.1416f; |
Nicholas75179 | 0:fde420d18f42 | 142 | if (diff_x > 0) angle_to_target += 3.1416f; |
Nicholas75179 | 0:fde420d18f42 | 143 | |
Nicholas75179 | 0:fde420d18f42 | 144 | float diff_angle = orientation - angle_to_target; |
Nicholas75179 | 0:fde420d18f42 | 145 | if (diff_angle > 6.1831f) diff_angle -= 6.2831f; |
Nicholas75179 | 0:fde420d18f42 | 146 | if (diff_angle < -6.1831f) diff_angle += 6.2831f; |
Nicholas75179 | 0:fde420d18f42 | 147 | //above maths finds if a CW or CCW turn is needed |
Nicholas75179 | 0:fde420d18f42 | 148 | //to point the enemy ships towards the player |
Nicholas75179 | 0:fde420d18f42 | 149 | |
Nicholas75179 | 0:fde420d18f42 | 150 | if (diff_angle > 0.10f && diff_angle < 3.25f || diff_angle < -3.25f) turn_CW(); |
Nicholas75179 | 0:fde420d18f42 | 151 | else if (diff_angle < -0.10 || diff_angle > 3.25f) turn_CCW(); |
Nicholas75179 | 0:fde420d18f42 | 152 | else if (sqrt((target_y - pos_y) * (target_y - pos_y) + diff_x * diff_x) < 40) { |
Nicholas75179 | 0:fde420d18f42 | 153 | machine_gun(0,0); |
Nicholas75179 | 0:fde420d18f42 | 154 | } |
Nicholas75179 | 0:fde420d18f42 | 155 | //if no adjustment is needed, fire away |
Nicholas75179 | 0:fde420d18f42 | 156 | |
Nicholas75179 | 0:fde420d18f42 | 157 | accelerate(); |
Nicholas75179 | 0:fde420d18f42 | 158 | //always accelerating makes the enemies fly more naturally |
Nicholas75179 | 0:fde420d18f42 | 159 | |
Nicholas75179 | 0:fde420d18f42 | 160 | #ifdef DEBUG_AI |
Nicholas75179 | 0:fde420d18f42 | 161 | sprintf(g_buffer, "%1.3f", diff_x); |
Nicholas75179 | 0:fde420d18f42 | 162 | lcd.printString(g_buffer, 0, 4); |
Nicholas75179 | 0:fde420d18f42 | 163 | sprintf(g_buffer, "%1.2f,%1.2f", pos_x, pos_y); |
Nicholas75179 | 0:fde420d18f42 | 164 | lcd.printString(g_buffer, 0, 5); |
Nicholas75179 | 2:bb50c3a9a05c | 165 | printf("Enemy position: %3.1f,%3.1f\n", pos_x, pos_y); |
Nicholas75179 | 0:fde420d18f42 | 166 | #endif |
Nicholas75179 | 0:fde420d18f42 | 167 | } |
Nicholas75179 | 0:fde420d18f42 | 168 | |
Nicholas75179 | 0:fde420d18f42 | 169 | void Spaceship::init_ship(float x, float y, float direction, |
Nicholas75179 | 0:fde420d18f42 | 170 | float turn, float acc, float top, int health) { |
Nicholas75179 | 0:fde420d18f42 | 171 | pos_x = x; pos_y = y; |
Nicholas75179 | 0:fde420d18f42 | 172 | v_x = 0; v_y= 0; |
Nicholas75179 | 0:fde420d18f42 | 173 | |
Nicholas75179 | 0:fde420d18f42 | 174 | if (x == 1 && y == 0) v_x = 0.1;//drft the player forwars, that looks cool |
Nicholas75179 | 0:fde420d18f42 | 175 | acceleration = acc; |
Nicholas75179 | 0:fde420d18f42 | 176 | orientation = direction; |
Nicholas75179 | 0:fde420d18f42 | 177 | top_speed = top; |
Nicholas75179 | 0:fde420d18f42 | 178 | turn_rate = turn; |
Nicholas75179 | 0:fde420d18f42 | 179 | if (turn_rate > 0.10f) turn_rate = 0.10f; |
Nicholas75179 | 0:fde420d18f42 | 180 | chamber = 0; |
Nicholas75179 | 0:fde420d18f42 | 181 | reload_timer = 0; |
Nicholas75179 | 0:fde420d18f42 | 182 | HP = health; |
Nicholas75179 | 0:fde420d18f42 | 183 | explosion_FX = 8; |
Nicholas75179 | 0:fde420d18f42 | 184 | // sets all ship parameters to the declaration from main |
Nicholas75179 | 0:fde420d18f42 | 185 | |
Nicholas75179 | 0:fde420d18f42 | 186 | for (int inc = 0; inc < 5; inc++) { |
Nicholas75179 | 0:fde420d18f42 | 187 | bullet[inc][0] = 50; |
Nicholas75179 | 0:fde420d18f42 | 188 | bullet[inc][1] = 50; |
Nicholas75179 | 0:fde420d18f42 | 189 | bullet[inc][2] = 4; |
Nicholas75179 | 0:fde420d18f42 | 190 | bullet[inc][3] = 4; |
Nicholas75179 | 0:fde420d18f42 | 191 | } |
Nicholas75179 | 0:fde420d18f42 | 192 | // make sure the projectiles are at known positions |
Nicholas75179 | 0:fde420d18f42 | 193 | // and won't appear on screen |
Nicholas75179 | 0:fde420d18f42 | 194 | } |
Nicholas75179 | 0:fde420d18f42 | 195 | |
Nicholas75179 | 0:fde420d18f42 | 196 | bool Spaceship::check_bullets(int temp1, int temp2) { |
Nicholas75179 | 0:fde420d18f42 | 197 | for (int inc1 = 0; inc1 < 5; inc1++) { |
Nicholas75179 | 0:fde420d18f42 | 198 | if (temp1 == int(bullet[inc1][0]) && temp2 == int(bullet[inc1][1]) |
Nicholas75179 | 0:fde420d18f42 | 199 | || temp1 == int(bullet[inc1][0] + bullet[inc1][2]) |
Nicholas75179 | 0:fde420d18f42 | 200 | && temp2 == int(bullet[inc1][1] + bullet[inc1][3]) |
Nicholas75179 | 0:fde420d18f42 | 201 | || temp1 == int(bullet[inc1][0] + 2 * bullet[inc1][2]) |
Nicholas75179 | 0:fde420d18f42 | 202 | && temp2 == int(bullet[inc1][1] + 2 * bullet[inc1][3]) |
Nicholas75179 | 0:fde420d18f42 | 203 | || temp1 == int(bullet[inc1][0] + 3 * bullet[inc1][2]) |
Nicholas75179 | 0:fde420d18f42 | 204 | && temp2 == int(bullet[inc1][1] + 3 * bullet[inc1][3]) |
Nicholas75179 | 0:fde420d18f42 | 205 | || temp1 == int(bullet[inc1][0] + 4 * bullet[inc1][2]) |
Nicholas75179 | 0:fde420d18f42 | 206 | && temp2 == int(bullet[inc1][1] + 4 * bullet[inc1][3]) |
Nicholas75179 | 0:fde420d18f42 | 207 | || temp1 == int(bullet[inc1][0] + 5 * bullet[inc1][2]) |
Nicholas75179 | 0:fde420d18f42 | 208 | && temp2 == int(bullet[inc1][1] + 5 * bullet[inc1][3]) |
Nicholas75179 | 0:fde420d18f42 | 209 | || temp1 == int(bullet[inc1][0] + 6 * bullet[inc1][2]) |
Nicholas75179 | 0:fde420d18f42 | 210 | && temp2 == int(bullet[inc1][1] + 6 * bullet[inc1][3]) |
Nicholas75179 | 0:fde420d18f42 | 211 | || temp1 == int(bullet[inc1][0] + 7 * bullet[inc1][2]) |
Nicholas75179 | 0:fde420d18f42 | 212 | && temp2 == int(bullet[inc1][1] + 7 * bullet[inc1][3])) { |
Nicholas75179 | 0:fde420d18f42 | 213 | return 1; |
Nicholas75179 | 0:fde420d18f42 | 214 | // this function allows a much simpler way to check |
Nicholas75179 | 0:fde420d18f42 | 215 | // if an area of space contains a bullet for rendering purposes |
Nicholas75179 | 0:fde420d18f42 | 216 | } |
Nicholas75179 | 0:fde420d18f42 | 217 | } |
Nicholas75179 | 0:fde420d18f42 | 218 | return 0; |
Nicholas75179 | 0:fde420d18f42 | 219 | // 0 is returned if no bullets are present |
Nicholas75179 | 0:fde420d18f42 | 220 | } |
Nicholas75179 | 0:fde420d18f42 | 221 | |
Nicholas75179 | 0:fde420d18f42 | 222 | bool Spaceship::check_hitbox(int target_x, int target_y, int radius) { |
Nicholas75179 | 0:fde420d18f42 | 223 | float distance_x, distance_y; |
Nicholas75179 | 0:fde420d18f42 | 224 | |
Nicholas75179 | 0:fde420d18f42 | 225 | for (int inc = 0; inc < 5; inc++) { |
Nicholas75179 | 0:fde420d18f42 | 226 | distance_x = bullet[inc][0] - target_x; |
Nicholas75179 | 0:fde420d18f42 | 227 | distance_y = bullet[inc][1] - target_y; |
Nicholas75179 | 0:fde420d18f42 | 228 | // above converts absolute position to relative distance |
Nicholas75179 | 0:fde420d18f42 | 229 | |
Nicholas75179 | 0:fde420d18f42 | 230 | if (sqrt(distance_x * distance_x + distance_y * distance_y) < radius) { |
Nicholas75179 | 0:fde420d18f42 | 231 | // calculates if the distance is short enough |
Nicholas75179 | 0:fde420d18f42 | 232 | // to the centre of a target for a hit |
Nicholas75179 | 0:fde420d18f42 | 233 | |
Nicholas75179 | 0:fde420d18f42 | 234 | bullet[inc][0] += 60 * bullet[inc][2];//bullets that land on target |
Nicholas75179 | 0:fde420d18f42 | 235 | bullet[inc][1] += 60 * bullet[inc][3];//are moved out of the screen |
Nicholas75179 | 0:fde420d18f42 | 236 | return 1; |
Nicholas75179 | 0:fde420d18f42 | 237 | } |
Nicholas75179 | 0:fde420d18f42 | 238 | } |
Nicholas75179 | 0:fde420d18f42 | 239 | return 0; |
Nicholas75179 | 0:fde420d18f42 | 240 | // return a 0 when no hits are detected |
Nicholas75179 | 0:fde420d18f42 | 241 | } |