commit 762dfd03dbf98c4319b9f4533553690c397524ba Author: Michael Chen Date: Tue Dec 26 23:24:29 2017 +0100 Initial commit diff --git a/assets/fonts/bulky.ttf b/assets/fonts/bulky.ttf new file mode 100644 index 0000000..1ed7903 Binary files /dev/null and b/assets/fonts/bulky.ttf differ diff --git a/assets/fonts/millenium.ttf b/assets/fonts/millenium.ttf new file mode 100644 index 0000000..8a15a60 Binary files /dev/null and b/assets/fonts/millenium.ttf differ diff --git a/assets/images/asteroid.png b/assets/images/asteroid.png new file mode 100644 index 0000000..a5946b9 Binary files /dev/null and b/assets/images/asteroid.png differ diff --git a/assets/images/asteroidDebug.png b/assets/images/asteroidDebug.png new file mode 100644 index 0000000..ee4e5c5 Binary files /dev/null and b/assets/images/asteroidDebug.png differ diff --git a/assets/images/bullet.png b/assets/images/bullet.png new file mode 100644 index 0000000..847d90d Binary files /dev/null and b/assets/images/bullet.png differ diff --git a/assets/images/enemy.png b/assets/images/enemy.png new file mode 100644 index 0000000..56a078f Binary files /dev/null and b/assets/images/enemy.png differ diff --git a/assets/images/enemyBullet.png b/assets/images/enemyBullet.png new file mode 100644 index 0000000..9c72069 Binary files /dev/null and b/assets/images/enemyBullet.png differ diff --git a/assets/images/ship.png b/assets/images/ship.png new file mode 100644 index 0000000..8fec603 Binary files /dev/null and b/assets/images/ship.png differ diff --git a/assets/images/shipAcc.png b/assets/images/shipAcc.png new file mode 100644 index 0000000..57d2c99 Binary files /dev/null and b/assets/images/shipAcc.png differ diff --git a/assets/images/shipExpl.png b/assets/images/shipExpl.png new file mode 100644 index 0000000..889b314 Binary files /dev/null and b/assets/images/shipExpl.png differ diff --git a/assets/images/shipExpl1.png b/assets/images/shipExpl1.png new file mode 100644 index 0000000..f6911bd Binary files /dev/null and b/assets/images/shipExpl1.png differ diff --git a/assets/images/star.png b/assets/images/star.png new file mode 100644 index 0000000..3a61952 Binary files /dev/null and b/assets/images/star.png differ diff --git a/assets/sounds/explosion.wav b/assets/sounds/explosion.wav new file mode 100644 index 0000000..81a39b3 Binary files /dev/null and b/assets/sounds/explosion.wav differ diff --git a/assets/sounds/laser.wav b/assets/sounds/laser.wav new file mode 100644 index 0000000..3384574 Binary files /dev/null and b/assets/sounds/laser.wav differ diff --git a/assets/sounds/rocket.wav b/assets/sounds/rocket.wav new file mode 100644 index 0000000..a8ac2fe Binary files /dev/null and b/assets/sounds/rocket.wav differ diff --git a/asteroids.c b/asteroids.c new file mode 100644 index 0000000..5aab8a7 --- /dev/null +++ b/asteroids.c @@ -0,0 +1,521 @@ +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef __nullptr__ +#define Nullptr(type) (type *)0 +#endif // __nullptr__ + +#include "vector.h" +#include "asteroids.h" + +// 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 SHIP_BoxWidth, SHIP_BoxHeight, SHIP_MaxBulletCount, ASTEROID_BoxWidth, ASTEROID_BoxHeight, BULLET_BoxWidth, BULLET_BoxHeight, ENEMY_BoxWidth, ENEMY_BoxHeight, 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; +// End Vars + +void BULLET_Initialize(SDL_Renderer * renderer, int width, int height){ + 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_BoxWidth = width; + BULLET_BoxHeight = height; + BULLET_Texture_Ally = IMG_LoadTexture(renderer, "bullet.png"); + if (!BULLET_Texture_Ally) printf("Ally bullet texture cannot be loaded!\n"); + BULLET_Texture_Enemy = IMG_LoadTexture(renderer, "enemyBullet.png"); + if (!BULLET_Texture_Enemy) printf("Enemy bullet texture cannot be loaded!\n"); + printf("Bullet initialized!\n"); +} + +void BULLET_Deinitialize(){ + 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 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 = BULLET_BoxWidth; // Check Boundaries + else if ((bul->Location).x > BULLET_BoxWidth) (bul->Location).x = 0.0f; + if ((bul->Location).y < 0.0f) (bul->Location).y = BULLET_BoxHeight; + else if ((bul->Location).y > BULLET_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; + } + (bul->Location) = vectorAdd((bul->Location), (bul->Momentum)); // Move + if ((bul->Location).x < 0.0f) (bul->Location).x = BULLET_BoxWidth; // Check Boundaries + else if ((bul->Location).x > BULLET_BoxWidth) (bul->Location).x = 0.0f; + if ((bul->Location).y < 0.0f) (bul->Location).y = BULLET_BoxHeight; + else if ((bul->Location).y > BULLET_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); + } + } +} + +void ASTEROID_Initialize(SDL_Renderer * renderer, int width, int height){ + printf("Initializing Asteroid...\n"); + ASTEROID_BoxWidth = width; + ASTEROID_BoxHeight = height; + ASTEROID_Texture = IMG_LoadTexture(renderer, "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_Initialize + +Asteroid ASTEROID_CreateRandom(){ + return (Asteroid) { + .Rotation = (double)(rand() % 360), + .Size = 200, + .RotationValue = fmod((double)(rand()), 4.0f) - 2.0f, + // .Location = (_vector) {.x = (double)(rand() % ASTEROID_BoxWidth), .y = (double)(rand() % ASTEROID_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_Deinitialize(){ + 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"); +} + +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 = ASTEROID_BoxWidth; // Check Boundaries + else if ((ast->Location).x > ASTEROID_BoxWidth) (ast->Location).x = -(ast->Size); + if ((ast->Location).y < -(ast->Size)) (ast->Location).y = ASTEROID_BoxHeight; + else if ((ast->Location).y > ASTEROID_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 + } +} + +void ENEMY_Initialize(SDL_Renderer * renderer, int width, int height){ + printf("Initializing Enemy...\n"); + BULLET_Initialize(renderer, width, height); + ENEMY_BoxWidth = width; + ENEMY_BoxHeight = height; + ENEMY_Texture = IMG_LoadTexture(renderer, "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_Initialize + +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() % ENEMY_BoxWidth), .y = (double)(rand() % ENEMY_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_Deinitialize(){ + 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"); +} + +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 = ENEMY_BoxWidth; + else if ((enm->Location).x > ENEMY_BoxWidth + (enm->TargetRect).w) (enm->Location).x = 0.0f; + if ((enm->Location).y < -(enm->TargetRect).h) (enm->Location).y = ENEMY_BoxHeight; + else if ((enm->Location).y > ENEMY_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 + } +} + +void SHIP_Initialize(SDL_Renderer * renderer, int width, int height){ + printf("Initializing Ship...\n"); + BULLET_Initialize(renderer, width, height); + SHIP_BoxWidth = width; + SHIP_BoxHeight = height; + SHIP_Texture_Gliding = IMG_LoadTexture(renderer, "ship.png"); + if (!SHIP_Texture_Gliding) printf("Ship texture 1 cannot be loaded!\n"); + SHIP_Texture_Accelerating = IMG_LoadTexture(renderer, "shipAcc.png"); + if (!SHIP_Texture_Accelerating) printf("Ship texture 2 cannot be loaded!\n"); + SHIP_Texture_Explosion = IMG_LoadTexture(renderer, "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 }; + 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_Initialize + +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_Deinitialize(){ + 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"); +} + +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 = SHIP_BoxWidth; + else if ((shp->Location).x > SHIP_BoxWidth + (shp->TargetRect_Gliding).w) (shp->Location).x = 0.0f; + if ((shp->Location).y < -(shp->TargetRect_Gliding).h) (shp->Location).y = SHIP_BoxHeight; + else if ((shp->Location).y > SHIP_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 + } +} diff --git a/asteroids.h b/asteroids.h new file mode 100644 index 0000000..ffcc3f0 --- /dev/null +++ b/asteroids.h @@ -0,0 +1,81 @@ +#ifndef __asteroids_h__ +#define __asteroids_h__ + +#include "vector.h" + +// Filebindings +const char * +// End Filebindings + +// Enums +typedef enum bullettype { AllyBullet = 0, EnemyBullet = 1 } BulletType; +// End Enums + +// Structs +typedef struct bulletStruct { + double Rotation; + Vector Location, Momentum; + SDL_Rect TargetRect; + int Lifetime; + bool IsDestroyed; + BulletType Type; +} Bullet; + +typedef struct enemyStruct { + bool IsDead; + Vector Location, Momentum; + SDL_Rect TargetRect; + int WeaponCooldown, lastBulletIndex, DeadTime, TurnCooldown; + Bullet * Bullets; +} Enemy; + +typedef struct shipStruct{ + bool TurnRightButtonPressed, TurnLeftButtonPressed, ForwardButtonPressed, ShootButtonPressed, IsDead; + double Rotation; + Vector FacingDirection, Location, Momentum; + SDL_Rect TargetRect_Gliding, TargetRect_Accelerating, TargetRect_Explosion; + int WeaponCooldown, lastBulletIndex, DeadTime; + Bullet * Bullets; +} Ship; + +typedef struct asteroidStruct { + double Rotation, Size, RotationValue; + Vector Location, Momentum; + SDL_Rect TargetRect, SourceRect; + bool IsDestroyed; + int Health; +} Asteroid; +// End Structs + +// Prototypes +void BULLET_Initialize(SDL_Renderer * renderer, int width, int height); +void BULLET_Deinitialize(); +Bullet BULLET_Fire(Vector location, double direction, BulletType type); +void BULLET_UpdateAlly(Bullet * bul, Asteroid * asts, int * astCount, Enemy * enemies, int * enemyCount); +void BULLET_UpdateEnemy(Bullet * bul, Ship * shp, int * shpCount); +void BULLET_Draw(Bullet * bul, SDL_Renderer * renderer); +void ASTEROID_Initialize(SDL_Renderer * renderer, int width, int height); +Asteroid ASTEROID_CreateRandom(); +bool ASTEROID_TryDestroy(Asteroid * asts, int * astCount, int index); +Asteroid ASTEROID_CreateFromSplit(Asteroid * creator); +bool ASTEROID_CanSplit(Asteroid * ast); +bool RECT_CircleCollide(SDL_Rect * rect1, SDL_Rect * rect2); +double distance(SDL_Rect * r1, SDL_Rect * r2); +void ASTEROID_Deinitialize(); +void ASTEROID_Update(Asteroid * ast); +void ASTEROID_Draw(Asteroid * ast, SDL_Renderer * renderer); +void ENEMY_Initialize(SDL_Renderer * renderer, int width, int height); +Enemy ENEMY_GetDefault(); +void ENEMY_Deinitialize(); +void ENEMY_DestroyObject(Enemy * enm); +void ENEMY_Update(Enemy * enm, Ship * targets, int targetCount); +void ENEMY_Draw(Enemy * enm, SDL_Renderer * renderer); +void SHIP_Initialize(SDL_Renderer * renderer, int width, int height); +Ship SHIP_CreateDefault(); +void SHIP_Deinitialize(); +void SHIP_DestroyObject(Ship * shp); +void SHIP_Update(Ship * shp, Uint8 * keystate, Asteroid * asts, int * astCount, Enemy * enemies, int * enemyCount); +void SHIP_Draw(Ship * shp, SDL_Renderer * renderer); +// End Prototypes + +#endif // __asteroids_h__ diff --git a/bin/Debug/Asteroids.exe b/bin/Debug/Asteroids.exe new file mode 100644 index 0000000..5610e79 Binary files /dev/null and b/bin/Debug/Asteroids.exe differ diff --git a/bin/Debug/SDL_Test.exe b/bin/Debug/SDL_Test.exe new file mode 100644 index 0000000..dd22ee1 Binary files /dev/null and b/bin/Debug/SDL_Test.exe differ diff --git a/bin/Release/Asteroids.exe b/bin/Release/Asteroids.exe new file mode 100644 index 0000000..2b136f7 Binary files /dev/null and b/bin/Release/Asteroids.exe differ diff --git a/bin/Release/SDL_Test.exe b/bin/Release/SDL_Test.exe new file mode 100644 index 0000000..11c1d18 Binary files /dev/null and b/bin/Release/SDL_Test.exe differ diff --git a/main.c b/main.c new file mode 100644 index 0000000..4b740f6 --- /dev/null +++ b/main.c @@ -0,0 +1,175 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vector.h" +#include "asteroids.h" +#include "starfield.h" + +#ifndef __nullptr__ +#define Nullptr(type) (type *)0 +#endif // __nullptr__ + +void DrawFrame(); +void INITIALIZE(); +void QUIT(); +void GAMELOOP(); +void mousePress(SDL_MouseButtonEvent b); + +const int width = 1600; +const int height = 900; +const int totalAsteroidCount = 6; +const int totalEnemyCount = 6; + +Uint8 * keystate; +SDL_Window * window; +SDL_Renderer * renderer; +SDL_Event event; +bool running = true; +SDL_Color messageColor; +TTF_Font * Sans; +SDL_Surface * messageSurface; +SDL_Rect messageRect; +SDL_Texture * messageTexture; +Asteroid * asteroids; +Ship ship; +Enemy * enemies; +Starfield starfield; +int asteroidCount = 0, enemyCount = 0; + +int main(int argc, char * args[]){ + INITIALIZE(); + while (running) { + GAMELOOP(); + DrawFrame(); + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + running = false; + break; + case SDL_KEYDOWN: + if (event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) running = false; + break; + } + } + } + QUIT(); + return 0; +} /* main */ + +void QUIT(){ + printf("De-initializing started...\n"); + free(keystate); + SDL_FreeSurface(messageSurface); + SDL_DestroyTexture(messageTexture); + SHIP_DestroyObject(&ship); + int i; + for (i = 0; i < enemyCount; i++){ + ENEMY_DestroyObject(&(enemies[i])); + } + free(enemies); + STARFIELD_DestroyObject(&starfield); + STARFIELD_Deinitialize(); + SHIP_Deinitialize(); + ENEMY_Deinitialize(); + ASTEROID_Deinitialize(); + TTF_CloseFont(Sans); + TTF_Quit(); + free(asteroids); + IMG_Quit(); + printf("Quitting SDL_IMG finished!\n"); + SDL_DestroyRenderer(renderer); + printf("De-initializing renderer finished!\n"); + SDL_DestroyWindow(window); + printf("De-initializing window finished!\n"); + SDL_Quit(); + printf("Quitting SDL finished!\n"); + printf("De-initializing finished!\n"); +} + +void DrawFrame(){ + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderClear(renderer); + STARFIELD_Draw(&starfield, renderer); + SHIP_Draw(&ship, renderer); + int i; + for (i = 0; i < enemyCount; i++){ + ENEMY_Draw(&(enemies[i]), renderer); + } + for (i = 0; i < asteroidCount; i++) { + ASTEROID_Draw(&(asteroids[i]), renderer); + } + // SDL_RenderCopy(renderer, messageTexture, NULL, &messageRect); + SDL_RenderPresent(renderer); +} + +void INITIALIZE() { + srand(time(NULL)); + if (SDL_Init(SDL_INIT_EVERYTHING) != 0) printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); + else printf("SDL was successfully initialized!\n"); + if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG) printf("IMG could not initialize! IMG_Error: %s\n", IMG_GetError()); + else printf("IMG was successfully initialized!\n"); + TTF_Init(); + + Sans = TTF_OpenFont("bulky.ttf", 12); + if (!Sans) printf("Font cannot be initialized!\n"); + else printf("Font was successfully initialized!\n"); + messageColor = (SDL_Color) {.r = 125,.g=255,.b = 125,.a = 255}; + messageSurface = TTF_RenderText_Solid(Sans, "A", messageColor); + if (!messageSurface) printf("Text surface is null!\n"); + else printf("Text surface was created!\n"); + messageTexture = SDL_CreateTextureFromSurface(renderer, messageSurface); + if (!messageTexture) printf("Text texture is null!\n"); + else printf("Text texture was created!\n"); + messageRect = (SDL_Rect) {.x = 100, .y = 100, .w = (messageSurface->w), .h = (messageSurface->h) }; + + window = SDL_CreateWindow("Asteroids Game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_OPENGL); + printf("Window was created!\n"); + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + printf("Renderer was created!\n"); + STARFIELD_Initialize(renderer, width, height); + SHIP_Initialize(renderer, width, height); + ENEMY_Initialize(renderer, width, height); + ASTEROID_Initialize(renderer, width, height); + + starfield = STARFIELD_GetDefault(100); + ship = SHIP_CreateDefault(); + enemies = calloc(20, sizeof(Enemy)); + int i; + enemies[enemyCount++] = ENEMY_GetDefault(); + asteroids = calloc(200, sizeof(Asteroid)); + for (i = 0; i < totalAsteroidCount; i++) { + asteroids[asteroidCount++] = ASTEROID_CreateRandom(); + } +} /* INITIALIZE */ + +void GAMELOOP() { + keystate = SDL_GetKeyboardState(NULL); // Get key changes + SHIP_Update(&ship, keystate, asteroids, &asteroidCount, enemies, &enemyCount); + int i; + for (i = 0; i < enemyCount; i++){ + ENEMY_Update(&(enemies[i]), &ship, 1); + } + STARFIELD_Update(&starfield); + if (!(ship.IsDead)) { + for (i = 0; i < asteroidCount; i++) { + ASTEROID_Update(&(asteroids[i])); + } + } +} /* GAMELOOP */ + +void mousePress(SDL_MouseButtonEvent b){ + return; + if (b.button == SDL_BUTTON_LEFT) { + printf("Left mouse pressed...\n"); + } else if (b.button == SDL_BUTTON_RIGHT) { + printf("Right mouse pressed...\n"); + } else { + printf("Unknown mouse button pressed: %d\n", b.button); + } +} diff --git a/starfield.c b/starfield.c new file mode 100644 index 0000000..03abc9d --- /dev/null +++ b/starfield.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include + +#include "starfield.h" + +// Properties +double STAR_Speed = 5.0f; +double STAR_MaxRotationValue = 5.0f; +// End Properties + +// Vars +int STARFIELD_BoxWidth, STARFIELD_BoxHeight; +SDL_Texture * STAR_Texture; +SDL_Rect * STAR_SourceRects; +// End Vars + +void STARFIELD_Initialize(SDL_Renderer * renderer, int width, int height){ + printf("Initializing starfield...\n"); + STARFIELD_BoxWidth = width; + STARFIELD_BoxHeight = height; + STAR_Texture = IMG_LoadTexture(renderer, "star.png"); + if (!STAR_Texture) + printf("Star texture cannot be loaded!\n"); + STAR_SourceRects = malloc(3 * sizeof(SDL_Rect)); + int i; + for (i = 0; i < 3; i++) { + STAR_SourceRects[i] = (SDL_Rect) {.x = 0, .y = (100 * i), .w = 100, .h = 100 }; + } + printf("Starfield initialized!\n"); +} + +void STARFIELD_Deinitialize(){ + printf("De-initializing Starfield class...\n"); + printf("De-initializing Source Rectangles...\n"); + free(STAR_SourceRects); + printf("De-initializing Starfield textures...\n"); + SDL_DestroyTexture(STAR_Texture); + printf("Starfield class de-initialized!\n"); +} + +Starfield STARFIELD_GetDefault(int count){ + Star * strs = malloc(count * sizeof(Star)); + int i; + + for (i = 0; i < count; i++) { + strs[i] = STAR_GetDefault(); + } + return (Starfield) {.Stars = strs, .StarCount = count }; +} + +void STARFIELD_Draw(Starfield * strf, SDL_Renderer * renderer){ + printf("Drawing starfield...\n"); + int i; + for (i = 0; i < (strf->StarCount); i++) { + STAR_Draw(&((strf->Stars)[i]), renderer); + } + printf("Starfield drawn!\n"); +} + +void STARFIELD_Update(Starfield * strf){ + int i; + for (i = 0; i < (strf->StarCount); i++) { + STAR_Update(&((strf->Stars)[i])); + } +} + +void STARFIELD_DestroyObject(Starfield * strf){ + printf("De-initializing Starfield...\n"); + printf("De-initializing Star-array...\n"); + free((strf->Stars)); + printf("Starfield de-initialized!\n"); +} + +Star STAR_GetDefault(){ + return (Star) { + .x = (rand() % STARFIELD_BoxWidth) - (STARFIELD_BoxWidth / 2), + .y = (rand() % STARFIELD_BoxHeight) - (STARFIELD_BoxHeight / 2), + .z = (rand() % STARFIELD_BoxWidth), + .TargetRect = (SDL_Rect) {.x = 0, .y = 0, .w = 0, .h = 0 }, + .SourceRect = STAR_SourceRects[(rand() % 3)], + .Rotation = (double)(rand() % 360), + .RotationValue = (fmod((double)(rand()), STAR_MaxRotationValue * 2.0f) - STAR_MaxRotationValue), + .OutOfBounds = false + }; +} +void STAR_Update(Star * star){ + if (!(star->OutOfBounds)) { + (star->Rotation) += (star->RotationValue); + (star->z) -= STAR_Speed; // increase speed (rather acceleration since it looks like a 3D room, but the speed is constant) + if ((star->z) < 1) { // respawns a star that has disappeared near the edge of the screen + *star = STAR_GetDefault(); + } + double sx = (star->x) / (star->z) * STARFIELD_BoxWidth;// current distance using perspective + if (sx > STARFIELD_BoxWidth / 2|| sx < -STARFIELD_BoxWidth / 2) + (star->OutOfBounds) = true; + double sy = (star->y) / (star->z) * STARFIELD_BoxHeight; // current distance using perspective + if (sy * 2 > STARFIELD_BoxHeight || sy < -STARFIELD_BoxHeight / 2) + (star->OutOfBounds) = true; + double size = (((double)(STARFIELD_BoxWidth - (star->z))) / ((double)(STARFIELD_BoxWidth)) * 2.4f) + 1.0f; // radius + size = 3 * size * size; // potentially grow particles + (star->TargetRect) = (SDL_Rect) {.x = (int)round(sx) + (STARFIELD_BoxWidth / 2), .y = (int)round(sy) + (STARFIELD_BoxHeight / 2), .w = size, .h = size }; + } else { + *star = STAR_GetDefault(); + } +} + +void STAR_Draw(Star * star, SDL_Renderer * renderer){ + if (!(star->OutOfBounds)) { + // printf("Drawing star at: %d | %d with Size %d...\n", (star->TargetRect).x,(star->TargetRect).y,(star->TargetRect).w ); + SDL_RenderCopyEx(renderer, STAR_Texture, &(star->SourceRect), &(star->TargetRect), (star->Rotation), NULL, SDL_FLIP_NONE); + } +} diff --git a/starfield.h b/starfield.h new file mode 100644 index 0000000..98e3e82 --- /dev/null +++ b/starfield.h @@ -0,0 +1,31 @@ +#ifndef __starfield_h__ +#define __starfield_h__ + +#include + +// Structs +typedef struct starStruct { + double x, y, z, Rotation, RotationValue; + SDL_Rect TargetRect, SourceRect; + bool OutOfBounds; +} Star; + +typedef struct starfieldStruct { + Star * Stars; + int StarCount; +} Starfield; +// End Structs + +// Prototypes +void STARFIELD_Initialize(SDL_Renderer * renderer, int width, int height); +void STARFIELD_Deinitialize(); +Starfield STARFIELD_GetDefault(int count); +void STARFIELD_Draw(Starfield * strf, SDL_Renderer * renderer); +void STARFIELD_Update(Starfield * strf); +void STARFIELD_DestroyObject(Starfield * strf); +Star STAR_GetDefault(); +void STAR_Update(Star * star); +void STAR_Draw(Star * star, SDL_Renderer * renderer); +// End Prototypes + +#endif // __starfield_h__ diff --git a/vector.c b/vector.c new file mode 100644 index 0000000..890f447 --- /dev/null +++ b/vector.c @@ -0,0 +1,83 @@ +#include + +#include "vector.h" + +// Properties +const double degreeToRadians = M_PI / 180.0f; +// End Properties + +Vector vectorScale(Vector v, double factor){ + return (Vector) + { + .x = v.x * factor, + .y = v.y * factor + }; +} + +double vectorMagnitude(Vector v){ + return sqrt((v.x * v.x) + (v.y * v.y)); +} + +double vectorRotation(Vector v){ + double da=atan2(v.x, -v.y)/degreeToRadians; + if (da < 0.0f) return (da+360.0f); + else return da; +} + +Vector vectorScaleTo(Vector v, double magnitude){ + return vectorScale(v, magnitude / vectorMagnitude(v)); +} + +double dotProduct(Vector v1, Vector v2){ + return (v1.x * v2.x ) + (v1.y * v2.y); +} + +double vectorDist(Vector v1, Vector v2){ + return sqrt(dotProduct(v1, v2)); +} + +Vector vectorAdd(Vector v1, Vector v2){ + return (Vector) + { + .x = v1.x + v2.x, + .y = v1.y + v2.y + }; +} + +Vector vectorSub(Vector v1, Vector v2){ + return (Vector) + { + .x = v1.x - v2.x, + .y = v1.y - v2.y + }; +} + +double degreeSin(double x){ + return sin(x * degreeToRadians); +} + +double degreeCos(double x){ + return cos(x * degreeToRadians); +} + +Vector getDirectionalUnitVector(double rotation){ + return (Vector) + { + .x = degreeSin(rotation), + .y = -degreeCos(rotation) + }; +} + +Vector getScaledDirectionalUnitVector(double rotation, double Magnitude){ + Vector v = (Vector) + { + .x = degreeSin(rotation), + .y = -degreeCos(rotation) + }; + + return vectorScale(v, Magnitude); +} + +Vector getScaledVectorFromTo(Vector from, Vector to, double Magnitude){ + return vectorScale(vectorSub(to, from), Magnitude); +} diff --git a/vector.h b/vector.h new file mode 100644 index 0000000..2bbaf4d --- /dev/null +++ b/vector.h @@ -0,0 +1,26 @@ +#ifndef __vector_h__ +#define __vector_h__ + +// Structs +typedef struct vectorStruct { + double x, y; +} Vector; +// End Structs + +// Prototypes +Vector vectorScale(Vector v, double factor); +double vectorMagnitude(Vector v); +double vectorRotation(Vector v); +Vector vectorScaleTo(Vector v, double magnitude); +double dotProduct(Vector v1, Vector v2); +double vectorDist(Vector v1, Vector v2); +Vector vectorAdd(Vector v1, Vector v2); +Vector vectorSub(Vector v1, Vector v2); +double degreeSin(double x); +double degreeCos(double x); +Vector getDirectionalUnitVector(double rotation); +Vector getScaledDirectionalUnitVector(double rotation, double Magnitude); +Vector getScaledVectorFromTo(Vector from, Vector to, double Magnitude); +// End Prototypes + +#endif // __vector_h__