Final Submission. I have read and agreed with Statement of Academic Integrity.

Dependencies:   mbed

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?

UserRevisionLine numberNew 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 }