#include #include #include #include #include #include #include #include #ifndef __nullptr__ #define Nullptr(type) (type *)0 #endif // __nullptr__ #include "vector.h" #include "asteroids.h" // TODO: Export all this to a scenery (For later implementation of enemy waves) // Properties const double BULLET_Speed_Ally = 12.0f; const double BULLET_Speed_Enemy = 6.0f; const int BULLET_DecayTime_Ally = 60; const int BULLET_DecayTime_Enemy = 100; const double SHIP_RotationValue = 4.0f; const int SHIP_DeathAnimSpeed = 6; const int SHIP_DeathAnimFrameCount = 5; const double SHIP_MaxSpeed = 8.0f; const double SHIP_Acceleration = 0.15f; const double SHIP_ShootIntevale = 12; // Based on frame count const double ASTEROID_MinimumSize = 50.0f; // No asteroid under this size if split // const int ENEMY_DeathAnimSpeed = 6; // const int ENEMY_DeathAnimFrameCount = 5; const double ENEMY_MaxSpeed = 5.0f; const int ENEMY_MaxTurnIntervale = 300; const double ENEMY_Acceleration = 0.15f; const double ENEMY_ShootIntevale = 120; // Based on frame count const SDL_Scancode SHIP_LeftButton = SDL_SCANCODE_A; const SDL_Scancode SHIP_RightButton = SDL_SCANCODE_D; const SDL_Scancode SHIP_ForwardButton = SDL_SCANCODE_W; const SDL_Scancode SHIP_ShootButton = SDL_SCANCODE_SPACE; // End Properties // Vars Bullet NULLET; int GAME_BoxWidth, GAME_BoxHeight, SHIP_MaxBulletCount, ENEMY_MaxBulletCount; // TODO: Explosion Texture SDL_Rect SHIP_SourceRect_Gliding, SHIP_SourceRect_Accelerating, * SHIP_SourceRect_Explosion, * ASTEROID_SourceRect_Size1, * ASTEROID_SourceRect_Size2, * ASTEROID_SourceRect_Size3; SDL_Texture * SHIP_Texture_Gliding, * SHIP_Texture_Accelerating, * SHIP_Texture_Explosion, * ASTEROID_Texture, * BULLET_Texture_Ally, * BULLET_Texture_Enemy, * ENEMY_Texture; SDL_Point SHIP_RotationCenter_Flight, SHIP_RotationCenter_Explosion; Asteroid ASTEROIDULLET; bool ASTEROID_IsDestroyed = false, BULLET_IsInit = false, ENEMY_IsInit = false, SHIP_IsInit = false, ASTEROID_IsInit = false; // TODO: check if init successful // End Vars void ASTEROIDS_InitializeGame(SDL_Renderer * renderer, int width, int height){ printf("Initializing Game...\n"); GAME_BoxWidth = width; GAME_BoxHeight = height; SHIP_Initialize(renderer); BULLET_Initialize(renderer); // Call may be redundant ENEMY_Initialize(renderer); ASTEROID_Initialize(renderer); printf("Game initialized!\n"); } void ASTEROIDS_DeinitializeGame(){ printf("Make sure all resources are destroyed (not fatal)!\nDe-initializing Game...\n"); SHIP_Deinitialize(); BULLET_Deinitialize(); // Call may be redundant ENEMY_Deinitialize(); ASTEROID_Deinitialize(); printf("Game de-initialized!\n"); } void BULLET_Initialize(SDL_Renderer * renderer){ if (BULLET_IsInit) return; printf("Initializing Bullet...\n"); NULLET = (Bullet) { .Rotation = 0.0f, .Location = (Vector) {.x = 0.0f, .y = 0.0f }, .Momentum = (Vector) {.x = 0.0f, .y = 0.0f }, .TargetRect = (SDL_Rect) {.x = 0, .y = 0, .w = 0, .h = 0 }, .Lifetime = 0, .IsDestroyed = true, .Type = AllyBullet }; // Default or null bullet BULLET_Texture_Ally = IMG_LoadTexture(renderer, "assets/images/bullet.png"); if (!BULLET_Texture_Ally) printf("Ally bullet texture cannot be loaded!\n"); BULLET_Texture_Enemy = IMG_LoadTexture(renderer, "assets/images/enemyBullet.png"); if (!BULLET_Texture_Enemy) printf("Enemy bullet texture cannot be loaded!\n"); printf("Bullet initialized!\n"); BULLET_IsInit = true; } void ENEMY_Initialize(SDL_Renderer * renderer){ if (ENEMY_IsInit) return; printf("Initializing Enemy...\n"); BULLET_Initialize(renderer); ENEMY_Texture = IMG_LoadTexture(renderer, "assets/images/enemy.png"); if (!ENEMY_Texture) printf("Enemy texture cannot be loaded!\n"); ENEMY_MaxBulletCount = ((BULLET_DecayTime_Ally / ENEMY_ShootIntevale) + 10); printf("Enemy initialized!\n"); ENEMY_IsInit = true; } // ENEMY_Initialize void SHIP_Initialize(SDL_Renderer * renderer){ if (SHIP_IsInit) return; printf("Initializing Ship...\n"); BULLET_Initialize(renderer); SHIP_Texture_Gliding = IMG_LoadTexture(renderer, "assets/images/ship.png"); if (!SHIP_Texture_Gliding) printf("Ship texture 1 cannot be loaded!\n"); SHIP_Texture_Accelerating = IMG_LoadTexture(renderer, "assets/images/shipAcc.png"); if (!SHIP_Texture_Accelerating) printf("Ship texture 2 cannot be loaded!\n"); SHIP_Texture_Explosion = IMG_LoadTexture(renderer, "assets/images/shipExpl.png"); if (!SHIP_Texture_Explosion) printf("Ship texture explosion cannot be loaded!\n"); SHIP_SourceRect_Explosion = calloc(5, sizeof(SDL_Rect)); if (!SHIP_SourceRect_Explosion) printf("Memory for SDL_Rect (SHIP) cannot be allocated!\n"); int i; for (i = 0; i < SHIP_DeathAnimFrameCount; i++) { SHIP_SourceRect_Explosion[i] = (SDL_Rect) {.x = 0, .y = (i * 1632), .w = 1280, .h = 1632 }; } SHIP_SourceRect_Gliding = (SDL_Rect) {.x = 0, .y = 0, .w = 320, .h = 408 }; // TODO: Sourcerects are currently redundant considering the usage of SDL_RenderCopyEx SHIP_SourceRect_Accelerating = (SDL_Rect) {.x = 0, .y = 0, .w = 320, .h = 576 }; SHIP_RotationCenter_Flight = (SDL_Point) {.x = 20, .y = 25 }; SHIP_MaxBulletCount = ((BULLET_DecayTime_Ally / SHIP_ShootIntevale) + 10); printf("Ship initialized!\n"); SHIP_IsInit = true; } // SHIP_Initialize void ASTEROID_Initialize(SDL_Renderer * renderer){ if (ASTEROID_IsInit) return; printf("Initializing Asteroid...\n"); ASTEROID_Texture = IMG_LoadTexture(renderer, "assets/images/asteroid.png"); ASTEROIDULLET = (Asteroid) { .Rotation = 0.0f, .Size = 0.0f, .RotationValue = 0.0f, .Location = (Vector) {.x = 0.0f, .y = 0.0f }, .Momentum = (Vector) {.x = 0.0f, .y = 0.0f }, .TargetRect = (SDL_Rect) {.x = 0, .y = 0, .w = 0, .h = 0 }, .IsDestroyed = true, .Health = 0 }; if (!ASTEROID_Texture) printf("Asteroid texture cannot be loaded!\n"); ASTEROID_SourceRect_Size1 = (SDL_Rect *)malloc(3 * sizeof(SDL_Rect)); ASTEROID_SourceRect_Size1[0] = (SDL_Rect) {.x = 0, .y = 0, .w = 800, .h = 800 }; ASTEROID_SourceRect_Size1[1] = (SDL_Rect) {.x = 0, .y = 800, .w = 800, .h = 800 }; ASTEROID_SourceRect_Size1[2] = (SDL_Rect) {.x = 800, .y = 0, .w = 800, .h = 800 }; ASTEROID_SourceRect_Size2 = (SDL_Rect *)malloc(3 * sizeof(SDL_Rect)); ASTEROID_SourceRect_Size2[0] = (SDL_Rect) {.x = 800, .y = 800, .w = 400, .h = 400 }; ASTEROID_SourceRect_Size2[1] = (SDL_Rect) {.x = 800, .y = 1200, .w = 400, .h = 400 }; ASTEROID_SourceRect_Size2[2] = (SDL_Rect) {.x = 1200, .y = 800, .w = 400, .h = 400 }; ASTEROID_SourceRect_Size3 = (SDL_Rect *)malloc(4 * sizeof(SDL_Rect)); ASTEROID_SourceRect_Size3[0] = (SDL_Rect) {.x = 1200, .y = 1200, .w = 200, .h = 200 }; ASTEROID_SourceRect_Size3[1] = (SDL_Rect) {.x = 1200, .y = 1400, .w = 200, .h = 200 }; ASTEROID_SourceRect_Size3[2] = (SDL_Rect) {.x = 1400, .y = 1200, .w = 200, .h = 200 }; ASTEROID_SourceRect_Size3[3] = (SDL_Rect) {.x = 1400, .y = 1400, .w = 200, .h = 200 }; printf("Asteroid initialized!\n"); ASTEROID_IsInit = true; } // ASTEROID_Initialize void BULLET_Deinitialize(){ if (!BULLET_IsInit) return; printf("De-initializing Bullet...\n"); printf("De-initializing ally bullet texture...\n"); SDL_DestroyTexture(BULLET_Texture_Ally); printf("De-initializing enemy bullet texture...\n"); SDL_DestroyTexture(BULLET_Texture_Enemy); printf("De-initializing Bullet finished!\n"); BULLET_IsInit = false; } void ENEMY_Deinitialize(){ if (!ENEMY_IsInit) return; printf("De-initializing Enemy class...\n"); BULLET_Deinitialize(); printf("De-initializing Enemy texture 1...\n"); SDL_DestroyTexture(ENEMY_Texture); printf("De-initializing Enemy class finished!\n"); ENEMY_IsInit = false; } void ASTEROID_Deinitialize(){ if (!ASTEROID_IsInit) return; printf("De-initializing Asteroid...\n"); printf("De-initializing Asteroid texture...\n"); SDL_DestroyTexture(ASTEROID_Texture); free(ASTEROID_SourceRect_Size1); free(ASTEROID_SourceRect_Size2); free(ASTEROID_SourceRect_Size3); printf("De-initializing Asteroid finished!\n"); ASTEROID_IsInit = false; } void SHIP_Deinitialize(){ if (!SHIP_IsInit) return; printf("De-initializing Ship class...\n"); BULLET_Deinitialize(); free(SHIP_SourceRect_Explosion); printf("De-initializing Ship texture 1...\n"); SDL_DestroyTexture(SHIP_Texture_Gliding); printf("De-initializing Ship texture 2...\n"); SDL_DestroyTexture(SHIP_Texture_Accelerating); printf("De-initializing Ship texture 2...\n"); SDL_DestroyTexture(SHIP_Texture_Explosion); printf("De-initializing Ship class finished!\n"); SHIP_IsInit = false; } Bullet BULLET_Fire(Vector location, double direction, BulletType type){ return (Bullet) { .Rotation = direction, .Location = location, .Momentum = getScaledDirectionalUnitVector(direction, (type == AllyBullet ? BULLET_Speed_Ally : BULLET_Speed_Enemy)), .TargetRect = (type == AllyBullet ? (SDL_Rect) {.x = 0, .y = 0, .w = 12, .h = 35 } : (SDL_Rect) {.x = 0, .y = 0, .w = 30, .h = 30 }), .Lifetime = (type == AllyBullet ? BULLET_DecayTime_Ally : BULLET_DecayTime_Enemy), .IsDestroyed = false, .Type = type }; } void BULLET_UpdateAlly(Bullet * bul, Asteroid * asts, int * astCount, Enemy * enemies, int * enemyCount) { if (!(bul->IsDestroyed)) { if ((bul->Lifetime)-- <= 0) { // Decay (bul->IsDestroyed) = true; return; } (bul->Location) = vectorAdd((bul->Location), (bul->Momentum)); // Move if ((bul->Location).x < 0.0f) (bul->Location).x = GAME_BoxWidth; // Check Boundaries else if ((bul->Location).x > GAME_BoxWidth) (bul->Location).x = 0.0f; if ((bul->Location).y < 0.0f) (bul->Location).y = GAME_BoxHeight; else if ((bul->Location).y > GAME_BoxHeight) (bul->Location).y = 0.0f; (bul->TargetRect).x = (int)round((bul->Location).x); // Update render Target (bul->TargetRect).y = (int)round((bul->Location).y); int i; for (i = 0; i < (*astCount); i++) { // Collide with Asteroids if (!(asts[i].IsDestroyed)) { if (RECT_CircleCollide(&(asts[i].TargetRect), &(bul->TargetRect))) { printf("Bullet is destroyed by asteroid no. %d!\n", i + 1); ASTEROID_TryDestroy(asts, astCount, i); if ((asts[i].IsDestroyed)) printf("Bullet destroyed asteroid no. %d!\n", i + 1); (bul->IsDestroyed) = true; break; } } } } } // BULLET_Update void BULLET_UpdateEnemy(Bullet * bul, Ship * shp, int * shpCount) { if (!(bul->IsDestroyed)) { if ((bul->Lifetime)-- <= 0) { // Decay (bul->IsDestroyed) = true; return; } // TODO: Export triple use of boundary check to method using pointers (bul->Location) = vectorAdd((bul->Location), (bul->Momentum)); // Move if ((bul->Location).x < 0.0f) (bul->Location).x = GAME_BoxWidth; // Check Boundaries else if ((bul->Location).x > GAME_BoxWidth) (bul->Location).x = 0.0f; if ((bul->Location).y < 0.0f) (bul->Location).y = GAME_BoxHeight; else if ((bul->Location).y > GAME_BoxHeight) (bul->Location).y = 0.0f; (bul->TargetRect).x = (int)round((bul->Location).x); // Update render Target (bul->TargetRect).y = (int)round((bul->Location).y); int i; for (i = 0; i < (*shpCount); i++) { // Collide with Asteroids if (!(shp->IsDead)) { if (RECT_CircleCollide(&(shp[i].TargetRect_Gliding), &(bul->TargetRect))) { printf("Player %d is destroyed by bullet!\n", i + 1); (bul->IsDestroyed) = true; (shp[i].IsDead) = true; break; } } } } } // BULLET_Update void BULLET_Draw(Bullet * bul, SDL_Renderer * renderer) { if (!(bul->IsDestroyed)) { if ((bul->Type) == AllyBullet) { SDL_RenderCopyEx(renderer, BULLET_Texture_Ally, NULL, &(bul->TargetRect), (bul->Rotation), NULL, SDL_FLIP_NONE); } else { SDL_RenderCopyEx(renderer, BULLET_Texture_Enemy, NULL, &(bul->TargetRect), (bul->Rotation), NULL, SDL_FLIP_NONE); } } } Asteroid ASTEROID_CreateRandom(){ return (Asteroid) { .Rotation = (double)(rand() % 360), .Size = 200, .RotationValue = fmod((double)(rand()), 4.0f) - 2.0f, // TODO: Reimplement random start pos here later // .Location = (_vector) {.x = (double)(rand() % GAME_BoxWidth), .y = (double)(rand() % GAME_BoxHeight) }, .Location = (Vector) {.x = 0, .y = 0 }, .Momentum = getScaledDirectionalUnitVector((double)(rand() % 360), fmod((double)rand(), 2.0f) + 1.0f), .TargetRect = (SDL_Rect) {.x = 0, .y = 0, .w = 200, .h = 200 }, .IsDestroyed = false, .SourceRect = ASTEROID_SourceRect_Size1[(rand() % 3)], .Health = 4 }; } bool ASTEROID_TryDestroy(Asteroid * asts, int * astCount, int index){ asts[index].Health--; if (asts[index].Health <= 0) { if (ASTEROID_CanSplit(&(asts[index]))) { printf("Asteroid %d was split...\n", index); asts[(*astCount)++] = ASTEROID_CreateFromSplit(&(asts[index])); Asteroid tmp = ASTEROID_CreateFromSplit(&(asts[index])); asts[index] = tmp; } else { printf("Asteroid %d was destroyed...\n", index); asts[index].IsDestroyed = true; } return true; } else { printf("Asteroid %d was hit...\n", index); } return false; } Asteroid ASTEROID_CreateFromSplit(Asteroid * creator){ Asteroid aster = (Asteroid) { .Rotation = (double)(rand() % 360), .Size = (creator->Size) / 2.0f, .RotationValue = fmod((double)(rand()), 4.0f) - 2.0f, .Location = creator->Location, .Momentum = getScaledDirectionalUnitVector((double)(rand() % 360), fmod((double)rand(), 2.0f) + 1.0f), .TargetRect = (SDL_Rect) {.x = 0, .y = 0, .w = (int)round((creator->Size) / 2.0f), .h = (int)round((creator->Size) / 2.0f) }, .IsDestroyed = false, .SourceRect = ASTEROID_SourceRect_Size1[0], .Health = 0 }; aster.Health = (int)round(aster.Size / 50.0f) + ((rand() % 2) ? (1) : (-1)); // Bei 200 3 - 5 Hits if (aster.Health <= 1) aster.Health = 1; if (aster.Size > 150.0f) aster.SourceRect = ASTEROID_SourceRect_Size1[(rand() % 3)]; else if (aster.Size > 75.0f) aster.SourceRect = ASTEROID_SourceRect_Size2[(rand() % 3)]; else aster.SourceRect = ASTEROID_SourceRect_Size3[(rand() % 4)]; return aster; } bool ASTEROID_CanSplit(Asteroid * ast){ return ((ast->Size) >= (2 * ASTEROID_MinimumSize)); } bool RECT_CircleCollide(SDL_Rect * rect1, SDL_Rect * rect2){ return (distance(rect1, rect2) < round(((double)(rect1->w + rect2->w)) / 2.0f)); } double distance(SDL_Rect * r1, SDL_Rect * r2){ double dx = (((double)(r2->x) + ((double)(r2->w) / 2.0f)) - ((double)(r1->x) + ((double)(r1->w) / 2.0f))); double dy = (((double)(r2->y) + ((double)(r2->h) / 2.0f)) - ((double)(r1->y) + ((double)(r1->h) / 2.0f))); return round(sqrt((dx * dx ) + (dy * dy))); } void ASTEROID_Update(Asteroid * ast){ if (!(ast->IsDestroyed)) { (ast->Rotation) += (ast->RotationValue); // Rotate (ast->Location) = vectorAdd(ast->Location, ast->Momentum); // Update Position if ((ast->Location).x < -(ast->Size)) (ast->Location).x = GAME_BoxWidth; // Check Boundaries else if ((ast->Location).x > GAME_BoxWidth) (ast->Location).x = -(ast->Size); if ((ast->Location).y < -(ast->Size)) (ast->Location).y = GAME_BoxHeight; else if ((ast->Location).y > GAME_BoxHeight) (ast->Location).y = -(ast->Size); (ast->TargetRect).x = (int)round((ast->Location).x); (ast->TargetRect).y = (int)round((ast->Location).y); } } // ASTEROID_Update void ASTEROID_Draw(Asteroid * ast, SDL_Renderer * renderer){ if (!(ast->IsDestroyed)) { SDL_RenderCopyEx(renderer, ASTEROID_Texture, &(ast->SourceRect), &(ast->TargetRect), ast->Rotation, NULL, SDL_FLIP_NONE); // Draw Image } } Enemy ENEMY_GetDefault(){ Enemy temp; temp.Bullets = (Bullet *)malloc(ENEMY_MaxBulletCount * sizeof(Bullet)); int i; for (i = 0; i < ENEMY_MaxBulletCount; i++) { temp.Bullets[i] = NULLET; // Nullet is set only if BULLET_Initialize() was called! } temp.Location = (Vector) {.x = (double)(rand() % GAME_BoxWidth), .y = (double)(rand() % GAME_BoxHeight) }; temp.Momentum = getScaledDirectionalUnitVector((rand() % 360), fmod((double)rand(), ENEMY_MaxSpeed / 2.0f) + (ENEMY_MaxSpeed / 2.0f)); temp.TargetRect = (SDL_Rect) {.x = 0, .y = 0, .w = 80, .h = 40 }; temp.WeaponCooldown = ENEMY_ShootIntevale; temp.lastBulletIndex = 0; temp.IsDead = false; temp.TurnCooldown = (rand() % ENEMY_MaxTurnIntervale); return temp; } // ENEMY_CreateDefault void ENEMY_DestroyObject(Enemy * enm){ printf("De-initializing Enemy...\n"); printf("De-initializing Bullet-array...\n"); free((enm->Bullets)); printf("De-initializing Enemy...\n"); } void ENEMY_Update(Enemy * enm, Ship * targets, int targetCount){ if (!(enm->IsDead)) { int i; for (i = 0; i < ENEMY_MaxBulletCount; i++) { // Update Bullets BULLET_UpdateEnemy(&((enm->Bullets)[i]), targets, &targetCount); } if ((enm->TurnCooldown)-- <= 0) { (enm->TurnCooldown) = (rand() % ENEMY_MaxTurnIntervale); (enm->Momentum) = getScaledDirectionalUnitVector((rand() % 360), fmod((double)rand(), ENEMY_MaxSpeed / 2.0f) + (ENEMY_MaxSpeed / 2.0f)); } (enm->Location) = vectorAdd((enm->Location), (enm->Momentum)); // Update Position if ((enm->Location).x < -(enm->TargetRect).w) (enm->Location).x = GAME_BoxWidth; else if ((enm->Location).x > GAME_BoxWidth + (enm->TargetRect).w) (enm->Location).x = 0.0f; if ((enm->Location).y < -(enm->TargetRect).h) (enm->Location).y = GAME_BoxHeight; else if ((enm->Location).y > GAME_BoxHeight + (enm->TargetRect).h) (enm->Location).y = 0.0f; (enm->TargetRect).x = (int)round((enm->Location).x); (enm->TargetRect).y = (int)round((enm->Location).y); if ((enm->WeaponCooldown) <= 0) { // Shoot instantly if cooldown ends (enm->WeaponCooldown) = ENEMY_ShootIntevale; (enm->lastBulletIndex)++; if ((enm->lastBulletIndex) >= ENEMY_MaxBulletCount) (enm->lastBulletIndex) = 0; Vector startPoint = vectorAdd((enm->Location), (Vector) {.x = (double)((enm->TargetRect).w) / 2.0f, .y = (double)((enm->TargetRect).h) / 2.0f }); (enm->Bullets)[(enm->lastBulletIndex)] = BULLET_Fire(startPoint, vectorRotation(vectorSub((targets[rand() % targetCount].Location), (enm->Location))), EnemyBullet); // Maybe check if bullet space is already taken from another bullet being fired... } (enm->WeaponCooldown)--; } else { (enm->DeadTime)++; } } // ENEMY_Update void ENEMY_Draw(Enemy * enm, SDL_Renderer * renderer){ if (!(enm->IsDead)) { int i; for (i = 0; i < ENEMY_MaxBulletCount; i++) { // Draw Bullets BULLET_Draw(&((enm->Bullets)[i]), renderer); } SDL_RenderCopyEx(renderer, ENEMY_Texture, NULL, &(enm->TargetRect), 0.0f, NULL, SDL_FLIP_NONE); // Draw Image } } Ship SHIP_CreateDefault(){ Ship temp; temp.Bullets = (Bullet *)malloc(SHIP_MaxBulletCount * sizeof(Bullet)); int i; for (i = 0; i < SHIP_MaxBulletCount; i++) { temp.Bullets[i] = NULLET; // Nullet is set only if BULLET_Initialize() was called! } temp.Rotation = 0.0f; temp.FacingDirection = (Vector) {.x = 0.0f, .y = 0.0f }; temp.Location = (Vector) {.x = 800.0f, .y = 450.0f }; temp.Momentum = (Vector) {.x = 0.0f, .y = 0.0f }; temp.TargetRect_Gliding = (SDL_Rect) {.x = 0, .y = 0, .w = 40, .h = 51 }; temp.TargetRect_Accelerating = (SDL_Rect) {.x = 0, .y = 0, .w = 40, .h = 74 }; temp.TargetRect_Explosion = (SDL_Rect) {.x = 0, .y = 0, .w = 160, .h = 204 }; temp.WeaponCooldown = 0; temp.DeadTime = 0; temp.lastBulletIndex = 0; temp.IsDead = false; return temp; } // SHIP_CreateDefault void SHIP_DestroyObject(Ship * shp){ printf("De-initializing Ship...\n"); printf("De-initializing Bullet-array...\n"); free((shp->Bullets)); printf("De-initializing Ship...\n"); } void SHIP_Update(Ship * shp, Uint8 * keystate, Asteroid * asts, int * astCount, Enemy * enemies, int * enemyCount){ if (!(shp->IsDead)) { (shp->TurnLeftButtonPressed) = keystate[SHIP_LeftButton]; (shp->TurnRightButtonPressed) = keystate[SHIP_RightButton]; (shp->ForwardButtonPressed) = keystate[SHIP_ForwardButton]; (shp->ShootButtonPressed) = keystate[SHIP_ShootButton]; int i; for (i = 0; i < SHIP_MaxBulletCount; i++) { // Update Bullets BULLET_UpdateAlly(&((shp->Bullets)[i]), asts, astCount, enemies, enemyCount); } if (((shp->TurnLeftButtonPressed) + (shp->TurnRightButtonPressed)) == 1) { // Handle rotation if ((shp->TurnLeftButtonPressed)) { // Rotate to the left (shp->Rotation) -= SHIP_RotationValue; } else if ((shp->TurnRightButtonPressed)) { // Rotate to the right (shp->Rotation) += SHIP_RotationValue; } (shp->FacingDirection) = getScaledDirectionalUnitVector((shp->Rotation), SHIP_Acceleration); } if ((shp->ForwardButtonPressed)) { // Handle forward acceleration (shp->Momentum) = vectorAdd((shp->FacingDirection), (shp->Momentum)); if (vectorMagnitude((shp->Momentum)) > SHIP_MaxSpeed) { (shp->Momentum) = vectorScaleTo((shp->Momentum), SHIP_MaxSpeed); } } (shp->Location) = vectorAdd((shp->Location), (shp->Momentum)); // Update Position if ((shp->Location).x < -(shp->TargetRect_Gliding).w) (shp->Location).x = GAME_BoxWidth; else if ((shp->Location).x > GAME_BoxWidth + (shp->TargetRect_Gliding).w) (shp->Location).x = 0.0f; if ((shp->Location).y < -(shp->TargetRect_Gliding).h) (shp->Location).y = GAME_BoxHeight; else if ((shp->Location).y > GAME_BoxHeight + (shp->TargetRect_Gliding).h) (shp->Location).y = 0.0f; (shp->TargetRect_Gliding).x = (int)round((shp->Location).x); (shp->TargetRect_Gliding).y = (int)round((shp->Location).y); (shp->TargetRect_Accelerating).x = (shp->TargetRect_Gliding).x; (shp->TargetRect_Accelerating).y = (shp->TargetRect_Gliding).y; if ((shp->ShootButtonPressed)) { // Fire bullet if ((shp->WeaponCooldown) <= 0) { (shp->WeaponCooldown) = SHIP_ShootIntevale; (shp->lastBulletIndex)++; if ((shp->lastBulletIndex) >= SHIP_MaxBulletCount) (shp->lastBulletIndex) = 0; (shp->Bullets)[(shp->lastBulletIndex)] = BULLET_Fire(vectorAdd((shp->Location), (Vector) {.x = (double)(SHIP_RotationCenter_Flight.x) / 2.0f, .y = (double)(SHIP_RotationCenter_Flight.y) / 2.0f }), (shp->Rotation), AllyBullet); // Maybe check if bullet space is already taken from another bullet being fired... } } (shp->WeaponCooldown)--; for (i = 0; i < (*astCount); i++) { if (RECT_CircleCollide(&(asts[i].TargetRect), &(shp->TargetRect_Gliding))) { printf("Ship is destroyed by asteroid no. %d!\n", i + 1); (shp->IsDead) = true; (shp->TargetRect_Explosion).x = ((int)round((shp->Location).x) - ((shp->TargetRect_Explosion).w / 4)); (shp->TargetRect_Explosion).y = ((int)round((shp->Location).y) - ((shp->TargetRect_Explosion).h / 4)); break; } } } else { (shp->DeadTime)++; } } // SHIP_Update void SHIP_Draw(Ship * shp, SDL_Renderer * renderer){ if (!(shp->IsDead)) { int i; for (i = 0; i < SHIP_MaxBulletCount; i++) { // Draw Bullets BULLET_Draw(&((shp->Bullets)[i]), renderer); } if ((shp->ForwardButtonPressed)) SDL_RenderCopyEx(renderer, SHIP_Texture_Accelerating, &SHIP_SourceRect_Accelerating, &(shp->TargetRect_Accelerating), (shp->Rotation), &SHIP_RotationCenter_Flight, SDL_FLIP_NONE); // Draw Image else SDL_RenderCopyEx(renderer, SHIP_Texture_Gliding, &SHIP_SourceRect_Gliding, &(shp->TargetRect_Gliding), (shp->Rotation), NULL, SDL_FLIP_NONE); // Draw Image } else if ((shp->DeadTime) < SHIP_DeathAnimSpeed * SHIP_DeathAnimFrameCount) { SDL_RenderCopyEx(renderer, SHIP_Texture_Explosion, &(SHIP_SourceRect_Explosion[((shp->DeadTime) / SHIP_DeathAnimSpeed)]), &(shp->TargetRect_Explosion), (shp->Rotation), NULL, SDL_FLIP_NONE); // Draw Image } }