2019-09-10 11:14:36 +03:00
|
|
|
|
/*
|
|
|
|
|
Author: Asrın "Syntriax" Doğan
|
|
|
|
|
Date: 10.09.2019
|
|
|
|
|
Mail: asrindogan99@gmail.com
|
2019-09-13 17:55:44 +03:00
|
|
|
|
|
|
|
|
|
Simple Shoot 'Em Up game.
|
|
|
|
|
|
|
|
|
|
Keys:
|
|
|
|
|
Move Up - Up Arrow
|
|
|
|
|
Move Right - Right Arrow
|
|
|
|
|
Move Down - Down Arrow
|
|
|
|
|
Move Left - Left Arrow
|
|
|
|
|
Shoot - Space
|
|
|
|
|
Restart - R
|
|
|
|
|
Exit - Escape(ESC)
|
2019-09-10 11:14:36 +03:00
|
|
|
|
*/
|
2019-09-13 17:55:44 +03:00
|
|
|
|
|
2019-09-10 11:14:36 +03:00
|
|
|
|
#include <stdio.h>
|
2019-09-10 12:45:06 +03:00
|
|
|
|
#include <stdlib.h>
|
2019-09-10 11:14:36 +03:00
|
|
|
|
#include <math.h>
|
2019-09-10 12:50:01 +03:00
|
|
|
|
#include "allegro\include\allegro5\allegro.h"
|
|
|
|
|
#include "allegro\include\allegro5\allegro_audio.h"
|
|
|
|
|
#include "allegro\include\allegro5\allegro_acodec.h"
|
|
|
|
|
#include "allegro\include\allegro5\allegro_image.h"
|
|
|
|
|
#include "allegro\include\allegro5\allegro_primitives.h"
|
2019-09-13 17:55:44 +03:00
|
|
|
|
#define playerSpeed 0.75
|
|
|
|
|
#define enemySpeed 0.1
|
2019-09-10 11:52:00 +03:00
|
|
|
|
#define initialPlayerHealth 4
|
2019-09-13 17:55:44 +03:00
|
|
|
|
#define bulletSpeed 2.5
|
2019-09-10 11:52:00 +03:00
|
|
|
|
#define numberImageSize 5
|
2019-09-10 22:22:22 +03:00
|
|
|
|
#define scoreDigitLimit 11
|
2019-09-13 17:55:44 +03:00
|
|
|
|
#define timerDigitLimit 4
|
2019-09-10 11:14:36 +03:00
|
|
|
|
#define initialEnemyLimit 3
|
2019-09-10 22:22:22 +03:00
|
|
|
|
#define sampleCount 3
|
2019-09-13 17:55:44 +03:00
|
|
|
|
#define colon 10
|
|
|
|
|
#define numbersLength 11
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
float x;
|
|
|
|
|
float y;
|
|
|
|
|
} Vector2D;
|
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
Vector2D position;
|
|
|
|
|
/* char health; */
|
|
|
|
|
float moveSpeed;
|
|
|
|
|
float fireCooldown;
|
|
|
|
|
Vector2D velocity;
|
|
|
|
|
} Enemy;
|
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
char isEnemyBullet;
|
|
|
|
|
Vector2D position;
|
|
|
|
|
Vector2D velocity;
|
|
|
|
|
} Bullet;
|
|
|
|
|
|
2019-09-10 22:22:22 +03:00
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
int enemyLimit;
|
|
|
|
|
int enemyCount;
|
|
|
|
|
Enemy *enemyArray;
|
|
|
|
|
} enemies;
|
|
|
|
|
|
2019-09-10 11:14:36 +03:00
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
int bulletCount;
|
|
|
|
|
Bullet *bulletArray;
|
|
|
|
|
} bullets;
|
|
|
|
|
|
2019-09-10 22:22:22 +03:00
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
Vector2D position;
|
|
|
|
|
char health;
|
|
|
|
|
float moveSpeed;
|
|
|
|
|
byte lookDirection;
|
|
|
|
|
int shootPerSecond;
|
|
|
|
|
float shootCooldown;
|
|
|
|
|
unsigned int killedEnemyCount;
|
|
|
|
|
unsigned int score;
|
|
|
|
|
|
|
|
|
|
ALLEGRO_BITMAP *playerImage;
|
|
|
|
|
} player;
|
|
|
|
|
|
2019-09-10 11:14:36 +03:00
|
|
|
|
void SpawnEnemies();
|
|
|
|
|
void CheckBullets();
|
|
|
|
|
void RemoveBulletAtIndex(int index);
|
|
|
|
|
void RemoveEnemyAtIndex(int index);
|
|
|
|
|
void CheckEnemies();
|
|
|
|
|
void MoveEnemies();
|
|
|
|
|
void InitializeEnemies();
|
|
|
|
|
void DestroyGame();
|
|
|
|
|
void DrawObject(Vector2D position, ALLEGRO_BITMAP *image, int flag);
|
2019-09-13 17:55:44 +03:00
|
|
|
|
void DrawSizedObject(Vector2D position, ALLEGRO_BITMAP *image, int flag, float objectscreenSizeMultiplier);
|
2019-09-10 11:14:36 +03:00
|
|
|
|
void DrawScreen();
|
|
|
|
|
void DrawScore();
|
2019-09-10 12:45:06 +03:00
|
|
|
|
void DrawHighScore();
|
2019-09-13 17:55:44 +03:00
|
|
|
|
void DrawTimer();
|
2019-09-10 12:45:06 +03:00
|
|
|
|
void CheckHighScore();
|
|
|
|
|
void GetHighScore();
|
2019-09-13 17:55:44 +03:00
|
|
|
|
void GetSettings();
|
2019-09-10 11:14:36 +03:00
|
|
|
|
void DrawNumber(Vector2D position, int number);
|
|
|
|
|
void Inputs();
|
|
|
|
|
void PlayerMovement();
|
2019-09-13 17:55:44 +03:00
|
|
|
|
void ClampPlayerPositionToScreenDimensions();
|
2019-09-10 11:14:36 +03:00
|
|
|
|
void BulletMovement();
|
|
|
|
|
void ShootSoundEffect();
|
|
|
|
|
void DieSoundEffect();
|
|
|
|
|
void PlayerShoot();
|
|
|
|
|
void EnemyShoot();
|
|
|
|
|
void BulletCollisions();
|
|
|
|
|
void Update();
|
|
|
|
|
void DestroyGameWindow();
|
|
|
|
|
float VectorMagnitude(Vector2D vector);
|
2019-09-13 17:55:44 +03:00
|
|
|
|
float VectorDistanceBetween(Vector2D vectorFirst, Vector2D vectorSecond);
|
2019-09-10 11:14:36 +03:00
|
|
|
|
byte isVectorExceedingLimits(Vector2D vector, Vector2D limits);
|
|
|
|
|
byte CheckCollision(Vector2D *firstPos, Vector2D *secondPos, ALLEGRO_BITMAP *firstMap, ALLEGRO_BITMAP *secondMap);
|
|
|
|
|
char InitializeGameWindow();
|
|
|
|
|
char InitializeGame();
|
2019-09-10 11:52:00 +03:00
|
|
|
|
char DealDamage(char *health);
|
2019-09-10 11:14:36 +03:00
|
|
|
|
Vector2D NormalizeVector(Vector2D vector);
|
|
|
|
|
|
|
|
|
|
ALLEGRO_KEYBOARD_STATE keyboardState;
|
|
|
|
|
ALLEGRO_DISPLAY_MODE disp_data;
|
|
|
|
|
ALLEGRO_COLOR backgroundColor;
|
2019-09-13 17:55:44 +03:00
|
|
|
|
ALLEGRO_DISPLAY *display = NULL;
|
|
|
|
|
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
|
|
|
|
|
ALLEGRO_TIMER *timer = NULL;
|
|
|
|
|
ALLEGRO_BITMAP *gameOverImage = NULL;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
ALLEGRO_SAMPLE *BGM = NULL;
|
2019-09-10 22:22:22 +03:00
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
ALLEGRO_SAMPLE *shootSound = NULL;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
ALLEGRO_SAMPLE_ID shootSoundID;
|
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
ALLEGRO_BITMAP *enemyImage = NULL;
|
|
|
|
|
ALLEGRO_BITMAP *enemyBulletImage = NULL;
|
|
|
|
|
ALLEGRO_SAMPLE *enemyDieSound = NULL;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
ALLEGRO_SAMPLE_ID enemyDieSoundID;
|
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
ALLEGRO_BITMAP *numberTable = NULL;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
|
|
|
|
const char *displayName = "Syn Game";
|
2019-09-10 12:45:06 +03:00
|
|
|
|
const char *savePath = "Save.syn";
|
2019-09-13 17:55:44 +03:00
|
|
|
|
const char *settingsPath = "Settings.syn";
|
|
|
|
|
const char *settingsFormat = "%d\n%d\n%d";
|
|
|
|
|
int isFullscreen = 1;
|
|
|
|
|
int settingsWidth = 1600;
|
|
|
|
|
int settingsHeight = 900;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
const Vector2D referenceScreenDimensions = {160, 90};
|
2019-09-13 17:55:44 +03:00
|
|
|
|
Vector2D screenDimensions = {0, 0};
|
|
|
|
|
Vector2D scorePosition = {0, 0};
|
|
|
|
|
Vector2D highScorePosition = {0, 0};
|
|
|
|
|
Vector2D timerPosition = {0, 0};
|
|
|
|
|
float screenSizeMultiplier;
|
|
|
|
|
float timeSinceStart;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
const float FPS = 60;
|
|
|
|
|
double deltaTime;
|
|
|
|
|
unsigned int enemyRespawnCounter = 0;
|
2019-09-10 12:45:06 +03:00
|
|
|
|
unsigned int highScore = 0;
|
2019-09-13 18:03:21 +03:00
|
|
|
|
int enemyLimiter = 12;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
Vector2D input;
|
2019-09-13 17:55:44 +03:00
|
|
|
|
byte isRestart = 0;
|
|
|
|
|
byte isRunning = 1;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
byte isGameOver = 0;
|
|
|
|
|
|
|
|
|
|
void Update()
|
|
|
|
|
{
|
|
|
|
|
al_get_keyboard_state(&keyboardState);
|
|
|
|
|
|
|
|
|
|
if(al_key_down(&keyboardState, ALLEGRO_KEY_ESCAPE))
|
|
|
|
|
isRunning = 0;
|
|
|
|
|
|
|
|
|
|
al_clear_to_color(backgroundColor);
|
|
|
|
|
|
|
|
|
|
if(!isGameOver)
|
|
|
|
|
{
|
|
|
|
|
printf("Inputs();\n");
|
|
|
|
|
Inputs();
|
|
|
|
|
|
|
|
|
|
printf("PlayerMovement();\n");
|
|
|
|
|
PlayerMovement();
|
|
|
|
|
|
|
|
|
|
printf("EnemyShoot();\n");
|
|
|
|
|
EnemyShoot();
|
|
|
|
|
|
|
|
|
|
printf("BulletCollisions();\n");
|
|
|
|
|
BulletCollisions();
|
|
|
|
|
|
|
|
|
|
if(player.shootCooldown < 0.0f)
|
|
|
|
|
{
|
|
|
|
|
if(al_key_down(&keyboardState, ALLEGRO_KEY_SPACE))
|
|
|
|
|
{
|
|
|
|
|
printf("PlayerShoot();\n");
|
|
|
|
|
PlayerShoot();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
player.shootCooldown -= deltaTime;
|
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
timeSinceStart += deltaTime;
|
|
|
|
|
player.score = (int)(timeSinceStart * timeSinceStart) * (player.killedEnemyCount + 1);
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
2019-09-13 20:12:30 +03:00
|
|
|
|
/* To limit the enemies on the screen */
|
2019-09-10 11:14:36 +03:00
|
|
|
|
if(enemies.enemyLimit != enemyLimiter)
|
|
|
|
|
{
|
2019-09-13 17:55:44 +03:00
|
|
|
|
enemies.enemyLimit = initialEnemyLimit + (int)(timeSinceStart / 10);
|
2019-09-10 22:22:22 +03:00
|
|
|
|
|
2019-09-10 11:14:36 +03:00
|
|
|
|
if(enemies.enemyCount > enemyLimiter)
|
|
|
|
|
enemies.enemyLimit = enemyLimiter;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(al_key_down(&keyboardState, ALLEGRO_KEY_R))
|
|
|
|
|
isRestart = 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
printf("CheckEnemies();\n");
|
|
|
|
|
CheckEnemies();
|
|
|
|
|
|
|
|
|
|
printf("MoveEnemies();\n");
|
|
|
|
|
MoveEnemies();
|
|
|
|
|
|
|
|
|
|
printf("CheckBullets();\n");
|
|
|
|
|
CheckBullets();
|
|
|
|
|
|
|
|
|
|
printf("BulletMovement();\n");
|
|
|
|
|
BulletMovement();
|
|
|
|
|
|
|
|
|
|
printf("DrawScreen();\n");
|
|
|
|
|
DrawScreen();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
al_flip_display();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
if(InitializeGameWindow() == 0)
|
2019-09-13 17:55:44 +03:00
|
|
|
|
{
|
|
|
|
|
DestroyGameWindow();
|
|
|
|
|
getchar();
|
2019-09-10 11:14:36 +03:00
|
|
|
|
return 0;
|
2019-09-13 17:55:44 +03:00
|
|
|
|
}
|
2019-09-10 22:22:22 +03:00
|
|
|
|
|
2019-09-10 11:14:36 +03:00
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if(InitializeGame() == 0)
|
2019-09-13 17:55:44 +03:00
|
|
|
|
{
|
|
|
|
|
DestroyGame();
|
|
|
|
|
getchar();
|
2019-09-10 11:14:36 +03:00
|
|
|
|
return 0;
|
2019-09-13 17:55:44 +03:00
|
|
|
|
}
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
|
|
|
|
while (isRunning && !isRestart)
|
|
|
|
|
{
|
|
|
|
|
ALLEGRO_EVENT ev;
|
|
|
|
|
al_wait_for_event(event_queue, &ev);
|
|
|
|
|
|
|
|
|
|
if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
|
|
|
|
|
isRunning = 0;
|
|
|
|
|
|
|
|
|
|
if(ev.type == ALLEGRO_EVENT_TIMER)
|
|
|
|
|
Update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DestroyGame();
|
|
|
|
|
} while (isRestart);
|
|
|
|
|
|
|
|
|
|
DestroyGameWindow();
|
|
|
|
|
|
|
|
|
|
getchar();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vector2D NormalizeVector(Vector2D vector)
|
|
|
|
|
{
|
|
|
|
|
Vector2D normalizedVector;
|
|
|
|
|
float magnitude = sqrt(vector.x * vector.x + vector.y * vector.y);
|
|
|
|
|
|
|
|
|
|
if(vector.x == 0.0 && vector.y == 0.0)
|
|
|
|
|
return vector;
|
|
|
|
|
|
|
|
|
|
normalizedVector.x = vector.x / magnitude;
|
|
|
|
|
normalizedVector.y = vector.y / magnitude;
|
|
|
|
|
|
|
|
|
|
return normalizedVector;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float VectorMagnitude(Vector2D vector)
|
|
|
|
|
{
|
|
|
|
|
return sqrt(vector.x * vector.x + vector.y * vector.y);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
float VectorDistanceBetween(Vector2D vectorFirst, Vector2D vectorSecond)
|
2019-09-10 11:14:36 +03:00
|
|
|
|
{
|
|
|
|
|
Vector2D difference;
|
|
|
|
|
difference.x = abs(vectorFirst.x - vectorSecond.x);
|
|
|
|
|
difference.y = abs(vectorFirst.y - vectorSecond.y);
|
|
|
|
|
return VectorMagnitude(difference);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
byte isVectorExceedingLimits(Vector2D vector, Vector2D limits)
|
|
|
|
|
{
|
|
|
|
|
byte result = vector.x > limits.x || vector.x < 0 || vector.y > limits.y || vector.y < 0;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-10 22:22:22 +03:00
|
|
|
|
/*
|
|
|
|
|
Gets the shortest dimensions of both images, sums these dimension and divides by 2 to get minimum accepted distance.
|
|
|
|
|
And compares the distance between those objects to the minimum distancce to check if they're colliding.
|
|
|
|
|
It's the most optimized way I can think of for a game like this.
|
|
|
|
|
*/
|
2019-09-10 11:14:36 +03:00
|
|
|
|
byte CheckCollision(Vector2D *firstPos, Vector2D *secondPos, ALLEGRO_BITMAP *firstMap, ALLEGRO_BITMAP *secondMap)
|
|
|
|
|
{
|
|
|
|
|
Vector2D firstImageSize;
|
|
|
|
|
Vector2D secondImageSize;
|
|
|
|
|
byte result;
|
|
|
|
|
float minDistance;
|
|
|
|
|
float distance;
|
|
|
|
|
firstImageSize.x = (float)al_get_bitmap_width(firstMap);
|
|
|
|
|
firstImageSize.y = (float)al_get_bitmap_height(firstMap);
|
|
|
|
|
secondImageSize.x = (float)al_get_bitmap_width(secondMap);
|
|
|
|
|
secondImageSize.y = (float)al_get_bitmap_height(secondMap);
|
|
|
|
|
|
|
|
|
|
minDistance = firstImageSize.x > firstImageSize.y ? firstImageSize.y : firstImageSize.x;
|
|
|
|
|
minDistance += secondImageSize.x > secondImageSize.y ? secondImageSize.y : secondImageSize.x;
|
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
minDistance *= screenSizeMultiplier * 0.5f;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
distance = VectorDistanceBetween(*firstPos, *secondPos);
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
|
|
|
|
result = distance <= minDistance;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char InitializeGameWindow()
|
|
|
|
|
{
|
|
|
|
|
float x = 0.0f;
|
|
|
|
|
float y = 0.0f;
|
|
|
|
|
|
|
|
|
|
if(!al_init() ||
|
|
|
|
|
!al_init_primitives_addon() ||
|
|
|
|
|
!al_init_image_addon() ||
|
|
|
|
|
!al_install_audio() ||
|
|
|
|
|
!al_init_acodec_addon() ||
|
2019-09-10 22:22:22 +03:00
|
|
|
|
!al_reserve_samples(sampleCount))
|
2019-09-10 11:14:36 +03:00
|
|
|
|
return 0;
|
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
GetSettings();
|
|
|
|
|
|
|
|
|
|
if(isFullscreen == 1)
|
|
|
|
|
{
|
|
|
|
|
al_get_display_mode(al_get_num_display_modes() - 1, &disp_data);
|
|
|
|
|
al_set_new_display_flags(ALLEGRO_FULLSCREEN);
|
|
|
|
|
|
|
|
|
|
x = disp_data.width;
|
|
|
|
|
y = disp_data.height;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
x = settingsWidth;
|
|
|
|
|
y = settingsHeight;
|
|
|
|
|
}
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
screenDimensions = (Vector2D){x, y};
|
|
|
|
|
scorePosition = (Vector2D){x * (float)0.05, y * (float)0.05};
|
|
|
|
|
highScorePosition = (Vector2D){x * (float)0.95, y * (float)0.05};
|
|
|
|
|
timerPosition = (Vector2D){x * (float)0.5 , y * (float)0.95};
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
screenSizeMultiplier = screenDimensions.x / referenceScreenDimensions.x;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
display = al_create_display(screenDimensions.x, screenDimensions.y);
|
|
|
|
|
|
|
|
|
|
if(display == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if(!al_install_keyboard())
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
deltaTime = 1.0 / FPS;
|
|
|
|
|
timer = al_create_timer(deltaTime);
|
|
|
|
|
event_queue = al_create_event_queue();
|
|
|
|
|
|
|
|
|
|
if(event_queue == NULL)
|
|
|
|
|
{
|
|
|
|
|
printf("Event Queue Error");
|
|
|
|
|
al_destroy_display(display);
|
|
|
|
|
al_destroy_timer(timer);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
al_register_event_source(event_queue, al_get_keyboard_event_source());
|
|
|
|
|
al_register_event_source(event_queue, al_get_display_event_source(display));
|
|
|
|
|
al_register_event_source(event_queue, al_get_timer_event_source(timer));
|
|
|
|
|
|
|
|
|
|
al_start_timer(timer);
|
|
|
|
|
al_set_window_title(display, displayName);
|
|
|
|
|
|
|
|
|
|
backgroundColor.a = 1;
|
|
|
|
|
backgroundColor.a = 0;
|
|
|
|
|
backgroundColor.a = 0;
|
|
|
|
|
backgroundColor.a = 0;
|
2019-09-10 22:22:22 +03:00
|
|
|
|
|
|
|
|
|
/* BGM is an exception since I don't want to it to restart itself every restart */
|
|
|
|
|
BGM = al_load_sample("Sounds/Background.wav");
|
|
|
|
|
al_play_sample(BGM, 1.0, 0.0, 1.0, ALLEGRO_PLAYMODE_LOOP, NULL);
|
2019-09-10 11:14:36 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char InitializeGame()
|
|
|
|
|
{
|
2019-09-13 17:55:44 +03:00
|
|
|
|
shootSound = al_load_sample("Sounds/Shoot.wav");
|
|
|
|
|
enemyDieSound = al_load_sample("Sounds/Die.wav");
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
|
|
|
|
InitializeEnemies();
|
2019-09-10 12:45:06 +03:00
|
|
|
|
GetHighScore();
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
|
|
|
|
/* Player Initialization */
|
|
|
|
|
player.position.x = screenDimensions.x / 2;
|
|
|
|
|
player.position.y = screenDimensions.y / 2;
|
2019-09-13 17:55:44 +03:00
|
|
|
|
player.moveSpeed = playerSpeed * screenSizeMultiplier;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
player.shootPerSecond = 10;
|
2019-09-10 11:52:00 +03:00
|
|
|
|
player.health = initialPlayerHealth;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
player.playerImage = al_load_bitmap("Images/Player.png");
|
2019-09-13 17:55:44 +03:00
|
|
|
|
|
2019-09-10 11:14:36 +03:00
|
|
|
|
if(player.playerImage == NULL ||
|
|
|
|
|
shootSound == NULL ||
|
|
|
|
|
enemyDieSound == NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
|
|
|
|
|
bullets.bulletCount = 0;
|
|
|
|
|
bullets.bulletArray = (Bullet *) malloc(sizeof(Bullet) * bullets.bulletCount);
|
|
|
|
|
|
2019-09-10 22:22:22 +03:00
|
|
|
|
/* Game Initialization */
|
2019-09-10 11:14:36 +03:00
|
|
|
|
isRunning = 1;
|
|
|
|
|
isRestart = 0;
|
|
|
|
|
isGameOver = 0;
|
2019-09-13 17:55:44 +03:00
|
|
|
|
timeSinceStart = 0;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
player.killedEnemyCount = 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void InitializeEnemies()
|
|
|
|
|
{
|
|
|
|
|
enemies.enemyLimit = initialEnemyLimit;
|
|
|
|
|
enemies.enemyCount = 0;
|
|
|
|
|
enemies.enemyArray = (Enemy *) malloc(sizeof(Enemy) * enemies.enemyCount);
|
|
|
|
|
enemyImage = al_load_bitmap("Images/Enemy.png");
|
|
|
|
|
numberTable = al_load_bitmap("Images/Numbers.png");
|
|
|
|
|
enemyBulletImage = al_load_bitmap("Images/Bullet.png");
|
|
|
|
|
gameOverImage = al_load_bitmap("Images/GameOver.png");
|
|
|
|
|
SpawnEnemies();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SpawnEnemies()
|
|
|
|
|
{
|
|
|
|
|
Vector2D enemySpawnVector;
|
2019-09-10 22:22:22 +03:00
|
|
|
|
Vector2D enemyVelocity;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
Enemy *enemy;
|
|
|
|
|
float speed;
|
|
|
|
|
int randomNumber;
|
2019-09-10 22:22:22 +03:00
|
|
|
|
|
|
|
|
|
if(enemyRespawnCounter > 10000)
|
|
|
|
|
enemyRespawnCounter = 0;
|
|
|
|
|
|
2019-09-10 11:14:36 +03:00
|
|
|
|
while (enemies.enemyCount < enemies.enemyLimit)
|
|
|
|
|
{
|
2019-09-10 22:22:22 +03:00
|
|
|
|
/* enemyRespawnCounter is just for making the value of rand() more randomized */
|
2019-09-10 11:14:36 +03:00
|
|
|
|
srand(time(0) + enemyRespawnCounter);
|
|
|
|
|
randomNumber = rand() * enemies.enemyCount;
|
2019-09-10 22:22:22 +03:00
|
|
|
|
enemies.enemyCount++;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
enemies.enemyArray = (Enemy *) realloc(enemies.enemyArray, sizeof(Enemy) * enemies.enemyCount);
|
2019-09-10 22:22:22 +03:00
|
|
|
|
|
|
|
|
|
/* Randomizing the velocity */
|
|
|
|
|
enemyVelocity.x = (float)(randomNumber % 20000) / 10000;
|
|
|
|
|
enemyVelocity.y = (float)(randomNumber % 2000) / 1000;
|
|
|
|
|
enemyVelocity.x *= randomNumber % 2 == 0 ? -1 : 1;
|
|
|
|
|
enemyVelocity.y *= randomNumber % 4 >= 2 ? -1 : 1;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
speed = (float)(randomNumber % 500 / 100 + 2) * enemySpeed;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
enemy = (enemies.enemyArray + enemies.enemyCount - 1);
|
2019-09-10 22:22:22 +03:00
|
|
|
|
enemy -> velocity = NormalizeVector(enemyVelocity);
|
2019-09-13 17:55:44 +03:00
|
|
|
|
enemy -> moveSpeed = speed * screenSizeMultiplier;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
2019-09-10 22:22:22 +03:00
|
|
|
|
enemySpawnVector.x = enemyVelocity.x > 0 ? 0 : screenDimensions.x;
|
|
|
|
|
enemySpawnVector.y = enemyVelocity.y > 0 ? 0 : screenDimensions.y;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
|
|
|
|
enemy -> position = enemySpawnVector;
|
|
|
|
|
enemy -> fireCooldown = 01.0 / (rand() % 5) + 2.0;
|
|
|
|
|
|
|
|
|
|
enemyRespawnCounter++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CheckBullets()
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
int j = 0;
|
|
|
|
|
|
|
|
|
|
for (; i < bullets.bulletCount; i++)
|
|
|
|
|
{
|
|
|
|
|
if(isVectorExceedingLimits((bullets.bulletArray + i) -> position, screenDimensions))
|
|
|
|
|
{
|
|
|
|
|
for (j = i; j < bullets.bulletCount - 1; j++)
|
|
|
|
|
*(bullets.bulletArray + j) = *(bullets.bulletArray + j + 1);
|
|
|
|
|
|
|
|
|
|
bullets.bulletCount--;
|
|
|
|
|
bullets.bulletArray = (Bullet *) realloc(bullets.bulletArray, sizeof(Bullet) * bullets.bulletCount);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RemoveBulletAtIndex(int index)
|
|
|
|
|
{
|
|
|
|
|
printf("RemoveBulletAtIndex();\n");
|
|
|
|
|
for (; index < bullets.bulletCount - 1; index++)
|
|
|
|
|
*(bullets.bulletArray + index) = *(bullets.bulletArray + index + 1);
|
|
|
|
|
|
|
|
|
|
bullets.bulletCount--;
|
|
|
|
|
bullets.bulletArray = (Bullet *) realloc(bullets.bulletArray, sizeof(Bullet) * bullets.bulletCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RemoveEnemyAtIndex(int index)
|
|
|
|
|
{
|
|
|
|
|
printf("RemoveEnemyAtIndex();\n");
|
|
|
|
|
for (; index < enemies.enemyCount - 1; index++)
|
|
|
|
|
*(enemies.enemyArray + index) = *(enemies.enemyArray + index + 1);
|
|
|
|
|
|
|
|
|
|
enemies.enemyCount--;
|
|
|
|
|
enemies.enemyArray = (Enemy *) realloc(enemies.enemyArray, sizeof(Enemy) * enemies.enemyCount);
|
2019-09-10 22:22:22 +03:00
|
|
|
|
|
2019-09-10 11:14:36 +03:00
|
|
|
|
DieSoundEffect();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CheckEnemies()
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
for (; i < enemies.enemyCount; i++)
|
|
|
|
|
if(isVectorExceedingLimits((enemies.enemyArray + i) -> position, screenDimensions))
|
|
|
|
|
RemoveEnemyAtIndex(i);
|
|
|
|
|
|
|
|
|
|
SpawnEnemies();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MoveEnemies()
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
Vector2D velocity;
|
|
|
|
|
float speed;
|
|
|
|
|
|
|
|
|
|
for (; i < enemies.enemyCount; i++)
|
|
|
|
|
{
|
|
|
|
|
speed = (enemies.enemyArray + i) -> moveSpeed;
|
|
|
|
|
velocity = (enemies.enemyArray + i) -> velocity;
|
|
|
|
|
(enemies.enemyArray + i) -> position.x += velocity.x * speed;
|
|
|
|
|
(enemies.enemyArray + i) -> position.y += velocity.y * speed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void DrawObject(Vector2D position, ALLEGRO_BITMAP *image, int flag)
|
|
|
|
|
{
|
|
|
|
|
Vector2D InstantiateSize;
|
|
|
|
|
InstantiateSize.x = (float)al_get_bitmap_width(image);
|
|
|
|
|
InstantiateSize.y = (float)al_get_bitmap_height(image);
|
|
|
|
|
|
|
|
|
|
al_draw_scaled_bitmap(image,
|
|
|
|
|
0, 0, InstantiateSize.x, InstantiateSize.y,
|
2019-09-13 17:55:44 +03:00
|
|
|
|
position.x - InstantiateSize.x / 2 * screenSizeMultiplier, position.y - InstantiateSize.y / 2 * screenSizeMultiplier,
|
|
|
|
|
InstantiateSize.x * screenSizeMultiplier, InstantiateSize.y * screenSizeMultiplier, flag);
|
2019-09-10 11:14:36 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawNumber(Vector2D position, int number)
|
|
|
|
|
{
|
|
|
|
|
Vector2D InstantiateSize;
|
|
|
|
|
InstantiateSize.x = (float)al_get_bitmap_width(numberTable);
|
|
|
|
|
InstantiateSize.y = (float)al_get_bitmap_height(numberTable);
|
|
|
|
|
|
|
|
|
|
al_draw_scaled_bitmap(numberTable,
|
2019-09-13 20:12:30 +03:00
|
|
|
|
numberImageSize * number, 0, numberImageSize, InstantiateSize.y,
|
|
|
|
|
position.x - numberImageSize / 2 * screenSizeMultiplier, position.y - InstantiateSize.y / 2 * screenSizeMultiplier,
|
|
|
|
|
numberImageSize * screenSizeMultiplier, InstantiateSize.y * screenSizeMultiplier, 0);
|
2019-09-10 11:14:36 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
void DrawSizedObject(Vector2D position, ALLEGRO_BITMAP *image, int flag, float objectscreenSizeMultiplier)
|
2019-09-10 11:14:36 +03:00
|
|
|
|
{
|
|
|
|
|
Vector2D InstantiateSize;
|
2019-09-13 17:55:44 +03:00
|
|
|
|
float sizeFactor = screenSizeMultiplier * objectscreenSizeMultiplier;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
InstantiateSize.x = (float)al_get_bitmap_width(image);
|
|
|
|
|
InstantiateSize.y = (float)al_get_bitmap_height(image);
|
|
|
|
|
|
|
|
|
|
al_draw_scaled_bitmap(image,
|
|
|
|
|
0, 0, InstantiateSize.x, InstantiateSize.y,
|
|
|
|
|
position.x - InstantiateSize.x / 2 * sizeFactor, position.y - InstantiateSize.y / 2 * sizeFactor,
|
|
|
|
|
InstantiateSize.x * sizeFactor, InstantiateSize.y * sizeFactor, flag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawScreen()
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
Vector2D halfScreen = {screenDimensions.x / 2, screenDimensions.y / 2};
|
|
|
|
|
|
|
|
|
|
/* Enemy Draw */
|
|
|
|
|
for (i = 0; i < enemies.enemyCount; i++)
|
|
|
|
|
DrawObject((enemies.enemyArray + i) -> position, enemyImage, (enemies.enemyArray + i) -> velocity.x > 0 ? ALLEGRO_FLIP_HORIZONTAL : 0 );
|
|
|
|
|
|
|
|
|
|
/* Bullet Draw */
|
|
|
|
|
for (i = 0; i < bullets.bulletCount; i++)
|
|
|
|
|
DrawObject((bullets.bulletArray + i) -> position, enemyBulletImage, 0);
|
|
|
|
|
|
|
|
|
|
/* Player Draw */
|
|
|
|
|
if(!isGameOver)
|
|
|
|
|
DrawObject(player.position, player.playerImage, player.lookDirection == 1 ? ALLEGRO_FLIP_HORIZONTAL : 0);
|
|
|
|
|
else
|
|
|
|
|
DrawObject(halfScreen, gameOverImage, 0);
|
|
|
|
|
|
|
|
|
|
DrawScore();
|
2019-09-10 12:45:06 +03:00
|
|
|
|
DrawHighScore();
|
2019-09-13 17:55:44 +03:00
|
|
|
|
DrawTimer();
|
2019-09-10 11:14:36 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawScore()
|
|
|
|
|
{
|
|
|
|
|
unsigned int processedScore = player.score;
|
|
|
|
|
char digit;
|
|
|
|
|
Vector2D spawnPosition;
|
2019-09-10 22:22:22 +03:00
|
|
|
|
int i = scoreDigitLimit - 1;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
2019-09-10 22:22:22 +03:00
|
|
|
|
/* while (processedScore >= 1 && i > 0) */
|
|
|
|
|
while (i >= 0)
|
2019-09-10 11:14:36 +03:00
|
|
|
|
{
|
|
|
|
|
spawnPosition = scorePosition;
|
2019-09-10 11:52:00 +03:00
|
|
|
|
/* numberImageSize + 1 is because 1 pixel space between digits */
|
2019-09-13 17:55:44 +03:00
|
|
|
|
spawnPosition.x += screenSizeMultiplier * (numberImageSize + 1) * i;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
digit = processedScore % 10;
|
|
|
|
|
processedScore = (int)(processedScore / 10);
|
|
|
|
|
DrawNumber(spawnPosition, digit);
|
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-10 12:45:06 +03:00
|
|
|
|
void DrawHighScore()
|
|
|
|
|
{
|
|
|
|
|
unsigned int processedScore = highScore;
|
|
|
|
|
char digit;
|
|
|
|
|
Vector2D spawnPosition;
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
2019-09-10 22:22:22 +03:00
|
|
|
|
/* while (processedScore >= 1 && i > 0) */
|
2019-09-10 12:45:06 +03:00
|
|
|
|
while (i < scoreDigitLimit)
|
|
|
|
|
{
|
|
|
|
|
spawnPosition = highScorePosition;
|
|
|
|
|
/* numberImageSize + 1 is because 1 pixel space between digits */
|
2019-09-13 17:55:44 +03:00
|
|
|
|
spawnPosition.x -= screenSizeMultiplier * (numberImageSize + 1) * i;
|
2019-09-10 12:45:06 +03:00
|
|
|
|
digit = processedScore % 10;
|
|
|
|
|
processedScore = (int)(processedScore / 10);
|
|
|
|
|
DrawNumber(spawnPosition, digit);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
void DrawTimer()
|
|
|
|
|
{
|
|
|
|
|
int seconds = (int)timeSinceStart % 60;
|
|
|
|
|
int minutes = (timeSinceStart - seconds) / 60;
|
|
|
|
|
char digit;
|
|
|
|
|
Vector2D spawnPosition;
|
|
|
|
|
int i = -timerDigitLimit / 2;
|
|
|
|
|
|
|
|
|
|
/* while (processedScore >= 1 && i > 0) */
|
|
|
|
|
while (i < 0)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
spawnPosition = timerPosition;
|
|
|
|
|
/* numberImageSize + 1 is because 1 pixel space between digits */
|
|
|
|
|
spawnPosition.x -= screenSizeMultiplier * (numberImageSize + 1) * i;
|
|
|
|
|
|
|
|
|
|
digit = seconds % 10;
|
|
|
|
|
seconds = (int)(seconds / 10);
|
|
|
|
|
DrawNumber(spawnPosition, digit);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
spawnPosition = timerPosition;
|
|
|
|
|
/* numberImageSize + 1 is because 1 pixel space between digits */
|
|
|
|
|
spawnPosition.x -= screenSizeMultiplier * (numberImageSize + 1) * i;
|
|
|
|
|
DrawNumber(spawnPosition, colon);
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
|
|
while (i < (timerDigitLimit / 2) + 1)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
spawnPosition = timerPosition;
|
|
|
|
|
/* numberImageSize + 1 is because 1 pixel space between digits */
|
|
|
|
|
spawnPosition.x -= screenSizeMultiplier * (numberImageSize + 1) * i;
|
|
|
|
|
|
|
|
|
|
if(i == 0)
|
|
|
|
|
{
|
|
|
|
|
DrawNumber(spawnPosition, colon);
|
|
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
digit = minutes % 10;
|
|
|
|
|
minutes = (int)(minutes / 10);
|
|
|
|
|
DrawNumber(spawnPosition, digit);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-10 12:45:06 +03:00
|
|
|
|
void CheckHighScore()
|
|
|
|
|
{
|
|
|
|
|
FILE *saveFile;
|
|
|
|
|
printf("Checking Highscore = %d and Score = %d\n", highScore, player.score);
|
|
|
|
|
|
|
|
|
|
if(player.score < highScore)
|
|
|
|
|
return;
|
2019-09-10 12:50:01 +03:00
|
|
|
|
|
2019-09-10 12:45:06 +03:00
|
|
|
|
saveFile = fopen(savePath, "wb");
|
|
|
|
|
if(saveFile == NULL)
|
|
|
|
|
{
|
|
|
|
|
printf("!!!!Error Saving Highscore!!!!\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
highScore = player.score;
|
|
|
|
|
fwrite(&highScore, sizeof(highScore), 1, saveFile);
|
|
|
|
|
fclose(saveFile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GetHighScore()
|
|
|
|
|
{
|
|
|
|
|
printf("Getting Highscore\n");
|
|
|
|
|
FILE *saveFile = fopen(savePath, "rb");
|
|
|
|
|
if(saveFile == NULL)
|
|
|
|
|
{
|
|
|
|
|
printf("!!!!Error Reading Highscore!!!!\n");
|
|
|
|
|
highScore = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fread(&highScore, sizeof(highScore), 1, saveFile);
|
|
|
|
|
fclose(saveFile);
|
2019-09-13 17:55:44 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GetSettings()
|
|
|
|
|
{
|
|
|
|
|
printf("Getting Settings\n");
|
|
|
|
|
FILE *settingsFile = fopen(settingsPath, "r");
|
|
|
|
|
if(settingsFile == NULL)
|
|
|
|
|
{
|
|
|
|
|
printf("!!!!Error Reading Settings!!!!\n");
|
|
|
|
|
settingsFile = fopen(settingsPath, "w");
|
|
|
|
|
if(settingsFile == NULL)
|
|
|
|
|
printf("!!!!Error Creating Settings!!!!\n");
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-09-13 18:03:21 +03:00
|
|
|
|
fprintf(settingsFile, settingsFormat, isFullscreen, settingsWidth, settingsHeight, enemyLimiter);
|
2019-09-13 17:55:44 +03:00
|
|
|
|
fclose(settingsFile);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-13 18:03:21 +03:00
|
|
|
|
fscanf(settingsFile, settingsFormat, &isFullscreen, &settingsWidth, &settingsHeight, &enemyLimiter);
|
2019-09-13 17:55:44 +03:00
|
|
|
|
fclose(settingsFile);
|
2019-09-10 12:45:06 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-10 11:14:36 +03:00
|
|
|
|
void Inputs()
|
|
|
|
|
{
|
|
|
|
|
input.x = 0;
|
|
|
|
|
input.y = 0;
|
|
|
|
|
|
|
|
|
|
if(al_key_down(&keyboardState, ALLEGRO_KEY_UP))
|
|
|
|
|
input.y = -1;
|
|
|
|
|
else if(al_key_down(&keyboardState, ALLEGRO_KEY_DOWN))
|
|
|
|
|
input.y = 1;
|
|
|
|
|
|
|
|
|
|
if(al_key_down(&keyboardState, ALLEGRO_KEY_RIGHT))
|
|
|
|
|
{
|
|
|
|
|
input.x = 1;
|
|
|
|
|
player.lookDirection = input.x;
|
|
|
|
|
}
|
|
|
|
|
else if(al_key_down(&keyboardState, ALLEGRO_KEY_LEFT))
|
|
|
|
|
{
|
|
|
|
|
input.x = -1;
|
|
|
|
|
player.lookDirection = input.x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
input = NormalizeVector(input);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PlayerMovement()
|
|
|
|
|
{
|
|
|
|
|
player.position.x += input.x * player.moveSpeed;
|
|
|
|
|
player.position.y += input.y * player.moveSpeed;
|
2019-09-10 22:22:22 +03:00
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
ClampPlayerPositionToScreenDimensions();
|
2019-09-10 22:22:22 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-13 17:55:44 +03:00
|
|
|
|
void ClampPlayerPositionToScreenDimensions()
|
2019-09-10 22:22:22 +03:00
|
|
|
|
{
|
|
|
|
|
if(player.position.x < 0)
|
|
|
|
|
player.position.x = 0;
|
|
|
|
|
else if(player.position.x > screenDimensions.x)
|
|
|
|
|
player.position.x = screenDimensions.x;
|
|
|
|
|
|
|
|
|
|
if(player.position.y < 0)
|
|
|
|
|
player.position.y = 0;
|
|
|
|
|
else if(player.position.y > screenDimensions.y)
|
|
|
|
|
player.position.y = screenDimensions.y;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-10 11:52:00 +03:00
|
|
|
|
char DealDamage(char *health)
|
2019-09-10 11:14:36 +03:00
|
|
|
|
{
|
2019-09-10 11:52:00 +03:00
|
|
|
|
return --*health <= 0;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BulletMovement()
|
|
|
|
|
{
|
|
|
|
|
Bullet *bullet;
|
|
|
|
|
int i = 0;
|
|
|
|
|
for (; i < bullets.bulletCount; i++)
|
|
|
|
|
{
|
|
|
|
|
bullet = (bullets.bulletArray + i);
|
|
|
|
|
bullet -> position.x += bullet -> velocity.x;
|
|
|
|
|
bullet -> position.y += bullet -> velocity.y;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ShootSoundEffect()
|
|
|
|
|
{
|
|
|
|
|
printf("ShootSoundEffect();\n");
|
2019-09-10 22:22:22 +03:00
|
|
|
|
/* al_stop_sample(&shootSoundID); */
|
2019-09-10 11:14:36 +03:00
|
|
|
|
al_play_sample(shootSound, 1.0, 0.0, 1.0, ALLEGRO_PLAYMODE_ONCE, &shootSoundID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DieSoundEffect()
|
|
|
|
|
{
|
|
|
|
|
printf("DieSoundEffect();\n");
|
2019-09-10 22:22:22 +03:00
|
|
|
|
/* al_stop_sample(&enemyDieSoundID); */
|
2019-09-10 11:14:36 +03:00
|
|
|
|
al_play_sample(enemyDieSound, 1.0, 0.0, 1.0, ALLEGRO_PLAYMODE_ONCE, &enemyDieSoundID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PlayerShoot()
|
|
|
|
|
{
|
|
|
|
|
Vector2D shootDir;
|
|
|
|
|
Bullet *newBullet;
|
2019-09-13 17:55:44 +03:00
|
|
|
|
float offset = (al_get_bitmap_width(player.playerImage) + al_get_bitmap_width(enemyBulletImage) * 2.0 * screenSizeMultiplier);
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
|
|
|
|
if(player.lookDirection != 1)
|
|
|
|
|
offset = -offset;
|
|
|
|
|
|
|
|
|
|
shootDir.x = player.lookDirection == 1 ? bulletSpeed : -bulletSpeed;
|
2019-09-13 17:55:44 +03:00
|
|
|
|
shootDir.x *= screenSizeMultiplier;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
shootDir.y = 0;
|
|
|
|
|
|
|
|
|
|
player.shootCooldown = 1 / (float)player.shootPerSecond;
|
|
|
|
|
bullets.bulletCount++;
|
|
|
|
|
bullets.bulletArray = (Bullet *) realloc(bullets.bulletArray, sizeof(Bullet) * bullets.bulletCount);
|
|
|
|
|
newBullet = (bullets.bulletArray + bullets.bulletCount - 1);
|
|
|
|
|
newBullet -> position = player.position;
|
|
|
|
|
newBullet -> position.x += offset;
|
|
|
|
|
newBullet -> velocity = shootDir;
|
|
|
|
|
newBullet -> isEnemyBullet = 0;
|
|
|
|
|
|
|
|
|
|
ShootSoundEffect();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnemyShoot()
|
|
|
|
|
{
|
|
|
|
|
Vector2D shootDir;
|
|
|
|
|
Vector2D normalizedVec;
|
|
|
|
|
Enemy *enemy;
|
|
|
|
|
Bullet *bullet;
|
|
|
|
|
int i;
|
2019-09-13 17:55:44 +03:00
|
|
|
|
float offset = (al_get_bitmap_width(player.playerImage) + al_get_bitmap_width(enemyBulletImage) * 2.0 * screenSizeMultiplier);
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < enemies.enemyCount; i++)
|
|
|
|
|
{
|
|
|
|
|
srand(time(0) + enemyRespawnCounter++);
|
|
|
|
|
enemy = (enemies.enemyArray + i);
|
|
|
|
|
if(enemy -> fireCooldown > 0.0)
|
|
|
|
|
enemy -> fireCooldown -= deltaTime;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
shootDir = (Vector2D){player.position.x - enemy -> position.x , player.position.y - enemy -> position.y};
|
|
|
|
|
|
|
|
|
|
shootDir = NormalizeVector(shootDir);
|
|
|
|
|
normalizedVec = shootDir;
|
2019-09-13 17:55:44 +03:00
|
|
|
|
shootDir = (Vector2D){shootDir.x * bulletSpeed * screenSizeMultiplier, shootDir.y * bulletSpeed * screenSizeMultiplier};
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
|
|
|
|
enemy -> fireCooldown = 1.0 / (rand() % 5) + 2.0;
|
|
|
|
|
bullets.bulletCount++;
|
|
|
|
|
bullets.bulletArray = (Bullet *) realloc(bullets.bulletArray, sizeof(Bullet) * bullets.bulletCount);
|
|
|
|
|
bullet = (bullets.bulletArray + bullets.bulletCount - 1);
|
|
|
|
|
bullet -> position = enemy -> position;
|
|
|
|
|
bullet -> position.x += normalizedVec.x * offset;
|
|
|
|
|
bullet -> position.y += normalizedVec.y * offset;
|
|
|
|
|
bullet -> velocity = shootDir;
|
|
|
|
|
bullet -> isEnemyBullet = 1;
|
|
|
|
|
ShootSoundEffect();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BulletCollisions()
|
|
|
|
|
{
|
|
|
|
|
Bullet *bullet;
|
|
|
|
|
Enemy *enemy;
|
|
|
|
|
int bulletCounter = 0;
|
|
|
|
|
int enemyCounter = 0;
|
|
|
|
|
int i = 0;
|
2019-09-10 11:52:00 +03:00
|
|
|
|
printf("Enemy-Bullet\n");
|
|
|
|
|
for (enemyCounter = 0; enemyCounter < enemies.enemyCount; enemyCounter++)
|
2019-09-10 11:14:36 +03:00
|
|
|
|
{
|
2019-09-10 11:52:00 +03:00
|
|
|
|
printf("Enemy-Bullet|enemyCounter\n");
|
|
|
|
|
enemy = (enemies.enemyArray + enemyCounter);
|
|
|
|
|
for (bulletCounter = 0; bulletCounter < bullets.bulletCount; bulletCounter++)
|
2019-09-10 11:14:36 +03:00
|
|
|
|
{
|
2019-09-10 11:52:00 +03:00
|
|
|
|
bullet = (bullets.bulletArray + bulletCounter);
|
|
|
|
|
printf("Player-Bullet\n");
|
|
|
|
|
if(bullet -> isEnemyBullet == 1 && CheckCollision(
|
|
|
|
|
&bullet -> position,
|
|
|
|
|
&player.position,
|
|
|
|
|
enemyBulletImage,
|
|
|
|
|
player.playerImage
|
|
|
|
|
))
|
|
|
|
|
{
|
|
|
|
|
RemoveBulletAtIndex(bulletCounter);
|
|
|
|
|
bulletCounter--;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
2019-09-10 11:52:00 +03:00
|
|
|
|
if(DealDamage(&player.health))
|
|
|
|
|
isGameOver = 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-10 11:14:36 +03:00
|
|
|
|
if(bullet -> isEnemyBullet == 0 && CheckCollision(
|
|
|
|
|
&bullet -> position,
|
|
|
|
|
&enemy -> position,
|
|
|
|
|
enemyBulletImage,
|
|
|
|
|
enemyImage
|
|
|
|
|
))
|
|
|
|
|
{
|
|
|
|
|
printf("Enemy-Bullet|EnemyRemove\n");
|
|
|
|
|
RemoveEnemyAtIndex(enemyCounter);
|
|
|
|
|
enemyCounter--;
|
|
|
|
|
|
|
|
|
|
printf("Enemy-Bullet|BulletRemove\n");
|
|
|
|
|
RemoveBulletAtIndex(bulletCounter);
|
|
|
|
|
bulletCounter--;
|
|
|
|
|
player.killedEnemyCount++;
|
|
|
|
|
}
|
2019-09-10 11:52:00 +03:00
|
|
|
|
}
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
2019-09-10 11:52:00 +03:00
|
|
|
|
printf("Enemy-Player\n");
|
|
|
|
|
if(CheckCollision(
|
|
|
|
|
&enemy -> position,
|
|
|
|
|
&player.position,
|
|
|
|
|
enemyImage,
|
|
|
|
|
player.playerImage
|
|
|
|
|
))
|
|
|
|
|
{
|
|
|
|
|
RemoveEnemyAtIndex(enemyCounter);
|
|
|
|
|
enemyCounter--;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
|
2019-09-10 11:52:00 +03:00
|
|
|
|
if(DealDamage(&player.health))
|
|
|
|
|
isGameOver = 1;
|
2019-09-10 11:14:36 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-10 11:52:00 +03:00
|
|
|
|
|
2019-09-10 11:14:36 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DestroyGame()
|
|
|
|
|
{
|
2019-09-10 12:45:06 +03:00
|
|
|
|
CheckHighScore();
|
2019-09-10 11:14:36 +03:00
|
|
|
|
al_destroy_bitmap(enemyImage);
|
|
|
|
|
al_destroy_bitmap(enemyBulletImage);
|
|
|
|
|
al_destroy_bitmap(gameOverImage);
|
|
|
|
|
al_destroy_bitmap(numberTable);
|
|
|
|
|
al_destroy_sample(shootSound);
|
|
|
|
|
al_destroy_sample(enemyDieSound);
|
|
|
|
|
al_destroy_bitmap(player.playerImage);
|
|
|
|
|
free(enemies.enemyArray);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DestroyGameWindow()
|
|
|
|
|
{
|
2019-09-10 22:22:22 +03:00
|
|
|
|
/* BGM is an exception since I don't want to it to restart itself every restart */
|
|
|
|
|
al_destroy_sample(BGM);
|
2019-09-10 11:14:36 +03:00
|
|
|
|
al_destroy_display(display);
|
|
|
|
|
al_uninstall_keyboard();
|
|
|
|
|
}
|