This commit is contained in:
Andras Schmelczer 2026-08-09 13:37:33 +01:00
commit 62d2de747e
59 changed files with 130940 additions and 0 deletions

View file

@ -0,0 +1,22 @@
#include "auxFunctions.h"
extern inline float randomWithinBorders(float base, float variance);
extern inline int randomIntWithinBorders(int base, int variance);
extern inline int randomPlusOrMinus();
extern inline int larger(int a, int b);
extern inline int smaller(int a, int b);
extern inline float largerF(float a, float b);
extern inline float smallerF(float a, float b);
extern inline void putInsideInterval(int min, int* a, int max);
extern inline void putInsideIntervalF(float min, float* a, float max);
extern inline float dist(int a, int b);
extern inline float fDist(float a, float b);
extern inline float square(float a);

View file

@ -0,0 +1,22 @@
#include "auxFunctions.h"
extern inline float randomWithinBorders(float base, float variance);
extern inline int randomIntWithinBorders(int base, int variance);
extern inline int randomPlusOrMinus();
extern inline int larger(int a, int b);
extern inline int smaller(int a, int b);
extern inline float largerF(float a, float b);
extern inline float smallerF(float a, float b);
extern inline void putInsideInterval(int min, int* a, int max);
extern inline void putInsideIntervalF(float min, float* a, float max);
extern inline float dist(int a, int b);
extern inline float fDist(float a, float b);
extern inline float square(float a);

View file

@ -0,0 +1,58 @@
#ifndef AUXFUNCTIONS_H_INCLUDED
#define AUXFUNCTIONS_H_INCLUDED
#include "../global.h"
inline float randomWithinBorders(float base, float variance) {
int intVariance = (int)(1e4 * variance);
return (1e4 * base + (rand() % (2 * intVariance + 1) - intVariance)) / 1e4;
}
inline int randomIntWithinBorders(int base, int variance) {
return base + (rand() % (2 * variance + 1) - variance);
}
inline int randomPlusOrMinus() {
return rand() % 2 ? 1 : -1;
}
inline int larger(int a, int b) {
return a > b ? a : b;
}
inline int smaller(int a, int b) {
return a < b ? a : b;
}
inline float largerF(float a, float b) {
return a > b ? a : b;
}
inline float smallerF(float a, float b) {
return a < b ? a : b;
}
inline void putInsideInterval(int min, int* a, int max) {
*a = largerF(min, smallerF(*a, max));
}
inline void putInsideIntervalF(float min, float* a, float max) {
*a = largerF(min, smallerF(*a, max));
}
inline float dist(int a, int b) {
return sqrt(a*a + b*b);
}
inline float fDist(float a, float b) {
return sqrt(a*a + b*b);
}
inline float square(float a) {
return a*a;
}
#endif // AUXFUNCTIONS_H_INCLUDED

View file

@ -0,0 +1,64 @@
#ifndef AUXFUNCTIONS_H_INCLUDED
#define AUXFUNCTIONS_H_INCLUDED
#include "../global.h"
inline float randomWithinBorders(float base, float variance) {
int intVariance = (int)(1e4 * variance);
return (1e4 * base + (rand() % (2 * intVariance + 1) - intVariance)) / 1e4;
}
inline int randomIntWithinBorders(int base, int variance) {
return base + (rand() % (2 * variance + 1) - variance);
}
inline int randomPlusOrMinus() {
return rand() % 2 ? 1 : -1;
}
inline int larger(int a, int b) {
return a > b ? a : b;
}
inline int smaller(int a, int b) {
return a < b ? a : b;
}
inline float largerF(float a, float b) {
return a > b ? a : b;
}
inline float smallerF(float a, float b) {
return a < b ? a : b;
}
inline void putInsideInterval(int min, int* a, int max) {
*a = largerF(min, smallerF(*a, max));
}
inline void putInsideIntervalF(float min, float* a, float max) {
*a = largerF(min, smallerF(*a, max));
}
inline float dist(int a, int b) {
return sqrt(a*a + b*b);
}
inline float fDist(float a, float b) {
return sqrt(a*a + b*b);
}
inline float square(float a) {
return a*a;
}
//++print + int = print xd
inline void print(int a) {
printf("%d\n", a);
}
#endif // AUXFUNCTIONS_H_INCLUDED

View file

@ -0,0 +1,73 @@
#include "auxSDL.h"
mousePos mouse; /**< Az egér koordinátáit tárolja, így egyszerűbb, mint közvetlen az eventek figyelése. */
/** \brief https://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlcreatecursor.html
* Hogy erre miért van szükség, az egy nagyon jó kérdés. Ha ehelyett a "SDL_ShowCursor(SDL_DISABLE);"-t
* használnám az egér random ugrálna néha néha, így viszont ezt nem teszi.
*/
static SDL_Cursor* createCursor() {
Uint8 data[4*32] = {0};
Uint8 mask[4*32] = {0};
return SDL_CreateCursor(data, mask, 32, 32, 0, 0);
}
/** \brief Létrehozza a játék futtatásához szükséges környezetet.
* Megnézi az elérhető legnagyobb felbontást, azzal a felbontással létrehoz egy ablakot, illetve
* meghív pár, az inicializáláshoz szükséges függvényt.
* \return kurzor amit fel kell később szabadítanunk
*/
SDL_Cursor* openWindow() {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
SDL_Rect** screenSizes = SDL_ListModes(NULL, SDL_FULLSCREEN);
screen = SDL_SetVideoMode(screenSizes[0] -> w, screenSizes[0] -> h, 0, SDL_FULLSCREEN);
if (!screen) {
fprintf(stderr, "Nem sikerult megnyitni az ablakot!\n");
exit(1);
}
SDL_WM_SetCaption("Platform játék", "Schmelczer András: Platform játék");
SDL_Cursor* cursor = createCursor();
SDL_SetCursor(cursor);
openFonts();
SDL_WM_GrabInput(SDL_GRAB_FULLSCREEN);
return cursor;
}
///A játék időzítéséhez szükséges.
Uint32 timer(Uint32 ms, void* param) {
SDL_Event event;
event.type = SDL_USEREVENT;
SDL_PushEvent(&event);
return ms;
}
///Frissití az egér pozicióját.
void setMousePosition(Uint16 x, Uint16 y) {
mouse.x = x;
mouse.y = y;
}
///Visszaadja az egérpoziciót.
mousePos getMousePosition() {
return mouse;
}
///Lerajzolja a képernyőre az egeret, erre azért van szükség, mert az SDL csak fekete-fehér egérmutatót kezel.
void drawMouse(bool isBW) {
Sint16 x1 = mouse.x - mouseSize / 2;
Sint16 x2 = mouse.x + mouseSize / 2;
Sint16 y1 = mouse.y - mouseSize / 2;
Sint16 y2 = mouse.y + mouseSize / 2;
boxColor(screen, x1, y1, x2, y2, isBW ? 0x7F7F7FFF : 0xFFFF00FF);
}
///Egy téglalap felett van-e az egérmutató közepe?
bool isMouseOverRect(int xCenter, int yCenter, int xSize, int ySize) {
return
screen -> w / 100.0 * (xCenter - xSize) < mouse.x && mouse.x < screen -> w / 100.0 * (xCenter + xSize) &&
screen -> h / 100.0 * (yCenter - ySize) < mouse.y && mouse.y < screen -> h / 100.0 * (yCenter + ySize);
}

View file

@ -0,0 +1,80 @@
#include "auxSDL.h"
mousePos mouse; /**< Az egér koordinátáit tárolja, így egyszerűbb, mint közvetlen az eventek figyelése. */
/** \brief https://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlcreatecursor.html
* Hogy erre miért van szükség, az egy nagyon jó kérdés. Ha ehelyett a "SDL_ShowCursor(SDL_DISABLE);"-t
* használnám az egér random ugrálna néha néha, így viszont ezt nem teszi.
*/
static SDL_Cursor* createCursor() {
Uint8 data[4*32] = {0};
Uint8 mask[4*32] = {0};
return SDL_CreateCursor(data, mask, 32, 32, 0, 0);
}
/** \brief Létrehozza a játék futtatásához szükséges környezetet.
* Megnézi az elérhető legnagyobb felbontást, azzal a felbontással létrehoz egy ablakot, illetve
* meghív pár, az inicializáláshoz szükséges függvényt.
* \return kurzor amit fel kell később szabadítanunk
*/
SDL_Cursor* openWindow() {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
SDL_Rect** screenSizes = SDL_ListModes(NULL, SDL_FULLSCREEN);
screen = SDL_SetVideoMode(screenSizes[0] -> w, screenSizes[0] -> h, 0, SDL_FULLSCREEN);
if (!screen) {
fprintf(stderr, "Nem sikerult megnyitni az ablakot!\n");
exit(1);
}
SDL_WM_SetCaption("Platform játék", "Schmelczer András: Platform játék");
SDL_Cursor* cursor = createCursor();
SDL_SetCursor(cursor);
openFonts();
SDL_WM_GrabInput(SDL_GRAB_FULLSCREEN);
return cursor;
}
///A játék időzítéséhez szükséges.
Uint32 timer(Uint32 ms, void* param) {
SDL_Event event;
event.type = SDL_USEREVENT;
SDL_PushEvent(&event);
return ms;
}
///Frissití az egér pozicióját.
void setMousePosition(Uint16 x, Uint16 y) {
mouse.x = x;
mouse.y = y;
}
///Visszaadja az egérpoziciót.
mousePos getMousePosition() {
return mouse;
}
///Lerajzolja a képernyőre az egeret, erre azért van szükség, mert az SDL csak fekete-fehér egérmutatót kezel.
void drawMouse(bool isBW) {
Sint16 x1 = mouse.x - mouseSize / 2;
Sint16 x2 = mouse.x + mouseSize / 2;
Sint16 y1 = mouse.y - mouseSize / 2;
Sint16 y2 = mouse.y + mouseSize / 2;
boxColor(screen, x1, y1, x2, y2, isBW ? 0x7F7F7FFF : 0xFFFF00FF);
}
bool isMouseOver(int yStart, int ySize, int y) {
return
(float) screen -> h / 100 * (yStart + (y - 0.5) * ySize) < mouse.y &&
mouse.y < (float) screen -> h / 100 * (yStart + (y + 0.5) * ySize);
}
///Egy téglalap felett van-e az egérmutató közepe?
bool isMouseOverRect(int xCenter, int yCenter, int xSize, int ySize) {
return
screen -> w / 100.0 * (xCenter - xSize) < mouse.x && mouse.x < screen -> w / 100.0 * (xCenter + xSize) &&
screen -> h / 100.0 * (yCenter - ySize) < mouse.y && mouse.y < screen -> h / 100.0 * (yCenter + ySize);
}

View file

@ -0,0 +1,20 @@
#ifndef AUXSDL_H_INCLUDED
#define AUXSDL_H_INCLUDED
#include "../global.h"
#include "unicodePrint.h"
#define mouseSize 20 /**< Az egérmutató négyzetnek az oldalhosszusága. */
typedef struct mousePos {
Uint16 x, y;
} mousePos;
SDL_Cursor* openWindow();
Uint32 timer(Uint32 ms, void* param);
void setMousePosition(Uint16 x, Uint16 y);
mousePos getMousePosition();
void drawMouse(bool isBW);
bool isMouseOverRect(int xCenter, int yCenter, int xSize, int ySize);
#endif // AUXSDL_H_INCLUDED

View file

@ -0,0 +1,21 @@
#ifndef AUXSDL_H_INCLUDED
#define AUXSDL_H_INCLUDED
#include "../global.h"
#include "unicodePrint.h"
#define mouseSize 20 /**< Az egérmutató négyzetnek az oldalhosszusága. */
typedef struct mousePos {
Uint16 x, y;
} mousePos;
SDL_Cursor* openWindow();
Uint32 timer(Uint32 ms, void* param);
void setMousePosition(Uint16 x, Uint16 y);
mousePos getMousePosition();
void drawMouse(bool isBW);
bool isMouseOver(int yStart, int ySize, int y);
bool isMouseOverRect(int xCenter, int yCenter, int xSize, int ySize);
#endif // AUXSDL_H_INCLUDED

View file

@ -0,0 +1,84 @@
#include "unicodePrint.h"
///Indításnál betölti a szükséges betűtípusokat.
void openFonts() {
SDL_EnableUNICODE(1);
TTF_Init();
fontSmaller = TTF_OpenFont("resources/Roboto-Thin.ttf", 40);
fontSmall = TTF_OpenFont("resources/Roboto-Thin.ttf", 48);
fontSmallBold = TTF_OpenFont("resources/Roboto-Light.ttf", 53);
fontLarge = TTF_OpenFont("resources/Roboto-Thin.ttf", 120);
}
///Ha már nem kellenek, felszabadítja a betűtípusokat.
void freeFonts() {
TTF_CloseFont(fontSmaller);
TTF_CloseFont(fontSmall);
TTF_CloseFont(fontSmallBold);
TTF_CloseFont(fontLarge);
}
///Itt tárolom a használható karaktereket. Eldönti, hogy a bemenet köztük van-e.
bool isValidChar(Uint16 chr) {
if(('A' <= chr && chr <= 'Z') || ('a' <= chr && chr <= 'z') || ('0' <= chr && chr <= '9')) return true;
Uint16 validChars[] = L"öüóőúéáűíÖÜÓŐÚÉÁŰÍ|€ß$Łł¤<>#&@{}Đ[]đ+!%=×)(.- ";
int i;
for(i = 0; validChars[i] != 0; i++) if(chr == validChars[i])
return true;
return false;
}
///Az egyszerűbb kezelhetőség miatt kell. Visszadja az enumhoz tartozó ttf-et.
TTF_Font* selectFont(fontType fontType) {
switch(fontType) {
case tiny:
return fontSmaller;
case small:
return fontSmall;
case smallBold:
return fontSmallBold;
case large:
default:
return fontLarge;
}
}
///A százalékot a képernyő mérete alapján átváltja pixelekre.
Sint16 percentageToPx(int percentage, bool isWidth) {
return (int)((float)percentage/100 * (isWidth ? screen -> w: screen -> h));
}
/** \brief Uint16-ból álló stringet összefűz.
* A két paramétert egy harmadik dinamikusan foglalt stringben fűzi össze.
* \param string eleje
* \param string vége
* \return string konkatenált
*/
Uint16* concatUnicode(const Uint16 a[], const Uint16 b[]) {
int aLength, bLength;
for(aLength = 0; a[aLength] != 0; aLength++)
;
for(bLength = 0; b[bLength] != 0; bLength++)
;
Uint16* newStr = (Uint16*) malloc((aLength + bLength - 1 + 100) * sizeof(Uint16));
int i = 0, ai, bi;
for(ai = 0; ai < aLength; ai++)
newStr[i++] = a[ai];
for(bi = 0; bi < bLength; bi++)
newStr[i++] = b[bi];
newStr[i] = 0;
return newStr;
}
///A megjelenítendő szöveg közepét kell megadni x,y-ként. A szöveget Uint16*-ban, a betűtipust pedig a betűtipus enumból. Ugyan mindent x = 50-nel hívunk meg, ez később változhat, ezért hagyom meg paraméternek.
void unicodePrintCentered(Uint16 textToWrite[], int x, int y, fontType fontType) {
TTF_Font* currentFont = selectFont(fontType);
SDL_FreeSurface(text);
text = TTF_RenderUNICODE_Blended(currentFont, textToWrite, (SDL_Color) {255, 255, 255});
SDL_BlitSurface(text, NULL, screen, &(SDL_Rect){percentageToPx(x, true) - text -> w / 2, percentageToPx(y, false) - text -> h / 2, 0, 0});
}

View file

@ -0,0 +1,84 @@
#include "unicodePrint.h"
///Indításnál betölti a szükséges betűtípusokat.
void openFonts() {
SDL_EnableUNICODE(1);
TTF_Init();
fontSmaller = TTF_OpenFont("resources/Roboto-Thin.ttf", 40);
fontSmall = TTF_OpenFont("resources/Roboto-Thin.ttf", 48);
fontSmallBold = TTF_OpenFont("resources/Roboto-Light.ttf", 53);
fontLarge = TTF_OpenFont("resources/Roboto-Thin.ttf", 120);
}
///Ha már nem kellenek, felszabadítja a betűtípusokat.
void freeFonts() {
TTF_CloseFont(fontSmaller);
TTF_CloseFont(fontSmall);
TTF_CloseFont(fontSmallBold);
TTF_CloseFont(fontLarge);
}
///Itt tárolom a használható karaktereket. Eldönti, hogy a bemenet köztük van-e.
bool isValidChar(Uint16 chr) {
if(('A' <= chr && chr <= 'Z') || ('a' <= chr && chr <= 'z') || ('0' <= chr && chr <= '9')) return true;
Uint16 validChars[] = L"öüóőúéáűíÖÜÓŐÚÉÁŰÍ|€ß$Łł¤<>#&@{}Đ[]đ+!%=×)(.- ";
int i;
for(i = 0; validChars[i] != 0; i++) if(chr == validChars[i])
return true;
return false;
}
///Az egyszerűbb kezelhetőség miatt kell. Visszadja az enumhoz tartozó ttf-et.
TTF_Font* selectFont(fontType fontType) {
switch(fontType) {
case tiny:
return fontSmaller;
case small:
return fontSmall;
case smallBold:
return fontSmallBold;
case large:
default:
return fontLarge;
}
}
///A százalékot a képernyő mérete alapján átváltja pixelekre.
Sint16 percentageToPx(int percentage, bool isWidth) {
return (int)((float)percentage/100 * (isWidth ? screen -> w: screen -> h));
}
/** \brief Uint16-ból álló stringet összefűz.
* A két paramétert egy harmadik dinamikusan foglalt stringben fűzi össze.
* \param string eleje
* \param string vége
* \return string konkatenált
*/
Uint16* concatUnicode(const Uint16 a[], const Uint16 b[]) {
int aLength, bLength;
for(aLength = 0; a[aLength] != 0; aLength++)
;
for(bLength = 0; b[bLength] != 0; bLength++)
;
Uint16* newStr = (Uint16*) malloc((aLength + bLength - 1 + 100) * sizeof(Uint16));
int i = 0, ai, bi;
for(ai = 0; ai < aLength; ai++)
newStr[i++] = a[ai];
for(bi = 0; bi < bLength; bi++)
newStr[i++] = b[bi];
newStr[i] = 0;
return newStr;
}
///A megjelenítendő szöveg közepét kell megadni x,y-ként. A szöveget Uint16*-ban, a betűtipust pedig a betűtipus enumból. Ugyan mindent x = 50-nel hívunk meg, ez később változhat, ezért hagyom meg paraméternek.
void unicodePrintCentered(Uint16 textToWrite[], int x, int y, fontType fontType) {
TTF_Font* currentFont = selectFont(fontType);
SDL_FreeSurface(text);
text = TTF_RenderUNICODE_Blended(currentFont, textToWrite, (SDL_Color) {255, 255, 255});
SDL_BlitSurface(text, NULL, screen, &(SDL_Rect){percentageToPx(x, true) - text -> w / 2, percentageToPx(y, false) - text -> h / 2, 0, 0});
}

View file

@ -0,0 +1,16 @@
#ifndef UNICODEPRINT_H_INCLUDED
#define UNICODEPRINT_H_INCLUDED
#include "../global.h"
typedef enum fontType {
tiny, small, smallBold, large
} fontType;
void openFonts();
void freeFonts();
bool isValidChar(Uint16 chr);
Uint16* concatUnicode(const Uint16 a[], const Uint16 b[]);
void unicodePrintCentered(Uint16 textToWrite[], int x, int y, fontType fontType);
#endif // UNICODEPRINT_H_INCLUDED

View file

@ -0,0 +1,16 @@
#ifndef UNICODEPRINT_H_INCLUDED
#define UNICODEPRINT_H_INCLUDED
#include "../global.h"
typedef enum fontType {
tiny, small, smallBold, large
} fontType;
void openFonts();
void freeFonts();
bool isValidChar(Uint16 chr);
Uint16* concatUnicode(const Uint16 a[], const Uint16 b[]);
void unicodePrintCentered(Uint16 textToWrite[], int x, int y, fontType fontType);
#endif // UNICODEPRINT_H_INCLUDED

View file

@ -0,0 +1,326 @@
#include "camera.h"
#define focalLength 0.05 /**< gyújtótáv [m] */
#define sensorSize 0.07 /**< szenzor hosszabb oldalának a fele [m] */
#define renderObjectsPerCube 10 /**< max( (projectile + player + enemy) / m^3), erről később bővebben. */
vector3D cameraPosition; /**< A kamera térbeli helyvektora. */
float magnification, columns, rows; /**< Ennyi látszik a pályából [m]. */
bool watchBounds = false; /**< Feldarabolós rajzolás van-e? */
float leftBound, rightBound, upperBound, lowerBound; /**< Darabolás határai. */
int leftMostBound, rightMostBound, topBound, bottomBound;
renderObject*** renderMap = NULL; /**< Darabolás mátrixa. */
///A feldarabolós rajzoláshoz szükséges mátrixot szabadítja fel.
void freeRenderMap() {
if(renderMap != NULL) {
free(renderMap[0][0]);
free(renderMap[0]);
free(renderMap);
}
}
///A feldarabolós rajzoláshoz szükséges mátrixot mallocolja.
static void initRenderMap() {
renderMap = (renderObject***) malloc(sizeof(renderObject**));
renderMap[0] = (renderObject**) malloc(sizeof(renderObject*));
renderMap[0][0] = (renderObject*) malloc(sizeof(renderObject));
}
/** \brief Kiszámolja a kamera poziciója és a képernyő mérete alapján, hogy mennyi látszik a pályából.
*
* Elsősorban ezeket a változókat változtatja:
* columns, rows = képernyőn megjelenő oszlopok és sorok száma,
* magnification = megmondja egy méter a kamera "szenzorán" hány pixelnek felel meg (jó soknak)
*
* Hasonló háromszögek alapján kiszámolja mennyi látszik a pályából:
* sensor size
* |
* V
* ----
* \ |
* \ | <- focalLength
* \|
* |
* |\
* | \
* Z -> | \
* | \
* | \
* -------------
* columns
*
* Ezek alapján reallocolja a darabolós mátrixot.
*
*/
static void calculateRowsAndColumns() {
magnification = (float) screen -> w / 2 / sensorSize;
columns = 2 * cameraPosition.z * sensorSize / focalLength;
//hogy a négyzet négyzet is maradjon
rows = (float)screen -> h / screen -> w * columns;
if(renderMap == NULL) initRenderMap();
int xSize = (int)columns + 4; //a nagyobb testek átlóghatnak a képernyő határán
int ySize = (int)rows + 4;
int iSize = renderObjectsPerCube;
renderObject* innerTmp = (renderObject*) realloc(renderMap[0][0], xSize * ySize * iSize * sizeof(renderObject));
renderObject** outerTmp = (renderObject**) realloc(renderMap[0], xSize * ySize * sizeof(renderObject*));
renderMap = (renderObject***) realloc(renderMap, xSize * sizeof(renderObject**));
renderMap[0] = outerTmp;
int x;
for(x = 1; x < xSize; x++)
renderMap[x] = renderMap[0] + x * ySize;
renderMap[0][0] = innerTmp;
renderObject empty;
empty.doesExist = false;
int y, i = 0;
int j;
for(x = 0; x < xSize; x++)
for(y = 0; y < ySize; y++) {
renderMap[x][y] = renderMap[0][0] + i++ * iSize;
for(j = 0; j < iSize; j++) renderMap[x][y][j] = empty;
}
}
///A játékost követi a kamerával, nem hagyja, hogy a pálya alá lásson.
void followPlayerWithCamera() {
renderObject player = getPlayerRenderObject();
cameraPosition.x = (2 * player.position.x + player.size.x) / 2;
cameraPosition.y = (player.position.y < rows / 2 ? rows / 2 : player.position.y) + 1;
}
///A menüben használt kamerát állítja be, visszaadja a columns-t és rows-t is.
void menuCamera(int* getColumns, int* getRows) {
cameraPosition.z = cameraDeltaZDistanceStart;
calculateRowsAndColumns();
*getColumns = columns;
*getRows = rows;
cameraPosition.x = columns / 2;
cameraPosition.y = rows / 2;
}
///Visszaadja, hogy hány oszlop látszik a pályából.
int getColumns() {
return columns;
}
/** \brief A kamera dollyzását végzi, a kamerát mozgatja
* A dolly állását staticban tárolja, ezért új dolly eseteén először egy restart = true-val kell meghívni,
* \param ms eltelt idő
* \param kell-e újrakezdés?
* \return elérte-e a végállást?
* Minden frameban újraszámolja a rows&coulmns-t,
*/
bool cameraDollyZ(int deltaTime, bool restart) {
static int timePassed;
if(restart) timePassed = 0;
bool done = true;
timePassed += deltaTime;
float t = (float)(cameraDollyTime - timePassed) / cameraDollyTime;
float cube = t*t*t;
float currentZ = cameraDeltaZDistanceEnd + (cameraDeltaZDistanceStart - cameraDeltaZDistanceEnd) * cube;
if(currentZ <= cameraDeltaZDistanceEnd) {
currentZ = cameraDeltaZDistanceEnd;
done = false;
}
cameraPosition.z = currentZ;
calculateRowsAndColumns();
return done;
}
/** \brief Térbeli pontból síkbelit képez.
* A 3D-s pont koordinátái és a kamera alapján kiszámolja, hogy a kamera 2D-s szenzorán hol jelenik meg a pont.
* Geometriailag leírva, a két ponton (point, cameraPosition) átmenő egyenes egyenletének, és a 'szenzor' vízszintesének metszéspontja
* a keresett pontunk. A lent és a linken is látható egyenletet először a tér x-z, majd az y-z vetületére alkalmazzuk,
* és megkapjuk a térbeli pontunk megfelelő síkbeli leképezést.
* Ez interaktívan ábrázolva így néz ki: https://www.desmos.com/calculator/8qjvkptjmn
* \param Térvektor típusú pont
* \return Síkvektor típusú pont
* A visszaadott pontnak int koordinátái vannak, hiszen valamelyik pixel koordinátáit jelöli.
* Ez a függvény igazából egy camera obscura modellje.
*/
intVector2D get2DPoint(vector3D point) {
//Ha watchBounds = true, csak egy megadott kockán belül adja vissza az értéket (rajzol), ez a feldarabolás miatt fontos
if(watchBounds) {
putInsideIntervalF(leftBound, &point.x, rightBound);
putInsideIntervalF(lowerBound, &point.y, upperBound);
}
//Ezt a két kifejezést újra felhasználjuk
float zDist = point.z - cameraPosition.z;
float zDistFromHole = zDist - focalLength;
float dx = (cameraPosition.x * zDistFromHole + focalLength * point.x) / zDist - cameraPosition.x;
float dy = (cameraPosition.y * zDistFromHole + focalLength * point.y) / zDist - cameraPosition.y;
//Megfelelően tükrözzük a kapot pontot, és a méterben kapott értéket átváltjuk pixelekre
intVector2D resultPoint = {
(int)(screen -> w / 2 - magnification * dx),
(int)(screen -> h / 2 + magnification * dy)
};
return resultPoint;
}
/** \brief Lerajzol egy négyszöget
* A bemenetként kapott 4 pont alkotta négyszöget rajzolja ki.
* \param síkvektor a csúcshoz
* \param síkvektor b csúcshoz
* \param síkvektor c csúcshoz
* \param síkvektor d csúcshoz
* \param szín négyszög színe
* Ezt egyszer kitöltéssel csinálja, egyszer pedig anti-aliasing poligonnal,
* hogy a rajz széle ne legyen recegős.
*/
static void drawTetragon(intVector2D a, intVector2D b, intVector2D c, intVector2D d, color color) {
Sint16 xCoords[4] = {(Sint16)a.x, (Sint16)b.x, (Sint16)c.x, (Sint16)d.x};
Sint16 yCoords[4] = {(Sint16)a.y, (Sint16)b.y, (Sint16)c.y, (Sint16)d.y};
filledPolygonRGBA(screen, xCoords, yCoords, 4, color.r, color.g, color.b, color.a);
aapolygonRGBA(screen, xCoords, yCoords, 4, color.r, color.g, color.b, color.a);
}
/** \brief Lerajzol egy téglatestet
* A kamera modul lényege, a rajzolást végzi el az eddigi függvények segítségével.
* \param test téglatest adatai
* \param bool melyik oldalakat kell rajzolni?
* Végez egy plusz ellenőrést is, nem csak a paraméterben megadott tömb alapján nem rajzol oldalakat,
* azokat se rajzolja le, amiket a helyzetük miatt biztosan nem láthat a kamera.
*/
void drawCuboid(renderObject object, bool sides[]) {
intVector2D vertexes[8];
//A téglatestet bejárva megkeressük a csúcsait
int i;
for(i = 0; i < 8; i++) {
vertexes[i] = get2DPoint(object.position);
switch(i % 4) {
case 0:
object.position.x += object.size.x;
break;
case 1:
object.position.y += object.size.y;
break;
case 2:
object.position.x -= object.size.x;
break;
case 3:
object.position.y -= object.size.y;
}
if(i == 3) object.position.z += object.size.z;
}
//alja
if(sides[0] && object.position.y > cameraPosition.y) drawTetragon(vertexes[0], vertexes[4], vertexes[5], vertexes[1], object.colors.dark);
//bal oldali lap
if(sides[1] && object.position.x > cameraPosition.x) drawTetragon(vertexes[0], vertexes[3], vertexes[7], vertexes[4], object.colors.dark);
//jobb oldali lap
if(sides[2] && object.position.x + object.size.x < cameraPosition.x) drawTetragon(vertexes[1], vertexes[2], vertexes[6], vertexes[5], object.colors.dark);
//teteje
if(sides[3] && object.position.y + object.size.y < cameraPosition.y) drawTetragon(vertexes[3], vertexes[7], vertexes[6], vertexes[2], object.colors.light);
//eleje
if(sides[4]) drawTetragon(vertexes[4], vertexes[5], vertexes[6], vertexes[7], object.colors.normal);
}
/// Az egy m^3-ben lévő testeket rajzolja le
static void drawPlace(int x, int* y, int direction, int bound) {
bool sides[5] = {true, true, true, true, true};
renderObject toDraw = getBlockRenderObject(x, y, direction, bound, sides);
if(toDraw.doesExist) {
watchBounds = false;
drawCuboid(toDraw, sides);
watchBounds = true;
}
else {
int i = 0;
toDraw = renderMap[x - leftMostBound][*y - bottomBound][i];
while(toDraw.doesExist && i < renderObjectsPerCube) {
drawCuboid(toDraw, sides);
i++;
toDraw = renderMap[x - leftMostBound][*y - bottomBound][i];
}
renderObject player = getPlayerRenderObject();
if(
(x == (int)floor(player.position.x) || x == (int)floor(player.position.x + player.size.x)) &&
(*y == (int)floor(player.position.y) || *y == (int)floor(player.position.y + player.size.y))
)
drawCuboid(player, sides);
}
}
///Az egy oszlopban lévő testeket rajzolja le, a részecskéket mozgatja közvetlen
static void drawY(int deltaTime, int x) {
int y;
for(y = topBound; y > cameraPosition.y; y--) {
upperBound = y + 1;
lowerBound = y;
drawPlace(x, &y, -1, (int)cameraPosition.y);
}
for(y = bottomBound; y <= cameraPosition.y; y++) {
upperBound = y + 1;
lowerBound = y;
drawPlace(x, &y, 1, (int)cameraPosition.y + 1);
}
watchBounds = false;
drawParticles(x, bottomBound, topBound, deltaTime);
watchBounds = true;
}
/** \brief Lerajzolja a teljes látható játékteret.
* A megfelelő rajzoláshoz figyelni kell a testek takarására, nem mindegy ezért, hogy milyen sorrendben rajzoljuk őket.
* A részecskéknél ezzel nincs probléma, azokat bármilyen sorrendben rajzolhatjuk. Ők a játékteret kitakarják, egymásnál viszont nem látszik,
* hogy melyik takrja melyiket, ezért azokat elég a játéktér után bármilyen sorrendben lerajzolni.
* A térképet alkotó kockáknál már nem ilyen egyszeű a helyzet. Azokat 4 irányból kell rajzolni, bal lentről, jobb lentről, bal fentről, illetve jobb fentről középre.
* Ha ebben a négy lépésben rajzoljuk őket (ezek között a sorrend nem számít) akkor mindig a legfesőket rajzoljuk utoljára, és így valósnak néz ki az eredmény.
* A játékos, a lövedékek, illetve az ellenségek viszont sajnos nincsenek egy négyzethálóhoz kötve. Így gyakran megesik, hogy az egyik felüket a pálya
* egyik kockája előtt, a másikat pedig az után, de még a kövektező előtt kéne rajzolni. Ezt nem tudjuk megcsinálni, hatalmas erőforrásba kerülne ez a majdnem pixelről
* pixelre történő szkennelés. A pályát továbbra is m^3-ént szeretnénk lerajzolni. Hogy ez megfelelően nézzen ki, minden köbméterben csak az abban a kockában lévő dolgokat
* szeretnénk megrajzolni. Ehhez fel kell "darabolnunk" a játékost, a lövedékeket, illetve az ellenségeket is. A darabolás azt jelenti, hogy egy mátrix minden cellájába
* beírjuk, hogy az adott kockában melyik, milyen tulajdonsággal rendelkező testek lógnak be. Rajzolásnál pedig a testeknek mindig csak az adott kockabeli részét rajzoljuk le.
* Mivel a kockákat jó sorrendben rajzoljuk, így a bennük levő "testekrészeket" is jó sorrendbe fogjuk rajzolni. A problémát megoldottuk.
* \param ms eltelt idő
* Ez a függvény elvégzi a részecskék, a pálya, illetve minden más test rajzolását is. A részecskék mozgatása innen van meghívva.
*/
void drawMap(int deltaTime) {
leftMostBound = (int)(cameraPosition.x - (float)columns / 2) - 1;
rightMostBound = (int)(cameraPosition.x + (float)columns / 2) + 1;
topBound = (int)(cameraPosition.y + (float)rows / 2 + 1);
bottomBound = (int)(cameraPosition.y - (float)rows / 2 - 1);
int y, x;
for(x = leftMostBound; x < rightMostBound; x++)
for(y = bottomBound; y < topBound; y++)
getFloatersRenderObject(x, y, renderMap[x - leftMostBound][y - bottomBound], renderObjectsPerCube);
float slicer = cameraPosition.x;
watchBounds = true;
for(x = leftMostBound; x <= slicer; x++) {
leftBound = x - 0.005;
rightBound = x + 1 + 0.005;
drawY(deltaTime, x);
}
for(x = rightMostBound; x > slicer - 1; x--) {
leftBound = x - 0.005;
rightBound = x + 1 + 0.005;
drawY(deltaTime, x);
}
watchBounds = false;
}

View file

@ -0,0 +1,326 @@
#include "camera.h"
#define focalLength 0.05 /**< gyújtótáv [m] */
#define sensorSize 0.07 /**< szenzor hosszabb oldalának a fele [m] */
#define renderObjectsPerCube 10 /**< max( (projectile + player + enemy) / m^3), erről később bővebben. */
vector3D cameraPosition; /**< A kamera térbeli helyvektora. */
float magnification, columns, rows; /**< Ennyi látszik a pályából [m]. */
bool watchBounds = false; /**< Feldarabolós rajzolás van-e? */
float leftBound, rightBound, upperBound, lowerBound; /**< Darabolás határai. */
int leftMostBound, rightMostBound, topBound, bottomBound;
renderObject*** renderMap = NULL; /**< Darabolás mátrixa. */
///A feldarabolós rajzoláshoz szükséges mátrixot szabadítja fel.
void freeRenderMap() {
if(renderMap != NULL) {
free(renderMap[0][0]);
free(renderMap[0]);
free(renderMap);
}
}
///A feldarabolós rajzoláshoz szükséges mátrixot mallocolja.
static void initRenderMap() {
renderMap = (renderObject***) malloc(sizeof(renderObject**));
renderMap[0] = (renderObject**) malloc(sizeof(renderObject*));
renderMap[0][0] = (renderObject*) malloc(sizeof(renderObject));
}
/** \brief Kiszámolja a kamera poziciója és a képernyő mérete alapján, hogy mennyi látszik a pályából.
*
* Elsősorban ezeket a változókat változtatja:
* columns, rows = képernyőn megjelenő oszlopok és sorok száma,
* magnification = megmondja egy méter a kamera "szenzorán" hány pixelnek felel meg (jó soknak)
*
* Hasonló háromszögek alapján kiszámolja mennyi látszik a pályából:
* sensor size
* |
* V
* ----
* \ |
* \ | <- focalLength
* \|
* |
* |\
* | \
* Z -> | \
* | \
* | \
* -------------
* columns
*
* Ezek alapján reallocolja a darabolós mátrixot.
*
*/
static void calculateRowsAndColumns() {
magnification = (float) screen -> w / 2 / sensorSize;
columns = 2 * cameraPosition.z * sensorSize / focalLength;
//hogy a négyzet négyzet is maradjon
rows = (float)screen -> h / screen -> w * columns;
if(renderMap == NULL) initRenderMap();
int xSize = (int)columns + 4; //a nagyobb testek átlóghatnak a képernyő határán
int ySize = (int)rows + 4;
int iSize = renderObjectsPerCube;
renderObject* innerTmp = (renderObject*) realloc(renderMap[0][0], xSize * ySize * iSize * sizeof(renderObject));
renderObject** outerTmp = (renderObject**) realloc(renderMap[0], xSize * ySize * sizeof(renderObject*));
renderMap = (renderObject***) realloc(renderMap, xSize * sizeof(renderObject**));
renderMap[0] = outerTmp;
int x;
for(x = 1; x < xSize; x++)
renderMap[x] = renderMap[0] + x * ySize;
renderMap[0][0] = innerTmp;
renderObject empty;
empty.doesExist = false;
int y, i = 0;
int j;
for(x = 0; x < xSize; x++)
for(y = 0; y < ySize; y++) {
renderMap[x][y] = renderMap[0][0] + i++ * iSize;
for(j = 0; j < iSize; j++) renderMap[x][y][j] = empty;
}
}
///A játékost követi a kamerával, nem hagyja, hogy a pálya alá lásson.
void followPlayerWithCamera() {
renderObject player = getPlayerRenderObject();
cameraPosition.x = (2 * player.position.x + player.size.x) / 2;
cameraPosition.y = (player.position.y < rows / 2 ? rows / 2 : player.position.y) + 1;
}
///A menüben használt kamerát állítja be, visszaadja a columns-t és rows-t is.
void menuCamera(int* getColumns, int* getRows) {
cameraPosition.z = cameraDeltaZDistanceStart;
calculateRowsAndColumns();
*getColumns = columns;
*getRows = rows;
cameraPosition.x = columns / 2;
cameraPosition.y = rows / 2;
}
///Visszaadja, hogy hány oszlop látszik a pályából.
int getColumns() {
return columns;
}
/** \brief A kamera dollyzását végzi, a kamerát mozgatja
* A dolly állását staticban tárolja, ezért új dolly eseteén először egy restart = true-val kell meghívni,
* \param ms eltelt idő
* \param kell-e újrakezdés?
* \return elérte-e a végállást?
* Minden frameban újraszámolja a rows&coulmns-t,
*/
bool cameraDollyZ(int deltaTime, bool restart) {
static int timePassed;
if(restart) timePassed = 0;
bool done = true;
timePassed += deltaTime;
float t = (float)(cameraDollyTime - timePassed) / cameraDollyTime;
float cube = t*t*t;
float currentZ = cameraDeltaZDistanceEnd + (cameraDeltaZDistanceStart - cameraDeltaZDistanceEnd) * cube;
if(currentZ <= cameraDeltaZDistanceEnd) {
currentZ = cameraDeltaZDistanceEnd;
done = false;
}
cameraPosition.z = currentZ;
calculateRowsAndColumns();
return done;
}
/** \brief Térbeli pontból síkbelit képez.
* A 3D-s pont koordinátái és a kamera alapján kiszámolja, hogy a kamera 2D-s szenzorán hol jelenik meg a pont.
* Geometriailag leírva, a két ponton (point, cameraPosition) átmenő egyenes egyenletének, és a 'szenzor' vízszintesének metszéspontja
* a keresett pontunk. A lent és a linken is látható egyenletet először a tér x-z, majd az y-z vetületére alkalmazzuk,
* és megkapjuk a térbeli pontunk megfelelő síkbeli leképezést.
* Ez interaktívan ábrázolva így néz ki: https://www.desmos.com/calculator/8qjvkptjmn
* \param Térvektor típusú pont
* \return Síkvektor típusú pont
* A visszaadott pontnak int koordinátái vannak, hiszen valamelyik pixel koordinátáit jelöli.
* Ez a függvény igazából egy camera obscura modellje.
*/
intVector2D get2DPoint(vector3D point) {
//Ha watchBounds = true, csak egy megadott kockán belül adja vissza az értéket (rajzol), ez a feldarabolás miatt fontos
if(watchBounds) {
putInsideIntervalF(leftBound, &point.x, rightBound);
putInsideIntervalF(lowerBound, &point.y, upperBound);
}
//Ezt a két kifejezést újra felhasználjuk
float zDist = point.z - cameraPosition.z;
float zDistFromHole = zDist - focalLength;
float dx = (cameraPosition.x * zDistFromHole + focalLength * point.x) / zDist - cameraPosition.x;
float dy = (cameraPosition.y * zDistFromHole + focalLength * point.y) / zDist - cameraPosition.y;
//Megfelelően tükrözzük a kapot pontot, és a méterben kapott értéket átváltjuk pixelekre
intVector2D resultPoint = {
(int)(screen -> w / 2 - magnification * dx),
(int)(screen -> h / 2 + magnification * dy)
};
return resultPoint;
}
/** \brief Lerajzol egy négyszöget
* A bemenetként kapott 4 pont alkotta négyszöget rajzolja ki.
* \param síkvektor a csúcshoz
* \param síkvektor b csúcshoz
* \param síkvektor c csúcshoz
* \param síkvektor d csúcshoz
* \param szín négyszög színe
* Ezt egyszer kitöltéssel csinálja, egyszer pedig anti-aliasing poligonnal,
* hogy a rajz széle ne legyen recegős.
*/
static void drawTetragon(intVector2D a, intVector2D b, intVector2D c, intVector2D d, color color) {
Sint16 xCoords[4] = {(Sint16)a.x, (Sint16)b.x, (Sint16)c.x, (Sint16)d.x};
Sint16 yCoords[4] = {(Sint16)a.y, (Sint16)b.y, (Sint16)c.y, (Sint16)d.y};
filledPolygonRGBA(screen, xCoords, yCoords, 4, color.r, color.g, color.b, color.a);
aapolygonRGBA(screen, xCoords, yCoords, 4, color.r, color.g, color.b, color.a);
}
/** \brief Lerajzol egy téglatestet
* A kamera modul lényege, a rajzolást végzi el az eddigi függvények segítségével.
* \param test téglatest adatai
* \param bool melyik oldalakat kell rajzolni?
* Végez egy plusz ellenőrést is, nem csak a paraméterben megadott tömb alapján nem rajzol oldalakat,
* azokat se rajzolja le, amiket a helyzetük miatt biztosan nem láthat a kamera.
*/
void drawCuboid(renderObject object, bool sides[]) {
intVector2D vertexes[8];
//A téglatestet bejárva megkeressük a csúcsait
int i;
for(i = 0; i < 8; i++) {
vertexes[i] = get2DPoint(object.position);
switch(i % 4) {
case 0:
object.position.x += object.size.x;
break;
case 1:
object.position.y += object.size.y;
break;
case 2:
object.position.x -= object.size.x;
break;
case 3:
object.position.y -= object.size.y;
}
if(i == 3) object.position.z += object.size.z;
}
//alja
if(sides[0] && object.position.y > cameraPosition.y) drawTetragon(vertexes[0], vertexes[4], vertexes[5], vertexes[1], object.colors.dark);
//bal oldali lap
if(sides[1] && object.position.x > cameraPosition.x) drawTetragon(vertexes[0], vertexes[3], vertexes[7], vertexes[4], object.colors.dark);
//jobb oldali lap
if(sides[2] && object.position.x + object.size.x < cameraPosition.x) drawTetragon(vertexes[1], vertexes[2], vertexes[6], vertexes[5], object.colors.dark);
//teteje
if(sides[3] && object.position.y + object.size.y < cameraPosition.y) drawTetragon(vertexes[3], vertexes[7], vertexes[6], vertexes[2], object.colors.light);
//eleje
if(sides[4]) drawTetragon(vertexes[4], vertexes[5], vertexes[6], vertexes[7], object.colors.normal);
}
/// Az egy m^3-ben lévő testeket rajzolja le
static void drawPlace(int x, int* y, int direction, int bound) {
bool sides[5] = {true, true, true, true, true};
renderObject toDraw = getBlockRenderObject(x, y, direction, bound, sides);
if(toDraw.doesExist) {
watchBounds = false;
drawCuboid(toDraw, sides);
watchBounds = true;
}
else {
int i = 0;
toDraw = renderMap[x - leftMostBound][*y - bottomBound][i];
while(toDraw.doesExist && i < renderObjectsPerCube) {
drawCuboid(toDraw, sides);
i++;
toDraw = renderMap[x - leftMostBound][*y - bottomBound][i];
}
renderObject player = getPlayerRenderObject();
if(
(x == (int)floor(player.position.x) || x == (int)floor(player.position.x + player.size.x)) &&
(*y == (int)floor(player.position.y) || *y == (int)floor(player.position.y + player.size.y))
)
drawCuboid(player, sides);
}
}
///Az egy oszlopban lévő testeket rajzolja le, a részecskéket mozgatja közvetlen
static void drawY(int deltaTime, int x) {
int y;
for(y = topBound; y > cameraPosition.y; y--) {
upperBound = y + 1;
lowerBound = y;
drawPlace(x, &y, -1, (int)cameraPosition.y);
}
for(y = bottomBound; y <= cameraPosition.y; y++) {
upperBound = y + 1;
lowerBound = y;
drawPlace(x, &y, 1, (int)cameraPosition.y + 1);
}
watchBounds = false;
drawParticles(x, bottomBound, topBound, deltaTime);
watchBounds = true;
}
/** \brief Lerajzolja a teljes látható játékteret.
* A megfelelő rajzoláshoz figyelni kell a testek takarására, nem mindegy ezért, hogy milyen sorrendben rajzoljuk őket.
* A részecskéknél ezzel nincs probléma, azokat bármilyen sorrendben rajzolhatjuk. Ők a játékteret kitakarják, egymásnál viszont nem látszik,
* hogy melyik takrja melyiket, ezért azokat elég a játéktér után bármilyen sorrendben lerajzolni.
* A térképet alkotó kockáknál már nem ilyen egyszeű a helyzet. Azokat 4 irányból kell rajzolni, bal lentről, jobb lentről, bal fentről, illetve jobb fentről középre.
* Ha ebben a négy lépésben rajzoljuk őket (ezek között a sorrend nem számít) akkor mindig a legfesőket rajzoljuk utoljára, és így valósnak néz ki az eredmény.
* A játékos, a lövedékek, illetve az ellenségek viszont sajnos nincsenek egy négyzethálóhoz kötve. Így gyakran megesik, hogy az egyik felüket a pálya
* egyik kockája előtt, a másikat pedig az után, de még a kövektező előtt kéne rajzolni. Ezt nem tudjuk megcsinálni, hatalmas erőforrásba kerülne ez a majdnem pixelről
* pixelre történő szkennelés. A pályát továbbra is m^3-ént szeretnénk lerajzolni. Hogy ez megfelelően nézzen ki, minden köbméterben csak az abban a kockában lévő dolgokat
* szeretnénk megrajzolni. Ehhez fel kell "darabolnunk" a játékost, a lövedékeket, illetve az ellenségeket is. A darabolás azt jelenti, hogy egy mátrix minden cellájába
* beírjuk, hogy az adott kockában melyik, milyen tulajdonsággal rendelkező testek lógnak be. Rajzolásnál pedig a testeknek mindig csak az adott kockabeli részét rajzoljuk le.
* Mivel a kockákat jó sorrendben rajzoljuk, így a bennük levő "testekrészeket" is jó sorrendbe fogjuk rajzolni. A problémát megoldottuk.
* \param ms eltelt idő
* Ez a függvény elvégzi a részecskék, a pálya, illetve minden más test rajzolását is. A részecskék mozgatása innen van meghívva.
*/
void drawMap(int deltaTime) {
leftMostBound = (int)(cameraPosition.x - (float)columns / 2) - 1;
rightMostBound = (int)(cameraPosition.x + (float)columns / 2) + 1;
topBound = (int)(cameraPosition.y + (float)rows / 2 + 1);
bottomBound = (int)(cameraPosition.y - (float)rows / 2 - 1);
int y, x;
for(x = leftMostBound; x < rightMostBound; x++)
for(y = bottomBound; y < topBound; y++)
getFloatersRenderObject(x, y, renderMap[x - leftMostBound][y - bottomBound], renderObjectsPerCube);
float slicer = cameraPosition.x;
watchBounds = true;
for(x = leftMostBound; x <= slicer; x++) {
leftBound = x - 0.005;
rightBound = x + 1 + 0.005;
drawY(deltaTime, x);
}
for(x = rightMostBound; x > slicer - 1; x--) {
leftBound = x - 0.005;
rightBound = x + 1 + 0.005;
drawY(deltaTime, x);
}
watchBounds = false;
}

View file

@ -0,0 +1,24 @@
#ifndef CAMERA_H_INCLUDED
#define CAMERA_H_INCLUDED
#include "global.h"
#include "floaters.h"
#include "player.h"
#include "map.h"
#include "particles.h"
#define cameraDeltaZDistanceStart 25 /**<dolly start táv [m]*/
#define cameraDeltaZDistanceEnd 14 /**<dolly end táv [m]*/
#define cameraDollyTime 3250 /**<[ms]*/
void freeRenderMap();
void followPlayerWithCamera();
void menuCamera(int* getColumns, int* getRows);
int getColumns();
bool cameraDollyZ(int deltaTime, bool restart);
intVector2D get2DPoint(vector3D point);
void drawCuboid(renderObject object, bool sides[]);
void drawMap(int deltaTime);
#endif // CAMERA_H_INCLUDED

View file

@ -0,0 +1,24 @@
#ifndef CAMERA_H_INCLUDED
#define CAMERA_H_INCLUDED
#include "global.h"
#include "floaters.h"
#include "player.h"
#include "map.h"
#include "particles.h"
#define cameraDeltaZDistanceStart 25 /**<dolly start táv [m]*/
#define cameraDeltaZDistanceEnd 15 /**<dolly end táv [m]*/
#define cameraDollyTime 3250 /**<[ms]*/
void freeRenderMap();
void followPlayerWithCamera();
void menuCamera(int* getColumns, int* getRows);
int getColumns();
bool cameraDollyZ(int deltaTime, bool restart);
intVector2D get2DPoint(vector3D point);
void drawCuboid(renderObject object, bool sides[]);
void drawMap(int deltaTime);
#endif // CAMERA_H_INCLUDED

View file

@ -0,0 +1,17 @@
#include "global.h"
#ifndef CAMERA_H_INCLUDED
#define CAMERA_H_INCLUDED
void followPlayerWCamera();
bool cameraDollyZ(int deltaTime);
intVector2D get2DPoint(vector3D point);
void drawCuboid(renderObject object, bool sides[]);
void drawMap(int deltaTime);
void calculateRowsAndColumns();
int getCamMinZDist();
#endif // CAMERA_H_INCLUDED

View file

@ -0,0 +1,56 @@
#include "color.h"
#define baseHue 30 /**< A kockák átlagos színezetsége. */
#define hueVariance 20 /**< A kockák színezetségének átlagostól vlaó eltérése. */
#define baseSaturation 0.75 /**< A kockák átlagos telítettsége. */
#define baseLightness 0.6 /**< A kockák átlagos fényessége. */
#define lightnessStep 0.08 /**< A kockák oldalainak háromféle fényesség értéke van, ezzel szimuláljuk a fény-árnyékot. */
///Ez a függvény majdnem teljes egészében erről az oldalról származik: https://www.programmingalgorithms.com/algorithm/hsl-to-rgb?lang=C
static float hueToRgb(float v1, float v2, float vH) {
if (vH < 0) vH += 1;
if (vH > 1) vH -= 1;
if ((6 * vH) < 1) return (v1 + (v2 - v1) * 6 * vH);
if ((2 * vH) < 1) return v2;
if ((3 * vH) < 2) return (v1 + (v2 - v1) * ((2.0f / 3) - vH) * 6);
return v1;
}
///Ez a függvény majdnem teljes egészében erről az oldalról származik: https://www.programmingalgorithms.com/algorithm/hsl-to-rgb?lang=C
static color hslToRgb(int h, float s, float l) {
color rgb;
if (s == 0) rgb.r = rgb.g = rgb.b = (unsigned char)(l * 255);
else {
float v1, v2;
float hue = (float)h / 360;
v2 = (l < 0.5) ? (l * (1 + s)) : ((l + s) - (l * s));
v1 = 2 * l - v2;
rgb.r = (unsigned char)(255 * hueToRgb(v1, v2, hue + (1.0 / 3)));
rgb.g = (unsigned char)(255 * hueToRgb(v1, v2, hue));
rgb.b = (unsigned char)(255 * hueToRgb(v1, v2, hue - (1.0 / 3)));
rgb.a = 255;
}
return rgb;
}
/** \brief Véletlenszerűre színez egy kockát.
* \return színek
* Az alapszín, és hueVariance alapján meghatároz
* véletlenszerűen egy színezetséget, és az ahhoz a színezetséghez tartozó világosabb és sötétebb
* árnyalatú színeket is, majd ezeket RGBA-ba kódolja.
* Egy random hue-val készített paletta sokkal jobban néz ki, mint egy random RGB-vel készített.
*/
colors createBlockColor() {
int hue = randomIntWithinBorders(baseHue, hueVariance);
if(hue < 0) hue += 360;
return (colors) {
hslToRgb(hue, baseSaturation, baseLightness + lightnessStep),
hslToRgb(hue, baseSaturation, baseLightness),
hslToRgb(hue, baseSaturation, baseLightness - lightnessStep)
};
}

View file

@ -0,0 +1,56 @@
#include "color.h"
#define baseHue 30 /**< A kockák átlagos színezetsége. */
#define hueVariance 20 /**< A kockák színezetségének átlagostól vlaó eltérése. */
#define baseSaturation 0.75 /**< A kockák átlagos telítettsége. */
#define baseLightness 0.6 /**< A kockák átlagos fényessége. */
#define lightnessStep 0.08 /**< A kockák oldalainak háromféle fényesség értéke van, ezzel szimuláljuk a fény-árnyékot. */
///Ez a függvény majdnem teljes egészében erről az oldalról származik: https://www.programmingalgorithms.com/algorithm/hsl-to-rgb?lang=C
static float hueToRgb(float v1, float v2, float vH) {
if (vH < 0) vH += 1;
if (vH > 1) vH -= 1;
if ((6 * vH) < 1) return (v1 + (v2 - v1) * 6 * vH);
if ((2 * vH) < 1) return v2;
if ((3 * vH) < 2) return (v1 + (v2 - v1) * ((2.0f / 3) - vH) * 6);
return v1;
}
///Ez a függvény majdnem teljes egészében erről az oldalról származik: https://www.programmingalgorithms.com/algorithm/hsl-to-rgb?lang=C
static color hslToRgb(int h, float s, float l) {
color rgb;
if (s == 0) rgb.r = rgb.g = rgb.b = (unsigned char)(l * 255);
else {
float v1, v2;
float hue = (float)h / 360;
v2 = (l < 0.5) ? (l * (1 + s)) : ((l + s) - (l * s));
v1 = 2 * l - v2;
rgb.r = (unsigned char)(255 * hueToRgb(v1, v2, hue + (1.0 / 3)));
rgb.g = (unsigned char)(255 * hueToRgb(v1, v2, hue));
rgb.b = (unsigned char)(255 * hueToRgb(v1, v2, hue - (1.0 / 3)));
rgb.a = 255;
}
return rgb;
}
/** \brief Véletlenszerűre színez egy kockát.
* \return színek
* Az alapszín, és hueVariance alapján meghatároz
* véletlenszerűen egy színezetséget, és az ahhoz a színezetséghez tartozó világosabb és sötétebb
* árnyalatú színeket is, majd ezeket RGBA-ba kódolja.
* Egy random hue-val készített paletta sokkal jobban néz ki, mint egy random RGB-vel készített.
*/
colors createBlockColor() {
int hue = randomIntWithinBorders(baseHue, hueVariance);
if(hue < 0) hue += 360;
return (colors) {
hslToRgb(hue, baseSaturation, baseLightness + lightnessStep),
hslToRgb(hue, baseSaturation, baseLightness),
hslToRgb(hue, baseSaturation, baseLightness - lightnessStep)
};
}

View file

@ -0,0 +1,8 @@
#ifndef COLOR_H_INCLUDED
#define COLOR_H_INCLUDED
#include "global.h"
colors createBlockColor();
#endif // COLOR_H_INCLUDED

Some files were not shown because too many files have changed in this diff Show more