281 lines
11 KiB
Text
281 lines
11 KiB
Text
#include "floaters.h"
|
|
|
|
#define enemyMinSize 0.75 /**< Ellenségek oldalhosszának kezdeti értéke [m].*/
|
|
#define enemyMaxSize 4 /**< Az ellenségek, ha összeérnek, összetapadnak, de ennél ne lehetnek nagyobbak [m]. */
|
|
#define enemyVelocity 0.006 /**< [m/ms] */
|
|
#define enemySlowing 0.15 /**< Ha az ellenség nekiütközik valaminek, akkor a sebessége ennyiszeresére csökken. */
|
|
#define slownessDebuffDuration 2000 /**< Ha az ellenség nekiütközik valaminek, akkor a sebessége ennyi ideig lesz alacsnyabb. [ms] */
|
|
#define projectileSize 0.2 /**< A játékos által lőtt lövedék oldalhossza [m]. */
|
|
#define projectileVelocity 0.03 /**< A játékos által lőtt lövedék kezdő sebessége [m/ms] */
|
|
#define projectileVelocityYMax 0.03 /**< A lövedék sebességét befolyásolja a játékos sebessége (a kiulövés pillanatában), illetve a gravitációs gyorsulás, viszont sosem lehet gyorsabb. */
|
|
#define floaterColor (colors) { (color) {229, 22, 22, 255}, (color) {200, 20, 20, 255}, (color) {168, 16, 16, 255} } /**< A lövedék és az ellenség ugyanolyan színű */
|
|
|
|
floater* floaterList = NULL; /**< Láncolt lista, ami az ellenségeket és lövedékeket is tartalmazza. Nagyon hasonló a kettő, ezért célszerű közösen kezelni őket.*/
|
|
|
|
///Lista elejére beszúr.
|
|
floater* addToFloaterList() {
|
|
floater* newfloater = (floater*) malloc(sizeof(floater));
|
|
newfloater -> next = floaterList;
|
|
floaterList = newfloater;
|
|
return newfloater;
|
|
}
|
|
|
|
///Felszabadítja az ellenségek és lövedékek listáját.
|
|
void freeFloaterList() {
|
|
if(floaterList == NULL) return;
|
|
|
|
floater* moving = floaterList;
|
|
|
|
floater* tmp;
|
|
while(moving != NULL) {
|
|
tmp = moving;
|
|
moving = moving -> next;
|
|
free(tmp);
|
|
}
|
|
|
|
floaterList = NULL;
|
|
}
|
|
|
|
///A játékos közelében elhelyez egy új ellenséget.
|
|
void createEnemy() {
|
|
|
|
floater* newEnemy = addToFloaterList();
|
|
newEnemy -> type = enemy;
|
|
newEnemy -> velocity = (vector2D) {0, 0};
|
|
newEnemy -> slownessDebuffLeft = 0;
|
|
newEnemy -> size = enemyMinSize;
|
|
|
|
vector3D playerPosition = getPlayerRenderObject().position;
|
|
|
|
int i = 0;
|
|
|
|
do {
|
|
newEnemy -> position.x = playerPosition.x + (float) (randomPlusOrMinus() * randomIntWithinBorders(50 - i, 20));
|
|
newEnemy -> position.y = playerPosition.y + (float) (randomIntWithinBorders(40 - i, 15));
|
|
i++;
|
|
}
|
|
while(!isWithinTheMap(newEnemy -> position, (vector2D) {newEnemy -> size, newEnemy -> size}));
|
|
|
|
}
|
|
|
|
/** \brief Lövedék létrehozása.
|
|
* A megadott paraméterek függvényében a létrehozott lövedék az egér irányafele indul el.
|
|
* \param helyvektor a játékoshoz
|
|
* \param térvektor a játékos méretéhez
|
|
* \param síkvektor* játékos sebesség (ezt Newton III. értelmében megváltoztatja
|
|
* \param koordinátája az egérnek
|
|
* A játékost ellenkező irányba elmozdítja. A lövedék kezdősebbességéhez hozzáadódik a játékos sebessége.
|
|
*/
|
|
void createProjectile(vector3D playerPosition, vector3D playerSize, vector2D* playerVelocity, mousePos mouse) {
|
|
floater* newProjectile = addToFloaterList();
|
|
newProjectile -> type = projectile;
|
|
newProjectile -> position.x = playerPosition.x + playerSize.x / 2;
|
|
newProjectile -> position.y = playerPosition.y + playerSize.y / 2;
|
|
newProjectile -> size = projectileSize;
|
|
|
|
intVector2D playerCoord = get2DPoint((vector3D) {newProjectile -> position.x, newProjectile -> position.y, 0});
|
|
int deltaX = mouse.x - playerCoord.x;
|
|
int deltaY = playerCoord.y - mouse.y;
|
|
float distance = sqrt(deltaX * deltaX + deltaY * deltaY);
|
|
float compensation = 0;
|
|
if(distance > 0) compensation = projectileVelocity / distance;
|
|
|
|
newProjectile -> velocity = (vector2D) {
|
|
deltaX * compensation + playerVelocity -> x,
|
|
deltaY * compensation + playerVelocity -> y
|
|
};
|
|
|
|
playerVelocity -> x -= newProjectile -> velocity.x * 0.25;
|
|
playerVelocity -> y -= newProjectile -> velocity.y * 0.25;
|
|
}
|
|
|
|
///Listából kiszed.
|
|
void destroyFloater(floater* floaterToDestroy) {
|
|
if(floaterList == floaterToDestroy) floaterList = floaterToDestroy -> next;
|
|
else {
|
|
floater* previous = floaterList;
|
|
|
|
while(previous != NULL && previous -> next != floaterToDestroy)
|
|
previous = previous -> next;
|
|
|
|
previous -> next = floaterToDestroy -> next;
|
|
}
|
|
free(floaterToDestroy);
|
|
}
|
|
|
|
/** \brief Megnézi összeér-e két ellenség, ha igen, összeolvasztja őket.
|
|
* A kisebb ellenség eltűnik, a nagyobbnak a térfogata a kisebbéjével nő.
|
|
* \param ellenség1
|
|
* \param ellenség2
|
|
* \return Összeértek-e?
|
|
*/
|
|
static bool mergeEnemies(floater* enemy1, floater* enemy2) {
|
|
floater* enemyBigger = enemy1 -> size > enemy2 -> size ? enemy1 : enemy2;
|
|
floater* enemySmaller = enemy1 -> size > enemy2 -> size ? enemy2 : enemy1;
|
|
|
|
if(isBoxOverlappingBox(
|
|
enemy1 -> position, (vector2D) {enemy1 -> size, enemy1 -> size},
|
|
enemy2 -> position, (vector2D) {enemy2 -> size, enemy2 -> size}
|
|
)) {
|
|
enemyBigger -> size = smallerF(fDist(enemyBigger -> size, enemySmaller -> size), enemyMaxSize);
|
|
|
|
destroyFloater(enemySmaller);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
///Kezeli ha egy ellenség le lett lőve, a lövedék eltűnik, az ellenség mérete pedig csökken, vagy ha túl kicsi, az ellenség eltűnik.
|
|
static void projectileEnemyCollision(floater* projectile) {
|
|
floater* currentFloater = floaterList;
|
|
while(currentFloater != NULL) {
|
|
|
|
if(currentFloater -> type == enemy &&
|
|
isBoxOverlappingBox(
|
|
projectile -> position, (vector2D) {projectile -> size, projectile -> size},
|
|
currentFloater -> position, (vector2D) {currentFloater -> size, currentFloater -> size}
|
|
)
|
|
) {
|
|
destroyFloater(projectile);
|
|
|
|
currentFloater -> size = sqrt(square(currentFloater -> size) - 0.95 * square(enemyMinSize * enemyMinSize));
|
|
if(currentFloater -> size < enemyMinSize * 1.05)
|
|
destroyFloater(currentFloater);
|
|
}
|
|
|
|
currentFloater = currentFloater -> next;
|
|
}
|
|
}
|
|
|
|
/** \brief Megnézi, hogy ütközött-e valami egy kockával, ha igen, kezeli.
|
|
* A kocka mindenképpen megsemmisül.
|
|
* \param helyvektor a floaterhez
|
|
* \param mérete a flaoternek
|
|
* \return Ütköztek-e?
|
|
* A visszatérési érték alapján megfelelően lehet kezelni az esetet.
|
|
*/
|
|
static bool floaterSolidCollision(vector2D position, float size) {
|
|
block* blockToDestroy;
|
|
if(
|
|
isWithinTheMap(position, (vector2D) {size, size}) &&
|
|
(detectCollision(position, (vector2D) {size, size}, solid, &blockToDestroy) ||
|
|
detectCollision(position, (vector2D) {size, size}, treasure, &blockToDestroy)) &&
|
|
blockToDestroy != NULL
|
|
) {
|
|
*blockToDestroy = air;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/** \brief Mozgatja az adott ellenséget.
|
|
* Figyel minden lehetsége ütközésre.
|
|
* \param ellenség
|
|
* \param ms eltelt idő
|
|
*/
|
|
static void moveEnemy(floater* thisEnemy, int deltaTime) {
|
|
float velocity = enemyVelocity;
|
|
if(thisEnemy -> slownessDebuffLeft > 0) {
|
|
thisEnemy -> slownessDebuffLeft -= deltaTime;
|
|
velocity *= enemySlowing;
|
|
}
|
|
|
|
renderObject player = getPlayerRenderObject();
|
|
vector3D playerPosition = player.position;
|
|
float deltaX = (playerPosition.x - thisEnemy -> position.x);
|
|
float deltaY = (playerPosition.y - thisEnemy -> position.y);
|
|
|
|
float compensation = 0;
|
|
float distance = fDist(deltaX, deltaY);
|
|
if(distance > 0)
|
|
compensation = velocity / distance;
|
|
|
|
thisEnemy -> position.x += deltaX * compensation * deltaTime;
|
|
thisEnemy -> position.y += deltaY * compensation * deltaTime;
|
|
|
|
|
|
if(floaterSolidCollision(thisEnemy -> position, thisEnemy -> size))
|
|
thisEnemy -> slownessDebuffLeft = slownessDebuffDuration;
|
|
|
|
|
|
if(isBoxOverlappingBox((vector2D) {player.position.x, player.position.y}, (vector2D){player.size.x, player.size.y},
|
|
thisEnemy -> position, (vector2D) {thisEnemy -> size, thisEnemy -> size})) setDie(true);
|
|
|
|
floater* currentEnemy = floaterList;
|
|
while(currentEnemy != NULL && (thisEnemy == currentEnemy || !mergeEnemies(thisEnemy, currentEnemy)))
|
|
currentEnemy = currentEnemy -> next;
|
|
}
|
|
|
|
/** \brief Mozgatja az adott lövedéket.
|
|
* Figyel minden lehetsége ütközésre.
|
|
* \param lövedék
|
|
* \param ms eltelt idő
|
|
*/
|
|
static void moveProjectile(floater* thisProjectile, int deltaTime) {
|
|
thisProjectile -> velocity.y -= g * deltaTime;
|
|
if(thisProjectile -> velocity.y < -projectileVelocityYMax) thisProjectile -> velocity.y = -projectileVelocityYMax;
|
|
thisProjectile -> position.x += thisProjectile -> velocity.x * deltaTime;
|
|
thisProjectile -> position.y += thisProjectile -> velocity.y * deltaTime;
|
|
|
|
if(
|
|
!isWithinTheMap(thisProjectile -> position, (vector2D) {projectileSize, projectileSize}) ||
|
|
floaterSolidCollision(thisProjectile -> position, thisProjectile -> size)
|
|
)
|
|
destroyFloater(thisProjectile);
|
|
|
|
projectileEnemyCollision(thisProjectile);
|
|
}
|
|
|
|
///Minden floaterre meghívja a szükséges mozgatási műveletet.
|
|
void moveFloaters(int deltaTime) {
|
|
floater* currentFloater = floaterList;
|
|
|
|
while(currentFloater != NULL) {
|
|
|
|
if(currentFloater -> type == projectile) moveProjectile(currentFloater, deltaTime);
|
|
else moveEnemy(currentFloater, deltaTime);
|
|
|
|
currentFloater = currentFloater -> next;
|
|
}
|
|
}
|
|
|
|
/** \brief Visszaadja az adott térfogatban lévő floater testeket.
|
|
* A sorrend nem elhanyagolható 3D-s testek rajzolásakor. Figyelni kell, melyik melyik másikat takarja el.
|
|
* Ezért kell "feldarabolni" őket. Itt még csak az egy adott m^3-ben lévő testek adatait adja oda a rajzoló függvénynek.
|
|
* Maga a feldarabolás már nem ennek a függvénynek a dolga.
|
|
* \param koord x
|
|
* \param koord y
|
|
* \param Hova kell írnia a testeket
|
|
* \param Max mennyit adhat vissza
|
|
* A feldarabolásról részletesebben a camera.c modulban.
|
|
*/
|
|
void getFloatersRenderObject(int x, int y, renderObject* renderMap, int renderObjectsPerCube) {
|
|
renderObject enemyRenderObject;
|
|
enemyRenderObject.colors = floaterColor;
|
|
|
|
int floaterCounter = 0;
|
|
|
|
floater* currentFloater = floaterList;
|
|
while(currentFloater != NULL) {
|
|
|
|
if(
|
|
(int)currentFloater -> position.x <= x && x <= (int)(currentFloater -> position.x + currentFloater -> size) &&
|
|
(int)currentFloater -> position.y <= y && y <= (int)(currentFloater -> position.y + currentFloater -> size)
|
|
) {
|
|
enemyRenderObject.position = (vector3D) {currentFloater -> position.x, currentFloater -> position.y, 0.5};
|
|
enemyRenderObject.size = (vector3D) {currentFloater -> size, currentFloater -> size, currentFloater -> size/2};
|
|
enemyRenderObject.doesExist = true;
|
|
|
|
if(floaterCounter < renderObjectsPerCube - 1) {
|
|
renderMap[floaterCounter] = enemyRenderObject;
|
|
floaterCounter++;
|
|
}
|
|
|
|
}
|
|
|
|
currentFloater = currentFloater -> next;
|
|
}
|
|
|
|
enemyRenderObject.doesExist = false;
|
|
renderMap[floaterCounter] = enemyRenderObject;
|
|
}
|