Initial commit
BIN
assets/fonts/bulky.ttf
Normal file
BIN
assets/fonts/millenium.ttf
Normal file
BIN
assets/images/asteroid.png
Normal file
After Width: | Height: | Size: 390 KiB |
BIN
assets/images/asteroidDebug.png
Normal file
After Width: | Height: | Size: 452 KiB |
BIN
assets/images/bullet.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
assets/images/enemy.png
Normal file
After Width: | Height: | Size: 71 KiB |
BIN
assets/images/enemyBullet.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
assets/images/ship.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
assets/images/shipAcc.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
assets/images/shipExpl.png
Normal file
After Width: | Height: | Size: 318 KiB |
BIN
assets/images/shipExpl1.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
assets/images/star.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
assets/sounds/explosion.wav
Normal file
BIN
assets/sounds/laser.wav
Normal file
BIN
assets/sounds/rocket.wav
Normal file
521
asteroids.c
Normal file
@ -0,0 +1,521 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_image.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
|
||||
#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
|
||||
}
|
||||
}
|
81
asteroids.h
Normal file
@ -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__
|
BIN
bin/Debug/Asteroids.exe
Normal file
BIN
bin/Debug/SDL_Test.exe
Normal file
BIN
bin/Release/Asteroids.exe
Normal file
BIN
bin/Release/SDL_Test.exe
Normal file
175
main.c
Normal file
@ -0,0 +1,175 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_image.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
116
starfield.c
Normal file
@ -0,0 +1,116 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_image.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
31
starfield.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef __starfield_h__
|
||||
#define __starfield_h__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// 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__
|
83
vector.c
Normal file
@ -0,0 +1,83 @@
|
||||
#include <math.h>
|
||||
|
||||
#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);
|
||||
}
|
26
vector.h
Normal file
@ -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__
|